k8s.io/kubernetes@v1.29.3/pkg/registry/core/node/storage/storage_test.go (about) 1 /* 2 Copyright 2015 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 storage 18 19 import ( 20 "fmt" 21 "testing" 22 23 "k8s.io/apimachinery/pkg/api/resource" 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 "k8s.io/apimachinery/pkg/fields" 26 "k8s.io/apimachinery/pkg/labels" 27 "k8s.io/apimachinery/pkg/runtime" 28 genericapirequest "k8s.io/apiserver/pkg/endpoints/request" 29 "k8s.io/apiserver/pkg/registry/generic" 30 genericregistrytest "k8s.io/apiserver/pkg/registry/generic/testing" 31 "k8s.io/apiserver/pkg/registry/rest" 32 etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing" 33 api "k8s.io/kubernetes/pkg/apis/core" 34 kubeletclient "k8s.io/kubernetes/pkg/kubelet/client" 35 "k8s.io/kubernetes/pkg/registry/registrytest" 36 ) 37 38 func newStorage(t *testing.T) (*REST, *etcd3testing.EtcdTestServer) { 39 etcdStorage, server := registrytest.NewEtcdStorage(t, "") 40 restOptions := generic.RESTOptions{ 41 StorageConfig: etcdStorage, 42 Decorator: generic.UndecoratedStorage, 43 DeleteCollectionWorkers: 1, 44 ResourcePrefix: "nodes", 45 } 46 storage, err := NewStorage(restOptions, kubeletclient.KubeletClientConfig{ 47 Port: 10250, 48 PreferredAddressTypes: []string{string(api.NodeInternalIP)}, 49 }, nil) 50 if err != nil { 51 t.Fatal(err) 52 } 53 return storage.Node, server 54 } 55 56 type tweak func(*api.Node) 57 58 func newNode(name string, tweaks ...tweak) *api.Node { 59 node := &api.Node{ 60 ObjectMeta: metav1.ObjectMeta{ 61 Name: name, 62 Labels: map[string]string{ 63 "name": name, 64 }, 65 }, 66 Status: api.NodeStatus{ 67 Capacity: api.ResourceList{ 68 api.ResourceCPU: resource.MustParse("10"), 69 api.ResourceMemory: resource.MustParse("0"), 70 }, 71 }, 72 } 73 74 for _, tweak := range tweaks { 75 tweak(node) 76 } 77 78 return node 79 } 80 81 func setNodeIPAddress(addr string) tweak { 82 return func(node *api.Node) { 83 node.Status.Addresses = []api.NodeAddress{ 84 {Type: api.NodeInternalIP, Address: addr}, 85 } 86 } 87 } 88 89 func setNodeDaemonEndpoint(port int32) tweak { 90 return func(node *api.Node) { 91 node.Status.DaemonEndpoints = api.NodeDaemonEndpoints{ 92 KubeletEndpoint: api.DaemonEndpoint{ 93 Port: port, 94 }, 95 } 96 } 97 } 98 99 func TestCreate(t *testing.T) { 100 storage, server := newStorage(t) 101 defer server.Terminate(t) 102 defer storage.Store.DestroyFunc() 103 test := genericregistrytest.New(t, storage.Store).ClusterScope() 104 test.TestCreate( 105 // valid 106 newNode("foo"), 107 // invalid 108 newNode("_-a123-a_"), 109 ) 110 } 111 112 func TestUpdate(t *testing.T) { 113 storage, server := newStorage(t) 114 defer server.Terminate(t) 115 defer storage.Store.DestroyFunc() 116 test := genericregistrytest.New(t, storage.Store).ClusterScope() 117 test.TestUpdate( 118 // valid 119 newNode("foo"), 120 // updateFunc 121 func(obj runtime.Object) runtime.Object { 122 object := obj.(*api.Node) 123 object.Spec.Unschedulable = !object.Spec.Unschedulable 124 return object 125 }, 126 ) 127 } 128 129 func TestDelete(t *testing.T) { 130 storage, server := newStorage(t) 131 defer server.Terminate(t) 132 defer storage.Store.DestroyFunc() 133 test := genericregistrytest.New(t, storage.Store).ClusterScope() 134 test.TestDelete(newNode("foo")) 135 } 136 137 func TestGet(t *testing.T) { 138 storage, server := newStorage(t) 139 defer server.Terminate(t) 140 defer storage.Store.DestroyFunc() 141 test := genericregistrytest.New(t, storage.Store).ClusterScope() 142 test.TestGet(newNode("foo")) 143 } 144 145 func TestList(t *testing.T) { 146 storage, server := newStorage(t) 147 defer server.Terminate(t) 148 defer storage.Store.DestroyFunc() 149 test := genericregistrytest.New(t, storage.Store).ClusterScope() 150 test.TestList(newNode("foo")) 151 } 152 153 func TestWatch(t *testing.T) { 154 storage, server := newStorage(t) 155 defer server.Terminate(t) 156 defer storage.Store.DestroyFunc() 157 test := genericregistrytest.New(t, storage.Store).ClusterScope() 158 test.TestWatch( 159 newNode("foo"), 160 // matching labels 161 []labels.Set{ 162 {"name": "foo"}, 163 }, 164 // not matching labels 165 []labels.Set{ 166 {"name": "bar"}, 167 {"foo": "bar"}, 168 }, 169 // matching fields 170 []fields.Set{ 171 {"metadata.name": "foo"}, 172 }, 173 // not matching fields 174 []fields.Set{ 175 {"metadata.name": "bar"}, 176 }, 177 ) 178 } 179 180 func TestShortNames(t *testing.T) { 181 storage, server := newStorage(t) 182 defer server.Terminate(t) 183 defer storage.Store.DestroyFunc() 184 expected := []string{"no"} 185 registrytest.AssertShortNames(t, storage, expected) 186 } 187 188 func TestResourceLocation(t *testing.T) { 189 type testCase struct { 190 name string 191 node *api.Node 192 query string 193 host string 194 err bool 195 } 196 197 testCases := []testCase{{ 198 name: "proxyable hostname with default port", 199 node: newNode("node0", setNodeIPAddress("10.0.0.1")), 200 query: "node0", 201 host: "10.0.0.1:10250", 202 }, { 203 name: "proxyable hostname with kubelet port in query", 204 node: newNode("node0", setNodeIPAddress("10.0.0.1")), 205 query: "node0:5000", 206 host: "10.0.0.1:5000", 207 }, { 208 name: "proxyable hostname with kubelet port in status", 209 node: newNode("node0", setNodeIPAddress("10.0.0.1"), setNodeDaemonEndpoint(5000)), 210 query: "node0", 211 host: "10.0.0.1:5000", 212 }, { 213 name: "non-proxyable hostname with default port", 214 node: newNode("node0", setNodeIPAddress("127.0.0.1")), 215 query: "node0", 216 host: "", 217 err: true, 218 }, { 219 name: "non-proxyable hostname with kubelet port in query", 220 node: newNode("node0", setNodeIPAddress("127.0.0.1")), 221 query: "node0:5000", 222 host: "", 223 err: true, 224 }, { 225 name: "non-proxyable hostname with kubelet port in status", 226 node: newNode("node0", setNodeIPAddress("127.0.0.1"), setNodeDaemonEndpoint(443)), 227 query: "node0", 228 host: "", 229 err: true, 230 }} 231 232 for _, testCase := range testCases { 233 t.Run(testCase.name, func(t *testing.T) { 234 storage, server := newStorage(t) 235 defer server.Terminate(t) 236 defer storage.Store.DestroyFunc() 237 238 ctx := genericapirequest.WithNamespace(genericapirequest.NewDefaultContext(), fmt.Sprintf("namespace-%s", testCase.name)) 239 key, _ := storage.KeyFunc(ctx, testCase.node.Name) 240 if err := storage.Storage.Create(ctx, key, testCase.node, nil, 0, false); err != nil { 241 t.Fatalf("unexpected error: %v", err) 242 } 243 244 redirector := rest.Redirector(storage) 245 location, _, err := redirector.ResourceLocation(ctx, testCase.query) 246 247 if err != nil { 248 if !testCase.err { 249 t.Fatalf("Unexpected error: %v", err) 250 } 251 return 252 } else if testCase.err { 253 t.Fatalf("Expected error but got none") 254 } 255 256 if location == nil { 257 t.Errorf("Unexpected nil resource location: %v", location) 258 } 259 260 if location.Host != testCase.host { 261 t.Errorf("Unexpected host: expected %v, but got %v", testCase.host, location.Host) 262 } 263 }) 264 } 265 }