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 }