diff --git a/cmd/machine-api-operator/client_builder.go b/cmd/machine-api-operator/client_builder.go index 2ac560f1cf..ff6752d673 100644 --- a/cmd/machine-api-operator/client_builder.go +++ b/cmd/machine-api-operator/client_builder.go @@ -21,8 +21,8 @@ func (cb *ClientBuilder) KubeClientOrDie(name string) kubernetes.Interface { return kubernetes.NewForConfigOrDie(rest.AddUserAgent(cb.config, name)) } -// NewForConfigOrDie returns the kubernetes client interface for dynamic objects. -func (cb *ClientBuilder) dynamicClientOrDie(name string) dynamic.Interface { +// DynamicClientOrDie returns a dynamic client interface. +func (cb *ClientBuilder) DynamicClientOrDie(name string) dynamic.Interface { return dynamic.NewForConfigOrDie(rest.AddUserAgent(cb.config, name)) } diff --git a/cmd/machine-api-operator/start.go b/cmd/machine-api-operator/start.go index 8cc7515270..eaa1c2c9fd 100644 --- a/cmd/machine-api-operator/start.go +++ b/cmd/machine-api-operator/start.go @@ -124,7 +124,7 @@ func startControllers(ctx *ControllerContext) { ctx.ConfigInformerFactory.Config().V1().FeatureGates(), ctx.ClientBuilder.KubeClientOrDie(componentName), ctx.ClientBuilder.OpenshiftClientOrDie(componentName), - ctx.ClientBuilder.dynamicClientOrDie(componentName), + ctx.ClientBuilder.DynamicClientOrDie(componentName), recorder, ).Run(1, ctx.Stop) } diff --git a/pkg/operator/baremetal_config.go b/pkg/operator/baremetal_config.go new file mode 100644 index 0000000000..ccc8c3c821 --- /dev/null +++ b/pkg/operator/baremetal_config.go @@ -0,0 +1,67 @@ +package operator + +import ( + "github.com/golang/glog" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + dynamic "k8s.io/client-go/dynamic" +) + +var provisioningGVR = schema.GroupVersionResource{Group: "metal3.io", Resource: "provisionings", Version: "v1alpha1"} +var baremetalProvisioningCR = "cluster" + +// Provisioning Config needed to deploy Metal3 pod +type BaremetalProvisioningConfig struct { + ProvisioningInterface string + ProvisioningIp string + ProvisioningNetworkCIDR string + ProvisioningDHCPExternal bool + ProvisioningDHCPRange string +} + +func getBaremetalProvisioningConfig(dc dynamic.Interface, configName string) (BaremetalProvisioningConfig, error) { + provisioningClient := dc.Resource(provisioningGVR) + provisioningConfig, err := provisioningClient.Get(configName, metav1.GetOptions{}) + if err != nil { + glog.Errorf("Error getting config from Baremetal provisioning CR %s", configName) + return BaremetalProvisioningConfig{}, err + } + provisioningSpec, found, err := unstructured.NestedMap(provisioningConfig.UnstructuredContent(), "spec") + if !found { + glog.Errorf("Nested Spec not found in Baremetal provisioning CR %s", configName) + return BaremetalProvisioningConfig{}, err + } + provisioningInterface, found, err := unstructured.NestedString(provisioningSpec, "provisioningInterface") + if !found { + glog.Errorf("provisioningInterface not found in Baremetal provisioning CR %s", configName) + return BaremetalProvisioningConfig{}, err + } + provisioningIP, found, err := unstructured.NestedString(provisioningSpec, "provisioningIP") + if !found { + glog.Errorf("provisioningIP not found in Baremetal provisioning CR %s", configName) + return BaremetalProvisioningConfig{}, err + } + provisioningNetworkCIDR, found, err := unstructured.NestedString(provisioningSpec, "provisioningNetworkCIDR") + if !found { + glog.Errorf("provisioningNetworkCIDR not found in Baremetal provisioning CR %s", configName) + return BaremetalProvisioningConfig{}, err + } + provisioningDHCPExternal, found, err := unstructured.NestedBool(provisioningSpec, "provisioningDHCPExternal") + if !found { + glog.Errorf("provisioningDHCPExternal not found in Baremetal provisioning CR %s", configName) + return BaremetalProvisioningConfig{}, err + } + provisioningDHCPRange, found, err := unstructured.NestedString(provisioningSpec, "provisioningDHCPRange") + if !found { + glog.Errorf("provisioningDHCPRange not found in Baremetal provisioning CR %s", configName) + return BaremetalProvisioningConfig{}, err + } + return BaremetalProvisioningConfig{ + ProvisioningInterface: provisioningInterface, + ProvisioningIp: provisioningIP, + ProvisioningNetworkCIDR: provisioningNetworkCIDR, + ProvisioningDHCPExternal: provisioningDHCPExternal, + ProvisioningDHCPRange: provisioningDHCPRange, + }, nil +} diff --git a/pkg/operator/baremetal_pod.go b/pkg/operator/baremetal_pod.go index a95deee277..3e61c42413 100644 --- a/pkg/operator/baremetal_pod.go +++ b/pkg/operator/baremetal_pod.go @@ -98,7 +98,8 @@ func createMariadbPasswordSecret(client coreclientv1.SecretsGetter, config *Oper return err } -func newMetal3Deployment(config *OperatorConfig) *appsv1.Deployment { +func newMetal3Deployment(config *OperatorConfig, baremetalProvisioningConfig BaremetalProvisioningConfig) *appsv1.Deployment { + // TODO(sadasu): Use config from BaremetalProvisioningConfig to set env vars for containers. replicas := int32(1) template := newMetal3PodTemplateSpec(config) diff --git a/pkg/operator/baremetal_test.go b/pkg/operator/baremetal_test.go index df45cf4bbe..bbe9974b1a 100644 --- a/pkg/operator/baremetal_test.go +++ b/pkg/operator/baremetal_test.go @@ -4,7 +4,31 @@ import ( "testing" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + fakedynamic "k8s.io/client-go/dynamic/fake" fakekube "k8s.io/client-go/kubernetes/fake" + "sigs.k8s.io/yaml" +) + +var yamlContent = ` +apiVersion: metal3.io/v1alpha1 +kind: Provisioning +metadata: + name: test +spec: + provisioningInterface: "ensp0" + provisioningIP: "172.30.20.3" + provisioningNetworkCIDR: "172.30.20.0/24" + provisioningDHCPExternal: false + provisioningDHCPRange: "172.30.20.10, 72.30.20.100" +` +var ( + expectedProvisioningInterface = "ensp0" + expectedProvisioningIP = "172.30.20.3" + expectedProvisioningNetworkCIDR = "172.30.20.0/24" + expectedProvisioningDHCPExternal = false + expectedProvisioningDHCPRange = "172.30.20.10, 72.30.20.100" ) func TestGenerateRandomPassword(t *testing.T) { @@ -71,3 +95,40 @@ func TestCreateMariadbPasswordSecret(t *testing.T) { t.Logf("First Mariadb password is being preserved over re-creation as expected.") } } + +func TestGetBaremetalProvisioningConfig(t *testing.T) { + u := &unstructured.Unstructured{Object: map[string]interface{}{}} + if err := yaml.Unmarshal([]byte(yamlContent), &u); err != nil { + t.Errorf("failed to unmarshall input yaml content:%v", err) + } + dynamicClient := fakedynamic.NewSimpleDynamicClient(runtime.NewScheme(), u) + baremetalConfig, err := getBaremetalProvisioningConfig(dynamicClient, "test") + if err != nil { + t.Logf("Unstructed Config: %+v", u) + t.Fatalf("Failed to get Baremetal Provisioning Interface from CR %s", "test") + } + if baremetalConfig.ProvisioningInterface != expectedProvisioningInterface || + baremetalConfig.ProvisioningIp != expectedProvisioningIP || + baremetalConfig.ProvisioningNetworkCIDR != expectedProvisioningNetworkCIDR || + baremetalConfig.ProvisioningDHCPExternal != expectedProvisioningDHCPExternal || + baremetalConfig.ProvisioningDHCPRange != expectedProvisioningDHCPRange { + t.Logf("Actual BaremetalProvisioningConfig: %+v", baremetalConfig) + t.Logf("Expected : ProvisioningInterface: %s, ProvisioningIP: %s, ProvisioningNetworkCIDR: %s, ProvisioningDHCPExternal: %t, expectedProvisioningDHCPRange: %s", expectedProvisioningInterface, expectedProvisioningIP, expectedProvisioningNetworkCIDR, expectedProvisioningDHCPExternal, expectedProvisioningDHCPRange) + t.Fatalf("failed getBaremetalProvisioningConfig. One or more BaremetalProvisioningConfig items do not match the expected config.") + } +} + +func TestGetIncorrectBaremetalProvisioningCR(t *testing.T) { + u := &unstructured.Unstructured{Object: map[string]interface{}{}} + if err := yaml.Unmarshal([]byte(yamlContent), &u); err != nil { + t.Errorf("failed to unmarshall input yaml content:%v", err) + } + dynamicClient := fakedynamic.NewSimpleDynamicClient(runtime.NewScheme(), u) + baremetalConfig, err := getBaremetalProvisioningConfig(dynamicClient, "test1") + if err != nil { + t.Logf("Unable to get Baremetal Provisioning Config from CR %s as expected", "test1") + } + if baremetalConfig.ProvisioningInterface != "" { + t.Errorf("BaremetalProvisioningConfig is not expected to be set.") + } +} diff --git a/pkg/operator/operator_test.go b/pkg/operator/operator_test.go index b4b771593e..35423e4fda 100644 --- a/pkg/operator/operator_test.go +++ b/pkg/operator/operator_test.go @@ -13,6 +13,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/wait" + fakedynamic "k8s.io/client-go/dynamic/fake" "k8s.io/client-go/informers" fakekube "k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/tools/record" @@ -42,6 +43,7 @@ func newOperatorConfig() *OperatorConfig { func newFakeOperator(kubeObjects []runtime.Object, osObjects []runtime.Object, stopCh <-chan struct{}) *Operator { kubeClient := fakekube.NewSimpleClientset(kubeObjects...) osClient := fakeos.NewSimpleClientset(osObjects...) + dynamicClient := fakedynamic.NewSimpleDynamicClient(runtime.NewScheme(), kubeObjects...) kubeNamespacedSharedInformer := informers.NewSharedInformerFactoryWithOptions(kubeClient, 2*time.Minute, informers.WithNamespace(targetNamespace)) configSharedInformer := configinformersv1.NewSharedInformerFactoryWithOptions(osClient, 2*time.Minute) featureGateInformer := configSharedInformer.Config().V1().FeatureGates() @@ -50,6 +52,7 @@ func newFakeOperator(kubeObjects []runtime.Object, osObjects []runtime.Object, s optr := &Operator{ kubeClient: kubeClient, osClient: osClient, + dynamicClient: dynamicClient, featureGateLister: featureGateInformer.Lister(), deployLister: deployInformer.Lister(), imagesFile: "fixtures/images.json", diff --git a/pkg/operator/sync.go b/pkg/operator/sync.go index 68d47954fc..93ad085967 100644 --- a/pkg/operator/sync.go +++ b/pkg/operator/sync.go @@ -74,13 +74,18 @@ func (optr *Operator) syncClusterAPIController(config *OperatorConfig) error { } func (optr *Operator) syncBaremetalControllers(config *OperatorConfig) error { - // First create a Secret needed for the Metal3 deployment + // Try to get baremetal provisioning config from a CR + baremetalProvisioningConfig, err := getBaremetalProvisioningConfig(optr.dynamicClient, baremetalProvisioningCR) + if err != nil { + glog.Infof("Unable to read Baremetal Provisioning config from CR %s.", baremetalProvisioningCR) + } + // Create a Secret needed for the Metal3 deployment if err := createMariadbPasswordSecret(optr.kubeClient.CoreV1(), config); err != nil { glog.Error("Not proceeding with Metal3 deployment. Failed to create Mariadb password.") return err } - metal3Deployment := newMetal3Deployment(config) + metal3Deployment := newMetal3Deployment(config, baremetalProvisioningConfig) _, updated, err := resourceapply.ApplyDeployment(optr.kubeClient.AppsV1(), metal3Deployment) if err != nil { return err diff --git a/vendor/k8s.io/client-go/dynamic/fake/simple.go b/vendor/k8s.io/client-go/dynamic/fake/simple.go new file mode 100644 index 0000000000..819b8d9c90 --- /dev/null +++ b/vendor/k8s.io/client-go/dynamic/fake/simple.go @@ -0,0 +1,370 @@ +/* +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 fake + +import ( + "strings" + + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/testing" +) + +func NewSimpleDynamicClient(scheme *runtime.Scheme, objects ...runtime.Object) *FakeDynamicClient { + // In order to use List with this client, you have to have the v1.List registered in your scheme. Neat thing though + // it does NOT have to be the *same* list + scheme.AddKnownTypeWithName(schema.GroupVersionKind{Group: "fake-dynamic-client-group", Version: "v1", Kind: "List"}, &unstructured.UnstructuredList{}) + + codecs := serializer.NewCodecFactory(scheme) + o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &FakeDynamicClient{scheme: scheme} + 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 FakeDynamicClient struct { + testing.Fake + scheme *runtime.Scheme +} + +type dynamicResourceClient struct { + client *FakeDynamicClient + namespace string + resource schema.GroupVersionResource +} + +var _ dynamic.Interface = &FakeDynamicClient{} + +func (c *FakeDynamicClient) Resource(resource schema.GroupVersionResource) dynamic.NamespaceableResourceInterface { + return &dynamicResourceClient{client: c, resource: resource} +} + +func (c *dynamicResourceClient) Namespace(ns string) dynamic.ResourceInterface { + ret := *c + ret.namespace = ns + return &ret +} + +func (c *dynamicResourceClient) Create(obj *unstructured.Unstructured, opts metav1.CreateOptions, subresources ...string) (*unstructured.Unstructured, error) { + var uncastRet runtime.Object + var err error + switch { + case len(c.namespace) == 0 && len(subresources) == 0: + uncastRet, err = c.client.Fake. + Invokes(testing.NewRootCreateAction(c.resource, obj), obj) + + case len(c.namespace) == 0 && len(subresources) > 0: + accessor, err := meta.Accessor(obj) + if err != nil { + return nil, err + } + name := accessor.GetName() + uncastRet, err = c.client.Fake. + Invokes(testing.NewRootCreateSubresourceAction(c.resource, name, strings.Join(subresources, "/"), obj), obj) + + case len(c.namespace) > 0 && len(subresources) == 0: + uncastRet, err = c.client.Fake. + Invokes(testing.NewCreateAction(c.resource, c.namespace, obj), obj) + + case len(c.namespace) > 0 && len(subresources) > 0: + accessor, err := meta.Accessor(obj) + if err != nil { + return nil, err + } + name := accessor.GetName() + uncastRet, err = c.client.Fake. + Invokes(testing.NewCreateSubresourceAction(c.resource, name, strings.Join(subresources, "/"), c.namespace, obj), obj) + + } + + if err != nil { + return nil, err + } + if uncastRet == nil { + return nil, err + } + + ret := &unstructured.Unstructured{} + if err := c.client.scheme.Convert(uncastRet, ret, nil); err != nil { + return nil, err + } + return ret, err +} + +func (c *dynamicResourceClient) Update(obj *unstructured.Unstructured, opts metav1.UpdateOptions, subresources ...string) (*unstructured.Unstructured, error) { + var uncastRet runtime.Object + var err error + switch { + case len(c.namespace) == 0 && len(subresources) == 0: + uncastRet, err = c.client.Fake. + Invokes(testing.NewRootUpdateAction(c.resource, obj), obj) + + case len(c.namespace) == 0 && len(subresources) > 0: + uncastRet, err = c.client.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(c.resource, strings.Join(subresources, "/"), obj), obj) + + case len(c.namespace) > 0 && len(subresources) == 0: + uncastRet, err = c.client.Fake. + Invokes(testing.NewUpdateAction(c.resource, c.namespace, obj), obj) + + case len(c.namespace) > 0 && len(subresources) > 0: + uncastRet, err = c.client.Fake. + Invokes(testing.NewUpdateSubresourceAction(c.resource, strings.Join(subresources, "/"), c.namespace, obj), obj) + + } + + if err != nil { + return nil, err + } + if uncastRet == nil { + return nil, err + } + + ret := &unstructured.Unstructured{} + if err := c.client.scheme.Convert(uncastRet, ret, nil); err != nil { + return nil, err + } + return ret, err +} + +func (c *dynamicResourceClient) UpdateStatus(obj *unstructured.Unstructured, opts metav1.UpdateOptions) (*unstructured.Unstructured, error) { + var uncastRet runtime.Object + var err error + switch { + case len(c.namespace) == 0: + uncastRet, err = c.client.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(c.resource, "status", obj), obj) + + case len(c.namespace) > 0: + uncastRet, err = c.client.Fake. + Invokes(testing.NewUpdateSubresourceAction(c.resource, "status", c.namespace, obj), obj) + + } + + if err != nil { + return nil, err + } + if uncastRet == nil { + return nil, err + } + + ret := &unstructured.Unstructured{} + if err := c.client.scheme.Convert(uncastRet, ret, nil); err != nil { + return nil, err + } + return ret, err +} + +func (c *dynamicResourceClient) Delete(name string, opts *metav1.DeleteOptions, subresources ...string) error { + var err error + switch { + case len(c.namespace) == 0 && len(subresources) == 0: + _, err = c.client.Fake. + Invokes(testing.NewRootDeleteAction(c.resource, name), &metav1.Status{Status: "dynamic delete fail"}) + + case len(c.namespace) == 0 && len(subresources) > 0: + _, err = c.client.Fake. + Invokes(testing.NewRootDeleteSubresourceAction(c.resource, strings.Join(subresources, "/"), name), &metav1.Status{Status: "dynamic delete fail"}) + + case len(c.namespace) > 0 && len(subresources) == 0: + _, err = c.client.Fake. + Invokes(testing.NewDeleteAction(c.resource, c.namespace, name), &metav1.Status{Status: "dynamic delete fail"}) + + case len(c.namespace) > 0 && len(subresources) > 0: + _, err = c.client.Fake. + Invokes(testing.NewDeleteSubresourceAction(c.resource, strings.Join(subresources, "/"), c.namespace, name), &metav1.Status{Status: "dynamic delete fail"}) + } + + return err +} + +func (c *dynamicResourceClient) DeleteCollection(opts *metav1.DeleteOptions, listOptions metav1.ListOptions) error { + var err error + switch { + case len(c.namespace) == 0: + action := testing.NewRootDeleteCollectionAction(c.resource, listOptions) + _, err = c.client.Fake.Invokes(action, &metav1.Status{Status: "dynamic deletecollection fail"}) + + case len(c.namespace) > 0: + action := testing.NewDeleteCollectionAction(c.resource, c.namespace, listOptions) + _, err = c.client.Fake.Invokes(action, &metav1.Status{Status: "dynamic deletecollection fail"}) + + } + + return err +} + +func (c *dynamicResourceClient) Get(name string, opts metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error) { + var uncastRet runtime.Object + var err error + switch { + case len(c.namespace) == 0 && len(subresources) == 0: + uncastRet, err = c.client.Fake. + Invokes(testing.NewRootGetAction(c.resource, name), &metav1.Status{Status: "dynamic get fail"}) + + case len(c.namespace) == 0 && len(subresources) > 0: + uncastRet, err = c.client.Fake. + Invokes(testing.NewRootGetSubresourceAction(c.resource, strings.Join(subresources, "/"), name), &metav1.Status{Status: "dynamic get fail"}) + + case len(c.namespace) > 0 && len(subresources) == 0: + uncastRet, err = c.client.Fake. + Invokes(testing.NewGetAction(c.resource, c.namespace, name), &metav1.Status{Status: "dynamic get fail"}) + + case len(c.namespace) > 0 && len(subresources) > 0: + uncastRet, err = c.client.Fake. + Invokes(testing.NewGetSubresourceAction(c.resource, c.namespace, strings.Join(subresources, "/"), name), &metav1.Status{Status: "dynamic get fail"}) + } + + if err != nil { + return nil, err + } + if uncastRet == nil { + return nil, err + } + + ret := &unstructured.Unstructured{} + if err := c.client.scheme.Convert(uncastRet, ret, nil); err != nil { + return nil, err + } + return ret, err +} + +func (c *dynamicResourceClient) List(opts metav1.ListOptions) (*unstructured.UnstructuredList, error) { + var obj runtime.Object + var err error + switch { + case len(c.namespace) == 0: + obj, err = c.client.Fake. + Invokes(testing.NewRootListAction(c.resource, schema.GroupVersionKind{Group: "fake-dynamic-client-group", Version: "v1", Kind: "" /*List is appended by the tracker automatically*/}, opts), &metav1.Status{Status: "dynamic list fail"}) + + case len(c.namespace) > 0: + obj, err = c.client.Fake. + Invokes(testing.NewListAction(c.resource, schema.GroupVersionKind{Group: "fake-dynamic-client-group", Version: "v1", Kind: "" /*List is appended by the tracker automatically*/}, c.namespace, opts), &metav1.Status{Status: "dynamic list fail"}) + + } + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + + retUnstructured := &unstructured.Unstructured{} + if err := c.client.scheme.Convert(obj, retUnstructured, nil); err != nil { + return nil, err + } + entireList, err := retUnstructured.ToList() + if err != nil { + return nil, err + } + + list := &unstructured.UnstructuredList{} + list.SetResourceVersion(entireList.GetResourceVersion()) + for i := range entireList.Items { + item := &entireList.Items[i] + metadata, err := meta.Accessor(item) + if err != nil { + return nil, err + } + if label.Matches(labels.Set(metadata.GetLabels())) { + list.Items = append(list.Items, *item) + } + } + return list, nil +} + +func (c *dynamicResourceClient) Watch(opts metav1.ListOptions) (watch.Interface, error) { + switch { + case len(c.namespace) == 0: + return c.client.Fake. + InvokesWatch(testing.NewRootWatchAction(c.resource, opts)) + + case len(c.namespace) > 0: + return c.client.Fake. + InvokesWatch(testing.NewWatchAction(c.resource, c.namespace, opts)) + + } + + panic("math broke") +} + +// TODO: opts are currently ignored. +func (c *dynamicResourceClient) Patch(name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (*unstructured.Unstructured, error) { + var uncastRet runtime.Object + var err error + switch { + case len(c.namespace) == 0 && len(subresources) == 0: + uncastRet, err = c.client.Fake. + Invokes(testing.NewRootPatchAction(c.resource, name, pt, data), &metav1.Status{Status: "dynamic patch fail"}) + + case len(c.namespace) == 0 && len(subresources) > 0: + uncastRet, err = c.client.Fake. + Invokes(testing.NewRootPatchSubresourceAction(c.resource, name, pt, data, subresources...), &metav1.Status{Status: "dynamic patch fail"}) + + case len(c.namespace) > 0 && len(subresources) == 0: + uncastRet, err = c.client.Fake. + Invokes(testing.NewPatchAction(c.resource, c.namespace, name, pt, data), &metav1.Status{Status: "dynamic patch fail"}) + + case len(c.namespace) > 0 && len(subresources) > 0: + uncastRet, err = c.client.Fake. + Invokes(testing.NewPatchSubresourceAction(c.resource, c.namespace, name, pt, data, subresources...), &metav1.Status{Status: "dynamic patch fail"}) + + } + + if err != nil { + return nil, err + } + if uncastRet == nil { + return nil, err + } + + ret := &unstructured.Unstructured{} + if err := c.client.scheme.Convert(uncastRet, ret, nil); err != nil { + return nil, err + } + return ret, err +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 3a4ff4609e..2732f1a221 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -347,33 +347,34 @@ k8s.io/apimachinery/pkg/util/runtime k8s.io/apimachinery/pkg/watch k8s.io/apimachinery/pkg/api/equality k8s.io/apimachinery/pkg/api/resource +k8s.io/apimachinery/pkg/apis/meta/v1/unstructured k8s.io/apimachinery/pkg/conversion k8s.io/apimachinery/pkg/selection k8s.io/apimachinery/pkg/conversion/queryparams k8s.io/apimachinery/pkg/util/json k8s.io/apimachinery/pkg/util/naming -k8s.io/apimachinery/pkg/util/net -k8s.io/apimachinery/pkg/runtime/serializer/streaming k8s.io/apimachinery/pkg/api/meta +k8s.io/apimachinery/pkg/runtime/serializer/json +k8s.io/apimachinery/pkg/runtime/serializer/streaming +k8s.io/apimachinery/pkg/runtime/serializer/versioning +k8s.io/apimachinery/pkg/util/net k8s.io/apimachinery/pkg/util/cache k8s.io/apimachinery/pkg/util/clock k8s.io/apimachinery/pkg/util/diff k8s.io/apimachinery/pkg/util/validation k8s.io/apimachinery/pkg/util/strategicpatch k8s.io/apimachinery/pkg/util/yaml -k8s.io/apimachinery/pkg/apis/meta/v1/unstructured k8s.io/apimachinery/pkg/version -k8s.io/apimachinery/pkg/runtime/serializer/json k8s.io/apimachinery/pkg/runtime/serializer/protobuf k8s.io/apimachinery/pkg/runtime/serializer/recognizer -k8s.io/apimachinery/pkg/runtime/serializer/versioning k8s.io/apimachinery/third_party/forked/golang/reflect +k8s.io/apimachinery/pkg/util/framer k8s.io/apimachinery/pkg/apis/meta/internalversion k8s.io/apimachinery/pkg/util/mergepatch k8s.io/apimachinery/third_party/forked/golang/json -k8s.io/apimachinery/pkg/util/framer k8s.io/apimachinery/pkg/apis/meta/v1beta1 # k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible => github.com/openshift/kubernetes-client-go v0.0.0-20190918160344-1fbdaa4c8d90 +k8s.io/client-go/dynamic k8s.io/client-go/informers k8s.io/client-go/kubernetes k8s.io/client-go/kubernetes/scheme @@ -463,8 +464,8 @@ k8s.io/client-go/tools/clientcmd/api/latest k8s.io/client-go/util/homedir k8s.io/client-go/tools/record/util k8s.io/client-go/util/jsonpath -k8s.io/client-go/dynamic k8s.io/client-go/kubernetes/fake +k8s.io/client-go/dynamic/fake k8s.io/client-go/informers/admissionregistration/v1 k8s.io/client-go/informers/admissionregistration/v1beta1 k8s.io/client-go/informers/apps/v1beta1