From 3ac4f75028ce4b34c81138a4572a6a9d4cca51d3 Mon Sep 17 00:00:00 2001 From: Alexander Demichev Date: Tue, 26 Oct 2021 19:52:52 +0200 Subject: [PATCH 01/10] Update dependencies --- go.mod | 5 +- go.sum | 6 +- .../typed/config/v1/config_client.go | 5 + .../config/v1/fake/fake_config_client.go | 4 + .../config/v1/fake/fake_imagecontentpolicy.go | 106 +++++++++++ .../typed/config/v1/generated_expansion.go | 2 + .../typed/config/v1/imagecontentpolicy.go | 152 +++++++++++++++ .../config/v1/imagecontentpolicy.go | 73 +++++++ .../externalversions/config/v1/interface.go | 7 + .../informers/externalversions/generic.go | 2 + .../listers/config/v1/expansion_generated.go | 4 + .../listers/config/v1/imagecontentpolicy.go | 52 +++++ .../machine/clientset/versioned/clientset.go | 81 ++++++++ .../machine/clientset/versioned/doc.go | 4 + .../machine/clientset/versioned/scheme/doc.go | 4 + .../clientset/versioned/scheme/register.go | 40 ++++ .../versioned/typed/machine/v1beta1/doc.go | 4 + .../machine/v1beta1/generated_expansion.go | 9 + .../typed/machine/v1beta1/machine.go | 179 ++++++++++++++++++ .../typed/machine/v1beta1/machine_client.go | 83 ++++++++ .../machine/v1beta1/machinehealthcheck.go | 179 ++++++++++++++++++ .../typed/machine/v1beta1/machineset.go | 179 ++++++++++++++++++ .../informers/externalversions/factory.go | 164 ++++++++++++++++ .../informers/externalversions/generic.go | 50 +++++ .../internalinterfaces/factory_interfaces.go | 24 +++ .../externalversions/machine/interface.go | 30 +++ .../machine/v1beta1/interface.go | 43 +++++ .../machine/v1beta1/machine.go | 74 ++++++++ .../machine/v1beta1/machinehealthcheck.go | 74 ++++++++ .../machine/v1beta1/machineset.go | 74 ++++++++ .../machine/v1beta1/expansion_generated.go | 27 +++ .../listers/machine/v1beta1/machine.go | 83 ++++++++ .../machine/v1beta1/machinehealthcheck.go | 83 ++++++++ .../listers/machine/v1beta1/machineset.go | 83 ++++++++ vendor/modules.txt | 13 +- 35 files changed, 1996 insertions(+), 6 deletions(-) create mode 100644 vendor/github.com/openshift/client-go/config/clientset/versioned/typed/config/v1/fake/fake_imagecontentpolicy.go create mode 100644 vendor/github.com/openshift/client-go/config/clientset/versioned/typed/config/v1/imagecontentpolicy.go create mode 100644 vendor/github.com/openshift/client-go/config/informers/externalversions/config/v1/imagecontentpolicy.go create mode 100644 vendor/github.com/openshift/client-go/config/listers/config/v1/imagecontentpolicy.go create mode 100644 vendor/github.com/openshift/client-go/machine/clientset/versioned/clientset.go create mode 100644 vendor/github.com/openshift/client-go/machine/clientset/versioned/doc.go create mode 100644 vendor/github.com/openshift/client-go/machine/clientset/versioned/scheme/doc.go create mode 100644 vendor/github.com/openshift/client-go/machine/clientset/versioned/scheme/register.go create mode 100644 vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/doc.go create mode 100644 vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/generated_expansion.go create mode 100644 vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/machine.go create mode 100644 vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/machine_client.go create mode 100644 vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/machinehealthcheck.go create mode 100644 vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/machineset.go create mode 100644 vendor/github.com/openshift/client-go/machine/informers/externalversions/factory.go create mode 100644 vendor/github.com/openshift/client-go/machine/informers/externalversions/generic.go create mode 100644 vendor/github.com/openshift/client-go/machine/informers/externalversions/internalinterfaces/factory_interfaces.go create mode 100644 vendor/github.com/openshift/client-go/machine/informers/externalversions/machine/interface.go create mode 100644 vendor/github.com/openshift/client-go/machine/informers/externalversions/machine/v1beta1/interface.go create mode 100644 vendor/github.com/openshift/client-go/machine/informers/externalversions/machine/v1beta1/machine.go create mode 100644 vendor/github.com/openshift/client-go/machine/informers/externalversions/machine/v1beta1/machinehealthcheck.go create mode 100644 vendor/github.com/openshift/client-go/machine/informers/externalversions/machine/v1beta1/machineset.go create mode 100644 vendor/github.com/openshift/client-go/machine/listers/machine/v1beta1/expansion_generated.go create mode 100644 vendor/github.com/openshift/client-go/machine/listers/machine/v1beta1/machine.go create mode 100644 vendor/github.com/openshift/client-go/machine/listers/machine/v1beta1/machinehealthcheck.go create mode 100644 vendor/github.com/openshift/client-go/machine/listers/machine/v1beta1/machineset.go diff --git a/go.mod b/go.mod index 9946dee62a..1250444c7c 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/onsi/ginkgo v1.16.4 github.com/onsi/gomega v1.14.0 github.com/openshift/api v0.0.0-20211025104849-a11323ccb6ea - github.com/openshift/client-go v0.0.0-20210730113412-1811c1b3fc0e + github.com/openshift/client-go v0.0.0-20211025111749-96ca2abfc56c github.com/openshift/library-go v0.0.0-20210811133500-5e31383de2a7 github.com/operator-framework/operator-sdk v0.5.1-0.20190301204940-c2efe6f74e7b github.com/prometheus/client_golang v1.11.0 @@ -21,10 +21,11 @@ require ( golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 gopkg.in/gcfg.v1 v1.2.3 gopkg.in/warnings.v0 v0.1.2 // indirect + gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.22.1 k8s.io/apimachinery v0.22.1 k8s.io/apiserver v0.22.0 - k8s.io/client-go v0.22.0 + k8s.io/client-go v0.22.1 k8s.io/code-generator v0.22.1 k8s.io/klog/v2 v2.9.0 k8s.io/kubectl v0.22.0 diff --git a/go.sum b/go.sum index a40d5c65c2..02ed2a81ea 100644 --- a/go.sum +++ b/go.sum @@ -538,8 +538,9 @@ github.com/openshift/api v0.0.0-20210730095913-85e1d547cdee/go.mod h1:ntkQrC1Z6A github.com/openshift/api v0.0.0-20211025104849-a11323ccb6ea h1:aCtko94sKCpceywj0I293WDFXtBJe+/Gg3v5ZuErq+Y= github.com/openshift/api v0.0.0-20211025104849-a11323ccb6ea/go.mod h1:RsQCVJu4qhUawxxDP7pGlwU3IA4F01wYm3qKEu29Su8= github.com/openshift/build-machinery-go v0.0.0-20210712174854-1bb7fd1518d3/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE= -github.com/openshift/client-go v0.0.0-20210730113412-1811c1b3fc0e h1:vhwzeXUxLd6JZlWZ+miBzTEpmVctHyHNq9z43ScYxWI= github.com/openshift/client-go v0.0.0-20210730113412-1811c1b3fc0e/go.mod h1:P1pjphFOgm/nYjmtouHGaSLGtdP25dQICJnYtcYhfEs= +github.com/openshift/client-go v0.0.0-20211025111749-96ca2abfc56c h1:2yUcA5LUiKqEnRnqW8MYaB3/7tEAFqCjLtVcbDFlIjg= +github.com/openshift/client-go v0.0.0-20211025111749-96ca2abfc56c/go.mod h1:xigLF97kzy1PZuDsC0Lfu6GlzChRt62+2Ts/nG3sPHY= github.com/openshift/library-go v0.0.0-20210811133500-5e31383de2a7 h1:aCoE+Q7jLvV7MFL2aZOnzO3dK6rpSuEE7273ijnAIWU= github.com/openshift/library-go v0.0.0-20210811133500-5e31383de2a7/go.mod h1:3GagmGg6gikg+hAqma7E7axBzs2pjx4+GrAbdl4OYdY= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -1221,8 +1222,9 @@ k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= k8s.io/client-go v0.18.0-beta.2/go.mod h1:UvuVxHjKWIcgy0iMvF+bwNDW7l0mskTNOaOW1Qv5BMA= k8s.io/client-go v0.21.3/go.mod h1:+VPhCgTsaFmGILxR/7E1N0S+ryO010QBeNCv5JwRGYU= k8s.io/client-go v0.22.0-rc.0/go.mod h1:BZGppBKJh4UtgDZcIIh6vHJsJ1iZiXS7EwKZYWhyklo= -k8s.io/client-go v0.22.0 h1:sD6o9O6tCwUKCENw8v+HFsuAbq2jCu8cWC61/ydwA50= k8s.io/client-go v0.22.0/go.mod h1:GUjIuXR5PiEv/RVK5OODUsm6eZk7wtSWZSaSJbpFdGg= +k8s.io/client-go v0.22.1 h1:jW0ZSHi8wW260FvcXHkIa0NLxFBQszTlhiAVsU5mopw= +k8s.io/client-go v0.22.1/go.mod h1:BquC5A4UOo4qVDUtoc04/+Nxp1MeHcVc1HJm1KmG8kk= k8s.io/code-generator v0.17.0/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= k8s.io/code-generator v0.18.0-beta.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= k8s.io/code-generator v0.21.3/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo= diff --git a/vendor/github.com/openshift/client-go/config/clientset/versioned/typed/config/v1/config_client.go b/vendor/github.com/openshift/client-go/config/clientset/versioned/typed/config/v1/config_client.go index 0f2182d2f5..707e5fc06e 100644 --- a/vendor/github.com/openshift/client-go/config/clientset/versioned/typed/config/v1/config_client.go +++ b/vendor/github.com/openshift/client-go/config/clientset/versioned/typed/config/v1/config_client.go @@ -19,6 +19,7 @@ type ConfigV1Interface interface { DNSesGetter FeatureGatesGetter ImagesGetter + ImageContentPoliciesGetter InfrastructuresGetter IngressesGetter NetworksGetter @@ -70,6 +71,10 @@ func (c *ConfigV1Client) Images() ImageInterface { return newImages(c) } +func (c *ConfigV1Client) ImageContentPolicies() ImageContentPolicyInterface { + return newImageContentPolicies(c) +} + func (c *ConfigV1Client) Infrastructures() InfrastructureInterface { return newInfrastructures(c) } diff --git a/vendor/github.com/openshift/client-go/config/clientset/versioned/typed/config/v1/fake/fake_config_client.go b/vendor/github.com/openshift/client-go/config/clientset/versioned/typed/config/v1/fake/fake_config_client.go index d743f46792..40d153d7c0 100644 --- a/vendor/github.com/openshift/client-go/config/clientset/versioned/typed/config/v1/fake/fake_config_client.go +++ b/vendor/github.com/openshift/client-go/config/clientset/versioned/typed/config/v1/fake/fake_config_client.go @@ -48,6 +48,10 @@ func (c *FakeConfigV1) Images() v1.ImageInterface { return &FakeImages{c} } +func (c *FakeConfigV1) ImageContentPolicies() v1.ImageContentPolicyInterface { + return &FakeImageContentPolicies{c} +} + func (c *FakeConfigV1) Infrastructures() v1.InfrastructureInterface { return &FakeInfrastructures{c} } diff --git a/vendor/github.com/openshift/client-go/config/clientset/versioned/typed/config/v1/fake/fake_imagecontentpolicy.go b/vendor/github.com/openshift/client-go/config/clientset/versioned/typed/config/v1/fake/fake_imagecontentpolicy.go new file mode 100644 index 0000000000..1cb92e2ee1 --- /dev/null +++ b/vendor/github.com/openshift/client-go/config/clientset/versioned/typed/config/v1/fake/fake_imagecontentpolicy.go @@ -0,0 +1,106 @@ +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + configv1 "github.com/openshift/api/config/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeImageContentPolicies implements ImageContentPolicyInterface +type FakeImageContentPolicies struct { + Fake *FakeConfigV1 +} + +var imagecontentpoliciesResource = schema.GroupVersionResource{Group: "config.openshift.io", Version: "v1", Resource: "imagecontentpolicies"} + +var imagecontentpoliciesKind = schema.GroupVersionKind{Group: "config.openshift.io", Version: "v1", Kind: "ImageContentPolicy"} + +// Get takes name of the imageContentPolicy, and returns the corresponding imageContentPolicy object, and an error if there is any. +func (c *FakeImageContentPolicies) Get(ctx context.Context, name string, options v1.GetOptions) (result *configv1.ImageContentPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(imagecontentpoliciesResource, name), &configv1.ImageContentPolicy{}) + if obj == nil { + return nil, err + } + return obj.(*configv1.ImageContentPolicy), err +} + +// List takes label and field selectors, and returns the list of ImageContentPolicies that match those selectors. +func (c *FakeImageContentPolicies) List(ctx context.Context, opts v1.ListOptions) (result *configv1.ImageContentPolicyList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(imagecontentpoliciesResource, imagecontentpoliciesKind, opts), &configv1.ImageContentPolicyList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &configv1.ImageContentPolicyList{ListMeta: obj.(*configv1.ImageContentPolicyList).ListMeta} + for _, item := range obj.(*configv1.ImageContentPolicyList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested imageContentPolicies. +func (c *FakeImageContentPolicies) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(imagecontentpoliciesResource, opts)) +} + +// Create takes the representation of a imageContentPolicy and creates it. Returns the server's representation of the imageContentPolicy, and an error, if there is any. +func (c *FakeImageContentPolicies) Create(ctx context.Context, imageContentPolicy *configv1.ImageContentPolicy, opts v1.CreateOptions) (result *configv1.ImageContentPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(imagecontentpoliciesResource, imageContentPolicy), &configv1.ImageContentPolicy{}) + if obj == nil { + return nil, err + } + return obj.(*configv1.ImageContentPolicy), err +} + +// Update takes the representation of a imageContentPolicy and updates it. Returns the server's representation of the imageContentPolicy, and an error, if there is any. +func (c *FakeImageContentPolicies) Update(ctx context.Context, imageContentPolicy *configv1.ImageContentPolicy, opts v1.UpdateOptions) (result *configv1.ImageContentPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(imagecontentpoliciesResource, imageContentPolicy), &configv1.ImageContentPolicy{}) + if obj == nil { + return nil, err + } + return obj.(*configv1.ImageContentPolicy), err +} + +// Delete takes name of the imageContentPolicy and deletes it. Returns an error if one occurs. +func (c *FakeImageContentPolicies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(imagecontentpoliciesResource, name), &configv1.ImageContentPolicy{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeImageContentPolicies) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(imagecontentpoliciesResource, listOpts) + + _, err := c.Fake.Invokes(action, &configv1.ImageContentPolicyList{}) + return err +} + +// Patch applies the patch and returns the patched imageContentPolicy. +func (c *FakeImageContentPolicies) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *configv1.ImageContentPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(imagecontentpoliciesResource, name, pt, data, subresources...), &configv1.ImageContentPolicy{}) + if obj == nil { + return nil, err + } + return obj.(*configv1.ImageContentPolicy), err +} diff --git a/vendor/github.com/openshift/client-go/config/clientset/versioned/typed/config/v1/generated_expansion.go b/vendor/github.com/openshift/client-go/config/clientset/versioned/typed/config/v1/generated_expansion.go index 50a4ec7f8f..646801584a 100644 --- a/vendor/github.com/openshift/client-go/config/clientset/versioned/typed/config/v1/generated_expansion.go +++ b/vendor/github.com/openshift/client-go/config/clientset/versioned/typed/config/v1/generated_expansion.go @@ -20,6 +20,8 @@ type FeatureGateExpansion interface{} type ImageExpansion interface{} +type ImageContentPolicyExpansion interface{} + type InfrastructureExpansion interface{} type IngressExpansion interface{} diff --git a/vendor/github.com/openshift/client-go/config/clientset/versioned/typed/config/v1/imagecontentpolicy.go b/vendor/github.com/openshift/client-go/config/clientset/versioned/typed/config/v1/imagecontentpolicy.go new file mode 100644 index 0000000000..17c441e5be --- /dev/null +++ b/vendor/github.com/openshift/client-go/config/clientset/versioned/typed/config/v1/imagecontentpolicy.go @@ -0,0 +1,152 @@ +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + "context" + "time" + + v1 "github.com/openshift/api/config/v1" + scheme "github.com/openshift/client-go/config/clientset/versioned/scheme" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// ImageContentPoliciesGetter has a method to return a ImageContentPolicyInterface. +// A group's client should implement this interface. +type ImageContentPoliciesGetter interface { + ImageContentPolicies() ImageContentPolicyInterface +} + +// ImageContentPolicyInterface has methods to work with ImageContentPolicy resources. +type ImageContentPolicyInterface interface { + Create(ctx context.Context, imageContentPolicy *v1.ImageContentPolicy, opts metav1.CreateOptions) (*v1.ImageContentPolicy, error) + Update(ctx context.Context, imageContentPolicy *v1.ImageContentPolicy, opts metav1.UpdateOptions) (*v1.ImageContentPolicy, error) + Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error + Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.ImageContentPolicy, error) + List(ctx context.Context, opts metav1.ListOptions) (*v1.ImageContentPolicyList, error) + Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.ImageContentPolicy, err error) + ImageContentPolicyExpansion +} + +// imageContentPolicies implements ImageContentPolicyInterface +type imageContentPolicies struct { + client rest.Interface +} + +// newImageContentPolicies returns a ImageContentPolicies +func newImageContentPolicies(c *ConfigV1Client) *imageContentPolicies { + return &imageContentPolicies{ + client: c.RESTClient(), + } +} + +// Get takes name of the imageContentPolicy, and returns the corresponding imageContentPolicy object, and an error if there is any. +func (c *imageContentPolicies) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.ImageContentPolicy, err error) { + result = &v1.ImageContentPolicy{} + err = c.client.Get(). + Resource("imagecontentpolicies"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of ImageContentPolicies that match those selectors. +func (c *imageContentPolicies) List(ctx context.Context, opts metav1.ListOptions) (result *v1.ImageContentPolicyList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1.ImageContentPolicyList{} + err = c.client.Get(). + Resource("imagecontentpolicies"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested imageContentPolicies. +func (c *imageContentPolicies) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("imagecontentpolicies"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a imageContentPolicy and creates it. Returns the server's representation of the imageContentPolicy, and an error, if there is any. +func (c *imageContentPolicies) Create(ctx context.Context, imageContentPolicy *v1.ImageContentPolicy, opts metav1.CreateOptions) (result *v1.ImageContentPolicy, err error) { + result = &v1.ImageContentPolicy{} + err = c.client.Post(). + Resource("imagecontentpolicies"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(imageContentPolicy). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a imageContentPolicy and updates it. Returns the server's representation of the imageContentPolicy, and an error, if there is any. +func (c *imageContentPolicies) Update(ctx context.Context, imageContentPolicy *v1.ImageContentPolicy, opts metav1.UpdateOptions) (result *v1.ImageContentPolicy, err error) { + result = &v1.ImageContentPolicy{} + err = c.client.Put(). + Resource("imagecontentpolicies"). + Name(imageContentPolicy.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(imageContentPolicy). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the imageContentPolicy and deletes it. Returns an error if one occurs. +func (c *imageContentPolicies) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { + return c.client.Delete(). + Resource("imagecontentpolicies"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *imageContentPolicies) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("imagecontentpolicies"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched imageContentPolicy. +func (c *imageContentPolicies) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.ImageContentPolicy, err error) { + result = &v1.ImageContentPolicy{} + err = c.client.Patch(pt). + Resource("imagecontentpolicies"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/vendor/github.com/openshift/client-go/config/informers/externalversions/config/v1/imagecontentpolicy.go b/vendor/github.com/openshift/client-go/config/informers/externalversions/config/v1/imagecontentpolicy.go new file mode 100644 index 0000000000..c50ea7b1b2 --- /dev/null +++ b/vendor/github.com/openshift/client-go/config/informers/externalversions/config/v1/imagecontentpolicy.go @@ -0,0 +1,73 @@ +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + "context" + time "time" + + configv1 "github.com/openshift/api/config/v1" + versioned "github.com/openshift/client-go/config/clientset/versioned" + internalinterfaces "github.com/openshift/client-go/config/informers/externalversions/internalinterfaces" + v1 "github.com/openshift/client-go/config/listers/config/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// ImageContentPolicyInformer provides access to a shared informer and lister for +// ImageContentPolicies. +type ImageContentPolicyInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.ImageContentPolicyLister +} + +type imageContentPolicyInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewImageContentPolicyInformer constructs a new informer for ImageContentPolicy type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewImageContentPolicyInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredImageContentPolicyInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredImageContentPolicyInformer constructs a new informer for ImageContentPolicy type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredImageContentPolicyInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ConfigV1().ImageContentPolicies().List(context.TODO(), options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ConfigV1().ImageContentPolicies().Watch(context.TODO(), options) + }, + }, + &configv1.ImageContentPolicy{}, + resyncPeriod, + indexers, + ) +} + +func (f *imageContentPolicyInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredImageContentPolicyInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *imageContentPolicyInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&configv1.ImageContentPolicy{}, f.defaultInformer) +} + +func (f *imageContentPolicyInformer) Lister() v1.ImageContentPolicyLister { + return v1.NewImageContentPolicyLister(f.Informer().GetIndexer()) +} diff --git a/vendor/github.com/openshift/client-go/config/informers/externalversions/config/v1/interface.go b/vendor/github.com/openshift/client-go/config/informers/externalversions/config/v1/interface.go index 00054daf31..6ee69a4811 100644 --- a/vendor/github.com/openshift/client-go/config/informers/externalversions/config/v1/interface.go +++ b/vendor/github.com/openshift/client-go/config/informers/externalversions/config/v1/interface.go @@ -26,6 +26,8 @@ type Interface interface { FeatureGates() FeatureGateInformer // Images returns a ImageInformer. Images() ImageInformer + // ImageContentPolicies returns a ImageContentPolicyInformer. + ImageContentPolicies() ImageContentPolicyInformer // Infrastructures returns a InfrastructureInformer. Infrastructures() InfrastructureInformer // Ingresses returns a IngressInformer. @@ -100,6 +102,11 @@ func (v *version) Images() ImageInformer { return &imageInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} } +// ImageContentPolicies returns a ImageContentPolicyInformer. +func (v *version) ImageContentPolicies() ImageContentPolicyInformer { + return &imageContentPolicyInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + // Infrastructures returns a InfrastructureInformer. func (v *version) Infrastructures() InfrastructureInformer { return &infrastructureInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} diff --git a/vendor/github.com/openshift/client-go/config/informers/externalversions/generic.go b/vendor/github.com/openshift/client-go/config/informers/externalversions/generic.go index 2795d10e95..e804d1cde5 100644 --- a/vendor/github.com/openshift/client-go/config/informers/externalversions/generic.go +++ b/vendor/github.com/openshift/client-go/config/informers/externalversions/generic.go @@ -55,6 +55,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Config().V1().FeatureGates().Informer()}, nil case v1.SchemeGroupVersion.WithResource("images"): return &genericInformer{resource: resource.GroupResource(), informer: f.Config().V1().Images().Informer()}, nil + case v1.SchemeGroupVersion.WithResource("imagecontentpolicies"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Config().V1().ImageContentPolicies().Informer()}, nil case v1.SchemeGroupVersion.WithResource("infrastructures"): return &genericInformer{resource: resource.GroupResource(), informer: f.Config().V1().Infrastructures().Informer()}, nil case v1.SchemeGroupVersion.WithResource("ingresses"): diff --git a/vendor/github.com/openshift/client-go/config/listers/config/v1/expansion_generated.go b/vendor/github.com/openshift/client-go/config/listers/config/v1/expansion_generated.go index 56b41a0445..1fbedb4dbb 100644 --- a/vendor/github.com/openshift/client-go/config/listers/config/v1/expansion_generated.go +++ b/vendor/github.com/openshift/client-go/config/listers/config/v1/expansion_generated.go @@ -38,6 +38,10 @@ type FeatureGateListerExpansion interface{} // ImageLister. type ImageListerExpansion interface{} +// ImageContentPolicyListerExpansion allows custom methods to be added to +// ImageContentPolicyLister. +type ImageContentPolicyListerExpansion interface{} + // InfrastructureListerExpansion allows custom methods to be added to // InfrastructureLister. type InfrastructureListerExpansion interface{} diff --git a/vendor/github.com/openshift/client-go/config/listers/config/v1/imagecontentpolicy.go b/vendor/github.com/openshift/client-go/config/listers/config/v1/imagecontentpolicy.go new file mode 100644 index 0000000000..c9dadb9235 --- /dev/null +++ b/vendor/github.com/openshift/client-go/config/listers/config/v1/imagecontentpolicy.go @@ -0,0 +1,52 @@ +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + v1 "github.com/openshift/api/config/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// ImageContentPolicyLister helps list ImageContentPolicies. +// All objects returned here must be treated as read-only. +type ImageContentPolicyLister interface { + // List lists all ImageContentPolicies in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1.ImageContentPolicy, err error) + // Get retrieves the ImageContentPolicy from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1.ImageContentPolicy, error) + ImageContentPolicyListerExpansion +} + +// imageContentPolicyLister implements the ImageContentPolicyLister interface. +type imageContentPolicyLister struct { + indexer cache.Indexer +} + +// NewImageContentPolicyLister returns a new ImageContentPolicyLister. +func NewImageContentPolicyLister(indexer cache.Indexer) ImageContentPolicyLister { + return &imageContentPolicyLister{indexer: indexer} +} + +// List lists all ImageContentPolicies in the indexer. +func (s *imageContentPolicyLister) List(selector labels.Selector) (ret []*v1.ImageContentPolicy, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.ImageContentPolicy)) + }) + return ret, err +} + +// Get retrieves the ImageContentPolicy from the index for a given name. +func (s *imageContentPolicyLister) Get(name string) (*v1.ImageContentPolicy, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("imagecontentpolicy"), name) + } + return obj.(*v1.ImageContentPolicy), nil +} diff --git a/vendor/github.com/openshift/client-go/machine/clientset/versioned/clientset.go b/vendor/github.com/openshift/client-go/machine/clientset/versioned/clientset.go new file mode 100644 index 0000000000..3ac61e7f1e --- /dev/null +++ b/vendor/github.com/openshift/client-go/machine/clientset/versioned/clientset.go @@ -0,0 +1,81 @@ +// Code generated by client-gen. DO NOT EDIT. + +package versioned + +import ( + "fmt" + + machinev1beta1 "github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1" + discovery "k8s.io/client-go/discovery" + rest "k8s.io/client-go/rest" + flowcontrol "k8s.io/client-go/util/flowcontrol" +) + +type Interface interface { + Discovery() discovery.DiscoveryInterface + MachineV1beta1() machinev1beta1.MachineV1beta1Interface +} + +// Clientset contains the clients for groups. Each group has exactly one +// version included in a Clientset. +type Clientset struct { + *discovery.DiscoveryClient + machineV1beta1 *machinev1beta1.MachineV1beta1Client +} + +// MachineV1beta1 retrieves the MachineV1beta1Client +func (c *Clientset) MachineV1beta1() machinev1beta1.MachineV1beta1Interface { + return c.machineV1beta1 +} + +// Discovery retrieves the DiscoveryClient +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + if c == nil { + return nil + } + return c.DiscoveryClient +} + +// NewForConfig creates a new Clientset for the given config. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfig will generate a rate-limiter in configShallowCopy. +func NewForConfig(c *rest.Config) (*Clientset, error) { + configShallowCopy := *c + if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { + if configShallowCopy.Burst <= 0 { + return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") + } + configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) + } + var cs Clientset + var err error + cs.machineV1beta1, err = machinev1beta1.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } + + cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) + if err != nil { + return nil, err + } + return &cs, nil +} + +// NewForConfigOrDie creates a new Clientset for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *Clientset { + var cs Clientset + cs.machineV1beta1 = machinev1beta1.NewForConfigOrDie(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) + return &cs +} + +// New creates a new Clientset for the given RESTClient. +func New(c rest.Interface) *Clientset { + var cs Clientset + cs.machineV1beta1 = machinev1beta1.New(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClient(c) + return &cs +} diff --git a/vendor/github.com/openshift/client-go/machine/clientset/versioned/doc.go b/vendor/github.com/openshift/client-go/machine/clientset/versioned/doc.go new file mode 100644 index 0000000000..0e0c2a8900 --- /dev/null +++ b/vendor/github.com/openshift/client-go/machine/clientset/versioned/doc.go @@ -0,0 +1,4 @@ +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated clientset. +package versioned diff --git a/vendor/github.com/openshift/client-go/machine/clientset/versioned/scheme/doc.go b/vendor/github.com/openshift/client-go/machine/clientset/versioned/scheme/doc.go new file mode 100644 index 0000000000..14db57a58f --- /dev/null +++ b/vendor/github.com/openshift/client-go/machine/clientset/versioned/scheme/doc.go @@ -0,0 +1,4 @@ +// Code generated by client-gen. DO NOT EDIT. + +// This package contains the scheme of the automatically generated clientset. +package scheme diff --git a/vendor/github.com/openshift/client-go/machine/clientset/versioned/scheme/register.go b/vendor/github.com/openshift/client-go/machine/clientset/versioned/scheme/register.go new file mode 100644 index 0000000000..91805c2bbf --- /dev/null +++ b/vendor/github.com/openshift/client-go/machine/clientset/versioned/scheme/register.go @@ -0,0 +1,40 @@ +// Code generated by client-gen. DO NOT EDIT. + +package scheme + +import ( + machinev1beta1 "github.com/openshift/api/machine/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" +) + +var Scheme = runtime.NewScheme() +var Codecs = serializer.NewCodecFactory(Scheme) +var ParameterCodec = runtime.NewParameterCodec(Scheme) +var localSchemeBuilder = runtime.SchemeBuilder{ + machinev1beta1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(Scheme)) +} diff --git a/vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/doc.go b/vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/doc.go new file mode 100644 index 0000000000..897c0995f8 --- /dev/null +++ b/vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/doc.go @@ -0,0 +1,4 @@ +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1beta1 diff --git a/vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/generated_expansion.go b/vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/generated_expansion.go new file mode 100644 index 0000000000..d45fc4afe5 --- /dev/null +++ b/vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/generated_expansion.go @@ -0,0 +1,9 @@ +// Code generated by client-gen. DO NOT EDIT. + +package v1beta1 + +type MachineExpansion interface{} + +type MachineHealthCheckExpansion interface{} + +type MachineSetExpansion interface{} diff --git a/vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/machine.go b/vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/machine.go new file mode 100644 index 0000000000..f67e4ea67c --- /dev/null +++ b/vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/machine.go @@ -0,0 +1,179 @@ +// Code generated by client-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "context" + "time" + + v1beta1 "github.com/openshift/api/machine/v1beta1" + scheme "github.com/openshift/client-go/machine/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// MachinesGetter has a method to return a MachineInterface. +// A group's client should implement this interface. +type MachinesGetter interface { + Machines(namespace string) MachineInterface +} + +// MachineInterface has methods to work with Machine resources. +type MachineInterface interface { + Create(ctx context.Context, machine *v1beta1.Machine, opts v1.CreateOptions) (*v1beta1.Machine, error) + Update(ctx context.Context, machine *v1beta1.Machine, opts v1.UpdateOptions) (*v1beta1.Machine, error) + UpdateStatus(ctx context.Context, machine *v1beta1.Machine, opts v1.UpdateOptions) (*v1beta1.Machine, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1beta1.Machine, error) + List(ctx context.Context, opts v1.ListOptions) (*v1beta1.MachineList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Machine, err error) + MachineExpansion +} + +// machines implements MachineInterface +type machines struct { + client rest.Interface + ns string +} + +// newMachines returns a Machines +func newMachines(c *MachineV1beta1Client, namespace string) *machines { + return &machines{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the machine, and returns the corresponding machine object, and an error if there is any. +func (c *machines) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.Machine, err error) { + result = &v1beta1.Machine{} + err = c.client.Get(). + Namespace(c.ns). + Resource("machines"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Machines that match those selectors. +func (c *machines) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.MachineList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1beta1.MachineList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("machines"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested machines. +func (c *machines) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("machines"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a machine and creates it. Returns the server's representation of the machine, and an error, if there is any. +func (c *machines) Create(ctx context.Context, machine *v1beta1.Machine, opts v1.CreateOptions) (result *v1beta1.Machine, err error) { + result = &v1beta1.Machine{} + err = c.client.Post(). + Namespace(c.ns). + Resource("machines"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(machine). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a machine and updates it. Returns the server's representation of the machine, and an error, if there is any. +func (c *machines) Update(ctx context.Context, machine *v1beta1.Machine, opts v1.UpdateOptions) (result *v1beta1.Machine, err error) { + result = &v1beta1.Machine{} + err = c.client.Put(). + Namespace(c.ns). + Resource("machines"). + Name(machine.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(machine). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *machines) UpdateStatus(ctx context.Context, machine *v1beta1.Machine, opts v1.UpdateOptions) (result *v1beta1.Machine, err error) { + result = &v1beta1.Machine{} + err = c.client.Put(). + Namespace(c.ns). + Resource("machines"). + Name(machine.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(machine). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the machine and deletes it. Returns an error if one occurs. +func (c *machines) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("machines"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *machines) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("machines"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched machine. +func (c *machines) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Machine, err error) { + result = &v1beta1.Machine{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("machines"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/machine_client.go b/vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/machine_client.go new file mode 100644 index 0000000000..8509b25896 --- /dev/null +++ b/vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/machine_client.go @@ -0,0 +1,83 @@ +// Code generated by client-gen. DO NOT EDIT. + +package v1beta1 + +import ( + v1beta1 "github.com/openshift/api/machine/v1beta1" + "github.com/openshift/client-go/machine/clientset/versioned/scheme" + rest "k8s.io/client-go/rest" +) + +type MachineV1beta1Interface interface { + RESTClient() rest.Interface + MachinesGetter + MachineHealthChecksGetter + MachineSetsGetter +} + +// MachineV1beta1Client is used to interact with features provided by the machine.openshift.io group. +type MachineV1beta1Client struct { + restClient rest.Interface +} + +func (c *MachineV1beta1Client) Machines(namespace string) MachineInterface { + return newMachines(c, namespace) +} + +func (c *MachineV1beta1Client) MachineHealthChecks(namespace string) MachineHealthCheckInterface { + return newMachineHealthChecks(c, namespace) +} + +func (c *MachineV1beta1Client) MachineSets(namespace string) MachineSetInterface { + return newMachineSets(c, namespace) +} + +// NewForConfig creates a new MachineV1beta1Client for the given config. +func NewForConfig(c *rest.Config) (*MachineV1beta1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &MachineV1beta1Client{client}, nil +} + +// NewForConfigOrDie creates a new MachineV1beta1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *MachineV1beta1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new MachineV1beta1Client for the given RESTClient. +func New(c rest.Interface) *MachineV1beta1Client { + return &MachineV1beta1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1beta1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *MachineV1beta1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/machinehealthcheck.go b/vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/machinehealthcheck.go new file mode 100644 index 0000000000..2998021571 --- /dev/null +++ b/vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/machinehealthcheck.go @@ -0,0 +1,179 @@ +// Code generated by client-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "context" + "time" + + v1beta1 "github.com/openshift/api/machine/v1beta1" + scheme "github.com/openshift/client-go/machine/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// MachineHealthChecksGetter has a method to return a MachineHealthCheckInterface. +// A group's client should implement this interface. +type MachineHealthChecksGetter interface { + MachineHealthChecks(namespace string) MachineHealthCheckInterface +} + +// MachineHealthCheckInterface has methods to work with MachineHealthCheck resources. +type MachineHealthCheckInterface interface { + Create(ctx context.Context, machineHealthCheck *v1beta1.MachineHealthCheck, opts v1.CreateOptions) (*v1beta1.MachineHealthCheck, error) + Update(ctx context.Context, machineHealthCheck *v1beta1.MachineHealthCheck, opts v1.UpdateOptions) (*v1beta1.MachineHealthCheck, error) + UpdateStatus(ctx context.Context, machineHealthCheck *v1beta1.MachineHealthCheck, opts v1.UpdateOptions) (*v1beta1.MachineHealthCheck, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1beta1.MachineHealthCheck, error) + List(ctx context.Context, opts v1.ListOptions) (*v1beta1.MachineHealthCheckList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.MachineHealthCheck, err error) + MachineHealthCheckExpansion +} + +// machineHealthChecks implements MachineHealthCheckInterface +type machineHealthChecks struct { + client rest.Interface + ns string +} + +// newMachineHealthChecks returns a MachineHealthChecks +func newMachineHealthChecks(c *MachineV1beta1Client, namespace string) *machineHealthChecks { + return &machineHealthChecks{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the machineHealthCheck, and returns the corresponding machineHealthCheck object, and an error if there is any. +func (c *machineHealthChecks) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.MachineHealthCheck, err error) { + result = &v1beta1.MachineHealthCheck{} + err = c.client.Get(). + Namespace(c.ns). + Resource("machinehealthchecks"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of MachineHealthChecks that match those selectors. +func (c *machineHealthChecks) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.MachineHealthCheckList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1beta1.MachineHealthCheckList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("machinehealthchecks"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested machineHealthChecks. +func (c *machineHealthChecks) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("machinehealthchecks"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a machineHealthCheck and creates it. Returns the server's representation of the machineHealthCheck, and an error, if there is any. +func (c *machineHealthChecks) Create(ctx context.Context, machineHealthCheck *v1beta1.MachineHealthCheck, opts v1.CreateOptions) (result *v1beta1.MachineHealthCheck, err error) { + result = &v1beta1.MachineHealthCheck{} + err = c.client.Post(). + Namespace(c.ns). + Resource("machinehealthchecks"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(machineHealthCheck). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a machineHealthCheck and updates it. Returns the server's representation of the machineHealthCheck, and an error, if there is any. +func (c *machineHealthChecks) Update(ctx context.Context, machineHealthCheck *v1beta1.MachineHealthCheck, opts v1.UpdateOptions) (result *v1beta1.MachineHealthCheck, err error) { + result = &v1beta1.MachineHealthCheck{} + err = c.client.Put(). + Namespace(c.ns). + Resource("machinehealthchecks"). + Name(machineHealthCheck.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(machineHealthCheck). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *machineHealthChecks) UpdateStatus(ctx context.Context, machineHealthCheck *v1beta1.MachineHealthCheck, opts v1.UpdateOptions) (result *v1beta1.MachineHealthCheck, err error) { + result = &v1beta1.MachineHealthCheck{} + err = c.client.Put(). + Namespace(c.ns). + Resource("machinehealthchecks"). + Name(machineHealthCheck.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(machineHealthCheck). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the machineHealthCheck and deletes it. Returns an error if one occurs. +func (c *machineHealthChecks) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("machinehealthchecks"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *machineHealthChecks) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("machinehealthchecks"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched machineHealthCheck. +func (c *machineHealthChecks) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.MachineHealthCheck, err error) { + result = &v1beta1.MachineHealthCheck{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("machinehealthchecks"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/machineset.go b/vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/machineset.go new file mode 100644 index 0000000000..0720dea13d --- /dev/null +++ b/vendor/github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1/machineset.go @@ -0,0 +1,179 @@ +// Code generated by client-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "context" + "time" + + v1beta1 "github.com/openshift/api/machine/v1beta1" + scheme "github.com/openshift/client-go/machine/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// MachineSetsGetter has a method to return a MachineSetInterface. +// A group's client should implement this interface. +type MachineSetsGetter interface { + MachineSets(namespace string) MachineSetInterface +} + +// MachineSetInterface has methods to work with MachineSet resources. +type MachineSetInterface interface { + Create(ctx context.Context, machineSet *v1beta1.MachineSet, opts v1.CreateOptions) (*v1beta1.MachineSet, error) + Update(ctx context.Context, machineSet *v1beta1.MachineSet, opts v1.UpdateOptions) (*v1beta1.MachineSet, error) + UpdateStatus(ctx context.Context, machineSet *v1beta1.MachineSet, opts v1.UpdateOptions) (*v1beta1.MachineSet, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1beta1.MachineSet, error) + List(ctx context.Context, opts v1.ListOptions) (*v1beta1.MachineSetList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.MachineSet, err error) + MachineSetExpansion +} + +// machineSets implements MachineSetInterface +type machineSets struct { + client rest.Interface + ns string +} + +// newMachineSets returns a MachineSets +func newMachineSets(c *MachineV1beta1Client, namespace string) *machineSets { + return &machineSets{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the machineSet, and returns the corresponding machineSet object, and an error if there is any. +func (c *machineSets) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.MachineSet, err error) { + result = &v1beta1.MachineSet{} + err = c.client.Get(). + Namespace(c.ns). + Resource("machinesets"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of MachineSets that match those selectors. +func (c *machineSets) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.MachineSetList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1beta1.MachineSetList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("machinesets"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested machineSets. +func (c *machineSets) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("machinesets"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a machineSet and creates it. Returns the server's representation of the machineSet, and an error, if there is any. +func (c *machineSets) Create(ctx context.Context, machineSet *v1beta1.MachineSet, opts v1.CreateOptions) (result *v1beta1.MachineSet, err error) { + result = &v1beta1.MachineSet{} + err = c.client.Post(). + Namespace(c.ns). + Resource("machinesets"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(machineSet). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a machineSet and updates it. Returns the server's representation of the machineSet, and an error, if there is any. +func (c *machineSets) Update(ctx context.Context, machineSet *v1beta1.MachineSet, opts v1.UpdateOptions) (result *v1beta1.MachineSet, err error) { + result = &v1beta1.MachineSet{} + err = c.client.Put(). + Namespace(c.ns). + Resource("machinesets"). + Name(machineSet.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(machineSet). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *machineSets) UpdateStatus(ctx context.Context, machineSet *v1beta1.MachineSet, opts v1.UpdateOptions) (result *v1beta1.MachineSet, err error) { + result = &v1beta1.MachineSet{} + err = c.client.Put(). + Namespace(c.ns). + Resource("machinesets"). + Name(machineSet.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(machineSet). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the machineSet and deletes it. Returns an error if one occurs. +func (c *machineSets) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("machinesets"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *machineSets) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("machinesets"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched machineSet. +func (c *machineSets) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.MachineSet, err error) { + result = &v1beta1.MachineSet{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("machinesets"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/vendor/github.com/openshift/client-go/machine/informers/externalversions/factory.go b/vendor/github.com/openshift/client-go/machine/informers/externalversions/factory.go new file mode 100644 index 0000000000..65711bbedb --- /dev/null +++ b/vendor/github.com/openshift/client-go/machine/informers/externalversions/factory.go @@ -0,0 +1,164 @@ +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + reflect "reflect" + sync "sync" + time "time" + + versioned "github.com/openshift/client-go/machine/clientset/versioned" + internalinterfaces "github.com/openshift/client-go/machine/informers/externalversions/internalinterfaces" + machine "github.com/openshift/client-go/machine/informers/externalversions/machine" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" +) + +// SharedInformerOption defines the functional option type for SharedInformerFactory. +type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory + +type sharedInformerFactory struct { + client versioned.Interface + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc + lock sync.Mutex + defaultResync time.Duration + customResync map[reflect.Type]time.Duration + + informers map[reflect.Type]cache.SharedIndexInformer + // startedInformers is used for tracking which informers have been started. + // This allows Start() to be called multiple times safely. + startedInformers map[reflect.Type]bool +} + +// WithCustomResyncConfig sets a custom resync period for the specified informer types. +func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + for k, v := range resyncConfig { + factory.customResync[reflect.TypeOf(k)] = v + } + return factory + } +} + +// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. +func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.tweakListOptions = tweakListOptions + return factory + } +} + +// WithNamespace limits the SharedInformerFactory to the specified namespace. +func WithNamespace(namespace string) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.namespace = namespace + return factory + } +} + +// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. +func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync) +} + +// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. +// Listers obtained via this SharedInformerFactory will be subject to the same filters +// as specified here. +// Deprecated: Please use NewSharedInformerFactoryWithOptions instead +func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) +} + +// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. +func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { + factory := &sharedInformerFactory{ + client: client, + namespace: v1.NamespaceAll, + defaultResync: defaultResync, + informers: make(map[reflect.Type]cache.SharedIndexInformer), + startedInformers: make(map[reflect.Type]bool), + customResync: make(map[reflect.Type]time.Duration), + } + + // Apply all options + for _, opt := range options { + factory = opt(factory) + } + + return factory +} + +// Start initializes all requested informers. +func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { + f.lock.Lock() + defer f.lock.Unlock() + + for informerType, informer := range f.informers { + if !f.startedInformers[informerType] { + go informer.Run(stopCh) + f.startedInformers[informerType] = true + } + } +} + +// WaitForCacheSync waits for all started informers' cache were synced. +func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { + informers := func() map[reflect.Type]cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informers := map[reflect.Type]cache.SharedIndexInformer{} + for informerType, informer := range f.informers { + if f.startedInformers[informerType] { + informers[informerType] = informer + } + } + return informers + }() + + res := map[reflect.Type]bool{} + for informType, informer := range informers { + res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) + } + return res +} + +// InternalInformerFor returns the SharedIndexInformer for obj using an internal +// client. +func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informerType := reflect.TypeOf(obj) + informer, exists := f.informers[informerType] + if exists { + return informer + } + + resyncPeriod, exists := f.customResync[informerType] + if !exists { + resyncPeriod = f.defaultResync + } + + informer = newFunc(f.client, resyncPeriod) + f.informers[informerType] = informer + + return informer +} + +// SharedInformerFactory provides shared informers for resources in all known +// API group versions. +type SharedInformerFactory interface { + internalinterfaces.SharedInformerFactory + ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + + Machine() machine.Interface +} + +func (f *sharedInformerFactory) Machine() machine.Interface { + return machine.New(f, f.namespace, f.tweakListOptions) +} diff --git a/vendor/github.com/openshift/client-go/machine/informers/externalversions/generic.go b/vendor/github.com/openshift/client-go/machine/informers/externalversions/generic.go new file mode 100644 index 0000000000..0b75c45992 --- /dev/null +++ b/vendor/github.com/openshift/client-go/machine/informers/externalversions/generic.go @@ -0,0 +1,50 @@ +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + "fmt" + + v1beta1 "github.com/openshift/api/machine/v1beta1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" +) + +// GenericInformer is type of SharedIndexInformer which will locate and delegate to other +// sharedInformers based on type +type GenericInformer interface { + Informer() cache.SharedIndexInformer + Lister() cache.GenericLister +} + +type genericInformer struct { + informer cache.SharedIndexInformer + resource schema.GroupResource +} + +// Informer returns the SharedIndexInformer. +func (f *genericInformer) Informer() cache.SharedIndexInformer { + return f.informer +} + +// Lister returns the GenericLister. +func (f *genericInformer) Lister() cache.GenericLister { + return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) +} + +// ForResource gives generic access to a shared informer of the matching type +// TODO extend this to unknown resources with a client pool +func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { + switch resource { + // Group=machine.openshift.io, Version=v1beta1 + case v1beta1.SchemeGroupVersion.WithResource("machines"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Machine().V1beta1().Machines().Informer()}, nil + case v1beta1.SchemeGroupVersion.WithResource("machinehealthchecks"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Machine().V1beta1().MachineHealthChecks().Informer()}, nil + case v1beta1.SchemeGroupVersion.WithResource("machinesets"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Machine().V1beta1().MachineSets().Informer()}, nil + + } + + return nil, fmt.Errorf("no informer found for %v", resource) +} diff --git a/vendor/github.com/openshift/client-go/machine/informers/externalversions/internalinterfaces/factory_interfaces.go b/vendor/github.com/openshift/client-go/machine/informers/externalversions/internalinterfaces/factory_interfaces.go new file mode 100644 index 0000000000..d777be27e1 --- /dev/null +++ b/vendor/github.com/openshift/client-go/machine/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -0,0 +1,24 @@ +// Code generated by informer-gen. DO NOT EDIT. + +package internalinterfaces + +import ( + time "time" + + versioned "github.com/openshift/client-go/machine/clientset/versioned" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + cache "k8s.io/client-go/tools/cache" +) + +// NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. +type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer + +// SharedInformerFactory a small interface to allow for adding an informer without an import cycle +type SharedInformerFactory interface { + Start(stopCh <-chan struct{}) + InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer +} + +// TweakListOptionsFunc is a function that transforms a v1.ListOptions. +type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/vendor/github.com/openshift/client-go/machine/informers/externalversions/machine/interface.go b/vendor/github.com/openshift/client-go/machine/informers/externalversions/machine/interface.go new file mode 100644 index 0000000000..af7fdc42ee --- /dev/null +++ b/vendor/github.com/openshift/client-go/machine/informers/externalversions/machine/interface.go @@ -0,0 +1,30 @@ +// Code generated by informer-gen. DO NOT EDIT. + +package machine + +import ( + internalinterfaces "github.com/openshift/client-go/machine/informers/externalversions/internalinterfaces" + v1beta1 "github.com/openshift/client-go/machine/informers/externalversions/machine/v1beta1" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1beta1 provides access to shared informers for resources in V1beta1. + V1beta1() v1beta1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1beta1 returns a new v1beta1.Interface. +func (g *group) V1beta1() v1beta1.Interface { + return v1beta1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/vendor/github.com/openshift/client-go/machine/informers/externalversions/machine/v1beta1/interface.go b/vendor/github.com/openshift/client-go/machine/informers/externalversions/machine/v1beta1/interface.go new file mode 100644 index 0000000000..7c9f54eb93 --- /dev/null +++ b/vendor/github.com/openshift/client-go/machine/informers/externalversions/machine/v1beta1/interface.go @@ -0,0 +1,43 @@ +// Code generated by informer-gen. DO NOT EDIT. + +package v1beta1 + +import ( + internalinterfaces "github.com/openshift/client-go/machine/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // Machines returns a MachineInformer. + Machines() MachineInformer + // MachineHealthChecks returns a MachineHealthCheckInformer. + MachineHealthChecks() MachineHealthCheckInformer + // MachineSets returns a MachineSetInformer. + MachineSets() MachineSetInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// Machines returns a MachineInformer. +func (v *version) Machines() MachineInformer { + return &machineInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + +// MachineHealthChecks returns a MachineHealthCheckInformer. +func (v *version) MachineHealthChecks() MachineHealthCheckInformer { + return &machineHealthCheckInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + +// MachineSets returns a MachineSetInformer. +func (v *version) MachineSets() MachineSetInformer { + return &machineSetInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/vendor/github.com/openshift/client-go/machine/informers/externalversions/machine/v1beta1/machine.go b/vendor/github.com/openshift/client-go/machine/informers/externalversions/machine/v1beta1/machine.go new file mode 100644 index 0000000000..c943acffb7 --- /dev/null +++ b/vendor/github.com/openshift/client-go/machine/informers/externalversions/machine/v1beta1/machine.go @@ -0,0 +1,74 @@ +// Code generated by informer-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "context" + time "time" + + machinev1beta1 "github.com/openshift/api/machine/v1beta1" + versioned "github.com/openshift/client-go/machine/clientset/versioned" + internalinterfaces "github.com/openshift/client-go/machine/informers/externalversions/internalinterfaces" + v1beta1 "github.com/openshift/client-go/machine/listers/machine/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// MachineInformer provides access to a shared informer and lister for +// Machines. +type MachineInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1beta1.MachineLister +} + +type machineInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewMachineInformer constructs a new informer for Machine type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewMachineInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredMachineInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredMachineInformer constructs a new informer for Machine type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredMachineInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.MachineV1beta1().Machines(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.MachineV1beta1().Machines(namespace).Watch(context.TODO(), options) + }, + }, + &machinev1beta1.Machine{}, + resyncPeriod, + indexers, + ) +} + +func (f *machineInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredMachineInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *machineInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&machinev1beta1.Machine{}, f.defaultInformer) +} + +func (f *machineInformer) Lister() v1beta1.MachineLister { + return v1beta1.NewMachineLister(f.Informer().GetIndexer()) +} diff --git a/vendor/github.com/openshift/client-go/machine/informers/externalversions/machine/v1beta1/machinehealthcheck.go b/vendor/github.com/openshift/client-go/machine/informers/externalversions/machine/v1beta1/machinehealthcheck.go new file mode 100644 index 0000000000..534bcb3730 --- /dev/null +++ b/vendor/github.com/openshift/client-go/machine/informers/externalversions/machine/v1beta1/machinehealthcheck.go @@ -0,0 +1,74 @@ +// Code generated by informer-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "context" + time "time" + + machinev1beta1 "github.com/openshift/api/machine/v1beta1" + versioned "github.com/openshift/client-go/machine/clientset/versioned" + internalinterfaces "github.com/openshift/client-go/machine/informers/externalversions/internalinterfaces" + v1beta1 "github.com/openshift/client-go/machine/listers/machine/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// MachineHealthCheckInformer provides access to a shared informer and lister for +// MachineHealthChecks. +type MachineHealthCheckInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1beta1.MachineHealthCheckLister +} + +type machineHealthCheckInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewMachineHealthCheckInformer constructs a new informer for MachineHealthCheck type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewMachineHealthCheckInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredMachineHealthCheckInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredMachineHealthCheckInformer constructs a new informer for MachineHealthCheck type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredMachineHealthCheckInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.MachineV1beta1().MachineHealthChecks(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.MachineV1beta1().MachineHealthChecks(namespace).Watch(context.TODO(), options) + }, + }, + &machinev1beta1.MachineHealthCheck{}, + resyncPeriod, + indexers, + ) +} + +func (f *machineHealthCheckInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredMachineHealthCheckInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *machineHealthCheckInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&machinev1beta1.MachineHealthCheck{}, f.defaultInformer) +} + +func (f *machineHealthCheckInformer) Lister() v1beta1.MachineHealthCheckLister { + return v1beta1.NewMachineHealthCheckLister(f.Informer().GetIndexer()) +} diff --git a/vendor/github.com/openshift/client-go/machine/informers/externalversions/machine/v1beta1/machineset.go b/vendor/github.com/openshift/client-go/machine/informers/externalversions/machine/v1beta1/machineset.go new file mode 100644 index 0000000000..62ffcfbc55 --- /dev/null +++ b/vendor/github.com/openshift/client-go/machine/informers/externalversions/machine/v1beta1/machineset.go @@ -0,0 +1,74 @@ +// Code generated by informer-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "context" + time "time" + + machinev1beta1 "github.com/openshift/api/machine/v1beta1" + versioned "github.com/openshift/client-go/machine/clientset/versioned" + internalinterfaces "github.com/openshift/client-go/machine/informers/externalversions/internalinterfaces" + v1beta1 "github.com/openshift/client-go/machine/listers/machine/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// MachineSetInformer provides access to a shared informer and lister for +// MachineSets. +type MachineSetInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1beta1.MachineSetLister +} + +type machineSetInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewMachineSetInformer constructs a new informer for MachineSet type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewMachineSetInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredMachineSetInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredMachineSetInformer constructs a new informer for MachineSet type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredMachineSetInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.MachineV1beta1().MachineSets(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.MachineV1beta1().MachineSets(namespace).Watch(context.TODO(), options) + }, + }, + &machinev1beta1.MachineSet{}, + resyncPeriod, + indexers, + ) +} + +func (f *machineSetInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredMachineSetInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *machineSetInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&machinev1beta1.MachineSet{}, f.defaultInformer) +} + +func (f *machineSetInformer) Lister() v1beta1.MachineSetLister { + return v1beta1.NewMachineSetLister(f.Informer().GetIndexer()) +} diff --git a/vendor/github.com/openshift/client-go/machine/listers/machine/v1beta1/expansion_generated.go b/vendor/github.com/openshift/client-go/machine/listers/machine/v1beta1/expansion_generated.go new file mode 100644 index 0000000000..777f3e3c8b --- /dev/null +++ b/vendor/github.com/openshift/client-go/machine/listers/machine/v1beta1/expansion_generated.go @@ -0,0 +1,27 @@ +// Code generated by lister-gen. DO NOT EDIT. + +package v1beta1 + +// MachineListerExpansion allows custom methods to be added to +// MachineLister. +type MachineListerExpansion interface{} + +// MachineNamespaceListerExpansion allows custom methods to be added to +// MachineNamespaceLister. +type MachineNamespaceListerExpansion interface{} + +// MachineHealthCheckListerExpansion allows custom methods to be added to +// MachineHealthCheckLister. +type MachineHealthCheckListerExpansion interface{} + +// MachineHealthCheckNamespaceListerExpansion allows custom methods to be added to +// MachineHealthCheckNamespaceLister. +type MachineHealthCheckNamespaceListerExpansion interface{} + +// MachineSetListerExpansion allows custom methods to be added to +// MachineSetLister. +type MachineSetListerExpansion interface{} + +// MachineSetNamespaceListerExpansion allows custom methods to be added to +// MachineSetNamespaceLister. +type MachineSetNamespaceListerExpansion interface{} diff --git a/vendor/github.com/openshift/client-go/machine/listers/machine/v1beta1/machine.go b/vendor/github.com/openshift/client-go/machine/listers/machine/v1beta1/machine.go new file mode 100644 index 0000000000..3b4cb164be --- /dev/null +++ b/vendor/github.com/openshift/client-go/machine/listers/machine/v1beta1/machine.go @@ -0,0 +1,83 @@ +// Code generated by lister-gen. DO NOT EDIT. + +package v1beta1 + +import ( + v1beta1 "github.com/openshift/api/machine/v1beta1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// MachineLister helps list Machines. +// All objects returned here must be treated as read-only. +type MachineLister interface { + // List lists all Machines in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1beta1.Machine, err error) + // Machines returns an object that can list and get Machines. + Machines(namespace string) MachineNamespaceLister + MachineListerExpansion +} + +// machineLister implements the MachineLister interface. +type machineLister struct { + indexer cache.Indexer +} + +// NewMachineLister returns a new MachineLister. +func NewMachineLister(indexer cache.Indexer) MachineLister { + return &machineLister{indexer: indexer} +} + +// List lists all Machines in the indexer. +func (s *machineLister) List(selector labels.Selector) (ret []*v1beta1.Machine, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1beta1.Machine)) + }) + return ret, err +} + +// Machines returns an object that can list and get Machines. +func (s *machineLister) Machines(namespace string) MachineNamespaceLister { + return machineNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// MachineNamespaceLister helps list and get Machines. +// All objects returned here must be treated as read-only. +type MachineNamespaceLister interface { + // List lists all Machines in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1beta1.Machine, err error) + // Get retrieves the Machine from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1beta1.Machine, error) + MachineNamespaceListerExpansion +} + +// machineNamespaceLister implements the MachineNamespaceLister +// interface. +type machineNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Machines in the indexer for a given namespace. +func (s machineNamespaceLister) List(selector labels.Selector) (ret []*v1beta1.Machine, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1beta1.Machine)) + }) + return ret, err +} + +// Get retrieves the Machine from the indexer for a given namespace and name. +func (s machineNamespaceLister) Get(name string) (*v1beta1.Machine, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1beta1.Resource("machine"), name) + } + return obj.(*v1beta1.Machine), nil +} diff --git a/vendor/github.com/openshift/client-go/machine/listers/machine/v1beta1/machinehealthcheck.go b/vendor/github.com/openshift/client-go/machine/listers/machine/v1beta1/machinehealthcheck.go new file mode 100644 index 0000000000..fea0af7ccd --- /dev/null +++ b/vendor/github.com/openshift/client-go/machine/listers/machine/v1beta1/machinehealthcheck.go @@ -0,0 +1,83 @@ +// Code generated by lister-gen. DO NOT EDIT. + +package v1beta1 + +import ( + v1beta1 "github.com/openshift/api/machine/v1beta1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// MachineHealthCheckLister helps list MachineHealthChecks. +// All objects returned here must be treated as read-only. +type MachineHealthCheckLister interface { + // List lists all MachineHealthChecks in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1beta1.MachineHealthCheck, err error) + // MachineHealthChecks returns an object that can list and get MachineHealthChecks. + MachineHealthChecks(namespace string) MachineHealthCheckNamespaceLister + MachineHealthCheckListerExpansion +} + +// machineHealthCheckLister implements the MachineHealthCheckLister interface. +type machineHealthCheckLister struct { + indexer cache.Indexer +} + +// NewMachineHealthCheckLister returns a new MachineHealthCheckLister. +func NewMachineHealthCheckLister(indexer cache.Indexer) MachineHealthCheckLister { + return &machineHealthCheckLister{indexer: indexer} +} + +// List lists all MachineHealthChecks in the indexer. +func (s *machineHealthCheckLister) List(selector labels.Selector) (ret []*v1beta1.MachineHealthCheck, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1beta1.MachineHealthCheck)) + }) + return ret, err +} + +// MachineHealthChecks returns an object that can list and get MachineHealthChecks. +func (s *machineHealthCheckLister) MachineHealthChecks(namespace string) MachineHealthCheckNamespaceLister { + return machineHealthCheckNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// MachineHealthCheckNamespaceLister helps list and get MachineHealthChecks. +// All objects returned here must be treated as read-only. +type MachineHealthCheckNamespaceLister interface { + // List lists all MachineHealthChecks in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1beta1.MachineHealthCheck, err error) + // Get retrieves the MachineHealthCheck from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1beta1.MachineHealthCheck, error) + MachineHealthCheckNamespaceListerExpansion +} + +// machineHealthCheckNamespaceLister implements the MachineHealthCheckNamespaceLister +// interface. +type machineHealthCheckNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all MachineHealthChecks in the indexer for a given namespace. +func (s machineHealthCheckNamespaceLister) List(selector labels.Selector) (ret []*v1beta1.MachineHealthCheck, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1beta1.MachineHealthCheck)) + }) + return ret, err +} + +// Get retrieves the MachineHealthCheck from the indexer for a given namespace and name. +func (s machineHealthCheckNamespaceLister) Get(name string) (*v1beta1.MachineHealthCheck, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1beta1.Resource("machinehealthcheck"), name) + } + return obj.(*v1beta1.MachineHealthCheck), nil +} diff --git a/vendor/github.com/openshift/client-go/machine/listers/machine/v1beta1/machineset.go b/vendor/github.com/openshift/client-go/machine/listers/machine/v1beta1/machineset.go new file mode 100644 index 0000000000..5ff65b657d --- /dev/null +++ b/vendor/github.com/openshift/client-go/machine/listers/machine/v1beta1/machineset.go @@ -0,0 +1,83 @@ +// Code generated by lister-gen. DO NOT EDIT. + +package v1beta1 + +import ( + v1beta1 "github.com/openshift/api/machine/v1beta1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// MachineSetLister helps list MachineSets. +// All objects returned here must be treated as read-only. +type MachineSetLister interface { + // List lists all MachineSets in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1beta1.MachineSet, err error) + // MachineSets returns an object that can list and get MachineSets. + MachineSets(namespace string) MachineSetNamespaceLister + MachineSetListerExpansion +} + +// machineSetLister implements the MachineSetLister interface. +type machineSetLister struct { + indexer cache.Indexer +} + +// NewMachineSetLister returns a new MachineSetLister. +func NewMachineSetLister(indexer cache.Indexer) MachineSetLister { + return &machineSetLister{indexer: indexer} +} + +// List lists all MachineSets in the indexer. +func (s *machineSetLister) List(selector labels.Selector) (ret []*v1beta1.MachineSet, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1beta1.MachineSet)) + }) + return ret, err +} + +// MachineSets returns an object that can list and get MachineSets. +func (s *machineSetLister) MachineSets(namespace string) MachineSetNamespaceLister { + return machineSetNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// MachineSetNamespaceLister helps list and get MachineSets. +// All objects returned here must be treated as read-only. +type MachineSetNamespaceLister interface { + // List lists all MachineSets in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1beta1.MachineSet, err error) + // Get retrieves the MachineSet from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1beta1.MachineSet, error) + MachineSetNamespaceListerExpansion +} + +// machineSetNamespaceLister implements the MachineSetNamespaceLister +// interface. +type machineSetNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all MachineSets in the indexer for a given namespace. +func (s machineSetNamespaceLister) List(selector labels.Selector) (ret []*v1beta1.MachineSet, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1beta1.MachineSet)) + }) + return ret, err +} + +// Get retrieves the MachineSet from the indexer for a given namespace and name. +func (s machineSetNamespaceLister) Get(name string) (*v1beta1.MachineSet, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1beta1.Resource("machineset"), name) + } + return obj.(*v1beta1.MachineSet), nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 82e1f01641..8077af5f84 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -216,7 +216,7 @@ github.com/openshift/api/template github.com/openshift/api/template/v1 github.com/openshift/api/user github.com/openshift/api/user/v1 -# github.com/openshift/client-go v0.0.0-20210730113412-1811c1b3fc0e +# github.com/openshift/client-go v0.0.0-20211025111749-96ca2abfc56c ## explicit github.com/openshift/client-go/config/clientset/versioned github.com/openshift/client-go/config/clientset/versioned/fake @@ -228,6 +228,14 @@ github.com/openshift/client-go/config/informers/externalversions/config github.com/openshift/client-go/config/informers/externalversions/config/v1 github.com/openshift/client-go/config/informers/externalversions/internalinterfaces github.com/openshift/client-go/config/listers/config/v1 +github.com/openshift/client-go/machine/clientset/versioned +github.com/openshift/client-go/machine/clientset/versioned/scheme +github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1 +github.com/openshift/client-go/machine/informers/externalversions +github.com/openshift/client-go/machine/informers/externalversions/internalinterfaces +github.com/openshift/client-go/machine/informers/externalversions/machine +github.com/openshift/client-go/machine/informers/externalversions/machine/v1beta1 +github.com/openshift/client-go/machine/listers/machine/v1beta1 # github.com/openshift/library-go v0.0.0-20210811133500-5e31383de2a7 ## explicit github.com/openshift/library-go/pkg/config/clusteroperator/v1helpers @@ -444,6 +452,7 @@ gopkg.in/tomb.v1 ## explicit gopkg.in/warnings.v0 # gopkg.in/yaml.v2 v2.4.0 +## explicit gopkg.in/yaml.v2 # gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b gopkg.in/yaml.v3 @@ -569,7 +578,7 @@ k8s.io/apiserver/pkg/storage/names k8s.io/cli-runtime/pkg/genericclioptions k8s.io/cli-runtime/pkg/printers k8s.io/cli-runtime/pkg/resource -# k8s.io/client-go v0.22.0 +# k8s.io/client-go v0.22.1 ## explicit k8s.io/client-go/applyconfigurations/admissionregistration/v1 k8s.io/client-go/applyconfigurations/admissionregistration/v1beta1 From 6602a0dae3f1bd86f8440172182edfb225f71eb7 Mon Sep 17 00:00:00 2001 From: Alexander Demichev Date: Tue, 26 Oct 2021 19:53:16 +0200 Subject: [PATCH 02/10] Remove generated client --- .../clientset/versioned/clientset.go | 97 --------- pkg/generated/clientset/versioned/doc.go | 20 -- .../versioned/fake/clientset_generated.go | 85 -------- pkg/generated/clientset/versioned/fake/doc.go | 20 -- .../clientset/versioned/fake/register.go | 56 ----- .../clientset/versioned/scheme/doc.go | 20 -- .../clientset/versioned/scheme/register.go | 56 ----- .../versioned/typed/machine/v1beta1/doc.go | 20 -- .../typed/machine/v1beta1/fake/doc.go | 20 -- .../machine/v1beta1/fake/fake_machine.go | 142 ------------- .../v1beta1/fake/fake_machine_client.go | 48 ----- .../v1beta1/fake/fake_machinehealthcheck.go | 142 ------------- .../machine/v1beta1/fake/fake_machineset.go | 142 ------------- .../machine/v1beta1/generated_expansion.go | 25 --- .../typed/machine/v1beta1/machine.go | 195 ------------------ .../typed/machine/v1beta1/machine_client.go | 99 --------- .../machine/v1beta1/machinehealthcheck.go | 195 ------------------ .../typed/machine/v1beta1/machineset.go | 195 ------------------ .../informers/externalversions/factory.go | 180 ---------------- .../informers/externalversions/generic.go | 66 ------ .../internalinterfaces/factory_interfaces.go | 40 ---- .../externalversions/machine/interface.go | 46 ----- .../machine/v1beta1/interface.go | 59 ------ .../machine/v1beta1/machine.go | 90 -------- .../machine/v1beta1/machinehealthcheck.go | 90 -------- .../machine/v1beta1/machineset.go | 90 -------- .../machine/v1beta1/expansion_generated.go | 43 ---- .../listers/machine/v1beta1/machine.go | 99 --------- .../machine/v1beta1/machinehealthcheck.go | 99 --------- .../listers/machine/v1beta1/machineset.go | 99 --------- 30 files changed, 2578 deletions(-) delete mode 100644 pkg/generated/clientset/versioned/clientset.go delete mode 100644 pkg/generated/clientset/versioned/doc.go delete mode 100644 pkg/generated/clientset/versioned/fake/clientset_generated.go delete mode 100644 pkg/generated/clientset/versioned/fake/doc.go delete mode 100644 pkg/generated/clientset/versioned/fake/register.go delete mode 100644 pkg/generated/clientset/versioned/scheme/doc.go delete mode 100644 pkg/generated/clientset/versioned/scheme/register.go delete mode 100644 pkg/generated/clientset/versioned/typed/machine/v1beta1/doc.go delete mode 100644 pkg/generated/clientset/versioned/typed/machine/v1beta1/fake/doc.go delete mode 100644 pkg/generated/clientset/versioned/typed/machine/v1beta1/fake/fake_machine.go delete mode 100644 pkg/generated/clientset/versioned/typed/machine/v1beta1/fake/fake_machine_client.go delete mode 100644 pkg/generated/clientset/versioned/typed/machine/v1beta1/fake/fake_machinehealthcheck.go delete mode 100644 pkg/generated/clientset/versioned/typed/machine/v1beta1/fake/fake_machineset.go delete mode 100644 pkg/generated/clientset/versioned/typed/machine/v1beta1/generated_expansion.go delete mode 100644 pkg/generated/clientset/versioned/typed/machine/v1beta1/machine.go delete mode 100644 pkg/generated/clientset/versioned/typed/machine/v1beta1/machine_client.go delete mode 100644 pkg/generated/clientset/versioned/typed/machine/v1beta1/machinehealthcheck.go delete mode 100644 pkg/generated/clientset/versioned/typed/machine/v1beta1/machineset.go delete mode 100644 pkg/generated/informers/externalversions/factory.go delete mode 100644 pkg/generated/informers/externalversions/generic.go delete mode 100644 pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go delete mode 100644 pkg/generated/informers/externalversions/machine/interface.go delete mode 100644 pkg/generated/informers/externalversions/machine/v1beta1/interface.go delete mode 100644 pkg/generated/informers/externalversions/machine/v1beta1/machine.go delete mode 100644 pkg/generated/informers/externalversions/machine/v1beta1/machinehealthcheck.go delete mode 100644 pkg/generated/informers/externalversions/machine/v1beta1/machineset.go delete mode 100644 pkg/generated/listers/machine/v1beta1/expansion_generated.go delete mode 100644 pkg/generated/listers/machine/v1beta1/machine.go delete mode 100644 pkg/generated/listers/machine/v1beta1/machinehealthcheck.go delete mode 100644 pkg/generated/listers/machine/v1beta1/machineset.go diff --git a/pkg/generated/clientset/versioned/clientset.go b/pkg/generated/clientset/versioned/clientset.go deleted file mode 100644 index 07b9a63358..0000000000 --- a/pkg/generated/clientset/versioned/clientset.go +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by client-gen. DO NOT EDIT. - -package versioned - -import ( - "fmt" - - machinev1beta1 "github.com/openshift/machine-api-operator/pkg/generated/clientset/versioned/typed/machine/v1beta1" - discovery "k8s.io/client-go/discovery" - rest "k8s.io/client-go/rest" - flowcontrol "k8s.io/client-go/util/flowcontrol" -) - -type Interface interface { - Discovery() discovery.DiscoveryInterface - MachineV1beta1() machinev1beta1.MachineV1beta1Interface -} - -// Clientset contains the clients for groups. Each group has exactly one -// version included in a Clientset. -type Clientset struct { - *discovery.DiscoveryClient - machineV1beta1 *machinev1beta1.MachineV1beta1Client -} - -// MachineV1beta1 retrieves the MachineV1beta1Client -func (c *Clientset) MachineV1beta1() machinev1beta1.MachineV1beta1Interface { - return c.machineV1beta1 -} - -// Discovery retrieves the DiscoveryClient -func (c *Clientset) Discovery() discovery.DiscoveryInterface { - if c == nil { - return nil - } - return c.DiscoveryClient -} - -// NewForConfig creates a new Clientset for the given config. -// If config's RateLimiter is not set and QPS and Burst are acceptable, -// NewForConfig will generate a rate-limiter in configShallowCopy. -func NewForConfig(c *rest.Config) (*Clientset, error) { - configShallowCopy := *c - if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { - if configShallowCopy.Burst <= 0 { - return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") - } - configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) - } - var cs Clientset - var err error - cs.machineV1beta1, err = machinev1beta1.NewForConfig(&configShallowCopy) - if err != nil { - return nil, err - } - - cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) - if err != nil { - return nil, err - } - return &cs, nil -} - -// NewForConfigOrDie creates a new Clientset for the given config and -// panics if there is an error in the config. -func NewForConfigOrDie(c *rest.Config) *Clientset { - var cs Clientset - cs.machineV1beta1 = machinev1beta1.NewForConfigOrDie(c) - - cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) - return &cs -} - -// New creates a new Clientset for the given RESTClient. -func New(c rest.Interface) *Clientset { - var cs Clientset - cs.machineV1beta1 = machinev1beta1.New(c) - - cs.DiscoveryClient = discovery.NewDiscoveryClient(c) - return &cs -} diff --git a/pkg/generated/clientset/versioned/doc.go b/pkg/generated/clientset/versioned/doc.go deleted file mode 100644 index 955e667a69..0000000000 --- a/pkg/generated/clientset/versioned/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated clientset. -package versioned diff --git a/pkg/generated/clientset/versioned/fake/clientset_generated.go b/pkg/generated/clientset/versioned/fake/clientset_generated.go deleted file mode 100644 index 0d3991405f..0000000000 --- a/pkg/generated/clientset/versioned/fake/clientset_generated.go +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - clientset "github.com/openshift/machine-api-operator/pkg/generated/clientset/versioned" - machinev1beta1 "github.com/openshift/machine-api-operator/pkg/generated/clientset/versioned/typed/machine/v1beta1" - fakemachinev1beta1 "github.com/openshift/machine-api-operator/pkg/generated/clientset/versioned/typed/machine/v1beta1/fake" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/client-go/discovery" - fakediscovery "k8s.io/client-go/discovery/fake" - "k8s.io/client-go/testing" -) - -// NewSimpleClientset returns a clientset that will respond with the provided objects. -// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, -// without applying any validations and/or defaults. It shouldn't be considered a replacement -// for a real clientset and is mostly useful in simple unit tests. -func NewSimpleClientset(objects ...runtime.Object) *Clientset { - o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) - for _, obj := range objects { - if err := o.Add(obj); err != nil { - panic(err) - } - } - - cs := &Clientset{tracker: o} - cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} - cs.AddReactor("*", "*", testing.ObjectReaction(o)) - cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { - gvr := action.GetResource() - ns := action.GetNamespace() - watch, err := o.Watch(gvr, ns) - if err != nil { - return false, nil, err - } - return true, watch, nil - }) - - return cs -} - -// Clientset implements clientset.Interface. Meant to be embedded into a -// struct to get a default implementation. This makes faking out just the method -// you want to test easier. -type Clientset struct { - testing.Fake - discovery *fakediscovery.FakeDiscovery - tracker testing.ObjectTracker -} - -func (c *Clientset) Discovery() discovery.DiscoveryInterface { - return c.discovery -} - -func (c *Clientset) Tracker() testing.ObjectTracker { - return c.tracker -} - -var ( - _ clientset.Interface = &Clientset{} - _ testing.FakeClient = &Clientset{} -) - -// MachineV1beta1 retrieves the MachineV1beta1Client -func (c *Clientset) MachineV1beta1() machinev1beta1.MachineV1beta1Interface { - return &fakemachinev1beta1.FakeMachineV1beta1{Fake: &c.Fake} -} diff --git a/pkg/generated/clientset/versioned/fake/doc.go b/pkg/generated/clientset/versioned/fake/doc.go deleted file mode 100644 index e38bd9f036..0000000000 --- a/pkg/generated/clientset/versioned/fake/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated fake clientset. -package fake diff --git a/pkg/generated/clientset/versioned/fake/register.go b/pkg/generated/clientset/versioned/fake/register.go deleted file mode 100644 index cf13c200b7..0000000000 --- a/pkg/generated/clientset/versioned/fake/register.go +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - machinev1beta1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - schema "k8s.io/apimachinery/pkg/runtime/schema" - serializer "k8s.io/apimachinery/pkg/runtime/serializer" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" -) - -var scheme = runtime.NewScheme() -var codecs = serializer.NewCodecFactory(scheme) - -var localSchemeBuilder = runtime.SchemeBuilder{ - machinev1beta1.AddToScheme, -} - -// AddToScheme adds all types of this clientset into the given scheme. This allows composition -// of clientsets, like in: -// -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) -// -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) -// -// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types -// correctly. -var AddToScheme = localSchemeBuilder.AddToScheme - -func init() { - v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) - utilruntime.Must(AddToScheme(scheme)) -} diff --git a/pkg/generated/clientset/versioned/scheme/doc.go b/pkg/generated/clientset/versioned/scheme/doc.go deleted file mode 100644 index 35df78e9c4..0000000000 --- a/pkg/generated/clientset/versioned/scheme/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by client-gen. DO NOT EDIT. - -// This package contains the scheme of the automatically generated clientset. -package scheme diff --git a/pkg/generated/clientset/versioned/scheme/register.go b/pkg/generated/clientset/versioned/scheme/register.go deleted file mode 100644 index 6d21458f1a..0000000000 --- a/pkg/generated/clientset/versioned/scheme/register.go +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by client-gen. DO NOT EDIT. - -package scheme - -import ( - machinev1beta1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - schema "k8s.io/apimachinery/pkg/runtime/schema" - serializer "k8s.io/apimachinery/pkg/runtime/serializer" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" -) - -var Scheme = runtime.NewScheme() -var Codecs = serializer.NewCodecFactory(Scheme) -var ParameterCodec = runtime.NewParameterCodec(Scheme) -var localSchemeBuilder = runtime.SchemeBuilder{ - machinev1beta1.AddToScheme, -} - -// AddToScheme adds all types of this clientset into the given scheme. This allows composition -// of clientsets, like in: -// -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) -// -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) -// -// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types -// correctly. -var AddToScheme = localSchemeBuilder.AddToScheme - -func init() { - v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) - utilruntime.Must(AddToScheme(Scheme)) -} diff --git a/pkg/generated/clientset/versioned/typed/machine/v1beta1/doc.go b/pkg/generated/clientset/versioned/typed/machine/v1beta1/doc.go deleted file mode 100644 index 813ac9eb62..0000000000 --- a/pkg/generated/clientset/versioned/typed/machine/v1beta1/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated typed clients. -package v1beta1 diff --git a/pkg/generated/clientset/versioned/typed/machine/v1beta1/fake/doc.go b/pkg/generated/clientset/versioned/typed/machine/v1beta1/fake/doc.go deleted file mode 100644 index 3b87edc967..0000000000 --- a/pkg/generated/clientset/versioned/typed/machine/v1beta1/fake/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by client-gen. DO NOT EDIT. - -// Package fake has the automatically generated clients. -package fake diff --git a/pkg/generated/clientset/versioned/typed/machine/v1beta1/fake/fake_machine.go b/pkg/generated/clientset/versioned/typed/machine/v1beta1/fake/fake_machine.go deleted file mode 100644 index 05b781d9c5..0000000000 --- a/pkg/generated/clientset/versioned/typed/machine/v1beta1/fake/fake_machine.go +++ /dev/null @@ -1,142 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - "context" - - v1beta1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - schema "k8s.io/apimachinery/pkg/runtime/schema" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" -) - -// FakeMachines implements MachineInterface -type FakeMachines struct { - Fake *FakeMachineV1beta1 - ns string -} - -var machinesResource = schema.GroupVersionResource{Group: "machine.openshift.io", Version: "v1beta1", Resource: "machines"} - -var machinesKind = schema.GroupVersionKind{Group: "machine.openshift.io", Version: "v1beta1", Kind: "Machine"} - -// Get takes name of the machine, and returns the corresponding machine object, and an error if there is any. -func (c *FakeMachines) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.Machine, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(machinesResource, c.ns, name), &v1beta1.Machine{}) - - if obj == nil { - return nil, err - } - return obj.(*v1beta1.Machine), err -} - -// List takes label and field selectors, and returns the list of Machines that match those selectors. -func (c *FakeMachines) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.MachineList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(machinesResource, machinesKind, c.ns, opts), &v1beta1.MachineList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &v1beta1.MachineList{ListMeta: obj.(*v1beta1.MachineList).ListMeta} - for _, item := range obj.(*v1beta1.MachineList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested machines. -func (c *FakeMachines) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(machinesResource, c.ns, opts)) - -} - -// Create takes the representation of a machine and creates it. Returns the server's representation of the machine, and an error, if there is any. -func (c *FakeMachines) Create(ctx context.Context, machine *v1beta1.Machine, opts v1.CreateOptions) (result *v1beta1.Machine, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(machinesResource, c.ns, machine), &v1beta1.Machine{}) - - if obj == nil { - return nil, err - } - return obj.(*v1beta1.Machine), err -} - -// Update takes the representation of a machine and updates it. Returns the server's representation of the machine, and an error, if there is any. -func (c *FakeMachines) Update(ctx context.Context, machine *v1beta1.Machine, opts v1.UpdateOptions) (result *v1beta1.Machine, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(machinesResource, c.ns, machine), &v1beta1.Machine{}) - - if obj == nil { - return nil, err - } - return obj.(*v1beta1.Machine), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeMachines) UpdateStatus(ctx context.Context, machine *v1beta1.Machine, opts v1.UpdateOptions) (*v1beta1.Machine, error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(machinesResource, "status", c.ns, machine), &v1beta1.Machine{}) - - if obj == nil { - return nil, err - } - return obj.(*v1beta1.Machine), err -} - -// Delete takes name of the machine and deletes it. Returns an error if one occurs. -func (c *FakeMachines) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteAction(machinesResource, c.ns, name), &v1beta1.Machine{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakeMachines) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(machinesResource, c.ns, listOpts) - - _, err := c.Fake.Invokes(action, &v1beta1.MachineList{}) - return err -} - -// Patch applies the patch and returns the patched machine. -func (c *FakeMachines) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Machine, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(machinesResource, c.ns, name, pt, data, subresources...), &v1beta1.Machine{}) - - if obj == nil { - return nil, err - } - return obj.(*v1beta1.Machine), err -} diff --git a/pkg/generated/clientset/versioned/typed/machine/v1beta1/fake/fake_machine_client.go b/pkg/generated/clientset/versioned/typed/machine/v1beta1/fake/fake_machine_client.go deleted file mode 100644 index 14a9282ded..0000000000 --- a/pkg/generated/clientset/versioned/typed/machine/v1beta1/fake/fake_machine_client.go +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - v1beta1 "github.com/openshift/machine-api-operator/pkg/generated/clientset/versioned/typed/machine/v1beta1" - rest "k8s.io/client-go/rest" - testing "k8s.io/client-go/testing" -) - -type FakeMachineV1beta1 struct { - *testing.Fake -} - -func (c *FakeMachineV1beta1) Machines(namespace string) v1beta1.MachineInterface { - return &FakeMachines{c, namespace} -} - -func (c *FakeMachineV1beta1) MachineHealthChecks(namespace string) v1beta1.MachineHealthCheckInterface { - return &FakeMachineHealthChecks{c, namespace} -} - -func (c *FakeMachineV1beta1) MachineSets(namespace string) v1beta1.MachineSetInterface { - return &FakeMachineSets{c, namespace} -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *FakeMachineV1beta1) RESTClient() rest.Interface { - var ret *rest.RESTClient - return ret -} diff --git a/pkg/generated/clientset/versioned/typed/machine/v1beta1/fake/fake_machinehealthcheck.go b/pkg/generated/clientset/versioned/typed/machine/v1beta1/fake/fake_machinehealthcheck.go deleted file mode 100644 index e5c821a019..0000000000 --- a/pkg/generated/clientset/versioned/typed/machine/v1beta1/fake/fake_machinehealthcheck.go +++ /dev/null @@ -1,142 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - "context" - - v1beta1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - schema "k8s.io/apimachinery/pkg/runtime/schema" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" -) - -// FakeMachineHealthChecks implements MachineHealthCheckInterface -type FakeMachineHealthChecks struct { - Fake *FakeMachineV1beta1 - ns string -} - -var machinehealthchecksResource = schema.GroupVersionResource{Group: "machine.openshift.io", Version: "v1beta1", Resource: "machinehealthchecks"} - -var machinehealthchecksKind = schema.GroupVersionKind{Group: "machine.openshift.io", Version: "v1beta1", Kind: "MachineHealthCheck"} - -// Get takes name of the machineHealthCheck, and returns the corresponding machineHealthCheck object, and an error if there is any. -func (c *FakeMachineHealthChecks) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.MachineHealthCheck, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(machinehealthchecksResource, c.ns, name), &v1beta1.MachineHealthCheck{}) - - if obj == nil { - return nil, err - } - return obj.(*v1beta1.MachineHealthCheck), err -} - -// List takes label and field selectors, and returns the list of MachineHealthChecks that match those selectors. -func (c *FakeMachineHealthChecks) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.MachineHealthCheckList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(machinehealthchecksResource, machinehealthchecksKind, c.ns, opts), &v1beta1.MachineHealthCheckList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &v1beta1.MachineHealthCheckList{ListMeta: obj.(*v1beta1.MachineHealthCheckList).ListMeta} - for _, item := range obj.(*v1beta1.MachineHealthCheckList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested machineHealthChecks. -func (c *FakeMachineHealthChecks) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(machinehealthchecksResource, c.ns, opts)) - -} - -// Create takes the representation of a machineHealthCheck and creates it. Returns the server's representation of the machineHealthCheck, and an error, if there is any. -func (c *FakeMachineHealthChecks) Create(ctx context.Context, machineHealthCheck *v1beta1.MachineHealthCheck, opts v1.CreateOptions) (result *v1beta1.MachineHealthCheck, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(machinehealthchecksResource, c.ns, machineHealthCheck), &v1beta1.MachineHealthCheck{}) - - if obj == nil { - return nil, err - } - return obj.(*v1beta1.MachineHealthCheck), err -} - -// Update takes the representation of a machineHealthCheck and updates it. Returns the server's representation of the machineHealthCheck, and an error, if there is any. -func (c *FakeMachineHealthChecks) Update(ctx context.Context, machineHealthCheck *v1beta1.MachineHealthCheck, opts v1.UpdateOptions) (result *v1beta1.MachineHealthCheck, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(machinehealthchecksResource, c.ns, machineHealthCheck), &v1beta1.MachineHealthCheck{}) - - if obj == nil { - return nil, err - } - return obj.(*v1beta1.MachineHealthCheck), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeMachineHealthChecks) UpdateStatus(ctx context.Context, machineHealthCheck *v1beta1.MachineHealthCheck, opts v1.UpdateOptions) (*v1beta1.MachineHealthCheck, error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(machinehealthchecksResource, "status", c.ns, machineHealthCheck), &v1beta1.MachineHealthCheck{}) - - if obj == nil { - return nil, err - } - return obj.(*v1beta1.MachineHealthCheck), err -} - -// Delete takes name of the machineHealthCheck and deletes it. Returns an error if one occurs. -func (c *FakeMachineHealthChecks) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteAction(machinehealthchecksResource, c.ns, name), &v1beta1.MachineHealthCheck{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakeMachineHealthChecks) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(machinehealthchecksResource, c.ns, listOpts) - - _, err := c.Fake.Invokes(action, &v1beta1.MachineHealthCheckList{}) - return err -} - -// Patch applies the patch and returns the patched machineHealthCheck. -func (c *FakeMachineHealthChecks) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.MachineHealthCheck, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(machinehealthchecksResource, c.ns, name, pt, data, subresources...), &v1beta1.MachineHealthCheck{}) - - if obj == nil { - return nil, err - } - return obj.(*v1beta1.MachineHealthCheck), err -} diff --git a/pkg/generated/clientset/versioned/typed/machine/v1beta1/fake/fake_machineset.go b/pkg/generated/clientset/versioned/typed/machine/v1beta1/fake/fake_machineset.go deleted file mode 100644 index c8be74330c..0000000000 --- a/pkg/generated/clientset/versioned/typed/machine/v1beta1/fake/fake_machineset.go +++ /dev/null @@ -1,142 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - "context" - - v1beta1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - schema "k8s.io/apimachinery/pkg/runtime/schema" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" -) - -// FakeMachineSets implements MachineSetInterface -type FakeMachineSets struct { - Fake *FakeMachineV1beta1 - ns string -} - -var machinesetsResource = schema.GroupVersionResource{Group: "machine.openshift.io", Version: "v1beta1", Resource: "machinesets"} - -var machinesetsKind = schema.GroupVersionKind{Group: "machine.openshift.io", Version: "v1beta1", Kind: "MachineSet"} - -// Get takes name of the machineSet, and returns the corresponding machineSet object, and an error if there is any. -func (c *FakeMachineSets) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.MachineSet, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(machinesetsResource, c.ns, name), &v1beta1.MachineSet{}) - - if obj == nil { - return nil, err - } - return obj.(*v1beta1.MachineSet), err -} - -// List takes label and field selectors, and returns the list of MachineSets that match those selectors. -func (c *FakeMachineSets) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.MachineSetList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(machinesetsResource, machinesetsKind, c.ns, opts), &v1beta1.MachineSetList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &v1beta1.MachineSetList{ListMeta: obj.(*v1beta1.MachineSetList).ListMeta} - for _, item := range obj.(*v1beta1.MachineSetList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested machineSets. -func (c *FakeMachineSets) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(machinesetsResource, c.ns, opts)) - -} - -// Create takes the representation of a machineSet and creates it. Returns the server's representation of the machineSet, and an error, if there is any. -func (c *FakeMachineSets) Create(ctx context.Context, machineSet *v1beta1.MachineSet, opts v1.CreateOptions) (result *v1beta1.MachineSet, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(machinesetsResource, c.ns, machineSet), &v1beta1.MachineSet{}) - - if obj == nil { - return nil, err - } - return obj.(*v1beta1.MachineSet), err -} - -// Update takes the representation of a machineSet and updates it. Returns the server's representation of the machineSet, and an error, if there is any. -func (c *FakeMachineSets) Update(ctx context.Context, machineSet *v1beta1.MachineSet, opts v1.UpdateOptions) (result *v1beta1.MachineSet, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(machinesetsResource, c.ns, machineSet), &v1beta1.MachineSet{}) - - if obj == nil { - return nil, err - } - return obj.(*v1beta1.MachineSet), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeMachineSets) UpdateStatus(ctx context.Context, machineSet *v1beta1.MachineSet, opts v1.UpdateOptions) (*v1beta1.MachineSet, error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(machinesetsResource, "status", c.ns, machineSet), &v1beta1.MachineSet{}) - - if obj == nil { - return nil, err - } - return obj.(*v1beta1.MachineSet), err -} - -// Delete takes name of the machineSet and deletes it. Returns an error if one occurs. -func (c *FakeMachineSets) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteAction(machinesetsResource, c.ns, name), &v1beta1.MachineSet{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakeMachineSets) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(machinesetsResource, c.ns, listOpts) - - _, err := c.Fake.Invokes(action, &v1beta1.MachineSetList{}) - return err -} - -// Patch applies the patch and returns the patched machineSet. -func (c *FakeMachineSets) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.MachineSet, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(machinesetsResource, c.ns, name, pt, data, subresources...), &v1beta1.MachineSet{}) - - if obj == nil { - return nil, err - } - return obj.(*v1beta1.MachineSet), err -} diff --git a/pkg/generated/clientset/versioned/typed/machine/v1beta1/generated_expansion.go b/pkg/generated/clientset/versioned/typed/machine/v1beta1/generated_expansion.go deleted file mode 100644 index d3ff3bc39c..0000000000 --- a/pkg/generated/clientset/versioned/typed/machine/v1beta1/generated_expansion.go +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by client-gen. DO NOT EDIT. - -package v1beta1 - -type MachineExpansion interface{} - -type MachineHealthCheckExpansion interface{} - -type MachineSetExpansion interface{} diff --git a/pkg/generated/clientset/versioned/typed/machine/v1beta1/machine.go b/pkg/generated/clientset/versioned/typed/machine/v1beta1/machine.go deleted file mode 100644 index e0efc668c1..0000000000 --- a/pkg/generated/clientset/versioned/typed/machine/v1beta1/machine.go +++ /dev/null @@ -1,195 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by client-gen. DO NOT EDIT. - -package v1beta1 - -import ( - "context" - "time" - - v1beta1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - scheme "github.com/openshift/machine-api-operator/pkg/generated/clientset/versioned/scheme" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" -) - -// MachinesGetter has a method to return a MachineInterface. -// A group's client should implement this interface. -type MachinesGetter interface { - Machines(namespace string) MachineInterface -} - -// MachineInterface has methods to work with Machine resources. -type MachineInterface interface { - Create(ctx context.Context, machine *v1beta1.Machine, opts v1.CreateOptions) (*v1beta1.Machine, error) - Update(ctx context.Context, machine *v1beta1.Machine, opts v1.UpdateOptions) (*v1beta1.Machine, error) - UpdateStatus(ctx context.Context, machine *v1beta1.Machine, opts v1.UpdateOptions) (*v1beta1.Machine, error) - Delete(ctx context.Context, name string, opts v1.DeleteOptions) error - DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error - Get(ctx context.Context, name string, opts v1.GetOptions) (*v1beta1.Machine, error) - List(ctx context.Context, opts v1.ListOptions) (*v1beta1.MachineList, error) - Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) - Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Machine, err error) - MachineExpansion -} - -// machines implements MachineInterface -type machines struct { - client rest.Interface - ns string -} - -// newMachines returns a Machines -func newMachines(c *MachineV1beta1Client, namespace string) *machines { - return &machines{ - client: c.RESTClient(), - ns: namespace, - } -} - -// Get takes name of the machine, and returns the corresponding machine object, and an error if there is any. -func (c *machines) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.Machine, err error) { - result = &v1beta1.Machine{} - err = c.client.Get(). - Namespace(c.ns). - Resource("machines"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of Machines that match those selectors. -func (c *machines) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.MachineList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1beta1.MachineList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("machines"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested machines. -func (c *machines) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("machines"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a machine and creates it. Returns the server's representation of the machine, and an error, if there is any. -func (c *machines) Create(ctx context.Context, machine *v1beta1.Machine, opts v1.CreateOptions) (result *v1beta1.Machine, err error) { - result = &v1beta1.Machine{} - err = c.client.Post(). - Namespace(c.ns). - Resource("machines"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(machine). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a machine and updates it. Returns the server's representation of the machine, and an error, if there is any. -func (c *machines) Update(ctx context.Context, machine *v1beta1.Machine, opts v1.UpdateOptions) (result *v1beta1.Machine, err error) { - result = &v1beta1.Machine{} - err = c.client.Put(). - Namespace(c.ns). - Resource("machines"). - Name(machine.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(machine). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *machines) UpdateStatus(ctx context.Context, machine *v1beta1.Machine, opts v1.UpdateOptions) (result *v1beta1.Machine, err error) { - result = &v1beta1.Machine{} - err = c.client.Put(). - Namespace(c.ns). - Resource("machines"). - Name(machine.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(machine). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the machine and deletes it. Returns an error if one occurs. -func (c *machines) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("machines"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *machines) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("machines"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched machine. -func (c *machines) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Machine, err error) { - result = &v1beta1.Machine{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("machines"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/pkg/generated/clientset/versioned/typed/machine/v1beta1/machine_client.go b/pkg/generated/clientset/versioned/typed/machine/v1beta1/machine_client.go deleted file mode 100644 index 7eb75589c1..0000000000 --- a/pkg/generated/clientset/versioned/typed/machine/v1beta1/machine_client.go +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by client-gen. DO NOT EDIT. - -package v1beta1 - -import ( - v1beta1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - "github.com/openshift/machine-api-operator/pkg/generated/clientset/versioned/scheme" - rest "k8s.io/client-go/rest" -) - -type MachineV1beta1Interface interface { - RESTClient() rest.Interface - MachinesGetter - MachineHealthChecksGetter - MachineSetsGetter -} - -// MachineV1beta1Client is used to interact with features provided by the machine.openshift.io group. -type MachineV1beta1Client struct { - restClient rest.Interface -} - -func (c *MachineV1beta1Client) Machines(namespace string) MachineInterface { - return newMachines(c, namespace) -} - -func (c *MachineV1beta1Client) MachineHealthChecks(namespace string) MachineHealthCheckInterface { - return newMachineHealthChecks(c, namespace) -} - -func (c *MachineV1beta1Client) MachineSets(namespace string) MachineSetInterface { - return newMachineSets(c, namespace) -} - -// NewForConfig creates a new MachineV1beta1Client for the given config. -func NewForConfig(c *rest.Config) (*MachineV1beta1Client, error) { - config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } - client, err := rest.RESTClientFor(&config) - if err != nil { - return nil, err - } - return &MachineV1beta1Client{client}, nil -} - -// NewForConfigOrDie creates a new MachineV1beta1Client for the given config and -// panics if there is an error in the config. -func NewForConfigOrDie(c *rest.Config) *MachineV1beta1Client { - client, err := NewForConfig(c) - if err != nil { - panic(err) - } - return client -} - -// New creates a new MachineV1beta1Client for the given RESTClient. -func New(c rest.Interface) *MachineV1beta1Client { - return &MachineV1beta1Client{c} -} - -func setConfigDefaults(config *rest.Config) error { - gv := v1beta1.SchemeGroupVersion - config.GroupVersion = &gv - config.APIPath = "/apis" - config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() - - if config.UserAgent == "" { - config.UserAgent = rest.DefaultKubernetesUserAgent() - } - - return nil -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *MachineV1beta1Client) RESTClient() rest.Interface { - if c == nil { - return nil - } - return c.restClient -} diff --git a/pkg/generated/clientset/versioned/typed/machine/v1beta1/machinehealthcheck.go b/pkg/generated/clientset/versioned/typed/machine/v1beta1/machinehealthcheck.go deleted file mode 100644 index 78ee76ec7a..0000000000 --- a/pkg/generated/clientset/versioned/typed/machine/v1beta1/machinehealthcheck.go +++ /dev/null @@ -1,195 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by client-gen. DO NOT EDIT. - -package v1beta1 - -import ( - "context" - "time" - - v1beta1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - scheme "github.com/openshift/machine-api-operator/pkg/generated/clientset/versioned/scheme" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" -) - -// MachineHealthChecksGetter has a method to return a MachineHealthCheckInterface. -// A group's client should implement this interface. -type MachineHealthChecksGetter interface { - MachineHealthChecks(namespace string) MachineHealthCheckInterface -} - -// MachineHealthCheckInterface has methods to work with MachineHealthCheck resources. -type MachineHealthCheckInterface interface { - Create(ctx context.Context, machineHealthCheck *v1beta1.MachineHealthCheck, opts v1.CreateOptions) (*v1beta1.MachineHealthCheck, error) - Update(ctx context.Context, machineHealthCheck *v1beta1.MachineHealthCheck, opts v1.UpdateOptions) (*v1beta1.MachineHealthCheck, error) - UpdateStatus(ctx context.Context, machineHealthCheck *v1beta1.MachineHealthCheck, opts v1.UpdateOptions) (*v1beta1.MachineHealthCheck, error) - Delete(ctx context.Context, name string, opts v1.DeleteOptions) error - DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error - Get(ctx context.Context, name string, opts v1.GetOptions) (*v1beta1.MachineHealthCheck, error) - List(ctx context.Context, opts v1.ListOptions) (*v1beta1.MachineHealthCheckList, error) - Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) - Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.MachineHealthCheck, err error) - MachineHealthCheckExpansion -} - -// machineHealthChecks implements MachineHealthCheckInterface -type machineHealthChecks struct { - client rest.Interface - ns string -} - -// newMachineHealthChecks returns a MachineHealthChecks -func newMachineHealthChecks(c *MachineV1beta1Client, namespace string) *machineHealthChecks { - return &machineHealthChecks{ - client: c.RESTClient(), - ns: namespace, - } -} - -// Get takes name of the machineHealthCheck, and returns the corresponding machineHealthCheck object, and an error if there is any. -func (c *machineHealthChecks) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.MachineHealthCheck, err error) { - result = &v1beta1.MachineHealthCheck{} - err = c.client.Get(). - Namespace(c.ns). - Resource("machinehealthchecks"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of MachineHealthChecks that match those selectors. -func (c *machineHealthChecks) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.MachineHealthCheckList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1beta1.MachineHealthCheckList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("machinehealthchecks"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested machineHealthChecks. -func (c *machineHealthChecks) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("machinehealthchecks"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a machineHealthCheck and creates it. Returns the server's representation of the machineHealthCheck, and an error, if there is any. -func (c *machineHealthChecks) Create(ctx context.Context, machineHealthCheck *v1beta1.MachineHealthCheck, opts v1.CreateOptions) (result *v1beta1.MachineHealthCheck, err error) { - result = &v1beta1.MachineHealthCheck{} - err = c.client.Post(). - Namespace(c.ns). - Resource("machinehealthchecks"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(machineHealthCheck). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a machineHealthCheck and updates it. Returns the server's representation of the machineHealthCheck, and an error, if there is any. -func (c *machineHealthChecks) Update(ctx context.Context, machineHealthCheck *v1beta1.MachineHealthCheck, opts v1.UpdateOptions) (result *v1beta1.MachineHealthCheck, err error) { - result = &v1beta1.MachineHealthCheck{} - err = c.client.Put(). - Namespace(c.ns). - Resource("machinehealthchecks"). - Name(machineHealthCheck.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(machineHealthCheck). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *machineHealthChecks) UpdateStatus(ctx context.Context, machineHealthCheck *v1beta1.MachineHealthCheck, opts v1.UpdateOptions) (result *v1beta1.MachineHealthCheck, err error) { - result = &v1beta1.MachineHealthCheck{} - err = c.client.Put(). - Namespace(c.ns). - Resource("machinehealthchecks"). - Name(machineHealthCheck.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(machineHealthCheck). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the machineHealthCheck and deletes it. Returns an error if one occurs. -func (c *machineHealthChecks) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("machinehealthchecks"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *machineHealthChecks) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("machinehealthchecks"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched machineHealthCheck. -func (c *machineHealthChecks) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.MachineHealthCheck, err error) { - result = &v1beta1.MachineHealthCheck{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("machinehealthchecks"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/pkg/generated/clientset/versioned/typed/machine/v1beta1/machineset.go b/pkg/generated/clientset/versioned/typed/machine/v1beta1/machineset.go deleted file mode 100644 index 531fcec96d..0000000000 --- a/pkg/generated/clientset/versioned/typed/machine/v1beta1/machineset.go +++ /dev/null @@ -1,195 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by client-gen. DO NOT EDIT. - -package v1beta1 - -import ( - "context" - "time" - - v1beta1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - scheme "github.com/openshift/machine-api-operator/pkg/generated/clientset/versioned/scheme" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" -) - -// MachineSetsGetter has a method to return a MachineSetInterface. -// A group's client should implement this interface. -type MachineSetsGetter interface { - MachineSets(namespace string) MachineSetInterface -} - -// MachineSetInterface has methods to work with MachineSet resources. -type MachineSetInterface interface { - Create(ctx context.Context, machineSet *v1beta1.MachineSet, opts v1.CreateOptions) (*v1beta1.MachineSet, error) - Update(ctx context.Context, machineSet *v1beta1.MachineSet, opts v1.UpdateOptions) (*v1beta1.MachineSet, error) - UpdateStatus(ctx context.Context, machineSet *v1beta1.MachineSet, opts v1.UpdateOptions) (*v1beta1.MachineSet, error) - Delete(ctx context.Context, name string, opts v1.DeleteOptions) error - DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error - Get(ctx context.Context, name string, opts v1.GetOptions) (*v1beta1.MachineSet, error) - List(ctx context.Context, opts v1.ListOptions) (*v1beta1.MachineSetList, error) - Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) - Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.MachineSet, err error) - MachineSetExpansion -} - -// machineSets implements MachineSetInterface -type machineSets struct { - client rest.Interface - ns string -} - -// newMachineSets returns a MachineSets -func newMachineSets(c *MachineV1beta1Client, namespace string) *machineSets { - return &machineSets{ - client: c.RESTClient(), - ns: namespace, - } -} - -// Get takes name of the machineSet, and returns the corresponding machineSet object, and an error if there is any. -func (c *machineSets) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.MachineSet, err error) { - result = &v1beta1.MachineSet{} - err = c.client.Get(). - Namespace(c.ns). - Resource("machinesets"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of MachineSets that match those selectors. -func (c *machineSets) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.MachineSetList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1beta1.MachineSetList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("machinesets"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested machineSets. -func (c *machineSets) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("machinesets"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a machineSet and creates it. Returns the server's representation of the machineSet, and an error, if there is any. -func (c *machineSets) Create(ctx context.Context, machineSet *v1beta1.MachineSet, opts v1.CreateOptions) (result *v1beta1.MachineSet, err error) { - result = &v1beta1.MachineSet{} - err = c.client.Post(). - Namespace(c.ns). - Resource("machinesets"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(machineSet). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a machineSet and updates it. Returns the server's representation of the machineSet, and an error, if there is any. -func (c *machineSets) Update(ctx context.Context, machineSet *v1beta1.MachineSet, opts v1.UpdateOptions) (result *v1beta1.MachineSet, err error) { - result = &v1beta1.MachineSet{} - err = c.client.Put(). - Namespace(c.ns). - Resource("machinesets"). - Name(machineSet.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(machineSet). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *machineSets) UpdateStatus(ctx context.Context, machineSet *v1beta1.MachineSet, opts v1.UpdateOptions) (result *v1beta1.MachineSet, err error) { - result = &v1beta1.MachineSet{} - err = c.client.Put(). - Namespace(c.ns). - Resource("machinesets"). - Name(machineSet.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(machineSet). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the machineSet and deletes it. Returns an error if one occurs. -func (c *machineSets) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("machinesets"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *machineSets) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("machinesets"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched machineSet. -func (c *machineSets) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.MachineSet, err error) { - result = &v1beta1.MachineSet{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("machinesets"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/pkg/generated/informers/externalversions/factory.go b/pkg/generated/informers/externalversions/factory.go deleted file mode 100644 index 90a7bb64d1..0000000000 --- a/pkg/generated/informers/externalversions/factory.go +++ /dev/null @@ -1,180 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by informer-gen. DO NOT EDIT. - -package externalversions - -import ( - reflect "reflect" - sync "sync" - time "time" - - versioned "github.com/openshift/machine-api-operator/pkg/generated/clientset/versioned" - internalinterfaces "github.com/openshift/machine-api-operator/pkg/generated/informers/externalversions/internalinterfaces" - machine "github.com/openshift/machine-api-operator/pkg/generated/informers/externalversions/machine" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - schema "k8s.io/apimachinery/pkg/runtime/schema" - cache "k8s.io/client-go/tools/cache" -) - -// SharedInformerOption defines the functional option type for SharedInformerFactory. -type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory - -type sharedInformerFactory struct { - client versioned.Interface - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc - lock sync.Mutex - defaultResync time.Duration - customResync map[reflect.Type]time.Duration - - informers map[reflect.Type]cache.SharedIndexInformer - // startedInformers is used for tracking which informers have been started. - // This allows Start() to be called multiple times safely. - startedInformers map[reflect.Type]bool -} - -// WithCustomResyncConfig sets a custom resync period for the specified informer types. -func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { - return func(factory *sharedInformerFactory) *sharedInformerFactory { - for k, v := range resyncConfig { - factory.customResync[reflect.TypeOf(k)] = v - } - return factory - } -} - -// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. -func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { - return func(factory *sharedInformerFactory) *sharedInformerFactory { - factory.tweakListOptions = tweakListOptions - return factory - } -} - -// WithNamespace limits the SharedInformerFactory to the specified namespace. -func WithNamespace(namespace string) SharedInformerOption { - return func(factory *sharedInformerFactory) *sharedInformerFactory { - factory.namespace = namespace - return factory - } -} - -// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. -func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { - return NewSharedInformerFactoryWithOptions(client, defaultResync) -} - -// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. -// Listers obtained via this SharedInformerFactory will be subject to the same filters -// as specified here. -// Deprecated: Please use NewSharedInformerFactoryWithOptions instead -func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { - return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) -} - -// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. -func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { - factory := &sharedInformerFactory{ - client: client, - namespace: v1.NamespaceAll, - defaultResync: defaultResync, - informers: make(map[reflect.Type]cache.SharedIndexInformer), - startedInformers: make(map[reflect.Type]bool), - customResync: make(map[reflect.Type]time.Duration), - } - - // Apply all options - for _, opt := range options { - factory = opt(factory) - } - - return factory -} - -// Start initializes all requested informers. -func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { - f.lock.Lock() - defer f.lock.Unlock() - - for informerType, informer := range f.informers { - if !f.startedInformers[informerType] { - go informer.Run(stopCh) - f.startedInformers[informerType] = true - } - } -} - -// WaitForCacheSync waits for all started informers' cache were synced. -func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { - informers := func() map[reflect.Type]cache.SharedIndexInformer { - f.lock.Lock() - defer f.lock.Unlock() - - informers := map[reflect.Type]cache.SharedIndexInformer{} - for informerType, informer := range f.informers { - if f.startedInformers[informerType] { - informers[informerType] = informer - } - } - return informers - }() - - res := map[reflect.Type]bool{} - for informType, informer := range informers { - res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) - } - return res -} - -// InternalInformerFor returns the SharedIndexInformer for obj using an internal -// client. -func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { - f.lock.Lock() - defer f.lock.Unlock() - - informerType := reflect.TypeOf(obj) - informer, exists := f.informers[informerType] - if exists { - return informer - } - - resyncPeriod, exists := f.customResync[informerType] - if !exists { - resyncPeriod = f.defaultResync - } - - informer = newFunc(f.client, resyncPeriod) - f.informers[informerType] = informer - - return informer -} - -// SharedInformerFactory provides shared informers for resources in all known -// API group versions. -type SharedInformerFactory interface { - internalinterfaces.SharedInformerFactory - ForResource(resource schema.GroupVersionResource) (GenericInformer, error) - WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool - - Machine() machine.Interface -} - -func (f *sharedInformerFactory) Machine() machine.Interface { - return machine.New(f, f.namespace, f.tweakListOptions) -} diff --git a/pkg/generated/informers/externalversions/generic.go b/pkg/generated/informers/externalversions/generic.go deleted file mode 100644 index 6d5f04e0a3..0000000000 --- a/pkg/generated/informers/externalversions/generic.go +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by informer-gen. DO NOT EDIT. - -package externalversions - -import ( - "fmt" - - v1beta1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - schema "k8s.io/apimachinery/pkg/runtime/schema" - cache "k8s.io/client-go/tools/cache" -) - -// GenericInformer is type of SharedIndexInformer which will locate and delegate to other -// sharedInformers based on type -type GenericInformer interface { - Informer() cache.SharedIndexInformer - Lister() cache.GenericLister -} - -type genericInformer struct { - informer cache.SharedIndexInformer - resource schema.GroupResource -} - -// Informer returns the SharedIndexInformer. -func (f *genericInformer) Informer() cache.SharedIndexInformer { - return f.informer -} - -// Lister returns the GenericLister. -func (f *genericInformer) Lister() cache.GenericLister { - return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) -} - -// ForResource gives generic access to a shared informer of the matching type -// TODO extend this to unknown resources with a client pool -func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { - switch resource { - // Group=machine.openshift.io, Version=v1beta1 - case v1beta1.SchemeGroupVersion.WithResource("machines"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Machine().V1beta1().Machines().Informer()}, nil - case v1beta1.SchemeGroupVersion.WithResource("machinehealthchecks"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Machine().V1beta1().MachineHealthChecks().Informer()}, nil - case v1beta1.SchemeGroupVersion.WithResource("machinesets"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Machine().V1beta1().MachineSets().Informer()}, nil - - } - - return nil, fmt.Errorf("no informer found for %v", resource) -} diff --git a/pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go b/pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go deleted file mode 100644 index cb72490d4c..0000000000 --- a/pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by informer-gen. DO NOT EDIT. - -package internalinterfaces - -import ( - time "time" - - versioned "github.com/openshift/machine-api-operator/pkg/generated/clientset/versioned" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - cache "k8s.io/client-go/tools/cache" -) - -// NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. -type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer - -// SharedInformerFactory a small interface to allow for adding an informer without an import cycle -type SharedInformerFactory interface { - Start(stopCh <-chan struct{}) - InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer -} - -// TweakListOptionsFunc is a function that transforms a v1.ListOptions. -type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/pkg/generated/informers/externalversions/machine/interface.go b/pkg/generated/informers/externalversions/machine/interface.go deleted file mode 100644 index 89d60c881b..0000000000 --- a/pkg/generated/informers/externalversions/machine/interface.go +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by informer-gen. DO NOT EDIT. - -package machine - -import ( - internalinterfaces "github.com/openshift/machine-api-operator/pkg/generated/informers/externalversions/internalinterfaces" - v1beta1 "github.com/openshift/machine-api-operator/pkg/generated/informers/externalversions/machine/v1beta1" -) - -// Interface provides access to each of this group's versions. -type Interface interface { - // V1beta1 provides access to shared informers for resources in V1beta1. - V1beta1() v1beta1.Interface -} - -type group struct { - factory internalinterfaces.SharedInformerFactory - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// New returns a new Interface. -func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { - return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} -} - -// V1beta1 returns a new v1beta1.Interface. -func (g *group) V1beta1() v1beta1.Interface { - return v1beta1.New(g.factory, g.namespace, g.tweakListOptions) -} diff --git a/pkg/generated/informers/externalversions/machine/v1beta1/interface.go b/pkg/generated/informers/externalversions/machine/v1beta1/interface.go deleted file mode 100644 index 9bbf4950d7..0000000000 --- a/pkg/generated/informers/externalversions/machine/v1beta1/interface.go +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by informer-gen. DO NOT EDIT. - -package v1beta1 - -import ( - internalinterfaces "github.com/openshift/machine-api-operator/pkg/generated/informers/externalversions/internalinterfaces" -) - -// Interface provides access to all the informers in this group version. -type Interface interface { - // Machines returns a MachineInformer. - Machines() MachineInformer - // MachineHealthChecks returns a MachineHealthCheckInformer. - MachineHealthChecks() MachineHealthCheckInformer - // MachineSets returns a MachineSetInformer. - MachineSets() MachineSetInformer -} - -type version struct { - factory internalinterfaces.SharedInformerFactory - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// New returns a new Interface. -func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { - return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} -} - -// Machines returns a MachineInformer. -func (v *version) Machines() MachineInformer { - return &machineInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} -} - -// MachineHealthChecks returns a MachineHealthCheckInformer. -func (v *version) MachineHealthChecks() MachineHealthCheckInformer { - return &machineHealthCheckInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} -} - -// MachineSets returns a MachineSetInformer. -func (v *version) MachineSets() MachineSetInformer { - return &machineSetInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} -} diff --git a/pkg/generated/informers/externalversions/machine/v1beta1/machine.go b/pkg/generated/informers/externalversions/machine/v1beta1/machine.go deleted file mode 100644 index 44fedc0df1..0000000000 --- a/pkg/generated/informers/externalversions/machine/v1beta1/machine.go +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by informer-gen. DO NOT EDIT. - -package v1beta1 - -import ( - "context" - time "time" - - machinev1beta1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - versioned "github.com/openshift/machine-api-operator/pkg/generated/clientset/versioned" - internalinterfaces "github.com/openshift/machine-api-operator/pkg/generated/informers/externalversions/internalinterfaces" - v1beta1 "github.com/openshift/machine-api-operator/pkg/generated/listers/machine/v1beta1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - watch "k8s.io/apimachinery/pkg/watch" - cache "k8s.io/client-go/tools/cache" -) - -// MachineInformer provides access to a shared informer and lister for -// Machines. -type MachineInformer interface { - Informer() cache.SharedIndexInformer - Lister() v1beta1.MachineLister -} - -type machineInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewMachineInformer constructs a new informer for Machine type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewMachineInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredMachineInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredMachineInformer constructs a new informer for Machine type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFilteredMachineInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( - &cache.ListWatch{ - ListFunc: func(options v1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.MachineV1beta1().Machines(namespace).List(context.TODO(), options) - }, - WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.MachineV1beta1().Machines(namespace).Watch(context.TODO(), options) - }, - }, - &machinev1beta1.Machine{}, - resyncPeriod, - indexers, - ) -} - -func (f *machineInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredMachineInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *machineInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&machinev1beta1.Machine{}, f.defaultInformer) -} - -func (f *machineInformer) Lister() v1beta1.MachineLister { - return v1beta1.NewMachineLister(f.Informer().GetIndexer()) -} diff --git a/pkg/generated/informers/externalversions/machine/v1beta1/machinehealthcheck.go b/pkg/generated/informers/externalversions/machine/v1beta1/machinehealthcheck.go deleted file mode 100644 index 036e8e70a3..0000000000 --- a/pkg/generated/informers/externalversions/machine/v1beta1/machinehealthcheck.go +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by informer-gen. DO NOT EDIT. - -package v1beta1 - -import ( - "context" - time "time" - - machinev1beta1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - versioned "github.com/openshift/machine-api-operator/pkg/generated/clientset/versioned" - internalinterfaces "github.com/openshift/machine-api-operator/pkg/generated/informers/externalversions/internalinterfaces" - v1beta1 "github.com/openshift/machine-api-operator/pkg/generated/listers/machine/v1beta1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - watch "k8s.io/apimachinery/pkg/watch" - cache "k8s.io/client-go/tools/cache" -) - -// MachineHealthCheckInformer provides access to a shared informer and lister for -// MachineHealthChecks. -type MachineHealthCheckInformer interface { - Informer() cache.SharedIndexInformer - Lister() v1beta1.MachineHealthCheckLister -} - -type machineHealthCheckInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewMachineHealthCheckInformer constructs a new informer for MachineHealthCheck type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewMachineHealthCheckInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredMachineHealthCheckInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredMachineHealthCheckInformer constructs a new informer for MachineHealthCheck type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFilteredMachineHealthCheckInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( - &cache.ListWatch{ - ListFunc: func(options v1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.MachineV1beta1().MachineHealthChecks(namespace).List(context.TODO(), options) - }, - WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.MachineV1beta1().MachineHealthChecks(namespace).Watch(context.TODO(), options) - }, - }, - &machinev1beta1.MachineHealthCheck{}, - resyncPeriod, - indexers, - ) -} - -func (f *machineHealthCheckInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredMachineHealthCheckInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *machineHealthCheckInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&machinev1beta1.MachineHealthCheck{}, f.defaultInformer) -} - -func (f *machineHealthCheckInformer) Lister() v1beta1.MachineHealthCheckLister { - return v1beta1.NewMachineHealthCheckLister(f.Informer().GetIndexer()) -} diff --git a/pkg/generated/informers/externalversions/machine/v1beta1/machineset.go b/pkg/generated/informers/externalversions/machine/v1beta1/machineset.go deleted file mode 100644 index e0225d2183..0000000000 --- a/pkg/generated/informers/externalversions/machine/v1beta1/machineset.go +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by informer-gen. DO NOT EDIT. - -package v1beta1 - -import ( - "context" - time "time" - - machinev1beta1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - versioned "github.com/openshift/machine-api-operator/pkg/generated/clientset/versioned" - internalinterfaces "github.com/openshift/machine-api-operator/pkg/generated/informers/externalversions/internalinterfaces" - v1beta1 "github.com/openshift/machine-api-operator/pkg/generated/listers/machine/v1beta1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - watch "k8s.io/apimachinery/pkg/watch" - cache "k8s.io/client-go/tools/cache" -) - -// MachineSetInformer provides access to a shared informer and lister for -// MachineSets. -type MachineSetInformer interface { - Informer() cache.SharedIndexInformer - Lister() v1beta1.MachineSetLister -} - -type machineSetInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewMachineSetInformer constructs a new informer for MachineSet type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewMachineSetInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredMachineSetInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredMachineSetInformer constructs a new informer for MachineSet type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFilteredMachineSetInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( - &cache.ListWatch{ - ListFunc: func(options v1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.MachineV1beta1().MachineSets(namespace).List(context.TODO(), options) - }, - WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.MachineV1beta1().MachineSets(namespace).Watch(context.TODO(), options) - }, - }, - &machinev1beta1.MachineSet{}, - resyncPeriod, - indexers, - ) -} - -func (f *machineSetInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredMachineSetInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *machineSetInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&machinev1beta1.MachineSet{}, f.defaultInformer) -} - -func (f *machineSetInformer) Lister() v1beta1.MachineSetLister { - return v1beta1.NewMachineSetLister(f.Informer().GetIndexer()) -} diff --git a/pkg/generated/listers/machine/v1beta1/expansion_generated.go b/pkg/generated/listers/machine/v1beta1/expansion_generated.go deleted file mode 100644 index 596792bf07..0000000000 --- a/pkg/generated/listers/machine/v1beta1/expansion_generated.go +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by lister-gen. DO NOT EDIT. - -package v1beta1 - -// MachineListerExpansion allows custom methods to be added to -// MachineLister. -type MachineListerExpansion interface{} - -// MachineNamespaceListerExpansion allows custom methods to be added to -// MachineNamespaceLister. -type MachineNamespaceListerExpansion interface{} - -// MachineHealthCheckListerExpansion allows custom methods to be added to -// MachineHealthCheckLister. -type MachineHealthCheckListerExpansion interface{} - -// MachineHealthCheckNamespaceListerExpansion allows custom methods to be added to -// MachineHealthCheckNamespaceLister. -type MachineHealthCheckNamespaceListerExpansion interface{} - -// MachineSetListerExpansion allows custom methods to be added to -// MachineSetLister. -type MachineSetListerExpansion interface{} - -// MachineSetNamespaceListerExpansion allows custom methods to be added to -// MachineSetNamespaceLister. -type MachineSetNamespaceListerExpansion interface{} diff --git a/pkg/generated/listers/machine/v1beta1/machine.go b/pkg/generated/listers/machine/v1beta1/machine.go deleted file mode 100644 index 19aa097388..0000000000 --- a/pkg/generated/listers/machine/v1beta1/machine.go +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by lister-gen. DO NOT EDIT. - -package v1beta1 - -import ( - v1beta1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" -) - -// MachineLister helps list Machines. -// All objects returned here must be treated as read-only. -type MachineLister interface { - // List lists all Machines in the indexer. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1beta1.Machine, err error) - // Machines returns an object that can list and get Machines. - Machines(namespace string) MachineNamespaceLister - MachineListerExpansion -} - -// machineLister implements the MachineLister interface. -type machineLister struct { - indexer cache.Indexer -} - -// NewMachineLister returns a new MachineLister. -func NewMachineLister(indexer cache.Indexer) MachineLister { - return &machineLister{indexer: indexer} -} - -// List lists all Machines in the indexer. -func (s *machineLister) List(selector labels.Selector) (ret []*v1beta1.Machine, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1beta1.Machine)) - }) - return ret, err -} - -// Machines returns an object that can list and get Machines. -func (s *machineLister) Machines(namespace string) MachineNamespaceLister { - return machineNamespaceLister{indexer: s.indexer, namespace: namespace} -} - -// MachineNamespaceLister helps list and get Machines. -// All objects returned here must be treated as read-only. -type MachineNamespaceLister interface { - // List lists all Machines in the indexer for a given namespace. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1beta1.Machine, err error) - // Get retrieves the Machine from the indexer for a given namespace and name. - // Objects returned here must be treated as read-only. - Get(name string) (*v1beta1.Machine, error) - MachineNamespaceListerExpansion -} - -// machineNamespaceLister implements the MachineNamespaceLister -// interface. -type machineNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all Machines in the indexer for a given namespace. -func (s machineNamespaceLister) List(selector labels.Selector) (ret []*v1beta1.Machine, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1beta1.Machine)) - }) - return ret, err -} - -// Get retrieves the Machine from the indexer for a given namespace and name. -func (s machineNamespaceLister) Get(name string) (*v1beta1.Machine, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1beta1.Resource("machine"), name) - } - return obj.(*v1beta1.Machine), nil -} diff --git a/pkg/generated/listers/machine/v1beta1/machinehealthcheck.go b/pkg/generated/listers/machine/v1beta1/machinehealthcheck.go deleted file mode 100644 index 4de72c6d9a..0000000000 --- a/pkg/generated/listers/machine/v1beta1/machinehealthcheck.go +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by lister-gen. DO NOT EDIT. - -package v1beta1 - -import ( - v1beta1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" -) - -// MachineHealthCheckLister helps list MachineHealthChecks. -// All objects returned here must be treated as read-only. -type MachineHealthCheckLister interface { - // List lists all MachineHealthChecks in the indexer. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1beta1.MachineHealthCheck, err error) - // MachineHealthChecks returns an object that can list and get MachineHealthChecks. - MachineHealthChecks(namespace string) MachineHealthCheckNamespaceLister - MachineHealthCheckListerExpansion -} - -// machineHealthCheckLister implements the MachineHealthCheckLister interface. -type machineHealthCheckLister struct { - indexer cache.Indexer -} - -// NewMachineHealthCheckLister returns a new MachineHealthCheckLister. -func NewMachineHealthCheckLister(indexer cache.Indexer) MachineHealthCheckLister { - return &machineHealthCheckLister{indexer: indexer} -} - -// List lists all MachineHealthChecks in the indexer. -func (s *machineHealthCheckLister) List(selector labels.Selector) (ret []*v1beta1.MachineHealthCheck, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1beta1.MachineHealthCheck)) - }) - return ret, err -} - -// MachineHealthChecks returns an object that can list and get MachineHealthChecks. -func (s *machineHealthCheckLister) MachineHealthChecks(namespace string) MachineHealthCheckNamespaceLister { - return machineHealthCheckNamespaceLister{indexer: s.indexer, namespace: namespace} -} - -// MachineHealthCheckNamespaceLister helps list and get MachineHealthChecks. -// All objects returned here must be treated as read-only. -type MachineHealthCheckNamespaceLister interface { - // List lists all MachineHealthChecks in the indexer for a given namespace. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1beta1.MachineHealthCheck, err error) - // Get retrieves the MachineHealthCheck from the indexer for a given namespace and name. - // Objects returned here must be treated as read-only. - Get(name string) (*v1beta1.MachineHealthCheck, error) - MachineHealthCheckNamespaceListerExpansion -} - -// machineHealthCheckNamespaceLister implements the MachineHealthCheckNamespaceLister -// interface. -type machineHealthCheckNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all MachineHealthChecks in the indexer for a given namespace. -func (s machineHealthCheckNamespaceLister) List(selector labels.Selector) (ret []*v1beta1.MachineHealthCheck, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1beta1.MachineHealthCheck)) - }) - return ret, err -} - -// Get retrieves the MachineHealthCheck from the indexer for a given namespace and name. -func (s machineHealthCheckNamespaceLister) Get(name string) (*v1beta1.MachineHealthCheck, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1beta1.Resource("machinehealthcheck"), name) - } - return obj.(*v1beta1.MachineHealthCheck), nil -} diff --git a/pkg/generated/listers/machine/v1beta1/machineset.go b/pkg/generated/listers/machine/v1beta1/machineset.go deleted file mode 100644 index fb2b103d1a..0000000000 --- a/pkg/generated/listers/machine/v1beta1/machineset.go +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ -// Code generated by lister-gen. DO NOT EDIT. - -package v1beta1 - -import ( - v1beta1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" -) - -// MachineSetLister helps list MachineSets. -// All objects returned here must be treated as read-only. -type MachineSetLister interface { - // List lists all MachineSets in the indexer. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1beta1.MachineSet, err error) - // MachineSets returns an object that can list and get MachineSets. - MachineSets(namespace string) MachineSetNamespaceLister - MachineSetListerExpansion -} - -// machineSetLister implements the MachineSetLister interface. -type machineSetLister struct { - indexer cache.Indexer -} - -// NewMachineSetLister returns a new MachineSetLister. -func NewMachineSetLister(indexer cache.Indexer) MachineSetLister { - return &machineSetLister{indexer: indexer} -} - -// List lists all MachineSets in the indexer. -func (s *machineSetLister) List(selector labels.Selector) (ret []*v1beta1.MachineSet, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1beta1.MachineSet)) - }) - return ret, err -} - -// MachineSets returns an object that can list and get MachineSets. -func (s *machineSetLister) MachineSets(namespace string) MachineSetNamespaceLister { - return machineSetNamespaceLister{indexer: s.indexer, namespace: namespace} -} - -// MachineSetNamespaceLister helps list and get MachineSets. -// All objects returned here must be treated as read-only. -type MachineSetNamespaceLister interface { - // List lists all MachineSets in the indexer for a given namespace. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1beta1.MachineSet, err error) - // Get retrieves the MachineSet from the indexer for a given namespace and name. - // Objects returned here must be treated as read-only. - Get(name string) (*v1beta1.MachineSet, error) - MachineSetNamespaceListerExpansion -} - -// machineSetNamespaceLister implements the MachineSetNamespaceLister -// interface. -type machineSetNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all MachineSets in the indexer for a given namespace. -func (s machineSetNamespaceLister) List(selector labels.Selector) (ret []*v1beta1.MachineSet, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1beta1.MachineSet)) - }) - return ret, err -} - -// Get retrieves the MachineSet from the indexer for a given namespace and name. -func (s machineSetNamespaceLister) Get(name string) (*v1beta1.MachineSet, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1beta1.Resource("machineset"), name) - } - return obj.(*v1beta1.MachineSet), nil -} From 6615b234876c527c70a7ac8031223e4a730e5054 Mon Sep 17 00:00:00 2001 From: Alexander Demichev Date: Tue, 26 Oct 2021 19:53:39 +0200 Subject: [PATCH 03/10] Move all webhooks related code to a separate package --- pkg/webhooks/machine_types_test.go | 128 ++ pkg/webhooks/machine_webhook.go | 1205 ++++++++++++ pkg/webhooks/machine_webhook_test.go | 2403 +++++++++++++++++++++++ pkg/webhooks/machineset_types_test.go | 128 ++ pkg/webhooks/machineset_webhook.go | 152 ++ pkg/webhooks/machineset_webhook_test.go | 829 ++++++++ pkg/webhooks/v1beta1_suite_test.go | 222 +++ 7 files changed, 5067 insertions(+) create mode 100644 pkg/webhooks/machine_types_test.go create mode 100644 pkg/webhooks/machine_webhook.go create mode 100644 pkg/webhooks/machine_webhook_test.go create mode 100644 pkg/webhooks/machineset_types_test.go create mode 100644 pkg/webhooks/machineset_webhook.go create mode 100644 pkg/webhooks/machineset_webhook_test.go create mode 100644 pkg/webhooks/v1beta1_suite_test.go diff --git a/pkg/webhooks/machine_types_test.go b/pkg/webhooks/machine_types_test.go new file mode 100644 index 0000000000..82a5eca10e --- /dev/null +++ b/pkg/webhooks/machine_types_test.go @@ -0,0 +1,128 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 webhooks + +import ( + "encoding/json" + "math/rand" + "reflect" + "testing" + "time" + + . "github.com/onsi/gomega" + machinev1 "github.com/openshift/api/machine/v1beta1" + "golang.org/x/net/context" + "k8s.io/apimachinery/pkg/api/apitesting/fuzzer" + metafuzzer "k8s.io/apimachinery/pkg/apis/meta/fuzzer" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func TestStorageMachine(t *testing.T) { + key := types.NamespacedName{Name: "foo", Namespace: "default"} + created := &machinev1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}} + + // Test Create + fetched := &machinev1.Machine{} + if err := c.Create(context.TODO(), created); err != nil { + t.Errorf("error creating machine: %v", err) + } + + if err := c.Get(context.TODO(), key, fetched); err != nil { + t.Errorf("error getting machine: %v", err) + } + if !reflect.DeepEqual(*fetched, *created) { + t.Error("fetched value not what was created") + } + + // Test Updating the Labels + updated := fetched.DeepCopy() + updated.Labels = map[string]string{"hello": "world"} + if err := c.Update(context.TODO(), updated); err != nil { + t.Errorf("error updating machine: %v", err) + } + + if err := c.Get(context.TODO(), key, fetched); err != nil { + t.Errorf("error getting machine: %v", err) + } + if !reflect.DeepEqual(*fetched, *updated) { + t.Error("fetched value not what was updated") + } + + // Test Delete + if err := c.Delete(context.TODO(), fetched); err != nil { + t.Errorf("error deleting machine: %v", err) + } + if err := c.Get(context.TODO(), key, fetched); err == nil { + t.Error("expected error getting machine") + } +} + +func TestRoundTripMachine(t *testing.T) { + codecs := serializer.NewCodecFactory(scheme.Scheme) + seed := time.Now().UnixNano() + fuzzer := fuzzer.FuzzerFor(fuzzer.MergeFuzzerFuncs(metafuzzer.Funcs, machineFuzzerFuncs), rand.NewSource(seed), codecs) + ctx := context.Background() + g := NewWithT(t) + + for i := 0; i < 100; i++ { + machine := &machinev1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "machine-round-trip-test-", + Namespace: "default", + }, + } + // Fuzz the spec and status as those are the ones we need to check aren't + // losing data + spec := &machinev1.MachineSpec{} + status := &machinev1.MachineStatus{} + fuzzer.Fuzz(spec) + fuzzer.Fuzz(status) + + machine.Spec = *spec.DeepCopy() + g.Expect(c.Create(ctx, machine)).To(Succeed()) + machine.Status = *status.DeepCopy() + g.Expect(c.Status().Update(ctx, machine)).To(Succeed()) + + // Check the spec and status weren't modified during create + // + // Use JSON representation as order of fields in RawExtensions may change + // during a round trip + machineSpecJSON, err := json.Marshal(machine.Spec) + g.Expect(err).ToNot(HaveOccurred()) + specJSON, err := json.Marshal(*spec) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(machineSpecJSON).To(MatchJSON(specJSON)) + + machineStatusJSON, err := json.Marshal(machine.Status) + g.Expect(err).ToNot(HaveOccurred()) + statusJSON, err := json.Marshal(*status) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(machineStatusJSON).To(MatchJSON(statusJSON)) + + fetched := &machinev1.Machine{} + key := client.ObjectKey{Namespace: machine.Namespace, Name: machine.Name} + g.Expect(c.Get(ctx, key, fetched)).To(Succeed()) + + // Check the spec and status haven't changed server side + g.Expect(fetched.Spec).To(Equal(machine.Spec)) + g.Expect(fetched.Status).To(Equal(machine.Status)) + } +} diff --git a/pkg/webhooks/machine_webhook.go b/pkg/webhooks/machine_webhook.go new file mode 100644 index 0000000000..76f6cd4d0c --- /dev/null +++ b/pkg/webhooks/machine_webhook.go @@ -0,0 +1,1205 @@ +package webhooks + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "runtime" + "strings" + + osconfigv1 "github.com/openshift/api/config/v1" + machinev1 "github.com/openshift/api/machine/v1beta1" + osclientset "github.com/openshift/client-go/config/clientset/versioned" + admissionregistrationv1 "k8s.io/api/admissionregistration/v1" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + kruntime "k8s.io/apimachinery/pkg/runtime" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/klog/v2" + "k8s.io/utils/pointer" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + yaml "sigs.k8s.io/yaml" +) + +var ( + // Azure Defaults + defaultAzureVnet = func(clusterID string) string { + return fmt.Sprintf("%s-vnet", clusterID) + } + defaultAzureSubnet = func(clusterID string) string { + return fmt.Sprintf("%s-worker-subnet", clusterID) + } + defaultAzureNetworkResourceGroup = func(clusterID string) string { + return fmt.Sprintf("%s-rg", clusterID) + } + defaultAzureImageResourceID = func(clusterID string) string { + return fmt.Sprintf("/resourceGroups/%s/providers/Microsoft.Compute/images/%s", clusterID+"-rg", clusterID) + } + defaultAzureManagedIdentiy = func(clusterID string) string { + return fmt.Sprintf("%s-identity", clusterID) + } + defaultAzureResourceGroup = func(clusterID string) string { + return fmt.Sprintf("%s-rg", clusterID) + } + + // GCP Defaults + defaultGCPNetwork = func(clusterID string) string { + return fmt.Sprintf("%s-network", clusterID) + } + defaultGCPSubnetwork = func(clusterID string) string { + return fmt.Sprintf("%s-worker-subnet", clusterID) + } + defaultGCPTags = func(clusterID string) []string { + return []string{fmt.Sprintf("%s-worker", clusterID)} + } +) + +const ( + DefaultMachineMutatingHookPath = "/mutate-machine-openshift-io-v1beta1-machine" + DefaultMachineValidatingHookPath = "/validate-machine-openshift-io-v1beta1-machine" + DefaultMachineSetMutatingHookPath = "/mutate-machine-openshift-io-v1beta1-machineset" + DefaultMachineSetValidatingHookPath = "/validate-machine-openshift-io-v1beta1-machineset" + + defaultWebhookConfigurationName = "machine-api" + defaultWebhookServiceName = "machine-api-operator-webhook" + defaultWebhookServiceNamespace = "openshift-machine-api" + defaultWebhookServicePort = 443 + + defaultUserDataSecret = "worker-user-data" + defaultSecretNamespace = "openshift-machine-api" + + // AWS Defaults + defaultAWSCredentialsSecret = "aws-cloud-credentials" + defaultAWSX86InstanceType = "m5.large" + defaultAWSARMInstanceType = "m6g.large" + + // Azure Defaults + defaultAzureVMSize = "Standard_D4s_V3" + defaultAzureCredentialsSecret = "azure-cloud-credentials" + defaultAzureOSDiskOSType = "Linux" + defaultAzureOSDiskStorageType = "Premium_LRS" + azureMaxDiskSizeGB = 32768 + + // GCP Defaults + defaultGCPMachineType = "n1-standard-4" + defaultGCPCredentialsSecret = "gcp-cloud-credentials" + defaultGCPDiskSizeGb = 128 + defaultGCPDiskType = "pd-standard" + // https://releases-art-rhcos.svc.ci.openshift.org/art/storage/releases/rhcos-4.8/48.83.202103122318-0/x86_64/meta.json + // https://github.com/openshift/installer/blob/796a99049d3b7489b6c08ec5bd7c7983731afbcf/data/data/rhcos.json#L90-L94 + defaultGCPDiskImage = "projects/rhcos-cloud/global/images/rhcos-48-83-202103221318-0-gcp-x86-64" + + // vSphere Defaults + defaultVSphereCredentialsSecret = "vsphere-cloud-credentials" + // Minimum vSphere values taken from vSphere reconciler + minVSphereCPU = 2 + minVSphereMemoryMiB = 2048 + // https://docs.openshift.com/container-platform/4.1/installing/installing_vsphere/installing-vsphere.html#minimum-resource-requirements_installing-vsphere + minVSphereDiskGiB = 120 +) + +var ( + // webhookFailurePolicy is ignore so we don't want to block machine lifecycle on the webhook operational aspects. + // This would be particularly problematic for chicken egg issues when bootstrapping a cluster. + webhookFailurePolicy = admissionregistrationv1.Ignore + webhookSideEffects = admissionregistrationv1.SideEffectClassNone +) + +func secretExists(c client.Client, name, namespace string) (bool, error) { + key := client.ObjectKey{ + Name: name, + Namespace: namespace, + } + obj := &corev1.Secret{} + + if err := c.Get(context.Background(), key, obj); err != nil { + if apierrors.IsNotFound(err) { + return false, nil + } + return false, err + } + return true, nil +} + +func credentialsSecretExists(c client.Client, name, namespace string) []string { + secretExists, err := secretExists(c, name, namespace) + if err != nil { + return []string{ + field.Invalid( + field.NewPath("providerSpec", "credentialsSecret"), + name, + fmt.Sprintf("failed to get credentialsSecret: %v", err), + ).Error(), + } + } + + if !secretExists { + return []string{ + field.Invalid( + field.NewPath("providerSpec", "credentialsSecret"), + name, + "not found. Expected CredentialsSecret to exist", + ).Error(), + } + } + + return []string{} +} + +func getInfra() (*osconfigv1.Infrastructure, error) { + cfg, err := ctrl.GetConfig() + if err != nil { + return nil, err + } + client, err := osclientset.NewForConfig(cfg) + if err != nil { + return nil, err + } + infra, err := client.ConfigV1().Infrastructures().Get(context.Background(), "cluster", metav1.GetOptions{}) + if err != nil { + return nil, err + } + return infra, nil +} + +func getDNS() (*osconfigv1.DNS, error) { + cfg, err := ctrl.GetConfig() + if err != nil { + return nil, err + } + client, err := osclientset.NewForConfig(cfg) + if err != nil { + return nil, err + } + dns, err := client.ConfigV1().DNSes().Get(context.Background(), "cluster", metav1.GetOptions{}) + if err != nil { + return nil, err + } + + return dns, nil +} + +type machineAdmissionFn func(m *machinev1.Machine, config *admissionConfig) (bool, []string, utilerrors.Aggregate) + +type admissionConfig struct { + clusterID string + platformStatus *osconfigv1.PlatformStatus + dnsDisconnected bool + client client.Client +} + +type admissionHandler struct { + *admissionConfig + webhookOperations machineAdmissionFn + decoder *admission.Decoder +} + +// InjectDecoder injects the decoder. +func (a *admissionHandler) InjectDecoder(d *admission.Decoder) error { + a.decoder = d + return nil +} + +// machineValidatorHandler validates Machine API resources. +// implements type Handler interface. +// https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/webhook/admission#Handler +type machineValidatorHandler struct { + *admissionHandler +} + +// machineDefaulterHandler defaults Machine API resources. +// implements type Handler interface. +// https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/webhook/admission#Handler +type machineDefaulterHandler struct { + *admissionHandler +} + +// NewValidator returns a new machineValidatorHandler. +func NewMachineValidator(client client.Client) (*machineValidatorHandler, error) { + infra, err := getInfra() + if err != nil { + return nil, err + } + + dns, err := getDNS() + if err != nil { + return nil, err + } + + return createMachineValidator(infra, client, dns), nil +} + +func createMachineValidator(infra *osconfigv1.Infrastructure, client client.Client, dns *osconfigv1.DNS) *machineValidatorHandler { + admissionConfig := &admissionConfig{ + dnsDisconnected: dns.Spec.PublicZone == nil, + clusterID: infra.Status.InfrastructureName, + platformStatus: infra.Status.PlatformStatus, + client: client, + } + return &machineValidatorHandler{ + admissionHandler: &admissionHandler{ + admissionConfig: admissionConfig, + webhookOperations: getMachineValidatorOperation(infra.Status.PlatformStatus.Type), + }, + } +} + +func getMachineValidatorOperation(platform osconfigv1.PlatformType) machineAdmissionFn { + switch platform { + case osconfigv1.AWSPlatformType: + return validateAWS + case osconfigv1.AzurePlatformType: + return validateAzure + case osconfigv1.GCPPlatformType: + return validateGCP + case osconfigv1.VSpherePlatformType: + return validateVSphere + default: + // just no-op + return func(m *machinev1.Machine, config *admissionConfig) (bool, []string, utilerrors.Aggregate) { + return true, []string{}, nil + } + } +} + +// NewDefaulter returns a new machineDefaulterHandler. +func NewMachineDefaulter() (*machineDefaulterHandler, error) { + infra, err := getInfra() + if err != nil { + return nil, err + } + + return createMachineDefaulter(infra.Status.PlatformStatus, infra.Status.InfrastructureName), nil +} + +func createMachineDefaulter(platformStatus *osconfigv1.PlatformStatus, clusterID string) *machineDefaulterHandler { + return &machineDefaulterHandler{ + admissionHandler: &admissionHandler{ + admissionConfig: &admissionConfig{clusterID: clusterID}, + webhookOperations: getMachineDefaulterOperation(platformStatus), + }, + } +} + +func getMachineDefaulterOperation(platformStatus *osconfigv1.PlatformStatus) machineAdmissionFn { + switch platformStatus.Type { + case osconfigv1.AWSPlatformType: + region := "" + if platformStatus.AWS != nil { + region = platformStatus.AWS.Region + } + arch := runtime.GOARCH + return awsDefaulter{region: region, arch: arch}.defaultAWS + case osconfigv1.AzurePlatformType: + return defaultAzure + case osconfigv1.GCPPlatformType: + return defaultGCP + case osconfigv1.VSpherePlatformType: + return defaultVSphere + default: + // just no-op + return func(m *machinev1.Machine, config *admissionConfig) (bool, []string, utilerrors.Aggregate) { + return true, []string{}, nil + } + } +} + +// NewValidatingWebhookConfiguration creates a validation webhook configuration with configured Machine and MachineSet webhooks +func NewValidatingWebhookConfiguration() *admissionregistrationv1.ValidatingWebhookConfiguration { + validatingWebhookConfiguration := &admissionregistrationv1.ValidatingWebhookConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaultWebhookConfigurationName, + Annotations: map[string]string{ + "service.beta.openshift.io/inject-cabundle": "true", + }, + }, + Webhooks: []admissionregistrationv1.ValidatingWebhook{ + MachineValidatingWebhook(), + MachineSetValidatingWebhook(), + }, + } + + // Setting group version is required for testEnv to create unstructured objects, as the new structure sets it on empty strings + // Usual way to populate those values, is to create the resource in the cluster first, which we can't yet do. + validatingWebhookConfiguration.SetGroupVersionKind(admissionregistrationv1.SchemeGroupVersion.WithKind("ValidatingWebhookConfiguration")) + return validatingWebhookConfiguration +} + +// MachineValidatingWebhook returns validating webhooks for machine to populate the configuration +func MachineValidatingWebhook() admissionregistrationv1.ValidatingWebhook { + serviceReference := admissionregistrationv1.ServiceReference{ + Namespace: defaultWebhookServiceNamespace, + Name: defaultWebhookServiceName, + Path: pointer.StringPtr(DefaultMachineValidatingHookPath), + Port: pointer.Int32Ptr(defaultWebhookServicePort), + } + return admissionregistrationv1.ValidatingWebhook{ + AdmissionReviewVersions: []string{"v1"}, + Name: "validation.machine.machine.openshift.io", + FailurePolicy: &webhookFailurePolicy, + SideEffects: &webhookSideEffects, + ClientConfig: admissionregistrationv1.WebhookClientConfig{ + Service: &serviceReference, + }, + Rules: []admissionregistrationv1.RuleWithOperations{ + { + Rule: admissionregistrationv1.Rule{ + APIGroups: []string{machinev1.GroupName}, + APIVersions: []string{machinev1.SchemeGroupVersion.Version}, + Resources: []string{"machines"}, + }, + Operations: []admissionregistrationv1.OperationType{ + admissionregistrationv1.Create, + admissionregistrationv1.Update, + }, + }, + }, + } +} + +// MachineSetValidatingWebhook returns validating webhooks for machineSet to populate the configuration +func MachineSetValidatingWebhook() admissionregistrationv1.ValidatingWebhook { + machinesetServiceReference := admissionregistrationv1.ServiceReference{ + Namespace: defaultWebhookServiceNamespace, + Name: defaultWebhookServiceName, + Path: pointer.StringPtr(DefaultMachineSetValidatingHookPath), + Port: pointer.Int32Ptr(defaultWebhookServicePort), + } + return admissionregistrationv1.ValidatingWebhook{ + AdmissionReviewVersions: []string{"v1"}, + Name: "validation.machineset.machine.openshift.io", + FailurePolicy: &webhookFailurePolicy, + SideEffects: &webhookSideEffects, + ClientConfig: admissionregistrationv1.WebhookClientConfig{ + Service: &machinesetServiceReference, + }, + Rules: []admissionregistrationv1.RuleWithOperations{ + { + Rule: admissionregistrationv1.Rule{ + APIGroups: []string{machinev1.GroupName}, + APIVersions: []string{machinev1.SchemeGroupVersion.Version}, + Resources: []string{"machinesets"}, + }, + Operations: []admissionregistrationv1.OperationType{ + admissionregistrationv1.Create, + admissionregistrationv1.Update, + }, + }, + }, + } +} + +// NewMutatingWebhookConfiguration creates a mutating webhook configuration with configured Machine and MachineSet webhooks +func NewMutatingWebhookConfiguration() *admissionregistrationv1.MutatingWebhookConfiguration { + mutatingWebhookConfiguration := &admissionregistrationv1.MutatingWebhookConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaultWebhookConfigurationName, + Annotations: map[string]string{ + "service.beta.openshift.io/inject-cabundle": "true", + }, + }, + Webhooks: []admissionregistrationv1.MutatingWebhook{ + MachineMutatingWebhook(), + MachineSetMutatingWebhook(), + }, + } + + // Setting group version is required for testEnv to create unstructured objects, as the new structure sets it on empty strings + // Usual way to populate those values, is to create the resource in the cluster first, which we can't yet do. + mutatingWebhookConfiguration.SetGroupVersionKind(admissionregistrationv1.SchemeGroupVersion.WithKind("MutatingWebhookConfiguration")) + return mutatingWebhookConfiguration +} + +// MachineMutatingWebhook returns mutating webhooks for machine to apply in configuration +func MachineMutatingWebhook() admissionregistrationv1.MutatingWebhook { + machineServiceReference := admissionregistrationv1.ServiceReference{ + Namespace: defaultWebhookServiceNamespace, + Name: defaultWebhookServiceName, + Path: pointer.StringPtr(DefaultMachineMutatingHookPath), + Port: pointer.Int32Ptr(defaultWebhookServicePort), + } + return admissionregistrationv1.MutatingWebhook{ + AdmissionReviewVersions: []string{"v1"}, + Name: "default.machine.machine.openshift.io", + FailurePolicy: &webhookFailurePolicy, + SideEffects: &webhookSideEffects, + ClientConfig: admissionregistrationv1.WebhookClientConfig{ + Service: &machineServiceReference, + }, + Rules: []admissionregistrationv1.RuleWithOperations{ + { + Rule: admissionregistrationv1.Rule{ + APIGroups: []string{machinev1.GroupName}, + APIVersions: []string{machinev1.SchemeGroupVersion.Version}, + Resources: []string{"machines"}, + }, + Operations: []admissionregistrationv1.OperationType{ + admissionregistrationv1.Create, + }, + }, + }, + } +} + +// MachineSetMutatingWebhook returns mutating webhook for machineSet to apply in configuration +func MachineSetMutatingWebhook() admissionregistrationv1.MutatingWebhook { + machineSetServiceReference := admissionregistrationv1.ServiceReference{ + Namespace: defaultWebhookServiceNamespace, + Name: defaultWebhookServiceName, + Path: pointer.StringPtr(DefaultMachineSetMutatingHookPath), + Port: pointer.Int32Ptr(defaultWebhookServicePort), + } + return admissionregistrationv1.MutatingWebhook{ + AdmissionReviewVersions: []string{"v1"}, + Name: "default.machineset.machine.openshift.io", + FailurePolicy: &webhookFailurePolicy, + SideEffects: &webhookSideEffects, + ClientConfig: admissionregistrationv1.WebhookClientConfig{ + Service: &machineSetServiceReference, + }, + Rules: []admissionregistrationv1.RuleWithOperations{ + { + Rule: admissionregistrationv1.Rule{ + APIGroups: []string{machinev1.GroupName}, + APIVersions: []string{machinev1.SchemeGroupVersion.Version}, + Resources: []string{"machinesets"}, + }, + Operations: []admissionregistrationv1.OperationType{ + admissionregistrationv1.Create, + }, + }, + }, + } +} + +// Handle handles HTTP requests for admission webhook servers. +func (h *machineValidatorHandler) Handle(ctx context.Context, req admission.Request) admission.Response { + m := &machinev1.Machine{} + + if err := h.decoder.Decode(req, m); err != nil { + return admission.Errored(http.StatusBadRequest, err) + } + + klog.V(3).Infof("Validate webhook called for Machine: %s", m.GetName()) + + ok, warnings, errs := h.webhookOperations(m, h.admissionConfig) + if !ok { + return admission.Denied(errs.Error()).WithWarnings(warnings...) + } + + return admission.Allowed("Machine valid").WithWarnings(warnings...) +} + +// Handle handles HTTP requests for admission webhook servers. +func (h *machineDefaulterHandler) Handle(ctx context.Context, req admission.Request) admission.Response { + m := &machinev1.Machine{} + + if err := h.decoder.Decode(req, m); err != nil { + return admission.Errored(http.StatusBadRequest, err) + } + + klog.V(3).Infof("Mutate webhook called for Machine: %s", m.GetName()) + + // Only enforce the clusterID if it's not set. + // Otherwise a discrepancy on the value would leave the machine orphan + // and would trigger a new machine creation by the machineSet. + // https://bugzilla.redhat.com/show_bug.cgi?id=1857175 + if m.Labels == nil { + m.Labels = make(map[string]string) + } + if _, ok := m.Labels[machinev1.MachineClusterIDLabel]; !ok { + m.Labels[machinev1.MachineClusterIDLabel] = h.clusterID + } + + ok, warnings, errs := h.webhookOperations(m, h.admissionConfig) + if !ok { + return admission.Denied(errs.Error()).WithWarnings(warnings...) + } + + marshaledMachine, err := json.Marshal(m) + if err != nil { + return admission.Errored(http.StatusInternalServerError, err).WithWarnings(warnings...) + } + return admission.PatchResponseFromRaw(req.Object.Raw, marshaledMachine).WithWarnings(warnings...) +} + +type awsDefaulter struct { + region string + arch string +} + +func (a awsDefaulter) defaultAWS(m *machinev1.Machine, config *admissionConfig) (bool, []string, utilerrors.Aggregate) { + klog.V(3).Infof("Defaulting AWS providerSpec") + + var errs []error + var warnings []string + providerSpec := new(machinev1.AWSMachineProviderConfig) + if err := unmarshalInto(m, providerSpec); err != nil { + errs = append(errs, err) + return false, warnings, utilerrors.NewAggregate(errs) + } + + if providerSpec.InstanceType == "" { + if a.arch == "arm64" { + providerSpec.InstanceType = defaultAWSARMInstanceType + } else { + providerSpec.InstanceType = defaultAWSX86InstanceType + } + } + + if providerSpec.Placement.Region == "" { + providerSpec.Placement.Region = a.region + } + + if providerSpec.UserDataSecret == nil { + providerSpec.UserDataSecret = &corev1.LocalObjectReference{Name: defaultUserDataSecret} + } + + if providerSpec.CredentialsSecret == nil { + providerSpec.CredentialsSecret = &corev1.LocalObjectReference{Name: defaultAWSCredentialsSecret} + } + + rawBytes, err := json.Marshal(providerSpec) + if err != nil { + errs = append(errs, err) + } + + if len(errs) > 0 { + return false, warnings, utilerrors.NewAggregate(errs) + } + + m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} + return true, warnings, nil +} + +func unmarshalInto(m *machinev1.Machine, providerSpec interface{}) error { + if m.Spec.ProviderSpec.Value == nil { + return field.Required(field.NewPath("providerSpec", "value"), "a value must be provided") + } + + if err := yaml.Unmarshal(m.Spec.ProviderSpec.Value.Raw, &providerSpec); err != nil { + return field.Invalid(field.NewPath("providerSpec", "value"), providerSpec, err.Error()) + } + return nil +} + +func validateAWS(m *machinev1.Machine, config *admissionConfig) (bool, []string, utilerrors.Aggregate) { + klog.V(3).Infof("Validating AWS providerSpec") + + var errs []error + var warnings []string + providerSpec := new(machinev1.AWSMachineProviderConfig) + if err := unmarshalInto(m, providerSpec); err != nil { + errs = append(errs, err) + return false, warnings, utilerrors.NewAggregate(errs) + } + + if providerSpec.AMI.ID == nil { + errs = append( + errs, + field.Required( + field.NewPath("providerSpec", "ami"), + "expected providerSpec.ami.id to be populated", + ), + ) + } + + if providerSpec.AMI.ARN != nil { + warnings = append( + warnings, + "can't use providerSpec.ami.arn, only providerSpec.ami.id can be used to reference AMI", + ) + } + + if providerSpec.AMI.Filters != nil { + warnings = append( + warnings, + "can't use providerSpec.ami.filters, only providerSpec.ami.id can be used to reference AMI", + ) + } + + if providerSpec.Placement.Region == "" { + errs = append( + errs, + field.Required( + field.NewPath("providerSpec", "placement", "region"), + "expected providerSpec.placement.region to be populated", + ), + ) + } + + if providerSpec.InstanceType == "" { + errs = append( + errs, + field.Required( + field.NewPath("providerSpec", "instanceType"), + "expected providerSpec.instanceType to be populated", + ), + ) + } + + if providerSpec.UserDataSecret == nil { + errs = append( + errs, + field.Required( + field.NewPath("providerSpec", "userDataSecret"), + "expected providerSpec.userDataSecret to be populated", + ), + ) + } + + if providerSpec.CredentialsSecret == nil { + errs = append( + errs, + field.Required( + field.NewPath("providerSpec", "credentialsSecret"), + "expected providerSpec.credentialsSecret to be populated", + ), + ) + } else { + warnings = append(warnings, credentialsSecretExists(config.client, providerSpec.CredentialsSecret.Name, m.GetNamespace())...) + } + + if providerSpec.Subnet.ARN == nil && providerSpec.Subnet.ID == nil && providerSpec.Subnet.Filters == nil { + warnings = append( + warnings, + "providerSpec.subnet: No subnet has been provided. Instances may be created in an unexpected subnet and may not join the cluster.", + ) + } + + if providerSpec.IAMInstanceProfile == nil { + warnings = append(warnings, "providerSpec.iamInstanceProfile: no IAM instance profile provided: nodes may be unable to join the cluster") + } + + // TODO(alberto): Validate providerSpec.BlockDevices. + // https://github.com/openshift/cluster-api-provider-aws/pull/299#discussion_r433920532 + + switch providerSpec.Placement.Tenancy { + case "", machinev1.DefaultTenancy, machinev1.DedicatedTenancy, machinev1.HostTenancy: + // Do nothing, valid values + default: + errs = append( + errs, + field.Invalid( + field.NewPath("providerSpec", "tenancy"), + providerSpec.Placement.Tenancy, + fmt.Sprintf("Invalid providerSpec.tenancy, the only allowed options are: %s, %s, %s", machinev1.DefaultTenancy, machinev1.DedicatedTenancy, machinev1.HostTenancy), + ), + ) + } + + duplicatedTags := getDuplicatedTags(providerSpec.Tags) + if len(duplicatedTags) > 0 { + warnings = append(warnings, fmt.Sprintf("providerSpec.tags: duplicated tag names (%s): only the first value will be used.", strings.Join(duplicatedTags, ","))) + } + + if len(errs) > 0 { + return false, warnings, utilerrors.NewAggregate(errs) + } + + return true, warnings, nil +} + +// getDuplicatedTags iterates through the AWS TagSpecifications +// to determine if any tag Name is duplicated within the list. +// A list of duplicated names will be returned. +func getDuplicatedTags(tagSpecs []machinev1.TagSpecification) []string { + tagNames := map[string]int{} + duplicatedTags := []string{} + for _, spec := range tagSpecs { + tagNames[spec.Name] += 1 + // Only append the duplicated tag on the second occurrence to prevent it + // being listed multiple times when there are more than 2 occurrences. + if tagNames[spec.Name] == 2 { + duplicatedTags = append(duplicatedTags, spec.Name) + } + } + return duplicatedTags +} + +func defaultAzure(m *machinev1.Machine, config *admissionConfig) (bool, []string, utilerrors.Aggregate) { + klog.V(3).Infof("Defaulting Azure providerSpec") + + var errs []error + var warnings []string + providerSpec := new(machinev1.AzureMachineProviderSpec) + if err := unmarshalInto(m, providerSpec); err != nil { + errs = append(errs, err) + return false, warnings, utilerrors.NewAggregate(errs) + } + + if providerSpec.VMSize == "" { + providerSpec.VMSize = defaultAzureVMSize + } + + // Vnet and Subnet need to be provided together by the user + if providerSpec.Vnet == "" && providerSpec.Subnet == "" { + providerSpec.Vnet = defaultAzureVnet(config.clusterID) + providerSpec.Subnet = defaultAzureSubnet(config.clusterID) + } + + if providerSpec.Image == (machinev1.Image{}) { + providerSpec.Image.ResourceID = defaultAzureImageResourceID(config.clusterID) + } + + if providerSpec.UserDataSecret == nil { + providerSpec.UserDataSecret = &corev1.SecretReference{Name: defaultUserDataSecret} + } else if providerSpec.UserDataSecret.Name == "" { + providerSpec.UserDataSecret.Name = defaultUserDataSecret + } + + if providerSpec.CredentialsSecret == nil { + providerSpec.CredentialsSecret = &corev1.SecretReference{Name: defaultAzureCredentialsSecret, Namespace: defaultSecretNamespace} + } else { + if providerSpec.CredentialsSecret.Namespace == "" { + providerSpec.CredentialsSecret.Namespace = defaultSecretNamespace + } + if providerSpec.CredentialsSecret.Name == "" { + providerSpec.CredentialsSecret.Name = defaultAzureCredentialsSecret + } + } + + rawBytes, err := json.Marshal(providerSpec) + if err != nil { + errs = append(errs, err) + } + + if len(errs) > 0 { + return false, warnings, utilerrors.NewAggregate(errs) + } + + m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} + return true, warnings, nil +} + +func validateAzure(m *machinev1.Machine, config *admissionConfig) (bool, []string, utilerrors.Aggregate) { + klog.V(3).Infof("Validating Azure providerSpec") + + var errs []error + var warnings []string + providerSpec := new(machinev1.AzureMachineProviderSpec) + if err := unmarshalInto(m, providerSpec); err != nil { + errs = append(errs, err) + return false, warnings, utilerrors.NewAggregate(errs) + } + + if providerSpec.VMSize == "" { + errs = append(errs, field.Required(field.NewPath("providerSpec", "vmSize"), "vmSize should be set to one of the supported Azure VM sizes")) + } + + if providerSpec.PublicIP && config.dnsDisconnected { + errs = append(errs, field.Forbidden(field.NewPath("providerSpec", "publicIP"), "publicIP is not allowed in Azure disconnected installation")) + } + // Vnet requires Subnet + if providerSpec.Vnet != "" && providerSpec.Subnet == "" { + errs = append(errs, field.Required(field.NewPath("providerSpec", "subnet"), "must provide a subnet when a virtual network is specified")) + } + + // Subnet requires Vnet + if providerSpec.Subnet != "" && providerSpec.Vnet == "" { + errs = append(errs, field.Required(field.NewPath("providerSpec", "vnet"), "must provide a virtual network when supplying subnets")) + } + + errs = append(errs, validateAzureImage(providerSpec.Image)...) + + if providerSpec.UserDataSecret == nil { + errs = append(errs, field.Required(field.NewPath("providerSpec", "userDataSecret"), "userDataSecret must be provided")) + } else if providerSpec.UserDataSecret.Name == "" { + errs = append(errs, field.Required(field.NewPath("providerSpec", "userDataSecret", "name"), "name must be provided")) + } + + if providerSpec.CredentialsSecret == nil { + errs = append(errs, field.Required(field.NewPath("providerSpec", "credentialsSecret"), "credentialsSecret must be provided")) + } else { + if providerSpec.CredentialsSecret.Namespace == "" { + errs = append(errs, field.Required(field.NewPath("providerSpec", "credentialsSecret", "namespace"), "namespace must be provided")) + } + if providerSpec.CredentialsSecret.Name == "" { + errs = append(errs, field.Required(field.NewPath("providerSpec", "credentialsSecret", "name"), "name must be provided")) + } + if providerSpec.CredentialsSecret.Name != "" && providerSpec.CredentialsSecret.Namespace != "" { + warnings = append(warnings, credentialsSecretExists(config.client, providerSpec.CredentialsSecret.Name, providerSpec.CredentialsSecret.Namespace)...) + } + } + + if providerSpec.OSDisk.DiskSizeGB <= 0 || providerSpec.OSDisk.DiskSizeGB >= azureMaxDiskSizeGB { + errs = append(errs, field.Invalid(field.NewPath("providerSpec", "osDisk", "diskSizeGB"), providerSpec.OSDisk.DiskSizeGB, "diskSizeGB must be greater than zero and less than 32768")) + } + + if isAzureGovCloud(config.platformStatus) && providerSpec.SpotVMOptions != nil { + warnings = append(warnings, "spot VMs may not be supported when using GovCloud region") + } + + if len(errs) > 0 { + return false, warnings, utilerrors.NewAggregate(errs) + } + return true, warnings, nil +} + +func validateAzureImage(image machinev1.Image) []error { + errors := []error{} + if image == (machinev1.Image{}) { + return append(errors, field.Required(field.NewPath("providerSpec", "image"), "an image reference must be provided")) + } + + if image.ResourceID != "" { + if image != (machinev1.Image{ResourceID: image.ResourceID}) { + return append(errors, field.Required(field.NewPath("providerSpec", "image", "resourceID"), "resourceID is already specified, other fields such as [Offer, Publisher, SKU, Version] should not be set")) + } + return errors + } + + // Resource ID not provided, so Offer, Publisher, SKU and Version are required + if image.Offer == "" { + errors = append(errors, field.Required(field.NewPath("providerSpec", "image", "Offer"), "Offer must be provided")) + } + if image.Publisher == "" { + errors = append(errors, field.Required(field.NewPath("providerSpec", "image", "Publisher"), "Publisher must be provided")) + } + if image.SKU == "" { + errors = append(errors, field.Required(field.NewPath("providerSpec", "image", "SKU"), "SKU must be provided")) + } + if image.Version == "" { + errors = append(errors, field.Required(field.NewPath("providerSpec", "image", "Version"), "Version must be provided")) + } + + return errors +} + +func defaultGCP(m *machinev1.Machine, config *admissionConfig) (bool, []string, utilerrors.Aggregate) { + klog.V(3).Infof("Defaulting GCP providerSpec") + + var errs []error + var warnings []string + providerSpec := new(machinev1.GCPMachineProviderSpec) + if err := unmarshalInto(m, providerSpec); err != nil { + errs = append(errs, err) + return false, warnings, utilerrors.NewAggregate(errs) + } + + if providerSpec.MachineType == "" { + providerSpec.MachineType = defaultGCPMachineType + } + + if len(providerSpec.NetworkInterfaces) == 0 { + providerSpec.NetworkInterfaces = append(providerSpec.NetworkInterfaces, &machinev1.GCPNetworkInterface{ + Network: defaultGCPNetwork(config.clusterID), + Subnetwork: defaultGCPSubnetwork(config.clusterID), + }) + } + + providerSpec.Disks = defaultGCPDisks(providerSpec.Disks, config.clusterID) + + if len(providerSpec.Tags) == 0 { + providerSpec.Tags = defaultGCPTags(config.clusterID) + } + + if providerSpec.UserDataSecret == nil { + providerSpec.UserDataSecret = &corev1.LocalObjectReference{Name: defaultUserDataSecret} + } + + if providerSpec.CredentialsSecret == nil { + providerSpec.CredentialsSecret = &corev1.LocalObjectReference{Name: defaultGCPCredentialsSecret} + } + + rawBytes, err := json.Marshal(providerSpec) + if err != nil { + errs = append(errs, err) + } + + if len(errs) > 0 { + return false, warnings, utilerrors.NewAggregate(errs) + } + + m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} + return true, warnings, nil +} + +func defaultGCPDisks(disks []*machinev1.GCPDisk, clusterID string) []*machinev1.GCPDisk { + if len(disks) == 0 { + return []*machinev1.GCPDisk{ + { + AutoDelete: true, + Boot: true, + SizeGB: defaultGCPDiskSizeGb, + Type: defaultGCPDiskType, + Image: defaultGCPDiskImage, + }, + } + } + + for _, disk := range disks { + if disk.Type == "" { + disk.Type = defaultGCPDiskType + } + + if disk.Image == "" { + disk.Image = defaultGCPDiskImage + } + } + + return disks +} + +func validateGCP(m *machinev1.Machine, config *admissionConfig) (bool, []string, utilerrors.Aggregate) { + klog.V(3).Infof("Validating GCP providerSpec") + + var errs []error + var warnings []string + providerSpec := new(machinev1.GCPMachineProviderSpec) + if err := unmarshalInto(m, providerSpec); err != nil { + errs = append(errs, err) + return false, warnings, utilerrors.NewAggregate(errs) + } + + if providerSpec.Region == "" { + errs = append(errs, field.Required(field.NewPath("providerSpec", "region"), "region is required")) + } + + if !strings.HasPrefix(providerSpec.Zone, providerSpec.Region) { + errs = append(errs, field.Invalid(field.NewPath("providerSpec", "zone"), providerSpec.Zone, fmt.Sprintf("zone not in configured region (%s)", providerSpec.Region))) + } + + if providerSpec.MachineType == "" { + errs = append(errs, field.Required(field.NewPath("providerSpec", "machineType"), "machineType should be set to one of the supported GCP machine types")) + } + + errs = append(errs, validateGCPNetworkInterfaces(providerSpec.NetworkInterfaces, field.NewPath("providerSpec", "networkInterfaces"))...) + errs = append(errs, validateGCPDisks(providerSpec.Disks, field.NewPath("providerSpec", "disks"))...) + + if len(providerSpec.ServiceAccounts) == 0 { + warnings = append(warnings, "providerSpec.serviceAccounts: no service account provided: nodes may be unable to join the cluster") + } else { + errs = append(errs, validateGCPServiceAccounts(providerSpec.ServiceAccounts, field.NewPath("providerSpec", "serviceAccounts"))...) + } + + if providerSpec.UserDataSecret == nil { + errs = append(errs, field.Required(field.NewPath("providerSpec", "userDataSecret"), "userDataSecret must be provided")) + } else { + if providerSpec.UserDataSecret.Name == "" { + errs = append(errs, field.Required(field.NewPath("providerSpec", "userDataSecret", "name"), "name must be provided")) + } + } + + if providerSpec.CredentialsSecret == nil { + errs = append(errs, field.Required(field.NewPath("providerSpec", "credentialsSecret"), "credentialsSecret must be provided")) + } else { + if providerSpec.CredentialsSecret.Name == "" { + errs = append(errs, field.Required(field.NewPath("providerSpec", "credentialsSecret", "name"), "name must be provided")) + } else { + warnings = append(warnings, credentialsSecretExists(config.client, providerSpec.CredentialsSecret.Name, m.GetNamespace())...) + } + } + + if len(errs) > 0 { + return false, warnings, utilerrors.NewAggregate(errs) + } + return true, warnings, nil +} + +func validateGCPNetworkInterfaces(networkInterfaces []*machinev1.GCPNetworkInterface, parentPath *field.Path) []error { + if len(networkInterfaces) == 0 { + return []error{field.Required(parentPath, "at least 1 network interface is required")} + } + + var errs []error + for i, ni := range networkInterfaces { + fldPath := parentPath.Index(i) + + if ni.Network == "" { + errs = append(errs, field.Required(fldPath.Child("network"), "network is required")) + } + + if ni.Subnetwork == "" { + errs = append(errs, field.Required(fldPath.Child("subnetwork"), "subnetwork is required")) + } + } + + return errs +} + +func validateGCPDisks(disks []*machinev1.GCPDisk, parentPath *field.Path) []error { + if len(disks) == 0 { + return []error{field.Required(parentPath, "at least 1 disk is required")} + } + + var errs []error + for i, disk := range disks { + fldPath := parentPath.Index(i) + + if disk.SizeGB != 0 { + if disk.SizeGB < 16 { + errs = append(errs, field.Invalid(fldPath.Child("sizeGb"), disk.SizeGB, "must be at least 16GB in size")) + } else if disk.SizeGB > 65536 { + errs = append(errs, field.Invalid(fldPath.Child("sizeGb"), disk.SizeGB, "exceeding maximum GCP disk size limit, must be below 65536")) + } + } + + if disk.Type != "" { + diskTypes := sets.NewString("pd-standard", "pd-ssd") + if !diskTypes.Has(disk.Type) { + errs = append(errs, field.NotSupported(fldPath.Child("type"), disk.Type, diskTypes.List())) + } + } + } + + return errs +} + +func validateGCPServiceAccounts(serviceAccounts []machinev1.GCPServiceAccount, parentPath *field.Path) []error { + if len(serviceAccounts) != 1 { + return []error{field.Invalid(parentPath, fmt.Sprintf("%d service accounts supplied", len(serviceAccounts)), "exactly 1 service account must be supplied")} + } + + var errs []error + for i, serviceAccount := range serviceAccounts { + fldPath := parentPath.Index(i) + + if serviceAccount.Email == "" { + errs = append(errs, field.Required(fldPath.Child("email"), "email is required")) + } + + if len(serviceAccount.Scopes) == 0 { + errs = append(errs, field.Required(fldPath.Child("scopes"), "at least 1 scope is required")) + } + } + return errs +} + +func defaultVSphere(m *machinev1.Machine, config *admissionConfig) (bool, []string, utilerrors.Aggregate) { + klog.V(3).Infof("Defaulting vSphere providerSpec") + + var errs []error + var warnings []string + providerSpec := new(machinev1.VSphereMachineProviderSpec) + if err := unmarshalInto(m, providerSpec); err != nil { + errs = append(errs, err) + return false, warnings, utilerrors.NewAggregate(errs) + } + + if providerSpec.UserDataSecret == nil { + providerSpec.UserDataSecret = &corev1.LocalObjectReference{Name: defaultUserDataSecret} + } + + if providerSpec.CredentialsSecret == nil { + providerSpec.CredentialsSecret = &corev1.LocalObjectReference{Name: defaultVSphereCredentialsSecret} + } + + rawBytes, err := json.Marshal(providerSpec) + if err != nil { + errs = append(errs, err) + } + + if len(errs) > 0 { + return false, warnings, utilerrors.NewAggregate(errs) + } + + m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} + return true, warnings, nil +} + +func validateVSphere(m *machinev1.Machine, config *admissionConfig) (bool, []string, utilerrors.Aggregate) { + klog.V(3).Infof("Validating vSphere providerSpec") + + var errs []error + var warnings []string + providerSpec := new(machinev1.VSphereMachineProviderSpec) + if err := unmarshalInto(m, providerSpec); err != nil { + errs = append(errs, err) + return false, warnings, utilerrors.NewAggregate(errs) + } + + if providerSpec.Template == "" { + errs = append(errs, field.Required(field.NewPath("providerSpec", "template"), "template must be provided")) + } + + workspaceWarnings, workspaceErrors := validateVSphereWorkspace(providerSpec.Workspace, field.NewPath("providerSpec", "workspace")) + warnings = append(warnings, workspaceWarnings...) + errs = append(errs, workspaceErrors...) + + errs = append(errs, validateVSphereNetwork(providerSpec.Network, field.NewPath("providerSpec", "network"))...) + + if providerSpec.NumCPUs < minVSphereCPU { + warnings = append(warnings, fmt.Sprintf("providerSpec.numCPUs: %d is missing or less than the minimum value (%d): nodes may not boot correctly", providerSpec.NumCPUs, minVSphereCPU)) + } + if providerSpec.MemoryMiB < minVSphereMemoryMiB { + warnings = append(warnings, fmt.Sprintf("providerSpec.memoryMiB: %d is missing or less than the recommended minimum value (%d): nodes may not boot correctly", providerSpec.MemoryMiB, minVSphereMemoryMiB)) + } + if providerSpec.DiskGiB < minVSphereDiskGiB { + warnings = append(warnings, fmt.Sprintf("providerSpec.diskGiB: %d is missing or less than the recommended minimum (%d): nodes may fail to start if disk size is too low", providerSpec.DiskGiB, minVSphereDiskGiB)) + } + + if providerSpec.UserDataSecret == nil { + errs = append(errs, field.Required(field.NewPath("providerSpec", "userDataSecret"), "userDataSecret must be provided")) + } else { + if providerSpec.UserDataSecret.Name == "" { + errs = append(errs, field.Required(field.NewPath("providerSpec", "userDataSecret", "name"), "name must be provided")) + } + } + + if providerSpec.CredentialsSecret == nil { + errs = append(errs, field.Required(field.NewPath("providerSpec", "credentialsSecret"), "credentialsSecret must be provided")) + } else { + if providerSpec.CredentialsSecret.Name == "" { + errs = append(errs, field.Required(field.NewPath("providerSpec", "credentialsSecret", "name"), "name must be provided")) + } else { + warnings = append(warnings, credentialsSecretExists(config.client, providerSpec.CredentialsSecret.Name, m.GetNamespace())...) + } + } + + if len(errs) > 0 { + return false, warnings, utilerrors.NewAggregate(errs) + } + return true, warnings, nil +} + +func validateVSphereWorkspace(workspace *machinev1.Workspace, parentPath *field.Path) ([]string, []error) { + if workspace == nil { + return []string{}, []error{field.Required(parentPath, "workspace must be provided")} + } + + var errs []error + var warnings []string + if workspace.Server == "" { + errs = append(errs, field.Required(parentPath.Child("server"), "server must be provided")) + } + if workspace.Datacenter == "" { + warnings = append(warnings, fmt.Sprintf("%s: datacenter is unset: if more than one datacenter is present, VMs cannot be created", parentPath.Child("datacenter"))) + } + if workspace.Folder != "" { + expectedPrefix := fmt.Sprintf("/%s/vm/", workspace.Datacenter) + if !strings.HasPrefix(workspace.Folder, expectedPrefix) { + errMsg := fmt.Sprintf("folder must be absolute path: expected prefix %q", expectedPrefix) + errs = append(errs, field.Invalid(parentPath.Child("folder"), workspace.Folder, errMsg)) + } + } + + return warnings, errs +} + +func validateVSphereNetwork(network machinev1.NetworkSpec, parentPath *field.Path) []error { + if len(network.Devices) == 0 { + return []error{field.Required(parentPath.Child("devices"), "at least 1 network device must be provided")} + } + + var errs []error + for i, spec := range network.Devices { + fldPath := parentPath.Child("devices").Index(i) + if spec.NetworkName == "" { + errs = append(errs, field.Required(fldPath.Child("networkName"), "networkName must be provided")) + } + } + + return errs +} + +func isAzureGovCloud(platformStatus *osconfigv1.PlatformStatus) bool { + return platformStatus != nil && platformStatus.Azure != nil && + platformStatus.Azure.CloudName != osconfigv1.AzurePublicCloud +} diff --git a/pkg/webhooks/machine_webhook_test.go b/pkg/webhooks/machine_webhook_test.go new file mode 100644 index 0000000000..4d2308edde --- /dev/null +++ b/pkg/webhooks/machine_webhook_test.go @@ -0,0 +1,2403 @@ +package webhooks + +import ( + "context" + "encoding/json" + "fmt" + "reflect" + "runtime" + "testing" + + . "github.com/onsi/gomega" + osconfigv1 "github.com/openshift/api/config/v1" + machinev1 "github.com/openshift/api/machine/v1beta1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/equality" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + kruntime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "k8s.io/utils/pointer" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client/config" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/webhook" + yaml "sigs.k8s.io/yaml" +) + +var ( + plainDNS = &osconfigv1.DNS{Spec: osconfigv1.DNSSpec{}} + plainInfra = &osconfigv1.Infrastructure{ + Status: osconfigv1.InfrastructureStatus{ + PlatformStatus: &osconfigv1.PlatformStatus{}, + }, + } +) + +func TestMachineCreation(t *testing.T) { + g := NewWithT(t) + + // Override config getter + ctrl.GetConfig = func() (*rest.Config, error) { + return cfg, nil + } + defer func() { + ctrl.GetConfig = config.GetConfig + }() + + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine-creation-test", + }, + } + g.Expect(c.Create(ctx, namespace)).To(Succeed()) + defer func() { + g.Expect(c.Delete(ctx, namespace)).To(Succeed()) + }() + + awsSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaultAWSCredentialsSecret, + Namespace: namespace.Name, + }, + } + vSphereSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaultVSphereCredentialsSecret, + Namespace: namespace.Name, + }, + } + GCPSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaultGCPCredentialsSecret, + Namespace: namespace.Name, + }, + } + azureSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaultAzureCredentialsSecret, + Namespace: defaultSecretNamespace, + }, + } + g.Expect(c.Create(ctx, awsSecret)).To(Succeed()) + g.Expect(c.Create(ctx, vSphereSecret)).To(Succeed()) + g.Expect(c.Create(ctx, GCPSecret)).To(Succeed()) + g.Expect(c.Create(ctx, azureSecret)).To(Succeed()) + defer func() { + g.Expect(c.Delete(ctx, awsSecret)).To(Succeed()) + g.Expect(c.Delete(ctx, vSphereSecret)).To(Succeed()) + g.Expect(c.Delete(ctx, GCPSecret)).To(Succeed()) + g.Expect(c.Delete(ctx, azureSecret)).To(Succeed()) + }() + + testCases := []struct { + name string + platformType osconfigv1.PlatformType + clusterID string + presetClusterID bool + expectedError string + disconnected bool + providerSpecValue *kruntime.RawExtension + }{ + { + name: "with AWS and a nil provider spec value", + platformType: osconfigv1.AWSPlatformType, + clusterID: "aws-cluster", + providerSpecValue: nil, + expectedError: "providerSpec.value: Required value: a value must be provided", + }, + { + name: "with AWS and no fields set", + platformType: osconfigv1.AWSPlatformType, + clusterID: "aws-cluster", + providerSpecValue: &kruntime.RawExtension{ + Object: &machinev1.AWSMachineProviderConfig{}, + }, + expectedError: "providerSpec.ami: Required value: expected providerSpec.ami.id to be populated", + }, + { + name: "with AWS and an AMI ID set", + platformType: osconfigv1.AWSPlatformType, + clusterID: "aws-cluster", + providerSpecValue: &kruntime.RawExtension{ + Object: &machinev1.AWSMachineProviderConfig{ + AMI: machinev1.AWSResourceReference{ + ID: pointer.StringPtr("ami"), + }, + }, + }, + expectedError: "", + }, + { + name: "with Azure and a nil provider spec value", + platformType: osconfigv1.AzurePlatformType, + clusterID: "azure-cluster", + providerSpecValue: nil, + expectedError: "providerSpec.value: Required value: a value must be provided", + }, + { + name: "with Azure and no fields set", + platformType: osconfigv1.AzurePlatformType, + clusterID: "azure-cluster", + providerSpecValue: &kruntime.RawExtension{ + Object: &machinev1.AzureMachineProviderSpec{}, + }, + expectedError: "providerSpec.osDisk.diskSizeGB: Invalid value: 0: diskSizeGB must be greater than zero and less than 32768", + }, + { + name: "with Azure and a disk size set", + platformType: osconfigv1.AzurePlatformType, + clusterID: "azure-cluster", + providerSpecValue: &kruntime.RawExtension{ + Object: &machinev1.AzureMachineProviderSpec{ + OSDisk: machinev1.OSDisk{ + DiskSizeGB: 128, + }, + }, + }, + expectedError: "", + }, + { + name: "with Azure disconnected installation request public IP", + platformType: osconfigv1.AzurePlatformType, + clusterID: "azure-cluster", + providerSpecValue: &kruntime.RawExtension{ + Object: &machinev1.AzureMachineProviderSpec{ + OSDisk: machinev1.OSDisk{ + DiskSizeGB: 128, + }, + PublicIP: true, + }, + }, + disconnected: true, + expectedError: "providerSpec.publicIP: Forbidden: publicIP is not allowed in Azure disconnected installation", + }, + { + name: "with Azure disconnected installation success", + platformType: osconfigv1.AzurePlatformType, + clusterID: "azure-cluster", + providerSpecValue: &kruntime.RawExtension{ + Object: &machinev1.AzureMachineProviderSpec{ + OSDisk: machinev1.OSDisk{ + DiskSizeGB: 128, + }, + }, + }, + disconnected: true, + }, + { + name: "with GCP and a nil provider spec value", + platformType: osconfigv1.GCPPlatformType, + clusterID: "gcp-cluster", + providerSpecValue: nil, + expectedError: "providerSpec.value: Required value: a value must be provided", + }, + { + name: "with GCP and no fields set", + platformType: osconfigv1.GCPPlatformType, + clusterID: "gcp-cluster", + providerSpecValue: &kruntime.RawExtension{ + Object: &machinev1.GCPMachineProviderSpec{}, + }, + expectedError: "providerSpec.region: Required value: region is required", + }, + { + name: "with GCP and the region and zone set", + platformType: osconfigv1.GCPPlatformType, + clusterID: "gcp-cluster", + providerSpecValue: &kruntime.RawExtension{ + Object: &machinev1.GCPMachineProviderSpec{ + Region: "region", + Zone: "region-zone", + }, + }, + expectedError: "", + }, + { + name: "with vSphere and a nil provider spec value", + platformType: osconfigv1.VSpherePlatformType, + clusterID: "vsphere-cluster", + providerSpecValue: nil, + expectedError: "providerSpec.value: Required value: a value must be provided", + }, + { + name: "with vSphere and no fields set", + platformType: osconfigv1.VSpherePlatformType, + clusterID: "vsphere-cluster", + providerSpecValue: &kruntime.RawExtension{ + Object: &machinev1.VSphereMachineProviderSpec{}, + }, + expectedError: "[providerSpec.template: Required value: template must be provided, providerSpec.workspace: Required value: workspace must be provided, providerSpec.network.devices: Required value: at least 1 network device must be provided]", + }, + { + name: "with vSphere and the template, workspace and network devices set", + platformType: osconfigv1.VSpherePlatformType, + clusterID: "vsphere-cluster", + presetClusterID: true, + providerSpecValue: &kruntime.RawExtension{ + Object: &machinev1.VSphereMachineProviderSpec{ + Template: "template", + Workspace: &machinev1.Workspace{ + Datacenter: "datacenter", + Server: "server", + }, + Network: machinev1.NetworkSpec{ + Devices: []machinev1.NetworkDeviceSpec{ + { + NetworkName: "networkName", + }, + }, + }, + }, + }, + expectedError: "", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + gs := NewWithT(t) + + mgr, err := manager.New(cfg, manager.Options{ + MetricsBindAddress: "0", + Port: testEnv.WebhookInstallOptions.LocalServingPort, + CertDir: testEnv.WebhookInstallOptions.LocalServingCertDir, + }) + gs.Expect(err).ToNot(HaveOccurred()) + + platformStatus := &osconfigv1.PlatformStatus{ + Type: tc.platformType, + GCP: &osconfigv1.GCPPlatformStatus{ + ProjectID: "gcp-project-id", + }, + AWS: &osconfigv1.AWSPlatformStatus{ + Region: "region", + }, + } + infra := plainInfra.DeepCopy() + infra.Status.InfrastructureName = tc.clusterID + infra.Status.PlatformStatus = platformStatus + + dns := plainDNS.DeepCopy() + if !tc.disconnected { + dns.Spec.PublicZone = &osconfigv1.DNSZone{} + } + machineDefaulter := createMachineDefaulter(platformStatus, tc.clusterID) + machineValidator := createMachineValidator(infra, c, dns) + mgr.GetWebhookServer().Register(DefaultMachineMutatingHookPath, &webhook.Admission{Handler: machineDefaulter}) + mgr.GetWebhookServer().Register(DefaultMachineValidatingHookPath, &webhook.Admission{Handler: machineValidator}) + + mgrCtx, cancel := context.WithCancel(context.Background()) + stopped := make(chan struct{}) + go func() { + gs.Expect(mgr.Start(mgrCtx)).To(Succeed()) + close(stopped) + }() + defer func() { + cancel() + <-stopped + }() + + gs.Eventually(func() (bool, error) { + resp, err := insecureHTTPClient.Get(fmt.Sprintf("https://127.0.0.1:%d", testEnv.WebhookInstallOptions.LocalServingPort)) + if err != nil { + return false, err + } + return resp.StatusCode == 404, nil + }).Should(BeTrue()) + + m := &machinev1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "machine-creation-", + Namespace: namespace.Name, + }, + Spec: machinev1.MachineSpec{ + ProviderSpec: machinev1.ProviderSpec{ + Value: tc.providerSpecValue, + }, + }, + } + + presetClusterID := "anything" + if tc.presetClusterID { + m.Labels = make(map[string]string) + m.Labels[machinev1.MachineClusterIDLabel] = presetClusterID + } + + err = c.Create(ctx, m) + if err == nil { + defer func() { + gs.Expect(c.Delete(ctx, m)).To(Succeed()) + }() + } + + if tc.expectedError != "" { + gs.Expect(err).ToNot(BeNil()) + gs.Expect(apierrors.ReasonForError(err)).To(BeEquivalentTo(tc.expectedError)) + } else { + if tc.presetClusterID { + gs.Expect(m.Labels[machinev1.MachineClusterIDLabel]).To(BeIdenticalTo(presetClusterID)) + } else { + gs.Expect(m.Labels[machinev1.MachineClusterIDLabel]).To(BeIdenticalTo(tc.clusterID)) + } + gs.Expect(err).To(BeNil()) + } + }) + } +} + +func TestMachineUpdate(t *testing.T) { + awsClusterID := "aws-cluster" + awsRegion := "region" + defaultAWSProviderSpec := &machinev1.AWSMachineProviderConfig{ + AMI: machinev1.AWSResourceReference{ + ID: pointer.StringPtr("ami"), + }, + InstanceType: defaultAWSX86InstanceType, + UserDataSecret: &corev1.LocalObjectReference{Name: defaultUserDataSecret}, + CredentialsSecret: &corev1.LocalObjectReference{Name: defaultAWSCredentialsSecret}, + Placement: machinev1.Placement{ + Region: awsRegion, + }, + } + + azureClusterID := "azure-cluster" + defaultAzureProviderSpec := &machinev1.AzureMachineProviderSpec{ + Location: "location", + VMSize: defaultAzureVMSize, + Vnet: defaultAzureVnet(azureClusterID), + Subnet: defaultAzureSubnet(azureClusterID), + NetworkResourceGroup: defaultAzureNetworkResourceGroup(azureClusterID), + Image: machinev1.Image{ + ResourceID: defaultAzureImageResourceID(azureClusterID), + }, + ManagedIdentity: defaultAzureManagedIdentiy(azureClusterID), + ResourceGroup: defaultAzureResourceGroup(azureClusterID), + UserDataSecret: &corev1.SecretReference{ + Name: defaultUserDataSecret, + Namespace: defaultSecretNamespace, + }, + CredentialsSecret: &corev1.SecretReference{ + Name: defaultAzureCredentialsSecret, + Namespace: defaultSecretNamespace, + }, + OSDisk: machinev1.OSDisk{ + DiskSizeGB: 128, + OSType: defaultAzureOSDiskOSType, + ManagedDisk: machinev1.ManagedDiskParameters{ + StorageAccountType: defaultAzureOSDiskStorageType, + }, + }, + } + + gcpClusterID := "gcp-cluster" + defaultGCPProviderSpec := &machinev1.GCPMachineProviderSpec{ + Region: "region", + Zone: "region-zone", + MachineType: defaultGCPMachineType, + NetworkInterfaces: []*machinev1.GCPNetworkInterface{ + { + Network: defaultGCPNetwork(gcpClusterID), + Subnetwork: defaultGCPSubnetwork(gcpClusterID), + }, + }, + Disks: []*machinev1.GCPDisk{ + { + AutoDelete: true, + Boot: true, + SizeGB: defaultGCPDiskSizeGb, + Type: defaultGCPDiskType, + Image: defaultGCPDiskImage, + }, + }, + Tags: defaultGCPTags(gcpClusterID), + UserDataSecret: &corev1.LocalObjectReference{ + Name: defaultUserDataSecret, + }, + CredentialsSecret: &corev1.LocalObjectReference{ + Name: defaultGCPCredentialsSecret, + }, + } + vsphereClusterID := "vsphere-cluster" + defaultVSphereProviderSpec := &machinev1.VSphereMachineProviderSpec{ + Template: "template", + Workspace: &machinev1.Workspace{ + Datacenter: "datacenter", + Server: "server", + }, + Network: machinev1.NetworkSpec{ + Devices: []machinev1.NetworkDeviceSpec{ + { + NetworkName: "networkName", + }, + }, + }, + UserDataSecret: &corev1.LocalObjectReference{ + Name: defaultUserDataSecret, + }, + CredentialsSecret: &corev1.LocalObjectReference{ + Name: defaultVSphereCredentialsSecret, + }, + } + + g := NewWithT(t) + + // Override config getter + ctrl.GetConfig = func() (*rest.Config, error) { + return cfg, nil + } + defer func() { + ctrl.GetConfig = config.GetConfig + }() + + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine-update-test", + }, + } + g.Expect(c.Create(ctx, namespace)).To(Succeed()) + defer func() { + g.Expect(c.Delete(ctx, namespace)).To(Succeed()) + }() + + awsSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaultAWSCredentialsSecret, + Namespace: namespace.Name, + }, + } + vSphereSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaultVSphereCredentialsSecret, + Namespace: namespace.Name, + }, + } + GCPSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaultGCPCredentialsSecret, + Namespace: namespace.Name, + }, + } + azureSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaultAzureCredentialsSecret, + Namespace: defaultSecretNamespace, + }, + } + g.Expect(c.Create(ctx, awsSecret)).To(Succeed()) + g.Expect(c.Create(ctx, vSphereSecret)).To(Succeed()) + g.Expect(c.Create(ctx, GCPSecret)).To(Succeed()) + g.Expect(c.Create(ctx, azureSecret)).To(Succeed()) + defer func() { + g.Expect(c.Delete(ctx, awsSecret)).To(Succeed()) + g.Expect(c.Delete(ctx, vSphereSecret)).To(Succeed()) + g.Expect(c.Delete(ctx, GCPSecret)).To(Succeed()) + g.Expect(c.Delete(ctx, azureSecret)).To(Succeed()) + }() + + testCases := []struct { + name string + platformType osconfigv1.PlatformType + clusterID string + expectedError string + baseProviderSpecValue *kruntime.RawExtension + updatedProviderSpecValue func() *kruntime.RawExtension + }{ + { + name: "with a valid AWS ProviderSpec", + platformType: osconfigv1.AWSPlatformType, + clusterID: awsClusterID, + baseProviderSpecValue: &kruntime.RawExtension{ + Object: defaultAWSProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *kruntime.RawExtension { + return &kruntime.RawExtension{ + Object: defaultAWSProviderSpec.DeepCopy(), + } + }, + expectedError: "", + }, + { + name: "with an AWS ProviderSpec, removing the instance type", + platformType: osconfigv1.AWSPlatformType, + clusterID: awsClusterID, + baseProviderSpecValue: &kruntime.RawExtension{ + Object: defaultAWSProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *kruntime.RawExtension { + object := defaultAWSProviderSpec.DeepCopy() + object.InstanceType = "" + return &kruntime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.instanceType: Required value: expected providerSpec.instanceType to be populated", + }, + { + name: "with an AWS ProviderSpec, removing the region", + platformType: osconfigv1.AWSPlatformType, + clusterID: awsClusterID, + baseProviderSpecValue: &kruntime.RawExtension{ + Object: defaultAWSProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *kruntime.RawExtension { + object := defaultAWSProviderSpec.DeepCopy() + object.Placement.Region = "" + return &kruntime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.placement.region: Required value: expected providerSpec.placement.region to be populated", + }, + { + name: "with an AWS ProviderSpec, removing the user data secret", + platformType: osconfigv1.AWSPlatformType, + clusterID: awsClusterID, + baseProviderSpecValue: &kruntime.RawExtension{ + Object: defaultAWSProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *kruntime.RawExtension { + object := defaultAWSProviderSpec.DeepCopy() + object.UserDataSecret = nil + return &kruntime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.userDataSecret: Required value: expected providerSpec.userDataSecret to be populated", + }, + { + name: "with a valid Azure ProviderSpec", + platformType: osconfigv1.AzurePlatformType, + clusterID: azureClusterID, + baseProviderSpecValue: &kruntime.RawExtension{ + Object: defaultAzureProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *kruntime.RawExtension { + return &kruntime.RawExtension{ + Object: defaultAzureProviderSpec.DeepCopy(), + } + }, + expectedError: "", + }, + { + name: "with an Azure ProviderSpec, removing the vm size", + platformType: osconfigv1.AzurePlatformType, + clusterID: azureClusterID, + baseProviderSpecValue: &kruntime.RawExtension{ + Object: defaultAzureProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *kruntime.RawExtension { + object := defaultAzureProviderSpec.DeepCopy() + object.VMSize = "" + return &kruntime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.vmSize: Required value: vmSize should be set to one of the supported Azure VM sizes", + }, + { + name: "with an Azure ProviderSpec, removing the subnet", + platformType: osconfigv1.AzurePlatformType, + clusterID: azureClusterID, + baseProviderSpecValue: &kruntime.RawExtension{ + Object: defaultAzureProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *kruntime.RawExtension { + object := defaultAzureProviderSpec.DeepCopy() + object.Subnet = "" + return &kruntime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.subnet: Required value: must provide a subnet when a virtual network is specified", + }, + { + name: "with an Azure ProviderSpec, removing the credentials secret", + platformType: osconfigv1.AzurePlatformType, + clusterID: azureClusterID, + baseProviderSpecValue: &kruntime.RawExtension{ + Object: defaultAzureProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *kruntime.RawExtension { + object := defaultAzureProviderSpec.DeepCopy() + object.CredentialsSecret = nil + return &kruntime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.credentialsSecret: Required value: credentialsSecret must be provided", + }, + { + name: "with a valid GCP ProviderSpec", + platformType: osconfigv1.GCPPlatformType, + clusterID: gcpClusterID, + baseProviderSpecValue: &kruntime.RawExtension{ + Object: defaultGCPProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *kruntime.RawExtension { + return &kruntime.RawExtension{ + Object: defaultGCPProviderSpec.DeepCopy(), + } + }, + expectedError: "", + }, + { + name: "with a GCP ProviderSpec, removing the region", + platformType: osconfigv1.GCPPlatformType, + clusterID: gcpClusterID, + baseProviderSpecValue: &kruntime.RawExtension{ + Object: defaultGCPProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *kruntime.RawExtension { + object := defaultGCPProviderSpec.DeepCopy() + object.Region = "" + return &kruntime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.region: Required value: region is required", + }, + { + name: "with a GCP ProviderSpec, and an invalid region", + platformType: osconfigv1.GCPPlatformType, + clusterID: gcpClusterID, + baseProviderSpecValue: &kruntime.RawExtension{ + Object: defaultGCPProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *kruntime.RawExtension { + object := defaultGCPProviderSpec.DeepCopy() + object.Zone = "zone" + return &kruntime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.zone: Invalid value: \"zone\": zone not in configured region (region)", + }, + { + name: "with a GCP ProviderSpec, removing the disks", + platformType: osconfigv1.GCPPlatformType, + clusterID: gcpClusterID, + baseProviderSpecValue: &kruntime.RawExtension{ + Object: defaultGCPProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *kruntime.RawExtension { + object := defaultGCPProviderSpec.DeepCopy() + object.Disks = nil + return &kruntime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.disks: Required value: at least 1 disk is required", + }, + { + name: "with a GCP ProviderSpec, removing the network interfaces", + platformType: osconfigv1.GCPPlatformType, + clusterID: gcpClusterID, + baseProviderSpecValue: &kruntime.RawExtension{ + Object: defaultGCPProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *kruntime.RawExtension { + object := defaultGCPProviderSpec.DeepCopy() + object.NetworkInterfaces = nil + return &kruntime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.networkInterfaces: Required value: at least 1 network interface is required", + }, + { + name: "with a valid VSphere ProviderSpec", + platformType: osconfigv1.VSpherePlatformType, + clusterID: vsphereClusterID, + baseProviderSpecValue: &kruntime.RawExtension{ + Object: defaultVSphereProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *kruntime.RawExtension { + return &kruntime.RawExtension{ + Object: defaultVSphereProviderSpec.DeepCopy(), + } + }, + expectedError: "", + }, + { + name: "with an VSphere ProviderSpec, removing the template", + platformType: osconfigv1.VSpherePlatformType, + clusterID: vsphereClusterID, + baseProviderSpecValue: &kruntime.RawExtension{ + Object: defaultVSphereProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *kruntime.RawExtension { + object := defaultVSphereProviderSpec.DeepCopy() + object.Template = "" + return &kruntime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.template: Required value: template must be provided", + }, + { + name: "with an VSphere ProviderSpec, removing the workspace server", + platformType: osconfigv1.VSpherePlatformType, + clusterID: vsphereClusterID, + baseProviderSpecValue: &kruntime.RawExtension{ + Object: defaultVSphereProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *kruntime.RawExtension { + object := defaultVSphereProviderSpec.DeepCopy() + object.Workspace.Server = "" + return &kruntime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.workspace.server: Required value: server must be provided", + }, + { + name: "with an VSphere ProviderSpec, removing the network devices", + platformType: osconfigv1.VSpherePlatformType, + clusterID: vsphereClusterID, + baseProviderSpecValue: &kruntime.RawExtension{ + Object: defaultVSphereProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *kruntime.RawExtension { + object := defaultVSphereProviderSpec.DeepCopy() + object.Network = machinev1.NetworkSpec{} + return &kruntime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.network.devices: Required value: at least 1 network device must be provided", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + gs := NewWithT(t) + + mgr, err := manager.New(cfg, manager.Options{ + MetricsBindAddress: "0", + Port: testEnv.WebhookInstallOptions.LocalServingPort, + CertDir: testEnv.WebhookInstallOptions.LocalServingCertDir, + }) + gs.Expect(err).ToNot(HaveOccurred()) + + platformStatus := &osconfigv1.PlatformStatus{ + Type: tc.platformType, + AWS: &osconfigv1.AWSPlatformStatus{ + Region: awsRegion, + }, + } + + infra := &osconfigv1.Infrastructure{ + Status: osconfigv1.InfrastructureStatus{ + InfrastructureName: tc.clusterID, + PlatformStatus: platformStatus, + }, + } + machineDefaulter := createMachineDefaulter(platformStatus, tc.clusterID) + machineValidator := createMachineValidator(infra, c, plainDNS) + mgr.GetWebhookServer().Register(DefaultMachineMutatingHookPath, &webhook.Admission{Handler: machineDefaulter}) + mgr.GetWebhookServer().Register(DefaultMachineValidatingHookPath, &webhook.Admission{Handler: machineValidator}) + + mgrCtx, cancel := context.WithCancel(context.Background()) + stopped := make(chan struct{}) + go func() { + gs.Expect(mgr.Start(mgrCtx)).To(Succeed()) + close(stopped) + }() + defer func() { + cancel() + <-stopped + }() + + gs.Eventually(func() (bool, error) { + resp, err := insecureHTTPClient.Get(fmt.Sprintf("https://127.0.0.1:%d", testEnv.WebhookInstallOptions.LocalServingPort)) + if err != nil { + return false, err + } + return resp.StatusCode == 404, nil + }).Should(BeTrue()) + + m := &machinev1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "machine-creation-", + Namespace: namespace.Name, + }, + Spec: machinev1.MachineSpec{ + ProviderSpec: machinev1.ProviderSpec{ + Value: tc.baseProviderSpecValue, + }, + }, + } + err = c.Create(ctx, m) + gs.Expect(err).ToNot(HaveOccurred()) + defer func() { + gs.Expect(c.Delete(ctx, m)).To(Succeed()) + }() + + m.Spec.ProviderSpec.Value = tc.updatedProviderSpecValue() + err = c.Update(ctx, m) + if tc.expectedError != "" { + gs.Expect(err).ToNot(BeNil()) + gs.Expect(apierrors.ReasonForError(err)).To(BeEquivalentTo(tc.expectedError)) + } else { + gs.Expect(err).To(BeNil()) + } + }) + } +} + +func TestValidateAWSProviderSpec(t *testing.T) { + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "aws-validation-test", + }, + } + + testCases := []struct { + testCase string + modifySpec func(*machinev1.AWSMachineProviderConfig) + expectedError string + expectedOk bool + expectedWarnings []string + }{ + { + testCase: "with no ami values it fails", + modifySpec: func(p *machinev1.AWSMachineProviderConfig) { + p.AMI = machinev1.AWSResourceReference{} + }, + expectedOk: false, + expectedError: "providerSpec.ami: Required value: expected providerSpec.ami.id to be populated", + }, + { + testCase: "with no region values it fails", + modifySpec: func(p *machinev1.AWSMachineProviderConfig) { + p.Placement.Region = "" + }, + expectedOk: false, + expectedError: "providerSpec.placement.region: Required value: expected providerSpec.placement.region to be populated", + }, + { + testCase: "with no instanceType it fails", + modifySpec: func(p *machinev1.AWSMachineProviderConfig) { + p.InstanceType = "" + }, + expectedOk: false, + expectedError: "providerSpec.instanceType: Required value: expected providerSpec.instanceType to be populated", + }, + { + testCase: "with no user data secret it fails", + modifySpec: func(p *machinev1.AWSMachineProviderConfig) { + p.UserDataSecret = nil + }, + expectedOk: false, + expectedError: "providerSpec.userDataSecret: Required value: expected providerSpec.userDataSecret to be populated", + }, + { + testCase: "with no credentials secret it fails", + modifySpec: func(p *machinev1.AWSMachineProviderConfig) { + p.CredentialsSecret = nil + }, + expectedOk: false, + expectedError: "providerSpec.credentialsSecret: Required value: expected providerSpec.credentialsSecret to be populated", + }, + { + testCase: "when the credentials secret does not exist", + modifySpec: func(p *machinev1.AWSMachineProviderConfig) { + p.CredentialsSecret.Name = "does-not-exist" + }, + expectedOk: true, + expectedWarnings: []string{"providerSpec.credentialsSecret: Invalid value: \"does-not-exist\": not found. Expected CredentialsSecret to exist"}, + }, + { + testCase: "with no subnet values it fails", + modifySpec: func(p *machinev1.AWSMachineProviderConfig) { + p.Subnet = machinev1.AWSResourceReference{} + }, + expectedOk: true, + expectedWarnings: []string{"providerSpec.subnet: No subnet has been provided. Instances may be created in an unexpected subnet and may not join the cluster."}, + }, + { + testCase: "with all required values it succeeds", + expectedOk: true, + expectedError: "", + }, + { + testCase: "with valid tenancy field", + modifySpec: func(p *machinev1.AWSMachineProviderConfig) { + p.Placement.Tenancy = machinev1.DedicatedTenancy + }, + expectedOk: true, + }, + { + testCase: "with empty tenancy field", + modifySpec: func(p *machinev1.AWSMachineProviderConfig) { + p.Placement.Tenancy = "" + }, + expectedOk: true, + }, + { + testCase: "fail with invalid tenancy field", + modifySpec: func(p *machinev1.AWSMachineProviderConfig) { + p.Placement.Tenancy = "invalid" + }, + expectedOk: false, + expectedError: "providerSpec.tenancy: Invalid value: \"invalid\": Invalid providerSpec.tenancy, the only allowed options are: default, dedicated, host", + }, + { + testCase: "with no iam instance profile", + modifySpec: func(p *machinev1.AWSMachineProviderConfig) { + p.IAMInstanceProfile = nil + }, + expectedOk: true, + expectedWarnings: []string{"providerSpec.iamInstanceProfile: no IAM instance profile provided: nodes may be unable to join the cluster"}, + }, + { + testCase: "with double tag names, lists duplicated tags", + modifySpec: func(p *machinev1.AWSMachineProviderConfig) { + p.Tags = []machinev1.TagSpecification{ + { + Name: "Tag-A", + }, + { + Name: "Tag-B", + }, + { + Name: "Tag-C", + }, + { + Name: "Tag-A", + }, + { + Name: "Tag-B", + }, + } + }, + expectedOk: true, + expectedWarnings: []string{"providerSpec.tags: duplicated tag names (Tag-A,Tag-B): only the first value will be used."}, + }, + { + testCase: "with triplicated tag names, lists duplicated tag", + modifySpec: func(p *machinev1.AWSMachineProviderConfig) { + p.Tags = []machinev1.TagSpecification{ + { + Name: "Tag-A", + }, + { + Name: "Tag-A", + }, + { + Name: "Tag-A", + }, + } + }, + expectedOk: true, + expectedWarnings: []string{"providerSpec.tags: duplicated tag names (Tag-A): only the first value will be used."}, + }, + { + testCase: "with alternately cased tag names, AWS tags are case sensitive, does not list duplicated tags", + modifySpec: func(p *machinev1.AWSMachineProviderConfig) { + p.Tags = []machinev1.TagSpecification{ + { + Name: "Tag-A", + }, + { + Name: "Tag-a", + }, + { + Name: "tag-a", + }, + } + }, + expectedOk: true, + }, + { + testCase: "with AMI ARN set", + modifySpec: func(p *machinev1.AWSMachineProviderConfig) { + p.AMI = machinev1.AWSResourceReference{ + ID: pointer.StringPtr("ami"), + ARN: pointer.StringPtr("arn"), + } + }, + expectedOk: true, + expectedWarnings: []string{"can't use providerSpec.ami.arn, only providerSpec.ami.id can be used to reference AMI"}, + }, + { + testCase: "with AMI filters set", + modifySpec: func(p *machinev1.AWSMachineProviderConfig) { + p.AMI = machinev1.AWSResourceReference{ + ID: pointer.StringPtr("ami"), + Filters: []machinev1.Filter{ + { + Name: "filter", + }, + }, + } + }, + expectedOk: true, + expectedWarnings: []string{"can't use providerSpec.ami.filters, only providerSpec.ami.id can be used to reference AMI"}, + }, + } + + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "secret", + Namespace: namespace.Name, + }, + } + c := fake.NewFakeClientWithScheme(scheme.Scheme, secret) + + infra := plainInfra.DeepCopy() + infra.Status.InfrastructureName = "clusterID" + infra.Status.PlatformStatus.Type = osconfigv1.AWSPlatformType + h := createMachineValidator(infra, c, plainDNS) + + for _, tc := range testCases { + t.Run(tc.testCase, func(t *testing.T) { + providerSpec := &machinev1.AWSMachineProviderConfig{ + AMI: machinev1.AWSResourceReference{ + ID: pointer.StringPtr("ami"), + }, + Placement: machinev1.Placement{ + Region: "region", + }, + InstanceType: "m5.large", + IAMInstanceProfile: &machinev1.AWSResourceReference{ + ID: pointer.StringPtr("profileID"), + }, + UserDataSecret: &corev1.LocalObjectReference{ + Name: "secret", + }, + CredentialsSecret: &corev1.LocalObjectReference{ + Name: "secret", + }, + SecurityGroups: []machinev1.AWSResourceReference{ + { + ID: pointer.StringPtr("sg"), + }, + }, + Subnet: machinev1.AWSResourceReference{ + ID: pointer.StringPtr("subnet"), + }, + } + if tc.modifySpec != nil { + tc.modifySpec(providerSpec) + } + + m := &machinev1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace.Name, + }, + } + rawBytes, err := json.Marshal(providerSpec) + if err != nil { + t.Fatal(err) + } + m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} + + ok, warnings, err := h.webhookOperations(m, h.admissionConfig) + if ok != tc.expectedOk { + t.Errorf("expected: %v, got: %v", tc.expectedOk, ok) + } + + if err == nil { + if tc.expectedError != "" { + t.Errorf("expected: %q, got: %v", tc.expectedError, err) + } + } else { + if err.Error() != tc.expectedError { + t.Errorf("expected: %q, got: %q", tc.expectedError, err.Error()) + } + } + + if !reflect.DeepEqual(warnings, tc.expectedWarnings) { + t.Errorf("expected: %q, got: %q", tc.expectedWarnings, warnings) + } + }) + } +} + +func TestDefaultAWSProviderSpec(t *testing.T) { + + clusterID := "clusterID" + region := "region" + arch := defaultAWSX86InstanceType + if runtime.GOARCH == "arm64" { + arch = defaultAWSARMInstanceType + } + testCases := []struct { + testCase string + providerSpec *machinev1.AWSMachineProviderConfig + expectedProviderSpec *machinev1.AWSMachineProviderConfig + expectedError string + expectedOk bool + expectedWarnings []string + }{ + { + testCase: "it defaults Region, InstanceType, UserDataSecret and CredentialsSecret", + providerSpec: &machinev1.AWSMachineProviderConfig{ + AMI: machinev1.AWSResourceReference{}, + InstanceType: "", + UserDataSecret: nil, + CredentialsSecret: nil, + }, + expectedProviderSpec: &machinev1.AWSMachineProviderConfig{ + AMI: machinev1.AWSResourceReference{}, + InstanceType: arch, + UserDataSecret: &corev1.LocalObjectReference{Name: defaultUserDataSecret}, + CredentialsSecret: &corev1.LocalObjectReference{Name: defaultAWSCredentialsSecret}, + Placement: machinev1.Placement{ + Region: "region", + }, + }, + expectedOk: true, + expectedError: "", + expectedWarnings: nil, + }, + } + + platformStatus := &osconfigv1.PlatformStatus{ + Type: osconfigv1.AWSPlatformType, + AWS: &osconfigv1.AWSPlatformStatus{ + Region: region, + }, + } + h := createMachineDefaulter(platformStatus, clusterID) + + for _, tc := range testCases { + t.Run(tc.testCase, func(t *testing.T) { + m := &machinev1.Machine{} + rawBytes, err := json.Marshal(tc.providerSpec) + if err != nil { + t.Fatal(err) + } + m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} + + ok, warnings, err := h.webhookOperations(m, h.admissionConfig) + if ok != tc.expectedOk { + t.Errorf("expected: %v, got: %v", tc.expectedOk, ok) + } + + gotProviderSpec := new(machinev1.AWSMachineProviderConfig) + if err := yaml.Unmarshal(m.Spec.ProviderSpec.Value.Raw, &gotProviderSpec); err != nil { + t.Fatal(err) + } + + if !equality.Semantic.DeepEqual(tc.expectedProviderSpec, gotProviderSpec) { + t.Errorf("expected: %+v, got: %+v", tc.expectedProviderSpec, gotProviderSpec) + } + if err == nil { + if tc.expectedError != "" { + t.Errorf("expected: %q, got: %v", tc.expectedError, err) + } + } else { + if err.Error() != tc.expectedError { + t.Errorf("expected: %q, got: %q", tc.expectedError, err.Error()) + } + } + + if !reflect.DeepEqual(warnings, tc.expectedWarnings) { + t.Errorf("expected: %q, got: %q", tc.expectedWarnings, warnings) + } + }) + } +} + +func TestValidateAzureProviderSpec(t *testing.T) { + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "azure-validation-test", + }, + } + + testCases := []struct { + testCase string + modifySpec func(providerSpec *machinev1.AzureMachineProviderSpec) + azurePlatformStatus *osconfigv1.AzurePlatformStatus + expectedError string + expectedOk bool + expectedWarnings []string + }{ + { + testCase: "with no vmsize it fails", + modifySpec: func(p *machinev1.AzureMachineProviderSpec) { + p.VMSize = "" + }, + expectedOk: false, + expectedError: "providerSpec.vmSize: Required value: vmSize should be set to one of the supported Azure VM sizes", + }, + { + testCase: "with a vnet but no subnet it fails", + modifySpec: func(p *machinev1.AzureMachineProviderSpec) { + p.Vnet = "vnet" + p.Subnet = "" + p.NetworkResourceGroup = "nrg" + }, + expectedOk: false, + expectedError: "providerSpec.subnet: Required value: must provide a subnet when a virtual network is specified", + }, + { + testCase: "with a subnet but no vnet it fails", + modifySpec: func(p *machinev1.AzureMachineProviderSpec) { + p.Vnet = "" + p.Subnet = "subnet" + p.NetworkResourceGroup = "nrg" + }, + expectedOk: false, + expectedError: "providerSpec.vnet: Required value: must provide a virtual network when supplying subnets", + }, + { + testCase: "with no image it fails", + modifySpec: func(p *machinev1.AzureMachineProviderSpec) { + p.Image = machinev1.Image{} + }, + expectedOk: false, + expectedError: "providerSpec.image: Required value: an image reference must be provided", + }, + { + testCase: "with resourceId and other fields set it fails", + modifySpec: func(p *machinev1.AzureMachineProviderSpec) { + p.Image = machinev1.Image{ + ResourceID: "rid", + SKU: "sku-rand", + Offer: "base-offer", + Version: "1", + Publisher: "test", + } + }, + expectedOk: false, + expectedError: "providerSpec.image.resourceID: Required value: resourceID is already specified, other fields such as [Offer, Publisher, SKU, Version] should not be set", + }, + { + testCase: "with no offer it fails", + modifySpec: func(p *machinev1.AzureMachineProviderSpec) { + p.Image = machinev1.Image{ + Version: "1", + SKU: "sku-rand", + Publisher: "test", + } + }, + expectedOk: false, + expectedError: "providerSpec.image.Offer: Required value: Offer must be provided", + }, + { + testCase: "with no SKU it fails", + modifySpec: func(p *machinev1.AzureMachineProviderSpec) { + p.Image = machinev1.Image{ + Offer: "base-offer", + Version: "1", + Publisher: "test", + } + }, + expectedOk: false, + expectedError: "providerSpec.image.SKU: Required value: SKU must be provided", + }, + { + testCase: "with no Version it fails", + modifySpec: func(p *machinev1.AzureMachineProviderSpec) { + p.Image = machinev1.Image{ + SKU: "sku-rand", + Offer: "base-offer", + Publisher: "test", + } + }, + expectedOk: false, + expectedError: "providerSpec.image.Version: Required value: Version must be provided", + }, + { + testCase: "with no Publisher it fails", + modifySpec: func(p *machinev1.AzureMachineProviderSpec) { + p.Image = machinev1.Image{ + SKU: "sku-rand", + Offer: "base-offer", + Version: "1", + } + }, + expectedOk: false, + expectedError: "providerSpec.image.Publisher: Required value: Publisher must be provided", + }, + { + testCase: "with resourceID in image it succeeds", + modifySpec: func(p *machinev1.AzureMachineProviderSpec) { + p.Image = machinev1.Image{ + ResourceID: "rid", + } + }, + expectedOk: true, + }, + { + testCase: "with no user data secret it fails", + modifySpec: func(p *machinev1.AzureMachineProviderSpec) { + p.UserDataSecret = nil + }, + expectedOk: false, + expectedError: "providerSpec.userDataSecret: Required value: userDataSecret must be provided", + }, + { + testCase: "with no user data secret name it fails", + modifySpec: func(p *machinev1.AzureMachineProviderSpec) { + p.UserDataSecret = &corev1.SecretReference{} + }, + expectedOk: false, + expectedError: "providerSpec.userDataSecret.name: Required value: name must be provided", + }, + { + testCase: "with no credentials secret it fails", + modifySpec: func(p *machinev1.AzureMachineProviderSpec) { + p.CredentialsSecret = nil + }, + expectedOk: false, + expectedError: "providerSpec.credentialsSecret: Required value: credentialsSecret must be provided", + }, + { + testCase: "with no credentials secret namespace it fails", + modifySpec: func(p *machinev1.AzureMachineProviderSpec) { + p.CredentialsSecret = &corev1.SecretReference{ + Name: "name", + } + }, + expectedOk: false, + expectedError: "providerSpec.credentialsSecret.namespace: Required value: namespace must be provided", + }, + { + testCase: "when the credentials secret does not exist", + modifySpec: func(p *machinev1.AzureMachineProviderSpec) { + p.CredentialsSecret.Name = "does-not-exist" + }, + expectedOk: true, + expectedWarnings: []string{"providerSpec.credentialsSecret: Invalid value: \"does-not-exist\": not found. Expected CredentialsSecret to exist"}, + }, + { + testCase: "with no credentials secret name it fails", + modifySpec: func(p *machinev1.AzureMachineProviderSpec) { + p.CredentialsSecret = &corev1.SecretReference{ + Namespace: namespace.Name, + } + }, + expectedOk: false, + expectedError: "providerSpec.credentialsSecret.name: Required value: name must be provided", + }, + { + testCase: "with no os disk size it fails", + modifySpec: func(p *machinev1.AzureMachineProviderSpec) { + p.OSDisk = machinev1.OSDisk{ + OSType: "osType", + ManagedDisk: machinev1.ManagedDiskParameters{ + StorageAccountType: "storageAccountType", + }, + } + }, + expectedOk: false, + expectedError: "providerSpec.osDisk.diskSizeGB: Invalid value: 0: diskSizeGB must be greater than zero and less than 32768", + }, + { + testCase: "with all required fields it succeeds", + expectedOk: true, + expectedError: "", + }, + { + testCase: "with government cloud and spot VMs enabled", + modifySpec: func(p *machinev1.AzureMachineProviderSpec) { + p.SpotVMOptions = &machinev1.SpotVMOptions{} + }, + azurePlatformStatus: &osconfigv1.AzurePlatformStatus{ + CloudName: osconfigv1.AzureUSGovernmentCloud, + }, + expectedOk: true, + expectedWarnings: []string{"spot VMs may not be supported when using GovCloud region"}, + }, + { + testCase: "with public cloud and spot VMs enabled", + modifySpec: func(p *machinev1.AzureMachineProviderSpec) { + p.SpotVMOptions = &machinev1.SpotVMOptions{} + }, + azurePlatformStatus: &osconfigv1.AzurePlatformStatus{ + CloudName: osconfigv1.AzurePublicCloud, + }, + expectedOk: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.testCase, func(t *testing.T) { + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: namespace.Name, + }, + } + c := fake.NewFakeClientWithScheme(scheme.Scheme, secret) + infra := plainInfra.DeepCopy() + infra.Status.InfrastructureName = "clusterID" + infra.Status.PlatformStatus.Type = osconfigv1.AzurePlatformType + infra.Status.PlatformStatus.Azure = tc.azurePlatformStatus + + h := createMachineValidator(infra, c, plainDNS) + + // create a valid spec that will then be 'broken' by modifySpec + providerSpec := &machinev1.AzureMachineProviderSpec{ + VMSize: "vmSize", + Image: machinev1.Image{ + ResourceID: "resourceID", + }, + UserDataSecret: &corev1.SecretReference{ + Name: "name", + }, + CredentialsSecret: &corev1.SecretReference{ + Name: "name", + Namespace: namespace.Name, + }, + OSDisk: machinev1.OSDisk{ + DiskSizeGB: 1, + }, + } + if tc.modifySpec != nil { + tc.modifySpec(providerSpec) + } + + m := &machinev1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace.Name, + }, + } + rawBytes, err := json.Marshal(providerSpec) + if err != nil { + t.Fatal(err) + } + m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} + + ok, warnings, err := h.webhookOperations(m, h.admissionConfig) + if ok != tc.expectedOk { + t.Errorf("expected: %v, got: %v", tc.expectedOk, ok) + } + + if err == nil { + if tc.expectedError != "" { + t.Errorf("expected: %q, got: %v", tc.expectedError, err) + } + } else { + if err.Error() != tc.expectedError { + t.Errorf("expected: %q, got: %q", tc.expectedError, err.Error()) + } + } + + if !reflect.DeepEqual(warnings, tc.expectedWarnings) { + t.Errorf("expected: %q, got: %q", tc.expectedWarnings, warnings) + } + }) + } +} + +func TestDefaultAzureProviderSpec(t *testing.T) { + + clusterID := "clusterID" + testCases := []struct { + testCase string + providerSpec *machinev1.AzureMachineProviderSpec + modifyDefault func(*machinev1.AzureMachineProviderSpec) + expectedError string + expectedOk bool + expectedWarnings []string + }{ + { + testCase: "it defaults defaultable fields", + providerSpec: &machinev1.AzureMachineProviderSpec{}, + expectedOk: true, + expectedError: "", + }, + { + testCase: "it does not override azure image spec", + providerSpec: &machinev1.AzureMachineProviderSpec{ + Image: machinev1.Image{ + Offer: "test-offer", + SKU: "test-sku", + Publisher: "base-publisher", + Version: "1", + }, + }, + modifyDefault: func(p *machinev1.AzureMachineProviderSpec) { + p.Image = machinev1.Image{ + Offer: "test-offer", + SKU: "test-sku", + Publisher: "base-publisher", + Version: "1", + } + }, + expectedOk: true, + expectedError: "", + }, + { + testCase: "it does not override azure image ResourceID", + providerSpec: &machinev1.AzureMachineProviderSpec{ + Image: machinev1.Image{ + ResourceID: "rid", + }, + }, + modifyDefault: func(p *machinev1.AzureMachineProviderSpec) { + p.Image = machinev1.Image{ + ResourceID: "rid", + } + }, + expectedOk: true, + expectedError: "", + }, + { + testCase: "does not overwrite the network resource group if it already exists", + providerSpec: &machinev1.AzureMachineProviderSpec{ + NetworkResourceGroup: "nrg", + }, + modifyDefault: func(p *machinev1.AzureMachineProviderSpec) { + p.NetworkResourceGroup = "nrg" + }, + expectedOk: true, + expectedError: "", + }, + { + testCase: "does not overwrite the credentials secret namespace if they already exist", + providerSpec: &machinev1.AzureMachineProviderSpec{ + CredentialsSecret: &corev1.SecretReference{ + Namespace: "foo", + }, + }, + modifyDefault: func(p *machinev1.AzureMachineProviderSpec) { + p.CredentialsSecret.Namespace = "foo" + }, + expectedOk: true, + expectedError: "", + }, + { + testCase: "does not overwrite the secret names if they already exist", + providerSpec: &machinev1.AzureMachineProviderSpec{ + UserDataSecret: &corev1.SecretReference{ + Name: "foo", + }, + CredentialsSecret: &corev1.SecretReference{ + Name: "foo", + }, + }, + modifyDefault: func(p *machinev1.AzureMachineProviderSpec) { + p.UserDataSecret.Name = "foo" + p.CredentialsSecret.Name = "foo" + }, + expectedOk: true, + expectedError: "", + }, + } + + platformStatus := &osconfigv1.PlatformStatus{Type: osconfigv1.AzurePlatformType} + h := createMachineDefaulter(platformStatus, clusterID) + + for _, tc := range testCases { + t.Run(tc.testCase, func(t *testing.T) { + defaultProviderSpec := &machinev1.AzureMachineProviderSpec{ + VMSize: defaultAzureVMSize, + Vnet: defaultAzureVnet(clusterID), + Subnet: defaultAzureSubnet(clusterID), + Image: machinev1.Image{ + ResourceID: defaultAzureImageResourceID(clusterID), + }, + UserDataSecret: &corev1.SecretReference{ + Name: defaultUserDataSecret, + }, + CredentialsSecret: &corev1.SecretReference{ + Name: defaultAzureCredentialsSecret, + Namespace: defaultSecretNamespace, + }, + } + if tc.modifyDefault != nil { + tc.modifyDefault(defaultProviderSpec) + } + + m := &machinev1.Machine{} + rawBytes, err := json.Marshal(tc.providerSpec) + if err != nil { + t.Fatal(err) + } + m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} + + ok, warnings, err := h.webhookOperations(m, h.admissionConfig) + if ok != tc.expectedOk { + t.Errorf("expected: %v, got: %v", tc.expectedOk, ok) + } + + gotProviderSpec := new(machinev1.AzureMachineProviderSpec) + if err := yaml.Unmarshal(m.Spec.ProviderSpec.Value.Raw, &gotProviderSpec); err != nil { + t.Fatal(err) + } + + if !equality.Semantic.DeepEqual(defaultProviderSpec, gotProviderSpec) { + t.Errorf("expected: %+v, got: %+v", defaultProviderSpec, gotProviderSpec) + } + if err == nil { + if tc.expectedError != "" { + t.Errorf("expected: %q, got: %v", tc.expectedError, err) + } + } else { + if err.Error() != tc.expectedError { + t.Errorf("expected: %q, got: %q", tc.expectedError, err.Error()) + } + } + + if !reflect.DeepEqual(warnings, tc.expectedWarnings) { + t.Errorf("expected: %q, got: %q", tc.expectedWarnings, warnings) + } + }) + } +} + +func TestValidateGCPProviderSpec(t *testing.T) { + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "gcp-validation-test", + }, + } + + testCases := []struct { + testCase string + modifySpec func(*machinev1.GCPMachineProviderSpec) + expectedError string + expectedOk bool + expectedWarnings []string + }{ + { + testCase: "with no region", + modifySpec: func(p *machinev1.GCPMachineProviderSpec) { + p.Region = "" + }, + expectedOk: false, + expectedError: "providerSpec.region: Required value: region is required", + }, + { + testCase: "with no zone", + modifySpec: func(p *machinev1.GCPMachineProviderSpec) { + p.Zone = "" + }, + expectedOk: false, + expectedError: "providerSpec.zone: Invalid value: \"\": zone not in configured region (region)", + }, + { + testCase: "with an invalid zone", + modifySpec: func(p *machinev1.GCPMachineProviderSpec) { + p.Zone = "zone" + }, + expectedOk: false, + expectedError: "providerSpec.zone: Invalid value: \"zone\": zone not in configured region (region)", + }, + { + testCase: "with no machine type", + modifySpec: func(p *machinev1.GCPMachineProviderSpec) { + p.MachineType = "" + }, + expectedOk: false, + expectedError: "providerSpec.machineType: Required value: machineType should be set to one of the supported GCP machine types", + }, + { + testCase: "with no network interfaces", + modifySpec: func(p *machinev1.GCPMachineProviderSpec) { + p.NetworkInterfaces = nil + }, + expectedOk: false, + expectedError: "providerSpec.networkInterfaces: Required value: at least 1 network interface is required", + }, + { + testCase: "with a network interfaces is missing the network", + modifySpec: func(p *machinev1.GCPMachineProviderSpec) { + p.NetworkInterfaces = []*machinev1.GCPNetworkInterface{ + { + Network: "network", + Subnetwork: "subnetwork", + }, + { + Subnetwork: "subnetwork", + }, + } + }, + expectedOk: false, + expectedError: "providerSpec.networkInterfaces[1].network: Required value: network is required", + }, + { + testCase: "with a network interfaces is missing the subnetwork", + modifySpec: func(p *machinev1.GCPMachineProviderSpec) { + p.NetworkInterfaces = []*machinev1.GCPNetworkInterface{ + { + Network: "network", + Subnetwork: "subnetwork", + }, + { + Network: "network", + }, + } + }, + expectedOk: false, + expectedError: "providerSpec.networkInterfaces[1].subnetwork: Required value: subnetwork is required", + }, + { + testCase: "with no disks", + modifySpec: func(p *machinev1.GCPMachineProviderSpec) { + p.Disks = nil + }, + expectedOk: false, + expectedError: "providerSpec.disks: Required value: at least 1 disk is required", + }, + { + testCase: "with a disk that is too small", + modifySpec: func(p *machinev1.GCPMachineProviderSpec) { + p.Disks = []*machinev1.GCPDisk{ + { + SizeGB: 1, + }, + } + }, + expectedOk: false, + expectedError: "providerSpec.disks[0].sizeGb: Invalid value: 1: must be at least 16GB in size", + }, + { + testCase: "with a disk that is too large", + modifySpec: func(p *machinev1.GCPMachineProviderSpec) { + p.Disks = []*machinev1.GCPDisk{ + { + SizeGB: 100000, + }, + } + }, + expectedOk: false, + expectedError: "providerSpec.disks[0].sizeGb: Invalid value: 100000: exceeding maximum GCP disk size limit, must be below 65536", + }, + { + testCase: "with a disk type that is not supported", + modifySpec: func(p *machinev1.GCPMachineProviderSpec) { + p.Disks = []*machinev1.GCPDisk{ + { + SizeGB: 16, + Type: "invalid", + }, + } + }, + expectedOk: false, + expectedError: "providerSpec.disks[0].type: Unsupported value: \"invalid\": supported values: \"pd-ssd\", \"pd-standard\"", + }, + { + testCase: "with no service accounts", + modifySpec: func(p *machinev1.GCPMachineProviderSpec) { + p.ServiceAccounts = nil + }, + expectedOk: true, + expectedError: "", + expectedWarnings: []string{"providerSpec.serviceAccounts: no service account provided: nodes may be unable to join the cluster"}, + }, + { + testCase: "with multiple service accounts", + modifySpec: func(p *machinev1.GCPMachineProviderSpec) { + p.ServiceAccounts = []machinev1.GCPServiceAccount{ + {}, + {}, + } + }, + expectedOk: false, + expectedError: "providerSpec.serviceAccounts: Invalid value: \"2 service accounts supplied\": exactly 1 service account must be supplied", + }, + { + testCase: "with the service account's email missing", + modifySpec: func(p *machinev1.GCPMachineProviderSpec) { + p.ServiceAccounts = []machinev1.GCPServiceAccount{ + { + Scopes: []string{"scope"}, + }, + } + }, + expectedOk: false, + expectedError: "providerSpec.serviceAccounts[0].email: Required value: email is required", + }, + { + testCase: "with the service account's with no scopes", + modifySpec: func(p *machinev1.GCPMachineProviderSpec) { + p.ServiceAccounts = []machinev1.GCPServiceAccount{ + { + Email: "email", + }, + } + }, + expectedOk: false, + expectedError: "providerSpec.serviceAccounts[0].scopes: Required value: at least 1 scope is required", + }, + { + testCase: "with no user data secret", + modifySpec: func(p *machinev1.GCPMachineProviderSpec) { + p.UserDataSecret = nil + }, + expectedOk: false, + expectedError: "providerSpec.userDataSecret: Required value: userDataSecret must be provided", + }, + { + testCase: "with no user data secret name", + modifySpec: func(p *machinev1.GCPMachineProviderSpec) { + p.UserDataSecret = &corev1.LocalObjectReference{} + }, + expectedOk: false, + expectedError: "providerSpec.userDataSecret.name: Required value: name must be provided", + }, + { + testCase: "with no credentials data secret", + modifySpec: func(p *machinev1.GCPMachineProviderSpec) { + p.CredentialsSecret = nil + }, + expectedOk: false, + expectedError: "providerSpec.credentialsSecret: Required value: credentialsSecret must be provided", + }, + { + testCase: "when the credentials secret does not exist", + modifySpec: func(p *machinev1.GCPMachineProviderSpec) { + p.CredentialsSecret.Name = "does-not-exist" + }, + expectedOk: true, + expectedWarnings: []string{"providerSpec.credentialsSecret: Invalid value: \"does-not-exist\": not found. Expected CredentialsSecret to exist"}, + }, + { + testCase: "with no user data secret name", + modifySpec: func(p *machinev1.GCPMachineProviderSpec) { + p.CredentialsSecret = &corev1.LocalObjectReference{} + }, + expectedOk: false, + expectedError: "providerSpec.credentialsSecret.name: Required value: name must be provided", + }, + { + testCase: "with all required fields it succeeds", + expectedOk: true, + expectedError: "", + }, + } + + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: namespace.Name, + }, + } + c := fake.NewFakeClientWithScheme(scheme.Scheme, secret) + infra := plainInfra.DeepCopy() + infra.Status.InfrastructureName = "clusterID" + infra.Status.PlatformStatus.Type = osconfigv1.GCPPlatformType + h := createMachineValidator(infra, c, plainDNS) + + for _, tc := range testCases { + providerSpec := &machinev1.GCPMachineProviderSpec{ + Region: "region", + Zone: "region-zone", + ProjectID: "projectID", + MachineType: "machineType", + NetworkInterfaces: []*machinev1.GCPNetworkInterface{ + { + Network: "network", + Subnetwork: "subnetwork", + }, + }, + Disks: []*machinev1.GCPDisk{ + { + SizeGB: 16, + }, + }, + ServiceAccounts: []machinev1.GCPServiceAccount{ + { + Email: "email", + Scopes: []string{"scope"}, + }, + }, + UserDataSecret: &corev1.LocalObjectReference{ + Name: "name", + }, + CredentialsSecret: &corev1.LocalObjectReference{ + Name: "name", + }, + } + if tc.modifySpec != nil { + tc.modifySpec(providerSpec) + } + + t.Run(tc.testCase, func(t *testing.T) { + m := &machinev1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace.Name, + }, + } + rawBytes, err := json.Marshal(providerSpec) + if err != nil { + t.Fatal(err) + } + m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} + + ok, warnings, err := h.webhookOperations(m, h.admissionConfig) + if ok != tc.expectedOk { + t.Errorf("expected: %v, got: %v", tc.expectedOk, ok) + } + + if err == nil { + if tc.expectedError != "" { + t.Errorf("expected: %q, got: %v", tc.expectedError, err) + } + } else { + if err.Error() != tc.expectedError { + t.Errorf("expected: %q, got: %q", tc.expectedError, err.Error()) + } + } + + if !reflect.DeepEqual(warnings, tc.expectedWarnings) { + t.Errorf("expected: %q, got: %q", tc.expectedWarnings, warnings) + } + }) + } +} + +func TestDefaultGCPProviderSpec(t *testing.T) { + + clusterID := "clusterID" + projectID := "projectID" + testCases := []struct { + testCase string + providerSpec *machinev1.GCPMachineProviderSpec + modifyDefault func(*machinev1.GCPMachineProviderSpec) + expectedError string + expectedOk bool + expectedWarnings []string + }{ + { + testCase: "it defaults defaultable fields", + providerSpec: &machinev1.GCPMachineProviderSpec{}, + expectedOk: true, + expectedError: "", + }, + { + testCase: "it does not overwrite disks which already have fields set", + providerSpec: &machinev1.GCPMachineProviderSpec{ + Disks: []*machinev1.GCPDisk{ + { + AutoDelete: false, + Boot: false, + SizeGB: 32, + }, + }, + }, + modifyDefault: func(p *machinev1.GCPMachineProviderSpec) { + p.Disks = []*machinev1.GCPDisk{ + { + AutoDelete: false, + Boot: false, + SizeGB: 32, + Type: defaultGCPDiskType, + Image: defaultGCPDiskImage, + }, + } + }, + expectedOk: true, + expectedError: "", + }, + } + + platformStatus := &osconfigv1.PlatformStatus{ + Type: osconfigv1.GCPPlatformType, + GCP: &osconfigv1.GCPPlatformStatus{ + ProjectID: projectID, + }, + } + h := createMachineDefaulter(platformStatus, clusterID) + + for _, tc := range testCases { + defaultProviderSpec := &machinev1.GCPMachineProviderSpec{ + MachineType: defaultGCPMachineType, + NetworkInterfaces: []*machinev1.GCPNetworkInterface{ + { + Network: defaultGCPNetwork(clusterID), + Subnetwork: defaultGCPSubnetwork(clusterID), + }, + }, + Disks: []*machinev1.GCPDisk{ + { + AutoDelete: true, + Boot: true, + SizeGB: defaultGCPDiskSizeGb, + Type: defaultGCPDiskType, + Image: defaultGCPDiskImage, + }, + }, + Tags: defaultGCPTags(clusterID), + UserDataSecret: &corev1.LocalObjectReference{ + Name: defaultUserDataSecret, + }, + CredentialsSecret: &corev1.LocalObjectReference{ + Name: defaultGCPCredentialsSecret, + }, + } + if tc.modifyDefault != nil { + tc.modifyDefault(defaultProviderSpec) + } + + t.Run(tc.testCase, func(t *testing.T) { + m := &machinev1.Machine{} + rawBytes, err := json.Marshal(tc.providerSpec) + if err != nil { + t.Fatal(err) + } + m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} + + ok, warnings, err := h.webhookOperations(m, h.admissionConfig) + if ok != tc.expectedOk { + t.Errorf("expected: %v, got: %v", tc.expectedOk, ok) + } + + gotProviderSpec := new(machinev1.GCPMachineProviderSpec) + if err := yaml.Unmarshal(m.Spec.ProviderSpec.Value.Raw, &gotProviderSpec); err != nil { + t.Fatal(err) + } + + if !equality.Semantic.DeepEqual(defaultProviderSpec, gotProviderSpec) { + t.Errorf("expected: %+v, got: %+v", defaultProviderSpec, gotProviderSpec) + } + if err == nil { + if tc.expectedError != "" { + t.Errorf("expected: %q, got: %v", tc.expectedError, err) + } + } else { + if err.Error() != tc.expectedError { + t.Errorf("expected: %q, got: %q", tc.expectedError, err.Error()) + } + } + + if !reflect.DeepEqual(warnings, tc.expectedWarnings) { + t.Errorf("expected: %q, got: %q", tc.expectedWarnings, warnings) + } + }) + } +} + +func TestValidateVSphereProviderSpec(t *testing.T) { + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "vsphere-validation-test", + }, + } + + testCases := []struct { + testCase string + modifySpec func(*machinev1.VSphereMachineProviderSpec) + expectedError string + expectedOk bool + expectedWarnings []string + }{ + { + testCase: "with no template provided", + modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { + p.Template = "" + }, + expectedOk: false, + expectedError: "providerSpec.template: Required value: template must be provided", + }, + { + testCase: "with no workspace provided", + modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { + p.Workspace = nil + }, + expectedOk: false, + expectedError: "providerSpec.workspace: Required value: workspace must be provided", + }, + { + testCase: "with no workspace server provided", + modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { + p.Workspace = &machinev1.Workspace{ + Datacenter: "datacenter", + } + }, + expectedOk: false, + expectedError: "providerSpec.workspace.server: Required value: server must be provided", + }, + { + testCase: "with no workspace datacenter provided", + modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { + p.Workspace = &machinev1.Workspace{ + Server: "server", + } + }, + expectedOk: true, + expectedError: "", + expectedWarnings: []string{"providerSpec.workspace.datacenter: datacenter is unset: if more than one datacenter is present, VMs cannot be created"}, + }, + { + testCase: "with a workspace folder outside of the current datacenter", + modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { + p.Workspace = &machinev1.Workspace{ + Server: "server", + Datacenter: "datacenter", + Folder: "/foo/vm/folder", + } + }, + expectedOk: false, + expectedError: "providerSpec.workspace.folder: Invalid value: \"/foo/vm/folder\": folder must be absolute path: expected prefix \"/datacenter/vm/\"", + }, + { + testCase: "with no network devices provided", + modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { + p.Network = machinev1.NetworkSpec{ + Devices: []machinev1.NetworkDeviceSpec{}, + } + }, + expectedOk: false, + expectedError: "providerSpec.network.devices: Required value: at least 1 network device must be provided", + }, + { + testCase: "with no network device name provided", + modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { + p.Network = machinev1.NetworkSpec{ + Devices: []machinev1.NetworkDeviceSpec{ + { + NetworkName: "networkName", + }, + {}, + }, + } + }, + expectedOk: false, + expectedError: "providerSpec.network.devices[1].networkName: Required value: networkName must be provided", + }, + { + testCase: "with too few CPUs provided", + modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { + p.NumCPUs = 1 + }, + expectedOk: true, + expectedError: "", + expectedWarnings: []string{"providerSpec.numCPUs: 1 is missing or less than the minimum value (2): nodes may not boot correctly"}, + }, + { + testCase: "with too little memory provided", + modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { + p.MemoryMiB = 1024 + }, + expectedOk: true, + expectedError: "", + expectedWarnings: []string{"providerSpec.memoryMiB: 1024 is missing or less than the recommended minimum value (2048): nodes may not boot correctly"}, + }, + { + testCase: "with too little disk size provided", + modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { + p.DiskGiB = 1 + }, + expectedOk: true, + expectedError: "", + expectedWarnings: []string{"providerSpec.diskGiB: 1 is missing or less than the recommended minimum (120): nodes may fail to start if disk size is too low"}, + }, + { + testCase: "with no user data secret provided", + modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { + p.UserDataSecret = nil + }, + expectedOk: false, + expectedError: "providerSpec.userDataSecret: Required value: userDataSecret must be provided", + }, + { + testCase: "with no user data secret name provided", + modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { + p.UserDataSecret = &corev1.LocalObjectReference{} + }, + expectedOk: false, + expectedError: "providerSpec.userDataSecret.name: Required value: name must be provided", + }, + { + testCase: "with no credentials secret provided", + modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { + p.CredentialsSecret = nil + }, + expectedOk: false, + expectedError: "providerSpec.credentialsSecret: Required value: credentialsSecret must be provided", + }, + { + testCase: "when the credentials secret does not exist", + modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { + p.CredentialsSecret.Name = "does-not-exist" + }, + expectedOk: true, + expectedWarnings: []string{"providerSpec.credentialsSecret: Invalid value: \"does-not-exist\": not found. Expected CredentialsSecret to exist"}, + }, + { + testCase: "with no credentials secret name provided", + modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { + p.CredentialsSecret = &corev1.LocalObjectReference{} + }, + expectedOk: false, + expectedError: "providerSpec.credentialsSecret.name: Required value: name must be provided", + }, + { + testCase: "with all required fields it succeeds", + expectedOk: true, + expectedError: "", + }, + { + testCase: "with numCPUs equal to 0", + modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { + p.NumCPUs = 0 + }, + expectedOk: true, + expectedWarnings: []string{"providerSpec.numCPUs: 0 is missing or less than the minimum value (2): nodes may not boot correctly"}, + }, + { + testCase: "with memoryMiB equal to 0", + modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { + p.MemoryMiB = 0 + }, + expectedOk: true, + expectedWarnings: []string{"providerSpec.memoryMiB: 0 is missing or less than the recommended minimum value (2048): nodes may not boot correctly"}, + }, + { + testCase: "with diskGiB equal to 0", + modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { + p.DiskGiB = 0 + }, + expectedOk: true, + expectedWarnings: []string{"providerSpec.diskGiB: 0 is missing or less than the recommended minimum (120): nodes may fail to start if disk size is too low"}, + }, + } + + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: namespace.Name, + }, + } + c := fake.NewFakeClientWithScheme(scheme.Scheme, secret) + infra := plainInfra.DeepCopy() + infra.Status.InfrastructureName = "clusterID" + infra.Status.PlatformStatus.Type = osconfigv1.VSpherePlatformType + h := createMachineValidator(infra, c, plainDNS) + + for _, tc := range testCases { + t.Run(tc.testCase, func(t *testing.T) { + providerSpec := &machinev1.VSphereMachineProviderSpec{ + Template: "template", + Workspace: &machinev1.Workspace{ + Datacenter: "datacenter", + Server: "server", + }, + Network: machinev1.NetworkSpec{ + Devices: []machinev1.NetworkDeviceSpec{ + { + NetworkName: "networkName", + }, + }, + }, + UserDataSecret: &corev1.LocalObjectReference{ + Name: "name", + }, + CredentialsSecret: &corev1.LocalObjectReference{ + Name: "name", + }, + NumCPUs: minVSphereCPU, + MemoryMiB: minVSphereMemoryMiB, + DiskGiB: minVSphereDiskGiB, + } + if tc.modifySpec != nil { + tc.modifySpec(providerSpec) + } + + m := &machinev1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace.Name, + }, + } + rawBytes, err := json.Marshal(providerSpec) + if err != nil { + t.Fatal(err) + } + m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} + + ok, warnings, err := h.webhookOperations(m, h.admissionConfig) + if ok != tc.expectedOk { + t.Errorf("expected: %v, got: %v", tc.expectedOk, ok) + } + + if err == nil { + if tc.expectedError != "" { + t.Errorf("expected: %q, got: %v", tc.expectedError, err) + } + } else { + if err.Error() != tc.expectedError { + t.Errorf("expected: %q, got: %q", tc.expectedError, err.Error()) + } + } + + if !reflect.DeepEqual(warnings, tc.expectedWarnings) { + t.Errorf("expected: %q, got: %q", tc.expectedWarnings, warnings) + } + }) + } +} + +func TestDefaultVSphereProviderSpec(t *testing.T) { + + clusterID := "clusterID" + testCases := []struct { + testCase string + providerSpec *machinev1.VSphereMachineProviderSpec + modifyDefault func(*machinev1.VSphereMachineProviderSpec) + expectedError string + expectedOk bool + expectedWarnings []string + }{ + { + testCase: "it defaults defaultable fields", + providerSpec: &machinev1.VSphereMachineProviderSpec{}, + expectedOk: true, + expectedError: "", + }, + } + + platformStatus := &osconfigv1.PlatformStatus{Type: osconfigv1.VSpherePlatformType} + h := createMachineDefaulter(platformStatus, clusterID) + + for _, tc := range testCases { + t.Run(tc.testCase, func(t *testing.T) { + defaultProviderSpec := &machinev1.VSphereMachineProviderSpec{ + UserDataSecret: &corev1.LocalObjectReference{ + Name: defaultUserDataSecret, + }, + CredentialsSecret: &corev1.LocalObjectReference{ + Name: defaultVSphereCredentialsSecret, + }, + } + if tc.modifyDefault != nil { + tc.modifyDefault(defaultProviderSpec) + } + + m := &machinev1.Machine{} + rawBytes, err := json.Marshal(tc.providerSpec) + if err != nil { + t.Fatal(err) + } + m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} + + ok, warnings, err := h.webhookOperations(m, h.admissionConfig) + if ok != tc.expectedOk { + t.Errorf("expected: %v, got: %v", tc.expectedOk, ok) + } + + gotProviderSpec := new(machinev1.VSphereMachineProviderSpec) + if err := yaml.Unmarshal(m.Spec.ProviderSpec.Value.Raw, &gotProviderSpec); err != nil { + t.Fatal(err) + } + + if !equality.Semantic.DeepEqual(defaultProviderSpec, gotProviderSpec) { + t.Errorf("expected: %+v, got: %+v", defaultProviderSpec, gotProviderSpec) + } + if err == nil { + if tc.expectedError != "" { + t.Errorf("expected: %q, got: %v", tc.expectedError, err) + } + } else { + if err.Error() != tc.expectedError { + t.Errorf("expected: %q, got: %q", tc.expectedError, err.Error()) + } + } + + if !reflect.DeepEqual(warnings, tc.expectedWarnings) { + t.Errorf("expected: %q, got: %q", tc.expectedWarnings, warnings) + } + }) + } +} diff --git a/pkg/webhooks/machineset_types_test.go b/pkg/webhooks/machineset_types_test.go new file mode 100644 index 0000000000..e7992cea66 --- /dev/null +++ b/pkg/webhooks/machineset_types_test.go @@ -0,0 +1,128 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 webhooks + +import ( + "encoding/json" + "math/rand" + "reflect" + "testing" + "time" + + . "github.com/onsi/gomega" + machinev1 "github.com/openshift/api/machine/v1beta1" + "golang.org/x/net/context" + "k8s.io/apimachinery/pkg/api/apitesting/fuzzer" + metafuzzer "k8s.io/apimachinery/pkg/apis/meta/fuzzer" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func TestStorageMachineSet(t *testing.T) { + key := types.NamespacedName{Name: "foo", Namespace: "default"} + created := &machinev1.MachineSet{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}} + + // Test Create + fetched := &machinev1.MachineSet{} + if err := c.Create(context.TODO(), created); err != nil { + t.Errorf("error creating machineset: %v", err) + } + + if err := c.Get(context.TODO(), key, fetched); err != nil { + t.Errorf("error getting machineset: %v", err) + } + if !reflect.DeepEqual(*fetched, *created) { + t.Error("fetched value not what was created") + } + + // Test Updating the Labels + updated := fetched.DeepCopy() + updated.Labels = map[string]string{"hello": "world"} + if err := c.Update(context.TODO(), updated); err != nil { + t.Errorf("error updating machineset: %v", err) + } + + if err := c.Get(context.TODO(), key, fetched); err != nil { + t.Errorf("error getting machineset: %v", err) + } + if !reflect.DeepEqual(*fetched, *updated) { + t.Error("fetched value not what was updated") + } + + // Test Delete + if err := c.Delete(context.TODO(), fetched); err != nil { + t.Errorf("error deleting machineset: %v", err) + } + if err := c.Get(context.TODO(), key, fetched); err == nil { + t.Error("expected error getting machineset") + } +} + +func TestRoundTripMachineSet(t *testing.T) { + codecs := serializer.NewCodecFactory(scheme.Scheme) + seed := time.Now().UnixNano() + machineFuzzer := fuzzer.FuzzerFor(fuzzer.MergeFuzzerFuncs(metafuzzer.Funcs, machineFuzzerFuncs), rand.NewSource(seed), codecs) + ctx := context.Background() + g := NewWithT(t) + + for i := 0; i < 100; i++ { + machineSet := &machinev1.MachineSet{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "machineset-round-trip-test-", + Namespace: "default", + }, + } + // Fuzz the spec and status as those are the ones we need to check aren't + // losing data + spec := &machinev1.MachineSetSpec{} + status := &machinev1.MachineSetStatus{} + machineFuzzer.Fuzz(spec) + machineFuzzer.Fuzz(status) + + machineSet.Spec = *spec.DeepCopy() + g.Expect(c.Create(ctx, machineSet)).To(Succeed()) + machineSet.Status = *status.DeepCopy() + g.Expect(c.Status().Update(ctx, machineSet)).To(Succeed()) + + // Check the spec and status weren't modified during create + // + // Use JSON representation as order of fields in RawExtensions may change + // during a round trip + machineSetSpecJSON, err := json.Marshal(machineSet.Spec) + g.Expect(err).ToNot(HaveOccurred()) + specJSON, err := json.Marshal(*spec) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(machineSetSpecJSON).To(MatchJSON(specJSON)) + + machineSetStatusJSON, err := json.Marshal(machineSet.Status) + g.Expect(err).ToNot(HaveOccurred()) + statusJSON, err := json.Marshal(*status) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(machineSetStatusJSON).To(MatchJSON(statusJSON)) + + fetched := &machinev1.MachineSet{} + key := client.ObjectKey{Namespace: machineSet.Namespace, Name: machineSet.Name} + g.Expect(c.Get(ctx, key, fetched)).To(Succeed()) + + // Check the spec and status haven't changed server side + g.Expect(fetched.Spec).To(Equal(machineSet.Spec)) + g.Expect(fetched.Status).To(Equal(machineSet.Status)) + } +} diff --git a/pkg/webhooks/machineset_webhook.go b/pkg/webhooks/machineset_webhook.go new file mode 100644 index 0000000000..ac1115e0e1 --- /dev/null +++ b/pkg/webhooks/machineset_webhook.go @@ -0,0 +1,152 @@ +package webhooks + +import ( + "context" + "encoding/json" + "net/http" + + osconfigv1 "github.com/openshift/api/config/v1" + machinev1 "github.com/openshift/api/machine/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + + "k8s.io/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" +) + +// machineSetValidatorHandler validates MachineSet API resources. +// implements type Handler interface. +// https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/webhook/admission#Handler +type machineSetValidatorHandler struct { + *admissionHandler +} + +// machineSetDefaulterHandler defaults MachineSet API resources. +// implements type Handler interface. +// https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/webhook/admission#Handler +type machineSetDefaulterHandler struct { + *admissionHandler +} + +// NewMachineSetValidator returns a new machineSetValidatorHandler. +func NewMachineSetValidator(client client.Client) (*machineSetValidatorHandler, error) { + infra, err := getInfra() + if err != nil { + return nil, err + } + + dns, err := getDNS() + if err != nil { + return nil, err + } + + return createMachineSetValidator(infra, client, dns), nil +} + +func createMachineSetValidator(infra *osconfigv1.Infrastructure, client client.Client, dns *osconfigv1.DNS) *machineSetValidatorHandler { + admissionConfig := &admissionConfig{ + dnsDisconnected: dns.Spec.PublicZone == nil, + clusterID: infra.Status.InfrastructureName, + client: client, + } + return &machineSetValidatorHandler{ + admissionHandler: &admissionHandler{ + admissionConfig: admissionConfig, + webhookOperations: getMachineValidatorOperation(infra.Status.PlatformStatus.Type), + }, + } +} + +// NewMachineSetDefaulter returns a new machineSetDefaulterHandler. +func NewMachineSetDefaulter() (*machineSetDefaulterHandler, error) { + infra, err := getInfra() + if err != nil { + return nil, err + } + + return createMachineSetDefaulter(infra.Status.PlatformStatus, infra.Status.InfrastructureName), nil +} + +func createMachineSetDefaulter(platformStatus *osconfigv1.PlatformStatus, clusterID string) *machineSetDefaulterHandler { + return &machineSetDefaulterHandler{ + admissionHandler: &admissionHandler{ + admissionConfig: &admissionConfig{clusterID: clusterID}, + webhookOperations: getMachineDefaulterOperation(platformStatus), + }, + } +} + +// Handle handles HTTP requests for admission webhook servers. +func (h *machineSetValidatorHandler) Handle(ctx context.Context, req admission.Request) admission.Response { + ms := &machinev1.MachineSet{} + + if err := h.decoder.Decode(req, ms); err != nil { + return admission.Errored(http.StatusBadRequest, err) + } + + klog.V(3).Infof("Validate webhook called for MachineSet: %s", ms.GetName()) + + ok, warnings, errs := h.validateMachineSet(ms) + if !ok { + return admission.Denied(errs.Error()).WithWarnings(warnings...) + } + + return admission.Allowed("MachineSet valid").WithWarnings(warnings...) +} + +// Handle handles HTTP requests for admission webhook servers. +func (h *machineSetDefaulterHandler) Handle(ctx context.Context, req admission.Request) admission.Response { + ms := &machinev1.MachineSet{} + + if err := h.decoder.Decode(req, ms); err != nil { + return admission.Errored(http.StatusBadRequest, err) + } + + klog.V(3).Infof("Mutate webhook called for MachineSet: %s", ms.GetName()) + + ok, warnings, errs := h.defaultMachineSet(ms) + if !ok { + return admission.Denied(errs.Error()).WithWarnings(warnings...) + } + + marshaledMachineSet, err := json.Marshal(ms) + if err != nil { + return admission.Errored(http.StatusInternalServerError, err).WithWarnings(warnings...) + } + return admission.PatchResponseFromRaw(req.Object.Raw, marshaledMachineSet).WithWarnings(warnings...) +} + +func (h *machineSetValidatorHandler) validateMachineSet(ms *machinev1.MachineSet) (bool, []string, utilerrors.Aggregate) { + var errs []error + + // Create a Machine from the MachineSet and validate the Machine template + m := &machinev1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ms.GetNamespace(), + }, + Spec: ms.Spec.Template.Spec, + } + ok, warnings, err := h.webhookOperations(m, h.admissionConfig) + if !ok { + errs = append(errs, err.Errors()...) + } + + if len(errs) > 0 { + return false, warnings, utilerrors.NewAggregate(errs) + } + return true, warnings, nil +} + +func (h *machineSetDefaulterHandler) defaultMachineSet(ms *machinev1.MachineSet) (bool, []string, utilerrors.Aggregate) { + // Create a Machine from the MachineSet and default the Machine template + m := &machinev1.Machine{Spec: ms.Spec.Template.Spec} + ok, warnings, err := h.webhookOperations(m, h.admissionConfig) + if !ok { + return false, warnings, utilerrors.NewAggregate(err.Errors()) + } + + // Restore the defaulted template + ms.Spec.Template.Spec = m.Spec + return true, warnings, nil +} diff --git a/pkg/webhooks/machineset_webhook_test.go b/pkg/webhooks/machineset_webhook_test.go new file mode 100644 index 0000000000..c543a38942 --- /dev/null +++ b/pkg/webhooks/machineset_webhook_test.go @@ -0,0 +1,829 @@ +package webhooks + +import ( + "context" + "fmt" + "testing" + + . "github.com/onsi/gomega" + osconfigv1 "github.com/openshift/api/config/v1" + machinev1 "github.com/openshift/api/machine/v1beta1" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/rest" + "k8s.io/utils/pointer" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client/config" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/webhook" +) + +func TestMachineSetCreation(t *testing.T) { + g := NewWithT(t) + + // Override config getter + ctrl.GetConfig = func() (*rest.Config, error) { + return cfg, nil + } + defer func() { + ctrl.GetConfig = config.GetConfig + }() + + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machineset-creation-test", + }, + } + g.Expect(c.Create(ctx, namespace)).To(Succeed()) + defer func() { + g.Expect(c.Delete(ctx, namespace)).To(Succeed()) + }() + + awsSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaultAWSCredentialsSecret, + Namespace: namespace.Name, + }, + } + vSphereSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaultVSphereCredentialsSecret, + Namespace: namespace.Name, + }, + } + GCPSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaultGCPCredentialsSecret, + Namespace: namespace.Name, + }, + } + azureSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaultAzureCredentialsSecret, + Namespace: defaultSecretNamespace, + }, + } + g.Expect(c.Create(ctx, awsSecret)).To(Succeed()) + g.Expect(c.Create(ctx, vSphereSecret)).To(Succeed()) + g.Expect(c.Create(ctx, GCPSecret)).To(Succeed()) + g.Expect(c.Create(ctx, azureSecret)).To(Succeed()) + defer func() { + g.Expect(c.Delete(ctx, awsSecret)).To(Succeed()) + g.Expect(c.Delete(ctx, vSphereSecret)).To(Succeed()) + g.Expect(c.Delete(ctx, GCPSecret)).To(Succeed()) + g.Expect(c.Delete(ctx, azureSecret)).To(Succeed()) + }() + + testCases := []struct { + name string + platformType osconfigv1.PlatformType + clusterID string + expectedError string + disconnected bool + providerSpecValue *runtime.RawExtension + }{ + { + name: "with AWS and a nil provider spec value", + platformType: osconfigv1.AWSPlatformType, + clusterID: "aws-cluster", + providerSpecValue: nil, + expectedError: "providerSpec.value: Required value: a value must be provided", + }, + { + name: "with AWS and no fields set", + platformType: osconfigv1.AWSPlatformType, + clusterID: "aws-cluster", + providerSpecValue: &runtime.RawExtension{ + Object: &machinev1.AWSMachineProviderConfig{}, + }, + expectedError: "providerSpec.ami: Required value: expected providerSpec.ami.id to be populated", + }, + { + name: "with AWS and an AMI ID", + platformType: osconfigv1.AWSPlatformType, + clusterID: "aws-cluster", + providerSpecValue: &runtime.RawExtension{ + Object: &machinev1.AWSMachineProviderConfig{ + AMI: machinev1.AWSResourceReference{ + ID: pointer.StringPtr("ami"), + }, + }, + }, + expectedError: "", + }, + { + name: "with Azure and a nil provider spec value", + platformType: osconfigv1.AWSPlatformType, + clusterID: "azure-cluster", + providerSpecValue: nil, + expectedError: "providerSpec.value: Required value: a value must be provided", + }, + { + name: "with Azure and no fields set", + platformType: osconfigv1.AzurePlatformType, + clusterID: "azure-cluster", + providerSpecValue: &runtime.RawExtension{ + Object: &machinev1.AzureMachineProviderSpec{}, + }, + expectedError: "providerSpec.osDisk.diskSizeGB: Invalid value: 0: diskSizeGB must be greater than zero and less than 32768", + }, + { + name: "with Azure and a location and disk size set", + platformType: osconfigv1.AzurePlatformType, + clusterID: "azure-cluster", + providerSpecValue: &runtime.RawExtension{ + Object: &machinev1.AzureMachineProviderSpec{ + Location: "location", + OSDisk: machinev1.OSDisk{ + DiskSizeGB: 128, + }, + }, + }, + expectedError: "", + }, + { + name: "with Azure disconnected installation request public IP", + platformType: osconfigv1.AzurePlatformType, + clusterID: "azure-cluster", + providerSpecValue: &runtime.RawExtension{ + Object: &machinev1.AzureMachineProviderSpec{ + OSDisk: machinev1.OSDisk{ + DiskSizeGB: 128, + }, + PublicIP: true, + }, + }, + disconnected: true, + expectedError: "providerSpec.publicIP: Forbidden: publicIP is not allowed in Azure disconnected installation", + }, + { + name: "with Azure disconnected installation success", + platformType: osconfigv1.AzurePlatformType, + clusterID: "azure-cluster", + providerSpecValue: &runtime.RawExtension{ + Object: &machinev1.AzureMachineProviderSpec{ + OSDisk: machinev1.OSDisk{ + DiskSizeGB: 128, + }, + }, + }, + disconnected: true, + }, + { + name: "with GCP and a nil provider spec value", + platformType: osconfigv1.AWSPlatformType, + clusterID: "gcp-cluster", + providerSpecValue: nil, + expectedError: "providerSpec.value: Required value: a value must be provided", + }, + { + name: "with GCP and no fields set", + platformType: osconfigv1.GCPPlatformType, + clusterID: "gcp-cluster", + providerSpecValue: &runtime.RawExtension{ + Object: &machinev1.GCPMachineProviderSpec{}, + }, + expectedError: "providerSpec.region: Required value: region is required", + }, + { + name: "with GCP and the region and zone set", + platformType: osconfigv1.GCPPlatformType, + clusterID: "gcp-cluster", + providerSpecValue: &runtime.RawExtension{ + Object: &machinev1.GCPMachineProviderSpec{ + Region: "region", + Zone: "region-zone", + }, + }, + expectedError: "", + }, + { + name: "with vSphere and a nil provider spec value", + platformType: osconfigv1.VSpherePlatformType, + clusterID: "vsphere-cluster", + providerSpecValue: nil, + expectedError: "providerSpec.value: Required value: a value must be provided", + }, + { + name: "with vSphere and no fields set", + platformType: osconfigv1.VSpherePlatformType, + clusterID: "vsphere-cluster", + providerSpecValue: &runtime.RawExtension{ + Object: &machinev1.VSphereMachineProviderSpec{}, + }, + expectedError: "[providerSpec.template: Required value: template must be provided, providerSpec.workspace: Required value: workspace must be provided, providerSpec.network.devices: Required value: at least 1 network device must be provided]", + }, + { + name: "with vSphere and the template, workspace and network devices set", + platformType: osconfigv1.VSpherePlatformType, + clusterID: "vsphere-cluster", + providerSpecValue: &runtime.RawExtension{ + Object: &machinev1.VSphereMachineProviderSpec{ + Template: "template", + Workspace: &machinev1.Workspace{ + Datacenter: "datacenter", + Server: "server", + }, + Network: machinev1.NetworkSpec{ + Devices: []machinev1.NetworkDeviceSpec{ + { + NetworkName: "networkName", + }, + }, + }, + }, + }, + expectedError: "", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + gs := NewWithT(t) + + mgr, err := manager.New(cfg, manager.Options{ + MetricsBindAddress: "0", + Port: testEnv.WebhookInstallOptions.LocalServingPort, + CertDir: testEnv.WebhookInstallOptions.LocalServingCertDir, + }) + gs.Expect(err).ToNot(HaveOccurred()) + + platformStatus := &osconfigv1.PlatformStatus{ + Type: tc.platformType, + GCP: &osconfigv1.GCPPlatformStatus{ + ProjectID: "gcp-project-id", + }, + AWS: &osconfigv1.AWSPlatformStatus{ + Region: "region", + }, + } + + infra := plainInfra.DeepCopy() + infra.Status.InfrastructureName = tc.clusterID + infra.Status.PlatformStatus = platformStatus + + dns := plainDNS.DeepCopy() + if !tc.disconnected { + dns.Spec.PublicZone = &osconfigv1.DNSZone{} + } + machineSetDefaulter := createMachineSetDefaulter(platformStatus, tc.clusterID) + machineSetValidator := createMachineSetValidator(infra, c, dns) + mgr.GetWebhookServer().Register(DefaultMachineSetMutatingHookPath, &webhook.Admission{Handler: machineSetDefaulter}) + mgr.GetWebhookServer().Register(DefaultMachineSetValidatingHookPath, &webhook.Admission{Handler: machineSetValidator}) + + mgrCtx, cancel := context.WithCancel(context.Background()) + stopped := make(chan struct{}) + go func() { + gs.Expect(mgr.Start(mgrCtx)).To(Succeed()) + close(stopped) + }() + defer func() { + cancel() + <-stopped + }() + + gs.Eventually(func() (bool, error) { + resp, err := insecureHTTPClient.Get(fmt.Sprintf("https://127.0.0.1:%d", testEnv.WebhookInstallOptions.LocalServingPort)) + if err != nil { + return false, err + } + return resp.StatusCode == 404, nil + }).Should(BeTrue()) + + ms := &machinev1.MachineSet{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "machineset-creation-", + Namespace: namespace.Name, + }, + Spec: machinev1.MachineSetSpec{ + Template: machinev1.MachineTemplateSpec{ + Spec: machinev1.MachineSpec{ + ProviderSpec: machinev1.ProviderSpec{ + Value: tc.providerSpecValue, + }, + }, + }, + }, + } + + err = c.Create(ctx, ms) + if err == nil { + defer func() { + gs.Expect(c.Delete(ctx, ms)).To(Succeed()) + }() + } + + if tc.expectedError != "" { + gs.Expect(err).ToNot(BeNil()) + gs.Expect(apierrors.ReasonForError(err)).To(BeEquivalentTo(tc.expectedError)) + } else { + gs.Expect(err).To(BeNil()) + } + }) + } +} + +func TestMachineSetUpdate(t *testing.T) { + awsClusterID := "aws-cluster" + awsRegion := "region" + defaultAWSProviderSpec := &machinev1.AWSMachineProviderConfig{ + AMI: machinev1.AWSResourceReference{ + ID: pointer.StringPtr("ami"), + }, + InstanceType: defaultAWSX86InstanceType, + UserDataSecret: &corev1.LocalObjectReference{Name: defaultUserDataSecret}, + CredentialsSecret: &corev1.LocalObjectReference{Name: defaultAWSCredentialsSecret}, + Placement: machinev1.Placement{ + Region: awsRegion, + }, + } + + azureClusterID := "azure-cluster" + defaultAzureProviderSpec := &machinev1.AzureMachineProviderSpec{ + Location: "location", + VMSize: defaultAzureVMSize, + Vnet: defaultAzureVnet(azureClusterID), + Subnet: defaultAzureSubnet(azureClusterID), + NetworkResourceGroup: defaultAzureNetworkResourceGroup(azureClusterID), + Image: machinev1.Image{ + ResourceID: defaultAzureImageResourceID(azureClusterID), + }, + ManagedIdentity: defaultAzureManagedIdentiy(azureClusterID), + ResourceGroup: defaultAzureResourceGroup(azureClusterID), + UserDataSecret: &corev1.SecretReference{ + Name: defaultUserDataSecret, + Namespace: defaultSecretNamespace, + }, + CredentialsSecret: &corev1.SecretReference{ + Name: defaultAzureCredentialsSecret, + Namespace: defaultSecretNamespace, + }, + OSDisk: machinev1.OSDisk{ + DiskSizeGB: 128, + OSType: defaultAzureOSDiskOSType, + ManagedDisk: machinev1.ManagedDiskParameters{ + StorageAccountType: defaultAzureOSDiskStorageType, + }, + }, + } + + gcpClusterID := "gcp-cluster" + defaultGCPProviderSpec := &machinev1.GCPMachineProviderSpec{ + Region: "region", + Zone: "region-zone", + MachineType: defaultGCPMachineType, + NetworkInterfaces: []*machinev1.GCPNetworkInterface{ + { + Network: defaultGCPNetwork(gcpClusterID), + Subnetwork: defaultGCPSubnetwork(gcpClusterID), + }, + }, + Disks: []*machinev1.GCPDisk{ + { + AutoDelete: true, + Boot: true, + SizeGB: defaultGCPDiskSizeGb, + Type: defaultGCPDiskType, + Image: defaultGCPDiskImage, + }, + }, + Tags: defaultGCPTags(gcpClusterID), + UserDataSecret: &corev1.LocalObjectReference{ + Name: defaultUserDataSecret, + }, + CredentialsSecret: &corev1.LocalObjectReference{ + Name: defaultGCPCredentialsSecret, + }, + } + + vsphereClusterID := "vsphere-cluster" + defaultVSphereProviderSpec := &machinev1.VSphereMachineProviderSpec{ + Template: "template", + Workspace: &machinev1.Workspace{ + Datacenter: "datacenter", + Server: "server", + }, + Network: machinev1.NetworkSpec{ + Devices: []machinev1.NetworkDeviceSpec{ + { + NetworkName: "networkName", + }, + }, + }, + UserDataSecret: &corev1.LocalObjectReference{ + Name: defaultUserDataSecret, + }, + CredentialsSecret: &corev1.LocalObjectReference{ + Name: defaultVSphereCredentialsSecret, + }, + } + + g := NewWithT(t) + + // Override config getter + ctrl.GetConfig = func() (*rest.Config, error) { + return cfg, nil + } + defer func() { + ctrl.GetConfig = config.GetConfig + }() + + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machineset-update-test", + }, + } + g.Expect(c.Create(ctx, namespace)).To(Succeed()) + defer func() { + g.Expect(c.Delete(ctx, namespace)).To(Succeed()) + }() + + awsSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaultAWSCredentialsSecret, + Namespace: namespace.Name, + }, + } + vSphereSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaultVSphereCredentialsSecret, + Namespace: namespace.Name, + }, + } + GCPSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaultGCPCredentialsSecret, + Namespace: namespace.Name, + }, + } + azureSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaultAzureCredentialsSecret, + Namespace: defaultSecretNamespace, + }, + } + g.Expect(c.Create(ctx, awsSecret)).To(Succeed()) + g.Expect(c.Create(ctx, vSphereSecret)).To(Succeed()) + g.Expect(c.Create(ctx, GCPSecret)).To(Succeed()) + g.Expect(c.Create(ctx, azureSecret)).To(Succeed()) + defer func() { + g.Expect(c.Delete(ctx, awsSecret)).To(Succeed()) + g.Expect(c.Delete(ctx, vSphereSecret)).To(Succeed()) + g.Expect(c.Delete(ctx, GCPSecret)).To(Succeed()) + g.Expect(c.Delete(ctx, azureSecret)).To(Succeed()) + }() + + testCases := []struct { + name string + platformType osconfigv1.PlatformType + clusterID string + expectedError string + baseProviderSpecValue *runtime.RawExtension + updatedProviderSpecValue func() *runtime.RawExtension + }{ + { + name: "with a valid AWS ProviderSpec", + platformType: osconfigv1.AWSPlatformType, + clusterID: awsClusterID, + baseProviderSpecValue: &runtime.RawExtension{ + Object: defaultAWSProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *runtime.RawExtension { + return &runtime.RawExtension{ + Object: defaultAWSProviderSpec.DeepCopy(), + } + }, + expectedError: "", + }, + { + name: "with an AWS ProviderSpec, removing the instance type", + platformType: osconfigv1.AWSPlatformType, + clusterID: awsClusterID, + baseProviderSpecValue: &runtime.RawExtension{ + Object: defaultAWSProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *runtime.RawExtension { + object := defaultAWSProviderSpec.DeepCopy() + object.InstanceType = "" + return &runtime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.instanceType: Required value: expected providerSpec.instanceType to be populated", + }, + { + name: "with an AWS ProviderSpec, removing the region", + platformType: osconfigv1.AWSPlatformType, + clusterID: awsClusterID, + baseProviderSpecValue: &runtime.RawExtension{ + Object: defaultAWSProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *runtime.RawExtension { + object := defaultAWSProviderSpec.DeepCopy() + object.Placement.Region = "" + return &runtime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.placement.region: Required value: expected providerSpec.placement.region to be populated", + }, + { + name: "with an AWS ProviderSpec, removing the user data secret", + platformType: osconfigv1.AWSPlatformType, + clusterID: awsClusterID, + baseProviderSpecValue: &runtime.RawExtension{ + Object: defaultAWSProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *runtime.RawExtension { + object := defaultAWSProviderSpec.DeepCopy() + object.UserDataSecret = nil + return &runtime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.userDataSecret: Required value: expected providerSpec.userDataSecret to be populated", + }, + { + name: "with a valid Azure ProviderSpec", + platformType: osconfigv1.AzurePlatformType, + clusterID: azureClusterID, + baseProviderSpecValue: &runtime.RawExtension{ + Object: defaultAzureProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *runtime.RawExtension { + return &runtime.RawExtension{ + Object: defaultAzureProviderSpec.DeepCopy(), + } + }, + expectedError: "", + }, + { + name: "with an Azure ProviderSpec, removing the vm size", + platformType: osconfigv1.AzurePlatformType, + clusterID: azureClusterID, + baseProviderSpecValue: &runtime.RawExtension{ + Object: defaultAzureProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *runtime.RawExtension { + object := defaultAzureProviderSpec.DeepCopy() + object.VMSize = "" + return &runtime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.vmSize: Required value: vmSize should be set to one of the supported Azure VM sizes", + }, + { + name: "with an Azure ProviderSpec, removing the subnet", + platformType: osconfigv1.AzurePlatformType, + clusterID: azureClusterID, + baseProviderSpecValue: &runtime.RawExtension{ + Object: defaultAzureProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *runtime.RawExtension { + object := defaultAzureProviderSpec.DeepCopy() + object.Subnet = "" + return &runtime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.subnet: Required value: must provide a subnet when a virtual network is specified", + }, + { + name: "with an Azure ProviderSpec, removing the credentials secret", + platformType: osconfigv1.AzurePlatformType, + clusterID: azureClusterID, + baseProviderSpecValue: &runtime.RawExtension{ + Object: defaultAzureProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *runtime.RawExtension { + object := defaultAzureProviderSpec.DeepCopy() + object.CredentialsSecret = nil + return &runtime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.credentialsSecret: Required value: credentialsSecret must be provided", + }, + { + name: "with a valid GCP ProviderSpec", + platformType: osconfigv1.GCPPlatformType, + clusterID: gcpClusterID, + baseProviderSpecValue: &runtime.RawExtension{ + Object: defaultGCPProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *runtime.RawExtension { + return &runtime.RawExtension{ + Object: defaultGCPProviderSpec.DeepCopy(), + } + }, + expectedError: "", + }, + { + name: "with a GCP ProviderSpec, removing the region", + platformType: osconfigv1.GCPPlatformType, + clusterID: gcpClusterID, + baseProviderSpecValue: &runtime.RawExtension{ + Object: defaultGCPProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *runtime.RawExtension { + object := defaultGCPProviderSpec.DeepCopy() + object.Region = "" + return &runtime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.region: Required value: region is required", + }, + { + name: "with a GCP ProviderSpec, and an invalid region", + platformType: osconfigv1.GCPPlatformType, + clusterID: gcpClusterID, + baseProviderSpecValue: &runtime.RawExtension{ + Object: defaultGCPProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *runtime.RawExtension { + object := defaultGCPProviderSpec.DeepCopy() + object.Zone = "zone" + return &runtime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.zone: Invalid value: \"zone\": zone not in configured region (region)", + }, + { + name: "with a GCP ProviderSpec, removing the disks", + platformType: osconfigv1.GCPPlatformType, + clusterID: gcpClusterID, + baseProviderSpecValue: &runtime.RawExtension{ + Object: defaultGCPProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *runtime.RawExtension { + object := defaultGCPProviderSpec.DeepCopy() + object.Disks = nil + return &runtime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.disks: Required value: at least 1 disk is required", + }, + { + name: "with a GCP ProviderSpec, removing the network interfaces", + platformType: osconfigv1.GCPPlatformType, + clusterID: gcpClusterID, + baseProviderSpecValue: &runtime.RawExtension{ + Object: defaultGCPProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *runtime.RawExtension { + object := defaultGCPProviderSpec.DeepCopy() + object.NetworkInterfaces = nil + return &runtime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.networkInterfaces: Required value: at least 1 network interface is required", + }, + { + name: "with a valid VSphere ProviderSpec", + platformType: osconfigv1.VSpherePlatformType, + clusterID: vsphereClusterID, + baseProviderSpecValue: &runtime.RawExtension{ + Object: defaultVSphereProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *runtime.RawExtension { + return &runtime.RawExtension{ + Object: defaultVSphereProviderSpec.DeepCopy(), + } + }, + expectedError: "", + }, + { + name: "with an VSphere ProviderSpec, removing the template", + platformType: osconfigv1.VSpherePlatformType, + clusterID: vsphereClusterID, + baseProviderSpecValue: &runtime.RawExtension{ + Object: defaultVSphereProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *runtime.RawExtension { + object := defaultVSphereProviderSpec.DeepCopy() + object.Template = "" + return &runtime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.template: Required value: template must be provided", + }, + { + name: "with an VSphere ProviderSpec, removing the workspace server", + platformType: osconfigv1.VSpherePlatformType, + clusterID: vsphereClusterID, + baseProviderSpecValue: &runtime.RawExtension{ + Object: defaultVSphereProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *runtime.RawExtension { + object := defaultVSphereProviderSpec.DeepCopy() + object.Workspace.Server = "" + return &runtime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.workspace.server: Required value: server must be provided", + }, + { + name: "with an VSphere ProviderSpec, removing the network devices", + platformType: osconfigv1.VSpherePlatformType, + clusterID: vsphereClusterID, + baseProviderSpecValue: &runtime.RawExtension{ + Object: defaultVSphereProviderSpec.DeepCopy(), + }, + updatedProviderSpecValue: func() *runtime.RawExtension { + object := defaultVSphereProviderSpec.DeepCopy() + object.Network = machinev1.NetworkSpec{} + return &runtime.RawExtension{ + Object: object, + } + }, + expectedError: "providerSpec.network.devices: Required value: at least 1 network device must be provided", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + gs := NewWithT(t) + + mgr, err := manager.New(cfg, manager.Options{ + MetricsBindAddress: "0", + Port: testEnv.WebhookInstallOptions.LocalServingPort, + CertDir: testEnv.WebhookInstallOptions.LocalServingCertDir, + }) + gs.Expect(err).ToNot(HaveOccurred()) + + platformStatus := &osconfigv1.PlatformStatus{ + Type: tc.platformType, + AWS: &osconfigv1.AWSPlatformStatus{ + Region: awsRegion, + }, + } + + infra := plainInfra.DeepCopy() + infra.Status.InfrastructureName = tc.clusterID + infra.Status.PlatformStatus = platformStatus + + machineSetDefaulter := createMachineSetDefaulter(platformStatus, tc.clusterID) + machineSetValidator := createMachineSetValidator(infra, c, plainDNS) + mgr.GetWebhookServer().Register(DefaultMachineSetMutatingHookPath, &webhook.Admission{Handler: machineSetDefaulter}) + mgr.GetWebhookServer().Register(DefaultMachineSetValidatingHookPath, &webhook.Admission{Handler: machineSetValidator}) + + mgrCtx, cancel := context.WithCancel(context.Background()) + stopped := make(chan struct{}) + go func() { + gs.Expect(mgr.Start(mgrCtx)).To(Succeed()) + close(stopped) + }() + defer func() { + cancel() + <-stopped + }() + + gs.Eventually(func() (bool, error) { + resp, err := insecureHTTPClient.Get(fmt.Sprintf("https://127.0.0.1:%d", testEnv.WebhookInstallOptions.LocalServingPort)) + if err != nil { + return false, err + } + return resp.StatusCode == 404, nil + }).Should(BeTrue()) + + ms := &machinev1.MachineSet{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "machineset-update-", + Namespace: namespace.Name, + }, + Spec: machinev1.MachineSetSpec{ + Template: machinev1.MachineTemplateSpec{ + Spec: machinev1.MachineSpec{ + ProviderSpec: machinev1.ProviderSpec{ + Value: tc.baseProviderSpecValue, + }, + }, + }, + }, + } + err = c.Create(ctx, ms) + gs.Expect(err).ToNot(HaveOccurred()) + defer func() { + gs.Expect(c.Delete(ctx, ms)).To(Succeed()) + }() + + ms.Spec.Template.Spec.ProviderSpec.Value = tc.updatedProviderSpecValue() + err = c.Update(ctx, ms) + if tc.expectedError != "" { + gs.Expect(err).ToNot(BeNil()) + gs.Expect(apierrors.ReasonForError(err)).To(BeEquivalentTo(tc.expectedError)) + } else { + gs.Expect(err).To(BeNil()) + } + }) + } +} diff --git a/pkg/webhooks/v1beta1_suite_test.go b/pkg/webhooks/v1beta1_suite_test.go new file mode 100644 index 0000000000..8a7b1b7a29 --- /dev/null +++ b/pkg/webhooks/v1beta1_suite_test.go @@ -0,0 +1,222 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 webhooks + +import ( + "context" + "crypto/tls" + "log" + "net/http" + "os" + "path/filepath" + "testing" + "time" + + corev1 "k8s.io/api/core/v1" + + fuzz "github.com/google/gofuzz" + osconfigv1 "github.com/openshift/api/config/v1" + machinev1 "github.com/openshift/api/machine/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" +) + +var ( + cfg *rest.Config + c client.Client + ctx = context.Background() + testEnv *envtest.Environment + insecureHTTPClient = http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + }, + } +) + +func TestMain(m *testing.M) { + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{ + filepath.Join("..", "..", "..", "..", "install"), + filepath.Join("..", "..", "..", "..", "vendor", "github.com", "openshift", "api", "config", "v1"), + }, + WebhookInstallOptions: envtest.WebhookInstallOptions{ + MutatingWebhooks: []client.Object{NewMutatingWebhookConfiguration()}, + ValidatingWebhooks: []client.Object{NewValidatingWebhookConfiguration()}, + }, + } + + err := machinev1.Install(scheme.Scheme) + if err != nil { + log.Fatal(err) + } + + err = osconfigv1.AddToScheme(scheme.Scheme) + if err != nil { + log.Fatal(err) + } + + if cfg, err = testEnv.Start(); err != nil { + log.Fatal(err) + } + + if c, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}); err != nil { + log.Fatal(err) + } + + // Azure credentialsSecret is a secretRef defaulting to defaultSecretNamespace instead of a localObjectRef. + // This is so the tests can assume this namespace exists. + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaultSecretNamespace, + }, + } + if err = c.Create(ctx, namespace); err != nil { + log.Fatal(err) + } + + code := m.Run() + testEnv.Stop() + os.Exit(code) +} + +func machineFuzzerFuncs(codecs runtimeserializer.CodecFactory) []interface{} { + return []interface{}{ + // Fuzzer for pointer to metav1.Time + func(j **metav1.Time, c fuzz.Continue) { + if c.RandBool() { + t := &time.Time{} + c.Fuzz(t) + *j = &metav1.Time{Time: *t} + } else { + *j = nil + } + }, + // Fuzzer for MachineSpec to ensure empty embedded maps are nil + func(j *machinev1.MachineSpec, c fuzz.Continue) { + c.FuzzNoCustom(j) + + // Fuzz ObjectMeta using custom fuzzer + c.Fuzz(&j.ObjectMeta) + + // Ensure embedded maps are nil if they have zero length + if len(j.ObjectMeta.Labels) == 0 { + j.ObjectMeta.Labels = nil + } + if len(j.ObjectMeta.Annotations) == 0 { + j.ObjectMeta.Annotations = nil + } + + // Ensure slices are nil if they are empty + if len(j.Taints) == 0 { + j.Taints = nil + } + }, + // Fuzzer for MachineStatus to ensure empty embedded maps are nil + func(j *machinev1.MachineStatus, c fuzz.Continue) { + c.FuzzNoCustom(j) + + // Fuzz LastUpdated using custom fuzzer + c.Fuzz(&j.LastUpdated) + c.Fuzz(&j.LastOperation) + + // Ensure slices are nil if they are empty + if len(j.Addresses) == 0 { + j.Addresses = nil + } + if len(j.Conditions) == 0 { + j.Conditions = nil + } + }, + // Fuzzer for MachineSetSpec to ensure value restrictions are honoured + func(j *machinev1.MachineSetSpec, c fuzz.Continue) { + c.FuzzNoCustom(j) + + // Fuzz Selector using custom fuzzer + c.Fuzz(&j.Selector) + if len(j.Selector.MatchLabels) == 0 { + j.Selector.MatchLabels = nil + } + if len(j.Selector.MatchExpressions) == 0 { + j.Selector.MatchExpressions = nil + } + + // Fuzz Template using custom fuzzers + c.Fuzz(&j.Template) + + // Ensure replicas is greater than zero + replicas := c.Rand.Int31() + j.Replicas = &replicas + + // Set DeletionPolicy to a valid value + validDeletionPolicy := []string{ + string(machinev1.RandomMachineSetDeletePolicy), + string(machinev1.NewestMachineSetDeletePolicy), + string(machinev1.OldestMachineSetDeletePolicy), + } + j.DeletePolicy = validDeletionPolicy[c.Rand.Intn(len(validDeletionPolicy))] + }, + // Fuzzer for MachineSetStatus to ensure value restrictions are honoured + func(j *machinev1.MachineSetStatus, c fuzz.Continue) { + c.FuzzNoCustom(j) + + // Ensure replicas is greater than zero + j.Replicas = c.Rand.Int31() + }, + // Fuzzer for ObjectMeta to ensure empty maps are nil + func(j *machinev1.ObjectMeta, c fuzz.Continue) { + c.FuzzNoCustom(j) + + if len(j.Labels) == 0 { + j.Labels = nil + } else { + delete(j.Labels, "") + } + if len(j.Annotations) == 0 { + j.Annotations = nil + } else { + delete(j.Annotations, "") + } + if len(j.OwnerReferences) == 0 { + j.OwnerReferences = nil + } + }, + // Fuzzer for MachineTemplateSpec to ensure empty embedded maps are nil + func(j *machinev1.MachineTemplateSpec, c fuzz.Continue) { + c.FuzzNoCustom(j) + + // Fuzz the ObjectMeta + c.Fuzz(&j.ObjectMeta) + + // Ensure embedded maps are nil if they have zero length + if len(j.ObjectMeta.Labels) == 0 { + j.ObjectMeta.Labels = nil + } + if len(j.ObjectMeta.Annotations) == 0 { + j.ObjectMeta.Annotations = nil + } + + // Fuzz the Spec + c.Fuzz(&j.Spec) + }, + } +} From ce0b1f467f9cb821dc371f2478b68587859cb39b Mon Sep 17 00:00:00 2001 From: Alexander Demichev Date: Tue, 26 Oct 2021 19:55:45 +0200 Subject: [PATCH 04/10] Move some validation from api to controllers --- pkg/controller/machine/controller.go | 19 ++++++++++++++++++- pkg/controller/machineset/controller.go | 24 +++++++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/pkg/controller/machine/controller.go b/pkg/controller/machine/controller.go index 537a3883a5..7d98426997 100644 --- a/pkg/controller/machine/controller.go +++ b/pkg/controller/machine/controller.go @@ -177,7 +177,7 @@ func (r *ReconcileMachine) Reconcile(ctx context.Context, request reconcile.Requ // This must be a copy otherwise the referenced slice will be modified by later machine conditions changes. originalConditions := m.GetConditions().DeepCopy() - if errList := m.Validate(); len(errList) > 0 { + if errList := validateMachine(m); len(errList) > 0 { err := fmt.Errorf("%v: machine validation failed: %v", machineName, errList.ToAggregate().Error()) klog.Error(err) r.eventRecorder.Eventf(m, corev1.EventTypeWarning, "FailedValidate", err.Error()) @@ -602,6 +602,23 @@ func (r *ReconcileMachine) overrideFailedMachineProviderStatusState(machine *mac return nil } +func validateMachine(m *machinev1.Machine) field.ErrorList { + errors := field.ErrorList{} + + // validate spec.labels + fldPath := field.NewPath("spec") + if m.Labels[machinev1.MachineClusterIDLabel] == "" { + errors = append(errors, field.Invalid(fldPath.Child("labels"), m.Labels, fmt.Sprintf("missing %v label.", machinev1.MachineClusterIDLabel))) + } + + // validate provider config is set + if m.Spec.ProviderSpec.Value == nil { + errors = append(errors, field.Invalid(fldPath.Child("spec").Child("providerspec"), m.Spec.ProviderSpec, "value field must be set")) + } + + return errors +} + // now is used to get the current time. If the reconciler nowFunc is no nil this will be used instead of time.Now(). // This is only here so that tests can modify the time to check time based assertions. func (r *ReconcileMachine) now() time.Time { diff --git a/pkg/controller/machineset/controller.go b/pkg/controller/machineset/controller.go index ed825eb340..8380a6166d 100644 --- a/pkg/controller/machineset/controller.go +++ b/pkg/controller/machineset/controller.go @@ -172,7 +172,7 @@ func (r *ReconcileMachineSet) Reconcile(ctx context.Context, request reconcile.R func (r *ReconcileMachineSet) reconcile(ctx context.Context, machineSet *machinev1beta1.MachineSet) (reconcile.Result, error) { klog.V(4).Infof("Reconcile machineset %v", machineSet.Name) - if errList := machineSet.Validate(); len(errList) > 0 { + if errList := validateMachineset(machineSet); len(errList) > 0 { err := fmt.Errorf("%q machineset validation failed: %v", machineSet.Name, errList.ToAggregate().Error()) klog.Error(err) return reconcile.Result{}, err @@ -432,3 +432,25 @@ func (r *ReconcileMachineSet) waitForMachineDeletion(machineList []*machinev1bet } return nil } + +func validateMachineset(m *machinev1.MachineSet) field.ErrorList { + errors := field.ErrorList{} + + // validate spec.selector and spec.template.labels + fldPath := field.NewPath("spec") + errors = append(errors, metav1validation.ValidateLabelSelector(&m.Spec.Selector, fldPath.Child("selector"))...) + if len(m.Spec.Selector.MatchLabels)+len(m.Spec.Selector.MatchExpressions) == 0 { + errors = append(errors, field.Invalid(fldPath.Child("selector"), m.Spec.Selector, "empty selector is not valid for MachineSet.")) + } + selector, err := metav1.LabelSelectorAsSelector(&m.Spec.Selector) + if err != nil { + errors = append(errors, field.Invalid(fldPath.Child("selector"), m.Spec.Selector, "invalid label selector.")) + } else { + labels := labels.Set(m.Spec.Template.Labels) + if !selector.Matches(labels) { + errors = append(errors, field.Invalid(fldPath.Child("template", "metadata", "labels"), m.Spec.Template.Labels, "`selector` does not match template `labels`")) + } + } + + return errors +} From a87957912fc29d055ab6f8d7bbb47220659c94a3 Mon Sep 17 00:00:00 2001 From: Alexander Demichev Date: Tue, 26 Oct 2021 19:56:24 +0200 Subject: [PATCH 05/10] Refactor conditions package --- pkg/util/conditions/getter.go | 20 +++- pkg/util/conditions/getter_test.go | 24 ++--- pkg/util/conditions/matcher.go | 12 +-- pkg/util/conditions/matcher_test.go | 147 ++++++++++++++-------------- pkg/util/conditions/setter.go | 49 ++++++---- pkg/util/conditions/setter_test.go | 25 ++--- pkg/util/conditions/wrap.go | 33 +++++++ 7 files changed, 186 insertions(+), 124 deletions(-) create mode 100644 pkg/util/conditions/wrap.go diff --git a/pkg/util/conditions/getter.go b/pkg/util/conditions/getter.go index 5899476a75..72864ec69a 100644 --- a/pkg/util/conditions/getter.go +++ b/pkg/util/conditions/getter.go @@ -17,7 +17,7 @@ limitations under the License. package conditions import ( - mapiv1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" ) @@ -29,13 +29,14 @@ type Getter interface { metav1.Object // GetConditions returns the list of conditions for a cluster API object. - GetConditions() mapiv1.Conditions + GetConditions() machinev1.Conditions } // Get returns the condition with the given type, if the condition does not exists, // it returns nil. -func Get(from Getter, t mapiv1.ConditionType) *mapiv1.Condition { - conditions := from.GetConditions() +func Get(from interface{}, t machinev1.ConditionType) *machinev1.Condition { + obj := getGetterObject(from) + conditions := obj.GetConditions() if conditions == nil { return nil } @@ -47,3 +48,14 @@ func Get(from Getter, t mapiv1.ConditionType) *mapiv1.Condition { } return nil } + +func getGetterObject(from interface{}) Getter { + switch obj := from.(type) { + case machinev1.Machine: + return &MachineWrapper{&obj} + case machinev1.MachineHealthCheck: + return &MachineHealthCheckWrapper{&obj} + default: + panic("type is not supported as conditions getter") + } +} diff --git a/pkg/util/conditions/getter_test.go b/pkg/util/conditions/getter_test.go index 08a36d6321..ebd129da72 100644 --- a/pkg/util/conditions/getter_test.go +++ b/pkg/util/conditions/getter_test.go @@ -23,30 +23,30 @@ import ( . "github.com/onsi/gomega" "github.com/onsi/gomega/format" "github.com/onsi/gomega/types" - mapiv1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" ) var ( - nil1 *mapiv1.Condition + nil1 *machinev1.Condition true1 = TrueCondition("true1") unknown1 = UnknownCondition("unknown1", "reason unknown1", "message unknown1") - falseInfo1 = FalseCondition("falseInfo1", "reason falseInfo1", mapiv1.ConditionSeverityInfo, "message falseInfo1") - falseWarning1 = FalseCondition("falseWarning1", "reason falseWarning1", mapiv1.ConditionSeverityWarning, "message falseWarning1") - falseError1 = FalseCondition("falseError1", "reason falseError1", mapiv1.ConditionSeverityError, "message falseError1") + falseInfo1 = FalseCondition("falseInfo1", "reason falseInfo1", machinev1.ConditionSeverityInfo, "message falseInfo1") + falseWarning1 = FalseCondition("falseWarning1", "reason falseWarning1", machinev1.ConditionSeverityWarning, "message falseWarning1") + falseError1 = FalseCondition("falseError1", "reason falseError1", machinev1.ConditionSeverityError, "message falseError1") ) func TestGet(t *testing.T) { g := NewWithT(t) - mhc := &mapiv1.MachineHealthCheck{} + mhc := &machinev1.MachineHealthCheck{} g.Expect(Get(mhc, "conditionBaz")).To(BeNil()) - mhc.SetConditions(conditionList(TrueCondition("conditionBaz"))) + mhc.Status.Conditions = conditionList(TrueCondition("conditionBaz")) g.Expect(Get(mhc, "conditionBaz")).To(haveSameStateOf(TrueCondition("conditionBaz"))) } -func conditionList(conditions ...*mapiv1.Condition) mapiv1.Conditions { - cs := mapiv1.Conditions{} +func conditionList(conditions ...*machinev1.Condition) machinev1.Conditions { + cs := machinev1.Conditions{} for _, x := range conditions { if x != nil { cs = append(cs, *x) @@ -55,18 +55,18 @@ func conditionList(conditions ...*mapiv1.Condition) mapiv1.Conditions { return cs } -func haveSameStateOf(expected *mapiv1.Condition) types.GomegaMatcher { +func haveSameStateOf(expected *machinev1.Condition) types.GomegaMatcher { return &ConditionMatcher{ Expected: expected, } } type ConditionMatcher struct { - Expected *mapiv1.Condition + Expected *machinev1.Condition } func (matcher *ConditionMatcher) Match(actual interface{}) (success bool, err error) { - actualCondition, ok := actual.(*mapiv1.Condition) + actualCondition, ok := actual.(*machinev1.Condition) if !ok { return false, errors.New("Value should be a condition") } diff --git a/pkg/util/conditions/matcher.go b/pkg/util/conditions/matcher.go index 74a9aa31aa..924a03ddc5 100644 --- a/pkg/util/conditions/matcher.go +++ b/pkg/util/conditions/matcher.go @@ -21,18 +21,18 @@ import ( . "github.com/onsi/gomega" "github.com/onsi/gomega/types" - mapiv1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" ) // MatchConditions returns a custom matcher to check equality of mapiv1.Conditions -func MatchConditions(expected mapiv1.Conditions) types.GomegaMatcher { +func MatchConditions(expected machinev1.Conditions) types.GomegaMatcher { return &matchConditions{ expected: expected, } } type matchConditions struct { - expected mapiv1.Conditions + expected machinev1.Conditions } func (m matchConditions) Match(actual interface{}) (success bool, err error) { @@ -53,18 +53,18 @@ func (m matchConditions) NegatedFailureMessage(actual interface{}) (message stri } // MatchCondition returns a custom matcher to check equality of mapiv1.Condition -func MatchCondition(expected mapiv1.Condition) types.GomegaMatcher { +func MatchCondition(expected machinev1.Condition) types.GomegaMatcher { return &matchCondition{ expected: expected, } } type matchCondition struct { - expected mapiv1.Condition + expected machinev1.Condition } func (m matchCondition) Match(actual interface{}) (success bool, err error) { - actualCondition, ok := actual.(mapiv1.Condition) + actualCondition, ok := actual.(machinev1.Condition) if !ok { return false, fmt.Errorf("actual should be of type Condition") } diff --git a/pkg/util/conditions/matcher_test.go b/pkg/util/conditions/matcher_test.go index 73c8c9f727..2a8466adac 100644 --- a/pkg/util/conditions/matcher_test.go +++ b/pkg/util/conditions/matcher_test.go @@ -20,7 +20,8 @@ import ( "testing" . "github.com/onsi/gomega" - mapiv1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -29,32 +30,32 @@ func TestMatchConditions(t *testing.T) { testCases := []struct { name string actual interface{} - expected mapiv1.Conditions + expected machinev1.Conditions expectMatch bool }{ { name: "with an empty conditions", - actual: mapiv1.Conditions{}, - expected: mapiv1.Conditions{}, + actual: machinev1.Conditions{}, + expected: machinev1.Conditions{}, expectMatch: true, }, { name: "with matching conditions", - actual: mapiv1.Conditions{ + actual: machinev1.Conditions{ { - Type: mapiv1.ConditionType("type"), + Type: machinev1.ConditionType("type"), Status: corev1.ConditionTrue, - Severity: mapiv1.ConditionSeverityNone, + Severity: machinev1.ConditionSeverityNone, LastTransitionTime: metav1.Now(), Reason: "reason", Message: "message", }, }, - expected: mapiv1.Conditions{ + expected: machinev1.Conditions{ { - Type: mapiv1.ConditionType("type"), + Type: machinev1.ConditionType("type"), Status: corev1.ConditionTrue, - Severity: mapiv1.ConditionSeverityNone, + Severity: machinev1.ConditionSeverityNone, LastTransitionTime: metav1.Now(), Reason: "reason", Message: "message", @@ -64,37 +65,37 @@ func TestMatchConditions(t *testing.T) { }, { name: "with non-matching conditions", - actual: mapiv1.Conditions{ + actual: machinev1.Conditions{ { - Type: mapiv1.ConditionType("type"), + Type: machinev1.ConditionType("type"), Status: corev1.ConditionTrue, - Severity: mapiv1.ConditionSeverityNone, + Severity: machinev1.ConditionSeverityNone, LastTransitionTime: metav1.Now(), Reason: "reason", Message: "message", }, { - Type: mapiv1.ConditionType("type"), + Type: machinev1.ConditionType("type"), Status: corev1.ConditionTrue, - Severity: mapiv1.ConditionSeverityNone, + Severity: machinev1.ConditionSeverityNone, LastTransitionTime: metav1.Now(), Reason: "reason", Message: "message", }, }, - expected: mapiv1.Conditions{ + expected: machinev1.Conditions{ { - Type: mapiv1.ConditionType("type"), + Type: machinev1.ConditionType("type"), Status: corev1.ConditionTrue, - Severity: mapiv1.ConditionSeverityNone, + Severity: machinev1.ConditionSeverityNone, LastTransitionTime: metav1.Now(), Reason: "reason", Message: "message", }, { - Type: mapiv1.ConditionType("different"), + Type: machinev1.ConditionType("different"), Status: corev1.ConditionTrue, - Severity: mapiv1.ConditionSeverityNone, + Severity: machinev1.ConditionSeverityNone, LastTransitionTime: metav1.Now(), Reason: "different", Message: "different", @@ -104,29 +105,29 @@ func TestMatchConditions(t *testing.T) { }, { name: "with a different number of conditions", - actual: mapiv1.Conditions{ + actual: machinev1.Conditions{ { - Type: mapiv1.ConditionType("type"), + Type: machinev1.ConditionType("type"), Status: corev1.ConditionTrue, - Severity: mapiv1.ConditionSeverityNone, + Severity: machinev1.ConditionSeverityNone, LastTransitionTime: metav1.Now(), Reason: "reason", Message: "message", }, { - Type: mapiv1.ConditionType("type"), + Type: machinev1.ConditionType("type"), Status: corev1.ConditionTrue, - Severity: mapiv1.ConditionSeverityNone, + Severity: machinev1.ConditionSeverityNone, LastTransitionTime: metav1.Now(), Reason: "reason", Message: "message", }, }, - expected: mapiv1.Conditions{ + expected: machinev1.Conditions{ { - Type: mapiv1.ConditionType("type"), + Type: machinev1.ConditionType("type"), Status: corev1.ConditionTrue, - Severity: mapiv1.ConditionSeverityNone, + Severity: machinev1.ConditionSeverityNone, LastTransitionTime: metav1.Now(), Reason: "reason", Message: "message", @@ -152,29 +153,29 @@ func TestMatchCondition(t *testing.T) { testCases := []struct { name string actual interface{} - expected mapiv1.Condition + expected machinev1.Condition expectMatch bool }{ { name: "with an empty condition", - actual: mapiv1.Condition{}, - expected: mapiv1.Condition{}, + actual: machinev1.Condition{}, + expected: machinev1.Condition{}, expectMatch: true, }, { name: "with a matching condition", - actual: mapiv1.Condition{ - Type: mapiv1.ConditionType("type"), + actual: machinev1.Condition{ + Type: machinev1.ConditionType("type"), Status: corev1.ConditionTrue, - Severity: mapiv1.ConditionSeverityNone, + Severity: machinev1.ConditionSeverityNone, LastTransitionTime: metav1.Now(), Reason: "reason", Message: "message", }, - expected: mapiv1.Condition{ - Type: mapiv1.ConditionType("type"), + expected: machinev1.Condition{ + Type: machinev1.ConditionType("type"), Status: corev1.ConditionTrue, - Severity: mapiv1.ConditionSeverityNone, + Severity: machinev1.ConditionSeverityNone, LastTransitionTime: metav1.Now(), Reason: "reason", Message: "message", @@ -183,18 +184,18 @@ func TestMatchCondition(t *testing.T) { }, { name: "with a different time", - actual: mapiv1.Condition{ - Type: mapiv1.ConditionType("type"), + actual: machinev1.Condition{ + Type: machinev1.ConditionType("type"), Status: corev1.ConditionTrue, - Severity: mapiv1.ConditionSeverityNone, + Severity: machinev1.ConditionSeverityNone, LastTransitionTime: metav1.Now(), Reason: "reason", Message: "message", }, - expected: mapiv1.Condition{ - Type: mapiv1.ConditionType("type"), + expected: machinev1.Condition{ + Type: machinev1.ConditionType("type"), Status: corev1.ConditionTrue, - Severity: mapiv1.ConditionSeverityNone, + Severity: machinev1.ConditionSeverityNone, LastTransitionTime: metav1.Time{}, Reason: "reason", Message: "message", @@ -203,18 +204,18 @@ func TestMatchCondition(t *testing.T) { }, { name: "with a different type", - actual: mapiv1.Condition{ - Type: mapiv1.ConditionType("type"), + actual: machinev1.Condition{ + Type: machinev1.ConditionType("type"), Status: corev1.ConditionTrue, - Severity: mapiv1.ConditionSeverityNone, + Severity: machinev1.ConditionSeverityNone, LastTransitionTime: metav1.Now(), Reason: "reason", Message: "message", }, - expected: mapiv1.Condition{ - Type: mapiv1.ConditionType("different"), + expected: machinev1.Condition{ + Type: machinev1.ConditionType("different"), Status: corev1.ConditionTrue, - Severity: mapiv1.ConditionSeverityNone, + Severity: machinev1.ConditionSeverityNone, LastTransitionTime: metav1.Now(), Reason: "reason", Message: "message", @@ -223,18 +224,18 @@ func TestMatchCondition(t *testing.T) { }, { name: "with a different status", - actual: mapiv1.Condition{ - Type: mapiv1.ConditionType("type"), + actual: machinev1.Condition{ + Type: machinev1.ConditionType("type"), Status: corev1.ConditionTrue, - Severity: mapiv1.ConditionSeverityNone, + Severity: machinev1.ConditionSeverityNone, LastTransitionTime: metav1.Now(), Reason: "reason", Message: "message", }, - expected: mapiv1.Condition{ - Type: mapiv1.ConditionType("type"), + expected: machinev1.Condition{ + Type: machinev1.ConditionType("type"), Status: corev1.ConditionFalse, - Severity: mapiv1.ConditionSeverityNone, + Severity: machinev1.ConditionSeverityNone, LastTransitionTime: metav1.Now(), Reason: "reason", Message: "message", @@ -243,18 +244,18 @@ func TestMatchCondition(t *testing.T) { }, { name: "with a different severity", - actual: mapiv1.Condition{ - Type: mapiv1.ConditionType("type"), + actual: machinev1.Condition{ + Type: machinev1.ConditionType("type"), Status: corev1.ConditionTrue, - Severity: mapiv1.ConditionSeverityNone, + Severity: machinev1.ConditionSeverityNone, LastTransitionTime: metav1.Now(), Reason: "reason", Message: "message", }, - expected: mapiv1.Condition{ - Type: mapiv1.ConditionType("type"), + expected: machinev1.Condition{ + Type: machinev1.ConditionType("type"), Status: corev1.ConditionTrue, - Severity: mapiv1.ConditionSeverityInfo, + Severity: machinev1.ConditionSeverityInfo, LastTransitionTime: metav1.Now(), Reason: "reason", Message: "message", @@ -263,18 +264,18 @@ func TestMatchCondition(t *testing.T) { }, { name: "with a different reason", - actual: mapiv1.Condition{ - Type: mapiv1.ConditionType("type"), + actual: machinev1.Condition{ + Type: machinev1.ConditionType("type"), Status: corev1.ConditionTrue, - Severity: mapiv1.ConditionSeverityNone, + Severity: machinev1.ConditionSeverityNone, LastTransitionTime: metav1.Now(), Reason: "reason", Message: "message", }, - expected: mapiv1.Condition{ - Type: mapiv1.ConditionType("type"), + expected: machinev1.Condition{ + Type: machinev1.ConditionType("type"), Status: corev1.ConditionTrue, - Severity: mapiv1.ConditionSeverityNone, + Severity: machinev1.ConditionSeverityNone, LastTransitionTime: metav1.Now(), Reason: "different", Message: "message", @@ -283,18 +284,18 @@ func TestMatchCondition(t *testing.T) { }, { name: "with a different message", - actual: mapiv1.Condition{ - Type: mapiv1.ConditionType("type"), + actual: machinev1.Condition{ + Type: machinev1.ConditionType("type"), Status: corev1.ConditionTrue, - Severity: mapiv1.ConditionSeverityNone, + Severity: machinev1.ConditionSeverityNone, LastTransitionTime: metav1.Now(), Reason: "reason", Message: "message", }, - expected: mapiv1.Condition{ - Type: mapiv1.ConditionType("type"), + expected: machinev1.Condition{ + Type: machinev1.ConditionType("type"), Status: corev1.ConditionTrue, - Severity: mapiv1.ConditionSeverityNone, + Severity: machinev1.ConditionSeverityNone, LastTransitionTime: metav1.Now(), Reason: "reason", Message: "different", diff --git a/pkg/util/conditions/setter.go b/pkg/util/conditions/setter.go index 26e4c7db6a..078d123d8d 100644 --- a/pkg/util/conditions/setter.go +++ b/pkg/util/conditions/setter.go @@ -21,7 +21,7 @@ import ( "sort" "time" - mapiv1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -30,21 +30,23 @@ import ( // use the conditions package for setting conditions. type Setter interface { Getter - SetConditions(mapiv1.Conditions) + SetConditions(machinev1.Conditions) } // Set sets the given condition. // // NOTE: If a condition already exists, the LastTransitionTime is updated only if a change is detected // in any of the following fields: Status, Reason, Severity and Message. -func Set(to Setter, condition *mapiv1.Condition) { +func Set(to interface{}, condition *machinev1.Condition) { if to == nil || condition == nil { return } + obj := getSetterObject(to) + // Check if the new conditions already exists, and change it only if there is a status // transition (otherwise we should preserve the current last transition time)- - conditions := to.GetConditions() + conditions := obj.GetConditions() exists := false for i := range conditions { existingCondition := conditions[i] @@ -73,20 +75,20 @@ func Set(to Setter, condition *mapiv1.Condition) { return lexicographicLess(&conditions[i], &conditions[j]) }) - to.SetConditions(conditions) + obj.SetConditions(conditions) } // TrueCondition returns a condition with Status=True and the given type. -func TrueCondition(t mapiv1.ConditionType) *mapiv1.Condition { - return &mapiv1.Condition{ +func TrueCondition(t machinev1.ConditionType) *machinev1.Condition { + return &machinev1.Condition{ Type: t, Status: corev1.ConditionTrue, } } // FalseCondition returns a condition with Status=False and the given type. -func FalseCondition(t mapiv1.ConditionType, reason string, severity mapiv1.ConditionSeverity, messageFormat string, messageArgs ...interface{}) *mapiv1.Condition { - return &mapiv1.Condition{ +func FalseCondition(t machinev1.ConditionType, reason string, severity machinev1.ConditionSeverity, messageFormat string, messageArgs ...interface{}) *machinev1.Condition { + return &machinev1.Condition{ Type: t, Status: corev1.ConditionFalse, Reason: reason, @@ -96,8 +98,8 @@ func FalseCondition(t mapiv1.ConditionType, reason string, severity mapiv1.Condi } // UnknownCondition returns a condition with Status=Unknown and the given type. -func UnknownCondition(t mapiv1.ConditionType, reason string, messageFormat string, messageArgs ...interface{}) *mapiv1.Condition { - return &mapiv1.Condition{ +func UnknownCondition(t machinev1.ConditionType, reason string, messageFormat string, messageArgs ...interface{}) *machinev1.Condition { + return &machinev1.Condition{ Type: t, Status: corev1.ConditionUnknown, Reason: reason, @@ -106,24 +108,37 @@ func UnknownCondition(t mapiv1.ConditionType, reason string, messageFormat strin } // MarkTrue sets Status=True for the condition with the given type. -func MarkTrue(to Setter, t mapiv1.ConditionType) { - Set(to, TrueCondition(t)) +func MarkTrue(to interface{}, t machinev1.ConditionType) { + obj := getSetterObject(to) + Set(obj, TrueCondition(t)) } // MarkFalse sets Status=False for the condition with the given type. -func MarkFalse(to Setter, t mapiv1.ConditionType, reason string, severity mapiv1.ConditionSeverity, messageFormat string, messageArgs ...interface{}) { - Set(to, FalseCondition(t, reason, severity, messageFormat, messageArgs...)) +func MarkFalse(to interface{}, t machinev1.ConditionType, reason string, severity machinev1.ConditionSeverity, messageFormat string, messageArgs ...interface{}) { + obj := getSetterObject(to) + Set(obj, FalseCondition(t, reason, severity, messageFormat, messageArgs...)) +} + +func getSetterObject(from interface{}) Setter { + switch obj := from.(type) { + case machinev1.Machine: + return &MachineWrapper{&obj} + case machinev1.MachineHealthCheck: + return &MachineHealthCheckWrapper{&obj} + default: + panic("type is not supported as conditions getter") + } } // lexicographicLess returns true if a condition is less than another with regards to the // to order of conditions designed for convenience of the consumer, i.e. kubectl. -func lexicographicLess(i, j *mapiv1.Condition) bool { +func lexicographicLess(i, j *machinev1.Condition) bool { return i.Type < j.Type } // hasSameState returns true if a condition has the same state of another; state is defined // by the union of following fields: Type, Status, Reason, Severity and Message (it excludes LastTransitionTime). -func hasSameState(i, j *mapiv1.Condition) bool { +func hasSameState(i, j *machinev1.Condition) bool { return i.Type == j.Type && i.Status == j.Status && i.Reason == j.Reason && diff --git a/pkg/util/conditions/setter_test.go b/pkg/util/conditions/setter_test.go index 07e83a69be..127b106cd7 100644 --- a/pkg/util/conditions/setter_test.go +++ b/pkg/util/conditions/setter_test.go @@ -24,7 +24,7 @@ import ( . "github.com/onsi/gomega" "github.com/onsi/gomega/format" "github.com/onsi/gomega/types" - mapiv1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -51,7 +51,7 @@ func TestHasSameState(t *testing.T) { g.Expect(hasSameState(falseInfo1, falseInfo2)).To(BeFalse()) falseInfo2 = falseInfo1.DeepCopy() - falseInfo2.Severity = mapiv1.ConditionSeverityWarning + falseInfo2.Severity = machinev1.ConditionSeverityWarning g.Expect(hasSameState(falseInfo1, falseInfo2)).To(BeFalse()) falseInfo2 = falseInfo1.DeepCopy() @@ -83,8 +83,8 @@ func TestSet(t *testing.T) { tests := []struct { name string to Setter - condition *mapiv1.Condition - want mapiv1.Conditions + condition *machinev1.Condition + want machinev1.Conditions }{ { name: "Set adds a condition", @@ -126,15 +126,15 @@ func TestSet(t *testing.T) { func TestSetLastTransitionTime(t *testing.T) { x := metav1.Date(2012, time.January, 1, 12, 15, 30, 5e8, time.UTC) - foo := FalseCondition("foo", "reason foo", mapiv1.ConditionSeverityInfo, "message foo") - fooWithLastTransitionTime := FalseCondition("foo", "reason foo", mapiv1.ConditionSeverityInfo, "message foo") + foo := FalseCondition("foo", "reason foo", machinev1.ConditionSeverityInfo, "message foo") + fooWithLastTransitionTime := FalseCondition("foo", "reason foo", machinev1.ConditionSeverityInfo, "message foo") fooWithLastTransitionTime.LastTransitionTime = x fooWithAnotherState := TrueCondition("foo") tests := []struct { name string to Setter - new *mapiv1.Condition + new *machinev1.Condition LastTransitionTimeCheck func(*WithT, metav1.Time) }{ { @@ -182,24 +182,25 @@ func TestSetLastTransitionTime(t *testing.T) { } } -func setterWithConditions(conditions ...*mapiv1.Condition) Setter { - obj := &mapiv1.MachineHealthCheck{} +func setterWithConditions(conditions ...*machinev1.Condition) Setter { + obj := &MachineHealthCheckWrapper{&machinev1.MachineHealthCheck{}} + obj.SetConditions(conditionList(conditions...)) return obj } -func haveSameConditionsOf(expected mapiv1.Conditions) types.GomegaMatcher { +func haveSameConditionsOf(expected machinev1.Conditions) types.GomegaMatcher { return &ConditionsMatcher{ Expected: expected, } } type ConditionsMatcher struct { - Expected mapiv1.Conditions + Expected machinev1.Conditions } func (matcher *ConditionsMatcher) Match(actual interface{}) (success bool, err error) { - actualConditions, ok := actual.(mapiv1.Conditions) + actualConditions, ok := actual.(machinev1.Conditions) if !ok { return false, errors.New("Value should be a conditions list") } diff --git a/pkg/util/conditions/wrap.go b/pkg/util/conditions/wrap.go new file mode 100644 index 0000000000..41d8d9fe13 --- /dev/null +++ b/pkg/util/conditions/wrap.go @@ -0,0 +1,33 @@ +package conditions + +import ( + machinev1 "github.com/openshift/api/machine/v1beta1" +) + +type MachineWrapper struct { + *machinev1.Machine +} + +func (m *MachineWrapper) GetConditions() machinev1.Conditions { + return m.Status.Conditions +} + +func (m *MachineWrapper) SetConditions(conditions machinev1.Conditions) { + m.Status.Conditions = conditions +} + +type MachineHealthCheckWrapper struct { + *machinev1.MachineHealthCheck +} + +func (m *MachineHealthCheckWrapper) GetConditions() machinev1.Conditions { + return m.Status.Conditions +} + +func (m *MachineHealthCheckWrapper) SetConditions(conditions machinev1.Conditions) { + m.Status.Conditions = conditions +} + +func WrapMachineHealthCheck(mhc *machinev1.MachineHealthCheck) *MachineHealthCheckWrapper { + return &MachineHealthCheckWrapper{MachineHealthCheck: mhc} +} From d4a79a076f7fc53f95e0c8e11efa9ec59a602dd2 Mon Sep 17 00:00:00 2001 From: Alexander Demichev Date: Tue, 26 Oct 2021 19:56:49 +0200 Subject: [PATCH 06/10] Remove api package --- cmd/machine-api-operator/client_builder.go | 2 +- .../controller_context.go | 2 +- cmd/machine-healthcheck/main.go | 5 +- cmd/machineset/main.go | 21 +- cmd/nodelink-controller/main.go | 4 +- cmd/vsphere/main.go | 7 +- pkg/apis/machine/register.go | 8 - pkg/apis/machine/v1beta1/common_types.go | 120 - pkg/apis/machine/v1beta1/condition_consts.go | 57 - pkg/apis/machine/v1beta1/condition_types.go | 81 - pkg/apis/machine/v1beta1/consts.go | 139 - pkg/apis/machine/v1beta1/doc.go | 4 - pkg/apis/machine/v1beta1/machine_types.go | 222 -- .../machine/v1beta1/machine_types_test.go | 127 - pkg/apis/machine/v1beta1/machine_webhook.go | 1206 --------- .../machine/v1beta1/machine_webhook_test.go | 2403 ----------------- .../v1beta1/machinehealthcheck_types.go | 134 - pkg/apis/machine/v1beta1/machineset_types.go | 210 -- .../machine/v1beta1/machineset_types_test.go | 138 - .../machine/v1beta1/machineset_webhook.go | 150 - .../v1beta1/machineset_webhook_test.go | 829 ------ pkg/apis/machine/v1beta1/register.go | 45 - .../machine/v1beta1/v1beta1_suite_test.go | 221 -- .../machine/v1beta1/zz_generated.deepcopy.go | 571 ---- .../addtoscheme_vsphereprovider_v1beta1.go | 10 - pkg/apis/vsphereprovider/apis.go | 19 - pkg/apis/vsphereprovider/v1beta1/doc.go | 7 - pkg/apis/vsphereprovider/v1beta1/register.go | 90 - .../v1beta1/vsphereproviderconfig_types.go | 128 - .../v1beta1/vsphereproviderstatus_types.go | 83 - .../v1beta1/zz_generated.deepcopy.go | 176 -- 31 files changed, 21 insertions(+), 7198 deletions(-) delete mode 100644 pkg/apis/machine/register.go delete mode 100644 pkg/apis/machine/v1beta1/common_types.go delete mode 100644 pkg/apis/machine/v1beta1/condition_consts.go delete mode 100644 pkg/apis/machine/v1beta1/condition_types.go delete mode 100644 pkg/apis/machine/v1beta1/consts.go delete mode 100644 pkg/apis/machine/v1beta1/doc.go delete mode 100644 pkg/apis/machine/v1beta1/machine_types.go delete mode 100644 pkg/apis/machine/v1beta1/machine_types_test.go delete mode 100644 pkg/apis/machine/v1beta1/machine_webhook.go delete mode 100644 pkg/apis/machine/v1beta1/machine_webhook_test.go delete mode 100644 pkg/apis/machine/v1beta1/machinehealthcheck_types.go delete mode 100644 pkg/apis/machine/v1beta1/machineset_types.go delete mode 100644 pkg/apis/machine/v1beta1/machineset_types_test.go delete mode 100644 pkg/apis/machine/v1beta1/machineset_webhook.go delete mode 100644 pkg/apis/machine/v1beta1/machineset_webhook_test.go delete mode 100644 pkg/apis/machine/v1beta1/register.go delete mode 100644 pkg/apis/machine/v1beta1/v1beta1_suite_test.go delete mode 100644 pkg/apis/machine/v1beta1/zz_generated.deepcopy.go delete mode 100644 pkg/apis/vsphereprovider/addtoscheme_vsphereprovider_v1beta1.go delete mode 100644 pkg/apis/vsphereprovider/apis.go delete mode 100644 pkg/apis/vsphereprovider/v1beta1/doc.go delete mode 100644 pkg/apis/vsphereprovider/v1beta1/register.go delete mode 100644 pkg/apis/vsphereprovider/v1beta1/vsphereproviderconfig_types.go delete mode 100644 pkg/apis/vsphereprovider/v1beta1/vsphereproviderstatus_types.go delete mode 100644 pkg/apis/vsphereprovider/v1beta1/zz_generated.deepcopy.go diff --git a/cmd/machine-api-operator/client_builder.go b/cmd/machine-api-operator/client_builder.go index 7ffb931292..25b676ec89 100644 --- a/cmd/machine-api-operator/client_builder.go +++ b/cmd/machine-api-operator/client_builder.go @@ -4,7 +4,7 @@ import ( "errors" osclientset "github.com/openshift/client-go/config/clientset/versioned" - mapiclientset "github.com/openshift/machine-api-operator/pkg/generated/clientset/versioned" + mapiclientset "github.com/openshift/client-go/machine/clientset/versioned" "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" diff --git a/cmd/machine-api-operator/controller_context.go b/cmd/machine-api-operator/controller_context.go index d4b205c4c3..207058bd35 100644 --- a/cmd/machine-api-operator/controller_context.go +++ b/cmd/machine-api-operator/controller_context.go @@ -4,7 +4,7 @@ import ( "time" configinformersv1 "github.com/openshift/client-go/config/informers/externalversions" - machineinformersv1beta1 "github.com/openshift/machine-api-operator/pkg/generated/informers/externalversions" + machineinformersv1beta1 "github.com/openshift/client-go/machine/informers/externalversions" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/informers" diff --git a/cmd/machine-healthcheck/main.go b/cmd/machine-healthcheck/main.go index b8a32c2200..1f9fb002a7 100644 --- a/cmd/machine-healthcheck/main.go +++ b/cmd/machine-healthcheck/main.go @@ -8,7 +8,8 @@ import ( "github.com/openshift/machine-api-operator/pkg/metrics" "github.com/openshift/machine-api-operator/pkg/util" - mapiv1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" + "github.com/openshift/machine-api-operator/pkg/controller" sdkVersion "github.com/operator-framework/operator-sdk/version" _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" @@ -96,7 +97,7 @@ func main() { klog.Infof("Registering Components.") // Setup Scheme for all resources - if err := mapiv1.AddToScheme(mgr.GetScheme()); err != nil { + if err := machinev1.AddToScheme(mgr.GetScheme()); err != nil { klog.Fatal(err) } diff --git a/cmd/machineset/main.go b/cmd/machineset/main.go index 471a256f5a..cb4d2f8a9f 100644 --- a/cmd/machineset/main.go +++ b/cmd/machineset/main.go @@ -21,11 +21,12 @@ import ( "log" "time" - "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" "github.com/openshift/machine-api-operator/pkg/controller" "github.com/openshift/machine-api-operator/pkg/controller/machineset" "github.com/openshift/machine-api-operator/pkg/metrics" "github.com/openshift/machine-api-operator/pkg/util" + mapiwebhooks "github.com/openshift/machine-api-operator/pkg/webhooks" _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" "k8s.io/klog/v2" "sigs.k8s.io/controller-runtime/pkg/client/config" @@ -113,22 +114,22 @@ func main() { } // Enable defaulting and validating webhooks - machineDefaulter, err := v1beta1.NewMachineDefaulter() + machineDefaulter, err := mapiwebhooks.NewMachineDefaulter() if err != nil { log.Fatal(err) } - machineValidator, err := v1beta1.NewMachineValidator(mgr.GetClient()) + machineValidator, err := mapiwebhooks.NewMachineValidator(mgr.GetClient()) if err != nil { log.Fatal(err) } - machineSetDefaulter, err := v1beta1.NewMachineSetDefaulter() + machineSetDefaulter, err := mapiwebhooks.NewMachineSetDefaulter() if err != nil { log.Fatal(err) } - machineSetValidator, err := v1beta1.NewMachineSetValidator(mgr.GetClient()) + machineSetValidator, err := mapiwebhooks.NewMachineSetValidator(mgr.GetClient()) if err != nil { log.Fatal(err) } @@ -136,16 +137,16 @@ func main() { if *webhookEnabled { mgr.GetWebhookServer().Port = *webhookPort mgr.GetWebhookServer().CertDir = *webhookCertdir - mgr.GetWebhookServer().Register(v1beta1.DefaultMachineMutatingHookPath, &webhook.Admission{Handler: machineDefaulter}) - mgr.GetWebhookServer().Register(v1beta1.DefaultMachineValidatingHookPath, &webhook.Admission{Handler: machineValidator}) - mgr.GetWebhookServer().Register(v1beta1.DefaultMachineSetMutatingHookPath, &webhook.Admission{Handler: machineSetDefaulter}) - mgr.GetWebhookServer().Register(v1beta1.DefaultMachineSetValidatingHookPath, &webhook.Admission{Handler: machineSetValidator}) + mgr.GetWebhookServer().Register(mapiwebhooks.DefaultMachineMutatingHookPath, &webhook.Admission{Handler: machineDefaulter}) + mgr.GetWebhookServer().Register(mapiwebhooks.DefaultMachineValidatingHookPath, &webhook.Admission{Handler: machineValidator}) + mgr.GetWebhookServer().Register(mapiwebhooks.DefaultMachineSetMutatingHookPath, &webhook.Admission{Handler: machineSetDefaulter}) + mgr.GetWebhookServer().Register(mapiwebhooks.DefaultMachineSetValidatingHookPath, &webhook.Admission{Handler: machineSetValidator}) } log.Printf("Registering Components.") // Setup Scheme for all resources - if err := v1beta1.AddToScheme(mgr.GetScheme()); err != nil { + if err := machinev1.AddToScheme(mgr.GetScheme()); err != nil { log.Fatal(err) } diff --git a/cmd/nodelink-controller/main.go b/cmd/nodelink-controller/main.go index dec2a78a08..9d04442398 100644 --- a/cmd/nodelink-controller/main.go +++ b/cmd/nodelink-controller/main.go @@ -4,7 +4,7 @@ import ( "flag" "runtime" - mapiv1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" "github.com/openshift/machine-api-operator/pkg/controller" "github.com/openshift/machine-api-operator/pkg/controller/nodelink" "github.com/openshift/machine-api-operator/pkg/util" @@ -81,7 +81,7 @@ func main() { klog.Infof("Registering Components.") // Setup Scheme for all resources - if err := mapiv1.AddToScheme(mgr.GetScheme()); err != nil { + if err := machinev1.AddToScheme(mgr.GetScheme()); err != nil { klog.Fatal(err) } diff --git a/cmd/vsphere/main.go b/cmd/vsphere/main.go index c1d668389e..19af41dfc3 100644 --- a/cmd/vsphere/main.go +++ b/cmd/vsphere/main.go @@ -7,8 +7,7 @@ import ( "time" configv1 "github.com/openshift/api/config/v1" - "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - vsphereapis "github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider" + machinev1 "github.com/openshift/api/machine/v1beta1" capimachine "github.com/openshift/machine-api-operator/pkg/controller/machine" machine "github.com/openshift/machine-api-operator/pkg/controller/vsphere" machinesetcontroller "github.com/openshift/machine-api-operator/pkg/controller/vsphere/machineset" @@ -114,11 +113,11 @@ func main() { klog.Fatal(err) } - if err := vsphereapis.AddToScheme(mgr.GetScheme()); err != nil { + if err := machinev1.AddToScheme(mgr.GetScheme()); err != nil { klog.Fatal(err) } - if err := v1beta1.AddToScheme(mgr.GetScheme()); err != nil { + if err := machinev1.AddToScheme(mgr.GetScheme()); err != nil { klog.Fatal(err) } diff --git a/pkg/apis/machine/register.go b/pkg/apis/machine/register.go deleted file mode 100644 index 1b710aafa2..0000000000 --- a/pkg/apis/machine/register.go +++ /dev/null @@ -1,8 +0,0 @@ -// Generate deepcopy for apis -//go:generate go run ../../../vendor/sigs.k8s.io/controller-tools/cmd/controller-gen paths=./... object:headerFile=../../../hack/boilerplate.go.txt,year=2019 -// Ensure generated code is goimports compliant -//go:generate goimports -w ./v1beta1/zz_generated.deepcopy.go - -package machine - -const GroupName = "machine.openshift.io" diff --git a/pkg/apis/machine/v1beta1/common_types.go b/pkg/apis/machine/v1beta1/common_types.go deleted file mode 100644 index b49141ac6d..0000000000 --- a/pkg/apis/machine/v1beta1/common_types.go +++ /dev/null @@ -1,120 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -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 v1beta1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" -) - -// ProviderSpec defines the configuration to use during node creation. -type ProviderSpec struct { - - // No more than one of the following may be specified. - - // Value is an inlined, serialized representation of the resource - // configuration. It is recommended that providers maintain their own - // versioned API types that should be serialized/deserialized from this - // field, akin to component config. - // +optional - // +kubebuilder:validation:XPreserveUnknownFields - Value *runtime.RawExtension `json:"value,omitempty"` -} - -// ObjectMeta is metadata that all persisted resources must have, which includes all objects -// users must create. This is a copy of customizable fields from metav1.ObjectMeta. -// -// ObjectMeta is embedded in `Machine.Spec`, `MachineDeployment.Template` and `MachineSet.Template`, -// which are not top-level Kubernetes objects. Given that metav1.ObjectMeta has lots of special cases -// and read-only fields which end up in the generated CRD validation, having it as a subset simplifies -// the API and some issues that can impact user experience. -// -// During the [upgrade to controller-tools@v2](https://github.com/kubernetes-sigs/cluster-api/pull/1054) -// for v1alpha2, we noticed a failure would occur running Cluster API test suite against the new CRDs, -// specifically `spec.metadata.creationTimestamp in body must be of type string: "null"`. -// The investigation showed that `controller-tools@v2` behaves differently than its previous version -// when handling types from [metav1](k8s.io/apimachinery/pkg/apis/meta/v1) package. -// -// In more details, we found that embedded (non-top level) types that embedded `metav1.ObjectMeta` -// had validation properties, including for `creationTimestamp` (metav1.Time). -// The `metav1.Time` type specifies a custom json marshaller that, when IsZero() is true, returns `null` -// which breaks validation because the field isn't marked as nullable. -// -// In future versions, controller-tools@v2 might allow overriding the type and validation for embedded -// types. When that happens, this hack should be revisited. -type ObjectMeta struct { - // Name must be unique within a namespace. Is required when creating resources, although - // some resources may allow a client to request the generation of an appropriate name - // automatically. Name is primarily intended for creation idempotence and configuration - // definition. - // Cannot be updated. - // More info: http://kubernetes.io/docs/user-guide/identifiers#names - // +optional - Name string `json:"name,omitempty"` - - // GenerateName is an optional prefix, used by the server, to generate a unique - // name ONLY IF the Name field has not been provided. - // If this field is used, the name returned to the client will be different - // than the name passed. This value will also be combined with a unique suffix. - // The provided value has the same validation rules as the Name field, - // and may be truncated by the length of the suffix required to make the value - // unique on the server. - // - // If this field is specified and the generated name exists, the server will - // NOT return a 409 - instead, it will either return 201 Created or 500 with Reason - // ServerTimeout indicating a unique name could not be found in the time allotted, and the client - // should retry (optionally after the time indicated in the Retry-After header). - // - // Applied only if Name is not specified. - // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency - // +optional - GenerateName string `json:"generateName,omitempty"` - - // Namespace defines the space within each name must be unique. An empty namespace is - // equivalent to the "default" namespace, but "default" is the canonical representation. - // Not all objects are required to be scoped to a namespace - the value of this field for - // those objects will be empty. - // - // Must be a DNS_LABEL. - // Cannot be updated. - // More info: http://kubernetes.io/docs/user-guide/namespaces - // +optional - Namespace string `json:"namespace,omitempty"` - - // Map of string keys and values that can be used to organize and categorize - // (scope and select) objects. May match selectors of replication controllers - // and services. - // More info: http://kubernetes.io/docs/user-guide/labels - // +optional - Labels map[string]string `json:"labels,omitempty"` - - // Annotations is an unstructured key value map stored with a resource that may be - // set by external tools to store and retrieve arbitrary metadata. They are not - // queryable and should be preserved when modifying objects. - // More info: http://kubernetes.io/docs/user-guide/annotations - // +optional - Annotations map[string]string `json:"annotations,omitempty"` - - // List of objects depended by this object. If ALL objects in the list have - // been deleted, this object will be garbage collected. If this object is managed by a controller, - // then an entry in this list will point to this controller, with the controller field set to true. - // There cannot be more than one managing controller. - // +optional - // +patchMergeKey=uid - // +patchStrategy=merge - OwnerReferences []metav1.OwnerReference `json:"ownerReferences,omitempty" patchStrategy:"merge" patchMergeKey:"uid"` -} diff --git a/pkg/apis/machine/v1beta1/condition_consts.go b/pkg/apis/machine/v1beta1/condition_consts.go deleted file mode 100644 index 9b579de3fb..0000000000 --- a/pkg/apis/machine/v1beta1/condition_consts.go +++ /dev/null @@ -1,57 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -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 v1beta1 - -// Conditions and condition Reasons for the MachineHealthCheck object -const ( - // RemediationAllowedCondition is set on MachineHealthChecks to show the status of whether the MachineHealthCheck is - // allowed to remediate any Machines or whether it is blocked from remediating any further. - RemediationAllowedCondition ConditionType = "RemediationAllowed" - - // TooManyUnhealthy is the reason used when too many Machines are unhealthy and the MachineHealthCheck is blocked - // from making any further remediations. - TooManyUnhealthyReason = "TooManyUnhealthy" - - // ExternalRemediationTemplateAvailable is set on machinehealthchecks when MachineHealthCheck controller uses external remediation. - // ExternalRemediationTemplateAvailable is set to false if external remediation template is not found. - ExternalRemediationTemplateAvailable ConditionType = "ExternalRemediationTemplateAvailable" - - // ExternalRemediationTemplateNotFound is the reason used when a machine health check fails to find external remediation template. - ExternalRemediationTemplateNotFound = "ExternalRemediationTemplateNotFound" - - // ExternalRemediationRequestAvailable is set on machinehealthchecks when MachineHealthCheck controller uses external remediation. - // ExternalRemediationRequestAvailable is set to false if creating external remediation request fails. - ExternalRemediationRequestAvailable ConditionType = "ExternalRemediationRequestAvailable" - - // ExternalRemediationRequestCreationFailed is the reason used when a machine health check fails to create external remediation request. - ExternalRemediationRequestCreationFailed = "ExternalRemediationRequestCreationFailed" -) - -const ( - // InstanceExistsCondition is set on the Machine to show whether a virtual mahcine has been created by the cloud provider. - InstanceExistsCondition ConditionType = "InstanceExists" - - // ErrorCheckingProviderReason is the reason used when the exist operation fails. - // This would normally be because we cannot contact the provider. - ErrorCheckingProviderReason = "ErrorCheckingProvider" - - // InstanceMissingReason is the reason used when the machine was provisioned, but the instance has gone missing. - InstanceMissingReason = "InstanceMissing" - - // InstanceNotCreatedReason is the reason used when the machine has not yet been provisioned. - InstanceNotCreatedReason = "InstanceNotCreated" -) diff --git a/pkg/apis/machine/v1beta1/condition_types.go b/pkg/apis/machine/v1beta1/condition_types.go deleted file mode 100644 index d95da5377d..0000000000 --- a/pkg/apis/machine/v1beta1/condition_types.go +++ /dev/null @@ -1,81 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -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 v1beta1 - -import ( - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// ConditionSeverity expresses the severity of a Condition Type failing. -type ConditionSeverity string - -const ( - // ConditionSeverityError specifies that a condition with `Status=False` is an error. - ConditionSeverityError ConditionSeverity = "Error" - - // ConditionSeverityWarning specifies that a condition with `Status=False` is a warning. - ConditionSeverityWarning ConditionSeverity = "Warning" - - // ConditionSeverityInfo specifies that a condition with `Status=False` is informative. - ConditionSeverityInfo ConditionSeverity = "Info" - - // ConditionSeverityNone should apply only to conditions with `Status=True`. - ConditionSeverityNone ConditionSeverity = "" -) - -// ConditionType is a valid value for Condition.Type. -type ConditionType string - -// Condition defines an observation of a Machine API resource operational state. -type Condition struct { - // Type of condition in CamelCase or in foo.example.com/CamelCase. - // Many .condition.type values are consistent across resources like Available, but because arbitrary conditions - // can be useful (see .node.status.conditions), the ability to deconflict is important. - // +required - Type ConditionType `json:"type"` - - // Status of the condition, one of True, False, Unknown. - // +required - Status corev1.ConditionStatus `json:"status"` - - // Severity provides an explicit classification of Reason code, so the users or machines can immediately - // understand the current situation and act accordingly. - // The Severity field MUST be set only when Status=False. - // +optional - Severity ConditionSeverity `json:"severity,omitempty"` - - // Last time the condition transitioned from one status to another. - // This should be when the underlying condition changed. If that is not known, then using the time when - // the API field changed is acceptable. - // +required - LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"` - - // The reason for the condition's last transition in CamelCase. - // The specific API may choose whether or not this field is considered a guaranteed API. - // This field may not be empty. - // +optional - Reason string `json:"reason,omitempty"` - - // A human readable message indicating details about the transition. - // This field may be empty. - // +optional - Message string `json:"message,omitempty"` -} - -// Conditions provide observations of the operational state of a Machine API resource. -type Conditions []Condition diff --git a/pkg/apis/machine/v1beta1/consts.go b/pkg/apis/machine/v1beta1/consts.go deleted file mode 100644 index 26a7ea2736..0000000000 --- a/pkg/apis/machine/v1beta1/consts.go +++ /dev/null @@ -1,139 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -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 v1beta1 - -const ( - // PausedAnnotation is an annotation that can be applied to MachineHealthCheck objects to prevent the MHC controller - // from processing it. - PausedAnnotation = "cluster.x-k8s.io/paused" -) - -// Constants aren't automatically generated for unversioned packages. -// Instead share the same constant for all versioned packages -type MachineStatusError string - -const ( - // Represents that the combination of configuration in the MachineSpec - // is not supported by this cluster. This is not a transient error, but - // indicates a state that must be fixed before progress can be made. - // - // Example: the ProviderSpec specifies an instance type that doesn't exist, - InvalidConfigurationMachineError MachineStatusError = "InvalidConfiguration" - - // This indicates that the MachineSpec has been updated in a way that - // is not supported for reconciliation on this cluster. The spec may be - // completely valid from a configuration standpoint, but the controller - // does not support changing the real world state to match the new - // spec. - // - // Example: the responsible controller is not capable of changing the - // container runtime from docker to rkt. - UnsupportedChangeMachineError MachineStatusError = "UnsupportedChange" - - // This generally refers to exceeding one's quota in a cloud provider, - // or running out of physical machines in an on-premise environment. - InsufficientResourcesMachineError MachineStatusError = "InsufficientResources" - - // There was an error while trying to create a Node to match this - // Machine. This may indicate a transient problem that will be fixed - // automatically with time, such as a service outage, or a terminal - // error during creation that doesn't match a more specific - // MachineStatusError value. - // - // Example: timeout trying to connect to GCE. - CreateMachineError MachineStatusError = "CreateError" - - // There was an error while trying to update a Node that this - // Machine represents. This may indicate a transient problem that will be - // fixed automatically with time, such as a service outage, - // - // Example: error updating load balancers - UpdateMachineError MachineStatusError = "UpdateError" - - // An error was encountered while trying to delete the Node that this - // Machine represents. This could be a transient or terminal error, but - // will only be observable if the provider's Machine controller has - // added a finalizer to the object to more gracefully handle deletions. - // - // Example: cannot resolve EC2 IP address. - DeleteMachineError MachineStatusError = "DeleteError" - - // TemplateClonedFromGroupKindAnnotation is the infrastructure machine - // annotation that stores the group-kind of the infrastructure template resource - // that was cloned for the machine. This annotation is set only during cloning a - // template. Older/adopted machines will not have this annotation. - TemplateClonedFromGroupKindAnnotation = "machine.openshift.io/cloned-from-groupkind" - - // TemplateClonedFromNameAnnotation is the infrastructure machine annotation that - // stores the name of the infrastructure template resource - // that was cloned for the machine. This annotation is set only during cloning a - // template. Older/adopted machines will not have this annotation. - TemplateClonedFromNameAnnotation = "machine.openshift.io/cloned-from-name" - - // This error indicates that the machine did not join the cluster - // as a new node within the expected timeframe after instance - // creation at the provider succeeded - // - // Example use case: A controller that deletes Machines which do - // not result in a Node joining the cluster within a given timeout - // and that are managed by a MachineSet - JoinClusterTimeoutMachineError = "JoinClusterTimeoutError" -) - -type ClusterStatusError string - -const ( - // InvalidConfigurationClusterError indicates that the cluster - // configuration is invalid. - InvalidConfigurationClusterError ClusterStatusError = "InvalidConfiguration" - - // UnsupportedChangeClusterError indicates that the cluster - // spec has been updated in an unsupported way. That cannot be - // reconciled. - UnsupportedChangeClusterError ClusterStatusError = "UnsupportedChange" - - // CreateClusterError indicates that an error was encountered - // when trying to create the cluster. - CreateClusterError ClusterStatusError = "CreateError" - - // UpdateClusterError indicates that an error was encountered - // when trying to update the cluster. - UpdateClusterError ClusterStatusError = "UpdateError" - - // DeleteClusterError indicates that an error was encountered - // when trying to delete the cluster. - DeleteClusterError ClusterStatusError = "DeleteError" -) - -type MachineSetStatusError string - -const ( - // Represents that the combination of configuration in the MachineTemplateSpec - // is not supported by this cluster. This is not a transient error, but - // indicates a state that must be fixed before progress can be made. - // - // Example: the ProviderSpec specifies an instance type that doesn't exist. - InvalidConfigurationMachineSetError MachineSetStatusError = "InvalidConfiguration" -) - -type MachineDeploymentStrategyType string - -const ( - // Replace the old MachineSet by new one using rolling update - // i.e. gradually scale down the old MachineSet and scale up the new one. - RollingUpdateMachineDeploymentStrategyType MachineDeploymentStrategyType = "RollingUpdate" -) diff --git a/pkg/apis/machine/v1beta1/doc.go b/pkg/apis/machine/v1beta1/doc.go deleted file mode 100644 index fb656f231e..0000000000 --- a/pkg/apis/machine/v1beta1/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -// Package v1alpha1 contains API Schema definitions for the healthchecking v1beta1 API group -// +k8s:deepcopy-gen=package,register -// +groupName=machine.openshift.io -package v1beta1 diff --git a/pkg/apis/machine/v1beta1/machine_types.go b/pkg/apis/machine/v1beta1/machine_types.go deleted file mode 100644 index a38c8909cf..0000000000 --- a/pkg/apis/machine/v1beta1/machine_types.go +++ /dev/null @@ -1,222 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -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 v1beta1 - -import ( - "fmt" - - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/validation/field" -) - -const ( - // MachineFinalizer is set on PrepareForCreate callback. - MachineFinalizer = "machine.machine.openshift.io" - - // MachineClusterLabelName is the label set on machines linked to a cluster. - MachineClusterLabelName = "cluster.k8s.io/cluster-name" - - // MachineClusterIDLabel is the label that a machine must have to identify the - // cluster to which it belongs. - MachineClusterIDLabel = "machine.openshift.io/cluster-api-cluster" -) - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// Machine is the Schema for the machines API -// +k8s:openapi-gen=true -// +kubebuilder:subresource:status -// +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="Phase of machine" -// +kubebuilder:printcolumn:name="Type",type="string",JSONPath=".metadata.labels['machine\\.openshift\\.io/instance-type']",description="Type of instance" -// +kubebuilder:printcolumn:name="Region",type="string",JSONPath=".metadata.labels['machine\\.openshift\\.io/region']",description="Region associated with machine" -// +kubebuilder:printcolumn:name="Zone",type="string",JSONPath=".metadata.labels['machine\\.openshift\\.io/zone']",description="Zone associated with machine" -// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Machine age" -// +kubebuilder:printcolumn:name="Node",type="string",JSONPath=".status.nodeRef.name",description="Node associated with machine",priority=1 -// +kubebuilder:printcolumn:name="ProviderID",type="string",JSONPath=".spec.providerID",description="Provider ID of machine created in cloud provider",priority=1 -// +kubebuilder:printcolumn:name="State",type="string",JSONPath=".metadata.annotations['machine\\.openshift\\.io/instance-state']",description="State of instance",priority=1 -type Machine struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec MachineSpec `json:"spec,omitempty"` - Status MachineStatus `json:"status,omitempty"` -} - -func (m *Machine) GetConditions() Conditions { - return m.Status.Conditions -} - -func (m *Machine) SetConditions(conditions Conditions) { - m.Status.Conditions = conditions -} - -// MachineSpec defines the desired state of Machine -type MachineSpec struct { - // ObjectMeta will autopopulate the Node created. Use this to - // indicate what labels, annotations, name prefix, etc., should be used - // when creating the Node. - // +optional - ObjectMeta `json:"metadata,omitempty"` - - // The list of the taints to be applied to the corresponding Node in additive - // manner. This list will not overwrite any other taints added to the Node on - // an ongoing basis by other entities. These taints should be actively reconciled - // e.g. if you ask the machine controller to apply a taint and then manually remove - // the taint the machine controller will put it back) but not have the machine controller - // remove any taints - // +optional - Taints []corev1.Taint `json:"taints,omitempty"` - - // ProviderSpec details Provider-specific configuration to use during node creation. - // +optional - ProviderSpec ProviderSpec `json:"providerSpec"` - - // ProviderID is the identification ID of the machine provided by the provider. - // This field must match the provider ID as seen on the node object corresponding to this machine. - // This field is required by higher level consumers of cluster-api. Example use case is cluster autoscaler - // with cluster-api as provider. Clean-up logic in the autoscaler compares machines to nodes to find out - // machines at provider which could not get registered as Kubernetes nodes. With cluster-api as a - // generic out-of-tree provider for autoscaler, this field is required by autoscaler to be - // able to have a provider view of the list of machines. Another list of nodes is queried from the k8s apiserver - // and then a comparison is done to find out unregistered machines and are marked for delete. - // This field will be set by the actuators and consumed by higher level entities like autoscaler that will - // be interfacing with cluster-api as generic provider. - // +optional - ProviderID *string `json:"providerID,omitempty"` -} - -// MachineStatus defines the observed state of Machine -type MachineStatus struct { - // NodeRef will point to the corresponding Node if it exists. - // +optional - NodeRef *corev1.ObjectReference `json:"nodeRef,omitempty"` - - // LastUpdated identifies when this status was last observed. - // +optional - LastUpdated *metav1.Time `json:"lastUpdated,omitempty"` - - // ErrorReason will be set in the event that there is a terminal problem - // reconciling the Machine and will contain a succinct value suitable - // for machine interpretation. - // - // This field should not be set for transitive errors that a controller - // faces that are expected to be fixed automatically over - // time (like service outages), but instead indicate that something is - // fundamentally wrong with the Machine's spec or the configuration of - // the controller, and that manual intervention is required. Examples - // of terminal errors would be invalid combinations of settings in the - // spec, values that are unsupported by the controller, or the - // responsible controller itself being critically misconfigured. - // - // Any transient errors that occur during the reconciliation of Machines - // can be added as events to the Machine object and/or logged in the - // controller's output. - // +optional - ErrorReason *MachineStatusError `json:"errorReason,omitempty"` - - // ErrorMessage will be set in the event that there is a terminal problem - // reconciling the Machine and will contain a more verbose string suitable - // for logging and human consumption. - // - // This field should not be set for transitive errors that a controller - // faces that are expected to be fixed automatically over - // time (like service outages), but instead indicate that something is - // fundamentally wrong with the Machine's spec or the configuration of - // the controller, and that manual intervention is required. Examples - // of terminal errors would be invalid combinations of settings in the - // spec, values that are unsupported by the controller, or the - // responsible controller itself being critically misconfigured. - // - // Any transient errors that occur during the reconciliation of Machines - // can be added as events to the Machine object and/or logged in the - // controller's output. - // +optional - ErrorMessage *string `json:"errorMessage,omitempty"` - - // ProviderStatus details a Provider-specific status. - // It is recommended that providers maintain their - // own versioned API types that should be - // serialized/deserialized from this field. - // +optional - // +kubebuilder:validation:XPreserveUnknownFields - ProviderStatus *runtime.RawExtension `json:"providerStatus,omitempty"` - - // Addresses is a list of addresses assigned to the machine. Queried from cloud provider, if available. - // +optional - Addresses []corev1.NodeAddress `json:"addresses,omitempty"` - - // LastOperation describes the last-operation performed by the machine-controller. - // This API should be useful as a history in terms of the latest operation performed on the - // specific machine. It should also convey the state of the latest-operation for example if - // it is still on-going, failed or completed successfully. - // +optional - LastOperation *LastOperation `json:"lastOperation,omitempty"` - - // Phase represents the current phase of machine actuation. - // One of: Failed, Provisioning, Provisioned, Running, Deleting - // +optional - Phase *string `json:"phase,omitempty"` - - // Conditions defines the current state of the Machine - Conditions Conditions `json:"conditions,omitempty"` -} - -// LastOperation represents the detail of the last performed operation on the MachineObject. -type LastOperation struct { - // Description is the human-readable description of the last operation. - Description *string `json:"description,omitempty"` - - // LastUpdated is the timestamp at which LastOperation API was last-updated. - LastUpdated *metav1.Time `json:"lastUpdated,omitempty"` - - // State is the current status of the last performed operation. - // E.g. Processing, Failed, Successful etc - State *string `json:"state,omitempty"` - - // Type is the type of operation which was last performed. - // E.g. Create, Delete, Update etc - Type *string `json:"type,omitempty"` -} - -func (m *Machine) Validate() field.ErrorList { - errors := field.ErrorList{} - - // validate spec.labels - fldPath := field.NewPath("spec") - if m.Labels[MachineClusterIDLabel] == "" { - errors = append(errors, field.Invalid(fldPath.Child("labels"), m.Labels, fmt.Sprintf("missing %v label.", MachineClusterIDLabel))) - } - - // validate provider config is set - if m.Spec.ProviderSpec.Value == nil { - errors = append(errors, field.Invalid(fldPath.Child("spec").Child("providerspec"), m.Spec.ProviderSpec, "value field must be set")) - } - - return errors -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// MachineList contains a list of Machine -type MachineList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []Machine `json:"items"` -} diff --git a/pkg/apis/machine/v1beta1/machine_types_test.go b/pkg/apis/machine/v1beta1/machine_types_test.go deleted file mode 100644 index 19c3353469..0000000000 --- a/pkg/apis/machine/v1beta1/machine_types_test.go +++ /dev/null @@ -1,127 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -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 v1beta1 - -import ( - "encoding/json" - "math/rand" - "reflect" - "testing" - "time" - - . "github.com/onsi/gomega" - "golang.org/x/net/context" - "k8s.io/apimachinery/pkg/api/apitesting/fuzzer" - metafuzzer "k8s.io/apimachinery/pkg/apis/meta/fuzzer" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/serializer" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/kubernetes/scheme" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -func TestStorageMachine(t *testing.T) { - key := types.NamespacedName{Name: "foo", Namespace: "default"} - created := &Machine{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}} - - // Test Create - fetched := &Machine{} - if err := c.Create(context.TODO(), created); err != nil { - t.Errorf("error creating machine: %v", err) - } - - if err := c.Get(context.TODO(), key, fetched); err != nil { - t.Errorf("error getting machine: %v", err) - } - if !reflect.DeepEqual(*fetched, *created) { - t.Error("fetched value not what was created") - } - - // Test Updating the Labels - updated := fetched.DeepCopy() - updated.Labels = map[string]string{"hello": "world"} - if err := c.Update(context.TODO(), updated); err != nil { - t.Errorf("error updating machine: %v", err) - } - - if err := c.Get(context.TODO(), key, fetched); err != nil { - t.Errorf("error getting machine: %v", err) - } - if !reflect.DeepEqual(*fetched, *updated) { - t.Error("fetched value not what was updated") - } - - // Test Delete - if err := c.Delete(context.TODO(), fetched); err != nil { - t.Errorf("error deleting machine: %v", err) - } - if err := c.Get(context.TODO(), key, fetched); err == nil { - t.Error("expected error getting machine") - } -} - -func TestRoundTripMachine(t *testing.T) { - codecs := serializer.NewCodecFactory(scheme.Scheme) - seed := time.Now().UnixNano() - fuzzer := fuzzer.FuzzerFor(fuzzer.MergeFuzzerFuncs(metafuzzer.Funcs, machineFuzzerFuncs), rand.NewSource(seed), codecs) - ctx := context.Background() - g := NewWithT(t) - - for i := 0; i < 100; i++ { - machine := &Machine{ - ObjectMeta: metav1.ObjectMeta{ - GenerateName: "machine-round-trip-test-", - Namespace: "default", - }, - } - // Fuzz the spec and status as those are the ones we need to check aren't - // losing data - spec := &MachineSpec{} - status := &MachineStatus{} - fuzzer.Fuzz(spec) - fuzzer.Fuzz(status) - - machine.Spec = *spec.DeepCopy() - g.Expect(c.Create(ctx, machine)).To(Succeed()) - machine.Status = *status.DeepCopy() - g.Expect(c.Status().Update(ctx, machine)).To(Succeed()) - - // Check the spec and status weren't modified during create - // - // Use JSON representation as order of fields in RawExtensions may change - // during a round trip - machineSpecJSON, err := json.Marshal(machine.Spec) - g.Expect(err).ToNot(HaveOccurred()) - specJSON, err := json.Marshal(*spec) - g.Expect(err).ToNot(HaveOccurred()) - g.Expect(machineSpecJSON).To(MatchJSON(specJSON)) - - machineStatusJSON, err := json.Marshal(machine.Status) - g.Expect(err).ToNot(HaveOccurred()) - statusJSON, err := json.Marshal(*status) - g.Expect(err).ToNot(HaveOccurred()) - g.Expect(machineStatusJSON).To(MatchJSON(statusJSON)) - - fetched := &Machine{} - key := client.ObjectKey{Namespace: machine.Namespace, Name: machine.Name} - g.Expect(c.Get(ctx, key, fetched)).To(Succeed()) - - // Check the spec and status haven't changed server side - g.Expect(fetched.Spec).To(Equal(machine.Spec)) - g.Expect(fetched.Status).To(Equal(machine.Status)) - } -} diff --git a/pkg/apis/machine/v1beta1/machine_webhook.go b/pkg/apis/machine/v1beta1/machine_webhook.go deleted file mode 100644 index ff368b0ad2..0000000000 --- a/pkg/apis/machine/v1beta1/machine_webhook.go +++ /dev/null @@ -1,1206 +0,0 @@ -package v1beta1 - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - "runtime" - "strings" - - osconfigv1 "github.com/openshift/api/config/v1" - machinev1 "github.com/openshift/api/machine/v1beta1" - osclientset "github.com/openshift/client-go/config/clientset/versioned" - "github.com/openshift/machine-api-operator/pkg/apis/machine" - admissionregistrationv1 "k8s.io/api/admissionregistration/v1" - corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - kruntime "k8s.io/apimachinery/pkg/runtime" - utilerrors "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/apimachinery/pkg/util/validation/field" - "k8s.io/klog/v2" - "k8s.io/utils/pointer" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - yaml "sigs.k8s.io/yaml" -) - -var ( - // Azure Defaults - defaultAzureVnet = func(clusterID string) string { - return fmt.Sprintf("%s-vnet", clusterID) - } - defaultAzureSubnet = func(clusterID string) string { - return fmt.Sprintf("%s-worker-subnet", clusterID) - } - defaultAzureNetworkResourceGroup = func(clusterID string) string { - return fmt.Sprintf("%s-rg", clusterID) - } - defaultAzureImageResourceID = func(clusterID string) string { - return fmt.Sprintf("/resourceGroups/%s/providers/Microsoft.Compute/images/%s", clusterID+"-rg", clusterID) - } - defaultAzureManagedIdentiy = func(clusterID string) string { - return fmt.Sprintf("%s-identity", clusterID) - } - defaultAzureResourceGroup = func(clusterID string) string { - return fmt.Sprintf("%s-rg", clusterID) - } - - // GCP Defaults - defaultGCPNetwork = func(clusterID string) string { - return fmt.Sprintf("%s-network", clusterID) - } - defaultGCPSubnetwork = func(clusterID string) string { - return fmt.Sprintf("%s-worker-subnet", clusterID) - } - defaultGCPTags = func(clusterID string) []string { - return []string{fmt.Sprintf("%s-worker", clusterID)} - } -) - -const ( - DefaultMachineMutatingHookPath = "/mutate-machine-openshift-io-v1beta1-machine" - DefaultMachineValidatingHookPath = "/validate-machine-openshift-io-v1beta1-machine" - DefaultMachineSetMutatingHookPath = "/mutate-machine-openshift-io-v1beta1-machineset" - DefaultMachineSetValidatingHookPath = "/validate-machine-openshift-io-v1beta1-machineset" - - defaultWebhookConfigurationName = "machine-api" - defaultWebhookServiceName = "machine-api-operator-webhook" - defaultWebhookServiceNamespace = "openshift-machine-api" - defaultWebhookServicePort = 443 - - defaultUserDataSecret = "worker-user-data" - defaultSecretNamespace = "openshift-machine-api" - - // AWS Defaults - defaultAWSCredentialsSecret = "aws-cloud-credentials" - defaultAWSX86InstanceType = "m5.large" - defaultAWSARMInstanceType = "m6g.large" - - // Azure Defaults - defaultAzureVMSize = "Standard_D4s_V3" - defaultAzureCredentialsSecret = "azure-cloud-credentials" - defaultAzureOSDiskOSType = "Linux" - defaultAzureOSDiskStorageType = "Premium_LRS" - azureMaxDiskSizeGB = 32768 - - // GCP Defaults - defaultGCPMachineType = "n1-standard-4" - defaultGCPCredentialsSecret = "gcp-cloud-credentials" - defaultGCPDiskSizeGb = 128 - defaultGCPDiskType = "pd-standard" - // https://releases-art-rhcos.svc.ci.openshift.org/art/storage/releases/rhcos-4.8/48.83.202103122318-0/x86_64/meta.json - // https://github.com/openshift/installer/blob/796a99049d3b7489b6c08ec5bd7c7983731afbcf/data/data/rhcos.json#L90-L94 - defaultGCPDiskImage = "projects/rhcos-cloud/global/images/rhcos-48-83-202103221318-0-gcp-x86-64" - - // vSphere Defaults - defaultVSphereCredentialsSecret = "vsphere-cloud-credentials" - // Minimum vSphere values taken from vSphere reconciler - minVSphereCPU = 2 - minVSphereMemoryMiB = 2048 - // https://docs.openshift.com/container-platform/4.1/installing/installing_vsphere/installing-vsphere.html#minimum-resource-requirements_installing-vsphere - minVSphereDiskGiB = 120 -) - -var ( - // webhookFailurePolicy is ignore so we don't want to block machine lifecycle on the webhook operational aspects. - // This would be particularly problematic for chicken egg issues when bootstrapping a cluster. - webhookFailurePolicy = admissionregistrationv1.Ignore - webhookSideEffects = admissionregistrationv1.SideEffectClassNone -) - -func secretExists(c client.Client, name, namespace string) (bool, error) { - key := client.ObjectKey{ - Name: name, - Namespace: namespace, - } - obj := &corev1.Secret{} - - if err := c.Get(context.Background(), key, obj); err != nil { - if apierrors.IsNotFound(err) { - return false, nil - } - return false, err - } - return true, nil -} - -func credentialsSecretExists(c client.Client, name, namespace string) []string { - secretExists, err := secretExists(c, name, namespace) - if err != nil { - return []string{ - field.Invalid( - field.NewPath("providerSpec", "credentialsSecret"), - name, - fmt.Sprintf("failed to get credentialsSecret: %v", err), - ).Error(), - } - } - - if !secretExists { - return []string{ - field.Invalid( - field.NewPath("providerSpec", "credentialsSecret"), - name, - "not found. Expected CredentialsSecret to exist", - ).Error(), - } - } - - return []string{} -} - -func getInfra() (*osconfigv1.Infrastructure, error) { - cfg, err := ctrl.GetConfig() - if err != nil { - return nil, err - } - client, err := osclientset.NewForConfig(cfg) - if err != nil { - return nil, err - } - infra, err := client.ConfigV1().Infrastructures().Get(context.Background(), "cluster", metav1.GetOptions{}) - if err != nil { - return nil, err - } - return infra, nil -} - -func getDNS() (*osconfigv1.DNS, error) { - cfg, err := ctrl.GetConfig() - if err != nil { - return nil, err - } - client, err := osclientset.NewForConfig(cfg) - if err != nil { - return nil, err - } - dns, err := client.ConfigV1().DNSes().Get(context.Background(), "cluster", metav1.GetOptions{}) - if err != nil { - return nil, err - } - - return dns, nil -} - -type machineAdmissionFn func(m *Machine, config *admissionConfig) (bool, []string, utilerrors.Aggregate) - -type admissionConfig struct { - clusterID string - platformStatus *osconfigv1.PlatformStatus - dnsDisconnected bool - client client.Client -} - -type admissionHandler struct { - *admissionConfig - webhookOperations machineAdmissionFn - decoder *admission.Decoder -} - -// InjectDecoder injects the decoder. -func (a *admissionHandler) InjectDecoder(d *admission.Decoder) error { - a.decoder = d - return nil -} - -// machineValidatorHandler validates Machine API resources. -// implements type Handler interface. -// https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/webhook/admission#Handler -type machineValidatorHandler struct { - *admissionHandler -} - -// machineDefaulterHandler defaults Machine API resources. -// implements type Handler interface. -// https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/webhook/admission#Handler -type machineDefaulterHandler struct { - *admissionHandler -} - -// NewValidator returns a new machineValidatorHandler. -func NewMachineValidator(client client.Client) (*machineValidatorHandler, error) { - infra, err := getInfra() - if err != nil { - return nil, err - } - - dns, err := getDNS() - if err != nil { - return nil, err - } - - return createMachineValidator(infra, client, dns), nil -} - -func createMachineValidator(infra *osconfigv1.Infrastructure, client client.Client, dns *osconfigv1.DNS) *machineValidatorHandler { - admissionConfig := &admissionConfig{ - dnsDisconnected: dns.Spec.PublicZone == nil, - clusterID: infra.Status.InfrastructureName, - platformStatus: infra.Status.PlatformStatus, - client: client, - } - return &machineValidatorHandler{ - admissionHandler: &admissionHandler{ - admissionConfig: admissionConfig, - webhookOperations: getMachineValidatorOperation(infra.Status.PlatformStatus.Type), - }, - } -} - -func getMachineValidatorOperation(platform osconfigv1.PlatformType) machineAdmissionFn { - switch platform { - case osconfigv1.AWSPlatformType: - return validateAWS - case osconfigv1.AzurePlatformType: - return validateAzure - case osconfigv1.GCPPlatformType: - return validateGCP - case osconfigv1.VSpherePlatformType: - return validateVSphere - default: - // just no-op - return func(m *Machine, config *admissionConfig) (bool, []string, utilerrors.Aggregate) { - return true, []string{}, nil - } - } -} - -// NewDefaulter returns a new machineDefaulterHandler. -func NewMachineDefaulter() (*machineDefaulterHandler, error) { - infra, err := getInfra() - if err != nil { - return nil, err - } - - return createMachineDefaulter(infra.Status.PlatformStatus, infra.Status.InfrastructureName), nil -} - -func createMachineDefaulter(platformStatus *osconfigv1.PlatformStatus, clusterID string) *machineDefaulterHandler { - return &machineDefaulterHandler{ - admissionHandler: &admissionHandler{ - admissionConfig: &admissionConfig{clusterID: clusterID}, - webhookOperations: getMachineDefaulterOperation(platformStatus), - }, - } -} - -func getMachineDefaulterOperation(platformStatus *osconfigv1.PlatformStatus) machineAdmissionFn { - switch platformStatus.Type { - case osconfigv1.AWSPlatformType: - region := "" - if platformStatus.AWS != nil { - region = platformStatus.AWS.Region - } - arch := runtime.GOARCH - return awsDefaulter{region: region, arch: arch}.defaultAWS - case osconfigv1.AzurePlatformType: - return defaultAzure - case osconfigv1.GCPPlatformType: - return defaultGCP - case osconfigv1.VSpherePlatformType: - return defaultVSphere - default: - // just no-op - return func(m *Machine, config *admissionConfig) (bool, []string, utilerrors.Aggregate) { - return true, []string{}, nil - } - } -} - -// NewValidatingWebhookConfiguration creates a validation webhook configuration with configured Machine and MachineSet webhooks -func NewValidatingWebhookConfiguration() *admissionregistrationv1.ValidatingWebhookConfiguration { - validatingWebhookConfiguration := &admissionregistrationv1.ValidatingWebhookConfiguration{ - ObjectMeta: metav1.ObjectMeta{ - Name: defaultWebhookConfigurationName, - Annotations: map[string]string{ - "service.beta.openshift.io/inject-cabundle": "true", - }, - }, - Webhooks: []admissionregistrationv1.ValidatingWebhook{ - MachineValidatingWebhook(), - MachineSetValidatingWebhook(), - }, - } - - // Setting group version is required for testEnv to create unstructured objects, as the new structure sets it on empty strings - // Usual way to populate those values, is to create the resource in the cluster first, which we can't yet do. - validatingWebhookConfiguration.SetGroupVersionKind(admissionregistrationv1.SchemeGroupVersion.WithKind("ValidatingWebhookConfiguration")) - return validatingWebhookConfiguration -} - -// MachineValidatingWebhook returns validating webhooks for machine to populate the configuration -func MachineValidatingWebhook() admissionregistrationv1.ValidatingWebhook { - serviceReference := admissionregistrationv1.ServiceReference{ - Namespace: defaultWebhookServiceNamespace, - Name: defaultWebhookServiceName, - Path: pointer.StringPtr(DefaultMachineValidatingHookPath), - Port: pointer.Int32Ptr(defaultWebhookServicePort), - } - return admissionregistrationv1.ValidatingWebhook{ - AdmissionReviewVersions: []string{"v1"}, - Name: "validation.machine.machine.openshift.io", - FailurePolicy: &webhookFailurePolicy, - SideEffects: &webhookSideEffects, - ClientConfig: admissionregistrationv1.WebhookClientConfig{ - Service: &serviceReference, - }, - Rules: []admissionregistrationv1.RuleWithOperations{ - { - Rule: admissionregistrationv1.Rule{ - APIGroups: []string{machine.GroupName}, - APIVersions: []string{SchemeGroupVersion.Version}, - Resources: []string{"machines"}, - }, - Operations: []admissionregistrationv1.OperationType{ - admissionregistrationv1.Create, - admissionregistrationv1.Update, - }, - }, - }, - } -} - -// MachineSetValidatingWebhook returns validating webhooks for machineSet to populate the configuration -func MachineSetValidatingWebhook() admissionregistrationv1.ValidatingWebhook { - machinesetServiceReference := admissionregistrationv1.ServiceReference{ - Namespace: defaultWebhookServiceNamespace, - Name: defaultWebhookServiceName, - Path: pointer.StringPtr(DefaultMachineSetValidatingHookPath), - Port: pointer.Int32Ptr(defaultWebhookServicePort), - } - return admissionregistrationv1.ValidatingWebhook{ - AdmissionReviewVersions: []string{"v1"}, - Name: "validation.machineset.machine.openshift.io", - FailurePolicy: &webhookFailurePolicy, - SideEffects: &webhookSideEffects, - ClientConfig: admissionregistrationv1.WebhookClientConfig{ - Service: &machinesetServiceReference, - }, - Rules: []admissionregistrationv1.RuleWithOperations{ - { - Rule: admissionregistrationv1.Rule{ - APIGroups: []string{machine.GroupName}, - APIVersions: []string{SchemeGroupVersion.Version}, - Resources: []string{"machinesets"}, - }, - Operations: []admissionregistrationv1.OperationType{ - admissionregistrationv1.Create, - admissionregistrationv1.Update, - }, - }, - }, - } -} - -// NewMutatingWebhookConfiguration creates a mutating webhook configuration with configured Machine and MachineSet webhooks -func NewMutatingWebhookConfiguration() *admissionregistrationv1.MutatingWebhookConfiguration { - mutatingWebhookConfiguration := &admissionregistrationv1.MutatingWebhookConfiguration{ - ObjectMeta: metav1.ObjectMeta{ - Name: defaultWebhookConfigurationName, - Annotations: map[string]string{ - "service.beta.openshift.io/inject-cabundle": "true", - }, - }, - Webhooks: []admissionregistrationv1.MutatingWebhook{ - MachineMutatingWebhook(), - MachineSetMutatingWebhook(), - }, - } - - // Setting group version is required for testEnv to create unstructured objects, as the new structure sets it on empty strings - // Usual way to populate those values, is to create the resource in the cluster first, which we can't yet do. - mutatingWebhookConfiguration.SetGroupVersionKind(admissionregistrationv1.SchemeGroupVersion.WithKind("MutatingWebhookConfiguration")) - return mutatingWebhookConfiguration -} - -// MachineMutatingWebhook returns mutating webhooks for machine to apply in configuration -func MachineMutatingWebhook() admissionregistrationv1.MutatingWebhook { - machineServiceReference := admissionregistrationv1.ServiceReference{ - Namespace: defaultWebhookServiceNamespace, - Name: defaultWebhookServiceName, - Path: pointer.StringPtr(DefaultMachineMutatingHookPath), - Port: pointer.Int32Ptr(defaultWebhookServicePort), - } - return admissionregistrationv1.MutatingWebhook{ - AdmissionReviewVersions: []string{"v1"}, - Name: "default.machine.machine.openshift.io", - FailurePolicy: &webhookFailurePolicy, - SideEffects: &webhookSideEffects, - ClientConfig: admissionregistrationv1.WebhookClientConfig{ - Service: &machineServiceReference, - }, - Rules: []admissionregistrationv1.RuleWithOperations{ - { - Rule: admissionregistrationv1.Rule{ - APIGroups: []string{machine.GroupName}, - APIVersions: []string{SchemeGroupVersion.Version}, - Resources: []string{"machines"}, - }, - Operations: []admissionregistrationv1.OperationType{ - admissionregistrationv1.Create, - }, - }, - }, - } -} - -// MachineSetMutatingWebhook returns mutating webhook for machineSet to apply in configuration -func MachineSetMutatingWebhook() admissionregistrationv1.MutatingWebhook { - machineSetServiceReference := admissionregistrationv1.ServiceReference{ - Namespace: defaultWebhookServiceNamespace, - Name: defaultWebhookServiceName, - Path: pointer.StringPtr(DefaultMachineSetMutatingHookPath), - Port: pointer.Int32Ptr(defaultWebhookServicePort), - } - return admissionregistrationv1.MutatingWebhook{ - AdmissionReviewVersions: []string{"v1"}, - Name: "default.machineset.machine.openshift.io", - FailurePolicy: &webhookFailurePolicy, - SideEffects: &webhookSideEffects, - ClientConfig: admissionregistrationv1.WebhookClientConfig{ - Service: &machineSetServiceReference, - }, - Rules: []admissionregistrationv1.RuleWithOperations{ - { - Rule: admissionregistrationv1.Rule{ - APIGroups: []string{machine.GroupName}, - APIVersions: []string{SchemeGroupVersion.Version}, - Resources: []string{"machinesets"}, - }, - Operations: []admissionregistrationv1.OperationType{ - admissionregistrationv1.Create, - }, - }, - }, - } -} - -// Handle handles HTTP requests for admission webhook servers. -func (h *machineValidatorHandler) Handle(ctx context.Context, req admission.Request) admission.Response { - m := &Machine{} - - if err := h.decoder.Decode(req, m); err != nil { - return admission.Errored(http.StatusBadRequest, err) - } - - klog.V(3).Infof("Validate webhook called for Machine: %s", m.GetName()) - - ok, warnings, errs := h.webhookOperations(m, h.admissionConfig) - if !ok { - return admission.Denied(errs.Error()).WithWarnings(warnings...) - } - - return admission.Allowed("Machine valid").WithWarnings(warnings...) -} - -// Handle handles HTTP requests for admission webhook servers. -func (h *machineDefaulterHandler) Handle(ctx context.Context, req admission.Request) admission.Response { - m := &Machine{} - - if err := h.decoder.Decode(req, m); err != nil { - return admission.Errored(http.StatusBadRequest, err) - } - - klog.V(3).Infof("Mutate webhook called for Machine: %s", m.GetName()) - - // Only enforce the clusterID if it's not set. - // Otherwise a discrepancy on the value would leave the machine orphan - // and would trigger a new machine creation by the machineSet. - // https://bugzilla.redhat.com/show_bug.cgi?id=1857175 - if m.Labels == nil { - m.Labels = make(map[string]string) - } - if _, ok := m.Labels[MachineClusterIDLabel]; !ok { - m.Labels[MachineClusterIDLabel] = h.clusterID - } - - ok, warnings, errs := h.webhookOperations(m, h.admissionConfig) - if !ok { - return admission.Denied(errs.Error()).WithWarnings(warnings...) - } - - marshaledMachine, err := json.Marshal(m) - if err != nil { - return admission.Errored(http.StatusInternalServerError, err).WithWarnings(warnings...) - } - return admission.PatchResponseFromRaw(req.Object.Raw, marshaledMachine).WithWarnings(warnings...) -} - -type awsDefaulter struct { - region string - arch string -} - -func (a awsDefaulter) defaultAWS(m *Machine, config *admissionConfig) (bool, []string, utilerrors.Aggregate) { - klog.V(3).Infof("Defaulting AWS providerSpec") - - var errs []error - var warnings []string - providerSpec := new(machinev1.AWSMachineProviderConfig) - if err := unmarshalInto(m, providerSpec); err != nil { - errs = append(errs, err) - return false, warnings, utilerrors.NewAggregate(errs) - } - - if providerSpec.InstanceType == "" { - if a.arch == "arm64" { - providerSpec.InstanceType = defaultAWSARMInstanceType - } else { - providerSpec.InstanceType = defaultAWSX86InstanceType - } - } - - if providerSpec.Placement.Region == "" { - providerSpec.Placement.Region = a.region - } - - if providerSpec.UserDataSecret == nil { - providerSpec.UserDataSecret = &corev1.LocalObjectReference{Name: defaultUserDataSecret} - } - - if providerSpec.CredentialsSecret == nil { - providerSpec.CredentialsSecret = &corev1.LocalObjectReference{Name: defaultAWSCredentialsSecret} - } - - rawBytes, err := json.Marshal(providerSpec) - if err != nil { - errs = append(errs, err) - } - - if len(errs) > 0 { - return false, warnings, utilerrors.NewAggregate(errs) - } - - m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} - return true, warnings, nil -} - -func unmarshalInto(m *Machine, providerSpec interface{}) error { - if m.Spec.ProviderSpec.Value == nil { - return field.Required(field.NewPath("providerSpec", "value"), "a value must be provided") - } - - if err := yaml.Unmarshal(m.Spec.ProviderSpec.Value.Raw, &providerSpec); err != nil { - return field.Invalid(field.NewPath("providerSpec", "value"), providerSpec, err.Error()) - } - return nil -} - -func validateAWS(m *Machine, config *admissionConfig) (bool, []string, utilerrors.Aggregate) { - klog.V(3).Infof("Validating AWS providerSpec") - - var errs []error - var warnings []string - providerSpec := new(machinev1.AWSMachineProviderConfig) - if err := unmarshalInto(m, providerSpec); err != nil { - errs = append(errs, err) - return false, warnings, utilerrors.NewAggregate(errs) - } - - if providerSpec.AMI.ID == nil { - errs = append( - errs, - field.Required( - field.NewPath("providerSpec", "ami"), - "expected providerSpec.ami.id to be populated", - ), - ) - } - - if providerSpec.AMI.ARN != nil { - warnings = append( - warnings, - "can't use providerSpec.ami.arn, only providerSpec.ami.id can be used to reference AMI", - ) - } - - if providerSpec.AMI.Filters != nil { - warnings = append( - warnings, - "can't use providerSpec.ami.filters, only providerSpec.ami.id can be used to reference AMI", - ) - } - - if providerSpec.Placement.Region == "" { - errs = append( - errs, - field.Required( - field.NewPath("providerSpec", "placement", "region"), - "expected providerSpec.placement.region to be populated", - ), - ) - } - - if providerSpec.InstanceType == "" { - errs = append( - errs, - field.Required( - field.NewPath("providerSpec", "instanceType"), - "expected providerSpec.instanceType to be populated", - ), - ) - } - - if providerSpec.UserDataSecret == nil { - errs = append( - errs, - field.Required( - field.NewPath("providerSpec", "userDataSecret"), - "expected providerSpec.userDataSecret to be populated", - ), - ) - } - - if providerSpec.CredentialsSecret == nil { - errs = append( - errs, - field.Required( - field.NewPath("providerSpec", "credentialsSecret"), - "expected providerSpec.credentialsSecret to be populated", - ), - ) - } else { - warnings = append(warnings, credentialsSecretExists(config.client, providerSpec.CredentialsSecret.Name, m.GetNamespace())...) - } - - if providerSpec.Subnet.ARN == nil && providerSpec.Subnet.ID == nil && providerSpec.Subnet.Filters == nil { - warnings = append( - warnings, - "providerSpec.subnet: No subnet has been provided. Instances may be created in an unexpected subnet and may not join the cluster.", - ) - } - - if providerSpec.IAMInstanceProfile == nil { - warnings = append(warnings, "providerSpec.iamInstanceProfile: no IAM instance profile provided: nodes may be unable to join the cluster") - } - - // TODO(alberto): Validate providerSpec.BlockDevices. - // https://github.com/openshift/cluster-api-provider-aws/pull/299#discussion_r433920532 - - switch providerSpec.Placement.Tenancy { - case "", machinev1.DefaultTenancy, machinev1.DedicatedTenancy, machinev1.HostTenancy: - // Do nothing, valid values - default: - errs = append( - errs, - field.Invalid( - field.NewPath("providerSpec", "tenancy"), - providerSpec.Placement.Tenancy, - fmt.Sprintf("Invalid providerSpec.tenancy, the only allowed options are: %s, %s, %s", machinev1.DefaultTenancy, machinev1.DedicatedTenancy, machinev1.HostTenancy), - ), - ) - } - - duplicatedTags := getDuplicatedTags(providerSpec.Tags) - if len(duplicatedTags) > 0 { - warnings = append(warnings, fmt.Sprintf("providerSpec.tags: duplicated tag names (%s): only the first value will be used.", strings.Join(duplicatedTags, ","))) - } - - if len(errs) > 0 { - return false, warnings, utilerrors.NewAggregate(errs) - } - - return true, warnings, nil -} - -// getDuplicatedTags iterates through the AWS TagSpecifications -// to determine if any tag Name is duplicated within the list. -// A list of duplicated names will be returned. -func getDuplicatedTags(tagSpecs []machinev1.TagSpecification) []string { - tagNames := map[string]int{} - duplicatedTags := []string{} - for _, spec := range tagSpecs { - tagNames[spec.Name] += 1 - // Only append the duplicated tag on the second occurrence to prevent it - // being listed multiple times when there are more than 2 occurrences. - if tagNames[spec.Name] == 2 { - duplicatedTags = append(duplicatedTags, spec.Name) - } - } - return duplicatedTags -} - -func defaultAzure(m *Machine, config *admissionConfig) (bool, []string, utilerrors.Aggregate) { - klog.V(3).Infof("Defaulting Azure providerSpec") - - var errs []error - var warnings []string - providerSpec := new(machinev1.AzureMachineProviderSpec) - if err := unmarshalInto(m, providerSpec); err != nil { - errs = append(errs, err) - return false, warnings, utilerrors.NewAggregate(errs) - } - - if providerSpec.VMSize == "" { - providerSpec.VMSize = defaultAzureVMSize - } - - // Vnet and Subnet need to be provided together by the user - if providerSpec.Vnet == "" && providerSpec.Subnet == "" { - providerSpec.Vnet = defaultAzureVnet(config.clusterID) - providerSpec.Subnet = defaultAzureSubnet(config.clusterID) - } - - if providerSpec.Image == (machinev1.Image{}) { - providerSpec.Image.ResourceID = defaultAzureImageResourceID(config.clusterID) - } - - if providerSpec.UserDataSecret == nil { - providerSpec.UserDataSecret = &corev1.SecretReference{Name: defaultUserDataSecret} - } else if providerSpec.UserDataSecret.Name == "" { - providerSpec.UserDataSecret.Name = defaultUserDataSecret - } - - if providerSpec.CredentialsSecret == nil { - providerSpec.CredentialsSecret = &corev1.SecretReference{Name: defaultAzureCredentialsSecret, Namespace: defaultSecretNamespace} - } else { - if providerSpec.CredentialsSecret.Namespace == "" { - providerSpec.CredentialsSecret.Namespace = defaultSecretNamespace - } - if providerSpec.CredentialsSecret.Name == "" { - providerSpec.CredentialsSecret.Name = defaultAzureCredentialsSecret - } - } - - rawBytes, err := json.Marshal(providerSpec) - if err != nil { - errs = append(errs, err) - } - - if len(errs) > 0 { - return false, warnings, utilerrors.NewAggregate(errs) - } - - m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} - return true, warnings, nil -} - -func validateAzure(m *Machine, config *admissionConfig) (bool, []string, utilerrors.Aggregate) { - klog.V(3).Infof("Validating Azure providerSpec") - - var errs []error - var warnings []string - providerSpec := new(machinev1.AzureMachineProviderSpec) - if err := unmarshalInto(m, providerSpec); err != nil { - errs = append(errs, err) - return false, warnings, utilerrors.NewAggregate(errs) - } - - if providerSpec.VMSize == "" { - errs = append(errs, field.Required(field.NewPath("providerSpec", "vmSize"), "vmSize should be set to one of the supported Azure VM sizes")) - } - - if providerSpec.PublicIP && config.dnsDisconnected { - errs = append(errs, field.Forbidden(field.NewPath("providerSpec", "publicIP"), "publicIP is not allowed in Azure disconnected installation")) - } - // Vnet requires Subnet - if providerSpec.Vnet != "" && providerSpec.Subnet == "" { - errs = append(errs, field.Required(field.NewPath("providerSpec", "subnet"), "must provide a subnet when a virtual network is specified")) - } - - // Subnet requires Vnet - if providerSpec.Subnet != "" && providerSpec.Vnet == "" { - errs = append(errs, field.Required(field.NewPath("providerSpec", "vnet"), "must provide a virtual network when supplying subnets")) - } - - errs = append(errs, validateAzureImage(providerSpec.Image)...) - - if providerSpec.UserDataSecret == nil { - errs = append(errs, field.Required(field.NewPath("providerSpec", "userDataSecret"), "userDataSecret must be provided")) - } else if providerSpec.UserDataSecret.Name == "" { - errs = append(errs, field.Required(field.NewPath("providerSpec", "userDataSecret", "name"), "name must be provided")) - } - - if providerSpec.CredentialsSecret == nil { - errs = append(errs, field.Required(field.NewPath("providerSpec", "credentialsSecret"), "credentialsSecret must be provided")) - } else { - if providerSpec.CredentialsSecret.Namespace == "" { - errs = append(errs, field.Required(field.NewPath("providerSpec", "credentialsSecret", "namespace"), "namespace must be provided")) - } - if providerSpec.CredentialsSecret.Name == "" { - errs = append(errs, field.Required(field.NewPath("providerSpec", "credentialsSecret", "name"), "name must be provided")) - } - if providerSpec.CredentialsSecret.Name != "" && providerSpec.CredentialsSecret.Namespace != "" { - warnings = append(warnings, credentialsSecretExists(config.client, providerSpec.CredentialsSecret.Name, providerSpec.CredentialsSecret.Namespace)...) - } - } - - if providerSpec.OSDisk.DiskSizeGB <= 0 || providerSpec.OSDisk.DiskSizeGB >= azureMaxDiskSizeGB { - errs = append(errs, field.Invalid(field.NewPath("providerSpec", "osDisk", "diskSizeGB"), providerSpec.OSDisk.DiskSizeGB, "diskSizeGB must be greater than zero and less than 32768")) - } - - if isAzureGovCloud(config.platformStatus) && providerSpec.SpotVMOptions != nil { - warnings = append(warnings, "spot VMs may not be supported when using GovCloud region") - } - - if len(errs) > 0 { - return false, warnings, utilerrors.NewAggregate(errs) - } - return true, warnings, nil -} - -func validateAzureImage(image machinev1.Image) []error { - errors := []error{} - if image == (machinev1.Image{}) { - return append(errors, field.Required(field.NewPath("providerSpec", "image"), "an image reference must be provided")) - } - - if image.ResourceID != "" { - if image != (machinev1.Image{ResourceID: image.ResourceID}) { - return append(errors, field.Required(field.NewPath("providerSpec", "image", "resourceID"), "resourceID is already specified, other fields such as [Offer, Publisher, SKU, Version] should not be set")) - } - return errors - } - - // Resource ID not provided, so Offer, Publisher, SKU and Version are required - if image.Offer == "" { - errors = append(errors, field.Required(field.NewPath("providerSpec", "image", "Offer"), "Offer must be provided")) - } - if image.Publisher == "" { - errors = append(errors, field.Required(field.NewPath("providerSpec", "image", "Publisher"), "Publisher must be provided")) - } - if image.SKU == "" { - errors = append(errors, field.Required(field.NewPath("providerSpec", "image", "SKU"), "SKU must be provided")) - } - if image.Version == "" { - errors = append(errors, field.Required(field.NewPath("providerSpec", "image", "Version"), "Version must be provided")) - } - - return errors -} - -func defaultGCP(m *Machine, config *admissionConfig) (bool, []string, utilerrors.Aggregate) { - klog.V(3).Infof("Defaulting GCP providerSpec") - - var errs []error - var warnings []string - providerSpec := new(machinev1.GCPMachineProviderSpec) - if err := unmarshalInto(m, providerSpec); err != nil { - errs = append(errs, err) - return false, warnings, utilerrors.NewAggregate(errs) - } - - if providerSpec.MachineType == "" { - providerSpec.MachineType = defaultGCPMachineType - } - - if len(providerSpec.NetworkInterfaces) == 0 { - providerSpec.NetworkInterfaces = append(providerSpec.NetworkInterfaces, &machinev1.GCPNetworkInterface{ - Network: defaultGCPNetwork(config.clusterID), - Subnetwork: defaultGCPSubnetwork(config.clusterID), - }) - } - - providerSpec.Disks = defaultGCPDisks(providerSpec.Disks, config.clusterID) - - if len(providerSpec.Tags) == 0 { - providerSpec.Tags = defaultGCPTags(config.clusterID) - } - - if providerSpec.UserDataSecret == nil { - providerSpec.UserDataSecret = &corev1.LocalObjectReference{Name: defaultUserDataSecret} - } - - if providerSpec.CredentialsSecret == nil { - providerSpec.CredentialsSecret = &corev1.LocalObjectReference{Name: defaultGCPCredentialsSecret} - } - - rawBytes, err := json.Marshal(providerSpec) - if err != nil { - errs = append(errs, err) - } - - if len(errs) > 0 { - return false, warnings, utilerrors.NewAggregate(errs) - } - - m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} - return true, warnings, nil -} - -func defaultGCPDisks(disks []*machinev1.GCPDisk, clusterID string) []*machinev1.GCPDisk { - if len(disks) == 0 { - return []*machinev1.GCPDisk{ - { - AutoDelete: true, - Boot: true, - SizeGB: defaultGCPDiskSizeGb, - Type: defaultGCPDiskType, - Image: defaultGCPDiskImage, - }, - } - } - - for _, disk := range disks { - if disk.Type == "" { - disk.Type = defaultGCPDiskType - } - - if disk.Image == "" { - disk.Image = defaultGCPDiskImage - } - } - - return disks -} - -func validateGCP(m *Machine, config *admissionConfig) (bool, []string, utilerrors.Aggregate) { - klog.V(3).Infof("Validating GCP providerSpec") - - var errs []error - var warnings []string - providerSpec := new(machinev1.GCPMachineProviderSpec) - if err := unmarshalInto(m, providerSpec); err != nil { - errs = append(errs, err) - return false, warnings, utilerrors.NewAggregate(errs) - } - - if providerSpec.Region == "" { - errs = append(errs, field.Required(field.NewPath("providerSpec", "region"), "region is required")) - } - - if !strings.HasPrefix(providerSpec.Zone, providerSpec.Region) { - errs = append(errs, field.Invalid(field.NewPath("providerSpec", "zone"), providerSpec.Zone, fmt.Sprintf("zone not in configured region (%s)", providerSpec.Region))) - } - - if providerSpec.MachineType == "" { - errs = append(errs, field.Required(field.NewPath("providerSpec", "machineType"), "machineType should be set to one of the supported GCP machine types")) - } - - errs = append(errs, validateGCPNetworkInterfaces(providerSpec.NetworkInterfaces, field.NewPath("providerSpec", "networkInterfaces"))...) - errs = append(errs, validateGCPDisks(providerSpec.Disks, field.NewPath("providerSpec", "disks"))...) - - if len(providerSpec.ServiceAccounts) == 0 { - warnings = append(warnings, "providerSpec.serviceAccounts: no service account provided: nodes may be unable to join the cluster") - } else { - errs = append(errs, validateGCPServiceAccounts(providerSpec.ServiceAccounts, field.NewPath("providerSpec", "serviceAccounts"))...) - } - - if providerSpec.UserDataSecret == nil { - errs = append(errs, field.Required(field.NewPath("providerSpec", "userDataSecret"), "userDataSecret must be provided")) - } else { - if providerSpec.UserDataSecret.Name == "" { - errs = append(errs, field.Required(field.NewPath("providerSpec", "userDataSecret", "name"), "name must be provided")) - } - } - - if providerSpec.CredentialsSecret == nil { - errs = append(errs, field.Required(field.NewPath("providerSpec", "credentialsSecret"), "credentialsSecret must be provided")) - } else { - if providerSpec.CredentialsSecret.Name == "" { - errs = append(errs, field.Required(field.NewPath("providerSpec", "credentialsSecret", "name"), "name must be provided")) - } else { - warnings = append(warnings, credentialsSecretExists(config.client, providerSpec.CredentialsSecret.Name, m.GetNamespace())...) - } - } - - if len(errs) > 0 { - return false, warnings, utilerrors.NewAggregate(errs) - } - return true, warnings, nil -} - -func validateGCPNetworkInterfaces(networkInterfaces []*machinev1.GCPNetworkInterface, parentPath *field.Path) []error { - if len(networkInterfaces) == 0 { - return []error{field.Required(parentPath, "at least 1 network interface is required")} - } - - var errs []error - for i, ni := range networkInterfaces { - fldPath := parentPath.Index(i) - - if ni.Network == "" { - errs = append(errs, field.Required(fldPath.Child("network"), "network is required")) - } - - if ni.Subnetwork == "" { - errs = append(errs, field.Required(fldPath.Child("subnetwork"), "subnetwork is required")) - } - } - - return errs -} - -func validateGCPDisks(disks []*machinev1.GCPDisk, parentPath *field.Path) []error { - if len(disks) == 0 { - return []error{field.Required(parentPath, "at least 1 disk is required")} - } - - var errs []error - for i, disk := range disks { - fldPath := parentPath.Index(i) - - if disk.SizeGB != 0 { - if disk.SizeGB < 16 { - errs = append(errs, field.Invalid(fldPath.Child("sizeGb"), disk.SizeGB, "must be at least 16GB in size")) - } else if disk.SizeGB > 65536 { - errs = append(errs, field.Invalid(fldPath.Child("sizeGb"), disk.SizeGB, "exceeding maximum GCP disk size limit, must be below 65536")) - } - } - - if disk.Type != "" { - diskTypes := sets.NewString("pd-standard", "pd-ssd") - if !diskTypes.Has(disk.Type) { - errs = append(errs, field.NotSupported(fldPath.Child("type"), disk.Type, diskTypes.List())) - } - } - } - - return errs -} - -func validateGCPServiceAccounts(serviceAccounts []machinev1.GCPServiceAccount, parentPath *field.Path) []error { - if len(serviceAccounts) != 1 { - return []error{field.Invalid(parentPath, fmt.Sprintf("%d service accounts supplied", len(serviceAccounts)), "exactly 1 service account must be supplied")} - } - - var errs []error - for i, serviceAccount := range serviceAccounts { - fldPath := parentPath.Index(i) - - if serviceAccount.Email == "" { - errs = append(errs, field.Required(fldPath.Child("email"), "email is required")) - } - - if len(serviceAccount.Scopes) == 0 { - errs = append(errs, field.Required(fldPath.Child("scopes"), "at least 1 scope is required")) - } - } - return errs -} - -func defaultVSphere(m *Machine, config *admissionConfig) (bool, []string, utilerrors.Aggregate) { - klog.V(3).Infof("Defaulting vSphere providerSpec") - - var errs []error - var warnings []string - providerSpec := new(machinev1.VSphereMachineProviderSpec) - if err := unmarshalInto(m, providerSpec); err != nil { - errs = append(errs, err) - return false, warnings, utilerrors.NewAggregate(errs) - } - - if providerSpec.UserDataSecret == nil { - providerSpec.UserDataSecret = &corev1.LocalObjectReference{Name: defaultUserDataSecret} - } - - if providerSpec.CredentialsSecret == nil { - providerSpec.CredentialsSecret = &corev1.LocalObjectReference{Name: defaultVSphereCredentialsSecret} - } - - rawBytes, err := json.Marshal(providerSpec) - if err != nil { - errs = append(errs, err) - } - - if len(errs) > 0 { - return false, warnings, utilerrors.NewAggregate(errs) - } - - m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} - return true, warnings, nil -} - -func validateVSphere(m *Machine, config *admissionConfig) (bool, []string, utilerrors.Aggregate) { - klog.V(3).Infof("Validating vSphere providerSpec") - - var errs []error - var warnings []string - providerSpec := new(machinev1.VSphereMachineProviderSpec) - if err := unmarshalInto(m, providerSpec); err != nil { - errs = append(errs, err) - return false, warnings, utilerrors.NewAggregate(errs) - } - - if providerSpec.Template == "" { - errs = append(errs, field.Required(field.NewPath("providerSpec", "template"), "template must be provided")) - } - - workspaceWarnings, workspaceErrors := validateVSphereWorkspace(providerSpec.Workspace, field.NewPath("providerSpec", "workspace")) - warnings = append(warnings, workspaceWarnings...) - errs = append(errs, workspaceErrors...) - - errs = append(errs, validateVSphereNetwork(providerSpec.Network, field.NewPath("providerSpec", "network"))...) - - if providerSpec.NumCPUs < minVSphereCPU { - warnings = append(warnings, fmt.Sprintf("providerSpec.numCPUs: %d is missing or less than the minimum value (%d): nodes may not boot correctly", providerSpec.NumCPUs, minVSphereCPU)) - } - if providerSpec.MemoryMiB < minVSphereMemoryMiB { - warnings = append(warnings, fmt.Sprintf("providerSpec.memoryMiB: %d is missing or less than the recommended minimum value (%d): nodes may not boot correctly", providerSpec.MemoryMiB, minVSphereMemoryMiB)) - } - if providerSpec.DiskGiB < minVSphereDiskGiB { - warnings = append(warnings, fmt.Sprintf("providerSpec.diskGiB: %d is missing or less than the recommended minimum (%d): nodes may fail to start if disk size is too low", providerSpec.DiskGiB, minVSphereDiskGiB)) - } - - if providerSpec.UserDataSecret == nil { - errs = append(errs, field.Required(field.NewPath("providerSpec", "userDataSecret"), "userDataSecret must be provided")) - } else { - if providerSpec.UserDataSecret.Name == "" { - errs = append(errs, field.Required(field.NewPath("providerSpec", "userDataSecret", "name"), "name must be provided")) - } - } - - if providerSpec.CredentialsSecret == nil { - errs = append(errs, field.Required(field.NewPath("providerSpec", "credentialsSecret"), "credentialsSecret must be provided")) - } else { - if providerSpec.CredentialsSecret.Name == "" { - errs = append(errs, field.Required(field.NewPath("providerSpec", "credentialsSecret", "name"), "name must be provided")) - } else { - warnings = append(warnings, credentialsSecretExists(config.client, providerSpec.CredentialsSecret.Name, m.GetNamespace())...) - } - } - - if len(errs) > 0 { - return false, warnings, utilerrors.NewAggregate(errs) - } - return true, warnings, nil -} - -func validateVSphereWorkspace(workspace *machinev1.Workspace, parentPath *field.Path) ([]string, []error) { - if workspace == nil { - return []string{}, []error{field.Required(parentPath, "workspace must be provided")} - } - - var errs []error - var warnings []string - if workspace.Server == "" { - errs = append(errs, field.Required(parentPath.Child("server"), "server must be provided")) - } - if workspace.Datacenter == "" { - warnings = append(warnings, fmt.Sprintf("%s: datacenter is unset: if more than one datacenter is present, VMs cannot be created", parentPath.Child("datacenter"))) - } - if workspace.Folder != "" { - expectedPrefix := fmt.Sprintf("/%s/vm/", workspace.Datacenter) - if !strings.HasPrefix(workspace.Folder, expectedPrefix) { - errMsg := fmt.Sprintf("folder must be absolute path: expected prefix %q", expectedPrefix) - errs = append(errs, field.Invalid(parentPath.Child("folder"), workspace.Folder, errMsg)) - } - } - - return warnings, errs -} - -func validateVSphereNetwork(network machinev1.NetworkSpec, parentPath *field.Path) []error { - if len(network.Devices) == 0 { - return []error{field.Required(parentPath.Child("devices"), "at least 1 network device must be provided")} - } - - var errs []error - for i, spec := range network.Devices { - fldPath := parentPath.Child("devices").Index(i) - if spec.NetworkName == "" { - errs = append(errs, field.Required(fldPath.Child("networkName"), "networkName must be provided")) - } - } - - return errs -} - -func isAzureGovCloud(platformStatus *osconfigv1.PlatformStatus) bool { - return platformStatus != nil && platformStatus.Azure != nil && - platformStatus.Azure.CloudName != osconfigv1.AzurePublicCloud -} diff --git a/pkg/apis/machine/v1beta1/machine_webhook_test.go b/pkg/apis/machine/v1beta1/machine_webhook_test.go deleted file mode 100644 index d9854e5c0a..0000000000 --- a/pkg/apis/machine/v1beta1/machine_webhook_test.go +++ /dev/null @@ -1,2403 +0,0 @@ -package v1beta1 - -import ( - "context" - "encoding/json" - "fmt" - "reflect" - "runtime" - "testing" - - . "github.com/onsi/gomega" - osconfigv1 "github.com/openshift/api/config/v1" - machinev1 "github.com/openshift/api/machine/v1beta1" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/equality" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - kruntime "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" - "k8s.io/utils/pointer" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client/config" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/webhook" - yaml "sigs.k8s.io/yaml" -) - -var ( - plainDNS = &osconfigv1.DNS{Spec: osconfigv1.DNSSpec{}} - plainInfra = &osconfigv1.Infrastructure{ - Status: osconfigv1.InfrastructureStatus{ - PlatformStatus: &osconfigv1.PlatformStatus{}, - }, - } -) - -func TestMachineCreation(t *testing.T) { - g := NewWithT(t) - - // Override config getter - ctrl.GetConfig = func() (*rest.Config, error) { - return cfg, nil - } - defer func() { - ctrl.GetConfig = config.GetConfig - }() - - namespace := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: "machine-creation-test", - }, - } - g.Expect(c.Create(ctx, namespace)).To(Succeed()) - defer func() { - g.Expect(c.Delete(ctx, namespace)).To(Succeed()) - }() - - awsSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: defaultAWSCredentialsSecret, - Namespace: namespace.Name, - }, - } - vSphereSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: defaultVSphereCredentialsSecret, - Namespace: namespace.Name, - }, - } - GCPSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: defaultGCPCredentialsSecret, - Namespace: namespace.Name, - }, - } - azureSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: defaultAzureCredentialsSecret, - Namespace: defaultSecretNamespace, - }, - } - g.Expect(c.Create(ctx, awsSecret)).To(Succeed()) - g.Expect(c.Create(ctx, vSphereSecret)).To(Succeed()) - g.Expect(c.Create(ctx, GCPSecret)).To(Succeed()) - g.Expect(c.Create(ctx, azureSecret)).To(Succeed()) - defer func() { - g.Expect(c.Delete(ctx, awsSecret)).To(Succeed()) - g.Expect(c.Delete(ctx, vSphereSecret)).To(Succeed()) - g.Expect(c.Delete(ctx, GCPSecret)).To(Succeed()) - g.Expect(c.Delete(ctx, azureSecret)).To(Succeed()) - }() - - testCases := []struct { - name string - platformType osconfigv1.PlatformType - clusterID string - presetClusterID bool - expectedError string - disconnected bool - providerSpecValue *kruntime.RawExtension - }{ - { - name: "with AWS and a nil provider spec value", - platformType: osconfigv1.AWSPlatformType, - clusterID: "aws-cluster", - providerSpecValue: nil, - expectedError: "providerSpec.value: Required value: a value must be provided", - }, - { - name: "with AWS and no fields set", - platformType: osconfigv1.AWSPlatformType, - clusterID: "aws-cluster", - providerSpecValue: &kruntime.RawExtension{ - Object: &machinev1.AWSMachineProviderConfig{}, - }, - expectedError: "providerSpec.ami: Required value: expected providerSpec.ami.id to be populated", - }, - { - name: "with AWS and an AMI ID set", - platformType: osconfigv1.AWSPlatformType, - clusterID: "aws-cluster", - providerSpecValue: &kruntime.RawExtension{ - Object: &machinev1.AWSMachineProviderConfig{ - AMI: machinev1.AWSResourceReference{ - ID: pointer.StringPtr("ami"), - }, - }, - }, - expectedError: "", - }, - { - name: "with Azure and a nil provider spec value", - platformType: osconfigv1.AzurePlatformType, - clusterID: "azure-cluster", - providerSpecValue: nil, - expectedError: "providerSpec.value: Required value: a value must be provided", - }, - { - name: "with Azure and no fields set", - platformType: osconfigv1.AzurePlatformType, - clusterID: "azure-cluster", - providerSpecValue: &kruntime.RawExtension{ - Object: &machinev1.AzureMachineProviderSpec{}, - }, - expectedError: "providerSpec.osDisk.diskSizeGB: Invalid value: 0: diskSizeGB must be greater than zero and less than 32768", - }, - { - name: "with Azure and a disk size set", - platformType: osconfigv1.AzurePlatformType, - clusterID: "azure-cluster", - providerSpecValue: &kruntime.RawExtension{ - Object: &machinev1.AzureMachineProviderSpec{ - OSDisk: machinev1.OSDisk{ - DiskSizeGB: 128, - }, - }, - }, - expectedError: "", - }, - { - name: "with Azure disconnected installation request public IP", - platformType: osconfigv1.AzurePlatformType, - clusterID: "azure-cluster", - providerSpecValue: &kruntime.RawExtension{ - Object: &machinev1.AzureMachineProviderSpec{ - OSDisk: machinev1.OSDisk{ - DiskSizeGB: 128, - }, - PublicIP: true, - }, - }, - disconnected: true, - expectedError: "providerSpec.publicIP: Forbidden: publicIP is not allowed in Azure disconnected installation", - }, - { - name: "with Azure disconnected installation success", - platformType: osconfigv1.AzurePlatformType, - clusterID: "azure-cluster", - providerSpecValue: &kruntime.RawExtension{ - Object: &machinev1.AzureMachineProviderSpec{ - OSDisk: machinev1.OSDisk{ - DiskSizeGB: 128, - }, - }, - }, - disconnected: true, - }, - { - name: "with GCP and a nil provider spec value", - platformType: osconfigv1.GCPPlatformType, - clusterID: "gcp-cluster", - providerSpecValue: nil, - expectedError: "providerSpec.value: Required value: a value must be provided", - }, - { - name: "with GCP and no fields set", - platformType: osconfigv1.GCPPlatformType, - clusterID: "gcp-cluster", - providerSpecValue: &kruntime.RawExtension{ - Object: &machinev1.GCPMachineProviderSpec{}, - }, - expectedError: "providerSpec.region: Required value: region is required", - }, - { - name: "with GCP and the region and zone set", - platformType: osconfigv1.GCPPlatformType, - clusterID: "gcp-cluster", - providerSpecValue: &kruntime.RawExtension{ - Object: &machinev1.GCPMachineProviderSpec{ - Region: "region", - Zone: "region-zone", - }, - }, - expectedError: "", - }, - { - name: "with vSphere and a nil provider spec value", - platformType: osconfigv1.VSpherePlatformType, - clusterID: "vsphere-cluster", - providerSpecValue: nil, - expectedError: "providerSpec.value: Required value: a value must be provided", - }, - { - name: "with vSphere and no fields set", - platformType: osconfigv1.VSpherePlatformType, - clusterID: "vsphere-cluster", - providerSpecValue: &kruntime.RawExtension{ - Object: &machinev1.VSphereMachineProviderSpec{}, - }, - expectedError: "[providerSpec.template: Required value: template must be provided, providerSpec.workspace: Required value: workspace must be provided, providerSpec.network.devices: Required value: at least 1 network device must be provided]", - }, - { - name: "with vSphere and the template, workspace and network devices set", - platformType: osconfigv1.VSpherePlatformType, - clusterID: "vsphere-cluster", - presetClusterID: true, - providerSpecValue: &kruntime.RawExtension{ - Object: &machinev1.VSphereMachineProviderSpec{ - Template: "template", - Workspace: &machinev1.Workspace{ - Datacenter: "datacenter", - Server: "server", - }, - Network: machinev1.NetworkSpec{ - Devices: []machinev1.NetworkDeviceSpec{ - { - NetworkName: "networkName", - }, - }, - }, - }, - }, - expectedError: "", - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - gs := NewWithT(t) - - mgr, err := manager.New(cfg, manager.Options{ - MetricsBindAddress: "0", - Port: testEnv.WebhookInstallOptions.LocalServingPort, - CertDir: testEnv.WebhookInstallOptions.LocalServingCertDir, - }) - gs.Expect(err).ToNot(HaveOccurred()) - - platformStatus := &osconfigv1.PlatformStatus{ - Type: tc.platformType, - GCP: &osconfigv1.GCPPlatformStatus{ - ProjectID: "gcp-project-id", - }, - AWS: &osconfigv1.AWSPlatformStatus{ - Region: "region", - }, - } - infra := plainInfra.DeepCopy() - infra.Status.InfrastructureName = tc.clusterID - infra.Status.PlatformStatus = platformStatus - - dns := plainDNS.DeepCopy() - if !tc.disconnected { - dns.Spec.PublicZone = &osconfigv1.DNSZone{} - } - machineDefaulter := createMachineDefaulter(platformStatus, tc.clusterID) - machineValidator := createMachineValidator(infra, c, dns) - mgr.GetWebhookServer().Register(DefaultMachineMutatingHookPath, &webhook.Admission{Handler: machineDefaulter}) - mgr.GetWebhookServer().Register(DefaultMachineValidatingHookPath, &webhook.Admission{Handler: machineValidator}) - - mgrCtx, cancel := context.WithCancel(context.Background()) - stopped := make(chan struct{}) - go func() { - gs.Expect(mgr.Start(mgrCtx)).To(Succeed()) - close(stopped) - }() - defer func() { - cancel() - <-stopped - }() - - gs.Eventually(func() (bool, error) { - resp, err := insecureHTTPClient.Get(fmt.Sprintf("https://127.0.0.1:%d", testEnv.WebhookInstallOptions.LocalServingPort)) - if err != nil { - return false, err - } - return resp.StatusCode == 404, nil - }).Should(BeTrue()) - - m := &Machine{ - ObjectMeta: metav1.ObjectMeta{ - GenerateName: "machine-creation-", - Namespace: namespace.Name, - }, - Spec: MachineSpec{ - ProviderSpec: ProviderSpec{ - Value: tc.providerSpecValue, - }, - }, - } - - presetClusterID := "anything" - if tc.presetClusterID { - m.Labels = make(map[string]string) - m.Labels[MachineClusterIDLabel] = presetClusterID - } - - err = c.Create(ctx, m) - if err == nil { - defer func() { - gs.Expect(c.Delete(ctx, m)).To(Succeed()) - }() - } - - if tc.expectedError != "" { - gs.Expect(err).ToNot(BeNil()) - gs.Expect(apierrors.ReasonForError(err)).To(BeEquivalentTo(tc.expectedError)) - } else { - if tc.presetClusterID { - gs.Expect(m.Labels[MachineClusterIDLabel]).To(BeIdenticalTo(presetClusterID)) - } else { - gs.Expect(m.Labels[MachineClusterIDLabel]).To(BeIdenticalTo(tc.clusterID)) - } - gs.Expect(err).To(BeNil()) - } - }) - } -} - -func TestMachineUpdate(t *testing.T) { - awsClusterID := "aws-cluster" - awsRegion := "region" - defaultAWSProviderSpec := &machinev1.AWSMachineProviderConfig{ - AMI: machinev1.AWSResourceReference{ - ID: pointer.StringPtr("ami"), - }, - InstanceType: defaultAWSX86InstanceType, - UserDataSecret: &corev1.LocalObjectReference{Name: defaultUserDataSecret}, - CredentialsSecret: &corev1.LocalObjectReference{Name: defaultAWSCredentialsSecret}, - Placement: machinev1.Placement{ - Region: awsRegion, - }, - } - - azureClusterID := "azure-cluster" - defaultAzureProviderSpec := &machinev1.AzureMachineProviderSpec{ - Location: "location", - VMSize: defaultAzureVMSize, - Vnet: defaultAzureVnet(azureClusterID), - Subnet: defaultAzureSubnet(azureClusterID), - NetworkResourceGroup: defaultAzureNetworkResourceGroup(azureClusterID), - Image: machinev1.Image{ - ResourceID: defaultAzureImageResourceID(azureClusterID), - }, - ManagedIdentity: defaultAzureManagedIdentiy(azureClusterID), - ResourceGroup: defaultAzureResourceGroup(azureClusterID), - UserDataSecret: &corev1.SecretReference{ - Name: defaultUserDataSecret, - Namespace: defaultSecretNamespace, - }, - CredentialsSecret: &corev1.SecretReference{ - Name: defaultAzureCredentialsSecret, - Namespace: defaultSecretNamespace, - }, - OSDisk: machinev1.OSDisk{ - DiskSizeGB: 128, - OSType: defaultAzureOSDiskOSType, - ManagedDisk: machinev1.ManagedDiskParameters{ - StorageAccountType: defaultAzureOSDiskStorageType, - }, - }, - } - - gcpClusterID := "gcp-cluster" - defaultGCPProviderSpec := &machinev1.GCPMachineProviderSpec{ - Region: "region", - Zone: "region-zone", - MachineType: defaultGCPMachineType, - NetworkInterfaces: []*machinev1.GCPNetworkInterface{ - { - Network: defaultGCPNetwork(gcpClusterID), - Subnetwork: defaultGCPSubnetwork(gcpClusterID), - }, - }, - Disks: []*machinev1.GCPDisk{ - { - AutoDelete: true, - Boot: true, - SizeGB: defaultGCPDiskSizeGb, - Type: defaultGCPDiskType, - Image: defaultGCPDiskImage, - }, - }, - Tags: defaultGCPTags(gcpClusterID), - UserDataSecret: &corev1.LocalObjectReference{ - Name: defaultUserDataSecret, - }, - CredentialsSecret: &corev1.LocalObjectReference{ - Name: defaultGCPCredentialsSecret, - }, - } - vsphereClusterID := "vsphere-cluster" - defaultVSphereProviderSpec := &machinev1.VSphereMachineProviderSpec{ - Template: "template", - Workspace: &machinev1.Workspace{ - Datacenter: "datacenter", - Server: "server", - }, - Network: machinev1.NetworkSpec{ - Devices: []machinev1.NetworkDeviceSpec{ - { - NetworkName: "networkName", - }, - }, - }, - UserDataSecret: &corev1.LocalObjectReference{ - Name: defaultUserDataSecret, - }, - CredentialsSecret: &corev1.LocalObjectReference{ - Name: defaultVSphereCredentialsSecret, - }, - } - - g := NewWithT(t) - - // Override config getter - ctrl.GetConfig = func() (*rest.Config, error) { - return cfg, nil - } - defer func() { - ctrl.GetConfig = config.GetConfig - }() - - namespace := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: "machine-update-test", - }, - } - g.Expect(c.Create(ctx, namespace)).To(Succeed()) - defer func() { - g.Expect(c.Delete(ctx, namespace)).To(Succeed()) - }() - - awsSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: defaultAWSCredentialsSecret, - Namespace: namespace.Name, - }, - } - vSphereSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: defaultVSphereCredentialsSecret, - Namespace: namespace.Name, - }, - } - GCPSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: defaultGCPCredentialsSecret, - Namespace: namespace.Name, - }, - } - azureSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: defaultAzureCredentialsSecret, - Namespace: defaultSecretNamespace, - }, - } - g.Expect(c.Create(ctx, awsSecret)).To(Succeed()) - g.Expect(c.Create(ctx, vSphereSecret)).To(Succeed()) - g.Expect(c.Create(ctx, GCPSecret)).To(Succeed()) - g.Expect(c.Create(ctx, azureSecret)).To(Succeed()) - defer func() { - g.Expect(c.Delete(ctx, awsSecret)).To(Succeed()) - g.Expect(c.Delete(ctx, vSphereSecret)).To(Succeed()) - g.Expect(c.Delete(ctx, GCPSecret)).To(Succeed()) - g.Expect(c.Delete(ctx, azureSecret)).To(Succeed()) - }() - - testCases := []struct { - name string - platformType osconfigv1.PlatformType - clusterID string - expectedError string - baseProviderSpecValue *kruntime.RawExtension - updatedProviderSpecValue func() *kruntime.RawExtension - }{ - { - name: "with a valid AWS ProviderSpec", - platformType: osconfigv1.AWSPlatformType, - clusterID: awsClusterID, - baseProviderSpecValue: &kruntime.RawExtension{ - Object: defaultAWSProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *kruntime.RawExtension { - return &kruntime.RawExtension{ - Object: defaultAWSProviderSpec.DeepCopy(), - } - }, - expectedError: "", - }, - { - name: "with an AWS ProviderSpec, removing the instance type", - platformType: osconfigv1.AWSPlatformType, - clusterID: awsClusterID, - baseProviderSpecValue: &kruntime.RawExtension{ - Object: defaultAWSProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *kruntime.RawExtension { - object := defaultAWSProviderSpec.DeepCopy() - object.InstanceType = "" - return &kruntime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.instanceType: Required value: expected providerSpec.instanceType to be populated", - }, - { - name: "with an AWS ProviderSpec, removing the region", - platformType: osconfigv1.AWSPlatformType, - clusterID: awsClusterID, - baseProviderSpecValue: &kruntime.RawExtension{ - Object: defaultAWSProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *kruntime.RawExtension { - object := defaultAWSProviderSpec.DeepCopy() - object.Placement.Region = "" - return &kruntime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.placement.region: Required value: expected providerSpec.placement.region to be populated", - }, - { - name: "with an AWS ProviderSpec, removing the user data secret", - platformType: osconfigv1.AWSPlatformType, - clusterID: awsClusterID, - baseProviderSpecValue: &kruntime.RawExtension{ - Object: defaultAWSProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *kruntime.RawExtension { - object := defaultAWSProviderSpec.DeepCopy() - object.UserDataSecret = nil - return &kruntime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.userDataSecret: Required value: expected providerSpec.userDataSecret to be populated", - }, - { - name: "with a valid Azure ProviderSpec", - platformType: osconfigv1.AzurePlatformType, - clusterID: azureClusterID, - baseProviderSpecValue: &kruntime.RawExtension{ - Object: defaultAzureProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *kruntime.RawExtension { - return &kruntime.RawExtension{ - Object: defaultAzureProviderSpec.DeepCopy(), - } - }, - expectedError: "", - }, - { - name: "with an Azure ProviderSpec, removing the vm size", - platformType: osconfigv1.AzurePlatformType, - clusterID: azureClusterID, - baseProviderSpecValue: &kruntime.RawExtension{ - Object: defaultAzureProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *kruntime.RawExtension { - object := defaultAzureProviderSpec.DeepCopy() - object.VMSize = "" - return &kruntime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.vmSize: Required value: vmSize should be set to one of the supported Azure VM sizes", - }, - { - name: "with an Azure ProviderSpec, removing the subnet", - platformType: osconfigv1.AzurePlatformType, - clusterID: azureClusterID, - baseProviderSpecValue: &kruntime.RawExtension{ - Object: defaultAzureProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *kruntime.RawExtension { - object := defaultAzureProviderSpec.DeepCopy() - object.Subnet = "" - return &kruntime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.subnet: Required value: must provide a subnet when a virtual network is specified", - }, - { - name: "with an Azure ProviderSpec, removing the credentials secret", - platformType: osconfigv1.AzurePlatformType, - clusterID: azureClusterID, - baseProviderSpecValue: &kruntime.RawExtension{ - Object: defaultAzureProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *kruntime.RawExtension { - object := defaultAzureProviderSpec.DeepCopy() - object.CredentialsSecret = nil - return &kruntime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.credentialsSecret: Required value: credentialsSecret must be provided", - }, - { - name: "with a valid GCP ProviderSpec", - platformType: osconfigv1.GCPPlatformType, - clusterID: gcpClusterID, - baseProviderSpecValue: &kruntime.RawExtension{ - Object: defaultGCPProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *kruntime.RawExtension { - return &kruntime.RawExtension{ - Object: defaultGCPProviderSpec.DeepCopy(), - } - }, - expectedError: "", - }, - { - name: "with a GCP ProviderSpec, removing the region", - platformType: osconfigv1.GCPPlatformType, - clusterID: gcpClusterID, - baseProviderSpecValue: &kruntime.RawExtension{ - Object: defaultGCPProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *kruntime.RawExtension { - object := defaultGCPProviderSpec.DeepCopy() - object.Region = "" - return &kruntime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.region: Required value: region is required", - }, - { - name: "with a GCP ProviderSpec, and an invalid region", - platformType: osconfigv1.GCPPlatformType, - clusterID: gcpClusterID, - baseProviderSpecValue: &kruntime.RawExtension{ - Object: defaultGCPProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *kruntime.RawExtension { - object := defaultGCPProviderSpec.DeepCopy() - object.Zone = "zone" - return &kruntime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.zone: Invalid value: \"zone\": zone not in configured region (region)", - }, - { - name: "with a GCP ProviderSpec, removing the disks", - platformType: osconfigv1.GCPPlatformType, - clusterID: gcpClusterID, - baseProviderSpecValue: &kruntime.RawExtension{ - Object: defaultGCPProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *kruntime.RawExtension { - object := defaultGCPProviderSpec.DeepCopy() - object.Disks = nil - return &kruntime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.disks: Required value: at least 1 disk is required", - }, - { - name: "with a GCP ProviderSpec, removing the network interfaces", - platformType: osconfigv1.GCPPlatformType, - clusterID: gcpClusterID, - baseProviderSpecValue: &kruntime.RawExtension{ - Object: defaultGCPProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *kruntime.RawExtension { - object := defaultGCPProviderSpec.DeepCopy() - object.NetworkInterfaces = nil - return &kruntime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.networkInterfaces: Required value: at least 1 network interface is required", - }, - { - name: "with a valid VSphere ProviderSpec", - platformType: osconfigv1.VSpherePlatformType, - clusterID: vsphereClusterID, - baseProviderSpecValue: &kruntime.RawExtension{ - Object: defaultVSphereProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *kruntime.RawExtension { - return &kruntime.RawExtension{ - Object: defaultVSphereProviderSpec.DeepCopy(), - } - }, - expectedError: "", - }, - { - name: "with an VSphere ProviderSpec, removing the template", - platformType: osconfigv1.VSpherePlatformType, - clusterID: vsphereClusterID, - baseProviderSpecValue: &kruntime.RawExtension{ - Object: defaultVSphereProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *kruntime.RawExtension { - object := defaultVSphereProviderSpec.DeepCopy() - object.Template = "" - return &kruntime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.template: Required value: template must be provided", - }, - { - name: "with an VSphere ProviderSpec, removing the workspace server", - platformType: osconfigv1.VSpherePlatformType, - clusterID: vsphereClusterID, - baseProviderSpecValue: &kruntime.RawExtension{ - Object: defaultVSphereProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *kruntime.RawExtension { - object := defaultVSphereProviderSpec.DeepCopy() - object.Workspace.Server = "" - return &kruntime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.workspace.server: Required value: server must be provided", - }, - { - name: "with an VSphere ProviderSpec, removing the network devices", - platformType: osconfigv1.VSpherePlatformType, - clusterID: vsphereClusterID, - baseProviderSpecValue: &kruntime.RawExtension{ - Object: defaultVSphereProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *kruntime.RawExtension { - object := defaultVSphereProviderSpec.DeepCopy() - object.Network = machinev1.NetworkSpec{} - return &kruntime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.network.devices: Required value: at least 1 network device must be provided", - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - gs := NewWithT(t) - - mgr, err := manager.New(cfg, manager.Options{ - MetricsBindAddress: "0", - Port: testEnv.WebhookInstallOptions.LocalServingPort, - CertDir: testEnv.WebhookInstallOptions.LocalServingCertDir, - }) - gs.Expect(err).ToNot(HaveOccurred()) - - platformStatus := &osconfigv1.PlatformStatus{ - Type: tc.platformType, - AWS: &osconfigv1.AWSPlatformStatus{ - Region: awsRegion, - }, - } - - infra := &osconfigv1.Infrastructure{ - Status: osconfigv1.InfrastructureStatus{ - InfrastructureName: tc.clusterID, - PlatformStatus: platformStatus, - }, - } - machineDefaulter := createMachineDefaulter(platformStatus, tc.clusterID) - machineValidator := createMachineValidator(infra, c, plainDNS) - mgr.GetWebhookServer().Register(DefaultMachineMutatingHookPath, &webhook.Admission{Handler: machineDefaulter}) - mgr.GetWebhookServer().Register(DefaultMachineValidatingHookPath, &webhook.Admission{Handler: machineValidator}) - - mgrCtx, cancel := context.WithCancel(context.Background()) - stopped := make(chan struct{}) - go func() { - gs.Expect(mgr.Start(mgrCtx)).To(Succeed()) - close(stopped) - }() - defer func() { - cancel() - <-stopped - }() - - gs.Eventually(func() (bool, error) { - resp, err := insecureHTTPClient.Get(fmt.Sprintf("https://127.0.0.1:%d", testEnv.WebhookInstallOptions.LocalServingPort)) - if err != nil { - return false, err - } - return resp.StatusCode == 404, nil - }).Should(BeTrue()) - - m := &Machine{ - ObjectMeta: metav1.ObjectMeta{ - GenerateName: "machine-creation-", - Namespace: namespace.Name, - }, - Spec: MachineSpec{ - ProviderSpec: ProviderSpec{ - Value: tc.baseProviderSpecValue, - }, - }, - } - err = c.Create(ctx, m) - gs.Expect(err).ToNot(HaveOccurred()) - defer func() { - gs.Expect(c.Delete(ctx, m)).To(Succeed()) - }() - - m.Spec.ProviderSpec.Value = tc.updatedProviderSpecValue() - err = c.Update(ctx, m) - if tc.expectedError != "" { - gs.Expect(err).ToNot(BeNil()) - gs.Expect(apierrors.ReasonForError(err)).To(BeEquivalentTo(tc.expectedError)) - } else { - gs.Expect(err).To(BeNil()) - } - }) - } -} - -func TestValidateAWSProviderSpec(t *testing.T) { - namespace := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: "aws-validation-test", - }, - } - - testCases := []struct { - testCase string - modifySpec func(*machinev1.AWSMachineProviderConfig) - expectedError string - expectedOk bool - expectedWarnings []string - }{ - { - testCase: "with no ami values it fails", - modifySpec: func(p *machinev1.AWSMachineProviderConfig) { - p.AMI = machinev1.AWSResourceReference{} - }, - expectedOk: false, - expectedError: "providerSpec.ami: Required value: expected providerSpec.ami.id to be populated", - }, - { - testCase: "with no region values it fails", - modifySpec: func(p *machinev1.AWSMachineProviderConfig) { - p.Placement.Region = "" - }, - expectedOk: false, - expectedError: "providerSpec.placement.region: Required value: expected providerSpec.placement.region to be populated", - }, - { - testCase: "with no instanceType it fails", - modifySpec: func(p *machinev1.AWSMachineProviderConfig) { - p.InstanceType = "" - }, - expectedOk: false, - expectedError: "providerSpec.instanceType: Required value: expected providerSpec.instanceType to be populated", - }, - { - testCase: "with no user data secret it fails", - modifySpec: func(p *machinev1.AWSMachineProviderConfig) { - p.UserDataSecret = nil - }, - expectedOk: false, - expectedError: "providerSpec.userDataSecret: Required value: expected providerSpec.userDataSecret to be populated", - }, - { - testCase: "with no credentials secret it fails", - modifySpec: func(p *machinev1.AWSMachineProviderConfig) { - p.CredentialsSecret = nil - }, - expectedOk: false, - expectedError: "providerSpec.credentialsSecret: Required value: expected providerSpec.credentialsSecret to be populated", - }, - { - testCase: "when the credentials secret does not exist", - modifySpec: func(p *machinev1.AWSMachineProviderConfig) { - p.CredentialsSecret.Name = "does-not-exist" - }, - expectedOk: true, - expectedWarnings: []string{"providerSpec.credentialsSecret: Invalid value: \"does-not-exist\": not found. Expected CredentialsSecret to exist"}, - }, - { - testCase: "with no subnet values it fails", - modifySpec: func(p *machinev1.AWSMachineProviderConfig) { - p.Subnet = machinev1.AWSResourceReference{} - }, - expectedOk: true, - expectedWarnings: []string{"providerSpec.subnet: No subnet has been provided. Instances may be created in an unexpected subnet and may not join the cluster."}, - }, - { - testCase: "with all required values it succeeds", - expectedOk: true, - expectedError: "", - }, - { - testCase: "with valid tenancy field", - modifySpec: func(p *machinev1.AWSMachineProviderConfig) { - p.Placement.Tenancy = machinev1.DedicatedTenancy - }, - expectedOk: true, - }, - { - testCase: "with empty tenancy field", - modifySpec: func(p *machinev1.AWSMachineProviderConfig) { - p.Placement.Tenancy = "" - }, - expectedOk: true, - }, - { - testCase: "fail with invalid tenancy field", - modifySpec: func(p *machinev1.AWSMachineProviderConfig) { - p.Placement.Tenancy = "invalid" - }, - expectedOk: false, - expectedError: "providerSpec.tenancy: Invalid value: \"invalid\": Invalid providerSpec.tenancy, the only allowed options are: default, dedicated, host", - }, - { - testCase: "with no iam instance profile", - modifySpec: func(p *machinev1.AWSMachineProviderConfig) { - p.IAMInstanceProfile = nil - }, - expectedOk: true, - expectedWarnings: []string{"providerSpec.iamInstanceProfile: no IAM instance profile provided: nodes may be unable to join the cluster"}, - }, - { - testCase: "with double tag names, lists duplicated tags", - modifySpec: func(p *machinev1.AWSMachineProviderConfig) { - p.Tags = []machinev1.TagSpecification{ - { - Name: "Tag-A", - }, - { - Name: "Tag-B", - }, - { - Name: "Tag-C", - }, - { - Name: "Tag-A", - }, - { - Name: "Tag-B", - }, - } - }, - expectedOk: true, - expectedWarnings: []string{"providerSpec.tags: duplicated tag names (Tag-A,Tag-B): only the first value will be used."}, - }, - { - testCase: "with triplicated tag names, lists duplicated tag", - modifySpec: func(p *machinev1.AWSMachineProviderConfig) { - p.Tags = []machinev1.TagSpecification{ - { - Name: "Tag-A", - }, - { - Name: "Tag-A", - }, - { - Name: "Tag-A", - }, - } - }, - expectedOk: true, - expectedWarnings: []string{"providerSpec.tags: duplicated tag names (Tag-A): only the first value will be used."}, - }, - { - testCase: "with alternately cased tag names, AWS tags are case sensitive, does not list duplicated tags", - modifySpec: func(p *machinev1.AWSMachineProviderConfig) { - p.Tags = []machinev1.TagSpecification{ - { - Name: "Tag-A", - }, - { - Name: "Tag-a", - }, - { - Name: "tag-a", - }, - } - }, - expectedOk: true, - }, - { - testCase: "with AMI ARN set", - modifySpec: func(p *machinev1.AWSMachineProviderConfig) { - p.AMI = machinev1.AWSResourceReference{ - ID: pointer.StringPtr("ami"), - ARN: pointer.StringPtr("arn"), - } - }, - expectedOk: true, - expectedWarnings: []string{"can't use providerSpec.ami.arn, only providerSpec.ami.id can be used to reference AMI"}, - }, - { - testCase: "with AMI filters set", - modifySpec: func(p *machinev1.AWSMachineProviderConfig) { - p.AMI = machinev1.AWSResourceReference{ - ID: pointer.StringPtr("ami"), - Filters: []machinev1.Filter{ - { - Name: "filter", - }, - }, - } - }, - expectedOk: true, - expectedWarnings: []string{"can't use providerSpec.ami.filters, only providerSpec.ami.id can be used to reference AMI"}, - }, - } - - secret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: namespace.Name, - }, - } - c := fake.NewFakeClientWithScheme(scheme.Scheme, secret) - - infra := plainInfra.DeepCopy() - infra.Status.InfrastructureName = "clusterID" - infra.Status.PlatformStatus.Type = osconfigv1.AWSPlatformType - h := createMachineValidator(infra, c, plainDNS) - - for _, tc := range testCases { - t.Run(tc.testCase, func(t *testing.T) { - providerSpec := &machinev1.AWSMachineProviderConfig{ - AMI: machinev1.AWSResourceReference{ - ID: pointer.StringPtr("ami"), - }, - Placement: machinev1.Placement{ - Region: "region", - }, - InstanceType: "m5.large", - IAMInstanceProfile: &machinev1.AWSResourceReference{ - ID: pointer.StringPtr("profileID"), - }, - UserDataSecret: &corev1.LocalObjectReference{ - Name: "secret", - }, - CredentialsSecret: &corev1.LocalObjectReference{ - Name: "secret", - }, - SecurityGroups: []machinev1.AWSResourceReference{ - { - ID: pointer.StringPtr("sg"), - }, - }, - Subnet: machinev1.AWSResourceReference{ - ID: pointer.StringPtr("subnet"), - }, - } - if tc.modifySpec != nil { - tc.modifySpec(providerSpec) - } - - m := &Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace.Name, - }, - } - rawBytes, err := json.Marshal(providerSpec) - if err != nil { - t.Fatal(err) - } - m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} - - ok, warnings, err := h.webhookOperations(m, h.admissionConfig) - if ok != tc.expectedOk { - t.Errorf("expected: %v, got: %v", tc.expectedOk, ok) - } - - if err == nil { - if tc.expectedError != "" { - t.Errorf("expected: %q, got: %v", tc.expectedError, err) - } - } else { - if err.Error() != tc.expectedError { - t.Errorf("expected: %q, got: %q", tc.expectedError, err.Error()) - } - } - - if !reflect.DeepEqual(warnings, tc.expectedWarnings) { - t.Errorf("expected: %q, got: %q", tc.expectedWarnings, warnings) - } - }) - } -} - -func TestDefaultAWSProviderSpec(t *testing.T) { - - clusterID := "clusterID" - region := "region" - arch := defaultAWSX86InstanceType - if runtime.GOARCH == "arm64" { - arch = defaultAWSARMInstanceType - } - testCases := []struct { - testCase string - providerSpec *machinev1.AWSMachineProviderConfig - expectedProviderSpec *machinev1.AWSMachineProviderConfig - expectedError string - expectedOk bool - expectedWarnings []string - }{ - { - testCase: "it defaults Region, InstanceType, UserDataSecret and CredentialsSecret", - providerSpec: &machinev1.AWSMachineProviderConfig{ - AMI: machinev1.AWSResourceReference{}, - InstanceType: "", - UserDataSecret: nil, - CredentialsSecret: nil, - }, - expectedProviderSpec: &machinev1.AWSMachineProviderConfig{ - AMI: machinev1.AWSResourceReference{}, - InstanceType: arch, - UserDataSecret: &corev1.LocalObjectReference{Name: defaultUserDataSecret}, - CredentialsSecret: &corev1.LocalObjectReference{Name: defaultAWSCredentialsSecret}, - Placement: machinev1.Placement{ - Region: "region", - }, - }, - expectedOk: true, - expectedError: "", - expectedWarnings: nil, - }, - } - - platformStatus := &osconfigv1.PlatformStatus{ - Type: osconfigv1.AWSPlatformType, - AWS: &osconfigv1.AWSPlatformStatus{ - Region: region, - }, - } - h := createMachineDefaulter(platformStatus, clusterID) - - for _, tc := range testCases { - t.Run(tc.testCase, func(t *testing.T) { - m := &Machine{} - rawBytes, err := json.Marshal(tc.providerSpec) - if err != nil { - t.Fatal(err) - } - m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} - - ok, warnings, err := h.webhookOperations(m, h.admissionConfig) - if ok != tc.expectedOk { - t.Errorf("expected: %v, got: %v", tc.expectedOk, ok) - } - - gotProviderSpec := new(machinev1.AWSMachineProviderConfig) - if err := yaml.Unmarshal(m.Spec.ProviderSpec.Value.Raw, &gotProviderSpec); err != nil { - t.Fatal(err) - } - - if !equality.Semantic.DeepEqual(tc.expectedProviderSpec, gotProviderSpec) { - t.Errorf("expected: %+v, got: %+v", tc.expectedProviderSpec, gotProviderSpec) - } - if err == nil { - if tc.expectedError != "" { - t.Errorf("expected: %q, got: %v", tc.expectedError, err) - } - } else { - if err.Error() != tc.expectedError { - t.Errorf("expected: %q, got: %q", tc.expectedError, err.Error()) - } - } - - if !reflect.DeepEqual(warnings, tc.expectedWarnings) { - t.Errorf("expected: %q, got: %q", tc.expectedWarnings, warnings) - } - }) - } -} - -func TestValidateAzureProviderSpec(t *testing.T) { - namespace := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: "azure-validation-test", - }, - } - - testCases := []struct { - testCase string - modifySpec func(providerSpec *machinev1.AzureMachineProviderSpec) - azurePlatformStatus *osconfigv1.AzurePlatformStatus - expectedError string - expectedOk bool - expectedWarnings []string - }{ - { - testCase: "with no vmsize it fails", - modifySpec: func(p *machinev1.AzureMachineProviderSpec) { - p.VMSize = "" - }, - expectedOk: false, - expectedError: "providerSpec.vmSize: Required value: vmSize should be set to one of the supported Azure VM sizes", - }, - { - testCase: "with a vnet but no subnet it fails", - modifySpec: func(p *machinev1.AzureMachineProviderSpec) { - p.Vnet = "vnet" - p.Subnet = "" - p.NetworkResourceGroup = "nrg" - }, - expectedOk: false, - expectedError: "providerSpec.subnet: Required value: must provide a subnet when a virtual network is specified", - }, - { - testCase: "with a subnet but no vnet it fails", - modifySpec: func(p *machinev1.AzureMachineProviderSpec) { - p.Vnet = "" - p.Subnet = "subnet" - p.NetworkResourceGroup = "nrg" - }, - expectedOk: false, - expectedError: "providerSpec.vnet: Required value: must provide a virtual network when supplying subnets", - }, - { - testCase: "with no image it fails", - modifySpec: func(p *machinev1.AzureMachineProviderSpec) { - p.Image = machinev1.Image{} - }, - expectedOk: false, - expectedError: "providerSpec.image: Required value: an image reference must be provided", - }, - { - testCase: "with resourceId and other fields set it fails", - modifySpec: func(p *machinev1.AzureMachineProviderSpec) { - p.Image = machinev1.Image{ - ResourceID: "rid", - SKU: "sku-rand", - Offer: "base-offer", - Version: "1", - Publisher: "test", - } - }, - expectedOk: false, - expectedError: "providerSpec.image.resourceID: Required value: resourceID is already specified, other fields such as [Offer, Publisher, SKU, Version] should not be set", - }, - { - testCase: "with no offer it fails", - modifySpec: func(p *machinev1.AzureMachineProviderSpec) { - p.Image = machinev1.Image{ - Version: "1", - SKU: "sku-rand", - Publisher: "test", - } - }, - expectedOk: false, - expectedError: "providerSpec.image.Offer: Required value: Offer must be provided", - }, - { - testCase: "with no SKU it fails", - modifySpec: func(p *machinev1.AzureMachineProviderSpec) { - p.Image = machinev1.Image{ - Offer: "base-offer", - Version: "1", - Publisher: "test", - } - }, - expectedOk: false, - expectedError: "providerSpec.image.SKU: Required value: SKU must be provided", - }, - { - testCase: "with no Version it fails", - modifySpec: func(p *machinev1.AzureMachineProviderSpec) { - p.Image = machinev1.Image{ - SKU: "sku-rand", - Offer: "base-offer", - Publisher: "test", - } - }, - expectedOk: false, - expectedError: "providerSpec.image.Version: Required value: Version must be provided", - }, - { - testCase: "with no Publisher it fails", - modifySpec: func(p *machinev1.AzureMachineProviderSpec) { - p.Image = machinev1.Image{ - SKU: "sku-rand", - Offer: "base-offer", - Version: "1", - } - }, - expectedOk: false, - expectedError: "providerSpec.image.Publisher: Required value: Publisher must be provided", - }, - { - testCase: "with resourceID in image it succeeds", - modifySpec: func(p *machinev1.AzureMachineProviderSpec) { - p.Image = machinev1.Image{ - ResourceID: "rid", - } - }, - expectedOk: true, - }, - { - testCase: "with no user data secret it fails", - modifySpec: func(p *machinev1.AzureMachineProviderSpec) { - p.UserDataSecret = nil - }, - expectedOk: false, - expectedError: "providerSpec.userDataSecret: Required value: userDataSecret must be provided", - }, - { - testCase: "with no user data secret name it fails", - modifySpec: func(p *machinev1.AzureMachineProviderSpec) { - p.UserDataSecret = &corev1.SecretReference{} - }, - expectedOk: false, - expectedError: "providerSpec.userDataSecret.name: Required value: name must be provided", - }, - { - testCase: "with no credentials secret it fails", - modifySpec: func(p *machinev1.AzureMachineProviderSpec) { - p.CredentialsSecret = nil - }, - expectedOk: false, - expectedError: "providerSpec.credentialsSecret: Required value: credentialsSecret must be provided", - }, - { - testCase: "with no credentials secret namespace it fails", - modifySpec: func(p *machinev1.AzureMachineProviderSpec) { - p.CredentialsSecret = &corev1.SecretReference{ - Name: "name", - } - }, - expectedOk: false, - expectedError: "providerSpec.credentialsSecret.namespace: Required value: namespace must be provided", - }, - { - testCase: "when the credentials secret does not exist", - modifySpec: func(p *machinev1.AzureMachineProviderSpec) { - p.CredentialsSecret.Name = "does-not-exist" - }, - expectedOk: true, - expectedWarnings: []string{"providerSpec.credentialsSecret: Invalid value: \"does-not-exist\": not found. Expected CredentialsSecret to exist"}, - }, - { - testCase: "with no credentials secret name it fails", - modifySpec: func(p *machinev1.AzureMachineProviderSpec) { - p.CredentialsSecret = &corev1.SecretReference{ - Namespace: namespace.Name, - } - }, - expectedOk: false, - expectedError: "providerSpec.credentialsSecret.name: Required value: name must be provided", - }, - { - testCase: "with no os disk size it fails", - modifySpec: func(p *machinev1.AzureMachineProviderSpec) { - p.OSDisk = machinev1.OSDisk{ - OSType: "osType", - ManagedDisk: machinev1.ManagedDiskParameters{ - StorageAccountType: "storageAccountType", - }, - } - }, - expectedOk: false, - expectedError: "providerSpec.osDisk.diskSizeGB: Invalid value: 0: diskSizeGB must be greater than zero and less than 32768", - }, - { - testCase: "with all required fields it succeeds", - expectedOk: true, - expectedError: "", - }, - { - testCase: "with government cloud and spot VMs enabled", - modifySpec: func(p *machinev1.AzureMachineProviderSpec) { - p.SpotVMOptions = &machinev1.SpotVMOptions{} - }, - azurePlatformStatus: &osconfigv1.AzurePlatformStatus{ - CloudName: osconfigv1.AzureUSGovernmentCloud, - }, - expectedOk: true, - expectedWarnings: []string{"spot VMs may not be supported when using GovCloud region"}, - }, - { - testCase: "with public cloud and spot VMs enabled", - modifySpec: func(p *machinev1.AzureMachineProviderSpec) { - p.SpotVMOptions = &machinev1.SpotVMOptions{} - }, - azurePlatformStatus: &osconfigv1.AzurePlatformStatus{ - CloudName: osconfigv1.AzurePublicCloud, - }, - expectedOk: true, - }, - } - - for _, tc := range testCases { - t.Run(tc.testCase, func(t *testing.T) { - secret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "name", - Namespace: namespace.Name, - }, - } - c := fake.NewFakeClientWithScheme(scheme.Scheme, secret) - infra := plainInfra.DeepCopy() - infra.Status.InfrastructureName = "clusterID" - infra.Status.PlatformStatus.Type = osconfigv1.AzurePlatformType - infra.Status.PlatformStatus.Azure = tc.azurePlatformStatus - - h := createMachineValidator(infra, c, plainDNS) - - // create a valid spec that will then be 'broken' by modifySpec - providerSpec := &machinev1.AzureMachineProviderSpec{ - VMSize: "vmSize", - Image: machinev1.Image{ - ResourceID: "resourceID", - }, - UserDataSecret: &corev1.SecretReference{ - Name: "name", - }, - CredentialsSecret: &corev1.SecretReference{ - Name: "name", - Namespace: namespace.Name, - }, - OSDisk: machinev1.OSDisk{ - DiskSizeGB: 1, - }, - } - if tc.modifySpec != nil { - tc.modifySpec(providerSpec) - } - - m := &Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace.Name, - }, - } - rawBytes, err := json.Marshal(providerSpec) - if err != nil { - t.Fatal(err) - } - m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} - - ok, warnings, err := h.webhookOperations(m, h.admissionConfig) - if ok != tc.expectedOk { - t.Errorf("expected: %v, got: %v", tc.expectedOk, ok) - } - - if err == nil { - if tc.expectedError != "" { - t.Errorf("expected: %q, got: %v", tc.expectedError, err) - } - } else { - if err.Error() != tc.expectedError { - t.Errorf("expected: %q, got: %q", tc.expectedError, err.Error()) - } - } - - if !reflect.DeepEqual(warnings, tc.expectedWarnings) { - t.Errorf("expected: %q, got: %q", tc.expectedWarnings, warnings) - } - }) - } -} - -func TestDefaultAzureProviderSpec(t *testing.T) { - - clusterID := "clusterID" - testCases := []struct { - testCase string - providerSpec *machinev1.AzureMachineProviderSpec - modifyDefault func(*machinev1.AzureMachineProviderSpec) - expectedError string - expectedOk bool - expectedWarnings []string - }{ - { - testCase: "it defaults defaultable fields", - providerSpec: &machinev1.AzureMachineProviderSpec{}, - expectedOk: true, - expectedError: "", - }, - { - testCase: "it does not override azure image spec", - providerSpec: &machinev1.AzureMachineProviderSpec{ - Image: machinev1.Image{ - Offer: "test-offer", - SKU: "test-sku", - Publisher: "base-publisher", - Version: "1", - }, - }, - modifyDefault: func(p *machinev1.AzureMachineProviderSpec) { - p.Image = machinev1.Image{ - Offer: "test-offer", - SKU: "test-sku", - Publisher: "base-publisher", - Version: "1", - } - }, - expectedOk: true, - expectedError: "", - }, - { - testCase: "it does not override azure image ResourceID", - providerSpec: &machinev1.AzureMachineProviderSpec{ - Image: machinev1.Image{ - ResourceID: "rid", - }, - }, - modifyDefault: func(p *machinev1.AzureMachineProviderSpec) { - p.Image = machinev1.Image{ - ResourceID: "rid", - } - }, - expectedOk: true, - expectedError: "", - }, - { - testCase: "does not overwrite the network resource group if it already exists", - providerSpec: &machinev1.AzureMachineProviderSpec{ - NetworkResourceGroup: "nrg", - }, - modifyDefault: func(p *machinev1.AzureMachineProviderSpec) { - p.NetworkResourceGroup = "nrg" - }, - expectedOk: true, - expectedError: "", - }, - { - testCase: "does not overwrite the credentials secret namespace if they already exist", - providerSpec: &machinev1.AzureMachineProviderSpec{ - CredentialsSecret: &corev1.SecretReference{ - Namespace: "foo", - }, - }, - modifyDefault: func(p *machinev1.AzureMachineProviderSpec) { - p.CredentialsSecret.Namespace = "foo" - }, - expectedOk: true, - expectedError: "", - }, - { - testCase: "does not overwrite the secret names if they already exist", - providerSpec: &machinev1.AzureMachineProviderSpec{ - UserDataSecret: &corev1.SecretReference{ - Name: "foo", - }, - CredentialsSecret: &corev1.SecretReference{ - Name: "foo", - }, - }, - modifyDefault: func(p *machinev1.AzureMachineProviderSpec) { - p.UserDataSecret.Name = "foo" - p.CredentialsSecret.Name = "foo" - }, - expectedOk: true, - expectedError: "", - }, - } - - platformStatus := &osconfigv1.PlatformStatus{Type: osconfigv1.AzurePlatformType} - h := createMachineDefaulter(platformStatus, clusterID) - - for _, tc := range testCases { - t.Run(tc.testCase, func(t *testing.T) { - defaultProviderSpec := &machinev1.AzureMachineProviderSpec{ - VMSize: defaultAzureVMSize, - Vnet: defaultAzureVnet(clusterID), - Subnet: defaultAzureSubnet(clusterID), - Image: machinev1.Image{ - ResourceID: defaultAzureImageResourceID(clusterID), - }, - UserDataSecret: &corev1.SecretReference{ - Name: defaultUserDataSecret, - }, - CredentialsSecret: &corev1.SecretReference{ - Name: defaultAzureCredentialsSecret, - Namespace: defaultSecretNamespace, - }, - } - if tc.modifyDefault != nil { - tc.modifyDefault(defaultProviderSpec) - } - - m := &Machine{} - rawBytes, err := json.Marshal(tc.providerSpec) - if err != nil { - t.Fatal(err) - } - m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} - - ok, warnings, err := h.webhookOperations(m, h.admissionConfig) - if ok != tc.expectedOk { - t.Errorf("expected: %v, got: %v", tc.expectedOk, ok) - } - - gotProviderSpec := new(machinev1.AzureMachineProviderSpec) - if err := yaml.Unmarshal(m.Spec.ProviderSpec.Value.Raw, &gotProviderSpec); err != nil { - t.Fatal(err) - } - - if !equality.Semantic.DeepEqual(defaultProviderSpec, gotProviderSpec) { - t.Errorf("expected: %+v, got: %+v", defaultProviderSpec, gotProviderSpec) - } - if err == nil { - if tc.expectedError != "" { - t.Errorf("expected: %q, got: %v", tc.expectedError, err) - } - } else { - if err.Error() != tc.expectedError { - t.Errorf("expected: %q, got: %q", tc.expectedError, err.Error()) - } - } - - if !reflect.DeepEqual(warnings, tc.expectedWarnings) { - t.Errorf("expected: %q, got: %q", tc.expectedWarnings, warnings) - } - }) - } -} - -func TestValidateGCPProviderSpec(t *testing.T) { - namespace := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: "gcp-validation-test", - }, - } - - testCases := []struct { - testCase string - modifySpec func(*machinev1.GCPMachineProviderSpec) - expectedError string - expectedOk bool - expectedWarnings []string - }{ - { - testCase: "with no region", - modifySpec: func(p *machinev1.GCPMachineProviderSpec) { - p.Region = "" - }, - expectedOk: false, - expectedError: "providerSpec.region: Required value: region is required", - }, - { - testCase: "with no zone", - modifySpec: func(p *machinev1.GCPMachineProviderSpec) { - p.Zone = "" - }, - expectedOk: false, - expectedError: "providerSpec.zone: Invalid value: \"\": zone not in configured region (region)", - }, - { - testCase: "with an invalid zone", - modifySpec: func(p *machinev1.GCPMachineProviderSpec) { - p.Zone = "zone" - }, - expectedOk: false, - expectedError: "providerSpec.zone: Invalid value: \"zone\": zone not in configured region (region)", - }, - { - testCase: "with no machine type", - modifySpec: func(p *machinev1.GCPMachineProviderSpec) { - p.MachineType = "" - }, - expectedOk: false, - expectedError: "providerSpec.machineType: Required value: machineType should be set to one of the supported GCP machine types", - }, - { - testCase: "with no network interfaces", - modifySpec: func(p *machinev1.GCPMachineProviderSpec) { - p.NetworkInterfaces = nil - }, - expectedOk: false, - expectedError: "providerSpec.networkInterfaces: Required value: at least 1 network interface is required", - }, - { - testCase: "with a network interfaces is missing the network", - modifySpec: func(p *machinev1.GCPMachineProviderSpec) { - p.NetworkInterfaces = []*machinev1.GCPNetworkInterface{ - { - Network: "network", - Subnetwork: "subnetwork", - }, - { - Subnetwork: "subnetwork", - }, - } - }, - expectedOk: false, - expectedError: "providerSpec.networkInterfaces[1].network: Required value: network is required", - }, - { - testCase: "with a network interfaces is missing the subnetwork", - modifySpec: func(p *machinev1.GCPMachineProviderSpec) { - p.NetworkInterfaces = []*machinev1.GCPNetworkInterface{ - { - Network: "network", - Subnetwork: "subnetwork", - }, - { - Network: "network", - }, - } - }, - expectedOk: false, - expectedError: "providerSpec.networkInterfaces[1].subnetwork: Required value: subnetwork is required", - }, - { - testCase: "with no disks", - modifySpec: func(p *machinev1.GCPMachineProviderSpec) { - p.Disks = nil - }, - expectedOk: false, - expectedError: "providerSpec.disks: Required value: at least 1 disk is required", - }, - { - testCase: "with a disk that is too small", - modifySpec: func(p *machinev1.GCPMachineProviderSpec) { - p.Disks = []*machinev1.GCPDisk{ - { - SizeGB: 1, - }, - } - }, - expectedOk: false, - expectedError: "providerSpec.disks[0].sizeGb: Invalid value: 1: must be at least 16GB in size", - }, - { - testCase: "with a disk that is too large", - modifySpec: func(p *machinev1.GCPMachineProviderSpec) { - p.Disks = []*machinev1.GCPDisk{ - { - SizeGB: 100000, - }, - } - }, - expectedOk: false, - expectedError: "providerSpec.disks[0].sizeGb: Invalid value: 100000: exceeding maximum GCP disk size limit, must be below 65536", - }, - { - testCase: "with a disk type that is not supported", - modifySpec: func(p *machinev1.GCPMachineProviderSpec) { - p.Disks = []*machinev1.GCPDisk{ - { - SizeGB: 16, - Type: "invalid", - }, - } - }, - expectedOk: false, - expectedError: "providerSpec.disks[0].type: Unsupported value: \"invalid\": supported values: \"pd-ssd\", \"pd-standard\"", - }, - { - testCase: "with no service accounts", - modifySpec: func(p *machinev1.GCPMachineProviderSpec) { - p.ServiceAccounts = nil - }, - expectedOk: true, - expectedError: "", - expectedWarnings: []string{"providerSpec.serviceAccounts: no service account provided: nodes may be unable to join the cluster"}, - }, - { - testCase: "with multiple service accounts", - modifySpec: func(p *machinev1.GCPMachineProviderSpec) { - p.ServiceAccounts = []machinev1.GCPServiceAccount{ - {}, - {}, - } - }, - expectedOk: false, - expectedError: "providerSpec.serviceAccounts: Invalid value: \"2 service accounts supplied\": exactly 1 service account must be supplied", - }, - { - testCase: "with the service account's email missing", - modifySpec: func(p *machinev1.GCPMachineProviderSpec) { - p.ServiceAccounts = []machinev1.GCPServiceAccount{ - { - Scopes: []string{"scope"}, - }, - } - }, - expectedOk: false, - expectedError: "providerSpec.serviceAccounts[0].email: Required value: email is required", - }, - { - testCase: "with the service account's with no scopes", - modifySpec: func(p *machinev1.GCPMachineProviderSpec) { - p.ServiceAccounts = []machinev1.GCPServiceAccount{ - { - Email: "email", - }, - } - }, - expectedOk: false, - expectedError: "providerSpec.serviceAccounts[0].scopes: Required value: at least 1 scope is required", - }, - { - testCase: "with no user data secret", - modifySpec: func(p *machinev1.GCPMachineProviderSpec) { - p.UserDataSecret = nil - }, - expectedOk: false, - expectedError: "providerSpec.userDataSecret: Required value: userDataSecret must be provided", - }, - { - testCase: "with no user data secret name", - modifySpec: func(p *machinev1.GCPMachineProviderSpec) { - p.UserDataSecret = &corev1.LocalObjectReference{} - }, - expectedOk: false, - expectedError: "providerSpec.userDataSecret.name: Required value: name must be provided", - }, - { - testCase: "with no credentials data secret", - modifySpec: func(p *machinev1.GCPMachineProviderSpec) { - p.CredentialsSecret = nil - }, - expectedOk: false, - expectedError: "providerSpec.credentialsSecret: Required value: credentialsSecret must be provided", - }, - { - testCase: "when the credentials secret does not exist", - modifySpec: func(p *machinev1.GCPMachineProviderSpec) { - p.CredentialsSecret.Name = "does-not-exist" - }, - expectedOk: true, - expectedWarnings: []string{"providerSpec.credentialsSecret: Invalid value: \"does-not-exist\": not found. Expected CredentialsSecret to exist"}, - }, - { - testCase: "with no user data secret name", - modifySpec: func(p *machinev1.GCPMachineProviderSpec) { - p.CredentialsSecret = &corev1.LocalObjectReference{} - }, - expectedOk: false, - expectedError: "providerSpec.credentialsSecret.name: Required value: name must be provided", - }, - { - testCase: "with all required fields it succeeds", - expectedOk: true, - expectedError: "", - }, - } - - secret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "name", - Namespace: namespace.Name, - }, - } - c := fake.NewFakeClientWithScheme(scheme.Scheme, secret) - infra := plainInfra.DeepCopy() - infra.Status.InfrastructureName = "clusterID" - infra.Status.PlatformStatus.Type = osconfigv1.GCPPlatformType - h := createMachineValidator(infra, c, plainDNS) - - for _, tc := range testCases { - providerSpec := &machinev1.GCPMachineProviderSpec{ - Region: "region", - Zone: "region-zone", - ProjectID: "projectID", - MachineType: "machineType", - NetworkInterfaces: []*machinev1.GCPNetworkInterface{ - { - Network: "network", - Subnetwork: "subnetwork", - }, - }, - Disks: []*machinev1.GCPDisk{ - { - SizeGB: 16, - }, - }, - ServiceAccounts: []machinev1.GCPServiceAccount{ - { - Email: "email", - Scopes: []string{"scope"}, - }, - }, - UserDataSecret: &corev1.LocalObjectReference{ - Name: "name", - }, - CredentialsSecret: &corev1.LocalObjectReference{ - Name: "name", - }, - } - if tc.modifySpec != nil { - tc.modifySpec(providerSpec) - } - - t.Run(tc.testCase, func(t *testing.T) { - m := &Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace.Name, - }, - } - rawBytes, err := json.Marshal(providerSpec) - if err != nil { - t.Fatal(err) - } - m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} - - ok, warnings, err := h.webhookOperations(m, h.admissionConfig) - if ok != tc.expectedOk { - t.Errorf("expected: %v, got: %v", tc.expectedOk, ok) - } - - if err == nil { - if tc.expectedError != "" { - t.Errorf("expected: %q, got: %v", tc.expectedError, err) - } - } else { - if err.Error() != tc.expectedError { - t.Errorf("expected: %q, got: %q", tc.expectedError, err.Error()) - } - } - - if !reflect.DeepEqual(warnings, tc.expectedWarnings) { - t.Errorf("expected: %q, got: %q", tc.expectedWarnings, warnings) - } - }) - } -} - -func TestDefaultGCPProviderSpec(t *testing.T) { - - clusterID := "clusterID" - projectID := "projectID" - testCases := []struct { - testCase string - providerSpec *machinev1.GCPMachineProviderSpec - modifyDefault func(*machinev1.GCPMachineProviderSpec) - expectedError string - expectedOk bool - expectedWarnings []string - }{ - { - testCase: "it defaults defaultable fields", - providerSpec: &machinev1.GCPMachineProviderSpec{}, - expectedOk: true, - expectedError: "", - }, - { - testCase: "it does not overwrite disks which already have fields set", - providerSpec: &machinev1.GCPMachineProviderSpec{ - Disks: []*machinev1.GCPDisk{ - { - AutoDelete: false, - Boot: false, - SizeGB: 32, - }, - }, - }, - modifyDefault: func(p *machinev1.GCPMachineProviderSpec) { - p.Disks = []*machinev1.GCPDisk{ - { - AutoDelete: false, - Boot: false, - SizeGB: 32, - Type: defaultGCPDiskType, - Image: defaultGCPDiskImage, - }, - } - }, - expectedOk: true, - expectedError: "", - }, - } - - platformStatus := &osconfigv1.PlatformStatus{ - Type: osconfigv1.GCPPlatformType, - GCP: &osconfigv1.GCPPlatformStatus{ - ProjectID: projectID, - }, - } - h := createMachineDefaulter(platformStatus, clusterID) - - for _, tc := range testCases { - defaultProviderSpec := &machinev1.GCPMachineProviderSpec{ - MachineType: defaultGCPMachineType, - NetworkInterfaces: []*machinev1.GCPNetworkInterface{ - { - Network: defaultGCPNetwork(clusterID), - Subnetwork: defaultGCPSubnetwork(clusterID), - }, - }, - Disks: []*machinev1.GCPDisk{ - { - AutoDelete: true, - Boot: true, - SizeGB: defaultGCPDiskSizeGb, - Type: defaultGCPDiskType, - Image: defaultGCPDiskImage, - }, - }, - Tags: defaultGCPTags(clusterID), - UserDataSecret: &corev1.LocalObjectReference{ - Name: defaultUserDataSecret, - }, - CredentialsSecret: &corev1.LocalObjectReference{ - Name: defaultGCPCredentialsSecret, - }, - } - if tc.modifyDefault != nil { - tc.modifyDefault(defaultProviderSpec) - } - - t.Run(tc.testCase, func(t *testing.T) { - m := &Machine{} - rawBytes, err := json.Marshal(tc.providerSpec) - if err != nil { - t.Fatal(err) - } - m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} - - ok, warnings, err := h.webhookOperations(m, h.admissionConfig) - if ok != tc.expectedOk { - t.Errorf("expected: %v, got: %v", tc.expectedOk, ok) - } - - gotProviderSpec := new(machinev1.GCPMachineProviderSpec) - if err := yaml.Unmarshal(m.Spec.ProviderSpec.Value.Raw, &gotProviderSpec); err != nil { - t.Fatal(err) - } - - if !equality.Semantic.DeepEqual(defaultProviderSpec, gotProviderSpec) { - t.Errorf("expected: %+v, got: %+v", defaultProviderSpec, gotProviderSpec) - } - if err == nil { - if tc.expectedError != "" { - t.Errorf("expected: %q, got: %v", tc.expectedError, err) - } - } else { - if err.Error() != tc.expectedError { - t.Errorf("expected: %q, got: %q", tc.expectedError, err.Error()) - } - } - - if !reflect.DeepEqual(warnings, tc.expectedWarnings) { - t.Errorf("expected: %q, got: %q", tc.expectedWarnings, warnings) - } - }) - } -} - -func TestValidateVSphereProviderSpec(t *testing.T) { - namespace := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: "vsphere-validation-test", - }, - } - - testCases := []struct { - testCase string - modifySpec func(*machinev1.VSphereMachineProviderSpec) - expectedError string - expectedOk bool - expectedWarnings []string - }{ - { - testCase: "with no template provided", - modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { - p.Template = "" - }, - expectedOk: false, - expectedError: "providerSpec.template: Required value: template must be provided", - }, - { - testCase: "with no workspace provided", - modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { - p.Workspace = nil - }, - expectedOk: false, - expectedError: "providerSpec.workspace: Required value: workspace must be provided", - }, - { - testCase: "with no workspace server provided", - modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { - p.Workspace = &machinev1.Workspace{ - Datacenter: "datacenter", - } - }, - expectedOk: false, - expectedError: "providerSpec.workspace.server: Required value: server must be provided", - }, - { - testCase: "with no workspace datacenter provided", - modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { - p.Workspace = &machinev1.Workspace{ - Server: "server", - } - }, - expectedOk: true, - expectedError: "", - expectedWarnings: []string{"providerSpec.workspace.datacenter: datacenter is unset: if more than one datacenter is present, VMs cannot be created"}, - }, - { - testCase: "with a workspace folder outside of the current datacenter", - modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { - p.Workspace = &machinev1.Workspace{ - Server: "server", - Datacenter: "datacenter", - Folder: "/foo/vm/folder", - } - }, - expectedOk: false, - expectedError: "providerSpec.workspace.folder: Invalid value: \"/foo/vm/folder\": folder must be absolute path: expected prefix \"/datacenter/vm/\"", - }, - { - testCase: "with no network devices provided", - modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { - p.Network = machinev1.NetworkSpec{ - Devices: []machinev1.NetworkDeviceSpec{}, - } - }, - expectedOk: false, - expectedError: "providerSpec.network.devices: Required value: at least 1 network device must be provided", - }, - { - testCase: "with no network device name provided", - modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { - p.Network = machinev1.NetworkSpec{ - Devices: []machinev1.NetworkDeviceSpec{ - { - NetworkName: "networkName", - }, - {}, - }, - } - }, - expectedOk: false, - expectedError: "providerSpec.network.devices[1].networkName: Required value: networkName must be provided", - }, - { - testCase: "with too few CPUs provided", - modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { - p.NumCPUs = 1 - }, - expectedOk: true, - expectedError: "", - expectedWarnings: []string{"providerSpec.numCPUs: 1 is missing or less than the minimum value (2): nodes may not boot correctly"}, - }, - { - testCase: "with too little memory provided", - modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { - p.MemoryMiB = 1024 - }, - expectedOk: true, - expectedError: "", - expectedWarnings: []string{"providerSpec.memoryMiB: 1024 is missing or less than the recommended minimum value (2048): nodes may not boot correctly"}, - }, - { - testCase: "with too little disk size provided", - modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { - p.DiskGiB = 1 - }, - expectedOk: true, - expectedError: "", - expectedWarnings: []string{"providerSpec.diskGiB: 1 is missing or less than the recommended minimum (120): nodes may fail to start if disk size is too low"}, - }, - { - testCase: "with no user data secret provided", - modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { - p.UserDataSecret = nil - }, - expectedOk: false, - expectedError: "providerSpec.userDataSecret: Required value: userDataSecret must be provided", - }, - { - testCase: "with no user data secret name provided", - modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { - p.UserDataSecret = &corev1.LocalObjectReference{} - }, - expectedOk: false, - expectedError: "providerSpec.userDataSecret.name: Required value: name must be provided", - }, - { - testCase: "with no credentials secret provided", - modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { - p.CredentialsSecret = nil - }, - expectedOk: false, - expectedError: "providerSpec.credentialsSecret: Required value: credentialsSecret must be provided", - }, - { - testCase: "when the credentials secret does not exist", - modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { - p.CredentialsSecret.Name = "does-not-exist" - }, - expectedOk: true, - expectedWarnings: []string{"providerSpec.credentialsSecret: Invalid value: \"does-not-exist\": not found. Expected CredentialsSecret to exist"}, - }, - { - testCase: "with no credentials secret name provided", - modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { - p.CredentialsSecret = &corev1.LocalObjectReference{} - }, - expectedOk: false, - expectedError: "providerSpec.credentialsSecret.name: Required value: name must be provided", - }, - { - testCase: "with all required fields it succeeds", - expectedOk: true, - expectedError: "", - }, - { - testCase: "with numCPUs equal to 0", - modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { - p.NumCPUs = 0 - }, - expectedOk: true, - expectedWarnings: []string{"providerSpec.numCPUs: 0 is missing or less than the minimum value (2): nodes may not boot correctly"}, - }, - { - testCase: "with memoryMiB equal to 0", - modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { - p.MemoryMiB = 0 - }, - expectedOk: true, - expectedWarnings: []string{"providerSpec.memoryMiB: 0 is missing or less than the recommended minimum value (2048): nodes may not boot correctly"}, - }, - { - testCase: "with diskGiB equal to 0", - modifySpec: func(p *machinev1.VSphereMachineProviderSpec) { - p.DiskGiB = 0 - }, - expectedOk: true, - expectedWarnings: []string{"providerSpec.diskGiB: 0 is missing or less than the recommended minimum (120): nodes may fail to start if disk size is too low"}, - }, - } - - secret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "name", - Namespace: namespace.Name, - }, - } - c := fake.NewFakeClientWithScheme(scheme.Scheme, secret) - infra := plainInfra.DeepCopy() - infra.Status.InfrastructureName = "clusterID" - infra.Status.PlatformStatus.Type = osconfigv1.VSpherePlatformType - h := createMachineValidator(infra, c, plainDNS) - - for _, tc := range testCases { - t.Run(tc.testCase, func(t *testing.T) { - providerSpec := &machinev1.VSphereMachineProviderSpec{ - Template: "template", - Workspace: &machinev1.Workspace{ - Datacenter: "datacenter", - Server: "server", - }, - Network: machinev1.NetworkSpec{ - Devices: []machinev1.NetworkDeviceSpec{ - { - NetworkName: "networkName", - }, - }, - }, - UserDataSecret: &corev1.LocalObjectReference{ - Name: "name", - }, - CredentialsSecret: &corev1.LocalObjectReference{ - Name: "name", - }, - NumCPUs: minVSphereCPU, - MemoryMiB: minVSphereMemoryMiB, - DiskGiB: minVSphereDiskGiB, - } - if tc.modifySpec != nil { - tc.modifySpec(providerSpec) - } - - m := &Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace.Name, - }, - } - rawBytes, err := json.Marshal(providerSpec) - if err != nil { - t.Fatal(err) - } - m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} - - ok, warnings, err := h.webhookOperations(m, h.admissionConfig) - if ok != tc.expectedOk { - t.Errorf("expected: %v, got: %v", tc.expectedOk, ok) - } - - if err == nil { - if tc.expectedError != "" { - t.Errorf("expected: %q, got: %v", tc.expectedError, err) - } - } else { - if err.Error() != tc.expectedError { - t.Errorf("expected: %q, got: %q", tc.expectedError, err.Error()) - } - } - - if !reflect.DeepEqual(warnings, tc.expectedWarnings) { - t.Errorf("expected: %q, got: %q", tc.expectedWarnings, warnings) - } - }) - } -} - -func TestDefaultVSphereProviderSpec(t *testing.T) { - - clusterID := "clusterID" - testCases := []struct { - testCase string - providerSpec *machinev1.VSphereMachineProviderSpec - modifyDefault func(*machinev1.VSphereMachineProviderSpec) - expectedError string - expectedOk bool - expectedWarnings []string - }{ - { - testCase: "it defaults defaultable fields", - providerSpec: &machinev1.VSphereMachineProviderSpec{}, - expectedOk: true, - expectedError: "", - }, - } - - platformStatus := &osconfigv1.PlatformStatus{Type: osconfigv1.VSpherePlatformType} - h := createMachineDefaulter(platformStatus, clusterID) - - for _, tc := range testCases { - t.Run(tc.testCase, func(t *testing.T) { - defaultProviderSpec := &machinev1.VSphereMachineProviderSpec{ - UserDataSecret: &corev1.LocalObjectReference{ - Name: defaultUserDataSecret, - }, - CredentialsSecret: &corev1.LocalObjectReference{ - Name: defaultVSphereCredentialsSecret, - }, - } - if tc.modifyDefault != nil { - tc.modifyDefault(defaultProviderSpec) - } - - m := &Machine{} - rawBytes, err := json.Marshal(tc.providerSpec) - if err != nil { - t.Fatal(err) - } - m.Spec.ProviderSpec.Value = &kruntime.RawExtension{Raw: rawBytes} - - ok, warnings, err := h.webhookOperations(m, h.admissionConfig) - if ok != tc.expectedOk { - t.Errorf("expected: %v, got: %v", tc.expectedOk, ok) - } - - gotProviderSpec := new(machinev1.VSphereMachineProviderSpec) - if err := yaml.Unmarshal(m.Spec.ProviderSpec.Value.Raw, &gotProviderSpec); err != nil { - t.Fatal(err) - } - - if !equality.Semantic.DeepEqual(defaultProviderSpec, gotProviderSpec) { - t.Errorf("expected: %+v, got: %+v", defaultProviderSpec, gotProviderSpec) - } - if err == nil { - if tc.expectedError != "" { - t.Errorf("expected: %q, got: %v", tc.expectedError, err) - } - } else { - if err.Error() != tc.expectedError { - t.Errorf("expected: %q, got: %q", tc.expectedError, err.Error()) - } - } - - if !reflect.DeepEqual(warnings, tc.expectedWarnings) { - t.Errorf("expected: %q, got: %q", tc.expectedWarnings, warnings) - } - }) - } -} diff --git a/pkg/apis/machine/v1beta1/machinehealthcheck_types.go b/pkg/apis/machine/v1beta1/machinehealthcheck_types.go deleted file mode 100644 index e674e9776e..0000000000 --- a/pkg/apis/machine/v1beta1/machinehealthcheck_types.go +++ /dev/null @@ -1,134 +0,0 @@ -package v1beta1 - -import ( - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/intstr" -) - -// RemediationStrategyType contains remediation strategy type -type RemediationStrategyType string - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// MachineHealthCheck is the Schema for the machinehealthchecks API -// +kubebuilder:subresource:status -// +kubebuilder:resource:shortName=mhc;mhcs -// +k8s:openapi-gen=true -// +kubebuilder:printcolumn:name="MaxUnhealthy",type="string",JSONPath=".spec.maxUnhealthy",description="Maximum number of unhealthy machines allowed" -// +kubebuilder:printcolumn:name="ExpectedMachines",type="integer",JSONPath=".status.expectedMachines",description="Number of machines currently monitored" -// +kubebuilder:printcolumn:name="CurrentHealthy",type="integer",JSONPath=".status.currentHealthy",description="Current observed healthy machines" -type MachineHealthCheck struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - // Specification of machine health check policy - Spec MachineHealthCheckSpec `json:"spec,omitempty"` - - // Most recently observed status of MachineHealthCheck resource - Status MachineHealthCheckStatus `json:"status,omitempty"` -} - -func (m *MachineHealthCheck) GetConditions() Conditions { - return m.Status.Conditions -} - -func (m *MachineHealthCheck) SetConditions(conditions Conditions) { - m.Status.Conditions = conditions -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// MachineHealthCheckList contains a list of MachineHealthCheck -type MachineHealthCheckList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []MachineHealthCheck `json:"items"` -} - -// MachineHealthCheckSpec defines the desired state of MachineHealthCheck -type MachineHealthCheckSpec struct { - // Label selector to match machines whose health will be exercised. - // Note: An empty selector will match all machines. - Selector metav1.LabelSelector `json:"selector"` - - // UnhealthyConditions contains a list of the conditions that determine - // whether a node is considered unhealthy. The conditions are combined in a - // logical OR, i.e. if any of the conditions is met, the node is unhealthy. - // - // +kubebuilder:validation:MinItems=1 - UnhealthyConditions []UnhealthyCondition `json:"unhealthyConditions"` - - // Any farther remediation is only allowed if at most "MaxUnhealthy" machines selected by - // "selector" are not healthy. - // Expects either a postive integer value or a percentage value. - // Percentage values must be positive whole numbers and are capped at 100%. - // Both 0 and 0% are valid and will block all remediation. - // +kubebuilder:default:="100%" - // +kubebuilder:validation:XIntOrString - // +kubebuilder:validation:Pattern="^((100|[0-9]{1,2})%|[0-9]+)$" - MaxUnhealthy *intstr.IntOrString `json:"maxUnhealthy,omitempty"` - - // Machines older than this duration without a node will be considered to have - // failed and will be remediated. - // To prevent Machines without Nodes from being removed, disable startup checks - // by setting this value explicitly to "0". - // Expects an unsigned duration string of decimal numbers each with optional - // fraction and a unit suffix, eg "300ms", "1.5h" or "2h45m". - // Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - // +optional - // +kubebuilder:default:="10m" - // +kubebuilder:validation:Pattern="^0|([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$" - // +kubebuilder:validation:Type:=string - NodeStartupTimeout *metav1.Duration `json:"nodeStartupTimeout,omitempty"` - - // RemediationTemplate is a reference to a remediation template - // provided by an infrastructure provider. - // - // This field is completely optional, when filled, the MachineHealthCheck controller - // creates a new object from the template referenced and hands off remediation of the machine to - // a controller that lives outside of Machine API Operator. - // +optional - RemediationTemplate *corev1.ObjectReference `json:"remediationTemplate,omitempty"` -} - -// UnhealthyCondition represents a Node condition type and value with a timeout -// specified as a duration. When the named condition has been in the given -// status for at least the timeout value, a node is considered unhealthy. -type UnhealthyCondition struct { - // +kubebuilder:validation:Type=string - // +kubebuilder:validation:MinLength=1 - Type corev1.NodeConditionType `json:"type"` - - // +kubebuilder:validation:Type=string - // +kubebuilder:validation:MinLength=1 - Status corev1.ConditionStatus `json:"status"` - - // Expects an unsigned duration string of decimal numbers each with optional - // fraction and a unit suffix, eg "300ms", "1.5h" or "2h45m". - // Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - // +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$" - // +kubebuilder:validation:Type:=string - Timeout metav1.Duration `json:"timeout"` -} - -// MachineHealthCheckStatus defines the observed state of MachineHealthCheck -type MachineHealthCheckStatus struct { - // total number of machines counted by this machine health check - // +kubebuilder:validation:Minimum=0 - ExpectedMachines *int `json:"expectedMachines"` - - // total number of machines counted by this machine health check - // +kubebuilder:validation:Minimum=0 - CurrentHealthy *int `json:"currentHealthy" protobuf:"varint,4,opt,name=currentHealthy"` - - // RemediationsAllowed is the number of further remediations allowed by this machine health check before - // maxUnhealthy short circuiting will be applied - // +kubebuilder:validation:Minimum=0 - // +optional - RemediationsAllowed int32 `json:"remediationsAllowed"` - - // Conditions defines the current state of the MachineHealthCheck - Conditions Conditions `json:"conditions,omitempty"` -} diff --git a/pkg/apis/machine/v1beta1/machineset_types.go b/pkg/apis/machine/v1beta1/machineset_types.go deleted file mode 100644 index 2dd562b4eb..0000000000 --- a/pkg/apis/machine/v1beta1/machineset_types.go +++ /dev/null @@ -1,210 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -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 v1beta1 - -import ( - "log" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - metav1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation" - - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/util/validation/field" -) - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// MachineSet ensures that a specified number of machines replicas are running at any given time. -// +k8s:openapi-gen=true -// +kubebuilder:subresource:status -// +kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas,selectorpath=.status.labelSelector -// +kubebuilder:printcolumn:name="Desired",type="integer",JSONPath=".spec.replicas",description="Desired Replicas" -// +kubebuilder:printcolumn:name="Current",type="integer",JSONPath=".status.replicas",description="Current Replicas" -// +kubebuilder:printcolumn:name="Ready",type="integer",JSONPath=".status.readyReplicas",description="Ready Replicas" -// +kubebuilder:printcolumn:name="Available",type="string",JSONPath=".status.availableReplicas",description="Observed number of available replicas" -// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Machineset age" -type MachineSet struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec MachineSetSpec `json:"spec,omitempty"` - Status MachineSetStatus `json:"status,omitempty"` -} - -// MachineSetSpec defines the desired state of MachineSet -type MachineSetSpec struct { - // Replicas is the number of desired replicas. - // This is a pointer to distinguish between explicit zero and unspecified. - // Defaults to 1. - // +kubebuilder:default=1 - Replicas *int32 `json:"replicas,omitempty"` - - // MinReadySeconds is the minimum number of seconds for which a newly created machine should be ready. - // Defaults to 0 (machine will be considered available as soon as it is ready) - // +optional - MinReadySeconds int32 `json:"minReadySeconds,omitempty"` - - // DeletePolicy defines the policy used to identify nodes to delete when downscaling. - // Defaults to "Random". Valid values are "Random, "Newest", "Oldest" - // +kubebuilder:validation:Enum=Random;Newest;Oldest - DeletePolicy string `json:"deletePolicy,omitempty"` - - // Selector is a label query over machines that should match the replica count. - // Label keys and values that must match in order to be controlled by this MachineSet. - // It must match the machine template's labels. - // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors - Selector metav1.LabelSelector `json:"selector"` - - // Template is the object that describes the machine that will be created if - // insufficient replicas are detected. - // +optional - Template MachineTemplateSpec `json:"template,omitempty"` -} - -// MachineSetDeletePolicy defines how priority is assigned to nodes to delete when -// downscaling a MachineSet. Defaults to "Random". -type MachineSetDeletePolicy string - -const ( - // RandomMachineSetDeletePolicy prioritizes both Machines that have the annotation - // "cluster.k8s.io/delete-machine=yes" and Machines that are unhealthy - // (Status.ErrorReason or Status.ErrorMessage are set to a non-empty value). - // Finally, it picks Machines at random to delete. - RandomMachineSetDeletePolicy MachineSetDeletePolicy = "Random" - - // NewestMachineSetDeletePolicy prioritizes both Machines that have the annotation - // "cluster.k8s.io/delete-machine=yes" and Machines that are unhealthy - // (Status.ErrorReason or Status.ErrorMessage are set to a non-empty value). - // It then prioritizes the newest Machines for deletion based on the Machine's CreationTimestamp. - NewestMachineSetDeletePolicy MachineSetDeletePolicy = "Newest" - - // OldestMachineSetDeletePolicy prioritizes both Machines that have the annotation - // "cluster.k8s.io/delete-machine=yes" and Machines that are unhealthy - // (Status.ErrorReason or Status.ErrorMessage are set to a non-empty value). - // It then prioritizes the oldest Machines for deletion based on the Machine's CreationTimestamp. - OldestMachineSetDeletePolicy MachineSetDeletePolicy = "Oldest" -) - -// MachineTemplateSpec describes the data needed to create a Machine from a template -type MachineTemplateSpec struct { - // Standard object's metadata. - // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - // +optional - ObjectMeta `json:"metadata,omitempty"` - - // Specification of the desired behavior of the machine. - // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - // +optional - Spec MachineSpec `json:"spec,omitempty"` -} - -// MachineSetStatus defines the observed state of MachineSet -type MachineSetStatus struct { - // Replicas is the most recently observed number of replicas. - Replicas int32 `json:"replicas"` - - // The number of replicas that have labels matching the labels of the machine template of the MachineSet. - // +optional - FullyLabeledReplicas int32 `json:"fullyLabeledReplicas,omitempty"` - - // The number of ready replicas for this MachineSet. A machine is considered ready when the node has been created and is "Ready". - // +optional - ReadyReplicas int32 `json:"readyReplicas,omitempty"` - - // The number of available replicas (ready for at least minReadySeconds) for this MachineSet. - // +optional - AvailableReplicas int32 `json:"availableReplicas,omitempty"` - - // ObservedGeneration reflects the generation of the most recently observed MachineSet. - // +optional - ObservedGeneration int64 `json:"observedGeneration,omitempty"` - - // In the event that there is a terminal problem reconciling the - // replicas, both ErrorReason and ErrorMessage will be set. ErrorReason - // will be populated with a succinct value suitable for machine - // interpretation, while ErrorMessage will contain a more verbose - // string suitable for logging and human consumption. - // - // These fields should not be set for transitive errors that a - // controller faces that are expected to be fixed automatically over - // time (like service outages), but instead indicate that something is - // fundamentally wrong with the MachineTemplate's spec or the configuration of - // the machine controller, and that manual intervention is required. Examples - // of terminal errors would be invalid combinations of settings in the - // spec, values that are unsupported by the machine controller, or the - // responsible machine controller itself being critically misconfigured. - // - // Any transient errors that occur during the reconciliation of Machines - // can be added as events to the MachineSet object and/or logged in the - // controller's output. - // +optional - ErrorReason *MachineSetStatusError `json:"errorReason,omitempty"` - // +optional - ErrorMessage *string `json:"errorMessage,omitempty"` -} - -func (m *MachineSet) Validate() field.ErrorList { - errors := field.ErrorList{} - - // validate spec.selector and spec.template.labels - fldPath := field.NewPath("spec") - errors = append(errors, metav1validation.ValidateLabelSelector(&m.Spec.Selector, fldPath.Child("selector"))...) - if len(m.Spec.Selector.MatchLabels)+len(m.Spec.Selector.MatchExpressions) == 0 { - errors = append(errors, field.Invalid(fldPath.Child("selector"), m.Spec.Selector, "empty selector is not valid for MachineSet.")) - } - selector, err := metav1.LabelSelectorAsSelector(&m.Spec.Selector) - if err != nil { - errors = append(errors, field.Invalid(fldPath.Child("selector"), m.Spec.Selector, "invalid label selector.")) - } else { - labels := labels.Set(m.Spec.Template.Labels) - if !selector.Matches(labels) { - errors = append(errors, field.Invalid(fldPath.Child("template", "metadata", "labels"), m.Spec.Template.Labels, "`selector` does not match template `labels`")) - } - } - - return errors -} - -// DefaultingFunction sets default MachineSet field values -func (m *MachineSet) Default() { - log.Printf("Defaulting fields for MachineSet %s\n", m.Name) - - if m.Spec.Replicas == nil { - m.Spec.Replicas = new(int32) - *m.Spec.Replicas = 1 - } - - if len(m.Namespace) == 0 { - m.Namespace = metav1.NamespaceDefault - } - - if m.Spec.DeletePolicy == "" { - randomPolicy := string(RandomMachineSetDeletePolicy) - log.Printf("Defaulting to %s\n", randomPolicy) - m.Spec.DeletePolicy = randomPolicy - } -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// MachineSetList contains a list of MachineSet -type MachineSetList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []MachineSet `json:"items"` -} diff --git a/pkg/apis/machine/v1beta1/machineset_types_test.go b/pkg/apis/machine/v1beta1/machineset_types_test.go deleted file mode 100644 index 79ea98498b..0000000000 --- a/pkg/apis/machine/v1beta1/machineset_types_test.go +++ /dev/null @@ -1,138 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -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 v1beta1 - -import ( - "encoding/json" - "math/rand" - "reflect" - "testing" - "time" - - . "github.com/onsi/gomega" - "golang.org/x/net/context" - "k8s.io/apimachinery/pkg/api/apitesting/fuzzer" - metafuzzer "k8s.io/apimachinery/pkg/apis/meta/fuzzer" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/serializer" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/kubernetes/scheme" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -func TestStorageMachineSet(t *testing.T) { - key := types.NamespacedName{Name: "foo", Namespace: "default"} - created := &MachineSet{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}} - - // Test Create - fetched := &MachineSet{} - if err := c.Create(context.TODO(), created); err != nil { - t.Errorf("error creating machineset: %v", err) - } - - if err := c.Get(context.TODO(), key, fetched); err != nil { - t.Errorf("error getting machineset: %v", err) - } - if !reflect.DeepEqual(*fetched, *created) { - t.Error("fetched value not what was created") - } - - // Test Updating the Labels - updated := fetched.DeepCopy() - updated.Labels = map[string]string{"hello": "world"} - if err := c.Update(context.TODO(), updated); err != nil { - t.Errorf("error updating machineset: %v", err) - } - - if err := c.Get(context.TODO(), key, fetched); err != nil { - t.Errorf("error getting machineset: %v", err) - } - if !reflect.DeepEqual(*fetched, *updated) { - t.Error("fetched value not what was updated") - } - - // Test Delete - if err := c.Delete(context.TODO(), fetched); err != nil { - t.Errorf("error deleting machineset: %v", err) - } - if err := c.Get(context.TODO(), key, fetched); err == nil { - t.Error("expected error getting machineset") - } -} - -func TestDefaults(t *testing.T) { - ms := &MachineSet{ObjectMeta: metav1.ObjectMeta{Name: "foo"}} - ms.Default() - - expected := string(RandomMachineSetDeletePolicy) - got := ms.Spec.DeletePolicy - if got != expected { - t.Errorf("expected default machineset delete policy '%s', got '%s'", expected, got) - } -} - -func TestRoundTripMachineSet(t *testing.T) { - codecs := serializer.NewCodecFactory(scheme.Scheme) - seed := time.Now().UnixNano() - machineFuzzer := fuzzer.FuzzerFor(fuzzer.MergeFuzzerFuncs(metafuzzer.Funcs, machineFuzzerFuncs), rand.NewSource(seed), codecs) - ctx := context.Background() - g := NewWithT(t) - - for i := 0; i < 100; i++ { - machineSet := &MachineSet{ - ObjectMeta: metav1.ObjectMeta{ - GenerateName: "machineset-round-trip-test-", - Namespace: "default", - }, - } - // Fuzz the spec and status as those are the ones we need to check aren't - // losing data - spec := &MachineSetSpec{} - status := &MachineSetStatus{} - machineFuzzer.Fuzz(spec) - machineFuzzer.Fuzz(status) - - machineSet.Spec = *spec.DeepCopy() - g.Expect(c.Create(ctx, machineSet)).To(Succeed()) - machineSet.Status = *status.DeepCopy() - g.Expect(c.Status().Update(ctx, machineSet)).To(Succeed()) - - // Check the spec and status weren't modified during create - // - // Use JSON representation as order of fields in RawExtensions may change - // during a round trip - machineSetSpecJSON, err := json.Marshal(machineSet.Spec) - g.Expect(err).ToNot(HaveOccurred()) - specJSON, err := json.Marshal(*spec) - g.Expect(err).ToNot(HaveOccurred()) - g.Expect(machineSetSpecJSON).To(MatchJSON(specJSON)) - - machineSetStatusJSON, err := json.Marshal(machineSet.Status) - g.Expect(err).ToNot(HaveOccurred()) - statusJSON, err := json.Marshal(*status) - g.Expect(err).ToNot(HaveOccurred()) - g.Expect(machineSetStatusJSON).To(MatchJSON(statusJSON)) - - fetched := &MachineSet{} - key := client.ObjectKey{Namespace: machineSet.Namespace, Name: machineSet.Name} - g.Expect(c.Get(ctx, key, fetched)).To(Succeed()) - - // Check the spec and status haven't changed server side - g.Expect(fetched.Spec).To(Equal(machineSet.Spec)) - g.Expect(fetched.Status).To(Equal(machineSet.Status)) - } -} diff --git a/pkg/apis/machine/v1beta1/machineset_webhook.go b/pkg/apis/machine/v1beta1/machineset_webhook.go deleted file mode 100644 index 7d71ed5413..0000000000 --- a/pkg/apis/machine/v1beta1/machineset_webhook.go +++ /dev/null @@ -1,150 +0,0 @@ -package v1beta1 - -import ( - "context" - "encoding/json" - "net/http" - - osconfigv1 "github.com/openshift/api/config/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - utilerrors "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/klog/v2" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" -) - -// machineSetValidatorHandler validates MachineSet API resources. -// implements type Handler interface. -// https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/webhook/admission#Handler -type machineSetValidatorHandler struct { - *admissionHandler -} - -// machineSetDefaulterHandler defaults MachineSet API resources. -// implements type Handler interface. -// https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/webhook/admission#Handler -type machineSetDefaulterHandler struct { - *admissionHandler -} - -// NewMachineSetValidator returns a new machineSetValidatorHandler. -func NewMachineSetValidator(client client.Client) (*machineSetValidatorHandler, error) { - infra, err := getInfra() - if err != nil { - return nil, err - } - - dns, err := getDNS() - if err != nil { - return nil, err - } - - return createMachineSetValidator(infra, client, dns), nil -} - -func createMachineSetValidator(infra *osconfigv1.Infrastructure, client client.Client, dns *osconfigv1.DNS) *machineSetValidatorHandler { - admissionConfig := &admissionConfig{ - dnsDisconnected: dns.Spec.PublicZone == nil, - clusterID: infra.Status.InfrastructureName, - client: client, - } - return &machineSetValidatorHandler{ - admissionHandler: &admissionHandler{ - admissionConfig: admissionConfig, - webhookOperations: getMachineValidatorOperation(infra.Status.PlatformStatus.Type), - }, - } -} - -// NewMachineSetDefaulter returns a new machineSetDefaulterHandler. -func NewMachineSetDefaulter() (*machineSetDefaulterHandler, error) { - infra, err := getInfra() - if err != nil { - return nil, err - } - - return createMachineSetDefaulter(infra.Status.PlatformStatus, infra.Status.InfrastructureName), nil -} - -func createMachineSetDefaulter(platformStatus *osconfigv1.PlatformStatus, clusterID string) *machineSetDefaulterHandler { - return &machineSetDefaulterHandler{ - admissionHandler: &admissionHandler{ - admissionConfig: &admissionConfig{clusterID: clusterID}, - webhookOperations: getMachineDefaulterOperation(platformStatus), - }, - } -} - -// Handle handles HTTP requests for admission webhook servers. -func (h *machineSetValidatorHandler) Handle(ctx context.Context, req admission.Request) admission.Response { - ms := &MachineSet{} - - if err := h.decoder.Decode(req, ms); err != nil { - return admission.Errored(http.StatusBadRequest, err) - } - - klog.V(3).Infof("Validate webhook called for MachineSet: %s", ms.GetName()) - - ok, warnings, errs := h.validateMachineSet(ms) - if !ok { - return admission.Denied(errs.Error()).WithWarnings(warnings...) - } - - return admission.Allowed("MachineSet valid").WithWarnings(warnings...) -} - -// Handle handles HTTP requests for admission webhook servers. -func (h *machineSetDefaulterHandler) Handle(ctx context.Context, req admission.Request) admission.Response { - ms := &MachineSet{} - - if err := h.decoder.Decode(req, ms); err != nil { - return admission.Errored(http.StatusBadRequest, err) - } - - klog.V(3).Infof("Mutate webhook called for MachineSet: %s", ms.GetName()) - - ok, warnings, errs := h.defaultMachineSet(ms) - if !ok { - return admission.Denied(errs.Error()).WithWarnings(warnings...) - } - - marshaledMachineSet, err := json.Marshal(ms) - if err != nil { - return admission.Errored(http.StatusInternalServerError, err).WithWarnings(warnings...) - } - return admission.PatchResponseFromRaw(req.Object.Raw, marshaledMachineSet).WithWarnings(warnings...) -} - -func (h *machineSetValidatorHandler) validateMachineSet(ms *MachineSet) (bool, []string, utilerrors.Aggregate) { - var errs []error - - // Create a Machine from the MachineSet and validate the Machine template - m := &Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: ms.GetNamespace(), - }, - Spec: ms.Spec.Template.Spec, - } - ok, warnings, err := h.webhookOperations(m, h.admissionConfig) - if !ok { - errs = append(errs, err.Errors()...) - } - - if len(errs) > 0 { - return false, warnings, utilerrors.NewAggregate(errs) - } - return true, warnings, nil -} - -func (h *machineSetDefaulterHandler) defaultMachineSet(ms *MachineSet) (bool, []string, utilerrors.Aggregate) { - // Create a Machine from the MachineSet and default the Machine template - m := &Machine{Spec: ms.Spec.Template.Spec} - ok, warnings, err := h.webhookOperations(m, h.admissionConfig) - if !ok { - return false, warnings, utilerrors.NewAggregate(err.Errors()) - } - - // Restore the defaulted template - ms.Spec.Template.Spec = m.Spec - return true, warnings, nil -} diff --git a/pkg/apis/machine/v1beta1/machineset_webhook_test.go b/pkg/apis/machine/v1beta1/machineset_webhook_test.go deleted file mode 100644 index 6ae00e1137..0000000000 --- a/pkg/apis/machine/v1beta1/machineset_webhook_test.go +++ /dev/null @@ -1,829 +0,0 @@ -package v1beta1 - -import ( - "context" - "fmt" - "testing" - - . "github.com/onsi/gomega" - osconfigv1 "github.com/openshift/api/config/v1" - machinev1 "github.com/openshift/api/machine/v1beta1" - corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/rest" - "k8s.io/utils/pointer" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client/config" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/webhook" -) - -func TestMachineSetCreation(t *testing.T) { - g := NewWithT(t) - - // Override config getter - ctrl.GetConfig = func() (*rest.Config, error) { - return cfg, nil - } - defer func() { - ctrl.GetConfig = config.GetConfig - }() - - namespace := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: "machineset-creation-test", - }, - } - g.Expect(c.Create(ctx, namespace)).To(Succeed()) - defer func() { - g.Expect(c.Delete(ctx, namespace)).To(Succeed()) - }() - - awsSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: defaultAWSCredentialsSecret, - Namespace: namespace.Name, - }, - } - vSphereSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: defaultVSphereCredentialsSecret, - Namespace: namespace.Name, - }, - } - GCPSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: defaultGCPCredentialsSecret, - Namespace: namespace.Name, - }, - } - azureSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: defaultAzureCredentialsSecret, - Namespace: defaultSecretNamespace, - }, - } - g.Expect(c.Create(ctx, awsSecret)).To(Succeed()) - g.Expect(c.Create(ctx, vSphereSecret)).To(Succeed()) - g.Expect(c.Create(ctx, GCPSecret)).To(Succeed()) - g.Expect(c.Create(ctx, azureSecret)).To(Succeed()) - defer func() { - g.Expect(c.Delete(ctx, awsSecret)).To(Succeed()) - g.Expect(c.Delete(ctx, vSphereSecret)).To(Succeed()) - g.Expect(c.Delete(ctx, GCPSecret)).To(Succeed()) - g.Expect(c.Delete(ctx, azureSecret)).To(Succeed()) - }() - - testCases := []struct { - name string - platformType osconfigv1.PlatformType - clusterID string - expectedError string - disconnected bool - providerSpecValue *runtime.RawExtension - }{ - { - name: "with AWS and a nil provider spec value", - platformType: osconfigv1.AWSPlatformType, - clusterID: "aws-cluster", - providerSpecValue: nil, - expectedError: "providerSpec.value: Required value: a value must be provided", - }, - { - name: "with AWS and no fields set", - platformType: osconfigv1.AWSPlatformType, - clusterID: "aws-cluster", - providerSpecValue: &runtime.RawExtension{ - Object: &machinev1.AWSMachineProviderConfig{}, - }, - expectedError: "providerSpec.ami: Required value: expected providerSpec.ami.id to be populated", - }, - { - name: "with AWS and an AMI ID", - platformType: osconfigv1.AWSPlatformType, - clusterID: "aws-cluster", - providerSpecValue: &runtime.RawExtension{ - Object: &machinev1.AWSMachineProviderConfig{ - AMI: machinev1.AWSResourceReference{ - ID: pointer.StringPtr("ami"), - }, - }, - }, - expectedError: "", - }, - { - name: "with Azure and a nil provider spec value", - platformType: osconfigv1.AWSPlatformType, - clusterID: "azure-cluster", - providerSpecValue: nil, - expectedError: "providerSpec.value: Required value: a value must be provided", - }, - { - name: "with Azure and no fields set", - platformType: osconfigv1.AzurePlatformType, - clusterID: "azure-cluster", - providerSpecValue: &runtime.RawExtension{ - Object: &machinev1.AzureMachineProviderSpec{}, - }, - expectedError: "providerSpec.osDisk.diskSizeGB: Invalid value: 0: diskSizeGB must be greater than zero and less than 32768", - }, - { - name: "with Azure and a location and disk size set", - platformType: osconfigv1.AzurePlatformType, - clusterID: "azure-cluster", - providerSpecValue: &runtime.RawExtension{ - Object: &machinev1.AzureMachineProviderSpec{ - Location: "location", - OSDisk: machinev1.OSDisk{ - DiskSizeGB: 128, - }, - }, - }, - expectedError: "", - }, - { - name: "with Azure disconnected installation request public IP", - platformType: osconfigv1.AzurePlatformType, - clusterID: "azure-cluster", - providerSpecValue: &runtime.RawExtension{ - Object: &machinev1.AzureMachineProviderSpec{ - OSDisk: machinev1.OSDisk{ - DiskSizeGB: 128, - }, - PublicIP: true, - }, - }, - disconnected: true, - expectedError: "providerSpec.publicIP: Forbidden: publicIP is not allowed in Azure disconnected installation", - }, - { - name: "with Azure disconnected installation success", - platformType: osconfigv1.AzurePlatformType, - clusterID: "azure-cluster", - providerSpecValue: &runtime.RawExtension{ - Object: &machinev1.AzureMachineProviderSpec{ - OSDisk: machinev1.OSDisk{ - DiskSizeGB: 128, - }, - }, - }, - disconnected: true, - }, - { - name: "with GCP and a nil provider spec value", - platformType: osconfigv1.AWSPlatformType, - clusterID: "gcp-cluster", - providerSpecValue: nil, - expectedError: "providerSpec.value: Required value: a value must be provided", - }, - { - name: "with GCP and no fields set", - platformType: osconfigv1.GCPPlatformType, - clusterID: "gcp-cluster", - providerSpecValue: &runtime.RawExtension{ - Object: &machinev1.GCPMachineProviderSpec{}, - }, - expectedError: "providerSpec.region: Required value: region is required", - }, - { - name: "with GCP and the region and zone set", - platformType: osconfigv1.GCPPlatformType, - clusterID: "gcp-cluster", - providerSpecValue: &runtime.RawExtension{ - Object: &machinev1.GCPMachineProviderSpec{ - Region: "region", - Zone: "region-zone", - }, - }, - expectedError: "", - }, - { - name: "with vSphere and a nil provider spec value", - platformType: osconfigv1.VSpherePlatformType, - clusterID: "vsphere-cluster", - providerSpecValue: nil, - expectedError: "providerSpec.value: Required value: a value must be provided", - }, - { - name: "with vSphere and no fields set", - platformType: osconfigv1.VSpherePlatformType, - clusterID: "vsphere-cluster", - providerSpecValue: &runtime.RawExtension{ - Object: &machinev1.VSphereMachineProviderSpec{}, - }, - expectedError: "[providerSpec.template: Required value: template must be provided, providerSpec.workspace: Required value: workspace must be provided, providerSpec.network.devices: Required value: at least 1 network device must be provided]", - }, - { - name: "with vSphere and the template, workspace and network devices set", - platformType: osconfigv1.VSpherePlatformType, - clusterID: "vsphere-cluster", - providerSpecValue: &runtime.RawExtension{ - Object: &machinev1.VSphereMachineProviderSpec{ - Template: "template", - Workspace: &machinev1.Workspace{ - Datacenter: "datacenter", - Server: "server", - }, - Network: machinev1.NetworkSpec{ - Devices: []machinev1.NetworkDeviceSpec{ - { - NetworkName: "networkName", - }, - }, - }, - }, - }, - expectedError: "", - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - gs := NewWithT(t) - - mgr, err := manager.New(cfg, manager.Options{ - MetricsBindAddress: "0", - Port: testEnv.WebhookInstallOptions.LocalServingPort, - CertDir: testEnv.WebhookInstallOptions.LocalServingCertDir, - }) - gs.Expect(err).ToNot(HaveOccurred()) - - platformStatus := &osconfigv1.PlatformStatus{ - Type: tc.platformType, - GCP: &osconfigv1.GCPPlatformStatus{ - ProjectID: "gcp-project-id", - }, - AWS: &osconfigv1.AWSPlatformStatus{ - Region: "region", - }, - } - - infra := plainInfra.DeepCopy() - infra.Status.InfrastructureName = tc.clusterID - infra.Status.PlatformStatus = platformStatus - - dns := plainDNS.DeepCopy() - if !tc.disconnected { - dns.Spec.PublicZone = &osconfigv1.DNSZone{} - } - machineSetDefaulter := createMachineSetDefaulter(platformStatus, tc.clusterID) - machineSetValidator := createMachineSetValidator(infra, c, dns) - mgr.GetWebhookServer().Register(DefaultMachineSetMutatingHookPath, &webhook.Admission{Handler: machineSetDefaulter}) - mgr.GetWebhookServer().Register(DefaultMachineSetValidatingHookPath, &webhook.Admission{Handler: machineSetValidator}) - - mgrCtx, cancel := context.WithCancel(context.Background()) - stopped := make(chan struct{}) - go func() { - gs.Expect(mgr.Start(mgrCtx)).To(Succeed()) - close(stopped) - }() - defer func() { - cancel() - <-stopped - }() - - gs.Eventually(func() (bool, error) { - resp, err := insecureHTTPClient.Get(fmt.Sprintf("https://127.0.0.1:%d", testEnv.WebhookInstallOptions.LocalServingPort)) - if err != nil { - return false, err - } - return resp.StatusCode == 404, nil - }).Should(BeTrue()) - - ms := &MachineSet{ - ObjectMeta: metav1.ObjectMeta{ - GenerateName: "machineset-creation-", - Namespace: namespace.Name, - }, - Spec: MachineSetSpec{ - Template: MachineTemplateSpec{ - Spec: MachineSpec{ - ProviderSpec: ProviderSpec{ - Value: tc.providerSpecValue, - }, - }, - }, - }, - } - - err = c.Create(ctx, ms) - if err == nil { - defer func() { - gs.Expect(c.Delete(ctx, ms)).To(Succeed()) - }() - } - - if tc.expectedError != "" { - gs.Expect(err).ToNot(BeNil()) - gs.Expect(apierrors.ReasonForError(err)).To(BeEquivalentTo(tc.expectedError)) - } else { - gs.Expect(err).To(BeNil()) - } - }) - } -} - -func TestMachineSetUpdate(t *testing.T) { - awsClusterID := "aws-cluster" - awsRegion := "region" - defaultAWSProviderSpec := &machinev1.AWSMachineProviderConfig{ - AMI: machinev1.AWSResourceReference{ - ID: pointer.StringPtr("ami"), - }, - InstanceType: defaultAWSX86InstanceType, - UserDataSecret: &corev1.LocalObjectReference{Name: defaultUserDataSecret}, - CredentialsSecret: &corev1.LocalObjectReference{Name: defaultAWSCredentialsSecret}, - Placement: machinev1.Placement{ - Region: awsRegion, - }, - } - - azureClusterID := "azure-cluster" - defaultAzureProviderSpec := &machinev1.AzureMachineProviderSpec{ - Location: "location", - VMSize: defaultAzureVMSize, - Vnet: defaultAzureVnet(azureClusterID), - Subnet: defaultAzureSubnet(azureClusterID), - NetworkResourceGroup: defaultAzureNetworkResourceGroup(azureClusterID), - Image: machinev1.Image{ - ResourceID: defaultAzureImageResourceID(azureClusterID), - }, - ManagedIdentity: defaultAzureManagedIdentiy(azureClusterID), - ResourceGroup: defaultAzureResourceGroup(azureClusterID), - UserDataSecret: &corev1.SecretReference{ - Name: defaultUserDataSecret, - Namespace: defaultSecretNamespace, - }, - CredentialsSecret: &corev1.SecretReference{ - Name: defaultAzureCredentialsSecret, - Namespace: defaultSecretNamespace, - }, - OSDisk: machinev1.OSDisk{ - DiskSizeGB: 128, - OSType: defaultAzureOSDiskOSType, - ManagedDisk: machinev1.ManagedDiskParameters{ - StorageAccountType: defaultAzureOSDiskStorageType, - }, - }, - } - - gcpClusterID := "gcp-cluster" - defaultGCPProviderSpec := &machinev1.GCPMachineProviderSpec{ - Region: "region", - Zone: "region-zone", - MachineType: defaultGCPMachineType, - NetworkInterfaces: []*machinev1.GCPNetworkInterface{ - { - Network: defaultGCPNetwork(gcpClusterID), - Subnetwork: defaultGCPSubnetwork(gcpClusterID), - }, - }, - Disks: []*machinev1.GCPDisk{ - { - AutoDelete: true, - Boot: true, - SizeGB: defaultGCPDiskSizeGb, - Type: defaultGCPDiskType, - Image: defaultGCPDiskImage, - }, - }, - Tags: defaultGCPTags(gcpClusterID), - UserDataSecret: &corev1.LocalObjectReference{ - Name: defaultUserDataSecret, - }, - CredentialsSecret: &corev1.LocalObjectReference{ - Name: defaultGCPCredentialsSecret, - }, - } - - vsphereClusterID := "vsphere-cluster" - defaultVSphereProviderSpec := &machinev1.VSphereMachineProviderSpec{ - Template: "template", - Workspace: &machinev1.Workspace{ - Datacenter: "datacenter", - Server: "server", - }, - Network: machinev1.NetworkSpec{ - Devices: []machinev1.NetworkDeviceSpec{ - { - NetworkName: "networkName", - }, - }, - }, - UserDataSecret: &corev1.LocalObjectReference{ - Name: defaultUserDataSecret, - }, - CredentialsSecret: &corev1.LocalObjectReference{ - Name: defaultVSphereCredentialsSecret, - }, - } - - g := NewWithT(t) - - // Override config getter - ctrl.GetConfig = func() (*rest.Config, error) { - return cfg, nil - } - defer func() { - ctrl.GetConfig = config.GetConfig - }() - - namespace := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: "machineset-update-test", - }, - } - g.Expect(c.Create(ctx, namespace)).To(Succeed()) - defer func() { - g.Expect(c.Delete(ctx, namespace)).To(Succeed()) - }() - - awsSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: defaultAWSCredentialsSecret, - Namespace: namespace.Name, - }, - } - vSphereSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: defaultVSphereCredentialsSecret, - Namespace: namespace.Name, - }, - } - GCPSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: defaultGCPCredentialsSecret, - Namespace: namespace.Name, - }, - } - azureSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: defaultAzureCredentialsSecret, - Namespace: defaultSecretNamespace, - }, - } - g.Expect(c.Create(ctx, awsSecret)).To(Succeed()) - g.Expect(c.Create(ctx, vSphereSecret)).To(Succeed()) - g.Expect(c.Create(ctx, GCPSecret)).To(Succeed()) - g.Expect(c.Create(ctx, azureSecret)).To(Succeed()) - defer func() { - g.Expect(c.Delete(ctx, awsSecret)).To(Succeed()) - g.Expect(c.Delete(ctx, vSphereSecret)).To(Succeed()) - g.Expect(c.Delete(ctx, GCPSecret)).To(Succeed()) - g.Expect(c.Delete(ctx, azureSecret)).To(Succeed()) - }() - - testCases := []struct { - name string - platformType osconfigv1.PlatformType - clusterID string - expectedError string - baseProviderSpecValue *runtime.RawExtension - updatedProviderSpecValue func() *runtime.RawExtension - }{ - { - name: "with a valid AWS ProviderSpec", - platformType: osconfigv1.AWSPlatformType, - clusterID: awsClusterID, - baseProviderSpecValue: &runtime.RawExtension{ - Object: defaultAWSProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *runtime.RawExtension { - return &runtime.RawExtension{ - Object: defaultAWSProviderSpec.DeepCopy(), - } - }, - expectedError: "", - }, - { - name: "with an AWS ProviderSpec, removing the instance type", - platformType: osconfigv1.AWSPlatformType, - clusterID: awsClusterID, - baseProviderSpecValue: &runtime.RawExtension{ - Object: defaultAWSProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *runtime.RawExtension { - object := defaultAWSProviderSpec.DeepCopy() - object.InstanceType = "" - return &runtime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.instanceType: Required value: expected providerSpec.instanceType to be populated", - }, - { - name: "with an AWS ProviderSpec, removing the region", - platformType: osconfigv1.AWSPlatformType, - clusterID: awsClusterID, - baseProviderSpecValue: &runtime.RawExtension{ - Object: defaultAWSProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *runtime.RawExtension { - object := defaultAWSProviderSpec.DeepCopy() - object.Placement.Region = "" - return &runtime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.placement.region: Required value: expected providerSpec.placement.region to be populated", - }, - { - name: "with an AWS ProviderSpec, removing the user data secret", - platformType: osconfigv1.AWSPlatformType, - clusterID: awsClusterID, - baseProviderSpecValue: &runtime.RawExtension{ - Object: defaultAWSProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *runtime.RawExtension { - object := defaultAWSProviderSpec.DeepCopy() - object.UserDataSecret = nil - return &runtime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.userDataSecret: Required value: expected providerSpec.userDataSecret to be populated", - }, - { - name: "with a valid Azure ProviderSpec", - platformType: osconfigv1.AzurePlatformType, - clusterID: azureClusterID, - baseProviderSpecValue: &runtime.RawExtension{ - Object: defaultAzureProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *runtime.RawExtension { - return &runtime.RawExtension{ - Object: defaultAzureProviderSpec.DeepCopy(), - } - }, - expectedError: "", - }, - { - name: "with an Azure ProviderSpec, removing the vm size", - platformType: osconfigv1.AzurePlatformType, - clusterID: azureClusterID, - baseProviderSpecValue: &runtime.RawExtension{ - Object: defaultAzureProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *runtime.RawExtension { - object := defaultAzureProviderSpec.DeepCopy() - object.VMSize = "" - return &runtime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.vmSize: Required value: vmSize should be set to one of the supported Azure VM sizes", - }, - { - name: "with an Azure ProviderSpec, removing the subnet", - platformType: osconfigv1.AzurePlatformType, - clusterID: azureClusterID, - baseProviderSpecValue: &runtime.RawExtension{ - Object: defaultAzureProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *runtime.RawExtension { - object := defaultAzureProviderSpec.DeepCopy() - object.Subnet = "" - return &runtime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.subnet: Required value: must provide a subnet when a virtual network is specified", - }, - { - name: "with an Azure ProviderSpec, removing the credentials secret", - platformType: osconfigv1.AzurePlatformType, - clusterID: azureClusterID, - baseProviderSpecValue: &runtime.RawExtension{ - Object: defaultAzureProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *runtime.RawExtension { - object := defaultAzureProviderSpec.DeepCopy() - object.CredentialsSecret = nil - return &runtime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.credentialsSecret: Required value: credentialsSecret must be provided", - }, - { - name: "with a valid GCP ProviderSpec", - platformType: osconfigv1.GCPPlatformType, - clusterID: gcpClusterID, - baseProviderSpecValue: &runtime.RawExtension{ - Object: defaultGCPProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *runtime.RawExtension { - return &runtime.RawExtension{ - Object: defaultGCPProviderSpec.DeepCopy(), - } - }, - expectedError: "", - }, - { - name: "with a GCP ProviderSpec, removing the region", - platformType: osconfigv1.GCPPlatformType, - clusterID: gcpClusterID, - baseProviderSpecValue: &runtime.RawExtension{ - Object: defaultGCPProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *runtime.RawExtension { - object := defaultGCPProviderSpec.DeepCopy() - object.Region = "" - return &runtime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.region: Required value: region is required", - }, - { - name: "with a GCP ProviderSpec, and an invalid region", - platformType: osconfigv1.GCPPlatformType, - clusterID: gcpClusterID, - baseProviderSpecValue: &runtime.RawExtension{ - Object: defaultGCPProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *runtime.RawExtension { - object := defaultGCPProviderSpec.DeepCopy() - object.Zone = "zone" - return &runtime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.zone: Invalid value: \"zone\": zone not in configured region (region)", - }, - { - name: "with a GCP ProviderSpec, removing the disks", - platformType: osconfigv1.GCPPlatformType, - clusterID: gcpClusterID, - baseProviderSpecValue: &runtime.RawExtension{ - Object: defaultGCPProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *runtime.RawExtension { - object := defaultGCPProviderSpec.DeepCopy() - object.Disks = nil - return &runtime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.disks: Required value: at least 1 disk is required", - }, - { - name: "with a GCP ProviderSpec, removing the network interfaces", - platformType: osconfigv1.GCPPlatformType, - clusterID: gcpClusterID, - baseProviderSpecValue: &runtime.RawExtension{ - Object: defaultGCPProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *runtime.RawExtension { - object := defaultGCPProviderSpec.DeepCopy() - object.NetworkInterfaces = nil - return &runtime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.networkInterfaces: Required value: at least 1 network interface is required", - }, - { - name: "with a valid VSphere ProviderSpec", - platformType: osconfigv1.VSpherePlatformType, - clusterID: vsphereClusterID, - baseProviderSpecValue: &runtime.RawExtension{ - Object: defaultVSphereProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *runtime.RawExtension { - return &runtime.RawExtension{ - Object: defaultVSphereProviderSpec.DeepCopy(), - } - }, - expectedError: "", - }, - { - name: "with an VSphere ProviderSpec, removing the template", - platformType: osconfigv1.VSpherePlatformType, - clusterID: vsphereClusterID, - baseProviderSpecValue: &runtime.RawExtension{ - Object: defaultVSphereProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *runtime.RawExtension { - object := defaultVSphereProviderSpec.DeepCopy() - object.Template = "" - return &runtime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.template: Required value: template must be provided", - }, - { - name: "with an VSphere ProviderSpec, removing the workspace server", - platformType: osconfigv1.VSpherePlatformType, - clusterID: vsphereClusterID, - baseProviderSpecValue: &runtime.RawExtension{ - Object: defaultVSphereProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *runtime.RawExtension { - object := defaultVSphereProviderSpec.DeepCopy() - object.Workspace.Server = "" - return &runtime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.workspace.server: Required value: server must be provided", - }, - { - name: "with an VSphere ProviderSpec, removing the network devices", - platformType: osconfigv1.VSpherePlatformType, - clusterID: vsphereClusterID, - baseProviderSpecValue: &runtime.RawExtension{ - Object: defaultVSphereProviderSpec.DeepCopy(), - }, - updatedProviderSpecValue: func() *runtime.RawExtension { - object := defaultVSphereProviderSpec.DeepCopy() - object.Network = machinev1.NetworkSpec{} - return &runtime.RawExtension{ - Object: object, - } - }, - expectedError: "providerSpec.network.devices: Required value: at least 1 network device must be provided", - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - gs := NewWithT(t) - - mgr, err := manager.New(cfg, manager.Options{ - MetricsBindAddress: "0", - Port: testEnv.WebhookInstallOptions.LocalServingPort, - CertDir: testEnv.WebhookInstallOptions.LocalServingCertDir, - }) - gs.Expect(err).ToNot(HaveOccurred()) - - platformStatus := &osconfigv1.PlatformStatus{ - Type: tc.platformType, - AWS: &osconfigv1.AWSPlatformStatus{ - Region: awsRegion, - }, - } - - infra := plainInfra.DeepCopy() - infra.Status.InfrastructureName = tc.clusterID - infra.Status.PlatformStatus = platformStatus - - machineSetDefaulter := createMachineSetDefaulter(platformStatus, tc.clusterID) - machineSetValidator := createMachineSetValidator(infra, c, plainDNS) - mgr.GetWebhookServer().Register(DefaultMachineSetMutatingHookPath, &webhook.Admission{Handler: machineSetDefaulter}) - mgr.GetWebhookServer().Register(DefaultMachineSetValidatingHookPath, &webhook.Admission{Handler: machineSetValidator}) - - mgrCtx, cancel := context.WithCancel(context.Background()) - stopped := make(chan struct{}) - go func() { - gs.Expect(mgr.Start(mgrCtx)).To(Succeed()) - close(stopped) - }() - defer func() { - cancel() - <-stopped - }() - - gs.Eventually(func() (bool, error) { - resp, err := insecureHTTPClient.Get(fmt.Sprintf("https://127.0.0.1:%d", testEnv.WebhookInstallOptions.LocalServingPort)) - if err != nil { - return false, err - } - return resp.StatusCode == 404, nil - }).Should(BeTrue()) - - ms := &MachineSet{ - ObjectMeta: metav1.ObjectMeta{ - GenerateName: "machineset-update-", - Namespace: namespace.Name, - }, - Spec: MachineSetSpec{ - Template: MachineTemplateSpec{ - Spec: MachineSpec{ - ProviderSpec: ProviderSpec{ - Value: tc.baseProviderSpecValue, - }, - }, - }, - }, - } - err = c.Create(ctx, ms) - gs.Expect(err).ToNot(HaveOccurred()) - defer func() { - gs.Expect(c.Delete(ctx, ms)).To(Succeed()) - }() - - ms.Spec.Template.Spec.ProviderSpec.Value = tc.updatedProviderSpecValue() - err = c.Update(ctx, ms) - if tc.expectedError != "" { - gs.Expect(err).ToNot(BeNil()) - gs.Expect(apierrors.ReasonForError(err)).To(BeEquivalentTo(tc.expectedError)) - } else { - gs.Expect(err).To(BeNil()) - } - }) - } -} diff --git a/pkg/apis/machine/v1beta1/register.go b/pkg/apis/machine/v1beta1/register.go deleted file mode 100644 index 7aef2f415b..0000000000 --- a/pkg/apis/machine/v1beta1/register.go +++ /dev/null @@ -1,45 +0,0 @@ -// NOTE: Boilerplate only. Ignore this file. - -// Package v1alpha1 contains API Schema definitions for the healthchecking v1beta1 API group -// +k8s:deepcopy-gen=package,register -// +groupName=machine.openshift.io -package v1beta1 - -import ( - "github.com/openshift/machine-api-operator/pkg/apis/machine" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -// SchemeGroupVersion is group version used to register these objects -var SchemeGroupVersion = schema.GroupVersion{Group: machine.GroupName, Version: "v1beta1"} - -// Kind takes an unqualified kind and returns back a Group qualified GroupKind -func Kind(kind string) schema.GroupKind { - return SchemeGroupVersion.WithKind(kind).GroupKind() -} - -// Resource takes an unqualified resource and returns a Group qualified GroupResource -func Resource(resource string) schema.GroupResource { - return SchemeGroupVersion.WithResource(resource).GroupResource() -} - -var ( - SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) - AddToScheme = SchemeBuilder.AddToScheme -) - -// Adds the list of known types to Scheme. -func addKnownTypes(scheme *runtime.Scheme) error { - scheme.AddKnownTypes(SchemeGroupVersion, - &MachineHealthCheck{}, - &MachineHealthCheckList{}, - &Machine{}, - &MachineList{}, - &MachineSet{}, - &MachineSetList{}, - ) - metav1.AddToGroupVersion(scheme, SchemeGroupVersion) - return nil -} diff --git a/pkg/apis/machine/v1beta1/v1beta1_suite_test.go b/pkg/apis/machine/v1beta1/v1beta1_suite_test.go deleted file mode 100644 index b58a75c0e0..0000000000 --- a/pkg/apis/machine/v1beta1/v1beta1_suite_test.go +++ /dev/null @@ -1,221 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -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 v1beta1 - -import ( - "context" - "crypto/tls" - "log" - "net/http" - "os" - "path/filepath" - "testing" - "time" - - corev1 "k8s.io/api/core/v1" - - fuzz "github.com/google/gofuzz" - osconfigv1 "github.com/openshift/api/config/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer" - "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/envtest" -) - -var ( - cfg *rest.Config - c client.Client - ctx = context.Background() - testEnv *envtest.Environment - insecureHTTPClient = http.Client{ - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - }, - }, - } -) - -func TestMain(m *testing.M) { - testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{ - filepath.Join("..", "..", "..", "..", "install"), - filepath.Join("..", "..", "..", "..", "vendor", "github.com", "openshift", "api", "config", "v1"), - }, - WebhookInstallOptions: envtest.WebhookInstallOptions{ - MutatingWebhooks: []client.Object{NewMutatingWebhookConfiguration()}, - ValidatingWebhooks: []client.Object{NewValidatingWebhookConfiguration()}, - }, - } - - err := SchemeBuilder.AddToScheme(scheme.Scheme) - if err != nil { - log.Fatal(err) - } - - err = osconfigv1.AddToScheme(scheme.Scheme) - if err != nil { - log.Fatal(err) - } - - if cfg, err = testEnv.Start(); err != nil { - log.Fatal(err) - } - - if c, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}); err != nil { - log.Fatal(err) - } - - // Azure credentialsSecret is a secretRef defaulting to defaultSecretNamespace instead of a localObjectRef. - // This is so the tests can assume this namespace exists. - namespace := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: defaultSecretNamespace, - }, - } - if err = c.Create(ctx, namespace); err != nil { - log.Fatal(err) - } - - code := m.Run() - testEnv.Stop() - os.Exit(code) -} - -func machineFuzzerFuncs(codecs runtimeserializer.CodecFactory) []interface{} { - return []interface{}{ - // Fuzzer for pointer to metav1.Time - func(j **metav1.Time, c fuzz.Continue) { - if c.RandBool() { - t := &time.Time{} - c.Fuzz(t) - *j = &metav1.Time{Time: *t} - } else { - *j = nil - } - }, - // Fuzzer for MachineSpec to ensure empty embedded maps are nil - func(j *MachineSpec, c fuzz.Continue) { - c.FuzzNoCustom(j) - - // Fuzz ObjectMeta using custom fuzzer - c.Fuzz(&j.ObjectMeta) - - // Ensure embedded maps are nil if they have zero length - if len(j.ObjectMeta.Labels) == 0 { - j.ObjectMeta.Labels = nil - } - if len(j.ObjectMeta.Annotations) == 0 { - j.ObjectMeta.Annotations = nil - } - - // Ensure slices are nil if they are empty - if len(j.Taints) == 0 { - j.Taints = nil - } - }, - // Fuzzer for MachineStatus to ensure empty embedded maps are nil - func(j *MachineStatus, c fuzz.Continue) { - c.FuzzNoCustom(j) - - // Fuzz LastUpdated using custom fuzzer - c.Fuzz(&j.LastUpdated) - c.Fuzz(&j.LastOperation) - - // Ensure slices are nil if they are empty - if len(j.Addresses) == 0 { - j.Addresses = nil - } - if len(j.Conditions) == 0 { - j.Conditions = nil - } - }, - // Fuzzer for MachineSetSpec to ensure value restrictions are honoured - func(j *MachineSetSpec, c fuzz.Continue) { - c.FuzzNoCustom(j) - - // Fuzz Selector using custom fuzzer - c.Fuzz(&j.Selector) - if len(j.Selector.MatchLabels) == 0 { - j.Selector.MatchLabels = nil - } - if len(j.Selector.MatchExpressions) == 0 { - j.Selector.MatchExpressions = nil - } - - // Fuzz Template using custom fuzzers - c.Fuzz(&j.Template) - - // Ensure replicas is greater than zero - replicas := c.Rand.Int31() - j.Replicas = &replicas - - // Set DeletionPolicy to a valid value - validDeletionPolicy := []string{ - string(RandomMachineSetDeletePolicy), - string(NewestMachineSetDeletePolicy), - string(OldestMachineSetDeletePolicy), - } - j.DeletePolicy = validDeletionPolicy[c.Rand.Intn(len(validDeletionPolicy))] - }, - // Fuzzer for MachineSetStatus to ensure value restrictions are honoured - func(j *MachineSetStatus, c fuzz.Continue) { - c.FuzzNoCustom(j) - - // Ensure replicas is greater than zero - j.Replicas = c.Rand.Int31() - }, - // Fuzzer for ObjectMeta to ensure empty maps are nil - func(j *ObjectMeta, c fuzz.Continue) { - c.FuzzNoCustom(j) - - if len(j.Labels) == 0 { - j.Labels = nil - } else { - delete(j.Labels, "") - } - if len(j.Annotations) == 0 { - j.Annotations = nil - } else { - delete(j.Annotations, "") - } - if len(j.OwnerReferences) == 0 { - j.OwnerReferences = nil - } - }, - // Fuzzer for MachineTemplateSpec to ensure empty embedded maps are nil - func(j *MachineTemplateSpec, c fuzz.Continue) { - c.FuzzNoCustom(j) - - // Fuzz the ObjectMeta - c.Fuzz(&j.ObjectMeta) - - // Ensure embedded maps are nil if they have zero length - if len(j.ObjectMeta.Labels) == 0 { - j.ObjectMeta.Labels = nil - } - if len(j.ObjectMeta.Annotations) == 0 { - j.ObjectMeta.Annotations = nil - } - - // Fuzz the Spec - c.Fuzz(&j.Spec) - }, - } -} diff --git a/pkg/apis/machine/v1beta1/zz_generated.deepcopy.go b/pkg/apis/machine/v1beta1/zz_generated.deepcopy.go deleted file mode 100644 index abbd90b22b..0000000000 --- a/pkg/apis/machine/v1beta1/zz_generated.deepcopy.go +++ /dev/null @@ -1,571 +0,0 @@ -// +build !ignore_autogenerated - -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ - -// Code generated by controller-gen. DO NOT EDIT. - -package v1beta1 - -import ( - corev1 "k8s.io/api/core/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/intstr" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Condition) DeepCopyInto(out *Condition) { - *out = *in - in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Condition. -func (in *Condition) DeepCopy() *Condition { - if in == nil { - return nil - } - out := new(Condition) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in Conditions) DeepCopyInto(out *Conditions) { - { - in := &in - *out = make(Conditions, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Conditions. -func (in Conditions) DeepCopy() Conditions { - if in == nil { - return nil - } - out := new(Conditions) - in.DeepCopyInto(out) - return *out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *LastOperation) DeepCopyInto(out *LastOperation) { - *out = *in - if in.Description != nil { - in, out := &in.Description, &out.Description - *out = new(string) - **out = **in - } - if in.LastUpdated != nil { - in, out := &in.LastUpdated, &out.LastUpdated - *out = (*in).DeepCopy() - } - if in.State != nil { - in, out := &in.State, &out.State - *out = new(string) - **out = **in - } - if in.Type != nil { - in, out := &in.Type, &out.Type - *out = new(string) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LastOperation. -func (in *LastOperation) DeepCopy() *LastOperation { - if in == nil { - return nil - } - out := new(LastOperation) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Machine) DeepCopyInto(out *Machine) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Machine. -func (in *Machine) DeepCopy() *Machine { - if in == nil { - return nil - } - out := new(Machine) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Machine) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineHealthCheck) DeepCopyInto(out *MachineHealthCheck) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineHealthCheck. -func (in *MachineHealthCheck) DeepCopy() *MachineHealthCheck { - if in == nil { - return nil - } - out := new(MachineHealthCheck) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineHealthCheck) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineHealthCheckList) DeepCopyInto(out *MachineHealthCheckList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]MachineHealthCheck, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineHealthCheckList. -func (in *MachineHealthCheckList) DeepCopy() *MachineHealthCheckList { - if in == nil { - return nil - } - out := new(MachineHealthCheckList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineHealthCheckList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineHealthCheckSpec) DeepCopyInto(out *MachineHealthCheckSpec) { - *out = *in - in.Selector.DeepCopyInto(&out.Selector) - if in.UnhealthyConditions != nil { - in, out := &in.UnhealthyConditions, &out.UnhealthyConditions - *out = make([]UnhealthyCondition, len(*in)) - copy(*out, *in) - } - if in.MaxUnhealthy != nil { - in, out := &in.MaxUnhealthy, &out.MaxUnhealthy - *out = new(intstr.IntOrString) - **out = **in - } - if in.NodeStartupTimeout != nil { - in, out := &in.NodeStartupTimeout, &out.NodeStartupTimeout - *out = new(v1.Duration) - **out = **in - } - if in.RemediationTemplate != nil { - in, out := &in.RemediationTemplate, &out.RemediationTemplate - *out = new(corev1.ObjectReference) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineHealthCheckSpec. -func (in *MachineHealthCheckSpec) DeepCopy() *MachineHealthCheckSpec { - if in == nil { - return nil - } - out := new(MachineHealthCheckSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineHealthCheckStatus) DeepCopyInto(out *MachineHealthCheckStatus) { - *out = *in - if in.ExpectedMachines != nil { - in, out := &in.ExpectedMachines, &out.ExpectedMachines - *out = new(int) - **out = **in - } - if in.CurrentHealthy != nil { - in, out := &in.CurrentHealthy, &out.CurrentHealthy - *out = new(int) - **out = **in - } - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make(Conditions, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineHealthCheckStatus. -func (in *MachineHealthCheckStatus) DeepCopy() *MachineHealthCheckStatus { - if in == nil { - return nil - } - out := new(MachineHealthCheckStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineList) DeepCopyInto(out *MachineList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]Machine, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineList. -func (in *MachineList) DeepCopy() *MachineList { - if in == nil { - return nil - } - out := new(MachineList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineSet) DeepCopyInto(out *MachineSet) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSet. -func (in *MachineSet) DeepCopy() *MachineSet { - if in == nil { - return nil - } - out := new(MachineSet) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineSet) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineSetList) DeepCopyInto(out *MachineSetList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]MachineSet, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetList. -func (in *MachineSetList) DeepCopy() *MachineSetList { - if in == nil { - return nil - } - out := new(MachineSetList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineSetList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineSetSpec) DeepCopyInto(out *MachineSetSpec) { - *out = *in - if in.Replicas != nil { - in, out := &in.Replicas, &out.Replicas - *out = new(int32) - **out = **in - } - in.Selector.DeepCopyInto(&out.Selector) - in.Template.DeepCopyInto(&out.Template) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetSpec. -func (in *MachineSetSpec) DeepCopy() *MachineSetSpec { - if in == nil { - return nil - } - out := new(MachineSetSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineSetStatus) DeepCopyInto(out *MachineSetStatus) { - *out = *in - if in.ErrorReason != nil { - in, out := &in.ErrorReason, &out.ErrorReason - *out = new(MachineSetStatusError) - **out = **in - } - if in.ErrorMessage != nil { - in, out := &in.ErrorMessage, &out.ErrorMessage - *out = new(string) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetStatus. -func (in *MachineSetStatus) DeepCopy() *MachineSetStatus { - if in == nil { - return nil - } - out := new(MachineSetStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineSpec) DeepCopyInto(out *MachineSpec) { - *out = *in - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - if in.Taints != nil { - in, out := &in.Taints, &out.Taints - *out = make([]corev1.Taint, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - in.ProviderSpec.DeepCopyInto(&out.ProviderSpec) - if in.ProviderID != nil { - in, out := &in.ProviderID, &out.ProviderID - *out = new(string) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSpec. -func (in *MachineSpec) DeepCopy() *MachineSpec { - if in == nil { - return nil - } - out := new(MachineSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineStatus) DeepCopyInto(out *MachineStatus) { - *out = *in - if in.NodeRef != nil { - in, out := &in.NodeRef, &out.NodeRef - *out = new(corev1.ObjectReference) - **out = **in - } - if in.LastUpdated != nil { - in, out := &in.LastUpdated, &out.LastUpdated - *out = (*in).DeepCopy() - } - if in.ErrorReason != nil { - in, out := &in.ErrorReason, &out.ErrorReason - *out = new(MachineStatusError) - **out = **in - } - if in.ErrorMessage != nil { - in, out := &in.ErrorMessage, &out.ErrorMessage - *out = new(string) - **out = **in - } - if in.ProviderStatus != nil { - in, out := &in.ProviderStatus, &out.ProviderStatus - *out = new(runtime.RawExtension) - (*in).DeepCopyInto(*out) - } - if in.Addresses != nil { - in, out := &in.Addresses, &out.Addresses - *out = make([]corev1.NodeAddress, len(*in)) - copy(*out, *in) - } - if in.LastOperation != nil { - in, out := &in.LastOperation, &out.LastOperation - *out = new(LastOperation) - (*in).DeepCopyInto(*out) - } - if in.Phase != nil { - in, out := &in.Phase, &out.Phase - *out = new(string) - **out = **in - } - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make(Conditions, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineStatus. -func (in *MachineStatus) DeepCopy() *MachineStatus { - if in == nil { - return nil - } - out := new(MachineStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineTemplateSpec) DeepCopyInto(out *MachineTemplateSpec) { - *out = *in - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineTemplateSpec. -func (in *MachineTemplateSpec) DeepCopy() *MachineTemplateSpec { - if in == nil { - return nil - } - out := new(MachineTemplateSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ObjectMeta) DeepCopyInto(out *ObjectMeta) { - *out = *in - if in.Labels != nil { - in, out := &in.Labels, &out.Labels - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - if in.Annotations != nil { - in, out := &in.Annotations, &out.Annotations - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - if in.OwnerReferences != nil { - in, out := &in.OwnerReferences, &out.OwnerReferences - *out = make([]v1.OwnerReference, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectMeta. -func (in *ObjectMeta) DeepCopy() *ObjectMeta { - if in == nil { - return nil - } - out := new(ObjectMeta) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProviderSpec) DeepCopyInto(out *ProviderSpec) { - *out = *in - if in.Value != nil { - in, out := &in.Value, &out.Value - *out = new(runtime.RawExtension) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderSpec. -func (in *ProviderSpec) DeepCopy() *ProviderSpec { - if in == nil { - return nil - } - out := new(ProviderSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *UnhealthyCondition) DeepCopyInto(out *UnhealthyCondition) { - *out = *in - out.Timeout = in.Timeout -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UnhealthyCondition. -func (in *UnhealthyCondition) DeepCopy() *UnhealthyCondition { - if in == nil { - return nil - } - out := new(UnhealthyCondition) - in.DeepCopyInto(out) - return out -} diff --git a/pkg/apis/vsphereprovider/addtoscheme_vsphereprovider_v1beta1.go b/pkg/apis/vsphereprovider/addtoscheme_vsphereprovider_v1beta1.go deleted file mode 100644 index 088adfa1aa..0000000000 --- a/pkg/apis/vsphereprovider/addtoscheme_vsphereprovider_v1beta1.go +++ /dev/null @@ -1,10 +0,0 @@ -package apis - -import ( - "github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/v1beta1" -) - -func init() { - // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back - AddToSchemes = append(AddToSchemes, v1beta1.SchemeBuilder.AddToScheme) -} diff --git a/pkg/apis/vsphereprovider/apis.go b/pkg/apis/vsphereprovider/apis.go deleted file mode 100644 index 3b340c70b7..0000000000 --- a/pkg/apis/vsphereprovider/apis.go +++ /dev/null @@ -1,19 +0,0 @@ -// Generate deepcopy for apis -//go:generate go run ../../../vendor/sigs.k8s.io/controller-tools/cmd/controller-gen paths=./... object:headerFile=../../../hack/boilerplate.go.txt,year=2019 -// Ensure generated code is goimports compliant -//go:generate goimports -w ./v1beta1/zz_generated.deepcopy.go - -// Package apis contains Kubernetes API groups. -package apis - -import ( - "k8s.io/apimachinery/pkg/runtime" -) - -// AddToSchemes may be used to add all resources defined in the project to a Scheme -var AddToSchemes runtime.SchemeBuilder - -// AddToScheme adds all Resources to the Scheme -func AddToScheme(s *runtime.Scheme) error { - return AddToSchemes.AddToScheme(s) -} diff --git a/pkg/apis/vsphereprovider/v1beta1/doc.go b/pkg/apis/vsphereprovider/v1beta1/doc.go deleted file mode 100644 index d59eebf3d6..0000000000 --- a/pkg/apis/vsphereprovider/v1beta1/doc.go +++ /dev/null @@ -1,7 +0,0 @@ -// Package v1beta1 contains API Schema definitions for the vsphereprovider v1beta1 API group -// +k8s:openapi-gen=true -// +k8s:deepcopy-gen=package,register -// +k8s:conversion-gen=github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider -// +k8s:defaulter-gen=TypeMeta -// +groupName=vsphereprovider.machine.openshift.io -package v1beta1 diff --git a/pkg/apis/vsphereprovider/v1beta1/register.go b/pkg/apis/vsphereprovider/v1beta1/register.go deleted file mode 100644 index 741becbf38..0000000000 --- a/pkg/apis/vsphereprovider/v1beta1/register.go +++ /dev/null @@ -1,90 +0,0 @@ -// Package v1beta1 contains API Schema definitions for the vsphereprovider v1beta1 API group -// +k8s:openapi-gen=true -// +k8s:deepcopy-gen=package,register -// +k8s:conversion-gen=github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider -// +k8s:defaulter-gen=TypeMeta -// +groupName=vsphereprovider.machine.openshift.io -package v1beta1 - -import ( - "encoding/json" - "fmt" - - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/klog/v2" - "sigs.k8s.io/controller-runtime/pkg/scheme" - "sigs.k8s.io/yaml" -) - -var ( - // SchemeGroupVersion is group version used to register these objects - SchemeGroupVersion = schema.GroupVersion{Group: "vsphereprovider.openshift.io", Version: "v1beta1"} - - // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} -) - -// RawExtensionFromProviderSpec marshals the machine provider spec. -func RawExtensionFromProviderSpec(spec *VSphereMachineProviderSpec) (*runtime.RawExtension, error) { - if spec == nil { - return &runtime.RawExtension{}, nil - } - - var rawBytes []byte - var err error - if rawBytes, err = json.Marshal(spec); err != nil { - return nil, fmt.Errorf("error marshalling providerSpec: %v", err) - } - - return &runtime.RawExtension{ - Raw: rawBytes, - }, nil -} - -// RawExtensionFromProviderStatus marshals the provider status -func RawExtensionFromProviderStatus(status *VSphereMachineProviderStatus) (*runtime.RawExtension, error) { - if status == nil { - return &runtime.RawExtension{}, nil - } - - var rawBytes []byte - var err error - if rawBytes, err = json.Marshal(status); err != nil { - return nil, fmt.Errorf("error marshalling providerStatus: %v", err) - } - - return &runtime.RawExtension{ - Raw: rawBytes, - }, nil -} - -// ProviderSpecFromRawExtension unmarshals the JSON-encoded spec -func ProviderSpecFromRawExtension(rawExtension *runtime.RawExtension) (*VSphereMachineProviderSpec, error) { - if rawExtension == nil { - return &VSphereMachineProviderSpec{}, nil - } - - spec := new(VSphereMachineProviderSpec) - if err := yaml.Unmarshal(rawExtension.Raw, &spec); err != nil { - return nil, fmt.Errorf("error unmarshalling providerSpec: %v", err) - } - - klog.V(5).Infof("Got provider spec from raw extension: %+v", spec) - return spec, nil -} - -// ProviderStatusFromRawExtension unmarshals a raw extension into a VSphereMachineProviderStatus type -func ProviderStatusFromRawExtension(rawExtension *runtime.RawExtension) (*VSphereMachineProviderStatus, error) { - if rawExtension == nil { - return &VSphereMachineProviderStatus{}, nil - } - - providerStatus := new(VSphereMachineProviderStatus) - if err := yaml.Unmarshal(rawExtension.Raw, providerStatus); err != nil { - return nil, fmt.Errorf("error unmarshalling providerStatus: %v", err) - } - - klog.V(5).Infof("Got provider Status from raw extension: %+v", providerStatus) - return providerStatus, nil -} diff --git a/pkg/apis/vsphereprovider/v1beta1/vsphereproviderconfig_types.go b/pkg/apis/vsphereprovider/v1beta1/vsphereproviderconfig_types.go deleted file mode 100644 index 68682cd1d3..0000000000 --- a/pkg/apis/vsphereprovider/v1beta1/vsphereproviderconfig_types.go +++ /dev/null @@ -1,128 +0,0 @@ -package v1beta1 - -import ( - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// VSphereMachineProviderSpec is the type that will be embedded in a Machine.Spec.ProviderSpec field -// for an VSphere virtual machine. It is used by the vSphere machine actuator to create a single Machine. -// +k8s:openapi-gen=true -type VSphereMachineProviderSpec struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - // UserDataSecret contains a local reference to a secret that contains the - // UserData to apply to the instance - UserDataSecret *corev1.LocalObjectReference `json:"userDataSecret,omitempty"` - - // CredentialsSecret is a reference to the secret with vSphere credentials. - CredentialsSecret *corev1.LocalObjectReference `json:"credentialsSecret,omitempty"` - - // Template is the name, inventory path, or instance UUID of the template - // used to clone new machines. - Template string `json:"template"` - - Workspace *Workspace `json:"workspace,omitempty"` - - // Network is the network configuration for this machine's VM. - Network NetworkSpec `json:"network"` - - // NumCPUs is the number of virtual processors in a virtual machine. - // Defaults to the analogue property value in the template from which this - // machine is cloned. - // +optional - NumCPUs int32 `json:"numCPUs,omitempty"` - // NumCPUs is the number of cores among which to distribute CPUs in this - // virtual machine. - // Defaults to the analogue property value in the template from which this - // machine is cloned. - // +optional - NumCoresPerSocket int32 `json:"numCoresPerSocket,omitempty"` - // MemoryMiB is the size of a virtual machine's memory, in MiB. - // Defaults to the analogue property value in the template from which this - // machine is cloned. - // +optional - MemoryMiB int64 `json:"memoryMiB,omitempty"` - // DiskGiB is the size of a virtual machine's disk, in GiB. - // Defaults to the analogue property value in the template from which this - // machine is cloned. - // +optional - DiskGiB int32 `json:"diskGiB,omitempty"` - // Snapshot is the name of the snapshot from which the VM was cloned - // +optional - Snapshot string `json:"snapshot"` - - // CloneMode specifies the type of clone operation. - // The LinkedClone mode is only support for templates that have at least - // one snapshot. If the template has no snapshots, then CloneMode defaults - // to FullClone. - // When LinkedClone mode is enabled the DiskGiB field is ignored as it is - // not possible to expand disks of linked clones. - // Defaults to LinkedClone, but fails gracefully to FullClone if the source - // of the clone operation has no snapshots. - // +optional - CloneMode CloneMode `json:"cloneMode,omitempty"` -} - -// CloneMode is the type of clone operation used to clone a VM from a template. -type CloneMode string - -const ( - // FullClone indicates a VM will have no relationship to the source of the - // clone operation once the operation is complete. This is the safest clone - // mode, but it is not the fastest. - FullClone CloneMode = "fullClone" - - // LinkedClone means resulting VMs will be dependent upon the snapshot of - // the source VM/template from which the VM was cloned. This is the fastest - // clone mode, but it also prevents expanding a VMs disk beyond the size of - // the source VM/template. - LinkedClone CloneMode = "linkedClone" -) - -// NetworkSpec defines the virtual machine's network configuration. -type NetworkSpec struct { - Devices []NetworkDeviceSpec `json:"devices"` -} - -// NetworkDeviceSpec defines the network configuration for a virtual machine's -// network device. -type NetworkDeviceSpec struct { - // NetworkName is the name of the vSphere network to which the device - // will be connected. - NetworkName string `json:"networkName"` -} - -// WorkspaceConfig defines a workspace configuration for the vSphere cloud -// provider. -type Workspace struct { - // Server is the IP address or FQDN of the vSphere endpoint. - // +optional - Server string `gcfg:"server,omitempty" json:"server,omitempty"` - - // Datacenter is the datacenter in which VMs are created/located. - // +optional - Datacenter string `gcfg:"datacenter,omitempty" json:"datacenter,omitempty"` - - // Folder is the folder in which VMs are created/located. - // +optional - Folder string `gcfg:"folder,omitempty" json:"folder,omitempty"` - - // Datastore is the datastore in which VMs are created/located. - // +optional - Datastore string `gcfg:"default-datastore,omitempty" json:"datastore,omitempty"` - - // ResourcePool is the resource pool in which VMs are created/located. - // +optional - ResourcePool string `gcfg:"resourcepool-path,omitempty" json:"resourcePool,omitempty"` -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -func init() { - SchemeBuilder.Register(&VSphereMachineProviderSpec{}) -} diff --git a/pkg/apis/vsphereprovider/v1beta1/vsphereproviderstatus_types.go b/pkg/apis/vsphereprovider/v1beta1/vsphereproviderstatus_types.go deleted file mode 100644 index ccffbb367e..0000000000 --- a/pkg/apis/vsphereprovider/v1beta1/vsphereproviderstatus_types.go +++ /dev/null @@ -1,83 +0,0 @@ -package v1beta1 - -import ( - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// VSphereMachineProviderConditionType is a valid value for VSphereMachineProviderCondition.Type. -type VSphereMachineProviderConditionType string - -// Valid conditions for an vSphere machine instance. -const ( - // MachineCreation indicates whether the machine has been created or not. If not, - // it should include a reason and message for the failure. - MachineCreation VSphereMachineProviderConditionType = "MachineCreation" -) - -// VSphereMachineProviderConditionReason is reason for the condition's last transition. -type VSphereMachineProviderConditionReason string - -const ( - // MachineCreationSucceeded indicates machine creation success. - MachineCreationSucceeded VSphereMachineProviderConditionReason = "MachineCreationSucceeded" - // MachineCreationFailed indicates machine creation failure. - MachineCreationFailed VSphereMachineProviderConditionReason = "MachineCreationFailed" -) - -// VSphereMachineProviderCondition is a condition in a VSphereMachineProviderStatus. -type VSphereMachineProviderCondition struct { - // Type is the type of the condition. - Type VSphereMachineProviderConditionType `json:"type"` - // Status is the status of the condition. - Status corev1.ConditionStatus `json:"status"` - // LastProbeTime is the last time we probed the condition. - // +optional - LastProbeTime metav1.Time `json:"lastProbeTime,omitempty"` - // LastTransitionTime is the last time the condition transitioned from one status to another. - // +optional - LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"` - // Reason is a unique, one-word, CamelCase reason for the condition's last transition. - // +optional - Reason VSphereMachineProviderConditionReason `json:"reason,omitempty"` - // Message is a human-readable message indicating details about last transition. - // +optional - Message string `json:"message,omitempty"` -} - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// VSphereMachineProviderStatus is the type that will be embedded in a Machine.Status.ProviderStatus field. -// It contains VSphere-specific status information. -// +k8s:openapi-gen=true -type VSphereMachineProviderStatus struct { - metav1.TypeMeta `json:",inline"` - - // TODO: populate what we need here: - // InstanceID is the ID of the instance in VSphere - // +optional - InstanceID *string `json:"instanceId,omitempty"` - - // InstanceState is the provisioning state of the VSphere Instance. - // +optional - InstanceState *string `json:"instanceState,omitempty"` - // - // TaskRef? - // Ready? - // Conditions is a set of conditions associated with the Machine to indicate - // errors or other status - Conditions []VSphereMachineProviderCondition `json:"conditions,omitempty"` - - // TaskRef is a managed object reference to a Task related to the machine. - // This value is set automatically at runtime and should not be set or - // modified by users. - // +optional - TaskRef string `json:"taskRef,omitempty"` -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -func init() { - SchemeBuilder.Register(&VSphereMachineProviderStatus{}) -} diff --git a/pkg/apis/vsphereprovider/v1beta1/zz_generated.deepcopy.go b/pkg/apis/vsphereprovider/v1beta1/zz_generated.deepcopy.go deleted file mode 100644 index 36ab434bcb..0000000000 --- a/pkg/apis/vsphereprovider/v1beta1/zz_generated.deepcopy.go +++ /dev/null @@ -1,176 +0,0 @@ -// +build !ignore_autogenerated - -/* - * 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. - * - * Copyright 2019 Red Hat, Inc. - * - */ - -// Code generated by controller-gen. DO NOT EDIT. - -package v1beta1 - -import ( - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NetworkDeviceSpec) DeepCopyInto(out *NetworkDeviceSpec) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkDeviceSpec. -func (in *NetworkDeviceSpec) DeepCopy() *NetworkDeviceSpec { - if in == nil { - return nil - } - out := new(NetworkDeviceSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NetworkSpec) DeepCopyInto(out *NetworkSpec) { - *out = *in - if in.Devices != nil { - in, out := &in.Devices, &out.Devices - *out = make([]NetworkDeviceSpec, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkSpec. -func (in *NetworkSpec) DeepCopy() *NetworkSpec { - if in == nil { - return nil - } - out := new(NetworkSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VSphereMachineProviderCondition) DeepCopyInto(out *VSphereMachineProviderCondition) { - *out = *in - in.LastProbeTime.DeepCopyInto(&out.LastProbeTime) - in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VSphereMachineProviderCondition. -func (in *VSphereMachineProviderCondition) DeepCopy() *VSphereMachineProviderCondition { - if in == nil { - return nil - } - out := new(VSphereMachineProviderCondition) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VSphereMachineProviderSpec) DeepCopyInto(out *VSphereMachineProviderSpec) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - if in.UserDataSecret != nil { - in, out := &in.UserDataSecret, &out.UserDataSecret - *out = new(v1.LocalObjectReference) - **out = **in - } - if in.CredentialsSecret != nil { - in, out := &in.CredentialsSecret, &out.CredentialsSecret - *out = new(v1.LocalObjectReference) - **out = **in - } - if in.Workspace != nil { - in, out := &in.Workspace, &out.Workspace - *out = new(Workspace) - **out = **in - } - in.Network.DeepCopyInto(&out.Network) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VSphereMachineProviderSpec. -func (in *VSphereMachineProviderSpec) DeepCopy() *VSphereMachineProviderSpec { - if in == nil { - return nil - } - out := new(VSphereMachineProviderSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *VSphereMachineProviderSpec) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VSphereMachineProviderStatus) DeepCopyInto(out *VSphereMachineProviderStatus) { - *out = *in - out.TypeMeta = in.TypeMeta - if in.InstanceID != nil { - in, out := &in.InstanceID, &out.InstanceID - *out = new(string) - **out = **in - } - if in.InstanceState != nil { - in, out := &in.InstanceState, &out.InstanceState - *out = new(string) - **out = **in - } - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]VSphereMachineProviderCondition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VSphereMachineProviderStatus. -func (in *VSphereMachineProviderStatus) DeepCopy() *VSphereMachineProviderStatus { - if in == nil { - return nil - } - out := new(VSphereMachineProviderStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *VSphereMachineProviderStatus) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Workspace) DeepCopyInto(out *Workspace) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Workspace. -func (in *Workspace) DeepCopy() *Workspace { - if in == nil { - return nil - } - out := new(Workspace) - in.DeepCopyInto(out) - return out -} From 806785e98db8169c1ec4665eccbee40031d0f10b Mon Sep 17 00:00:00 2001 From: Alexander Demichev Date: Tue, 26 Oct 2021 19:57:05 +0200 Subject: [PATCH 07/10] Replace api types imports --- pkg/controller/machine/actuator.go | 2 +- pkg/controller/machine/controller.go | 11 +- pkg/controller/machine/controller_test.go | 8 +- pkg/controller/machine/errors.go | 12 +- .../machine/machine_controller_suite_test.go | 4 +- .../machine/machine_controller_test.go | 18 +- pkg/controller/machine/testactuator.go | 10 +- .../machinehealthcheck_controller.go | 91 +-- .../machinehealthcheck_controller_test.go | 517 +++++++++--------- .../machinehealthcheck_status_matcher.go | 10 +- pkg/controller/machineset/controller.go | 50 +- pkg/controller/machineset/controller_test.go | 72 +-- pkg/controller/machineset/delete_policy.go | 26 +- .../machineset/delete_policy_test.go | 140 ++--- pkg/controller/machineset/machine.go | 10 +- pkg/controller/machineset/machine_test.go | 18 +- .../machineset_controller_suite_test.go | 2 +- .../machineset/machineset_controller_test.go | 2 +- pkg/controller/machineset/status.go | 8 +- .../nodelink/nodelink_controller.go | 36 +- .../nodelink/nodelink_controller_test.go | 44 +- pkg/controller/vsphere/actuator.go | 2 +- pkg/controller/vsphere/actuator_test.go | 7 +- pkg/controller/vsphere/machine_scope.go | 15 +- pkg/controller/vsphere/machine_scope_test.go | 49 +- .../vsphere/machineset/controller.go | 6 +- .../machineset/controller_suite_test.go | 2 +- .../vsphere/machineset/controller_test.go | 7 +- pkg/controller/vsphere/reconciler.go | 7 +- pkg/controller/vsphere/reconciler_test.go | 121 ++-- pkg/controller/vsphere/util.go | 94 +++- pkg/metrics/metrics.go | 10 +- pkg/operator/sync.go | 10 +- pkg/util/annotations/helpers.go | 9 +- pkg/util/external/util.go | 6 +- pkg/util/machines/machines.go | 4 +- pkg/util/testing/testing.go | 21 +- 37 files changed, 768 insertions(+), 693 deletions(-) diff --git a/pkg/controller/machine/actuator.go b/pkg/controller/machine/actuator.go index 5196502b5c..05286a09a0 100644 --- a/pkg/controller/machine/actuator.go +++ b/pkg/controller/machine/actuator.go @@ -19,7 +19,7 @@ package machine import ( "context" - machinev1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" ) /// [Actuator] diff --git a/pkg/controller/machine/controller.go b/pkg/controller/machine/controller.go index 7d98426997..229ac588ae 100644 --- a/pkg/controller/machine/controller.go +++ b/pkg/controller/machine/controller.go @@ -23,7 +23,7 @@ import ( "reflect" "time" - machinev1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" "github.com/openshift/machine-api-operator/pkg/metrics" "github.com/openshift/machine-api-operator/pkg/util" "github.com/openshift/machine-api-operator/pkg/util/conditions" @@ -32,6 +32,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/record" @@ -175,7 +176,7 @@ func (r *ReconcileMachine) Reconcile(ctx context.Context, request reconcile.Requ // Get the original state of conditions now so that they can be used to calculate the patch later. // This must be a copy otherwise the referenced slice will be modified by later machine conditions changes. - originalConditions := m.GetConditions().DeepCopy() + originalConditions := m.Status.Conditions.DeepCopy() if errList := validateMachine(m); len(errList) > 0 { err := fmt.Errorf("%v: machine validation failed: %v", machineName, errList.ToAggregate().Error()) @@ -484,7 +485,7 @@ func (r *ReconcileMachine) updateStatus(ctx context.Context, machine *machinev1. // Conditions need to be deep copied as they are set outside of this function. // They will be restored after any updates to the base (done by patching annotations). - conditions := machine.GetConditions().DeepCopy() + conditions := machine.Status.Conditions.DeepCopy() // A call to Patch will mutate our local copy of the machine to match what is stored in the API. // Before we make any changes to the status subresource on our local copy, we need to patch the object first, @@ -500,8 +501,8 @@ func (r *ReconcileMachine) updateStatus(ctx context.Context, machine *machinev1. // To ensure conditions can be patched properly, set the original conditions on the baseMachine. // This allows the difference to be calculated as part of the patch. baseMachine := machine.DeepCopy() - baseMachine.SetConditions(originalConditions) - machine.SetConditions(conditions) + baseMachine.Status.Conditions = originalConditions + machine.Status.Conditions = conditions // Since we may have mutated the local copy of the machine above, we need to calculate baseToPatch here. // Any updates to the status must be done after this point. diff --git a/pkg/controller/machine/controller_test.go b/pkg/controller/machine/controller_test.go index 9b040a5d93..c0809db7e1 100644 --- a/pkg/controller/machine/controller_test.go +++ b/pkg/controller/machine/controller_test.go @@ -25,7 +25,7 @@ import ( "time" . "github.com/onsi/gomega" - machinev1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" "github.com/openshift/machine-api-operator/pkg/util/conditions" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -521,7 +521,7 @@ func TestUpdateStatus(t *testing.T) { g.Expect(got.Status.Phase).ToNot(BeNil()) g.Expect(*got.Status.Phase).To(Equal(phaseRunning)) lastUpdated := got.Status.LastUpdated - gotConditions := got.GetConditions() + gotConditions := got.Status.Conditions g.Expect(lastUpdated).ToNot(BeNil()) // validate passed object g.Expect(machine.Status.Phase).ToNot(BeNil()) @@ -562,8 +562,8 @@ func TestUpdateStatus(t *testing.T) { g.Expect(*got.Status.Phase).To(Equal(tc.phase)) g.Expect(*machine.Status.Phase).To(Equal(tc.phase)) - g.Expect(got.GetConditions()).To(conditions.MatchConditions(tc.conditions)) - g.Expect(machine.GetConditions()).To(conditions.MatchConditions(tc.conditions)) + g.Expect(got.Status.Conditions).To(conditions.MatchConditions(tc.conditions)) + g.Expect(machine.Status.Conditions).To(conditions.MatchConditions(tc.conditions)) g.Expect(got.GetAnnotations()).To(Equal(tc.annotations)) g.Expect(machine.GetAnnotations()).To(Equal(tc.annotations)) diff --git a/pkg/controller/machine/errors.go b/pkg/controller/machine/errors.go index d6ff745223..1571976e96 100644 --- a/pkg/controller/machine/errors.go +++ b/pkg/controller/machine/errors.go @@ -20,7 +20,7 @@ import ( "fmt" "time" - commonerrors "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" ) // A more descriptive kind of error that represents an error condition that @@ -28,7 +28,7 @@ import ( // enum-style constants meant to be interpreted by machines. The "Message" // field is meant to be read by humans. type MachineError struct { - Reason commonerrors.MachineStatusError + Reason machinev1.MachineStatusError Message string } @@ -42,28 +42,28 @@ func (e *MachineError) Error() string { func InvalidMachineConfiguration(msg string, args ...interface{}) *MachineError { return &MachineError{ - Reason: commonerrors.InvalidConfigurationMachineError, + Reason: machinev1.InvalidConfigurationMachineError, Message: fmt.Sprintf(msg, args...), } } func CreateMachine(msg string, args ...interface{}) *MachineError { return &MachineError{ - Reason: commonerrors.CreateMachineError, + Reason: machinev1.CreateMachineError, Message: fmt.Sprintf(msg, args...), } } func UpdateMachine(msg string, args ...interface{}) *MachineError { return &MachineError{ - Reason: commonerrors.UpdateMachineError, + Reason: machinev1.UpdateMachineError, Message: fmt.Sprintf(msg, args...), } } func DeleteMachine(msg string, args ...interface{}) *MachineError { return &MachineError{ - Reason: commonerrors.DeleteMachineError, + Reason: machinev1.DeleteMachineError, Message: fmt.Sprintf(msg, args...), } } diff --git a/pkg/controller/machine/machine_controller_suite_test.go b/pkg/controller/machine/machine_controller_suite_test.go index 5b7f55b9d6..29c72a206c 100644 --- a/pkg/controller/machine/machine_controller_suite_test.go +++ b/pkg/controller/machine/machine_controller_suite_test.go @@ -23,7 +23,7 @@ import ( "path/filepath" "testing" - "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/envtest" @@ -39,7 +39,7 @@ func TestMain(m *testing.M) { t := &envtest.Environment{ CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "install")}, } - v1beta1.AddToScheme(scheme.Scheme) + machinev1.AddToScheme(scheme.Scheme) var err error if cfg, err = t.Start(); err != nil { diff --git a/pkg/controller/machine/machine_controller_test.go b/pkg/controller/machine/machine_controller_test.go index c660f34f16..a8cbeb58c7 100644 --- a/pkg/controller/machine/machine_controller_test.go +++ b/pkg/controller/machine/machine_controller_test.go @@ -21,7 +21,7 @@ import ( "time" . "github.com/onsi/gomega" - machinev1beta1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" "golang.org/x/net/context" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -35,16 +35,16 @@ var c client.Client const timeout = time.Second * 5 func TestReconcile(t *testing.T) { - instance := &machinev1beta1.Machine{ + instance := &machinev1.Machine{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: "default", Labels: map[string]string{ - machinev1beta1.MachineClusterIDLabel: "foo", + machinev1.MachineClusterIDLabel: "foo", }, }, - Spec: machinev1beta1.MachineSpec{ - ProviderSpec: machinev1beta1.ProviderSpec{ + Spec: machinev1.MachineSpec{ + ProviderSpec: machinev1.ProviderSpec{ Value: &runtime.RawExtension{ Raw: []byte("{}"), }, @@ -80,15 +80,15 @@ func TestReconcile(t *testing.T) { } defer c.Delete(context.TODO(), instance) g := NewWithT(t) - g.Eventually(func() (machinev1beta1.MachineStatus, error) { - machine := &machinev1beta1.Machine{} + g.Eventually(func() (machinev1.MachineStatus, error) { + machine := &machinev1.Machine{} namespacedName := client.ObjectKey{Namespace: instance.Namespace, Name: instance.Name} err := c.Get(ctx, namespacedName, machine) if err != nil { - return machinev1beta1.MachineStatus{}, err + return machinev1.MachineStatus{}, err } return machine.Status, nil - }, timeout).ShouldNot(Equal(machinev1beta1.MachineStatus{})) + }, timeout).ShouldNot(Equal(machinev1.MachineStatus{})) // TODO: Verify that the actuator is called correctly on Create } diff --git a/pkg/controller/machine/testactuator.go b/pkg/controller/machine/testactuator.go index b0b33db350..94917efdaa 100644 --- a/pkg/controller/machine/testactuator.go +++ b/pkg/controller/machine/testactuator.go @@ -20,7 +20,7 @@ import ( "context" "sync" - "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" ) var _ Actuator = &TestActuator{} @@ -39,7 +39,7 @@ type TestActuator struct { Lock sync.Mutex } -func (a *TestActuator) Create(context.Context, *v1beta1.Machine) error { +func (a *TestActuator) Create(context.Context, *machinev1.Machine) error { defer func() { if a.BlockOnCreate { <-a.unblock @@ -52,7 +52,7 @@ func (a *TestActuator) Create(context.Context, *v1beta1.Machine) error { return nil } -func (a *TestActuator) Delete(context.Context, *v1beta1.Machine) error { +func (a *TestActuator) Delete(context.Context, *machinev1.Machine) error { defer func() { if a.BlockOnDelete { <-a.unblock @@ -65,7 +65,7 @@ func (a *TestActuator) Delete(context.Context, *v1beta1.Machine) error { return nil } -func (a *TestActuator) Update(ctx context.Context, machine *v1beta1.Machine) error { +func (a *TestActuator) Update(ctx context.Context, machine *machinev1.Machine) error { defer func() { if a.BlockOnUpdate { <-a.unblock @@ -77,7 +77,7 @@ func (a *TestActuator) Update(ctx context.Context, machine *v1beta1.Machine) err return nil } -func (a *TestActuator) Exists(context.Context, *v1beta1.Machine) (bool, error) { +func (a *TestActuator) Exists(context.Context, *machinev1.Machine) (bool, error) { defer func() { if a.BlockOnExists { <-a.unblock diff --git a/pkg/controller/machinehealthcheck/machinehealthcheck_controller.go b/pkg/controller/machinehealthcheck/machinehealthcheck_controller.go index d912a256e4..cc5065cca8 100644 --- a/pkg/controller/machinehealthcheck/machinehealthcheck_controller.go +++ b/pkg/controller/machinehealthcheck/machinehealthcheck_controller.go @@ -9,6 +9,11 @@ import ( "strings" "time" + machinev1 "github.com/openshift/api/machine/v1beta1" + "github.com/openshift/machine-api-operator/pkg/metrics" + "github.com/openshift/machine-api-operator/pkg/util/annotations" + "github.com/openshift/machine-api-operator/pkg/util/conditions" + "github.com/openshift/machine-api-operator/pkg/util/external" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" apimachineryerrors "k8s.io/apimachinery/pkg/api/errors" @@ -28,12 +33,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/reconcile" "sigs.k8s.io/controller-runtime/pkg/source" - - mapiv1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - "github.com/openshift/machine-api-operator/pkg/metrics" - "github.com/openshift/machine-api-operator/pkg/util/annotations" - "github.com/openshift/machine-api-operator/pkg/util/conditions" - "github.com/openshift/machine-api-operator/pkg/util/external" ) const ( @@ -44,7 +43,7 @@ const ( machineMasterRole = "master" machinePhaseFailed = "Failed" remediationStrategyAnnotation = "machine.openshift.io/remediation-strategy" - remediationStrategyExternal = mapiv1.RemediationStrategyType("external-baremetal") + remediationStrategyExternal = machinev1.RemediationStrategyType("external-baremetal") defaultNodeStartupTimeout = 10 * time.Minute machineNodeNameIndex = "machineNodeNameIndex" controllerName = "machinehealthcheck-controller" @@ -71,6 +70,10 @@ const ( // EventExternalAnnotationAdded is emitted when external annotation was // successfully added to a Node object EventExternalAnnotationAdded string = "ExternalAnnotationAdded" + // PausedAnnotation is an annotation that can be applied to MachineHealthCheck objects to prevent the MHC controller + // from processing it. + // TODO: move this annotation to the openshift/api package + PausedAnnotation = "cluster.x-k8s.io/paused" ) var ( @@ -91,7 +94,7 @@ func Add(mgr manager.Manager, opts manager.Options) error { // newReconciler returns a new reconcile.Reconciler func newReconciler(mgr manager.Manager, opts manager.Options) (*ReconcileMachineHealthCheck, error) { if err := mgr.GetCache().IndexField(context.TODO(), - &mapiv1.Machine{}, + &machinev1.Machine{}, machineNodeNameIndex, indexMachineByNodeName, ); err != nil { @@ -107,7 +110,7 @@ func newReconciler(mgr manager.Manager, opts manager.Options) (*ReconcileMachine } func indexMachineByNodeName(object client.Object) []string { - machine, ok := object.(*mapiv1.Machine) + machine, ok := object.(*machinev1.Machine) if !ok { klog.Warningf("Expected a machine for indexing field, got: %T", object) return nil @@ -127,12 +130,12 @@ func add(mgr manager.Manager, r reconcile.Reconciler, mapMachineToMHC, mapNodeTo return err } - err = c.Watch(&source.Kind{Type: &mapiv1.MachineHealthCheck{}}, &handler.EnqueueRequestForObject{}) + err = c.Watch(&source.Kind{Type: &machinev1.MachineHealthCheck{}}, &handler.EnqueueRequestForObject{}) if err != nil { return err } - err = c.Watch(&source.Kind{Type: &mapiv1.Machine{}}, handler.EnqueueRequestsFromMapFunc(mapMachineToMHC)) + err = c.Watch(&source.Kind{Type: &machinev1.Machine{}}, handler.EnqueueRequestsFromMapFunc(mapMachineToMHC)) if err != nil { return err } @@ -153,16 +156,16 @@ type ReconcileMachineHealthCheck struct { } type target struct { - Machine mapiv1.Machine + Machine machinev1.Machine Node *corev1.Node - MHC mapiv1.MachineHealthCheck + MHC machinev1.MachineHealthCheck } // Reconcile fetch all targets for a MachineHealthCheck request and does health checking for each of them func (r *ReconcileMachineHealthCheck) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { klog.Infof("Reconciling %s", request.String()) - mhc := &mapiv1.MachineHealthCheck{} + mhc := &machinev1.MachineHealthCheck{} if err := r.client.Get(context.TODO(), request.NamespacedName, mhc); err != nil { if apimachineryerrors.IsNotFound(err) { // Request object not found, could have been deleted after reconcile request. @@ -222,11 +225,11 @@ func (r *ReconcileMachineHealthCheck) Reconcile(ctx context.Context, request rec // Remediation not allowed, the number of not started or unhealthy machines exceeds maxUnhealthy mhc.Status.RemediationsAllowed = 0 - conditions.Set(mhc, &mapiv1.Condition{ - Type: mapiv1.RemediationAllowedCondition, + conditions.Set(mhc, &machinev1.Condition{ + Type: machinev1.RemediationAllowedCondition, Status: corev1.ConditionFalse, - Severity: mapiv1.ConditionSeverityWarning, - Reason: mapiv1.TooManyUnhealthyReason, + Severity: machinev1.ConditionSeverityWarning, + Reason: machinev1.TooManyUnhealthyReason, Message: message, }) @@ -255,7 +258,7 @@ func (r *ReconcileMachineHealthCheck) Reconcile(ctx context.Context, request rec ) metrics.ObserveMachineHealthCheckShortCircuitDisabled(mhc.Name, mhc.Namespace) - conditions.MarkTrue(mhc, mapiv1.RemediationAllowedCondition) + conditions.MarkTrue(mhc, machinev1.RemediationAllowedCondition) if err := r.reconcileStatus(mergeBase, mhc); err != nil { klog.Errorf("Reconciling %s: error patching status: %v", request.String(), err) return reconcile.Result{}, err @@ -279,7 +282,7 @@ func (r *ReconcileMachineHealthCheck) Reconcile(ctx context.Context, request rec return reconcile.Result{}, nil } -func (r *ReconcileMachineHealthCheck) remediate(ctx context.Context, needRemediationTargets []target, m *mapiv1.MachineHealthCheck) []error { +func (r *ReconcileMachineHealthCheck) remediate(ctx context.Context, needRemediationTargets []target, m *machinev1.MachineHealthCheck) []error { var errList []error // remediate unhealthy for _, t := range needRemediationTargets { @@ -300,7 +303,7 @@ func (r *ReconcileMachineHealthCheck) remediate(ctx context.Context, needRemedia } // deletes EMR (External Machine Remediation) for healthy machines -func (r *ReconcileMachineHealthCheck) cleanEMR(ctx context.Context, currentHealthy []target, m *mapiv1.MachineHealthCheck) { +func (r *ReconcileMachineHealthCheck) cleanEMR(ctx context.Context, currentHealthy []target, m *machinev1.MachineHealthCheck) { if m.Spec.RemediationTemplate == nil { return } @@ -325,7 +328,7 @@ func (r *ReconcileMachineHealthCheck) cleanEMR(ctx context.Context, currentHealt } } -func (r *ReconcileMachineHealthCheck) externalRemediation(ctx context.Context, m *mapiv1.MachineHealthCheck, t target) error { +func (r *ReconcileMachineHealthCheck) externalRemediation(ctx context.Context, m *machinev1.MachineHealthCheck, t target) error { klog.V(3).Infof(" %s: start external remediation logic", t.string()) re, err := r.externalRemediationRequestExists(ctx, m, t.Machine.Name) if err != nil { @@ -338,14 +341,14 @@ func (r *ReconcileMachineHealthCheck) externalRemediation(ctx context.Context, m } cloneOwnerRef := &metav1.OwnerReference{ - APIVersion: mapiv1.SchemeGroupVersion.String(), + APIVersion: machinev1.SchemeGroupVersion.String(), Kind: "Machine", Name: t.Machine.Name, UID: t.Machine.UID, } from, err := external.Get(ctx, r.client, m.Spec.RemediationTemplate, t.Machine.Namespace) if err != nil { - conditions.MarkFalse(m, mapiv1.ExternalRemediationTemplateAvailable, mapiv1.ExternalRemediationTemplateNotFound, mapiv1.ConditionSeverityError, err.Error()) + conditions.MarkFalse(m, machinev1.ExternalRemediationTemplateAvailable, machinev1.ExternalRemediationTemplateNotFound, machinev1.ConditionSeverityError, err.Error()) return fmt.Errorf("error retrieving remediation template %v %q for machine %q in namespace %q: %v", m.Spec.RemediationTemplate.GroupVersionKind(), m.Spec.RemediationTemplate.Name, t.Machine.Name, t.Machine.Namespace, err) } @@ -371,14 +374,14 @@ func (r *ReconcileMachineHealthCheck) externalRemediation(ctx context.Context, m klog.V(3).Infof("Target has failed health check, creating an external remediation request", "remediation request name", to.GetName(), "target", t.string()) // Create the external clone. if err := r.client.Create(ctx, to); err != nil { - conditions.MarkFalse(m, mapiv1.ExternalRemediationRequestAvailable, mapiv1.ExternalRemediationRequestCreationFailed, mapiv1.ConditionSeverityError, err.Error()) + conditions.MarkFalse(m, machinev1.ExternalRemediationRequestAvailable, machinev1.ExternalRemediationRequestCreationFailed, machinev1.ConditionSeverityError, err.Error()) return fmt.Errorf("error creating remediation request for machine %q in namespace %q: %v", t.Machine.Name, t.Machine.Namespace, err) } return nil } // getExternalRemediationRequest gets reference to External Remediation Request, unstructured object. -func (r *ReconcileMachineHealthCheck) getExternalRemediationRequest(ctx context.Context, m *mapiv1.MachineHealthCheck, machineName string) (*unstructured.Unstructured, error) { +func (r *ReconcileMachineHealthCheck) getExternalRemediationRequest(ctx context.Context, m *machinev1.MachineHealthCheck, machineName string) (*unstructured.Unstructured, error) { remediationRef := &corev1.ObjectReference{ APIVersion: m.Spec.RemediationTemplate.APIVersion, Kind: strings.TrimSuffix(m.Spec.RemediationTemplate.Kind, external.TemplateSuffix), @@ -389,7 +392,7 @@ func (r *ReconcileMachineHealthCheck) getExternalRemediationRequest(ctx context. // externalRemediationRequestExists checks if the External Remediation Request is created // for the machine. -func (r *ReconcileMachineHealthCheck) externalRemediationRequestExists(ctx context.Context, m *mapiv1.MachineHealthCheck, machineName string) (bool, error) { +func (r *ReconcileMachineHealthCheck) externalRemediationRequestExists(ctx context.Context, m *machinev1.MachineHealthCheck, machineName string) (bool, error) { remediationReq, err := r.getExternalRemediationRequest(ctx, m, machineName) if err != nil && !apierrors.IsNotFound(err) { return false, err @@ -397,7 +400,7 @@ func (r *ReconcileMachineHealthCheck) externalRemediationRequestExists(ctx conte return remediationReq != nil, nil } -func isAllowedRemediation(mhc *mapiv1.MachineHealthCheck) bool { +func isAllowedRemediation(mhc *machinev1.MachineHealthCheck) bool { maxUnhealthy, err := getMaxUnhealthy(mhc) if err != nil { return false @@ -407,7 +410,7 @@ func isAllowedRemediation(mhc *mapiv1.MachineHealthCheck) bool { return unhealthyMachineCount(mhc) <= maxUnhealthy } -func getMaxUnhealthy(mhc *mapiv1.MachineHealthCheck) (int, error) { +func getMaxUnhealthy(mhc *machinev1.MachineHealthCheck) (int, error) { if mhc.Spec.MaxUnhealthy == nil { // This value should be defaulted, but if not, 100% is the default return derefInt(mhc.Status.ExpectedMachines), nil @@ -427,7 +430,7 @@ func getMaxUnhealthy(mhc *mapiv1.MachineHealthCheck) (int, error) { // unhealthyMachineCount calculates the number of presently unhealthy or missing machines // ie the delta between the expected number of machines and the current number deemed healthy -func unhealthyMachineCount(mhc *mapiv1.MachineHealthCheck) int { +func unhealthyMachineCount(mhc *machinev1.MachineHealthCheck) int { return derefInt(mhc.Status.ExpectedMachines) - derefInt(mhc.Status.CurrentHealthy) } @@ -438,7 +441,7 @@ func derefInt(i *int) int { return 0 } -func (r *ReconcileMachineHealthCheck) reconcileStatus(baseToPatch client.Patch, mhc *mapiv1.MachineHealthCheck) error { +func (r *ReconcileMachineHealthCheck) reconcileStatus(baseToPatch client.Patch, mhc *machinev1.MachineHealthCheck) error { maxUnhealthy, err := getMaxUnhealthy(mhc) if err != nil { return fmt.Errorf("failed to get value for maxUnhealthy: %v", err) @@ -498,7 +501,7 @@ func (r *ReconcileMachineHealthCheck) healthCheckTargets(targets []target, timeo return currentHealthy, needRemediationTargets, nextCheckTimes, errList } -func (r *ReconcileMachineHealthCheck) getTargetsFromMHC(mhc mapiv1.MachineHealthCheck) ([]target, error) { +func (r *ReconcileMachineHealthCheck) getTargetsFromMHC(mhc machinev1.MachineHealthCheck) ([]target, error) { machines, err := r.getMachinesFromMHC(mhc) if err != nil { return nil, fmt.Errorf("error getting machines from MHC: %v", err) @@ -528,7 +531,7 @@ func (r *ReconcileMachineHealthCheck) getTargetsFromMHC(mhc mapiv1.MachineHealth return targets, nil } -func (r *ReconcileMachineHealthCheck) getMachinesFromMHC(mhc mapiv1.MachineHealthCheck) ([]mapiv1.Machine, error) { +func (r *ReconcileMachineHealthCheck) getMachinesFromMHC(mhc machinev1.MachineHealthCheck) ([]machinev1.Machine, error) { selector, err := metav1.LabelSelectorAsSelector(&mhc.Spec.Selector) if err != nil { return nil, fmt.Errorf("failed to build selector") @@ -538,15 +541,15 @@ func (r *ReconcileMachineHealthCheck) getMachinesFromMHC(mhc mapiv1.MachineHealt LabelSelector: selector, Namespace: mhc.GetNamespace(), } - machineList := &mapiv1.MachineList{} + machineList := &machinev1.MachineList{} if err := r.client.List(context.Background(), machineList, &options); err != nil { return nil, fmt.Errorf("failed to list machines: %v", err) } return machineList.Items, nil } -func (r *ReconcileMachineHealthCheck) getMachineFromNode(nodeName string) (*mapiv1.Machine, error) { - machineList := &mapiv1.MachineList{} +func (r *ReconcileMachineHealthCheck) getMachineFromNode(nodeName string) (*machinev1.Machine, error) { + machineList := &machinev1.MachineList{} if err := r.client.List( context.TODO(), machineList, @@ -578,7 +581,7 @@ func (r *ReconcileMachineHealthCheck) mhcRequestsFromNode(o client.Object) []rec return nil } - mhcList := &mapiv1.MachineHealthCheckList{} + mhcList := &machinev1.MachineHealthCheckList{} if err := r.client.List(context.Background(), mhcList); err != nil { klog.Errorf("No-op: Unable to list mhc: %v", err) return nil @@ -596,7 +599,7 @@ func (r *ReconcileMachineHealthCheck) mhcRequestsFromNode(o client.Object) []rec func (r *ReconcileMachineHealthCheck) mhcRequestsFromMachine(o client.Object) []reconcile.Request { klog.V(4).Infof("Getting MHC requests from machine %q", namespacedName(o).String()) - machine := &mapiv1.Machine{} + machine := &machinev1.Machine{} if err := r.client.Get(context.Background(), client.ObjectKey{ Namespace: o.GetNamespace(), @@ -608,7 +611,7 @@ func (r *ReconcileMachineHealthCheck) mhcRequestsFromMachine(o client.Object) [] return nil } - mhcList := &mapiv1.MachineHealthCheckList{} + mhcList := &machinev1.MachineHealthCheckList{} if err := r.client.List(context.Background(), mhcList); err != nil { klog.Errorf("No-op: Unable to list mhc: %v", err) return nil @@ -627,7 +630,7 @@ func (r *ReconcileMachineHealthCheck) internalRemediation(t target) error { klog.Infof(" %s: start remediation logic", t.string()) if derefStringPointer(t.Machine.Status.Phase) != machinePhaseFailed { if remediationStrategy, ok := t.MHC.Annotations[remediationStrategyAnnotation]; ok { - if mapiv1.RemediationStrategyType(remediationStrategy) == remediationStrategyExternal { + if machinev1.RemediationStrategyType(remediationStrategy) == remediationStrategyExternal { return t.remediationStrategyExternal(r) } } @@ -646,7 +649,7 @@ func (r *ReconcileMachineHealthCheck) internalRemediation(t target) error { } key := client.ObjectKey{Namespace: t.Machine.Namespace, Name: t.Machine.Name} - machine := &mapiv1.Machine{} + machine := &machinev1.Machine{} if err := r.client.Get(context.TODO(), key, machine); err != nil { if apimachineryerrors.IsNotFound(err) { // Machine has already been deleted @@ -717,7 +720,7 @@ func (t *target) remediationStrategyExternal(r *ReconcileMachineHealthCheck) err return nil } -func externalRemediationAnnotationExists(machine *mapiv1.Machine) bool { +func externalRemediationAnnotationExists(machine *machinev1.Machine) bool { if machine.Annotations == nil { return false } @@ -725,7 +728,7 @@ func externalRemediationAnnotationExists(machine *mapiv1.Machine) bool { return externalRemediation } -func (r *ReconcileMachineHealthCheck) getNodeFromMachine(machine mapiv1.Machine) (*corev1.Node, error) { +func (r *ReconcileMachineHealthCheck) getNodeFromMachine(machine machinev1.Machine) (*corev1.Node, error) { if machine.Status.NodeRef == nil { return nil, nil } @@ -850,7 +853,7 @@ func namespacedName(obj metav1.Object) types.NamespacedName { } } -func hasMatchingLabels(machineHealthCheck *mapiv1.MachineHealthCheck, machine *mapiv1.Machine) bool { +func hasMatchingLabels(machineHealthCheck *machinev1.MachineHealthCheck, machine *machinev1.Machine) bool { selector, err := metav1.LabelSelectorAsSelector(&machineHealthCheck.Spec.Selector) if err != nil { klog.Warningf("unable to convert selector: %v", err) diff --git a/pkg/controller/machinehealthcheck/machinehealthcheck_controller_test.go b/pkg/controller/machinehealthcheck/machinehealthcheck_controller_test.go index 5f25edbf4b..5c7f718e13 100644 --- a/pkg/controller/machinehealthcheck/machinehealthcheck_controller_test.go +++ b/pkg/controller/machinehealthcheck/machinehealthcheck_controller_test.go @@ -12,7 +12,8 @@ import ( "github.com/openshift/machine-api-operator/pkg/util/external" . "github.com/onsi/gomega" - mapiv1beta1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" + "github.com/openshift/machine-api-operator/pkg/util/conditions" maotesting "github.com/openshift/machine-api-operator/pkg/util/testing" corev1 "k8s.io/api/core/v1" @@ -36,20 +37,20 @@ const ( ) var ( - remediationAllowedCondition = mapiv1beta1.Condition{ - Type: mapiv1beta1.RemediationAllowedCondition, + remediationAllowedCondition = machinev1.Condition{ + Type: machinev1.RemediationAllowedCondition, Status: corev1.ConditionTrue, } ) type testCase struct { name string - machine *mapiv1beta1.Machine + machine *machinev1.Machine node *corev1.Node - mhc *mapiv1beta1.MachineHealthCheck + mhc *machinev1.MachineHealthCheck expected expectedReconcile expectedEvents []string - expectedStatus *mapiv1beta1.MachineHealthCheckStatus + expectedStatus *machinev1.MachineHealthCheckStatus externalRemediationMachine *unstructured.Unstructured externalRemediationTemplate *unstructured.Unstructured } @@ -61,7 +62,7 @@ type expectedReconcile struct { func init() { // Add types to scheme - if err := mapiv1beta1.AddToScheme(scheme.Scheme); err != nil { + if err := machinev1.AddToScheme(scheme.Scheme); err != nil { panic(err) } } @@ -69,8 +70,8 @@ func init() { func TestHasMatchingLabels(t *testing.T) { machine := maotesting.NewMachine("machine", "node") testsCases := []struct { - machine *mapiv1beta1.Machine - machineHealthCheck *mapiv1beta1.MachineHealthCheck + machine *machinev1.Machine + machineHealthCheck *machinev1.MachineHealthCheck expected bool }{ { @@ -80,7 +81,7 @@ func TestHasMatchingLabels(t *testing.T) { }, { machine: machine, - machineHealthCheck: &mapiv1beta1.MachineHealthCheck{ + machineHealthCheck: &machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "NoMatchingLabels", Namespace: namespace, @@ -88,20 +89,20 @@ func TestHasMatchingLabels(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "no": "match", }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, expected: false, }, { machine: machine, - machineHealthCheck: &mapiv1beta1.MachineHealthCheck{ + machineHealthCheck: &machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "EmptySelector", Namespace: namespace, @@ -109,16 +110,16 @@ func TestHasMatchingLabels(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{}, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, expected: true, }, { machine: machine, - machineHealthCheck: &mapiv1beta1.MachineHealthCheck{ + machineHealthCheck: &machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "NilSelector", // Note this shouldn't happen, API schema validation requires the selector be non-nil Namespace: namespace, @@ -126,8 +127,8 @@ func TestHasMatchingLabels(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{}, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Spec: machinev1.MachineHealthCheckSpec{}, + Status: machinev1.MachineHealthCheckStatus{}, }, expected: true, }, @@ -229,7 +230,7 @@ func TestReconcile(t *testing.T) { machineHealthCheckPaused := maotesting.NewMachineHealthCheck("machineHealthCheck") machineHealthCheckPaused.Annotations = make(map[string]string) - machineHealthCheckPaused.Annotations[mapiv1beta1.PausedAnnotation] = "test" + machineHealthCheckPaused.Annotations[PausedAnnotation] = "test" // remediationExternal nodeUnhealthyForTooLong := maotesting.NewNode("nodeUnhealthyForTooLong", false) @@ -259,11 +260,11 @@ func TestReconcile(t *testing.T) { error: false, }, expectedEvents: []string{EventMachineDeleted}, - expectedStatus: &mapiv1beta1.MachineHealthCheckStatus{ + expectedStatus: &machinev1.MachineHealthCheckStatus{ ExpectedMachines: IntPtr(1), CurrentHealthy: IntPtr(0), RemediationsAllowed: 0, - Conditions: mapiv1beta1.Conditions{ + Conditions: machinev1.Conditions{ remediationAllowedCondition, }, }, @@ -278,7 +279,7 @@ func TestReconcile(t *testing.T) { error: false, }, expectedEvents: []string{}, - expectedStatus: &mapiv1beta1.MachineHealthCheckStatus{}, + expectedStatus: &machinev1.MachineHealthCheckStatus{}, }, { name: "machine with node healthy", @@ -290,11 +291,11 @@ func TestReconcile(t *testing.T) { error: false, }, expectedEvents: []string{}, - expectedStatus: &mapiv1beta1.MachineHealthCheckStatus{ + expectedStatus: &machinev1.MachineHealthCheckStatus{ ExpectedMachines: IntPtr(1), CurrentHealthy: IntPtr(1), RemediationsAllowed: 1, - Conditions: mapiv1beta1.Conditions{ + Conditions: machinev1.Conditions{ remediationAllowedCondition, }, }, @@ -309,11 +310,11 @@ func TestReconcile(t *testing.T) { error: false, }, expectedEvents: []string{}, - expectedStatus: &mapiv1beta1.MachineHealthCheckStatus{ + expectedStatus: &machinev1.MachineHealthCheckStatus{ ExpectedMachines: IntPtr(1), CurrentHealthy: IntPtr(0), RemediationsAllowed: 0, - Conditions: mapiv1beta1.Conditions{ + Conditions: machinev1.Conditions{ remediationAllowedCondition, }, }, @@ -331,11 +332,11 @@ func TestReconcile(t *testing.T) { error: false, }, expectedEvents: []string{EventDetectedUnhealthy}, - expectedStatus: &mapiv1beta1.MachineHealthCheckStatus{ + expectedStatus: &machinev1.MachineHealthCheckStatus{ ExpectedMachines: IntPtr(1), CurrentHealthy: IntPtr(0), RemediationsAllowed: 0, - Conditions: mapiv1beta1.Conditions{ + Conditions: machinev1.Conditions{ remediationAllowedCondition, }, }, @@ -350,11 +351,11 @@ func TestReconcile(t *testing.T) { error: false, }, expectedEvents: []string{}, - expectedStatus: &mapiv1beta1.MachineHealthCheckStatus{ + expectedStatus: &machinev1.MachineHealthCheckStatus{ ExpectedMachines: IntPtr(0), CurrentHealthy: IntPtr(0), RemediationsAllowed: 0, - Conditions: mapiv1beta1.Conditions{ + Conditions: machinev1.Conditions{ remediationAllowedCondition, }, }, @@ -369,11 +370,11 @@ func TestReconcile(t *testing.T) { error: false, }, expectedEvents: []string{}, - expectedStatus: &mapiv1beta1.MachineHealthCheckStatus{ + expectedStatus: &machinev1.MachineHealthCheckStatus{ ExpectedMachines: IntPtr(0), CurrentHealthy: IntPtr(0), RemediationsAllowed: 0, - Conditions: mapiv1beta1.Conditions{ + Conditions: machinev1.Conditions{ remediationAllowedCondition, }, }, @@ -388,11 +389,11 @@ func TestReconcile(t *testing.T) { error: false, }, expectedEvents: []string{EventSkippedNoController}, - expectedStatus: &mapiv1beta1.MachineHealthCheckStatus{ + expectedStatus: &machinev1.MachineHealthCheckStatus{ ExpectedMachines: IntPtr(1), CurrentHealthy: IntPtr(0), RemediationsAllowed: 0, - Conditions: mapiv1beta1.Conditions{ + Conditions: machinev1.Conditions{ remediationAllowedCondition, }, }, @@ -409,11 +410,11 @@ func TestReconcile(t *testing.T) { error: false, }, expectedEvents: []string{EventDetectedUnhealthy}, - expectedStatus: &mapiv1beta1.MachineHealthCheckStatus{ + expectedStatus: &machinev1.MachineHealthCheckStatus{ ExpectedMachines: IntPtr(1), CurrentHealthy: IntPtr(0), RemediationsAllowed: 0, - Conditions: mapiv1beta1.Conditions{ + Conditions: machinev1.Conditions{ remediationAllowedCondition, }, }, @@ -428,11 +429,11 @@ func TestReconcile(t *testing.T) { error: false, }, expectedEvents: []string{}, - expectedStatus: &mapiv1beta1.MachineHealthCheckStatus{ + expectedStatus: &machinev1.MachineHealthCheckStatus{ ExpectedMachines: IntPtr(1), CurrentHealthy: IntPtr(0), RemediationsAllowed: 0, - Conditions: mapiv1beta1.Conditions{ + Conditions: machinev1.Conditions{ remediationAllowedCondition, }, }, @@ -447,11 +448,11 @@ func TestReconcile(t *testing.T) { error: false, }, expectedEvents: []string{}, - expectedStatus: &mapiv1beta1.MachineHealthCheckStatus{ + expectedStatus: &machinev1.MachineHealthCheckStatus{ ExpectedMachines: IntPtr(1), CurrentHealthy: IntPtr(1), RemediationsAllowed: 0, - Conditions: mapiv1beta1.Conditions{ + Conditions: machinev1.Conditions{ remediationAllowedCondition, }, }, @@ -468,16 +469,16 @@ func TestReconcile(t *testing.T) { error: false, }, expectedEvents: []string{EventRemediationRestricted}, - expectedStatus: &mapiv1beta1.MachineHealthCheckStatus{ + expectedStatus: &machinev1.MachineHealthCheckStatus{ ExpectedMachines: IntPtr(1), CurrentHealthy: IntPtr(0), RemediationsAllowed: 0, - Conditions: mapiv1beta1.Conditions{ + Conditions: machinev1.Conditions{ { - Type: mapiv1beta1.RemediationAllowedCondition, + Type: machinev1.RemediationAllowedCondition, Status: corev1.ConditionFalse, - Severity: mapiv1beta1.ConditionSeverityWarning, - Reason: mapiv1beta1.TooManyUnhealthyReason, + Severity: machinev1.ConditionSeverityWarning, + Reason: machinev1.TooManyUnhealthyReason, Message: "Remediation is not allowed, the number of not started or unhealthy machines exceeds maxUnhealthy (total: 1, unhealthy: 1, maxUnhealthy: -1)", }, }, @@ -502,7 +503,7 @@ func TestReconcileExternalRemediationTemplate(t *testing.T) { nodeUnHealthy := maotesting.NewNode("NodeUnhealthy", false) machineWithNodeUnHealthy := maotesting.NewMachine("Machine", nodeUnHealthy.Name) - machineWithNodeUnHealthy.APIVersion = mapiv1beta1.SchemeGroupVersion.String() + machineWithNodeUnHealthy.APIVersion = machinev1.SchemeGroupVersion.String() //external remediation machine template crd ermTemplate := maotesting.NewExternalRemediationTemplate() mhcWithRemediationTemplate := newMachineHealthCheckWithRemediationTemplate(ermTemplate) @@ -522,11 +523,11 @@ func TestReconcileExternalRemediationTemplate(t *testing.T) { error: false, }, expectedEvents: []string{}, - expectedStatus: &mapiv1beta1.MachineHealthCheckStatus{ + expectedStatus: &machinev1.MachineHealthCheckStatus{ ExpectedMachines: IntPtr(1), CurrentHealthy: IntPtr(1), RemediationsAllowed: 1, - Conditions: mapiv1beta1.Conditions{ + Conditions: machinev1.Conditions{ remediationAllowedCondition, }, }, @@ -544,11 +545,11 @@ func TestReconcileExternalRemediationTemplate(t *testing.T) { error: false, }, expectedEvents: []string{}, - expectedStatus: &mapiv1beta1.MachineHealthCheckStatus{ + expectedStatus: &machinev1.MachineHealthCheckStatus{ ExpectedMachines: IntPtr(1), CurrentHealthy: IntPtr(0), RemediationsAllowed: 0, - Conditions: mapiv1beta1.Conditions{ + Conditions: machinev1.Conditions{ remediationAllowedCondition, }, }, @@ -566,11 +567,11 @@ func TestReconcileExternalRemediationTemplate(t *testing.T) { error: false, }, expectedEvents: []string{}, - expectedStatus: &mapiv1beta1.MachineHealthCheckStatus{ + expectedStatus: &machinev1.MachineHealthCheckStatus{ ExpectedMachines: IntPtr(1), CurrentHealthy: IntPtr(0), RemediationsAllowed: 0, - Conditions: mapiv1beta1.Conditions{ + Conditions: machinev1.Conditions{ remediationAllowedCondition, }, }, @@ -665,7 +666,7 @@ func TestApplyRemediationExternal(t *testing.T) { target := target{ Node: nodeUnhealthyForTooLong, Machine: *machineUnhealthyForTooLong, - MHC: mapiv1beta1.MachineHealthCheck{}, + MHC: machinev1.MachineHealthCheck{}, } if err := target.remediationStrategyExternal(r); err != nil { t.Fatalf("unexpected error %v", err) @@ -677,7 +678,7 @@ func TestApplyRemediationExternal(t *testing.T) { recorder.Events, ) - machine := &mapiv1beta1.Machine{} + machine := &machinev1.Machine{} if err := r.client.Get(context.TODO(), request.NamespacedName, machine); err != nil { t.Errorf("Expected: no error, got: %v", err) } @@ -690,13 +691,13 @@ func TestApplyRemediationExternal(t *testing.T) { func TestMHCRequestsFromMachine(t *testing.T) { testCases := []struct { testCase string - mhcs []*mapiv1beta1.MachineHealthCheck - machine *mapiv1beta1.Machine + mhcs []*machinev1.MachineHealthCheck + machine *machinev1.Machine expectedRequests []reconcile.Request }{ { testCase: "at least one match", - mhcs: []*mapiv1beta1.MachineHealthCheck{ + mhcs: []*machinev1.MachineHealthCheck{ { ObjectMeta: metav1.ObjectMeta{ Name: "match", @@ -705,14 +706,14 @@ func TestMHCRequestsFromMachine(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "foo": "bar", }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, { ObjectMeta: metav1.ObjectMeta{ @@ -722,14 +723,14 @@ func TestMHCRequestsFromMachine(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "no": "match", }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, }, machine: maotesting.NewMachine("test", "node1"), @@ -744,7 +745,7 @@ func TestMHCRequestsFromMachine(t *testing.T) { }, { testCase: "more than one match", - mhcs: []*mapiv1beta1.MachineHealthCheck{ + mhcs: []*machinev1.MachineHealthCheck{ { ObjectMeta: metav1.ObjectMeta{ Name: "match1", @@ -753,14 +754,14 @@ func TestMHCRequestsFromMachine(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "foo": "bar", }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, { ObjectMeta: metav1.ObjectMeta{ @@ -770,14 +771,14 @@ func TestMHCRequestsFromMachine(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "foo": "bar", }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, }, machine: maotesting.NewMachine("test", "node1"), @@ -798,7 +799,7 @@ func TestMHCRequestsFromMachine(t *testing.T) { }, { testCase: "no match", - mhcs: []*mapiv1beta1.MachineHealthCheck{ + mhcs: []*machinev1.MachineHealthCheck{ { ObjectMeta: metav1.ObjectMeta{ Name: "noMatch1", @@ -807,14 +808,14 @@ func TestMHCRequestsFromMachine(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "no": "match", }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, { ObjectMeta: metav1.ObjectMeta{ @@ -824,14 +825,14 @@ func TestMHCRequestsFromMachine(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "no": "match", }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, }, machine: maotesting.NewMachine("test", "node1"), @@ -857,14 +858,14 @@ func TestMHCRequestsFromMachine(t *testing.T) { func TestMHCRequestsFromNode(t *testing.T) { testCases := []struct { testCase string - mhcs []*mapiv1beta1.MachineHealthCheck + mhcs []*machinev1.MachineHealthCheck node *corev1.Node - machine *mapiv1beta1.Machine + machine *machinev1.Machine expectedRequests []reconcile.Request }{ { testCase: "at least one match", - mhcs: []*mapiv1beta1.MachineHealthCheck{ + mhcs: []*machinev1.MachineHealthCheck{ { ObjectMeta: metav1.ObjectMeta{ Name: "match", @@ -873,14 +874,14 @@ func TestMHCRequestsFromNode(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "foo": "bar", }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, { ObjectMeta: metav1.ObjectMeta{ @@ -890,14 +891,14 @@ func TestMHCRequestsFromNode(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "no": "match", }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, }, machine: maotesting.NewMachine("fakeMachine", "node1"), @@ -913,7 +914,7 @@ func TestMHCRequestsFromNode(t *testing.T) { }, { testCase: "more than one match", - mhcs: []*mapiv1beta1.MachineHealthCheck{ + mhcs: []*machinev1.MachineHealthCheck{ { ObjectMeta: metav1.ObjectMeta{ Name: "match1", @@ -922,14 +923,14 @@ func TestMHCRequestsFromNode(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "foo": "bar", }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, { ObjectMeta: metav1.ObjectMeta{ @@ -939,14 +940,14 @@ func TestMHCRequestsFromNode(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "foo": "bar", }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, }, machine: maotesting.NewMachine("fakeMachine", "node1"), @@ -968,7 +969,7 @@ func TestMHCRequestsFromNode(t *testing.T) { }, { testCase: "no match", - mhcs: []*mapiv1beta1.MachineHealthCheck{ + mhcs: []*machinev1.MachineHealthCheck{ { ObjectMeta: metav1.ObjectMeta{ Name: "noMatch1", @@ -977,14 +978,14 @@ func TestMHCRequestsFromNode(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "no": "match", }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, { ObjectMeta: metav1.ObjectMeta{ @@ -994,14 +995,14 @@ func TestMHCRequestsFromNode(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "no": "match", }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, }, machine: maotesting.NewMachine("fakeMachine", "node1"), @@ -1010,7 +1011,7 @@ func TestMHCRequestsFromNode(t *testing.T) { }, { testCase: "node has bad machine annotation", - mhcs: []*mapiv1beta1.MachineHealthCheck{ + mhcs: []*machinev1.MachineHealthCheck{ { ObjectMeta: metav1.ObjectMeta{ Name: "mhc1", @@ -1019,14 +1020,14 @@ func TestMHCRequestsFromNode(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "no": "match", }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, }, machine: maotesting.NewMachine("noNodeAnnotation", "node1"), @@ -1052,15 +1053,15 @@ func TestMHCRequestsFromNode(t *testing.T) { } func TestGetMachinesFromMHC(t *testing.T) { - machines := []mapiv1beta1.Machine{ + machines := []machinev1.Machine{ *maotesting.NewMachine("test1", "node1"), *maotesting.NewMachine("test2", "node2"), } testCases := []struct { testCase string - mhc *mapiv1beta1.MachineHealthCheck - machines []mapiv1beta1.Machine - expectedMachines []mapiv1beta1.Machine + mhc *machinev1.MachineHealthCheck + machines []machinev1.Machine + expectedMachines []machinev1.Machine expectedError bool }{ { @@ -1071,7 +1072,7 @@ func TestGetMachinesFromMHC(t *testing.T) { }, { testCase: "no match", - mhc: &mapiv1beta1.MachineHealthCheck{ + mhc: &machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "match", Namespace: namespace, @@ -1079,21 +1080,21 @@ func TestGetMachinesFromMHC(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "dont": "match", }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, machines: machines, expectedMachines: nil, }, { testCase: "bad selector", - mhc: &mapiv1beta1.MachineHealthCheck{ + mhc: &machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "match", Namespace: namespace, @@ -1101,14 +1102,14 @@ func TestGetMachinesFromMHC(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "bad selector": "''", }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, machines: machines, expectedMachines: nil, @@ -1141,8 +1142,8 @@ func TestGetTargetsFromMHC(t *testing.T) { mhc := maotesting.NewMachineHealthCheck("findTargets") testCases := []struct { testCase string - mhc *mapiv1beta1.MachineHealthCheck - machines []*mapiv1beta1.Machine + mhc *machinev1.MachineHealthCheck + machines []*machinev1.Machine nodes []*corev1.Node expectedTargets []target expectedError bool @@ -1150,7 +1151,7 @@ func TestGetTargetsFromMHC(t *testing.T) { { testCase: "at least one match", mhc: mhc, - machines: []*mapiv1beta1.Machine{ + machines: []*machinev1.Machine{ machine1, { TypeMeta: metav1.TypeMeta{Kind: "Machine"}, @@ -1161,7 +1162,7 @@ func TestGetTargetsFromMHC(t *testing.T) { Labels: map[string]string{"no": "match"}, OwnerReferences: []metav1.OwnerReference{{Kind: "MachineSet"}}, }, - Spec: mapiv1beta1.MachineSpec{}, + Spec: machinev1.MachineSpec{}, }, }, nodes: []*corev1.Node{ @@ -1227,7 +1228,7 @@ func TestGetTargetsFromMHC(t *testing.T) { { testCase: "more than one match", mhc: mhc, - machines: []*mapiv1beta1.Machine{ + machines: []*machinev1.Machine{ machine1, machine2, }, @@ -1319,7 +1320,7 @@ func TestGetTargetsFromMHC(t *testing.T) { { testCase: "machine has no node", mhc: mhc, - machines: []*mapiv1beta1.Machine{ + machines: []*machinev1.Machine{ { TypeMeta: metav1.TypeMeta{Kind: "Machine"}, ObjectMeta: metav1.ObjectMeta{ @@ -1329,15 +1330,15 @@ func TestGetTargetsFromMHC(t *testing.T) { Labels: map[string]string{"foo": "bar"}, OwnerReferences: []metav1.OwnerReference{{Kind: "MachineSet"}}, }, - Spec: mapiv1beta1.MachineSpec{}, - Status: mapiv1beta1.MachineStatus{}, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{}, }, }, nodes: []*corev1.Node{}, expectedTargets: []target{ { MHC: *mhc, - Machine: mapiv1beta1.Machine{ + Machine: machinev1.Machine{ TypeMeta: metav1.TypeMeta{Kind: "Machine"}, ObjectMeta: metav1.ObjectMeta{ Annotations: make(map[string]string), @@ -1348,8 +1349,8 @@ func TestGetTargetsFromMHC(t *testing.T) { // the following line is to account for a change in the fake client, see https://github.com/kubernetes-sigs/controller-runtime/pull/1306 ResourceVersion: "999", }, - Spec: mapiv1beta1.MachineSpec{}, - Status: mapiv1beta1.MachineStatus{}, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{}, }, Node: nil, }, @@ -1358,7 +1359,7 @@ func TestGetTargetsFromMHC(t *testing.T) { { testCase: "node not found", mhc: mhc, - machines: []*mapiv1beta1.Machine{ + machines: []*machinev1.Machine{ machine1, }, nodes: []*corev1.Node{}, @@ -1401,14 +1402,14 @@ func TestGetTargetsFromMHC(t *testing.T) { func TestGetNodeFromMachine(t *testing.T) { testCases := []struct { testCase string - machine *mapiv1beta1.Machine + machine *machinev1.Machine node *corev1.Node expectedNode *corev1.Node expectedError bool }{ { testCase: "match", - machine: &mapiv1beta1.Machine{ + machine: &machinev1.Machine{ TypeMeta: metav1.TypeMeta{Kind: "Machine"}, ObjectMeta: metav1.ObjectMeta{ Annotations: make(map[string]string), @@ -1417,8 +1418,8 @@ func TestGetNodeFromMachine(t *testing.T) { Labels: map[string]string{"foo": "bar"}, OwnerReferences: []metav1.OwnerReference{{Kind: "MachineSet"}}, }, - Spec: mapiv1beta1.MachineSpec{}, - Status: mapiv1beta1.MachineStatus{ + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{ NodeRef: &corev1.ObjectReference{ Name: "node", Namespace: metav1.NamespaceNone, @@ -1464,7 +1465,7 @@ func TestGetNodeFromMachine(t *testing.T) { }, { testCase: "no nodeRef", - machine: &mapiv1beta1.Machine{ + machine: &machinev1.Machine{ TypeMeta: metav1.TypeMeta{Kind: "Machine"}, ObjectMeta: metav1.ObjectMeta{ Annotations: make(map[string]string), @@ -1473,8 +1474,8 @@ func TestGetNodeFromMachine(t *testing.T) { Labels: map[string]string{"foo": "bar"}, OwnerReferences: []metav1.OwnerReference{{Kind: "MachineSet"}}, }, - Spec: mapiv1beta1.MachineSpec{}, - Status: mapiv1beta1.MachineStatus{}, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{}, }, node: &corev1.Node{ ObjectMeta: metav1.ObjectMeta{ @@ -1497,7 +1498,7 @@ func TestGetNodeFromMachine(t *testing.T) { }, { testCase: "node not found", - machine: &mapiv1beta1.Machine{ + machine: &machinev1.Machine{ TypeMeta: metav1.TypeMeta{Kind: "Machine"}, ObjectMeta: metav1.ObjectMeta{ Annotations: make(map[string]string), @@ -1506,8 +1507,8 @@ func TestGetNodeFromMachine(t *testing.T) { Labels: map[string]string{"foo": "bar"}, OwnerReferences: []metav1.OwnerReference{{Kind: "MachineSet"}}, }, - Spec: mapiv1beta1.MachineSpec{}, - Status: mapiv1beta1.MachineStatus{ + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{ NodeRef: &corev1.ObjectReference{ Name: "nonExistingNode", Namespace: metav1.NamespaceNone, @@ -1572,7 +1573,7 @@ func TestNeedsRemediation(t *testing.T) { }, }, }, - MHC: mapiv1beta1.MachineHealthCheck{ + MHC: machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -1580,13 +1581,13 @@ func TestNeedsRemediation(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "foo": "bar", }, }, - UnhealthyConditions: []mapiv1beta1.UnhealthyCondition{ + UnhealthyConditions: []machinev1.UnhealthyCondition{ { Type: "Ready", Status: "Unknown", @@ -1599,7 +1600,7 @@ func TestNeedsRemediation(t *testing.T) { }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, }, timeoutForMachineToHaveNode: defaultNodeStartupTimeout, @@ -1612,7 +1613,7 @@ func TestNeedsRemediation(t *testing.T) { target: &target{ Machine: *maotesting.NewMachine("test", "node"), Node: &corev1.Node{}, - MHC: mapiv1beta1.MachineHealthCheck{ + MHC: machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -1620,13 +1621,13 @@ func TestNeedsRemediation(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "foo": "bar", }, }, - UnhealthyConditions: []mapiv1beta1.UnhealthyCondition{ + UnhealthyConditions: []machinev1.UnhealthyCondition{ { Type: "Ready", Status: "Unknown", @@ -1639,7 +1640,7 @@ func TestNeedsRemediation(t *testing.T) { }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, }, timeoutForMachineToHaveNode: defaultNodeStartupTimeout, @@ -1650,7 +1651,7 @@ func TestNeedsRemediation(t *testing.T) { { testCase: "unhealthy: nodeRef nil longer than timeout", target: &target{ - Machine: mapiv1beta1.Machine{ + Machine: machinev1.Machine{ TypeMeta: metav1.TypeMeta{Kind: "Machine"}, ObjectMeta: metav1.ObjectMeta{ Annotations: make(map[string]string), @@ -1659,13 +1660,13 @@ func TestNeedsRemediation(t *testing.T) { Labels: map[string]string{"foo": "bar"}, OwnerReferences: []metav1.OwnerReference{{Kind: "MachineSet"}}, }, - Spec: mapiv1beta1.MachineSpec{}, - Status: mapiv1beta1.MachineStatus{ + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{ LastUpdated: &metav1.Time{Time: time.Now().Add(-defaultNodeStartupTimeout - 1*time.Second)}, }, }, Node: nil, - MHC: mapiv1beta1.MachineHealthCheck{ + MHC: machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -1673,13 +1674,13 @@ func TestNeedsRemediation(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "foo": "bar", }, }, - UnhealthyConditions: []mapiv1beta1.UnhealthyCondition{ + UnhealthyConditions: []machinev1.UnhealthyCondition{ { Type: "Ready", Status: "Unknown", @@ -1692,7 +1693,7 @@ func TestNeedsRemediation(t *testing.T) { }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, }, timeoutForMachineToHaveNode: defaultNodeStartupTimeout, @@ -1703,7 +1704,7 @@ func TestNeedsRemediation(t *testing.T) { { testCase: "unhealthy: nodeRef nil, timeout disabled", target: &target{ - Machine: mapiv1beta1.Machine{ + Machine: machinev1.Machine{ TypeMeta: metav1.TypeMeta{Kind: "Machine"}, ObjectMeta: metav1.ObjectMeta{ Annotations: make(map[string]string), @@ -1712,13 +1713,13 @@ func TestNeedsRemediation(t *testing.T) { Labels: map[string]string{"foo": "bar"}, OwnerReferences: []metav1.OwnerReference{{Kind: "MachineSet"}}, }, - Spec: mapiv1beta1.MachineSpec{}, - Status: mapiv1beta1.MachineStatus{ + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{ LastUpdated: &metav1.Time{Time: time.Now().Add(time.Duration(-defaultNodeStartupTimeout) - 1*time.Second)}, }, }, Node: nil, - MHC: mapiv1beta1.MachineHealthCheck{ + MHC: machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -1726,13 +1727,13 @@ func TestNeedsRemediation(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "foo": "bar", }, }, - UnhealthyConditions: []mapiv1beta1.UnhealthyCondition{ + UnhealthyConditions: []machinev1.UnhealthyCondition{ { Type: "Ready", Status: "Unknown", @@ -1745,7 +1746,7 @@ func TestNeedsRemediation(t *testing.T) { }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, }, timeoutForMachineToHaveNode: time.Duration(0), @@ -1756,7 +1757,7 @@ func TestNeedsRemediation(t *testing.T) { { testCase: "unhealthy: meet conditions criteria", target: &target{ - Machine: mapiv1beta1.Machine{ + Machine: machinev1.Machine{ TypeMeta: metav1.TypeMeta{Kind: "Machine"}, ObjectMeta: metav1.ObjectMeta{ Annotations: make(map[string]string), @@ -1765,8 +1766,8 @@ func TestNeedsRemediation(t *testing.T) { Labels: map[string]string{"foo": "bar"}, OwnerReferences: []metav1.OwnerReference{{Kind: "MachineSet"}}, }, - Spec: mapiv1beta1.MachineSpec{}, - Status: mapiv1beta1.MachineStatus{ + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{ LastUpdated: &metav1.Time{Time: time.Now().Add(-defaultNodeStartupTimeout - 1*time.Second)}, }, }, @@ -1793,7 +1794,7 @@ func TestNeedsRemediation(t *testing.T) { }, }, }, - MHC: mapiv1beta1.MachineHealthCheck{ + MHC: machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -1801,13 +1802,13 @@ func TestNeedsRemediation(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "foo": "bar", }, }, - UnhealthyConditions: []mapiv1beta1.UnhealthyCondition{ + UnhealthyConditions: []machinev1.UnhealthyCondition{ { Type: "Ready", Status: "Unknown", @@ -1820,7 +1821,7 @@ func TestNeedsRemediation(t *testing.T) { }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, }, timeoutForMachineToHaveNode: defaultNodeStartupTimeout, @@ -1831,7 +1832,7 @@ func TestNeedsRemediation(t *testing.T) { { testCase: "unhealthy: machine phase failed", target: &target{ - Machine: mapiv1beta1.Machine{ + Machine: machinev1.Machine{ TypeMeta: metav1.TypeMeta{Kind: "Machine"}, ObjectMeta: metav1.ObjectMeta{ Annotations: make(map[string]string), @@ -1840,13 +1841,13 @@ func TestNeedsRemediation(t *testing.T) { Labels: map[string]string{"foo": "bar"}, OwnerReferences: []metav1.OwnerReference{{Kind: "MachineSet"}}, }, - Spec: mapiv1beta1.MachineSpec{}, - Status: mapiv1beta1.MachineStatus{ + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{ Phase: &machineFailed, }, }, Node: nil, - MHC: mapiv1beta1.MachineHealthCheck{ + MHC: machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -1854,13 +1855,13 @@ func TestNeedsRemediation(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "foo": "bar", }, }, - UnhealthyConditions: []mapiv1beta1.UnhealthyCondition{ + UnhealthyConditions: []machinev1.UnhealthyCondition{ { Type: "Ready", Status: "Unknown", @@ -1873,7 +1874,7 @@ func TestNeedsRemediation(t *testing.T) { }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, }, timeoutForMachineToHaveNode: defaultNodeStartupTimeout, @@ -1884,7 +1885,7 @@ func TestNeedsRemediation(t *testing.T) { { testCase: "healthy: meet conditions criteria but timeout", target: &target{ - Machine: mapiv1beta1.Machine{ + Machine: machinev1.Machine{ TypeMeta: metav1.TypeMeta{Kind: "Machine"}, ObjectMeta: metav1.ObjectMeta{ Annotations: make(map[string]string), @@ -1893,8 +1894,8 @@ func TestNeedsRemediation(t *testing.T) { Labels: map[string]string{"foo": "bar"}, OwnerReferences: []metav1.OwnerReference{{Kind: "MachineSet"}}, }, - Spec: mapiv1beta1.MachineSpec{}, - Status: mapiv1beta1.MachineStatus{ + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{ LastUpdated: &metav1.Time{Time: time.Now().Add(-defaultNodeStartupTimeout - 1*time.Second)}, }, }, @@ -1921,7 +1922,7 @@ func TestNeedsRemediation(t *testing.T) { }, }, }, - MHC: mapiv1beta1.MachineHealthCheck{ + MHC: machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -1929,13 +1930,13 @@ func TestNeedsRemediation(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "foo": "bar", }, }, - UnhealthyConditions: []mapiv1beta1.UnhealthyCondition{ + UnhealthyConditions: []machinev1.UnhealthyCondition{ { Type: "Ready", Status: "Unknown", @@ -1948,7 +1949,7 @@ func TestNeedsRemediation(t *testing.T) { }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, }, timeoutForMachineToHaveNode: defaultNodeStartupTimeout, @@ -2046,7 +2047,7 @@ func TestRemediate(t *testing.T) { { testCase: "no master", target: &target{ - Machine: mapiv1beta1.Machine{ + Machine: machinev1.Machine{ TypeMeta: metav1.TypeMeta{ Kind: "Machine", APIVersion: "machine.openshift.io/v1beta1", @@ -2063,8 +2064,8 @@ func TestRemediate(t *testing.T) { }, }, }, - Spec: mapiv1beta1.MachineSpec{}, - Status: mapiv1beta1.MachineStatus{}, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{}, }, Node: &corev1.Node{ ObjectMeta: metav1.ObjectMeta{ @@ -2080,7 +2081,7 @@ func TestRemediate(t *testing.T) { }, Status: corev1.NodeStatus{}, }, - MHC: mapiv1beta1.MachineHealthCheck{}, + MHC: machinev1.MachineHealthCheck{}, }, deletion: true, expectedError: false, @@ -2089,7 +2090,7 @@ func TestRemediate(t *testing.T) { { testCase: "node master", target: &target{ - Machine: mapiv1beta1.Machine{ + Machine: machinev1.Machine{ TypeMeta: metav1.TypeMeta{ Kind: "Machine", APIVersion: "machine.openshift.io/v1beta1", @@ -2107,8 +2108,8 @@ func TestRemediate(t *testing.T) { }, UID: "uid", }, - //Spec: mapiv1beta1.MachineSpec{}, - //Status: mapiv1beta1.MachineStatus{}, + //Spec: machinev1.MachineSpec{}, + //Status: machinev1.MachineStatus{}, }, Node: &corev1.Node{ ObjectMeta: metav1.ObjectMeta{ @@ -2126,7 +2127,7 @@ func TestRemediate(t *testing.T) { }, Status: corev1.NodeStatus{}, }, - MHC: mapiv1beta1.MachineHealthCheck{}, + MHC: machinev1.MachineHealthCheck{}, }, deletion: true, expectedError: false, @@ -2135,7 +2136,7 @@ func TestRemediate(t *testing.T) { { testCase: "machine master", target: &target{ - Machine: mapiv1beta1.Machine{ + Machine: machinev1.Machine{ TypeMeta: metav1.TypeMeta{ Kind: "Machine", APIVersion: "machine.openshift.io/v1beta1", @@ -2154,11 +2155,11 @@ func TestRemediate(t *testing.T) { }, }, }, - Spec: mapiv1beta1.MachineSpec{}, - Status: mapiv1beta1.MachineStatus{}, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{}, }, Node: &corev1.Node{}, - MHC: mapiv1beta1.MachineHealthCheck{}, + MHC: machinev1.MachineHealthCheck{}, }, deletion: true, expectedError: false, @@ -2176,7 +2177,7 @@ func TestRemediate(t *testing.T) { t.Errorf("Case: %v. Got: %v, expected error: %v", tc.testCase, err, tc.expectedError) } assertEvents(t, tc.testCase, tc.expectedEvents, recorder.Events) - machine := &mapiv1beta1.Machine{} + machine := &machinev1.Machine{} err := r.client.Get(context.TODO(), namespacedName(&tc.target.Machine), machine) if tc.deletion { if err != nil { @@ -2199,14 +2200,14 @@ func TestRemediate(t *testing.T) { func TestReconcileStatus(t *testing.T) { testCases := []struct { testCase string - mhc *mapiv1beta1.MachineHealthCheck + mhc *machinev1.MachineHealthCheck totalTargets int currentHealthy int remediationsAllowed int32 }{ { testCase: "status gets new values", - mhc: &mapiv1beta1.MachineHealthCheck{ + mhc: &machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -2214,10 +2215,10 @@ func TestReconcileStatus(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{}, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, totalTargets: 10, currentHealthy: 5, @@ -2225,7 +2226,7 @@ func TestReconcileStatus(t *testing.T) { }, { testCase: "when the unhealthy machines exceed maxUnhealthy", - mhc: &mapiv1beta1.MachineHealthCheck{ + mhc: &machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -2233,11 +2234,11 @@ func TestReconcileStatus(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{}, MaxUnhealthy: &intstr.IntOrString{Type: intstr.String, StrVal: "40%"}, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, totalTargets: 10, currentHealthy: 5, @@ -2245,7 +2246,7 @@ func TestReconcileStatus(t *testing.T) { }, { testCase: "when the unhealthy machines does not exceed maxUnhealthy", - mhc: &mapiv1beta1.MachineHealthCheck{ + mhc: &machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -2253,11 +2254,11 @@ func TestReconcileStatus(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{}, MaxUnhealthy: &intstr.IntOrString{Type: intstr.String, StrVal: "40%"}, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, totalTargets: 10, currentHealthy: 7, @@ -2278,7 +2279,7 @@ func TestReconcileStatus(t *testing.T) { if err := r.reconcileStatus(mergeBase, tc.mhc); err != nil { t.Fatalf("Unexpected error: %v", err) } - mhc := &mapiv1beta1.MachineHealthCheck{} + mhc := &machinev1.MachineHealthCheck{} if err := r.client.Get(context.TODO(), namespacedName(tc.mhc), mhc); err != nil { t.Fatalf("Unexpected error: %v", err) } @@ -2310,7 +2311,7 @@ func TestHealthCheckTargets(t *testing.T) { testCase: "one healthy, one unhealthy", targets: []target{ { - Machine: mapiv1beta1.Machine{ + Machine: machinev1.Machine{ TypeMeta: metav1.TypeMeta{Kind: "Machine"}, ObjectMeta: metav1.ObjectMeta{ Annotations: make(map[string]string), @@ -2319,8 +2320,8 @@ func TestHealthCheckTargets(t *testing.T) { Labels: map[string]string{"foo": "bar"}, OwnerReferences: []metav1.OwnerReference{{Kind: "MachineSet"}}, }, - Spec: mapiv1beta1.MachineSpec{}, - Status: mapiv1beta1.MachineStatus{}, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{}, }, Node: &corev1.Node{ ObjectMeta: metav1.ObjectMeta{ @@ -2345,7 +2346,7 @@ func TestHealthCheckTargets(t *testing.T) { }, }, }, - MHC: mapiv1beta1.MachineHealthCheck{ + MHC: machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -2353,13 +2354,13 @@ func TestHealthCheckTargets(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "foo": "bar", }, }, - UnhealthyConditions: []mapiv1beta1.UnhealthyCondition{ + UnhealthyConditions: []machinev1.UnhealthyCondition{ { Type: "Ready", Status: "Unknown", @@ -2372,11 +2373,11 @@ func TestHealthCheckTargets(t *testing.T) { }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, }, { - Machine: mapiv1beta1.Machine{ + Machine: machinev1.Machine{ TypeMeta: metav1.TypeMeta{Kind: "Machine"}, ObjectMeta: metav1.ObjectMeta{ Annotations: make(map[string]string), @@ -2385,8 +2386,8 @@ func TestHealthCheckTargets(t *testing.T) { Labels: map[string]string{"foo": "bar"}, OwnerReferences: []metav1.OwnerReference{{Kind: "MachineSet"}}, }, - Spec: mapiv1beta1.MachineSpec{}, - Status: mapiv1beta1.MachineStatus{}, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{}, }, Node: &corev1.Node{ ObjectMeta: metav1.ObjectMeta{ @@ -2411,7 +2412,7 @@ func TestHealthCheckTargets(t *testing.T) { }, }, }, - MHC: mapiv1beta1.MachineHealthCheck{ + MHC: machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -2419,13 +2420,13 @@ func TestHealthCheckTargets(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "foo": "bar", }, }, - UnhealthyConditions: []mapiv1beta1.UnhealthyCondition{ + UnhealthyConditions: []machinev1.UnhealthyCondition{ { Type: "Ready", Status: "Unknown", @@ -2438,7 +2439,7 @@ func TestHealthCheckTargets(t *testing.T) { }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, }, }, @@ -2446,7 +2447,7 @@ func TestHealthCheckTargets(t *testing.T) { currentHealthy: 1, needRemediationTargets: []target{ { - Machine: mapiv1beta1.Machine{ + Machine: machinev1.Machine{ TypeMeta: metav1.TypeMeta{Kind: "Machine"}, ObjectMeta: metav1.ObjectMeta{ Annotations: make(map[string]string), @@ -2455,8 +2456,8 @@ func TestHealthCheckTargets(t *testing.T) { Labels: map[string]string{"foo": "bar"}, OwnerReferences: []metav1.OwnerReference{{Kind: "MachineSet"}}, }, - Spec: mapiv1beta1.MachineSpec{}, - Status: mapiv1beta1.MachineStatus{}, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{}, }, Node: &corev1.Node{ ObjectMeta: metav1.ObjectMeta{ @@ -2481,7 +2482,7 @@ func TestHealthCheckTargets(t *testing.T) { }, }, }, - MHC: mapiv1beta1.MachineHealthCheck{ + MHC: machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -2489,13 +2490,13 @@ func TestHealthCheckTargets(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "foo": "bar", }, }, - UnhealthyConditions: []mapiv1beta1.UnhealthyCondition{ + UnhealthyConditions: []machinev1.UnhealthyCondition{ { Type: "Ready", Status: "Unknown", @@ -2508,7 +2509,7 @@ func TestHealthCheckTargets(t *testing.T) { }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, }, }, @@ -2519,7 +2520,7 @@ func TestHealthCheckTargets(t *testing.T) { testCase: "two checkTimes", targets: []target{ { - Machine: mapiv1beta1.Machine{ + Machine: machinev1.Machine{ TypeMeta: metav1.TypeMeta{Kind: "Machine"}, ObjectMeta: metav1.ObjectMeta{ Annotations: make(map[string]string), @@ -2528,13 +2529,13 @@ func TestHealthCheckTargets(t *testing.T) { Labels: map[string]string{"foo": "bar"}, OwnerReferences: []metav1.OwnerReference{{Kind: "MachineSet"}}, }, - Spec: mapiv1beta1.MachineSpec{}, - Status: mapiv1beta1.MachineStatus{ + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{ LastUpdated: &metav1.Time{Time: now.Add(-defaultNodeStartupTimeout + 1*time.Minute)}, }, }, Node: nil, - MHC: mapiv1beta1.MachineHealthCheck{ + MHC: machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -2542,13 +2543,13 @@ func TestHealthCheckTargets(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "foo": "bar", }, }, - UnhealthyConditions: []mapiv1beta1.UnhealthyCondition{ + UnhealthyConditions: []machinev1.UnhealthyCondition{ { Type: "Ready", Status: "Unknown", @@ -2561,11 +2562,11 @@ func TestHealthCheckTargets(t *testing.T) { }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, }, { - Machine: mapiv1beta1.Machine{ + Machine: machinev1.Machine{ TypeMeta: metav1.TypeMeta{Kind: "Machine"}, ObjectMeta: metav1.ObjectMeta{ Annotations: make(map[string]string), @@ -2574,8 +2575,8 @@ func TestHealthCheckTargets(t *testing.T) { Labels: map[string]string{"foo": "bar"}, OwnerReferences: []metav1.OwnerReference{{Kind: "MachineSet"}}, }, - Spec: mapiv1beta1.MachineSpec{}, - Status: mapiv1beta1.MachineStatus{}, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{}, }, Node: &corev1.Node{ ObjectMeta: metav1.ObjectMeta{ @@ -2600,7 +2601,7 @@ func TestHealthCheckTargets(t *testing.T) { }, }, }, - MHC: mapiv1beta1.MachineHealthCheck{ + MHC: machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -2608,13 +2609,13 @@ func TestHealthCheckTargets(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "foo": "bar", }, }, - UnhealthyConditions: []mapiv1beta1.UnhealthyCondition{ + UnhealthyConditions: []machinev1.UnhealthyCondition{ { Type: "Ready", Status: "Unknown", @@ -2627,7 +2628,7 @@ func TestHealthCheckTargets(t *testing.T) { }, }, }, - Status: mapiv1beta1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, }, }, }, @@ -2668,12 +2669,12 @@ func TestIsAllowedRemediation(t *testing.T) { testCases := []struct { testCase string - mhc *mapiv1beta1.MachineHealthCheck + mhc *machinev1.MachineHealthCheck expected bool }{ { testCase: "not above maxUnhealthy", - mhc: &mapiv1beta1.MachineHealthCheck{ + mhc: &machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -2681,11 +2682,11 @@ func TestIsAllowedRemediation(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{}, MaxUnhealthy: &maxUnhealthyInt, }, - Status: mapiv1beta1.MachineHealthCheckStatus{ + Status: machinev1.MachineHealthCheckStatus{ ExpectedMachines: IntPtr(5), CurrentHealthy: IntPtr(3), }, @@ -2694,7 +2695,7 @@ func TestIsAllowedRemediation(t *testing.T) { }, { testCase: "above maxUnhealthy", - mhc: &mapiv1beta1.MachineHealthCheck{ + mhc: &machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -2702,11 +2703,11 @@ func TestIsAllowedRemediation(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{}, MaxUnhealthy: &maxUnhealthyInt, }, - Status: mapiv1beta1.MachineHealthCheckStatus{ + Status: machinev1.MachineHealthCheckStatus{ ExpectedMachines: IntPtr(5), CurrentHealthy: IntPtr(2), }, @@ -2715,7 +2716,7 @@ func TestIsAllowedRemediation(t *testing.T) { }, { testCase: "maxUnhealthy is negative", - mhc: &mapiv1beta1.MachineHealthCheck{ + mhc: &machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -2723,11 +2724,11 @@ func TestIsAllowedRemediation(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{}, MaxUnhealthy: &maxUnhealthyNegative, }, - Status: mapiv1beta1.MachineHealthCheckStatus{ + Status: machinev1.MachineHealthCheckStatus{ ExpectedMachines: IntPtr(5), CurrentHealthy: IntPtr(2), }, @@ -2736,7 +2737,7 @@ func TestIsAllowedRemediation(t *testing.T) { }, { testCase: "not above maxUnhealthy (percentange)", - mhc: &mapiv1beta1.MachineHealthCheck{ + mhc: &machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -2744,11 +2745,11 @@ func TestIsAllowedRemediation(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{}, MaxUnhealthy: &maxUnhealthyString, }, - Status: mapiv1beta1.MachineHealthCheckStatus{ + Status: machinev1.MachineHealthCheckStatus{ ExpectedMachines: IntPtr(5), CurrentHealthy: IntPtr(3), }, @@ -2757,7 +2758,7 @@ func TestIsAllowedRemediation(t *testing.T) { }, { testCase: "above maxUnhealthy (percentange)", - mhc: &mapiv1beta1.MachineHealthCheck{ + mhc: &machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -2765,11 +2766,11 @@ func TestIsAllowedRemediation(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{}, MaxUnhealthy: &maxUnhealthyString, }, - Status: mapiv1beta1.MachineHealthCheckStatus{ + Status: machinev1.MachineHealthCheckStatus{ ExpectedMachines: IntPtr(5), CurrentHealthy: IntPtr(2), }, @@ -2778,7 +2779,7 @@ func TestIsAllowedRemediation(t *testing.T) { }, { testCase: "not above maxUnhealthy (int in string)", - mhc: &mapiv1beta1.MachineHealthCheck{ + mhc: &machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -2786,11 +2787,11 @@ func TestIsAllowedRemediation(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{}, MaxUnhealthy: &maxUnhealthyIntInString, }, - Status: mapiv1beta1.MachineHealthCheckStatus{ + Status: machinev1.MachineHealthCheckStatus{ ExpectedMachines: IntPtr(5), CurrentHealthy: IntPtr(3), }, @@ -2799,7 +2800,7 @@ func TestIsAllowedRemediation(t *testing.T) { }, { testCase: "above maxUnhealthy (int in string)", - mhc: &mapiv1beta1.MachineHealthCheck{ + mhc: &machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -2807,11 +2808,11 @@ func TestIsAllowedRemediation(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{}, MaxUnhealthy: &maxUnhealthyIntInString, }, - Status: mapiv1beta1.MachineHealthCheckStatus{ + Status: machinev1.MachineHealthCheckStatus{ ExpectedMachines: IntPtr(5), CurrentHealthy: IntPtr(2), }, @@ -2820,7 +2821,7 @@ func TestIsAllowedRemediation(t *testing.T) { }, { testCase: "nil values", - mhc: &mapiv1beta1.MachineHealthCheck{ + mhc: &machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -2828,11 +2829,11 @@ func TestIsAllowedRemediation(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{}, MaxUnhealthy: &maxUnhealthyString, }, - Status: mapiv1beta1.MachineHealthCheckStatus{ + Status: machinev1.MachineHealthCheckStatus{ ExpectedMachines: nil, CurrentHealthy: nil, }, @@ -2841,7 +2842,7 @@ func TestIsAllowedRemediation(t *testing.T) { }, { testCase: "invalid string value", - mhc: &mapiv1beta1.MachineHealthCheck{ + mhc: &machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: namespace, @@ -2849,11 +2850,11 @@ func TestIsAllowedRemediation(t *testing.T) { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1beta1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: metav1.LabelSelector{}, MaxUnhealthy: &maxUnhealthyMixedString, }, - Status: mapiv1beta1.MachineHealthCheckStatus{ + Status: machinev1.MachineHealthCheckStatus{ ExpectedMachines: nil, CurrentHealthy: nil, }, @@ -2920,11 +2921,11 @@ func TestGetMaxUnhealthy(t *testing.T) { t.Run(tc.name, func(t *testing.T) { g := NewWithT(t) - mhc := &mapiv1beta1.MachineHealthCheck{ - Spec: mapiv1beta1.MachineHealthCheckSpec{ + mhc := &machinev1.MachineHealthCheck{ + Spec: machinev1.MachineHealthCheckSpec{ MaxUnhealthy: tc.maxUnhealthy, }, - Status: mapiv1beta1.MachineHealthCheckStatus{ + Status: machinev1.MachineHealthCheckStatus{ ExpectedMachines: &tc.expectedMachines, }, } @@ -3092,7 +3093,7 @@ func assertBaseReconcile(t *testing.T, tc testCase, ctx context.Context, r *Reco } g := NewWithT(t) if tc.expectedStatus != nil { - mhc := &mapiv1beta1.MachineHealthCheck{} + mhc := &machinev1.MachineHealthCheck{} g.Expect(r.client.Get(ctx, request.NamespacedName, mhc)).To(Succeed()) g.Expect(tc.expectedStatus).To(MatchMachineHealthCheckStatus(&mhc.Status)) } @@ -3113,7 +3114,7 @@ func assertExternalRemediation(t *testing.T, tc testCase, ctx context.Context, r } } -func newMachineHealthCheckWithRemediationTemplate(infraRemediationTmpl *unstructured.Unstructured) *mapiv1beta1.MachineHealthCheck { +func newMachineHealthCheckWithRemediationTemplate(infraRemediationTmpl *unstructured.Unstructured) *machinev1.MachineHealthCheck { mhc := maotesting.NewMachineHealthCheck("machineHealthCheck") remediationTemplateObjRef := &corev1.ObjectReference{ diff --git a/pkg/controller/machinehealthcheck/machinehealthcheck_status_matcher.go b/pkg/controller/machinehealthcheck/machinehealthcheck_status_matcher.go index 163a3fbfc1..d6b885fadc 100644 --- a/pkg/controller/machinehealthcheck/machinehealthcheck_status_matcher.go +++ b/pkg/controller/machinehealthcheck/machinehealthcheck_status_matcher.go @@ -21,23 +21,23 @@ import ( . "github.com/onsi/gomega" "github.com/onsi/gomega/types" - mapiv1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" "github.com/openshift/machine-api-operator/pkg/util/conditions" ) -// MatchMachineHealthCheckStatus returns a custom matcher to check equality of mapiv1.MachineHealthCheckStatus -func MatchMachineHealthCheckStatus(expected *mapiv1.MachineHealthCheckStatus) types.GomegaMatcher { +// MatchMachineHealthCheckStatus returns a custom matcher to check equality of machinev1..MachineHealthCheckStatus +func MatchMachineHealthCheckStatus(expected *machinev1.MachineHealthCheckStatus) types.GomegaMatcher { return &machineHealthCheckStatusMatcher{ expected: expected, } } type machineHealthCheckStatusMatcher struct { - expected *mapiv1.MachineHealthCheckStatus + expected *machinev1.MachineHealthCheckStatus } func (m machineHealthCheckStatusMatcher) Match(actual interface{}) (success bool, err error) { - actualStatus, ok := actual.(*mapiv1.MachineHealthCheckStatus) + actualStatus, ok := actual.(*machinev1.MachineHealthCheckStatus) if !ok { return false, fmt.Errorf("actual should be of type MachineHealthCheckStatus") } diff --git a/pkg/controller/machineset/controller.go b/pkg/controller/machineset/controller.go index 8380a6166d..60ee7333bf 100644 --- a/pkg/controller/machineset/controller.go +++ b/pkg/controller/machineset/controller.go @@ -25,13 +25,15 @@ import ( "sync" "time" - machinev1beta1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" "github.com/openshift/machine-api-operator/pkg/util" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + metav1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/client-go/tools/record" "k8s.io/klog/v2" "sigs.k8s.io/controller-runtime/pkg/client" @@ -43,7 +45,7 @@ import ( ) var ( - controllerKind = machinev1beta1.SchemeGroupVersion.WithKind("MachineSet") + controllerKind = machinev1.SchemeGroupVersion.WithKind("MachineSet") // stateConfirmationTimeout is the amount of time allowed to wait for desired state. stateConfirmationTimeout = 10 * time.Second @@ -78,7 +80,7 @@ func add(mgr manager.Manager, r reconcile.Reconciler, mapFn handler.MapFunc) err // Watch for changes to MachineSet. err = c.Watch( - &source.Kind{Type: &machinev1beta1.MachineSet{}}, + &source.Kind{Type: &machinev1.MachineSet{}}, &handler.EnqueueRequestForObject{}, ) if err != nil { @@ -87,8 +89,8 @@ func add(mgr manager.Manager, r reconcile.Reconciler, mapFn handler.MapFunc) err // Map Machine changes to MachineSets using ControllerRef. err = c.Watch( - &source.Kind{Type: &machinev1beta1.Machine{}}, - &handler.EnqueueRequestForOwner{IsController: true, OwnerType: &machinev1beta1.MachineSet{}}, + &source.Kind{Type: &machinev1.Machine{}}, + &handler.EnqueueRequestForOwner{IsController: true, OwnerType: &machinev1.MachineSet{}}, ) if err != nil { return err @@ -96,7 +98,7 @@ func add(mgr manager.Manager, r reconcile.Reconciler, mapFn handler.MapFunc) err // Map Machine changes to MachineSets by machining labels. return c.Watch( - &source.Kind{Type: &machinev1beta1.Machine{}}, + &source.Kind{Type: &machinev1.Machine{}}, handler.EnqueueRequestsFromMapFunc(mapFn), ) } @@ -110,7 +112,7 @@ type ReconcileMachineSet struct { func (r *ReconcileMachineSet) MachineToMachineSets(o client.Object) []reconcile.Request { result := []reconcile.Request{} - m := &machinev1beta1.Machine{} + m := &machinev1.Machine{} key := client.ObjectKey{Namespace: o.GetNamespace(), Name: o.GetName()} err := r.Client.Get(context.Background(), key, m) if err != nil { @@ -145,7 +147,7 @@ func (r *ReconcileMachineSet) MachineToMachineSets(o client.Object) []reconcile. // +kubebuilder:rbac:groups=machine.openshift.io,resources=machines,verbs=get;list;watch;create;update;patch;delete func (r *ReconcileMachineSet) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { // Fetch the MachineSet instance - machineSet := &machinev1beta1.MachineSet{} + machineSet := &machinev1.MachineSet{} if err := r.Get(ctx, request.NamespacedName, machineSet); err != nil { if apierrors.IsNotFound(err) { // Object not found, return. Created objects are automatically garbage collected. @@ -170,7 +172,7 @@ func (r *ReconcileMachineSet) Reconcile(ctx context.Context, request reconcile.R return result, err } -func (r *ReconcileMachineSet) reconcile(ctx context.Context, machineSet *machinev1beta1.MachineSet) (reconcile.Result, error) { +func (r *ReconcileMachineSet) reconcile(ctx context.Context, machineSet *machinev1.MachineSet) (reconcile.Result, error) { klog.V(4).Infof("Reconcile machineset %v", machineSet.Name) if errList := validateMachineset(machineSet); len(errList) > 0 { err := fmt.Errorf("%q machineset validation failed: %v", machineSet.Name, errList.ToAggregate().Error()) @@ -178,7 +180,7 @@ func (r *ReconcileMachineSet) reconcile(ctx context.Context, machineSet *machine return reconcile.Result{}, err } - allMachines := &machinev1beta1.MachineList{} + allMachines := &machinev1.MachineList{} if err := r.Client.List(context.Background(), allMachines, client.InNamespace(machineSet.Namespace)); err != nil { return reconcile.Result{}, fmt.Errorf("failed to list machines: %w", err) @@ -197,7 +199,7 @@ func (r *ReconcileMachineSet) reconcile(ctx context.Context, machineSet *machine // Filter out irrelevant machines (deleting/mismatch labels) and claim orphaned machines. var machineNames []string - machineSetMachines := make(map[string]*machinev1beta1.Machine) + machineSetMachines := make(map[string]*machinev1.Machine) for idx := range allMachines.Items { machine := &allMachines.Items[idx] if shouldExcludeMachine(machineSet, machine) { @@ -217,7 +219,7 @@ func (r *ReconcileMachineSet) reconcile(ctx context.Context, machineSet *machine // sort the filteredMachines from the oldest to the youngest sort.Strings(machineNames) - var filteredMachines []*machinev1beta1.Machine + var filteredMachines []*machinev1.Machine for _, machineName := range machineNames { filteredMachines = append(filteredMachines, machineSetMachines[machineName]) } @@ -263,7 +265,7 @@ func (r *ReconcileMachineSet) reconcile(ctx context.Context, machineSet *machine } // syncReplicas essentially scales machine resources up and down. -func (r *ReconcileMachineSet) syncReplicas(ms *machinev1beta1.MachineSet, machines []*machinev1beta1.Machine) error { +func (r *ReconcileMachineSet) syncReplicas(ms *machinev1.MachineSet, machines []*machinev1.Machine) error { if ms.Spec.Replicas == nil { return fmt.Errorf("the Replicas field in Spec for machineset %v is nil, this should not be allowed", ms.Name) } @@ -275,7 +277,7 @@ func (r *ReconcileMachineSet) syncReplicas(ms *machinev1beta1.MachineSet, machin klog.Infof("Too few replicas for %v %s/%s, need %d, creating %d", controllerKind, ms.Namespace, ms.Name, *(ms.Spec.Replicas), diff) - var machineList []*machinev1beta1.Machine + var machineList []*machinev1.Machine var errstrings []string for i := 0; i < diff; i++ { klog.Infof("Creating machine %d of %d, ( spec.replicas(%d) > currentMachineCount(%d) )", @@ -313,7 +315,7 @@ func (r *ReconcileMachineSet) syncReplicas(ms *machinev1beta1.MachineSet, machin var wg sync.WaitGroup wg.Add(diff) for _, machine := range machinesToDelete { - go func(targetMachine *machinev1beta1.Machine) { + go func(targetMachine *machinev1.Machine) { defer wg.Done() err := r.Client.Delete(context.Background(), targetMachine) if err != nil { @@ -341,9 +343,9 @@ func (r *ReconcileMachineSet) syncReplicas(ms *machinev1beta1.MachineSet, machin // createMachine creates a machine resource. // the name of the newly created resource is going to be created by the API server, we set the generateName field -func (r *ReconcileMachineSet) createMachine(machineSet *machinev1beta1.MachineSet) *machinev1beta1.Machine { - gv := machinev1beta1.SchemeGroupVersion - machine := &machinev1beta1.Machine{ +func (r *ReconcileMachineSet) createMachine(machineSet *machinev1.MachineSet) *machinev1.Machine { + gv := machinev1.SchemeGroupVersion + machine := &machinev1.Machine{ TypeMeta: metav1.TypeMeta{ Kind: gv.WithKind("Machine").Kind, APIVersion: gv.String(), @@ -362,7 +364,7 @@ func (r *ReconcileMachineSet) createMachine(machineSet *machinev1beta1.MachineSe } // shouldExcludeMachine returns true if the machine should be filtered out, false otherwise. -func shouldExcludeMachine(machineSet *machinev1beta1.MachineSet, machine *machinev1beta1.Machine) bool { +func shouldExcludeMachine(machineSet *machinev1.MachineSet, machine *machinev1.Machine) bool { // Ignore inactive machines. if metav1.GetControllerOf(machine) != nil && !metav1.IsControlledBy(machine, machineSet) { klog.V(4).Infof("%s not controlled by %v", machine.Name, machineSet.Name) @@ -380,18 +382,18 @@ func shouldExcludeMachine(machineSet *machinev1beta1.MachineSet, machine *machin return false } -func (r *ReconcileMachineSet) adoptOrphan(machineSet *machinev1beta1.MachineSet, machine *machinev1beta1.Machine) error { +func (r *ReconcileMachineSet) adoptOrphan(machineSet *machinev1.MachineSet, machine *machinev1.Machine) error { newRef := *metav1.NewControllerRef(machineSet, controllerKind) machine.OwnerReferences = append(machine.OwnerReferences, newRef) return r.Client.Update(context.Background(), machine) } -func (r *ReconcileMachineSet) waitForMachineCreation(machineList []*machinev1beta1.Machine) error { +func (r *ReconcileMachineSet) waitForMachineCreation(machineList []*machinev1.Machine) error { for _, machine := range machineList { pollErr := util.PollImmediate(stateConfirmationInterval, stateConfirmationTimeout, func() (bool, error) { key := client.ObjectKey{Namespace: machine.Namespace, Name: machine.Name} - if err := r.Client.Get(context.Background(), key, &machinev1beta1.Machine{}); err != nil { + if err := r.Client.Get(context.Background(), key, &machinev1.Machine{}); err != nil { if apierrors.IsNotFound(err) { return false, nil } @@ -411,10 +413,10 @@ func (r *ReconcileMachineSet) waitForMachineCreation(machineList []*machinev1bet return nil } -func (r *ReconcileMachineSet) waitForMachineDeletion(machineList []*machinev1beta1.Machine) error { +func (r *ReconcileMachineSet) waitForMachineDeletion(machineList []*machinev1.Machine) error { for _, machine := range machineList { pollErr := util.PollImmediate(stateConfirmationInterval, stateConfirmationTimeout, func() (bool, error) { - m := &machinev1beta1.Machine{} + m := &machinev1.Machine{} key := client.ObjectKey{Namespace: machine.Namespace, Name: machine.Name} err := r.Client.Get(context.Background(), key, m) diff --git a/pkg/controller/machineset/controller_test.go b/pkg/controller/machineset/controller_test.go index 0596936b1e..d809e95d9f 100644 --- a/pkg/controller/machineset/controller_test.go +++ b/pkg/controller/machineset/controller_test.go @@ -23,7 +23,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes/scheme" @@ -36,21 +36,21 @@ import ( var _ reconcile.Reconciler = &ReconcileMachineSet{} func TestMachineSetToMachines(t *testing.T) { - machineSetList := &v1beta1.MachineSetList{ + machineSetList := &machinev1.MachineSetList{ TypeMeta: metav1.TypeMeta{ Kind: "MachineSetList", }, - Items: []v1beta1.MachineSet{ + Items: []machinev1.MachineSet{ { ObjectMeta: metav1.ObjectMeta{ Name: "withMatchingLabels", Namespace: "test", }, - Spec: v1beta1.MachineSetSpec{ + Spec: machinev1.MachineSetSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ - "foo": "bar", - v1beta1.MachineClusterLabelName: "test-cluster", + "foo": "bar", + machinev1.MachineClusterLabelName: "test-cluster", }, }, }, @@ -58,7 +58,7 @@ func TestMachineSetToMachines(t *testing.T) { }, } controller := true - m := v1beta1.Machine{ + m := machinev1.Machine{ TypeMeta: metav1.TypeMeta{ Kind: "Machine", }, @@ -66,7 +66,7 @@ func TestMachineSetToMachines(t *testing.T) { Name: "withOwnerRef", Namespace: "test", Labels: map[string]string{ - v1beta1.MachineClusterLabelName: "test-cluster", + machinev1.MachineClusterLabelName: "test-cluster", }, OwnerReferences: []metav1.OwnerReference{ { @@ -77,7 +77,7 @@ func TestMachineSetToMachines(t *testing.T) { }, }, } - m2 := v1beta1.Machine{ + m2 := machinev1.Machine{ TypeMeta: metav1.TypeMeta{ Kind: "Machine", }, @@ -85,11 +85,11 @@ func TestMachineSetToMachines(t *testing.T) { Name: "noOwnerRefNoLabels", Namespace: "test", Labels: map[string]string{ - v1beta1.MachineClusterLabelName: "test-cluster", + machinev1.MachineClusterLabelName: "test-cluster", }, }, } - m3 := v1beta1.Machine{ + m3 := machinev1.Machine{ TypeMeta: metav1.TypeMeta{ Kind: "Machine", }, @@ -97,13 +97,13 @@ func TestMachineSetToMachines(t *testing.T) { Name: "withMatchingLabels", Namespace: "test", Labels: map[string]string{ - "foo": "bar", - v1beta1.MachineClusterLabelName: "test-cluster", + "foo": "bar", + machinev1.MachineClusterLabelName: "test-cluster", }, }, } testsCases := []struct { - machine v1beta1.Machine + machine machinev1.Machine object client.Object expected []reconcile.Request }{ @@ -126,7 +126,7 @@ func TestMachineSetToMachines(t *testing.T) { }, } - v1beta1.AddToScheme(scheme.Scheme) + machinev1.AddToScheme(scheme.Scheme) r := &ReconcileMachineSet{ Client: fake.NewFakeClient(&m, &m2, &m3, machineSetList), scheme: scheme.Scheme, @@ -143,13 +143,13 @@ func TestMachineSetToMachines(t *testing.T) { func TestShouldExcludeMachine(t *testing.T) { controller := true testCases := []struct { - machineSet v1beta1.MachineSet - machine v1beta1.Machine + machineSet machinev1.MachineSet + machine machinev1.Machine expected bool }{ { - machineSet: v1beta1.MachineSet{}, - machine: v1beta1.Machine{ + machineSet: machinev1.MachineSet{}, + machine: machinev1.Machine{ ObjectMeta: metav1.ObjectMeta{ Name: "withNoMatchingOwnerRef", Namespace: "test", @@ -165,8 +165,8 @@ func TestShouldExcludeMachine(t *testing.T) { expected: true, }, { - machineSet: v1beta1.MachineSet{ - Spec: v1beta1.MachineSetSpec{ + machineSet: machinev1.MachineSet{ + Spec: machinev1.MachineSetSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "foo": "bar", @@ -174,7 +174,7 @@ func TestShouldExcludeMachine(t *testing.T) { }, }, }, - machine: v1beta1.Machine{ + machine: machinev1.Machine{ ObjectMeta: metav1.ObjectMeta{ Name: "withMatchingLabels", Namespace: "test", @@ -186,8 +186,8 @@ func TestShouldExcludeMachine(t *testing.T) { expected: false, }, { - machineSet: v1beta1.MachineSet{}, - machine: v1beta1.Machine{ + machineSet: machinev1.MachineSet{}, + machine: machinev1.Machine{ ObjectMeta: metav1.ObjectMeta{ Name: "withDeletionTimestamp", Namespace: "test", @@ -210,12 +210,12 @@ func TestShouldExcludeMachine(t *testing.T) { } func TestAdoptOrphan(t *testing.T) { - m := v1beta1.Machine{ + m := machinev1.Machine{ ObjectMeta: metav1.ObjectMeta{ Name: "orphanMachine", }, } - ms := v1beta1.MachineSet{ + ms := machinev1.MachineSet{ ObjectMeta: metav1.ObjectMeta{ Name: "adoptOrphanMachine", }, @@ -223,8 +223,8 @@ func TestAdoptOrphan(t *testing.T) { controller := true blockOwnerDeletion := true testCases := []struct { - machineSet v1beta1.MachineSet - machine v1beta1.Machine + machineSet machinev1.MachineSet + machine machinev1.Machine expected []metav1.OwnerReference }{ { @@ -232,7 +232,7 @@ func TestAdoptOrphan(t *testing.T) { machineSet: ms, expected: []metav1.OwnerReference{ { - APIVersion: v1beta1.SchemeGroupVersion.String(), + APIVersion: machinev1.SchemeGroupVersion.String(), Kind: "MachineSet", Name: "adoptOrphanMachine", UID: "", @@ -243,7 +243,7 @@ func TestAdoptOrphan(t *testing.T) { }, } - v1beta1.AddToScheme(scheme.Scheme) + machinev1.AddToScheme(scheme.Scheme) r := &ReconcileMachineSet{ Client: fake.NewFakeClient(&m), scheme: scheme.Scheme, @@ -264,7 +264,7 @@ var _ = Describe("MachineSet Reconcile", func() { var rec *record.FakeRecorder BeforeEach(func() { - Expect(v1beta1.AddToScheme(scheme.Scheme)).To(Succeed()) + Expect(machinev1.AddToScheme(scheme.Scheme)).To(Succeed()) rec = record.NewFakeRecorder(32) r = &ReconcileMachineSet{ @@ -282,14 +282,14 @@ var _ = Describe("MachineSet Reconcile", func() { BeforeEach(func() { dt := metav1.Now() - ms := &v1beta1.MachineSet{ + ms := &machinev1.MachineSet{ ObjectMeta: metav1.ObjectMeta{ Name: "machineset1", Namespace: "default", DeletionTimestamp: &dt, }, - Spec: v1beta1.MachineSetSpec{ - Template: v1beta1.MachineTemplateSpec{}, + Spec: machinev1.MachineSetSpec{ + Template: machinev1.MachineTemplateSpec{}, }} r.Client = fake.NewFakeClientWithScheme(scheme.Scheme, ms) @@ -307,12 +307,12 @@ var _ = Describe("MachineSet Reconcile", func() { Context("record event if reconcile fails", func() { BeforeEach(func() { var replicas int32 - ms := &v1beta1.MachineSet{ + ms := &machinev1.MachineSet{ ObjectMeta: metav1.ObjectMeta{ Name: "machineset1", Namespace: "default", }, - Spec: v1beta1.MachineSetSpec{ + Spec: machinev1.MachineSetSpec{ Replicas: &replicas, }, } diff --git a/pkg/controller/machineset/delete_policy.go b/pkg/controller/machineset/delete_policy.go index b0289323f4..cef86efed1 100644 --- a/pkg/controller/machineset/delete_policy.go +++ b/pkg/controller/machineset/delete_policy.go @@ -21,7 +21,7 @@ import ( "math" "sort" - "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -42,10 +42,10 @@ const ( secondsPerTenDays float64 = 864000 ) -type deletePriorityFunc func(machine *v1beta1.Machine) deletePriority +type deletePriorityFunc func(machine *machinev1.Machine) deletePriority // maps the creation timestamp onto the 0-100 priority range -func oldestDeletePriority(machine *v1beta1.Machine) deletePriority { +func oldestDeletePriority(machine *machinev1.Machine) deletePriority { if machine.DeletionTimestamp != nil && !machine.DeletionTimestamp.IsZero() { return mustDelete } @@ -65,7 +65,7 @@ func oldestDeletePriority(machine *v1beta1.Machine) deletePriority { return deletePriority(float64(mustDelete) * (1.0 - math.Exp(-d.Seconds()/secondsPerTenDays))) } -func newestDeletePriority(machine *v1beta1.Machine) deletePriority { +func newestDeletePriority(machine *machinev1.Machine) deletePriority { if machine.DeletionTimestamp != nil && !machine.DeletionTimestamp.IsZero() { return mustDelete } @@ -78,7 +78,7 @@ func newestDeletePriority(machine *v1beta1.Machine) deletePriority { return mustDelete - oldestDeletePriority(machine) } -func randomDeletePolicy(machine *v1beta1.Machine) deletePriority { +func randomDeletePolicy(machine *machinev1.Machine) deletePriority { if machine.DeletionTimestamp != nil && !machine.DeletionTimestamp.IsZero() { return mustDelete } @@ -96,7 +96,7 @@ func randomDeletePolicy(machine *v1beta1.Machine) deletePriority { } type sortableMachines struct { - machines []*v1beta1.Machine + machines []*machinev1.Machine priority deletePriorityFunc } @@ -106,11 +106,11 @@ func (m sortableMachines) Less(i, j int) bool { return m.priority(m.machines[j]) < m.priority(m.machines[i]) // high to low } -func getMachinesToDeletePrioritized(filteredMachines []*v1beta1.Machine, diff int, fun deletePriorityFunc) []*v1beta1.Machine { +func getMachinesToDeletePrioritized(filteredMachines []*machinev1.Machine, diff int, fun deletePriorityFunc) []*machinev1.Machine { if diff >= len(filteredMachines) { return filteredMachines } else if diff <= 0 { - return []*v1beta1.Machine{} + return []*machinev1.Machine{} } sortable := sortableMachines{ @@ -122,14 +122,14 @@ func getMachinesToDeletePrioritized(filteredMachines []*v1beta1.Machine, diff in return sortable.machines[:diff] } -func getDeletePriorityFunc(ms *v1beta1.MachineSet) (deletePriorityFunc, error) { +func getDeletePriorityFunc(ms *machinev1.MachineSet) (deletePriorityFunc, error) { // Map the Spec.DeletePolicy value to the appropriate delete priority function - switch msdp := v1beta1.MachineSetDeletePolicy(ms.Spec.DeletePolicy); msdp { - case v1beta1.RandomMachineSetDeletePolicy: + switch msdp := machinev1.MachineSetDeletePolicy(ms.Spec.DeletePolicy); msdp { + case machinev1.RandomMachineSetDeletePolicy: return randomDeletePolicy, nil - case v1beta1.NewestMachineSetDeletePolicy: + case machinev1.NewestMachineSetDeletePolicy: return newestDeletePriority, nil - case v1beta1.OldestMachineSetDeletePolicy: + case machinev1.OldestMachineSetDeletePolicy: return oldestDeletePriority, nil case "": return randomDeletePolicy, nil diff --git a/pkg/controller/machineset/delete_policy_test.go b/pkg/controller/machineset/delete_policy_test.go index 12e23758ab..998a31087a 100644 --- a/pkg/controller/machineset/delete_policy_test.go +++ b/pkg/controller/machineset/delete_policy_test.go @@ -20,7 +20,7 @@ import ( "reflect" "testing" - "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -28,45 +28,45 @@ import ( func TestMachineToDelete(t *testing.T) { msg := "something wrong with the machine" now := metav1.Now() - mustDeleteMachine := &v1beta1.Machine{ObjectMeta: metav1.ObjectMeta{DeletionTimestamp: &now}} - betterDeleteMachine := &v1beta1.Machine{Status: v1beta1.MachineStatus{ErrorMessage: &msg}} - deleteMeMachine := &v1beta1.Machine{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{DeleteNodeAnnotation: "yes"}}} - runningMachine := &v1beta1.Machine{Status: v1beta1.MachineStatus{NodeRef: &corev1.ObjectReference{}}} - notYetRunningMachine := &v1beta1.Machine{} + mustDeleteMachine := &machinev1.Machine{ObjectMeta: metav1.ObjectMeta{DeletionTimestamp: &now}} + betterDeleteMachine := &machinev1.Machine{Status: machinev1.MachineStatus{ErrorMessage: &msg}} + deleteMeMachine := &machinev1.Machine{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{DeleteNodeAnnotation: "yes"}}} + runningMachine := &machinev1.Machine{Status: machinev1.MachineStatus{NodeRef: &corev1.ObjectReference{}}} + notYetRunningMachine := &machinev1.Machine{} tests := []struct { desc string - machines []*v1beta1.Machine + machines []*machinev1.Machine diff int - expect []*v1beta1.Machine + expect []*machinev1.Machine }{ { desc: "func=randomDeletePolicy, diff=0", diff: 0, - machines: []*v1beta1.Machine{ + machines: []*machinev1.Machine{ runningMachine, }, - expect: []*v1beta1.Machine{}, + expect: []*machinev1.Machine{}, }, { desc: "func=randomDeletePolicy, diff>len(machines)", diff: 2, - machines: []*v1beta1.Machine{ + machines: []*machinev1.Machine{ runningMachine, }, - expect: []*v1beta1.Machine{ + expect: []*machinev1.Machine{ runningMachine, }, }, { desc: "func=randomDeletePolicy, diff>betterDelete", diff: 2, - machines: []*v1beta1.Machine{ + machines: []*machinev1.Machine{ runningMachine, betterDeleteMachine, runningMachine, }, - expect: []*v1beta1.Machine{ + expect: []*machinev1.Machine{ betterDeleteMachine, runningMachine, }, @@ -74,13 +74,13 @@ func TestMachineToDelete(t *testing.T) { { desc: "func=randomDeletePolicy, diffbetterDelete", diff: 2, - machines: []*v1beta1.Machine{ + machines: []*machinev1.Machine{ runningMachine, betterDeleteMachine, runningMachine, }, - expect: []*v1beta1.Machine{ + expect: []*machinev1.Machine{ betterDeleteMachine, runningMachine, }, @@ -142,25 +142,25 @@ func TestMachineToDelete(t *testing.T) { { desc: "func=randomDeletePolicy, annotated, diff=1", diff: 1, - machines: []*v1beta1.Machine{ + machines: []*machinev1.Machine{ runningMachine, deleteMeMachine, runningMachine, }, - expect: []*v1beta1.Machine{ + expect: []*machinev1.Machine{ deleteMeMachine, }, }, { desc: "func=randomDeletePolicy, delete non-running hosts first", diff: 3, - machines: []*v1beta1.Machine{ + machines: []*machinev1.Machine{ runningMachine, notYetRunningMachine, deleteMeMachine, betterDeleteMachine, }, - expect: []*v1beta1.Machine{ + expect: []*machinev1.Machine{ deleteMeMachine, betterDeleteMachine, notYetRunningMachine, @@ -179,60 +179,60 @@ func TestMachineToDelete(t *testing.T) { func TestMachineNewestDelete(t *testing.T) { currentTime := metav1.Now() - statusError := v1beta1.MachineStatusError("I'm unhealthy!") - mustDeleteMachine := &v1beta1.Machine{ObjectMeta: metav1.ObjectMeta{DeletionTimestamp: ¤tTime}} - newest := &v1beta1.Machine{ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -1))}} - new := &v1beta1.Machine{ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -5))}} - old := &v1beta1.Machine{ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}} - oldest := &v1beta1.Machine{ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}} - annotatedMachine := &v1beta1.Machine{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{DeleteNodeAnnotation: "yes"}, CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}} - unhealthyMachine := &v1beta1.Machine{ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}, Status: v1beta1.MachineStatus{ErrorReason: &statusError}} + statusError := machinev1.MachineStatusError("I'm unhealthy!") + mustDeleteMachine := &machinev1.Machine{ObjectMeta: metav1.ObjectMeta{DeletionTimestamp: ¤tTime}} + newest := &machinev1.Machine{ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -1))}} + new := &machinev1.Machine{ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -5))}} + old := &machinev1.Machine{ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}} + oldest := &machinev1.Machine{ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}} + annotatedMachine := &machinev1.Machine{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{DeleteNodeAnnotation: "yes"}, CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}} + unhealthyMachine := &machinev1.Machine{ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}, Status: machinev1.MachineStatus{ErrorReason: &statusError}} tests := []struct { desc string - machines []*v1beta1.Machine + machines []*machinev1.Machine diff int - expect []*v1beta1.Machine + expect []*machinev1.Machine }{ { desc: "func=newestDeletePriority, diff=1", diff: 1, - machines: []*v1beta1.Machine{ + machines: []*machinev1.Machine{ new, oldest, old, mustDeleteMachine, newest, }, - expect: []*v1beta1.Machine{mustDeleteMachine}, + expect: []*machinev1.Machine{mustDeleteMachine}, }, { desc: "func=newestDeletePriority, diff=2", diff: 2, - machines: []*v1beta1.Machine{ + machines: []*machinev1.Machine{ new, oldest, mustDeleteMachine, old, newest, }, - expect: []*v1beta1.Machine{mustDeleteMachine, newest}, + expect: []*machinev1.Machine{mustDeleteMachine, newest}, }, { desc: "func=newestDeletePriority, diff=3", diff: 3, - machines: []*v1beta1.Machine{ + machines: []*machinev1.Machine{ new, mustDeleteMachine, oldest, old, newest, }, - expect: []*v1beta1.Machine{mustDeleteMachine, newest, new}, + expect: []*machinev1.Machine{mustDeleteMachine, newest, new}, }, { desc: "func=newestDeletePriority, diff=1 (annotated)", diff: 1, - machines: []*v1beta1.Machine{ + machines: []*machinev1.Machine{ new, oldest, old, newest, annotatedMachine, }, - expect: []*v1beta1.Machine{annotatedMachine}, + expect: []*machinev1.Machine{annotatedMachine}, }, { desc: "func=newestDeletePriority, diff=1 (unhealthy)", diff: 1, - machines: []*v1beta1.Machine{ + machines: []*machinev1.Machine{ new, oldest, old, newest, unhealthyMachine, }, - expect: []*v1beta1.Machine{unhealthyMachine}, + expect: []*machinev1.Machine{unhealthyMachine}, }, } @@ -247,68 +247,68 @@ func TestMachineNewestDelete(t *testing.T) { func TestMachineOldestDelete(t *testing.T) { currentTime := metav1.Now() - statusError := v1beta1.MachineStatusError("I'm unhealthy!") - empty := &v1beta1.Machine{} - newest := &v1beta1.Machine{ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -1))}} - new := &v1beta1.Machine{ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -5))}} - old := &v1beta1.Machine{ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}} - oldest := &v1beta1.Machine{ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}} - annotatedMachine := &v1beta1.Machine{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{DeleteNodeAnnotation: "yes"}, CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}} - unhealthyMachine := &v1beta1.Machine{ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}, Status: v1beta1.MachineStatus{ErrorReason: &statusError}} + statusError := machinev1.MachineStatusError("I'm unhealthy!") + empty := &machinev1.Machine{} + newest := &machinev1.Machine{ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -1))}} + new := &machinev1.Machine{ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -5))}} + old := &machinev1.Machine{ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}} + oldest := &machinev1.Machine{ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}} + annotatedMachine := &machinev1.Machine{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{DeleteNodeAnnotation: "yes"}, CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}} + unhealthyMachine := &machinev1.Machine{ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}, Status: machinev1.MachineStatus{ErrorReason: &statusError}} tests := []struct { desc string - machines []*v1beta1.Machine + machines []*machinev1.Machine diff int - expect []*v1beta1.Machine + expect []*machinev1.Machine }{ { desc: "func=oldestDeletePriority, diff=1", diff: 1, - machines: []*v1beta1.Machine{ + machines: []*machinev1.Machine{ empty, new, oldest, old, newest, }, - expect: []*v1beta1.Machine{oldest}, + expect: []*machinev1.Machine{oldest}, }, { desc: "func=oldestDeletePriority, diff=2", diff: 2, - machines: []*v1beta1.Machine{ + machines: []*machinev1.Machine{ new, oldest, old, newest, empty, }, - expect: []*v1beta1.Machine{oldest, old}, + expect: []*machinev1.Machine{oldest, old}, }, { desc: "func=oldestDeletePriority, diff=3", diff: 3, - machines: []*v1beta1.Machine{ + machines: []*machinev1.Machine{ new, oldest, old, newest, empty, }, - expect: []*v1beta1.Machine{oldest, old, new}, + expect: []*machinev1.Machine{oldest, old, new}, }, { desc: "func=oldestDeletePriority, diff=4", diff: 4, - machines: []*v1beta1.Machine{ + machines: []*machinev1.Machine{ new, oldest, old, newest, empty, }, - expect: []*v1beta1.Machine{oldest, old, new, newest}, + expect: []*machinev1.Machine{oldest, old, new, newest}, }, { desc: "func=oldestDeletePriority, diff=1 (annotated)", diff: 1, - machines: []*v1beta1.Machine{ + machines: []*machinev1.Machine{ empty, new, oldest, old, newest, annotatedMachine, }, - expect: []*v1beta1.Machine{annotatedMachine}, + expect: []*machinev1.Machine{annotatedMachine}, }, { desc: "func=oldestDeletePriority, diff=1 (unhealthy)", diff: 1, - machines: []*v1beta1.Machine{ + machines: []*machinev1.Machine{ empty, new, oldest, old, newest, unhealthyMachine, }, - expect: []*v1beta1.Machine{unhealthyMachine}, + expect: []*machinev1.Machine{unhealthyMachine}, }, } diff --git a/pkg/controller/machineset/machine.go b/pkg/controller/machineset/machine.go index 69a78f9ce5..dc4c05c51d 100644 --- a/pkg/controller/machineset/machine.go +++ b/pkg/controller/machineset/machine.go @@ -19,27 +19,27 @@ package machineset import ( "context" - "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/klog/v2" "sigs.k8s.io/controller-runtime/pkg/client" ) -func (c *ReconcileMachineSet) getMachineSetsForMachine(m *v1beta1.Machine) []*v1beta1.MachineSet { +func (c *ReconcileMachineSet) getMachineSetsForMachine(m *machinev1.Machine) []*machinev1.MachineSet { if len(m.Labels) == 0 { klog.Warningf("No machine sets found for Machine %v because it has no labels", m.Name) return nil } - msList := &v1beta1.MachineSetList{} + msList := &machinev1.MachineSetList{} err := c.Client.List(context.Background(), msList, client.InNamespace(m.Namespace)) if err != nil { klog.Errorf("Failed to list machine sets, %v", err) return nil } - var mss []*v1beta1.MachineSet + var mss []*machinev1.MachineSet for idx := range msList.Items { ms := &msList.Items[idx] if hasMatchingLabels(ms, m) { @@ -50,7 +50,7 @@ func (c *ReconcileMachineSet) getMachineSetsForMachine(m *v1beta1.Machine) []*v1 return mss } -func hasMatchingLabels(machineSet *v1beta1.MachineSet, machine *v1beta1.Machine) bool { +func hasMatchingLabels(machineSet *machinev1.MachineSet, machine *machinev1.Machine) bool { selector, err := metav1.LabelSelectorAsSelector(&machineSet.Spec.Selector) if err != nil { klog.Warningf("unable to convert selector: %v", err) diff --git a/pkg/controller/machineset/machine_test.go b/pkg/controller/machineset/machine_test.go index 66eef69eab..efe0c9c04b 100644 --- a/pkg/controller/machineset/machine_test.go +++ b/pkg/controller/machineset/machine_test.go @@ -19,19 +19,19 @@ package machineset import ( "testing" - "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) func TestHasMatchingLabels(t *testing.T) { testCases := []struct { - machineSet v1beta1.MachineSet - machine v1beta1.Machine + machineSet machinev1.MachineSet + machine machinev1.Machine expected bool }{ { - machineSet: v1beta1.MachineSet{ - Spec: v1beta1.MachineSetSpec{ + machineSet: machinev1.MachineSet{ + Spec: machinev1.MachineSetSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "foo": "bar", @@ -39,7 +39,7 @@ func TestHasMatchingLabels(t *testing.T) { }, }, }, - machine: v1beta1.Machine{ + machine: machinev1.Machine{ ObjectMeta: metav1.ObjectMeta{ Name: "matchSelector", Labels: map[string]string{ @@ -50,8 +50,8 @@ func TestHasMatchingLabels(t *testing.T) { expected: true, }, { - machineSet: v1beta1.MachineSet{ - Spec: v1beta1.MachineSetSpec{ + machineSet: machinev1.MachineSet{ + Spec: machinev1.MachineSetSpec{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "foo": "bar", @@ -59,7 +59,7 @@ func TestHasMatchingLabels(t *testing.T) { }, }, }, - machine: v1beta1.Machine{ + machine: machinev1.Machine{ ObjectMeta: metav1.ObjectMeta{ Name: "doesNotMatchSelector", Labels: map[string]string{ diff --git a/pkg/controller/machineset/machineset_controller_suite_test.go b/pkg/controller/machineset/machineset_controller_suite_test.go index c6c81635c8..ddc1491d43 100644 --- a/pkg/controller/machineset/machineset_controller_suite_test.go +++ b/pkg/controller/machineset/machineset_controller_suite_test.go @@ -24,7 +24,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - machinev1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" "k8s.io/klog/v2" diff --git a/pkg/controller/machineset/machineset_controller_test.go b/pkg/controller/machineset/machineset_controller_test.go index bc16cb7b55..b197218f6a 100644 --- a/pkg/controller/machineset/machineset_controller_test.go +++ b/pkg/controller/machineset/machineset_controller_test.go @@ -21,7 +21,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - machinev1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" diff --git a/pkg/controller/machineset/status.go b/pkg/controller/machineset/status.go index 639b9a45aa..430a1b8734 100644 --- a/pkg/controller/machineset/status.go +++ b/pkg/controller/machineset/status.go @@ -21,7 +21,7 @@ import ( "errors" "fmt" - "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -34,7 +34,7 @@ const ( statusUpdateRetries = 1 ) -func (c *ReconcileMachineSet) calculateStatus(ms *v1beta1.MachineSet, filteredMachines []*v1beta1.Machine) v1beta1.MachineSetStatus { +func (c *ReconcileMachineSet) calculateStatus(ms *machinev1.MachineSet, filteredMachines []*machinev1.Machine) machinev1.MachineSetStatus { newStatus := ms.Status // Count the number of machines that have labels matching the labels of the machine // template of the replica set, the matching machines may have more @@ -70,7 +70,7 @@ func (c *ReconcileMachineSet) calculateStatus(ms *v1beta1.MachineSet, filteredMa } // updateMachineSetStatus attempts to update the Status.Replicas of the given MachineSet, with a single GET/PUT retry. -func updateMachineSetStatus(c client.Client, ms *v1beta1.MachineSet, newStatus v1beta1.MachineSetStatus) (*v1beta1.MachineSet, error) { +func updateMachineSetStatus(c client.Client, ms *machinev1.MachineSet, newStatus machinev1.MachineSetStatus) (*machinev1.MachineSet, error) { // This is the steady state. It happens when the MachineSet doesn't have any expectations, since // we do a periodic relist every 30s. If the generations differ but the replicas are // the same, a caller might've resized to the same replica count. @@ -121,7 +121,7 @@ func updateMachineSetStatus(c client.Client, ms *v1beta1.MachineSet, newStatus v return nil, updateErr } -func (c *ReconcileMachineSet) getMachineNode(machine *v1beta1.Machine) (*corev1.Node, error) { +func (c *ReconcileMachineSet) getMachineNode(machine *machinev1.Machine) (*corev1.Node, error) { nodeRef := machine.Status.NodeRef if nodeRef == nil { return nil, errors.New("machine has no node ref") diff --git a/pkg/controller/nodelink/nodelink_controller.go b/pkg/controller/nodelink/nodelink_controller.go index 988b001a00..e222590b29 100644 --- a/pkg/controller/nodelink/nodelink_controller.go +++ b/pkg/controller/nodelink/nodelink_controller.go @@ -5,7 +5,7 @@ import ( "fmt" "reflect" - mapiv1beta1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -37,7 +37,7 @@ type ReconcileNodeLink struct { // This is useful for unit testing so we can mock cache IndexField // and emulate Client.List.MatchingField behaviour listNodesByFieldFunc func(key, value string) ([]corev1.Node, error) - listMachinesByFieldFunc func(key, value string) ([]mapiv1beta1.Machine, error) + listMachinesByFieldFunc func(key, value string) ([]machinev1.Machine, error) nodeReadinessCache map[string]bool } @@ -64,7 +64,7 @@ func indexNodeByProviderID(object client.Object) []string { } func indexMachineByProvider(object client.Object) []string { - if machine, ok := object.(*mapiv1beta1.Machine); ok { + if machine, ok := object.(*machinev1.Machine); ok { if machine.Spec.ProviderID != nil { if *machine.Spec.ProviderID != "" { klog.V(3).Infof("Adding providerID %q for machine %q to indexer", *machine.Spec.ProviderID, machine.GetName()) @@ -96,7 +96,7 @@ func indexNodeByInternalIP(object client.Object) []string { } func indexMachineByInternalIP(object client.Object) []string { - machine, ok := object.(*mapiv1beta1.Machine) + machine, ok := object.(*machinev1.Machine) if !ok { klog.Warningf("Expected a machine for indexing field, got: %T", object) return nil @@ -125,7 +125,7 @@ func newReconciler(mgr manager.Manager) (*ReconcileNodeLink, error) { } if err := mgr.GetCache().IndexField(context.TODO(), - &mapiv1beta1.Machine{}, + &machinev1.Machine{}, machineProviderIDIndex, indexMachineByProvider, ); err != nil { @@ -141,7 +141,7 @@ func newReconciler(mgr manager.Manager) (*ReconcileNodeLink, error) { } if err := mgr.GetCache().IndexField(context.TODO(), - &mapiv1beta1.Machine{}, + &machinev1.Machine{}, machineInternalIPIndex, indexMachineByInternalIP, ); err != nil { @@ -175,7 +175,7 @@ func add(mgr manager.Manager, r reconcile.Reconciler, mapFn handler.MapFunc) err } // Watch for changes to Machines and enqueue if it exists the backed node - err = c.Watch(&source.Kind{Type: &mapiv1beta1.Machine{}}, handler.EnqueueRequestsFromMapFunc(mapFn)) + err = c.Watch(&source.Kind{Type: &machinev1.Machine{}}, handler.EnqueueRequestsFromMapFunc(mapFn)) if err != nil { return err } @@ -253,7 +253,7 @@ func (r *ReconcileNodeLink) Reconcile(ctx context.Context, request reconcile.Req } // updateNodeRef set the given node as nodeRef in the machine status -func (r *ReconcileNodeLink) updateNodeRef(machine *mapiv1beta1.Machine, node *corev1.Node) error { +func (r *ReconcileNodeLink) updateNodeRef(machine *machinev1.Machine, node *corev1.Node) error { now := metav1.Now() machine.Status.LastUpdated = &now @@ -289,7 +289,7 @@ func (r *ReconcileNodeLink) updateNodeRef(machine *mapiv1beta1.Machine, node *co func (r *ReconcileNodeLink) nodeRequestFromMachine(o client.Object) []reconcile.Request { klog.V(3).Infof("Watched machine event, finding node to reconcile.Request") // get machine - machine := &mapiv1beta1.Machine{} + machine := &machinev1.Machine{} if err := r.client.Get( context.Background(), client.ObjectKey{ @@ -329,7 +329,7 @@ func (r *ReconcileNodeLink) nodeRequestFromMachine(o client.Object) []reconcile. } // findNodeFromMachine find a node from by providerID and fallback to find by IP -func (r *ReconcileNodeLink) findNodeFromMachine(machine *mapiv1beta1.Machine) (*corev1.Node, error) { +func (r *ReconcileNodeLink) findNodeFromMachine(machine *machinev1.Machine) (*corev1.Node, error) { klog.V(3).Infof("Finding node from machine %q", machine.GetName()) node, err := r.findNodeFromMachineByProviderID(machine) if err != nil { @@ -346,7 +346,7 @@ func (r *ReconcileNodeLink) findNodeFromMachine(machine *mapiv1beta1.Machine) (* return node, nil } -func (r *ReconcileNodeLink) findNodeFromMachineByProviderID(machine *mapiv1beta1.Machine) (*corev1.Node, error) { +func (r *ReconcileNodeLink) findNodeFromMachineByProviderID(machine *machinev1.Machine) (*corev1.Node, error) { klog.V(3).Infof("Finding node from machine %q by providerID", machine.GetName()) if machine.Spec.ProviderID == nil { klog.Warningf("Machine %q has no providerID", machine.GetName()) @@ -370,7 +370,7 @@ func (r *ReconcileNodeLink) findNodeFromMachineByProviderID(machine *mapiv1beta1 return nil, nil } -func (r *ReconcileNodeLink) findNodeFromMachineByIP(machine *mapiv1beta1.Machine) (*corev1.Node, error) { +func (r *ReconcileNodeLink) findNodeFromMachineByIP(machine *machinev1.Machine) (*corev1.Node, error) { klog.V(3).Infof("Finding node from machine %q by IP", machine.GetName()) var machineInternalAddress string for _, a := range machine.Status.Addresses { @@ -404,7 +404,7 @@ func (r *ReconcileNodeLink) findNodeFromMachineByIP(machine *mapiv1beta1.Machine return nil, nil } -func (r *ReconcileNodeLink) findMachineFromNode(node *corev1.Node) (*mapiv1beta1.Machine, error) { +func (r *ReconcileNodeLink) findMachineFromNode(node *corev1.Node) (*machinev1.Machine, error) { klog.V(3).Infof("Finding machine from node %q", node.GetName()) machine, err := r.findMachineFromNodeByProviderID(node) if err != nil { @@ -421,7 +421,7 @@ func (r *ReconcileNodeLink) findMachineFromNode(node *corev1.Node) (*mapiv1beta1 return machine, nil } -func (r *ReconcileNodeLink) findMachineFromNodeByProviderID(node *corev1.Node) (*mapiv1beta1.Machine, error) { +func (r *ReconcileNodeLink) findMachineFromNodeByProviderID(node *corev1.Node) (*machinev1.Machine, error) { klog.V(3).Infof("Finding machine from node %q by ProviderID", node.GetName()) if node.Spec.ProviderID == "" { klog.Warningf("Node %q has no providerID", node.GetName()) @@ -444,7 +444,7 @@ func (r *ReconcileNodeLink) findMachineFromNodeByProviderID(node *corev1.Node) ( return nil, nil } -func (r *ReconcileNodeLink) findMachineFromNodeByIP(node *corev1.Node) (*mapiv1beta1.Machine, error) { +func (r *ReconcileNodeLink) findMachineFromNodeByIP(node *corev1.Node) (*machinev1.Machine, error) { klog.V(3).Infof("Finding machine from node %q by IP", node.GetName()) var nodeInternalAddress string for _, a := range node.Status.Addresses { @@ -481,7 +481,7 @@ func (r *ReconcileNodeLink) findMachineFromNodeByIP(node *corev1.Node) (*mapiv1b // addTaintsToNode adds taints from machine object to the node object // Taints are to be an authoritative list on the machine spec per cluster-api comments. // However, we believe many components can directly taint a node and there is no direct source of truth that should enforce a single writer of taints -func addTaintsToNode(node *corev1.Node, machine *mapiv1beta1.Machine) { +func addTaintsToNode(node *corev1.Node, machine *machinev1.Machine) { for _, mTaint := range machine.Spec.Taints { klog.V(4).Infof("Adding taint %v from machine %q to node %q", mTaint, machine.GetName(), node.GetName()) alreadyPresent := false @@ -510,8 +510,8 @@ func (r *ReconcileNodeLink) listNodesByField(key, value string) ([]corev1.Node, return nodeList.Items, nil } -func (r *ReconcileNodeLink) listMachinesByField(key, value string) ([]mapiv1beta1.Machine, error) { - machineList := &mapiv1beta1.MachineList{} +func (r *ReconcileNodeLink) listMachinesByField(key, value string) ([]machinev1.Machine, error) { + machineList := &machinev1.MachineList{} if err := r.client.List( context.TODO(), machineList, diff --git a/pkg/controller/nodelink/nodelink_controller_test.go b/pkg/controller/nodelink/nodelink_controller_test.go index 456dbdf468..aedf0c7adf 100644 --- a/pkg/controller/nodelink/nodelink_controller_test.go +++ b/pkg/controller/nodelink/nodelink_controller_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - mapiv1beta1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/scheme" @@ -20,7 +20,7 @@ import ( ) func init() { - if err := mapiv1beta1.AddToScheme(scheme.Scheme); err != nil { + if err := machinev1.AddToScheme(scheme.Scheme); err != nil { klog.Fatal(err) } } @@ -69,8 +69,8 @@ func node(name, providerID string, addresses []corev1.NodeAddress, taints []core return node } -func machine(name, providerID string, addresses []corev1.NodeAddress, taints []corev1.Taint, nodeRef *corev1.ObjectReference) *mapiv1beta1.Machine { - machine := &mapiv1beta1.Machine{ +func machine(name, providerID string, addresses []corev1.NodeAddress, taints []corev1.Taint, nodeRef *corev1.ObjectReference) *machinev1.Machine { + machine := &machinev1.Machine{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: namespace, @@ -89,7 +89,7 @@ func machine(name, providerID string, addresses []corev1.NodeAddress, taints []c TypeMeta: metav1.TypeMeta{ Kind: "Machine", }, - Spec: mapiv1beta1.MachineSpec{}, + Spec: machinev1.MachineSpec{}, } if providerID != "" { @@ -111,16 +111,16 @@ func machine(name, providerID string, addresses []corev1.NodeAddress, taints []c type fakeReconciler struct { ReconcileNodeLink fakeNodeIndexer map[string]corev1.Node - fakeMachineIndexer map[string]mapiv1beta1.Machine + fakeMachineIndexer map[string]machinev1.Machine } -func newFakeReconciler(client client.Client, machine *mapiv1beta1.Machine, node *corev1.Node) fakeReconciler { +func newFakeReconciler(client client.Client, machine *machinev1.Machine, node *corev1.Node) fakeReconciler { r := fakeReconciler{ ReconcileNodeLink: ReconcileNodeLink{ client: client, }, fakeNodeIndexer: make(map[string]corev1.Node), - fakeMachineIndexer: make(map[string]mapiv1beta1.Machine), + fakeMachineIndexer: make(map[string]machinev1.Machine), } r.listNodesByFieldFunc = func(_, value string) ([]corev1.Node, error) { _, ok := r.fakeNodeIndexer[value] @@ -129,10 +129,10 @@ func newFakeReconciler(client client.Client, machine *mapiv1beta1.Machine, node } return nil, nil } - r.listMachinesByFieldFunc = func(_, value string) ([]mapiv1beta1.Machine, error) { + r.listMachinesByFieldFunc = func(_, value string) ([]machinev1.Machine, error) { _, ok := r.fakeMachineIndexer[value] if ok { - return []mapiv1beta1.Machine{r.fakeMachineIndexer[value]}, nil + return []machinev1.Machine{r.fakeMachineIndexer[value]}, nil } return nil, nil } @@ -154,7 +154,7 @@ func (r *fakeReconciler) buildFakeNodeIndexer(nodes ...corev1.Node) { } } -func (r *fakeReconciler) buildFakeMachineIndexer(machines ...mapiv1beta1.Machine) { +func (r *fakeReconciler) buildFakeMachineIndexer(machines ...machinev1.Machine) { for i := range machines { if machines[i].Spec.ProviderID != nil { r.fakeMachineIndexer[*machines[i].Spec.ProviderID] = machines[i] @@ -167,9 +167,9 @@ func (r *fakeReconciler) buildFakeMachineIndexer(machines ...mapiv1beta1.Machine func TestFindMachineFromNodeByProviderID(t *testing.T) { testCases := []struct { - machine *mapiv1beta1.Machine + machine *machinev1.Machine node *corev1.Node - expected *mapiv1beta1.Machine + expected *machinev1.Machine }{ { machine: machine("noProviderID", "", nil, nil, nil), @@ -203,9 +203,9 @@ func TestFindMachineFromNodeByProviderID(t *testing.T) { func TestFindMachineFromNodeByIP(t *testing.T) { testCases := []struct { - machine *mapiv1beta1.Machine + machine *machinev1.Machine node *corev1.Node - expected *mapiv1beta1.Machine + expected *machinev1.Machine }{ { machine: machine("noInternalIP", "", nil, nil, nil), @@ -263,7 +263,7 @@ func TestFindMachineFromNodeByIP(t *testing.T) { func TestFindNodeFromMachineByProviderID(t *testing.T) { testCases := []struct { - machine *mapiv1beta1.Machine + machine *machinev1.Machine node *corev1.Node expected *corev1.Node }{ @@ -299,7 +299,7 @@ func TestFindNodeFromMachineByProviderID(t *testing.T) { func TestFindNodeFromMachineByIP(t *testing.T) { testCases := []struct { - machine *mapiv1beta1.Machine + machine *machinev1.Machine node *corev1.Node expected *corev1.Node }{ @@ -408,7 +408,7 @@ func TestAddTaintsToNode(t *testing.T) { func TestNodeRequestFromMachine(t *testing.T) { testCases := []struct { - machine *mapiv1beta1.Machine + machine *machinev1.Machine node *corev1.Node expected []reconcile.Request }{ @@ -490,7 +490,7 @@ func TestNodeRequestFromMachine(t *testing.T) { func TestReconcile(t *testing.T) { testCases := []struct { - machine *mapiv1beta1.Machine + machine *machinev1.Machine node *corev1.Node expected reconcile.Result expectedError bool @@ -714,7 +714,7 @@ func TestIndexMachineByInternalIP(t *testing.T) { func TestUpdateNodeRef(t *testing.T) { testCases := []struct { - machine *mapiv1beta1.Machine + machine *machinev1.Machine node *corev1.Node nodeRef *corev1.ObjectReference nodeReadinessCache map[string]bool @@ -772,7 +772,7 @@ func TestUpdateNodeRef(t *testing.T) { t.Errorf("unexpected error: %v", err) } - got := &mapiv1beta1.Machine{} + got := &machinev1.Machine{} if err := r.client.Get( context.TODO(), client.ObjectKey{ @@ -813,7 +813,7 @@ func TestFindMachineFromNodeDoesNotPanicBZ1747246(t *testing.T) { // Intercept to force a known failure. errmsg := "BZ#1747246" - r.listMachinesByFieldFunc = func(key, value string) ([]mapiv1beta1.Machine, error) { + r.listMachinesByFieldFunc = func(key, value string) ([]machinev1.Machine, error) { return nil, errors.New(errmsg) } diff --git a/pkg/controller/vsphere/actuator.go b/pkg/controller/vsphere/actuator.go index 46f9035386..2f4182a60d 100644 --- a/pkg/controller/vsphere/actuator.go +++ b/pkg/controller/vsphere/actuator.go @@ -7,7 +7,7 @@ import ( "fmt" "time" - machinev1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" machinecontroller "github.com/openshift/machine-api-operator/pkg/controller/machine" corev1 "k8s.io/api/core/v1" "k8s.io/client-go/tools/record" diff --git a/pkg/controller/vsphere/actuator_test.go b/pkg/controller/vsphere/actuator_test.go index 4279df8971..70746d7c98 100644 --- a/pkg/controller/vsphere/actuator_test.go +++ b/pkg/controller/vsphere/actuator_test.go @@ -10,8 +10,7 @@ import ( . "github.com/onsi/gomega" configv1 "github.com/openshift/api/config/v1" - machinev1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - vsphereapi "github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" "github.com/vmware/govmomi/simulator" corev1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1" @@ -249,9 +248,9 @@ func TestMachineEvents(t *testing.T) { timeout := 10 * time.Second gs := NewWithT(t) - providerSpec, err := vsphereapi.RawExtensionFromProviderSpec(&vsphereapi.VSphereMachineProviderSpec{ + providerSpec, err := RawExtensionFromProviderSpec(&machinev1.VSphereMachineProviderSpec{ Template: vm.Name, - Workspace: &vsphereapi.Workspace{ + Workspace: &machinev1.Workspace{ Server: host, }, CredentialsSecret: &corev1.LocalObjectReference{ diff --git a/pkg/controller/vsphere/machine_scope.go b/pkg/controller/vsphere/machine_scope.go index c4b06004e7..07f0dcce5c 100644 --- a/pkg/controller/vsphere/machine_scope.go +++ b/pkg/controller/vsphere/machine_scope.go @@ -5,8 +5,7 @@ import ( "errors" "fmt" - machinev1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - apivsphere "github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" machineapierros "github.com/openshift/machine-api-operator/pkg/controller/machine" machinecontroller "github.com/openshift/machine-api-operator/pkg/controller/machine" "github.com/openshift/machine-api-operator/pkg/controller/vsphere/session" @@ -41,8 +40,8 @@ type machineScope struct { vSphereConfig *vSphereConfig // machine resource machine *machinev1.Machine - providerSpec *apivsphere.VSphereMachineProviderSpec - providerStatus *apivsphere.VSphereMachineProviderStatus + providerSpec *machinev1.VSphereMachineProviderSpec + providerStatus *machinev1.VSphereMachineProviderStatus machineToBePatched runtimeclient.Patch } @@ -58,12 +57,12 @@ func newMachineScope(params machineScopeParams) (*machineScope, error) { klog.Errorf("Failed to fetch vSphere config: %v", err) } - providerSpec, err := apivsphere.ProviderSpecFromRawExtension(params.machine.Spec.ProviderSpec.Value) + providerSpec, err := ProviderSpecFromRawExtension(params.machine.Spec.ProviderSpec.Value) if err != nil { return nil, machineapierros.InvalidMachineConfiguration("failed to get machine config: %v", err) } - providerStatus, err := apivsphere.ProviderStatusFromRawExtension(params.machine.Status.ProviderStatus) + providerStatus, err := ProviderStatusFromRawExtension(params.machine.Status.ProviderStatus) if err != nil { return nil, machineapierros.InvalidMachineConfiguration("failed to get machine provider status: %v", err.Error()) } @@ -101,7 +100,7 @@ func newMachineScope(params machineScopeParams) (*machineScope, error) { func (s *machineScope) PatchMachine() error { klog.V(3).Infof("%v: patching machine", s.machine.GetName()) - providerStatus, err := apivsphere.RawExtensionFromProviderStatus(s.providerStatus) + providerStatus, err := RawExtensionFromProviderStatus(s.providerStatus) if err != nil { return machineapierros.InvalidMachineConfiguration("failed to get machine provider status: %v", err.Error()) } @@ -213,7 +212,7 @@ func (s *machineScope) GetUserData() ([]byte, error) { //data: // vcsa.vmware.devcluster.openshift.com.username: base64 string // vcsa.vmware.devcluster.openshift.com.password: base64 string -func getCredentialsSecret(client runtimeclient.Client, namespace string, spec apivsphere.VSphereMachineProviderSpec) (string, string, error) { +func getCredentialsSecret(client runtimeclient.Client, namespace string, spec machinev1.VSphereMachineProviderSpec) (string, string, error) { if spec.CredentialsSecret == nil { return "", "", nil } diff --git a/pkg/controller/vsphere/machine_scope_test.go b/pkg/controller/vsphere/machine_scope_test.go index 9cad633f97..c5362f1c47 100644 --- a/pkg/controller/vsphere/machine_scope_test.go +++ b/pkg/controller/vsphere/machine_scope_test.go @@ -11,8 +11,7 @@ import ( . "github.com/onsi/gomega" configv1 "github.com/openshift/api/config/v1" - machinev1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - vspherev1 "github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -25,8 +24,8 @@ import ( const TestNamespace = "vsphere-test" -func MachineWithSpec(spec *vspherev1.VSphereMachineProviderSpec) *machinev1.Machine { - rawSpec, err := vspherev1.RawExtensionFromProviderSpec(spec) +func MachineWithSpec(spec *machinev1.VSphereMachineProviderSpec) *machinev1.Machine { + rawSpec, err := RawExtensionFromProviderSpec(spec) if err != nil { panic("Failed to encode raw extension from provider spec") } @@ -47,7 +46,7 @@ func MachineWithSpec(spec *vspherev1.VSphereMachineProviderSpec) *machinev1.Mach func TestGetUserData(t *testing.T) { userDataSecretName := "vsphere-ignition" - defaultProviderSpec := &vspherev1.VSphereMachineProviderSpec{ + defaultProviderSpec := &machinev1.VSphereMachineProviderSpec{ UserDataSecret: &corev1.LocalObjectReference{ Name: userDataSecretName, }, @@ -56,7 +55,7 @@ func TestGetUserData(t *testing.T) { testCases := []struct { testCase string userDataSecret *corev1.Secret - providerSpec *vspherev1.VSphereMachineProviderSpec + providerSpec *machinev1.VSphereMachineProviderSpec expectedUserdata []byte expectError bool }{ @@ -105,7 +104,7 @@ func TestGetUserData(t *testing.T) { { testCase: "no user-data in provider spec", userDataSecret: nil, - providerSpec: &vspherev1.VSphereMachineProviderSpec{}, + providerSpec: &machinev1.VSphereMachineProviderSpec{}, expectError: true, expectedUserdata: nil, }, @@ -151,7 +150,7 @@ func TestGetCredentialsSecret(t *testing.T) { testCases := []struct { testCase string secret *corev1.Secret - providerSpec *vspherev1.VSphereMachineProviderSpec + providerSpec *machinev1.VSphereMachineProviderSpec expectError bool expectCredentials bool }{ @@ -167,11 +166,11 @@ func TestGetCredentialsSecret(t *testing.T) { expectedCredentialsSecretPassword: []byte(expectedPassword), }, }, - providerSpec: &vspherev1.VSphereMachineProviderSpec{ + providerSpec: &machinev1.VSphereMachineProviderSpec{ CredentialsSecret: &corev1.LocalObjectReference{ Name: "test", }, - Workspace: &vspherev1.Workspace{ + Workspace: &machinev1.Workspace{ Server: expectedServer, }, }, @@ -189,11 +188,11 @@ func TestGetCredentialsSecret(t *testing.T) { expectedCredentialsSecretPassword: []byte(expectedPassword), }, }, - providerSpec: &vspherev1.VSphereMachineProviderSpec{ + providerSpec: &machinev1.VSphereMachineProviderSpec{ CredentialsSecret: &corev1.LocalObjectReference{ Name: "secret-does-not-exist", }, - Workspace: &vspherev1.Workspace{ + Workspace: &machinev1.Workspace{ Server: expectedServer, }, }, @@ -211,11 +210,11 @@ func TestGetCredentialsSecret(t *testing.T) { expectedCredentialsSecretPassword: []byte(expectedPassword), }, }, - providerSpec: &vspherev1.VSphereMachineProviderSpec{ + providerSpec: &machinev1.VSphereMachineProviderSpec{ CredentialsSecret: &corev1.LocalObjectReference{ Name: "test", }, - Workspace: &vspherev1.Workspace{ + Workspace: &machinev1.Workspace{ Server: expectedServer, }, }, @@ -233,11 +232,11 @@ func TestGetCredentialsSecret(t *testing.T) { "badPasswordKey": []byte(expectedPassword), }, }, - providerSpec: &vspherev1.VSphereMachineProviderSpec{ + providerSpec: &machinev1.VSphereMachineProviderSpec{ CredentialsSecret: &corev1.LocalObjectReference{ Name: "test", }, - Workspace: &vspherev1.Workspace{ + Workspace: &machinev1.Workspace{ Server: expectedServer, }, }, @@ -255,7 +254,7 @@ func TestGetCredentialsSecret(t *testing.T) { expectedCredentialsSecretPassword: []byte(expectedPassword), }, }, - providerSpec: &vspherev1.VSphereMachineProviderSpec{}, + providerSpec: &machinev1.VSphereMachineProviderSpec{}, expectError: false, expectCredentials: false, }, @@ -389,7 +388,7 @@ func TestPatchMachine(t *testing.T) { failedPhase := "Failed" - providerStatus := &vspherev1.VSphereMachineProviderStatus{} + providerStatus := &machinev1.VSphereMachineProviderStatus{} machineName := "test" machineKey := types.NamespacedName{Namespace: testNamespaceName, Name: machineName} @@ -432,7 +431,7 @@ func TestPatchMachine(t *testing.T) { providerStatus.InstanceState = &instanceState }, expect: func(m *machinev1.Machine) error { - providerStatus, err := vspherev1.ProviderStatusFromRawExtension(m.Status.ProviderStatus) + providerStatus, err := ProviderStatusFromRawExtension(m.Status.ProviderStatus) if err != nil { return fmt.Errorf("unable to get provider status: %v", err) } @@ -456,22 +455,22 @@ func TestPatchMachine(t *testing.T) { timeout := 10 * time.Second // original objects - originalProviderSpec := vspherev1.VSphereMachineProviderSpec{ + originalProviderSpec := machinev1.VSphereMachineProviderSpec{ CredentialsSecret: &corev1.LocalObjectReference{ Name: "test", }, - Workspace: &vspherev1.Workspace{ + Workspace: &machinev1.Workspace{ Server: host, Folder: "test", }, } - rawProviderSpec, err := vspherev1.RawExtensionFromProviderSpec(&originalProviderSpec) + rawProviderSpec, err := RawExtensionFromProviderSpec(&originalProviderSpec) gs.Expect(err).ToNot(HaveOccurred()) - originalProviderStatus := &vspherev1.VSphereMachineProviderStatus{ + originalProviderStatus := &machinev1.VSphereMachineProviderStatus{ TaskRef: "test", } - rawProviderStatus, err := vspherev1.RawExtensionFromProviderStatus(originalProviderStatus) + rawProviderStatus, err := RawExtensionFromProviderStatus(originalProviderStatus) gs.Expect(err).ToNot(HaveOccurred()) machine := &machinev1.Machine{ @@ -622,7 +621,7 @@ func TestNodeGetter(t *testing.T) { client: k8sClient, apiReader: k8sClient, machine: machine, - providerSpec: &vspherev1.VSphereMachineProviderSpec{}, + providerSpec: &machinev1.VSphereMachineProviderSpec{}, } resetStatuses := func(node *corev1.Node, machine *machinev1.Machine) { diff --git a/pkg/controller/vsphere/machineset/controller.go b/pkg/controller/vsphere/machineset/controller.go index a2413b80e6..27e875322b 100644 --- a/pkg/controller/vsphere/machineset/controller.go +++ b/pkg/controller/vsphere/machineset/controller.go @@ -6,9 +6,9 @@ import ( "strconv" "github.com/go-logr/logr" - machinev1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - providerconfigv1 "github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" mapierrors "github.com/openshift/machine-api-operator/pkg/controller/machine" + vsphereutil "github.com/openshift/machine-api-operator/pkg/controller/vsphere" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" @@ -105,7 +105,7 @@ func isInvalidConfigurationError(err error) bool { } func reconcile(machineSet *machinev1.MachineSet) (ctrl.Result, error) { - providerConfig, err := providerconfigv1.ProviderSpecFromRawExtension(machineSet.Spec.Template.Spec.ProviderSpec.Value) + providerConfig, err := vsphereutil.ProviderSpecFromRawExtension(machineSet.Spec.Template.Spec.ProviderSpec.Value) if err != nil { return ctrl.Result{}, mapierrors.InvalidMachineConfiguration("failed to get providerConfig: %v", err) } diff --git a/pkg/controller/vsphere/machineset/controller_suite_test.go b/pkg/controller/vsphere/machineset/controller_suite_test.go index c2774217a2..f24365a5fd 100644 --- a/pkg/controller/vsphere/machineset/controller_suite_test.go +++ b/pkg/controller/vsphere/machineset/controller_suite_test.go @@ -24,7 +24,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - machinev1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/envtest" diff --git a/pkg/controller/vsphere/machineset/controller_test.go b/pkg/controller/vsphere/machineset/controller_test.go index 742a6b755d..9c9f88d549 100644 --- a/pkg/controller/vsphere/machineset/controller_test.go +++ b/pkg/controller/vsphere/machineset/controller_test.go @@ -24,8 +24,7 @@ import ( . "github.com/onsi/ginkgo/extensions/table" . "github.com/onsi/gomega" gtypes "github.com/onsi/gomega/types" - machinev1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - providerconfigv1 "github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -212,7 +211,7 @@ func newTestMachineSet(namespace string, vmNumCPUs int32, vmMemoryMiB int64, exi annotations[k] = v } - machineProviderSpec := &providerconfigv1.VSphereMachineProviderSpec{ + machineProviderSpec := &machinev1.VSphereMachineProviderSpec{ NumCPUs: vmNumCPUs, MemoryMiB: vmMemoryMiB, } @@ -237,7 +236,7 @@ func newTestMachineSet(namespace string, vmNumCPUs int32, vmMemoryMiB int64, exi }, nil } -func providerSpecFromMachine(in *providerconfigv1.VSphereMachineProviderSpec) (machinev1.ProviderSpec, error) { +func providerSpecFromMachine(in *machinev1.VSphereMachineProviderSpec) (machinev1.ProviderSpec, error) { bytes, err := json.Marshal(in) if err != nil { return machinev1.ProviderSpec{}, err diff --git a/pkg/controller/vsphere/reconciler.go b/pkg/controller/vsphere/reconciler.go index 384909c625..6c1dcae727 100644 --- a/pkg/controller/vsphere/reconciler.go +++ b/pkg/controller/vsphere/reconciler.go @@ -10,8 +10,7 @@ import ( apimachineryutilerrors "k8s.io/apimachinery/pkg/util/errors" "github.com/google/uuid" - machinev1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - vspherev1 "github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" machineapierros "github.com/openshift/machine-api-operator/pkg/controller/machine" machinecontroller "github.com/openshift/machine-api-operator/pkg/controller/machine" "github.com/openshift/machine-api-operator/pkg/controller/vsphere/session" @@ -554,7 +553,7 @@ func clone(s *machineScope) (string, error) { // If a linked clone is requested then a MoRef for a snapshot must be // found with which to perform the linked clone. // Empty clone mode is linked clone - if s.providerSpec.CloneMode == "" || s.providerSpec.CloneMode == vspherev1.LinkedClone { + if s.providerSpec.CloneMode == "" || s.providerSpec.CloneMode == machinev1.LinkedClone { if s.providerSpec.Snapshot == "" { klog.V(3).Infof("%v: no snapshot name provided, getting snapshot using template", s.machine.GetName()) var vm mo.VirtualMachine @@ -788,7 +787,7 @@ func taskIsFinished(task *mo.Task) (bool, error) { } } -func setProviderStatus(taskRef string, condition vspherev1.VSphereMachineProviderCondition, scope *machineScope, vm *virtualMachine) error { +func setProviderStatus(taskRef string, condition machinev1.VSphereMachineProviderCondition, scope *machineScope, vm *virtualMachine) error { klog.Infof("%s: Updating provider status", scope.machine.Name) if vm != nil { diff --git a/pkg/controller/vsphere/reconciler_test.go b/pkg/controller/vsphere/reconciler_test.go index 72b5ef3189..39e8493b72 100644 --- a/pkg/controller/vsphere/reconciler_test.go +++ b/pkg/controller/vsphere/reconciler_test.go @@ -26,8 +26,7 @@ import ( . "github.com/onsi/gomega" configv1 "github.com/openshift/api/config/v1" - machinev1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - vsphereapi "github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" machinecontroller "github.com/openshift/machine-api-operator/pkg/controller/machine" "github.com/openshift/machine-api-operator/pkg/controller/vsphere/session" "github.com/vmware/govmomi/object" @@ -146,16 +145,16 @@ func TestClone(t *testing.T) { cloneVM bool expectedError error setupFailureCondition func() error - providerSpec vsphereapi.VSphereMachineProviderSpec + providerSpec machinev1.VSphereMachineProviderSpec machineName string }{ { testCase: "clone machine from default values", - providerSpec: vsphereapi.VSphereMachineProviderSpec{ + providerSpec: machinev1.VSphereMachineProviderSpec{ CredentialsSecret: &corev1.LocalObjectReference{ Name: "test", }, - Workspace: &vsphereapi.Workspace{ + Workspace: &machinev1.Workspace{ Server: server.URL.Host, }, DiskGiB: defaultSizeGiB, @@ -169,11 +168,11 @@ func TestClone(t *testing.T) { }, { testCase: "clone machine in specific folder", - providerSpec: vsphereapi.VSphereMachineProviderSpec{ + providerSpec: machinev1.VSphereMachineProviderSpec{ CredentialsSecret: &corev1.LocalObjectReference{ Name: "test", }, - Workspace: &vsphereapi.Workspace{ + Workspace: &machinev1.Workspace{ Server: server.URL.Host, Folder: "custom-folder", }, @@ -188,11 +187,11 @@ func TestClone(t *testing.T) { }, { testCase: "clone machine and increase disk", - providerSpec: vsphereapi.VSphereMachineProviderSpec{ + providerSpec: machinev1.VSphereMachineProviderSpec{ CredentialsSecret: &corev1.LocalObjectReference{ Name: "test", }, - Workspace: &vsphereapi.Workspace{ + Workspace: &machinev1.Workspace{ Server: server.URL.Host, }, DiskGiB: defaultSizeGiB + 1, @@ -206,11 +205,11 @@ func TestClone(t *testing.T) { }, { testCase: "fail on disc resize down", - providerSpec: vsphereapi.VSphereMachineProviderSpec{ + providerSpec: machinev1.VSphereMachineProviderSpec{ CredentialsSecret: &corev1.LocalObjectReference{ Name: "test", }, - Workspace: &vsphereapi.Workspace{ + Workspace: &machinev1.Workspace{ Server: server.URL.Host, }, DiskGiB: defaultSizeGiB - 1, @@ -223,11 +222,11 @@ func TestClone(t *testing.T) { }, { testCase: "fail on invalid resource pool", - providerSpec: vsphereapi.VSphereMachineProviderSpec{ + providerSpec: machinev1.VSphereMachineProviderSpec{ CredentialsSecret: &corev1.LocalObjectReference{ Name: "test", }, - Workspace: &vsphereapi.Workspace{ + Workspace: &machinev1.Workspace{ Server: server.URL.Host, ResourcePool: "invalid", }, @@ -240,11 +239,11 @@ func TestClone(t *testing.T) { }, { testCase: "fail on multiple resource pools", - providerSpec: vsphereapi.VSphereMachineProviderSpec{ + providerSpec: machinev1.VSphereMachineProviderSpec{ CredentialsSecret: &corev1.LocalObjectReference{ Name: "test", }, - Workspace: &vsphereapi.Workspace{ + Workspace: &machinev1.Workspace{ Server: server.URL.Host, ResourcePool: "/DC0/host/DC0_C0/Resources/...", }, @@ -275,11 +274,11 @@ func TestClone(t *testing.T) { { testCase: "fail on invalid folder", expectedError: errors.New("folder not found, specify valid value"), - providerSpec: vsphereapi.VSphereMachineProviderSpec{ + providerSpec: machinev1.VSphereMachineProviderSpec{ CredentialsSecret: &corev1.LocalObjectReference{ Name: "test", }, - Workspace: &vsphereapi.Workspace{ + Workspace: &machinev1.Workspace{ Server: server.URL.Host, Folder: "invalid", }, @@ -291,11 +290,11 @@ func TestClone(t *testing.T) { }, { testCase: "fail on multiple folders", - providerSpec: vsphereapi.VSphereMachineProviderSpec{ + providerSpec: machinev1.VSphereMachineProviderSpec{ CredentialsSecret: &corev1.LocalObjectReference{ Name: "test", }, - Workspace: &vsphereapi.Workspace{ + Workspace: &machinev1.Workspace{ Server: server.URL.Host, Folder: "/DC0/vm/...", }, @@ -324,11 +323,11 @@ func TestClone(t *testing.T) { }, { testCase: "fail on invalid datastore", - providerSpec: vsphereapi.VSphereMachineProviderSpec{ + providerSpec: machinev1.VSphereMachineProviderSpec{ CredentialsSecret: &corev1.LocalObjectReference{ Name: "test", }, - Workspace: &vsphereapi.Workspace{ + Workspace: &machinev1.Workspace{ Server: server.URL.Host, Datastore: "invalid", }, @@ -341,11 +340,11 @@ func TestClone(t *testing.T) { }, { testCase: "fail on multiple datastores", - providerSpec: vsphereapi.VSphereMachineProviderSpec{ + providerSpec: machinev1.VSphereMachineProviderSpec{ CredentialsSecret: &corev1.LocalObjectReference{ Name: "test", }, - Workspace: &vsphereapi.Workspace{ + Workspace: &machinev1.Workspace{ Server: server.URL.Host, Datastore: "/DC0/...", }, @@ -382,7 +381,7 @@ func TestClone(t *testing.T) { }, { testCase: "fail on invalid template", - providerSpec: vsphereapi.VSphereMachineProviderSpec{ + providerSpec: machinev1.VSphereMachineProviderSpec{ Template: "invalid", UserDataSecret: &corev1.LocalObjectReference{ Name: userDataSecretName, @@ -413,7 +412,7 @@ func TestClone(t *testing.T) { }, providerSpec: &tc.providerSpec, session: session, - providerStatus: &vsphereapi.VSphereMachineProviderStatus{}, + providerStatus: &machinev1.VSphereMachineProviderStatus{}, client: fake.NewFakeClientWithScheme(scheme.Scheme, &credentialsSecret, &userDataSecret), } @@ -627,12 +626,12 @@ func TestGetNetworkDevices(t *testing.T) { testCases := []struct { testCase string - providerSpec *vsphereapi.VSphereMachineProviderSpec + providerSpec *machinev1.VSphereMachineProviderSpec expected func(gotDevices []types.BaseVirtualDeviceConfigSpec) bool }{ { testCase: "no Network", - providerSpec: &vsphereapi.VSphereMachineProviderSpec{}, + providerSpec: &machinev1.VSphereMachineProviderSpec{}, expected: func(gotDevices []types.BaseVirtualDeviceConfigSpec) bool { if len(gotDevices) != 1 { return false @@ -645,9 +644,9 @@ func TestGetNetworkDevices(t *testing.T) { }, { testCase: "one Network", - providerSpec: &vsphereapi.VSphereMachineProviderSpec{ - Network: vsphereapi.NetworkSpec{ - Devices: []vsphereapi.NetworkDeviceSpec{ + providerSpec: &machinev1.VSphereMachineProviderSpec{ + Network: machinev1.NetworkSpec{ + Devices: []machinev1.NetworkDeviceSpec{ { NetworkName: "VM Network", }, @@ -749,7 +748,7 @@ func TestGetDiskSpec(t *testing.T) { t.Run(tc.name, func(t *testing.T) { machineScope := &machineScope{ Context: context.TODO(), - providerSpec: &vsphereapi.VSphereMachineProviderSpec{ + providerSpec: &machinev1.VSphereMachineProviderSpec{ DiskGiB: tc.diskSize, }, session: session, @@ -868,9 +867,9 @@ func TestReconcileNetwork(t *testing.T) { machine: &machinev1.Machine{ Status: machinev1.MachineStatus{}, }, - providerSpec: &vsphereapi.VSphereMachineProviderSpec{ - Network: vsphereapi.NetworkSpec{ - Devices: []vsphereapi.NetworkDeviceSpec{ + providerSpec: &machinev1.VSphereMachineProviderSpec{ + Network: machinev1.NetworkSpec{ + Devices: []machinev1.NetworkDeviceSpec{ { NetworkName: "dummy", }, @@ -1262,15 +1261,15 @@ func TestDelete(t *testing.T) { nodeName := "somenodename" getMachineWithStatus := func(t *testing.T, status machinev1.MachineStatus) *machinev1.Machine { - providerSpec := vsphereapi.VSphereMachineProviderSpec{ + providerSpec := machinev1.VSphereMachineProviderSpec{ CredentialsSecret: &corev1.LocalObjectReference{ Name: "test", }, - Workspace: &vsphereapi.Workspace{ + Workspace: &machinev1.Workspace{ Server: host, }, } - raw, err := vsphereapi.RawExtensionFromProviderSpec(&providerSpec) + raw, err := RawExtensionFromProviderSpec(&providerSpec) if err != nil { t.Fatal(err) } @@ -1488,15 +1487,15 @@ func TestCreate(t *testing.T) { cases := []struct { name string expectedError error - providerSpec vsphereapi.VSphereMachineProviderSpec + providerSpec machinev1.VSphereMachineProviderSpec labels map[string]string notConnectedToVCenter bool }{ { name: "Successfully create machine", - providerSpec: vsphereapi.VSphereMachineProviderSpec{ + providerSpec: machinev1.VSphereMachineProviderSpec{ Template: vmName, - Workspace: &vsphereapi.Workspace{ + Workspace: &machinev1.Workspace{ Server: host, }, CredentialsSecret: &corev1.LocalObjectReference{ @@ -1513,9 +1512,9 @@ func TestCreate(t *testing.T) { labels: map[string]string{ machinev1.MachineClusterIDLabel: "", }, - providerSpec: vsphereapi.VSphereMachineProviderSpec{ + providerSpec: machinev1.VSphereMachineProviderSpec{ Template: vmName, - Workspace: &vsphereapi.Workspace{ + Workspace: &machinev1.Workspace{ Server: host, }, CredentialsSecret: &corev1.LocalObjectReference{ @@ -1526,9 +1525,9 @@ func TestCreate(t *testing.T) { }, { name: "Fail on not connected to vCenter", - providerSpec: vsphereapi.VSphereMachineProviderSpec{ + providerSpec: machinev1.VSphereMachineProviderSpec{ Template: vmName, - Workspace: &vsphereapi.Workspace{ + Workspace: &machinev1.Workspace{ Server: host, }, CredentialsSecret: &corev1.LocalObjectReference{ @@ -1560,7 +1559,7 @@ func TestCreate(t *testing.T) { infra, userDataSecret) - rawProviderSpec, err := vsphereapi.RawExtensionFromProviderSpec(&tc.providerSpec) + rawProviderSpec, err := RawExtensionFromProviderSpec(&tc.providerSpec) if err != nil { t.Fatal(err) } @@ -1663,21 +1662,21 @@ func TestUpdate(t *testing.T) { cases := []struct { name string expectedError error - providerSpec vsphereapi.VSphereMachineProviderSpec + providerSpec machinev1.VSphereMachineProviderSpec labels map[string]string }{ { name: "Successfully update machine", - providerSpec: vsphereapi.VSphereMachineProviderSpec{ - Workspace: &vsphereapi.Workspace{ + providerSpec: machinev1.VSphereMachineProviderSpec{ + Workspace: &machinev1.Workspace{ Server: host, }, CredentialsSecret: &corev1.LocalObjectReference{ Name: "test", }, Template: vm.Name, - Network: vsphereapi.NetworkSpec{ - Devices: []vsphereapi.NetworkDeviceSpec{ + Network: machinev1.NetworkSpec{ + Devices: []machinev1.NetworkDeviceSpec{ { NetworkName: "test", }, @@ -1690,16 +1689,16 @@ func TestUpdate(t *testing.T) { labels: map[string]string{ machinev1.MachineClusterIDLabel: "", }, - providerSpec: vsphereapi.VSphereMachineProviderSpec{ - Workspace: &vsphereapi.Workspace{ + providerSpec: machinev1.VSphereMachineProviderSpec{ + Workspace: &machinev1.Workspace{ Server: host, }, CredentialsSecret: &corev1.LocalObjectReference{ Name: "test", }, Template: vm.Name, - Network: vsphereapi.NetworkSpec{ - Devices: []vsphereapi.NetworkDeviceSpec{ + Network: machinev1.NetworkSpec{ + Devices: []machinev1.NetworkDeviceSpec{ { NetworkName: "test", }, @@ -1725,7 +1724,7 @@ func TestUpdate(t *testing.T) { configMap, infra) - rawProviderSpec, err := vsphereapi.RawExtensionFromProviderSpec(&tc.providerSpec) + rawProviderSpec, err := RawExtensionFromProviderSpec(&tc.providerSpec) if err != nil { t.Fatal(err) } @@ -1829,11 +1828,11 @@ func TestExists(t *testing.T) { }, }, }, - providerSpec: &vsphereapi.VSphereMachineProviderSpec{ + providerSpec: &machinev1.VSphereMachineProviderSpec{ Template: vm.Name, }, session: session, - providerStatus: &vsphereapi.VSphereMachineProviderStatus{ + providerStatus: &machinev1.VSphereMachineProviderStatus{ TaskRef: task.Reference().Value, }, client: fake.NewFakeClientWithScheme(scheme.Scheme, &credentialsSecret), @@ -1904,10 +1903,10 @@ func TestReconcileMachineWithCloudState(t *testing.T) { }, }, }, - providerSpec: &vsphereapi.VSphereMachineProviderSpec{ + providerSpec: &machinev1.VSphereMachineProviderSpec{ Template: vm.Name, - Network: vsphereapi.NetworkSpec{ - Devices: []vsphereapi.NetworkDeviceSpec{ + Network: machinev1.NetworkSpec{ + Devices: []machinev1.NetworkDeviceSpec{ { NetworkName: "test", }, @@ -1915,7 +1914,7 @@ func TestReconcileMachineWithCloudState(t *testing.T) { }, }, session: session, - providerStatus: &vsphereapi.VSphereMachineProviderStatus{ + providerStatus: &machinev1.VSphereMachineProviderStatus{ TaskRef: task.Reference().Value, }, vSphereConfig: &vSphereConfig{ diff --git a/pkg/controller/vsphere/util.go b/pkg/controller/vsphere/util.go index 5215357344..cd807b9adf 100644 --- a/pkg/controller/vsphere/util.go +++ b/pkg/controller/vsphere/util.go @@ -2,15 +2,19 @@ package vsphere import ( "context" + "encoding/json" "errors" "fmt" "gopkg.in/gcfg.v1" + "gopkg.in/yaml.v2" configv1 "github.com/openshift/api/config/v1" - vspherev1 "github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog/v2" runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -107,7 +111,7 @@ func getVSphereConfig(c runtimeclient.Reader) (*vSphereConfig, error) { return &vcfg, nil } -func setVSphereMachineProviderConditions(condition vspherev1.VSphereMachineProviderCondition, conditions []vspherev1.VSphereMachineProviderCondition) []vspherev1.VSphereMachineProviderCondition { +func setVSphereMachineProviderConditions(condition machinev1.VSphereMachineProviderCondition, conditions []machinev1.VSphereMachineProviderCondition) []machinev1.VSphereMachineProviderCondition { now := metav1.Now() if existingCondition := findProviderCondition(conditions, condition.Type); existingCondition == nil { @@ -121,7 +125,7 @@ func setVSphereMachineProviderConditions(condition vspherev1.VSphereMachineProvi return conditions } -func findProviderCondition(conditions []vspherev1.VSphereMachineProviderCondition, conditionType vspherev1.VSphereMachineProviderConditionType) *vspherev1.VSphereMachineProviderCondition { +func findProviderCondition(conditions []machinev1.VSphereMachineProviderCondition, conditionType machinev1.ConditionType) *machinev1.VSphereMachineProviderCondition { for i := range conditions { if conditions[i].Type == conditionType { return &conditions[i] @@ -130,7 +134,7 @@ func findProviderCondition(conditions []vspherev1.VSphereMachineProviderConditio return nil } -func updateExistingCondition(newCondition, existingCondition *vspherev1.VSphereMachineProviderCondition) { +func updateExistingCondition(newCondition, existingCondition *machinev1.VSphereMachineProviderCondition) { if !shouldUpdateCondition(newCondition, existingCondition) { return } @@ -144,24 +148,24 @@ func updateExistingCondition(newCondition, existingCondition *vspherev1.VSphereM existingCondition.LastProbeTime = newCondition.LastProbeTime } -func shouldUpdateCondition(newCondition, existingCondition *vspherev1.VSphereMachineProviderCondition) bool { +func shouldUpdateCondition(newCondition, existingCondition *machinev1.VSphereMachineProviderCondition) bool { return newCondition.Reason != existingCondition.Reason || newCondition.Message != existingCondition.Message } -func conditionSuccess() vspherev1.VSphereMachineProviderCondition { - return vspherev1.VSphereMachineProviderCondition{ - Type: vspherev1.MachineCreation, +func conditionSuccess() machinev1.VSphereMachineProviderCondition { + return machinev1.VSphereMachineProviderCondition{ + Type: machinev1.MachineCreation, Status: corev1.ConditionTrue, - Reason: vspherev1.MachineCreationSucceeded, + Reason: machinev1.MachineCreationSucceededConditionReason, Message: "Machine successfully created", } } -func conditionFailed() vspherev1.VSphereMachineProviderCondition { - return vspherev1.VSphereMachineProviderCondition{ - Type: vspherev1.MachineCreation, +func conditionFailed() machinev1.VSphereMachineProviderCondition { + return machinev1.VSphereMachineProviderCondition{ + Type: machinev1.MachineCreation, Status: corev1.ConditionFalse, - Reason: vspherev1.MachineCreationFailed, + Reason: machinev1.MachineCreationSucceededConditionReason, } } @@ -179,3 +183,67 @@ func getInsecureFlagFromConfig(config *vSphereConfig) bool { } return false } + +// RawExtensionFromProviderSpec marshals the machine provider spec. +func RawExtensionFromProviderSpec(spec *machinev1.VSphereMachineProviderSpec) (*runtime.RawExtension, error) { + if spec == nil { + return &runtime.RawExtension{}, nil + } + + var rawBytes []byte + var err error + if rawBytes, err = json.Marshal(spec); err != nil { + return nil, fmt.Errorf("error marshalling providerSpec: %v", err) + } + + return &runtime.RawExtension{ + Raw: rawBytes, + }, nil +} + +// RawExtensionFromProviderStatus marshals the provider status +func RawExtensionFromProviderStatus(status *machinev1.VSphereMachineProviderStatus) (*runtime.RawExtension, error) { + if status == nil { + return &runtime.RawExtension{}, nil + } + + var rawBytes []byte + var err error + if rawBytes, err = json.Marshal(status); err != nil { + return nil, fmt.Errorf("error marshalling providerStatus: %v", err) + } + + return &runtime.RawExtension{ + Raw: rawBytes, + }, nil +} + +// ProviderSpecFromRawExtension unmarshals the JSON-encoded spec +func ProviderSpecFromRawExtension(rawExtension *runtime.RawExtension) (*machinev1.VSphereMachineProviderSpec, error) { + if rawExtension == nil { + return &machinev1.VSphereMachineProviderSpec{}, nil + } + + spec := new(machinev1.VSphereMachineProviderSpec) + if err := yaml.Unmarshal(rawExtension.Raw, &spec); err != nil { + return nil, fmt.Errorf("error unmarshalling providerSpec: %v", err) + } + + klog.V(5).Infof("Got provider spec from raw extension: %+v", spec) + return spec, nil +} + +// ProviderStatusFromRawExtension unmarshals a raw extension into a VSphereMachineProviderStatus type +func ProviderStatusFromRawExtension(rawExtension *runtime.RawExtension) (*machinev1.VSphereMachineProviderStatus, error) { + if rawExtension == nil { + return &machinev1.VSphereMachineProviderStatus{}, nil + } + + providerStatus := new(machinev1.VSphereMachineProviderStatus) + if err := yaml.Unmarshal(rawExtension.Raw, providerStatus); err != nil { + return nil, fmt.Errorf("error unmarshalling providerStatus: %v", err) + } + + klog.V(5).Infof("Got provider Status from raw extension: %+v", providerStatus) + return providerStatus, nil +} diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go index 4da1b93dd5..b8b3e80c4c 100644 --- a/pkg/metrics/metrics.go +++ b/pkg/metrics/metrics.go @@ -1,9 +1,9 @@ package metrics import ( - mapiv1beta1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" - machineinformers "github.com/openshift/machine-api-operator/pkg/generated/informers/externalversions/machine/v1beta1" - machinelisters "github.com/openshift/machine-api-operator/pkg/generated/listers/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" + machineinformers "github.com/openshift/client-go/machine/informers/externalversions/machine/v1beta1" + machinelisters "github.com/openshift/client-go/machine/listers/machine/v1beta1" "github.com/prometheus/client_golang/prometheus" "k8s.io/apimachinery/pkg/labels" "k8s.io/klog/v2" @@ -201,11 +201,11 @@ func (mc MachineCollector) collectMachineSetMetrics(ch chan<- prometheus.Metric) } } -func (mc MachineCollector) listMachines() ([]*mapiv1beta1.Machine, error) { +func (mc MachineCollector) listMachines() ([]*machinev1.Machine, error) { return mc.machineLister.Machines(mc.namespace).List(labels.Everything()) } -func (mc MachineCollector) listMachineSets() ([]*mapiv1beta1.MachineSet, error) { +func (mc MachineCollector) listMachineSets() ([]*machinev1.MachineSet, error) { return mc.machineSetLister.MachineSets(mc.namespace).List(labels.Everything()) } diff --git a/pkg/operator/sync.go b/pkg/operator/sync.go index 80526c4684..2e54796f8f 100644 --- a/pkg/operator/sync.go +++ b/pkg/operator/sync.go @@ -9,10 +9,10 @@ import ( "github.com/openshift/library-go/pkg/operator/resource/resourceapply" "github.com/openshift/library-go/pkg/operator/resource/resourcehash" "github.com/openshift/library-go/pkg/operator/resource/resourcemerge" - mapiv1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" machinecontroller "github.com/openshift/machine-api-operator/pkg/controller/machine" "github.com/openshift/machine-api-operator/pkg/metrics" "github.com/openshift/machine-api-operator/pkg/util/conditions" + mapiwebhooks "github.com/openshift/machine-api-operator/pkg/webhooks" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -183,10 +183,10 @@ func (optr *Operator) syncWebhookConfiguration() error { } func (optr *Operator) syncValidatingWebhook() error { - expectedGeneration := resourcemerge.ExpectedValidatingWebhooksConfiguration(mapiv1.NewValidatingWebhookConfiguration().Name, optr.generations) + expectedGeneration := resourcemerge.ExpectedValidatingWebhooksConfiguration(mapiwebhooks.NewValidatingWebhookConfiguration().Name, optr.generations) validatingWebhook, updated, err := resourceapply.ApplyValidatingWebhookConfiguration(context.TODO(), optr.kubeClient.AdmissionregistrationV1(), events.NewLoggingEventRecorder(optr.name), - mapiv1.NewValidatingWebhookConfiguration(), expectedGeneration) + mapiwebhooks.NewValidatingWebhookConfiguration(), expectedGeneration) if err != nil { return err } @@ -198,10 +198,10 @@ func (optr *Operator) syncValidatingWebhook() error { } func (optr *Operator) syncMutatingWebhook() error { - expectedGeneration := resourcemerge.ExpectedMutatingWebhooksConfiguration(mapiv1.NewMutatingWebhookConfiguration().Name, optr.generations) + expectedGeneration := resourcemerge.ExpectedMutatingWebhooksConfiguration(mapiwebhooks.NewMutatingWebhookConfiguration().Name, optr.generations) validatingWebhook, updated, err := resourceapply.ApplyMutatingWebhookConfiguration(context.TODO(), optr.kubeClient.AdmissionregistrationV1(), events.NewLoggingEventRecorder(optr.name), - mapiv1.NewMutatingWebhookConfiguration(), expectedGeneration) + mapiwebhooks.NewMutatingWebhookConfiguration(), expectedGeneration) if err != nil { return err } diff --git a/pkg/util/annotations/helpers.go b/pkg/util/annotations/helpers.go index 2451c5f426..46a00a94a9 100644 --- a/pkg/util/annotations/helpers.go +++ b/pkg/util/annotations/helpers.go @@ -3,8 +3,13 @@ package annotations import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) - "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" +const ( + // PausedAnnotation is an annotation that can be applied to MachineHealthCheck objects to prevent the MHC controller + // from processing it. + // TODO: move this annotation to the openshift/api package + PausedAnnotation = "cluster.x-k8s.io/paused" ) // IsPaused returns true if the Cluster is paused or the object has the `paused` annotation. @@ -14,7 +19,7 @@ func IsPaused(o metav1.Object) bool { // HasPausedAnnotation returns true if the object has the `paused` annotation. func HasPausedAnnotation(o metav1.Object) bool { - return hasAnnotation(o, v1beta1.PausedAnnotation) + return hasAnnotation(o, PausedAnnotation) } // hasAnnotation returns true if the object has the specified annotation. diff --git a/pkg/util/external/util.go b/pkg/util/external/util.go index 6f0ce10e40..fe0358a48e 100644 --- a/pkg/util/external/util.go +++ b/pkg/util/external/util.go @@ -20,7 +20,7 @@ import ( "context" "fmt" - mapiv1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -94,8 +94,8 @@ func GenerateTemplate(in *GenerateTemplateInput) (*unstructured.Unstructured, er to.SetAnnotations(map[string]string{}) } annotations := to.GetAnnotations() - annotations[mapiv1.TemplateClonedFromNameAnnotation] = in.TemplateRef.Name - annotations[mapiv1.TemplateClonedFromGroupKindAnnotation] = in.TemplateRef.GroupVersionKind().GroupKind().String() + annotations[machinev1.TemplateClonedFromNameAnnotation] = in.TemplateRef.Name + annotations[machinev1.TemplateClonedFromGroupKindAnnotation] = in.TemplateRef.GroupVersionKind().GroupKind().String() to.SetAnnotations(annotations) // Set the owner reference. diff --git a/pkg/util/machines/machines.go b/pkg/util/machines/machines.go index f65fed65b9..7398a6dac0 100644 --- a/pkg/util/machines/machines.go +++ b/pkg/util/machines/machines.go @@ -3,7 +3,7 @@ package machines import ( "context" - mapiv1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" "github.com/openshift/machine-api-operator/pkg/util/conditions" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -12,7 +12,7 @@ import ( ) // IsMachineHealthy returns true if the the machine is running and machine node is healthy -func IsMachineHealthy(c client.Client, machine *mapiv1.Machine) bool { +func IsMachineHealthy(c client.Client, machine *machinev1.Machine) bool { if machine.Status.NodeRef == nil { klog.V(4).Infof("machine %s does not have NodeRef", machine.Name) return false diff --git a/pkg/util/testing/testing.go b/pkg/util/testing/testing.go index 80c8b578ed..4a75910cf8 100644 --- a/pkg/util/testing/testing.go +++ b/pkg/util/testing/testing.go @@ -4,7 +4,8 @@ import ( "fmt" "time" - mapiv1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" + machinev1 "github.com/openshift/api/machine/v1beta1" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -103,8 +104,8 @@ func NewNode(name string, ready bool) *corev1.Node { } // NewMachine returns new machine object that can be used for testing -func NewMachine(name string, nodeName string) *mapiv1.Machine { - m := &mapiv1.Machine{ +func NewMachine(name string, nodeName string) *machinev1.Machine { + m := &machinev1.Machine{ TypeMeta: metav1.TypeMeta{Kind: "Machine"}, ObjectMeta: metav1.ObjectMeta{ Annotations: make(map[string]string), @@ -121,10 +122,10 @@ func NewMachine(name string, nodeName string) *mapiv1.Machine { // the following line is to account for a change in the fake client, see https://github.com/kubernetes-sigs/controller-runtime/pull/1306 ResourceVersion: "999", }, - Spec: mapiv1.MachineSpec{}, + Spec: machinev1.MachineSpec{}, } if nodeName != "" { - m.Status = mapiv1.MachineStatus{ + m.Status = machinev1.MachineStatus{ NodeRef: &corev1.ObjectReference{ Name: nodeName, Namespace: metav1.NamespaceNone, @@ -135,8 +136,8 @@ func NewMachine(name string, nodeName string) *mapiv1.Machine { } // NewMachineHealthCheck returns new MachineHealthCheck object that can be used for testing -func NewMachineHealthCheck(name string) *mapiv1.MachineHealthCheck { - return &mapiv1.MachineHealthCheck{ +func NewMachineHealthCheck(name string) *machinev1.MachineHealthCheck { + return &machinev1.MachineHealthCheck{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: Namespace, @@ -146,9 +147,9 @@ func NewMachineHealthCheck(name string) *mapiv1.MachineHealthCheck { TypeMeta: metav1.TypeMeta{ Kind: "MachineHealthCheck", }, - Spec: mapiv1.MachineHealthCheckSpec{ + Spec: machinev1.MachineHealthCheckSpec{ Selector: *NewSelectorFooBar(), - UnhealthyConditions: []mapiv1.UnhealthyCondition{ + UnhealthyConditions: []machinev1.UnhealthyCondition{ { Type: "Ready", Status: "Unknown", @@ -161,6 +162,6 @@ func NewMachineHealthCheck(name string) *mapiv1.MachineHealthCheck { }, }, }, - Status: mapiv1.MachineHealthCheckStatus{}, + Status: machinev1.MachineHealthCheckStatus{}, } } From 752fc6de0393929d802cae5054e067bbf99df022 Mon Sep 17 00:00:00 2001 From: Alexander Demichev Date: Wed, 27 Oct 2021 12:09:18 +0200 Subject: [PATCH 08/10] Remove generation related code --- Makefile | 22 +------------------ hack/gen-crd.sh | 43 ------------------------------------- hack/go-gen.sh | 4 ---- hack/update-codegen.sh | 38 --------------------------------- hack/verify-codegen.sh | 48 ------------------------------------------ hack/verify-diff.sh | 0 6 files changed, 1 insertion(+), 154 deletions(-) delete mode 100755 hack/gen-crd.sh delete mode 100755 hack/go-gen.sh delete mode 100755 hack/update-codegen.sh delete mode 100755 hack/verify-codegen.sh mode change 100755 => 100644 hack/verify-diff.sh diff --git a/Makefile b/Makefile index baf80b0e12..955532eeb4 100644 --- a/Makefile +++ b/Makefile @@ -49,7 +49,7 @@ vendor: $(DOCKER_CMD) ./hack/go-mod.sh .PHONY: check -check: lint fmt vet verify-codegen test ## Run code validations +check: lint fmt vet test ## Run code validations .PHONY: build build: machine-api-operator nodelink-controller machine-healthcheck machineset vsphere ## Build binaries @@ -74,26 +74,6 @@ vsphere: machineset: $(DOCKER_CMD) ./hack/go-build.sh machineset -.PHONY: generate -generate: gen-crd gogen update-codegen goimports - ./hack/verify-diff.sh - -.PHONY: gogen -gogen: - $(DOCKER_CMD) ./hack/go-gen.sh - -.PHONY: gen-crd -gen-crd: - $(DOCKER_CMD) ./hack/gen-crd.sh - -.PHONY: update-codegen -update-codegen: - $(DOCKER_CMD) ./hack/update-codegen.sh - -.PHONY: verify-codegen -verify-codegen: - $(DOCKER_CMD) ./hack/verify-codegen.sh - .PHONY: test-e2e test-e2e: ## Run openshift specific e2e tests ./hack/e2e.sh test-e2e diff --git a/hack/gen-crd.sh b/hack/gen-crd.sh deleted file mode 100755 index 30b2634722..0000000000 --- a/hack/gen-crd.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env bash - -set -eu - -function annotate_crd() { - script1='/^ annotations:/a\ -\ \ \ \ exclude.release.openshift.io/internal-openshift-hosted: "true"\ -\ \ \ \ include.release.openshift.io/self-managed-high-availability: "true"\ -\ \ \ \ include.release.openshift.io/single-node-developer: "true"' - script2='/^ controller-gen.kubebuilder.io\/version: (devel)/d' - input="${1}" - output="${2}" - sed -e "${script1}" -e "${script2}" "${input}" > "${output}" -} - -echo "Building controller-gen tool..." -go build -o bin/controller-gen github.com/openshift/machine-api-operator/vendor/sigs.k8s.io/controller-tools/cmd/controller-gen - -dir=$(mktemp -d -t XXXXXXXX) -echo $dir -mkdir -p $dir/src/github.com/openshift/machine-api-operator/pkg/apis - -cp -r pkg/apis/* $dir/src/github.com/openshift/machine-api-operator/pkg/apis -# Some dependencies need to be copied as well. Othwerwise, controller-gen will complain about non-existing kind Unsupported -cp -r vendor $dir/src/github.com/openshift/machine-api-operator/ -cp go.mod go.sum $dir/src/github.com/openshift/machine-api-operator/ - -cwd=$(pwd) -pushd $dir/src/github.com/openshift/machine-api-operator -GOPATH=$dir ${cwd}/bin/controller-gen crd \ - crd:crdVersions=v1 \ - paths=$dir/src/github.com/openshift/machine-api-operator/pkg/apis/machine/... \ - output:crd:dir=$dir/src/github.com/openshift/machine-api-operator/config/crds/ - -#${cwd}/bin/controller-gen crd paths=$dir/src/github.com/openshift/machine-api-operator/pkg/apis/... output:crd:dir=$dir/src/github.com/openshift/machine-api-operator/config/crds/ -popd - -echo "Copying and patching generated CRDs" -annotate_crd $dir/src/github.com/openshift/machine-api-operator/config/crds/machine.openshift.io_machinehealthchecks.yaml install/0000_30_machine-api-operator_07_machinehealthcheck.crd.yaml -annotate_crd $dir/src/github.com/openshift/machine-api-operator/config/crds/machine.openshift.io_machinesets.yaml install/0000_30_machine-api-operator_03_machineset.crd.yaml -annotate_crd $dir/src/github.com/openshift/machine-api-operator/config/crds/machine.openshift.io_machines.yaml install/0000_30_machine-api-operator_02_machine.crd.yaml - -rm -rf $dir diff --git a/hack/go-gen.sh b/hack/go-gen.sh deleted file mode 100755 index 86628444b9..0000000000 --- a/hack/go-gen.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -go generate ./pkg/apis/... - diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh deleted file mode 100755 index 7ce7664429..0000000000 --- a/hack/update-codegen.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2017 The Kubernetes Authors. -# -# 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. - -set -o errexit -set -o nounset -set -o pipefail - -SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -CODEGEN_PKG=${CODEGEN_PKG:-$(cd "${SCRIPT_ROOT}"; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../code-generator)} - -# generate the code with: -# --output-base because this script should also be able to run inside the vendor dir of -# k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir -# instead of the $GOPATH directly. For normal projects this can be dropped. - -# go modules do not bring this file so we create a runtime symbolic link from our copy. -cp "${SCRIPT_ROOT}"/hack/generate-groups.sh "${CODEGEN_PKG}"/generate-groups.sh -"${CODEGEN_PKG}"/generate-groups.sh client,lister,informer \ - github.com/openshift/machine-api-operator/pkg/generated \ - github.com/openshift/machine-api-operator/pkg/apis \ - machine:v1beta1 \ - --output-base "$(dirname "${BASH_SOURCE[0]}")/../../../.." \ - --go-header-file "${SCRIPT_ROOT}"/hack/boilerplate.go.txt - -rm -f "${CODEGEN_PKG}"/generate-groups.sh diff --git a/hack/verify-codegen.sh b/hack/verify-codegen.sh deleted file mode 100755 index 1ec6462d93..0000000000 --- a/hack/verify-codegen.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2017 The Kubernetes Authors. -# -# 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. - -set -o errexit -set -o nounset -set -o pipefail - -SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. - -DIFFROOT="${SCRIPT_ROOT}/pkg" -TMP_DIFFROOT="${SCRIPT_ROOT}/_tmp/pkg" -_tmp="${SCRIPT_ROOT}/_tmp" - -cleanup() { - rm -rf "${_tmp}" -} -trap "cleanup" EXIT SIGINT - -cleanup - -mkdir -p "${TMP_DIFFROOT}" -cp -a "${DIFFROOT}"/* "${TMP_DIFFROOT}" - -NO_DOCKER=1 make --directory="${SCRIPT_ROOT}" update-codegen -echo "diffing ${DIFFROOT} against freshly generated codegen" -ret=0 -diff -Naupr "${DIFFROOT}" "${TMP_DIFFROOT}" || ret=$? -cp -a "${TMP_DIFFROOT}"/* "${DIFFROOT}" -if [[ $ret -eq 0 ]] -then - echo "${DIFFROOT} up to date." -else - echo "${DIFFROOT} is out of date. Please run: make generate" - exit 1 -fi diff --git a/hack/verify-diff.sh b/hack/verify-diff.sh old mode 100755 new mode 100644 From 52fedf842f73d0404408c8ace37343a9b553a47e Mon Sep 17 00:00:00 2001 From: Alexander Demichev Date: Wed, 27 Oct 2021 12:09:31 +0200 Subject: [PATCH 09/10] Fix unit tests --- pkg/controller/vsphere/util.go | 5 ++--- pkg/util/conditions/getter.go | 8 ++++---- pkg/util/conditions/setter.go | 14 ++++++-------- pkg/util/conditions/setter_test.go | 13 ++++++------- pkg/webhooks/v1beta1_suite_test.go | 2 +- 5 files changed, 19 insertions(+), 23 deletions(-) diff --git a/pkg/controller/vsphere/util.go b/pkg/controller/vsphere/util.go index cd807b9adf..21e1ac1dad 100644 --- a/pkg/controller/vsphere/util.go +++ b/pkg/controller/vsphere/util.go @@ -7,7 +7,6 @@ import ( "fmt" "gopkg.in/gcfg.v1" - "gopkg.in/yaml.v2" configv1 "github.com/openshift/api/config/v1" machinev1 "github.com/openshift/api/machine/v1beta1" @@ -225,7 +224,7 @@ func ProviderSpecFromRawExtension(rawExtension *runtime.RawExtension) (*machinev } spec := new(machinev1.VSphereMachineProviderSpec) - if err := yaml.Unmarshal(rawExtension.Raw, &spec); err != nil { + if err := json.Unmarshal(rawExtension.Raw, &spec); err != nil { return nil, fmt.Errorf("error unmarshalling providerSpec: %v", err) } @@ -240,7 +239,7 @@ func ProviderStatusFromRawExtension(rawExtension *runtime.RawExtension) (*machin } providerStatus := new(machinev1.VSphereMachineProviderStatus) - if err := yaml.Unmarshal(rawExtension.Raw, providerStatus); err != nil { + if err := json.Unmarshal(rawExtension.Raw, providerStatus); err != nil { return nil, fmt.Errorf("error unmarshalling providerStatus: %v", err) } diff --git a/pkg/util/conditions/getter.go b/pkg/util/conditions/getter.go index 72864ec69a..84cc249686 100644 --- a/pkg/util/conditions/getter.go +++ b/pkg/util/conditions/getter.go @@ -51,10 +51,10 @@ func Get(from interface{}, t machinev1.ConditionType) *machinev1.Condition { func getGetterObject(from interface{}) Getter { switch obj := from.(type) { - case machinev1.Machine: - return &MachineWrapper{&obj} - case machinev1.MachineHealthCheck: - return &MachineHealthCheckWrapper{&obj} + case *machinev1.Machine: + return &MachineWrapper{obj} + case *machinev1.MachineHealthCheck: + return &MachineHealthCheckWrapper{obj} default: panic("type is not supported as conditions getter") } diff --git a/pkg/util/conditions/setter.go b/pkg/util/conditions/setter.go index 078d123d8d..e3f35d4fb6 100644 --- a/pkg/util/conditions/setter.go +++ b/pkg/util/conditions/setter.go @@ -109,22 +109,20 @@ func UnknownCondition(t machinev1.ConditionType, reason string, messageFormat st // MarkTrue sets Status=True for the condition with the given type. func MarkTrue(to interface{}, t machinev1.ConditionType) { - obj := getSetterObject(to) - Set(obj, TrueCondition(t)) + Set(to, TrueCondition(t)) } // MarkFalse sets Status=False for the condition with the given type. func MarkFalse(to interface{}, t machinev1.ConditionType, reason string, severity machinev1.ConditionSeverity, messageFormat string, messageArgs ...interface{}) { - obj := getSetterObject(to) - Set(obj, FalseCondition(t, reason, severity, messageFormat, messageArgs...)) + Set(to, FalseCondition(t, reason, severity, messageFormat, messageArgs...)) } func getSetterObject(from interface{}) Setter { switch obj := from.(type) { - case machinev1.Machine: - return &MachineWrapper{&obj} - case machinev1.MachineHealthCheck: - return &MachineHealthCheckWrapper{&obj} + case *machinev1.Machine: + return &MachineWrapper{obj} + case *machinev1.MachineHealthCheck: + return &MachineHealthCheckWrapper{obj} default: panic("type is not supported as conditions getter") } diff --git a/pkg/util/conditions/setter_test.go b/pkg/util/conditions/setter_test.go index 127b106cd7..9d59a0e729 100644 --- a/pkg/util/conditions/setter_test.go +++ b/pkg/util/conditions/setter_test.go @@ -82,7 +82,7 @@ func TestSet(t *testing.T) { tests := []struct { name string - to Setter + to *machinev1.MachineHealthCheck condition *machinev1.Condition want machinev1.Conditions }{ @@ -118,7 +118,7 @@ func TestSet(t *testing.T) { Set(tt.to, tt.condition) - g.Expect(tt.to.GetConditions()).To(haveSameConditionsOf(tt.want)) + g.Expect(tt.to.Status.Conditions).To(haveSameConditionsOf(tt.want)) }) } } @@ -133,7 +133,7 @@ func TestSetLastTransitionTime(t *testing.T) { tests := []struct { name string - to Setter + to *machinev1.MachineHealthCheck new *machinev1.Condition LastTransitionTimeCheck func(*WithT, metav1.Time) }{ @@ -182,10 +182,9 @@ func TestSetLastTransitionTime(t *testing.T) { } } -func setterWithConditions(conditions ...*machinev1.Condition) Setter { - obj := &MachineHealthCheckWrapper{&machinev1.MachineHealthCheck{}} - - obj.SetConditions(conditionList(conditions...)) +func setterWithConditions(conditions ...*machinev1.Condition) *machinev1.MachineHealthCheck { + obj := &machinev1.MachineHealthCheck{} + obj.Status.Conditions = conditionList(conditions...) return obj } diff --git a/pkg/webhooks/v1beta1_suite_test.go b/pkg/webhooks/v1beta1_suite_test.go index 8a7b1b7a29..c8f547288f 100644 --- a/pkg/webhooks/v1beta1_suite_test.go +++ b/pkg/webhooks/v1beta1_suite_test.go @@ -56,7 +56,7 @@ var ( func TestMain(m *testing.M) { testEnv = &envtest.Environment{ CRDDirectoryPaths: []string{ - filepath.Join("..", "..", "..", "..", "install"), + filepath.Join("..", "..", "install"), filepath.Join("..", "..", "..", "..", "vendor", "github.com", "openshift", "api", "config", "v1"), }, WebhookInstallOptions: envtest.WebhookInstallOptions{ From ecbdcb37036b1612c5bdb98303bbdb3d65af455c Mon Sep 17 00:00:00 2001 From: Alexander Demichev Date: Fri, 29 Oct 2021 12:37:08 +0200 Subject: [PATCH 10/10] Combine conditions interfaces --- pkg/util/conditions/getter.go | 61 -------------- pkg/util/conditions/getter_test.go | 82 ------------------- .../conditions/{setter.go => gettersetter.go} | 70 ++++++++-------- .../{setter_test.go => gettersetter_test.go} | 55 +++++++++++++ pkg/util/conditions/matcher_test.go | 1 - pkg/util/conditions/wrap.go | 4 - 6 files changed, 93 insertions(+), 180 deletions(-) delete mode 100644 pkg/util/conditions/getter.go delete mode 100644 pkg/util/conditions/getter_test.go rename pkg/util/conditions/{setter.go => gettersetter.go} (82%) rename pkg/util/conditions/{setter_test.go => gettersetter_test.go} (78%) diff --git a/pkg/util/conditions/getter.go b/pkg/util/conditions/getter.go deleted file mode 100644 index 84cc249686..0000000000 --- a/pkg/util/conditions/getter.go +++ /dev/null @@ -1,61 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -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 conditions - -import ( - machinev1 "github.com/openshift/api/machine/v1beta1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" -) - -// Getter interface defines methods that a Machine API object should implement in order to -// use the conditions package for getting conditions. -type Getter interface { - runtime.Object - metav1.Object - - // GetConditions returns the list of conditions for a cluster API object. - GetConditions() machinev1.Conditions -} - -// Get returns the condition with the given type, if the condition does not exists, -// it returns nil. -func Get(from interface{}, t machinev1.ConditionType) *machinev1.Condition { - obj := getGetterObject(from) - conditions := obj.GetConditions() - if conditions == nil { - return nil - } - - for _, condition := range conditions { - if condition.Type == t { - return &condition - } - } - return nil -} - -func getGetterObject(from interface{}) Getter { - switch obj := from.(type) { - case *machinev1.Machine: - return &MachineWrapper{obj} - case *machinev1.MachineHealthCheck: - return &MachineHealthCheckWrapper{obj} - default: - panic("type is not supported as conditions getter") - } -} diff --git a/pkg/util/conditions/getter_test.go b/pkg/util/conditions/getter_test.go deleted file mode 100644 index ebd129da72..0000000000 --- a/pkg/util/conditions/getter_test.go +++ /dev/null @@ -1,82 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -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 conditions - -import ( - "errors" - "testing" - - . "github.com/onsi/gomega" - "github.com/onsi/gomega/format" - "github.com/onsi/gomega/types" - machinev1 "github.com/openshift/api/machine/v1beta1" -) - -var ( - nil1 *machinev1.Condition - true1 = TrueCondition("true1") - unknown1 = UnknownCondition("unknown1", "reason unknown1", "message unknown1") - falseInfo1 = FalseCondition("falseInfo1", "reason falseInfo1", machinev1.ConditionSeverityInfo, "message falseInfo1") - falseWarning1 = FalseCondition("falseWarning1", "reason falseWarning1", machinev1.ConditionSeverityWarning, "message falseWarning1") - falseError1 = FalseCondition("falseError1", "reason falseError1", machinev1.ConditionSeverityError, "message falseError1") -) - -func TestGet(t *testing.T) { - g := NewWithT(t) - - mhc := &machinev1.MachineHealthCheck{} - g.Expect(Get(mhc, "conditionBaz")).To(BeNil()) - - mhc.Status.Conditions = conditionList(TrueCondition("conditionBaz")) - g.Expect(Get(mhc, "conditionBaz")).To(haveSameStateOf(TrueCondition("conditionBaz"))) -} - -func conditionList(conditions ...*machinev1.Condition) machinev1.Conditions { - cs := machinev1.Conditions{} - for _, x := range conditions { - if x != nil { - cs = append(cs, *x) - } - } - return cs -} - -func haveSameStateOf(expected *machinev1.Condition) types.GomegaMatcher { - return &ConditionMatcher{ - Expected: expected, - } -} - -type ConditionMatcher struct { - Expected *machinev1.Condition -} - -func (matcher *ConditionMatcher) Match(actual interface{}) (success bool, err error) { - actualCondition, ok := actual.(*machinev1.Condition) - if !ok { - return false, errors.New("Value should be a condition") - } - - return hasSameState(actualCondition, matcher.Expected), nil -} - -func (matcher *ConditionMatcher) FailureMessage(actual interface{}) (message string) { - return format.Message(actual, "to have the same state of", matcher.Expected) -} -func (matcher *ConditionMatcher) NegatedFailureMessage(actual interface{}) (message string) { - return format.Message(actual, "not to have the same state of", matcher.Expected) -} diff --git a/pkg/util/conditions/setter.go b/pkg/util/conditions/gettersetter.go similarity index 82% rename from pkg/util/conditions/setter.go rename to pkg/util/conditions/gettersetter.go index e3f35d4fb6..0d8c9fd8f7 100644 --- a/pkg/util/conditions/setter.go +++ b/pkg/util/conditions/gettersetter.go @@ -1,19 +1,3 @@ -/* -Copyright 2020 The Kubernetes Authors. - -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 conditions import ( @@ -24,15 +8,37 @@ import ( machinev1 "github.com/openshift/api/machine/v1beta1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" ) -// Setter interface defines methods that a Machine API object should implement in order to -// use the conditions package for setting conditions. -type Setter interface { - Getter +type GetterSetter interface { + runtime.Object + metav1.Object + + // GetConditions returns the list of conditions for a machine API object. + GetConditions() machinev1.Conditions + + // SetConditions sets the list of conditions for a machine API object. SetConditions(machinev1.Conditions) } +// Get returns the condition with the given type, if the condition does not exists, +// it returns nil. +func Get(from interface{}, t machinev1.ConditionType) *machinev1.Condition { + obj := getWrapperObject(from) + conditions := obj.GetConditions() + if conditions == nil { + return nil + } + + for _, condition := range conditions { + if condition.Type == t { + return &condition + } + } + return nil +} + // Set sets the given condition. // // NOTE: If a condition already exists, the LastTransitionTime is updated only if a change is detected @@ -42,7 +48,7 @@ func Set(to interface{}, condition *machinev1.Condition) { return } - obj := getSetterObject(to) + obj := getWrapperObject(to) // Check if the new conditions already exists, and change it only if there is a status // transition (otherwise we should preserve the current last transition time)- @@ -117,17 +123,6 @@ func MarkFalse(to interface{}, t machinev1.ConditionType, reason string, severit Set(to, FalseCondition(t, reason, severity, messageFormat, messageArgs...)) } -func getSetterObject(from interface{}) Setter { - switch obj := from.(type) { - case *machinev1.Machine: - return &MachineWrapper{obj} - case *machinev1.MachineHealthCheck: - return &MachineHealthCheckWrapper{obj} - default: - panic("type is not supported as conditions getter") - } -} - // lexicographicLess returns true if a condition is less than another with regards to the // to order of conditions designed for convenience of the consumer, i.e. kubectl. func lexicographicLess(i, j *machinev1.Condition) bool { @@ -143,3 +138,14 @@ func hasSameState(i, j *machinev1.Condition) bool { i.Severity == j.Severity && i.Message == j.Message } + +func getWrapperObject(from interface{}) GetterSetter { + switch obj := from.(type) { + case *machinev1.Machine: + return &MachineWrapper{obj} + case *machinev1.MachineHealthCheck: + return &MachineHealthCheckWrapper{obj} + default: + panic("type is not supported as conditions getter or setter") + } +} diff --git a/pkg/util/conditions/setter_test.go b/pkg/util/conditions/gettersetter_test.go similarity index 78% rename from pkg/util/conditions/setter_test.go rename to pkg/util/conditions/gettersetter_test.go index 9d59a0e729..5edc478904 100644 --- a/pkg/util/conditions/setter_test.go +++ b/pkg/util/conditions/gettersetter_test.go @@ -29,6 +29,61 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +var ( + nil1 *machinev1.Condition + true1 = TrueCondition("true1") + unknown1 = UnknownCondition("unknown1", "reason unknown1", "message unknown1") + falseInfo1 = FalseCondition("falseInfo1", "reason falseInfo1", machinev1.ConditionSeverityInfo, "message falseInfo1") + falseWarning1 = FalseCondition("falseWarning1", "reason falseWarning1", machinev1.ConditionSeverityWarning, "message falseWarning1") + falseError1 = FalseCondition("falseError1", "reason falseError1", machinev1.ConditionSeverityError, "message falseError1") +) + +func TestGet(t *testing.T) { + g := NewWithT(t) + + mhc := &machinev1.MachineHealthCheck{} + g.Expect(Get(mhc, "conditionBaz")).To(BeNil()) + + mhc.Status.Conditions = conditionList(TrueCondition("conditionBaz")) + g.Expect(Get(mhc, "conditionBaz")).To(haveSameStateOf(TrueCondition("conditionBaz"))) +} + +func conditionList(conditions ...*machinev1.Condition) machinev1.Conditions { + cs := machinev1.Conditions{} + for _, x := range conditions { + if x != nil { + cs = append(cs, *x) + } + } + return cs +} + +func haveSameStateOf(expected *machinev1.Condition) types.GomegaMatcher { + return &ConditionMatcher{ + Expected: expected, + } +} + +type ConditionMatcher struct { + Expected *machinev1.Condition +} + +func (matcher *ConditionMatcher) Match(actual interface{}) (success bool, err error) { + actualCondition, ok := actual.(*machinev1.Condition) + if !ok { + return false, errors.New("Value should be a condition") + } + + return hasSameState(actualCondition, matcher.Expected), nil +} + +func (matcher *ConditionMatcher) FailureMessage(actual interface{}) (message string) { + return format.Message(actual, "to have the same state of", matcher.Expected) +} +func (matcher *ConditionMatcher) NegatedFailureMessage(actual interface{}) (message string) { + return format.Message(actual, "not to have the same state of", matcher.Expected) +} + func TestHasSameState(t *testing.T) { g := NewWithT(t) diff --git a/pkg/util/conditions/matcher_test.go b/pkg/util/conditions/matcher_test.go index 2a8466adac..59f9a5c22a 100644 --- a/pkg/util/conditions/matcher_test.go +++ b/pkg/util/conditions/matcher_test.go @@ -21,7 +21,6 @@ import ( . "github.com/onsi/gomega" machinev1 "github.com/openshift/api/machine/v1beta1" - corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) diff --git a/pkg/util/conditions/wrap.go b/pkg/util/conditions/wrap.go index 41d8d9fe13..aba14a54e5 100644 --- a/pkg/util/conditions/wrap.go +++ b/pkg/util/conditions/wrap.go @@ -27,7 +27,3 @@ func (m *MachineHealthCheckWrapper) GetConditions() machinev1.Conditions { func (m *MachineHealthCheckWrapper) SetConditions(conditions machinev1.Conditions) { m.Status.Conditions = conditions } - -func WrapMachineHealthCheck(mhc *machinev1.MachineHealthCheck) *MachineHealthCheckWrapper { - return &MachineHealthCheckWrapper{MachineHealthCheck: mhc} -}