sigs.k8s.io/cluster-api@v1.7.1/cmd/clusterctl/internal/test/fake_proxy.go (about)

     1  /*
     2  Copyright 2019 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package test
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  
    23  	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    24  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    26  	"k8s.io/apimachinery/pkg/runtime"
    27  	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
    28  	"k8s.io/client-go/rest"
    29  	"k8s.io/utils/ptr"
    30  	"sigs.k8s.io/controller-runtime/pkg/client"
    31  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    32  
    33  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    34  	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
    35  	fakebootstrap "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test/providers/bootstrap"
    36  	fakecontrolplane "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test/providers/controlplane"
    37  	fakeexternal "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test/providers/external"
    38  	fakeinfrastructure "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test/providers/infrastructure"
    39  	controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1"
    40  	addonsv1 "sigs.k8s.io/cluster-api/exp/addons/api/v1beta1"
    41  	expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1"
    42  )
    43  
    44  type FakeProxy struct {
    45  	cs        client.Client
    46  	namespace string
    47  	objs      []client.Object
    48  	available *bool
    49  }
    50  
    51  var (
    52  	FakeScheme = runtime.NewScheme() //nolint:revive
    53  )
    54  
    55  func init() {
    56  	_ = clientgoscheme.AddToScheme(FakeScheme)
    57  	_ = clusterctlv1.AddToScheme(FakeScheme)
    58  	_ = clusterv1.AddToScheme(FakeScheme)
    59  	_ = expv1.AddToScheme(FakeScheme)
    60  	_ = addonsv1.AddToScheme(FakeScheme)
    61  	_ = apiextensionsv1.AddToScheme(FakeScheme)
    62  	_ = controlplanev1.AddToScheme(FakeScheme)
    63  
    64  	_ = fakebootstrap.AddToScheme(FakeScheme)
    65  	_ = fakecontrolplane.AddToScheme(FakeScheme)
    66  	_ = fakeexternal.AddToScheme(FakeScheme)
    67  	_ = fakeinfrastructure.AddToScheme(FakeScheme)
    68  }
    69  
    70  func (f *FakeProxy) CurrentNamespace() (string, error) {
    71  	return f.namespace, nil
    72  }
    73  
    74  func (f *FakeProxy) ValidateKubernetesVersion() error {
    75  	return nil
    76  }
    77  
    78  func (f *FakeProxy) GetConfig() (*rest.Config, error) {
    79  	return nil, nil
    80  }
    81  
    82  func (f *FakeProxy) NewClient(_ context.Context) (client.Client, error) {
    83  	if f.cs != nil {
    84  		return f.cs, nil
    85  	}
    86  	f.cs = fake.NewClientBuilder().WithScheme(FakeScheme).WithObjects(f.objs...).Build()
    87  	return f.cs, nil
    88  }
    89  
    90  func (f *FakeProxy) CheckClusterAvailable(_ context.Context) error {
    91  	// default to considering the cluster as available unless explicitly set to be
    92  	// unavailable.
    93  	if f.available == nil || *f.available {
    94  		return nil
    95  	}
    96  	return errors.New("cluster is not available")
    97  }
    98  
    99  // ListResources returns all the resources known by the FakeProxy.
   100  func (f *FakeProxy) ListResources(_ context.Context, labels map[string]string, namespaces ...string) ([]unstructured.Unstructured, error) {
   101  	var ret []unstructured.Unstructured //nolint:prealloc
   102  	for _, o := range f.objs {
   103  		u := unstructured.Unstructured{}
   104  		err := FakeScheme.Convert(o, &u, nil)
   105  		if err != nil {
   106  			return nil, err
   107  		}
   108  
   109  		// filter by namespace, if any
   110  		if len(namespaces) > 0 && u.GetNamespace() != "" {
   111  			inNamespaces := false
   112  			for _, namespace := range namespaces {
   113  				if u.GetNamespace() == namespace {
   114  					inNamespaces = true
   115  					break
   116  				}
   117  			}
   118  			if !inNamespaces {
   119  				continue
   120  			}
   121  		}
   122  
   123  		// filter by label, if any
   124  		haslabel := false
   125  		for l, v := range labels {
   126  			for ul, uv := range u.GetLabels() {
   127  				if l == ul && v == uv {
   128  					haslabel = true
   129  				}
   130  			}
   131  		}
   132  		if !haslabel {
   133  			continue
   134  		}
   135  
   136  		ret = append(ret, u)
   137  	}
   138  
   139  	return ret, nil
   140  }
   141  
   142  func (f *FakeProxy) GetContexts(_ string) ([]string, error) {
   143  	return nil, nil
   144  }
   145  
   146  func (f *FakeProxy) GetResourceNames(_ context.Context, _, _ string, _ []client.ListOption, _ string) ([]string, error) {
   147  	return nil, nil
   148  }
   149  
   150  func NewFakeProxy() *FakeProxy {
   151  	return &FakeProxy{
   152  		namespace: "default",
   153  	}
   154  }
   155  
   156  func (f *FakeProxy) WithObjs(objs ...client.Object) *FakeProxy {
   157  	f.objs = append(f.objs, objs...)
   158  	return f
   159  }
   160  
   161  func (f *FakeProxy) WithNamespace(n string) *FakeProxy {
   162  	f.namespace = n
   163  	return f
   164  }
   165  
   166  // WithProviderInventory can be used as a fast track for setting up test scenarios requiring an already initialized management cluster.
   167  // NB. this method adds an items to the Provider inventory, but it doesn't install the corresponding provider; if the
   168  // test case requires the actual provider to be installed, use the fake client to install both the provider
   169  // components and the corresponding inventory item.
   170  func (f *FakeProxy) WithProviderInventory(name string, providerType clusterctlv1.ProviderType, version, targetNamespace string) *FakeProxy {
   171  	f.objs = append(f.objs, &clusterctlv1.Provider{
   172  		TypeMeta: metav1.TypeMeta{
   173  			APIVersion: clusterctlv1.GroupVersion.String(),
   174  			Kind:       "Provider",
   175  		},
   176  		ObjectMeta: metav1.ObjectMeta{
   177  			ResourceVersion: "999",
   178  			Namespace:       targetNamespace,
   179  			Name:            clusterctlv1.ManifestLabel(name, providerType),
   180  			Labels: map[string]string{
   181  				clusterctlv1.ClusterctlLabel:     "",
   182  				clusterv1.ProviderNameLabel:      clusterctlv1.ManifestLabel(name, providerType),
   183  				clusterctlv1.ClusterctlCoreLabel: clusterctlv1.ClusterctlCoreLabelInventoryValue,
   184  			},
   185  		},
   186  		ProviderName: name,
   187  		Type:         string(providerType),
   188  		Version:      version,
   189  	})
   190  
   191  	return f
   192  }
   193  
   194  // WithFakeCAPISetup adds required objects in order to make kubeadm pass checks
   195  // ensuring that management cluster has a proper release of Cluster API installed.
   196  // NOTE: When using the fake client it is not required to install CRDs, given that type information are
   197  // derived from the schema. However, CheckCAPIContract looks for CRDs to be installed, so this
   198  // helper provide a way to get around to this difference between fake client and a real API server.
   199  func (f *FakeProxy) WithFakeCAPISetup() *FakeProxy {
   200  	f.objs = append(f.objs, FakeCAPISetupObjects()...)
   201  
   202  	return f
   203  }
   204  
   205  func (f *FakeProxy) WithClusterAvailable(available bool) *FakeProxy {
   206  	f.available = ptr.To(available)
   207  	return f
   208  }
   209  
   210  // FakeCAPISetupObjects return required objects in order to make kubeadm pass checks
   211  // ensuring that management cluster has a proper release of Cluster API installed.
   212  func FakeCAPISetupObjects() []client.Object {
   213  	return []client.Object{
   214  		&apiextensionsv1.CustomResourceDefinition{
   215  			ObjectMeta: metav1.ObjectMeta{Name: "clusters.cluster.x-k8s.io"},
   216  			Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   217  				Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   218  					{
   219  						Name:    clusterv1.GroupVersion.Version, // Current Cluster API contract
   220  						Storage: true,
   221  					},
   222  				},
   223  			},
   224  		},
   225  	}
   226  }