k8s.io/kubernetes@v1.29.3/test/integration/etcd/data.go (about) 1 /* 2 Copyright 2018 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 etcd 18 19 import ( 20 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" 21 "k8s.io/apiextensions-apiserver/test/integration/fixtures" 22 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 "k8s.io/apimachinery/pkg/runtime/schema" 24 25 "k8s.io/kubernetes/test/utils/image" 26 ) 27 28 // GetEtcdStorageData returns etcd data for all persisted objects. 29 // It is exported so that it can be reused across multiple tests. 30 // It returns a new map on every invocation to prevent different tests from mutating shared state. 31 func GetEtcdStorageData() map[schema.GroupVersionResource]StorageData { 32 return GetEtcdStorageDataForNamespace("etcdstoragepathtestnamespace") 33 } 34 35 // GetEtcdStorageDataForNamespace returns etcd data for all persisted objects. 36 // It is exported so that it can be reused across multiple tests. 37 // It returns a new map on every invocation to prevent different tests from mutating shared state. 38 // Namespaced objects keys are computed for the specified namespace. 39 func GetEtcdStorageDataForNamespace(namespace string) map[schema.GroupVersionResource]StorageData { 40 image := image.GetE2EImage(image.BusyBox) 41 etcdStorageData := map[schema.GroupVersionResource]StorageData{ 42 // k8s.io/kubernetes/pkg/api/v1 43 gvr("", "v1", "configmaps"): { 44 Stub: `{"data": {"foo": "bar"}, "metadata": {"name": "cm1"}}`, 45 ExpectedEtcdPath: "/registry/configmaps/" + namespace + "/cm1", 46 }, 47 gvr("", "v1", "services"): { 48 Stub: `{"metadata": {"name": "service1"}, "spec": {"type": "LoadBalancer", "ports": [{"port": 10000, "targetPort": 11000}], "selector": {"test": "data"}}}`, 49 ExpectedEtcdPath: "/registry/services/specs/" + namespace + "/service1", 50 }, 51 gvr("", "v1", "podtemplates"): { 52 Stub: `{"metadata": {"name": "pt1name"}, "template": {"metadata": {"labels": {"pt": "01"}}, "spec": {"containers": [{"image": "` + image + `", "name": "container9"}]}}}`, 53 ExpectedEtcdPath: "/registry/podtemplates/" + namespace + "/pt1name", 54 }, 55 gvr("", "v1", "pods"): { 56 Stub: `{"metadata": {"name": "pod1"}, "spec": {"containers": [{"image": "` + image + `", "name": "container7", "resources": {"limits": {"cpu": "1M"}, "requests": {"cpu": "1M"}}}]}}`, 57 ExpectedEtcdPath: "/registry/pods/" + namespace + "/pod1", 58 }, 59 gvr("", "v1", "endpoints"): { 60 Stub: `{"metadata": {"name": "ep1name"}, "subsets": [{"addresses": [{"hostname": "bar-001", "ip": "192.168.3.1"}], "ports": [{"port": 8000}]}]}`, 61 ExpectedEtcdPath: "/registry/services/endpoints/" + namespace + "/ep1name", 62 }, 63 gvr("", "v1", "resourcequotas"): { 64 Stub: `{"metadata": {"name": "rq1name"}, "spec": {"hard": {"cpu": "5M"}}}`, 65 ExpectedEtcdPath: "/registry/resourcequotas/" + namespace + "/rq1name", 66 }, 67 gvr("", "v1", "limitranges"): { 68 Stub: `{"metadata": {"name": "lr1name"}, "spec": {"limits": [{"type": "Pod"}]}}`, 69 ExpectedEtcdPath: "/registry/limitranges/" + namespace + "/lr1name", 70 }, 71 gvr("", "v1", "namespaces"): { 72 Stub: `{"metadata": {"name": "namespace1"}, "spec": {"finalizers": ["kubernetes"]}}`, 73 ExpectedEtcdPath: "/registry/namespaces/namespace1", 74 }, 75 gvr("", "v1", "nodes"): { 76 Stub: `{"metadata": {"name": "node1"}, "spec": {"unschedulable": true}}`, 77 ExpectedEtcdPath: "/registry/minions/node1", 78 }, 79 gvr("", "v1", "persistentvolumes"): { 80 Stub: `{"metadata": {"name": "pv1name"}, "spec": {"accessModes": ["ReadWriteOnce"], "capacity": {"storage": "3M"}, "hostPath": {"path": "/tmp/test/"}}}`, 81 ExpectedEtcdPath: "/registry/persistentvolumes/pv1name", 82 }, 83 gvr("", "v1", "events"): { 84 Stub: `{"involvedObject": {"namespace": "` + namespace + `"}, "message": "some data here", "metadata": {"name": "event1"}}`, 85 ExpectedEtcdPath: "/registry/events/" + namespace + "/event1", 86 }, 87 gvr("", "v1", "persistentvolumeclaims"): { 88 Stub: `{"metadata": {"name": "pvc1"}, "spec": {"accessModes": ["ReadWriteOnce"], "resources": {"limits": {"storage": "1M"}, "requests": {"storage": "2M"}}, "selector": {"matchLabels": {"pvc": "stuff"}}}}`, 89 ExpectedEtcdPath: "/registry/persistentvolumeclaims/" + namespace + "/pvc1", 90 }, 91 gvr("", "v1", "serviceaccounts"): { 92 Stub: `{"metadata": {"name": "sa1name"}, "secrets": [{"name": "secret00"}]}`, 93 ExpectedEtcdPath: "/registry/serviceaccounts/" + namespace + "/sa1name", 94 }, 95 gvr("", "v1", "secrets"): { 96 Stub: `{"data": {"key": "ZGF0YSBmaWxl"}, "metadata": {"name": "secret1"}}`, 97 ExpectedEtcdPath: "/registry/secrets/" + namespace + "/secret1", 98 }, 99 gvr("", "v1", "replicationcontrollers"): { 100 Stub: `{"metadata": {"name": "rc1"}, "spec": {"selector": {"new": "stuff"}, "template": {"metadata": {"labels": {"new": "stuff"}}, "spec": {"containers": [{"image": "` + image + `", "name": "container8"}]}}}}`, 101 ExpectedEtcdPath: "/registry/controllers/" + namespace + "/rc1", 102 }, 103 // -- 104 105 // k8s.io/kubernetes/pkg/apis/apps/v1 106 gvr("apps", "v1", "daemonsets"): { 107 Stub: `{"metadata": {"name": "ds6"}, "spec": {"selector": {"matchLabels": {"a": "b"}}, "template": {"metadata": {"labels": {"a": "b"}}, "spec": {"containers": [{"image": "` + image + `", "name": "container6"}]}}}}`, 108 ExpectedEtcdPath: "/registry/daemonsets/" + namespace + "/ds6", 109 }, 110 gvr("apps", "v1", "deployments"): { 111 Stub: `{"metadata": {"name": "deployment4"}, "spec": {"selector": {"matchLabels": {"f": "z"}}, "template": {"metadata": {"labels": {"f": "z"}}, "spec": {"containers": [{"image": "` + image + `", "name": "container6"}]}}}}`, 112 ExpectedEtcdPath: "/registry/deployments/" + namespace + "/deployment4", 113 }, 114 gvr("apps", "v1", "statefulsets"): { 115 Stub: `{"metadata": {"name": "ss3"}, "spec": {"selector": {"matchLabels": {"a": "b"}}, "template": {"metadata": {"labels": {"a": "b"}}}}}`, 116 ExpectedEtcdPath: "/registry/statefulsets/" + namespace + "/ss3", 117 }, 118 gvr("apps", "v1", "replicasets"): { 119 Stub: `{"metadata": {"name": "rs3"}, "spec": {"selector": {"matchLabels": {"g": "h"}}, "template": {"metadata": {"labels": {"g": "h"}}, "spec": {"containers": [{"image": "` + image + `", "name": "container4"}]}}}}`, 120 ExpectedEtcdPath: "/registry/replicasets/" + namespace + "/rs3", 121 }, 122 gvr("apps", "v1", "controllerrevisions"): { 123 Stub: `{"metadata":{"name":"crs3"},"data":{"name":"abc","namespace":"default","creationTimestamp":null,"Spec":{"Replicas":0,"Selector":{"matchLabels":{"foo":"bar"}},"Template":{"creationTimestamp":null,"labels":{"foo":"bar"},"Spec":{"Volumes":null,"InitContainers":null,"Containers":null,"RestartPolicy":"Always","TerminationGracePeriodSeconds":null,"ActiveDeadlineSeconds":null,"DNSPolicy":"ClusterFirst","NodeSelector":null,"ServiceAccountName":"","AutomountServiceAccountToken":null,"NodeName":"","SecurityContext":null,"ImagePullSecrets":null,"Hostname":"","Subdomain":"","Affinity":null,"SchedulerName":"","Tolerations":null,"HostAliases":null}},"VolumeClaimTemplates":null,"ServiceName":""},"Status":{"ObservedGeneration":null,"Replicas":0}},"revision":0}`, 124 ExpectedEtcdPath: "/registry/controllerrevisions/" + namespace + "/crs3", 125 }, 126 // -- 127 128 // k8s.io/kubernetes/pkg/apis/autoscaling/v1 129 gvr("autoscaling", "v1", "horizontalpodautoscalers"): { 130 Stub: `{"metadata": {"name": "hpa2"}, "spec": {"maxReplicas": 3, "scaleTargetRef": {"kind": "something", "name": "cross"}}}`, 131 ExpectedEtcdPath: "/registry/horizontalpodautoscalers/" + namespace + "/hpa2", 132 ExpectedGVK: gvkP("autoscaling", "v2", "HorizontalPodAutoscaler"), 133 }, 134 // -- 135 136 // k8s.io/kubernetes/pkg/apis/autoscaling/v2 137 gvr("autoscaling", "v2", "horizontalpodautoscalers"): { 138 Stub: `{"metadata": {"name": "hpa4"}, "spec": {"maxReplicas": 3, "scaleTargetRef": {"kind": "something", "name": "cross"}}}`, 139 ExpectedEtcdPath: "/registry/horizontalpodautoscalers/" + namespace + "/hpa4", 140 }, 141 // -- 142 143 // k8s.io/kubernetes/pkg/apis/batch/v1 144 gvr("batch", "v1", "jobs"): { 145 Stub: `{"metadata": {"name": "job1"}, "spec": {"manualSelector": true, "selector": {"matchLabels": {"controller-uid": "uid1"}}, "template": {"metadata": {"labels": {"controller-uid": "uid1"}}, "spec": {"containers": [{"image": "` + image + `", "name": "container1"}], "dnsPolicy": "ClusterFirst", "restartPolicy": "Never"}}}}`, 146 ExpectedEtcdPath: "/registry/jobs/" + namespace + "/job1", 147 }, 148 gvr("batch", "v1", "cronjobs"): { 149 Stub: `{"metadata": {"name": "cjv1"}, "spec": {"jobTemplate": {"spec": {"template": {"metadata": {"labels": {"controller-uid": "uid0"}}, "spec": {"containers": [{"image": "` + image + `", "name": "container0"}], "dnsPolicy": "ClusterFirst", "restartPolicy": "Never"}}}}, "schedule": "* * * * *"}}`, 150 ExpectedEtcdPath: "/registry/cronjobs/" + namespace + "/cjv1", 151 }, 152 // -- 153 154 // k8s.io/kubernetes/pkg/apis/certificates/v1 155 gvr("certificates.k8s.io", "v1", "certificatesigningrequests"): { 156 Stub: `{"metadata": {"name": "csr2"}, "spec": {"signerName":"example.com/signer", "usages":["any"], "request": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQnlqQ0NBVE1DQVFBd2dZa3hDekFKQmdOVkJBWVRBbFZUTVJNd0VRWURWUVFJRXdwRFlXeHBabTl5Ym1saApNUll3RkFZRFZRUUhFdzFOYjNWdWRHRnBiaUJXYVdWM01STXdFUVlEVlFRS0V3cEhiMjluYkdVZ1NXNWpNUjh3CkhRWURWUVFMRXhaSmJtWnZjbTFoZEdsdmJpQlVaV05vYm05c2IyZDVNUmN3RlFZRFZRUURFdzUzZDNjdVoyOXYKWjJ4bExtTnZiVENCbnpBTkJna3Foa2lHOXcwQkFRRUZBQU9CalFBd2dZa0NnWUVBcFp0WUpDSEo0VnBWWEhmVgpJbHN0UVRsTzRxQzAzaGpYK1prUHl2ZFlkMVE0K3FiQWVUd1htQ1VLWUhUaFZSZDVhWFNxbFB6eUlCd2llTVpyCldGbFJRZGRaMUl6WEFsVlJEV3dBbzYwS2VjcWVBWG5uVUsrNWZYb1RJL1VnV3NocmU4dEoreC9UTUhhUUtSL0oKY0lXUGhxYVFoc0p1elpidkFkR0E4MEJMeGRNQ0F3RUFBYUFBTUEwR0NTcUdTSWIzRFFFQkJRVUFBNEdCQUlobAo0UHZGcStlN2lwQVJnSTVaTStHWng2bXBDejQ0RFRvMEprd2ZSRGYrQnRyc2FDMHE2OGVUZjJYaFlPc3E0ZmtIClEwdUEwYVZvZzNmNWlKeENhM0hwNWd4YkpRNnpWNmtKMFRFc3VhYU9oRWtvOXNkcENvUE9uUkJtMmkvWFJEMkQKNmlOaDhmOHowU2hHc0ZxakRnRkh5RjNvK2xVeWorVUM2SDFRVzdibgotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0="}}`, 157 ExpectedEtcdPath: "/registry/certificatesigningrequests/csr2", 158 }, 159 // -- 160 161 // k8s.io/kubernetes/pkg/apis/certificates/v1alpha1 162 gvr("certificates.k8s.io", "v1alpha1", "clustertrustbundles"): { 163 Stub: `{"metadata": {"name": "example.com:signer:abc"}, "spec": {"signerName":"example.com/signer", "trustBundle": "-----BEGIN CERTIFICATE-----\nMIIBBDCBt6ADAgECAgEAMAUGAytlcDAQMQ4wDAYDVQQDEwVyb290MTAiGA8wMDAx\nMDEwMTAwMDAwMFoYDzAwMDEwMTAxMDAwMDAwWjAQMQ4wDAYDVQQDEwVyb290MTAq\nMAUGAytlcAMhAF2MoFeGa97gK2NGT1h6p1/a1GlMXAXbcjI/OShyIobPozIwMDAP\nBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTWDdK2CNQiHqRjPaAWYPPtIykQgjAF\nBgMrZXADQQCtom9WGl7m2SAa4tXM9Soo/mbInBsRhn187BMoqTAHInHchKup5/3y\nl1tYJSZZsEXnXrCvw2qLCBNif6+2YYgE\n-----END CERTIFICATE-----\n"}}`, 164 ExpectedEtcdPath: "/registry/clustertrustbundles/example.com:signer:abc", 165 }, 166 // -- 167 168 // k8s.io/kubernetes/pkg/apis/coordination/v1 169 gvr("coordination.k8s.io", "v1", "leases"): { 170 Stub: `{"metadata": {"name": "leasev1"}, "spec": {"holderIdentity": "holder", "leaseDurationSeconds": 5}}`, 171 ExpectedEtcdPath: "/registry/leases/" + namespace + "/leasev1", 172 }, 173 // -- 174 175 // k8s.io/kubernetes/pkg/apis/discovery/v1 176 gvr("discovery.k8s.io", "v1", "endpointslices"): { 177 Stub: `{"metadata": {"name": "slicev1"}, "addressType": "IPv4", "protocol": "TCP", "ports": [], "endpoints": []}`, 178 ExpectedEtcdPath: "/registry/endpointslices/" + namespace + "/slicev1", 179 ExpectedGVK: gvkP("discovery.k8s.io", "v1beta1", "EndpointSlice"), 180 }, 181 // -- 182 183 // k8s.io/kubernetes/pkg/apis/events/v1 184 gvr("events.k8s.io", "v1", "events"): { 185 Stub: `{"metadata": {"name": "event3"}, "regarding": {"namespace": "` + namespace + `"}, "note": "some data here", "eventTime": "2017-08-09T15:04:05.000000Z", "reportingInstance": "node-xyz", "reportingController": "k8s.io/my-controller", "action": "DidNothing", "reason": "Laziness", "type": "Normal"}`, 186 ExpectedEtcdPath: "/registry/events/" + namespace + "/event3", 187 ExpectedGVK: gvkP("", "v1", "Event"), 188 }, 189 // -- 190 191 // k8s.io/kubernetes/pkg/apis/networking/v1 192 gvr("networking.k8s.io", "v1", "ingresses"): { 193 Stub: `{"metadata": {"name": "ingress3"}, "spec": {"defaultBackend": {"service":{"name":"service", "port":{"number": 5000}}}}}`, 194 ExpectedEtcdPath: "/registry/ingress/" + namespace + "/ingress3", 195 }, 196 gvr("networking.k8s.io", "v1", "ingressclasses"): { 197 Stub: `{"metadata": {"name": "ingressclass3"}, "spec": {"controller": "example.com/controller"}}`, 198 ExpectedEtcdPath: "/registry/ingressclasses/ingressclass3", 199 }, 200 gvr("networking.k8s.io", "v1", "networkpolicies"): { 201 Stub: `{"metadata": {"name": "np2"}, "spec": {"podSelector": {"matchLabels": {"e": "f"}}}}`, 202 ExpectedEtcdPath: "/registry/networkpolicies/" + namespace + "/np2", 203 }, 204 // -- 205 206 // k8s.io/kubernetes/pkg/apis/networking/v1alpha1 207 gvr("networking.k8s.io", "v1alpha1", "ipaddresses"): { 208 Stub: `{"metadata": {"name": "192.168.1.2"}, "spec": {"parentRef": {"resource": "services","name": "test", "namespace": "ns"}}}`, 209 ExpectedEtcdPath: "/registry/ipaddresses/192.168.1.2", 210 }, 211 // -- 212 213 // k8s.io/kubernetes/pkg/apis/networking/v1alpha1 214 gvr("networking.k8s.io", "v1alpha1", "servicecidrs"): { 215 Stub: `{"metadata": {"name": "range1"}, "spec": {"cidrs": ["192.168.0.0/16","fd00:1::/120"]}}`, 216 ExpectedEtcdPath: "/registry/servicecidrs/range1", 217 }, 218 // -- 219 220 // k8s.io/kubernetes/pkg/apis/policy/v1 221 gvr("policy", "v1", "poddisruptionbudgets"): { 222 Stub: `{"metadata": {"name": "pdbv1"}, "spec": {"selector": {"matchLabels": {"anokkey": "anokvalue"}}}}`, 223 ExpectedEtcdPath: "/registry/poddisruptionbudgets/" + namespace + "/pdbv1", 224 }, 225 // -- 226 227 // k8s.io/kubernetes/pkg/apis/storage/v1alpha1 228 gvr("storage.k8s.io", "v1alpha1", "csistoragecapacities"): { 229 Stub: `{"metadata": {"name": "csc-12345-1"}, "storageClassName": "sc1"}`, 230 ExpectedEtcdPath: "/registry/csistoragecapacities/" + namespace + "/csc-12345-1", 231 ExpectedGVK: gvkP("storage.k8s.io", "v1", "CSIStorageCapacity"), 232 }, 233 // -- 234 235 // k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta1 236 gvr("flowcontrol.apiserver.k8s.io", "v1beta1", "flowschemas"): { 237 Stub: `{"metadata": {"name": "va2"}, "spec": {"priorityLevelConfiguration": {"name": "name1"}}}`, 238 ExpectedEtcdPath: "/registry/flowschemas/va2", 239 ExpectedGVK: gvkP("flowcontrol.apiserver.k8s.io", "v1beta3", "FlowSchema"), 240 }, 241 // -- 242 243 // k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta1 244 gvr("flowcontrol.apiserver.k8s.io", "v1beta1", "prioritylevelconfigurations"): { 245 Stub: `{"metadata": {"name": "conf2"}, "spec": {"type": "Limited", "limited": {"assuredConcurrencyShares":3, "limitResponse": {"type": "Reject"}}}}`, 246 ExpectedEtcdPath: "/registry/prioritylevelconfigurations/conf2", 247 ExpectedGVK: gvkP("flowcontrol.apiserver.k8s.io", "v1beta3", "PriorityLevelConfiguration"), 248 }, 249 // -- 250 251 // k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta2 252 gvr("flowcontrol.apiserver.k8s.io", "v1beta2", "flowschemas"): { 253 Stub: `{"metadata": {"name": "fs-1"}, "spec": {"priorityLevelConfiguration": {"name": "name1"}}}`, 254 ExpectedEtcdPath: "/registry/flowschemas/fs-1", 255 ExpectedGVK: gvkP("flowcontrol.apiserver.k8s.io", "v1beta3", "FlowSchema"), 256 }, 257 // -- 258 259 // k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta2 260 gvr("flowcontrol.apiserver.k8s.io", "v1beta2", "prioritylevelconfigurations"): { 261 Stub: `{"metadata": {"name": "conf3"}, "spec": {"type": "Limited", "limited": {"assuredConcurrencyShares":3, "limitResponse": {"type": "Reject"}}}}`, 262 ExpectedEtcdPath: "/registry/prioritylevelconfigurations/conf3", 263 ExpectedGVK: gvkP("flowcontrol.apiserver.k8s.io", "v1beta3", "PriorityLevelConfiguration"), 264 }, 265 // -- 266 267 // k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta3 268 gvr("flowcontrol.apiserver.k8s.io", "v1beta3", "flowschemas"): { 269 Stub: `{"metadata": {"name": "fs-2"}, "spec": {"priorityLevelConfiguration": {"name": "name1"}}}`, 270 ExpectedEtcdPath: "/registry/flowschemas/fs-2", 271 }, 272 // -- 273 274 // k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta3 275 gvr("flowcontrol.apiserver.k8s.io", "v1beta3", "prioritylevelconfigurations"): { 276 Stub: `{"metadata": {"name": "conf4"}, "spec": {"type": "Limited", "limited": {"nominalConcurrencyShares":3, "limitResponse": {"type": "Reject"}}}}`, 277 ExpectedEtcdPath: "/registry/prioritylevelconfigurations/conf4", 278 }, 279 // -- 280 281 // k8s.io/kubernetes/pkg/apis/flowcontrol/v1 282 gvr("flowcontrol.apiserver.k8s.io", "v1", "flowschemas"): { 283 Stub: `{"metadata": {"name": "fs-3"}, "spec": {"priorityLevelConfiguration": {"name": "name1"}}}`, 284 ExpectedEtcdPath: "/registry/flowschemas/fs-3", 285 ExpectedGVK: gvkP("flowcontrol.apiserver.k8s.io", "v1beta3", "FlowSchema"), 286 }, 287 // -- 288 289 // k8s.io/kubernetes/pkg/apis/flowcontrol/v1 290 gvr("flowcontrol.apiserver.k8s.io", "v1", "prioritylevelconfigurations"): { 291 Stub: `{"metadata": {"name": "conf5"}, "spec": {"type": "Limited", "limited": {"nominalConcurrencyShares":3, "limitResponse": {"type": "Reject"}}}}`, 292 ExpectedEtcdPath: "/registry/prioritylevelconfigurations/conf5", 293 ExpectedGVK: gvkP("flowcontrol.apiserver.k8s.io", "v1beta3", "PriorityLevelConfiguration"), 294 }, 295 // -- 296 297 // k8s.io/kubernetes/pkg/apis/storage/v1 298 gvr("storage.k8s.io", "v1", "volumeattachments"): { 299 Stub: `{"metadata": {"name": "va3"}, "spec": {"attacher": "gce", "nodeName": "localhost", "source": {"persistentVolumeName": "pv3"}}}`, 300 ExpectedEtcdPath: "/registry/volumeattachments/va3", 301 }, 302 // -- 303 304 // k8s.io/kubernetes/pkg/apis/storage/v1alpha1 305 gvr("storage.k8s.io", "v1alpha1", "volumeattributesclasses"): { 306 Stub: `{"metadata": {"name": "vac1"}, "driverName": "example.com/driver", "parameters": {"foo": "bar"}}`, 307 ExpectedEtcdPath: "/registry/volumeattributesclasses/vac1", 308 }, 309 // -- 310 311 // k8s.io/kubernetes/pkg/apis/storage/v1beta1 312 gvr("storage.k8s.io", "v1beta1", "csistoragecapacities"): { 313 Stub: `{"metadata": {"name": "csc-12345-2"}, "storageClassName": "sc1"}`, 314 ExpectedEtcdPath: "/registry/csistoragecapacities/" + namespace + "/csc-12345-2", 315 ExpectedGVK: gvkP("storage.k8s.io", "v1", "CSIStorageCapacity"), 316 }, 317 // -- 318 319 // k8s.io/kubernetes/pkg/apis/storage/v1 320 gvr("storage.k8s.io", "v1", "storageclasses"): { 321 Stub: `{"metadata": {"name": "sc2"}, "provisioner": "aws"}`, 322 ExpectedEtcdPath: "/registry/storageclasses/sc2", 323 }, 324 gvr("storage.k8s.io", "v1", "csistoragecapacities"): { 325 Stub: `{"metadata": {"name": "csc-12345-3"}, "storageClassName": "sc1"}`, 326 ExpectedEtcdPath: "/registry/csistoragecapacities/" + namespace + "/csc-12345-3", 327 }, 328 // -- 329 330 // k8s.io/kubernetes/pkg/apis/rbac/v1 331 gvr("rbac.authorization.k8s.io", "v1", "roles"): { 332 Stub: `{"metadata": {"name": "role3"}, "rules": [{"apiGroups": ["v1"], "resources": ["events"], "verbs": ["watch"]}]}`, 333 ExpectedEtcdPath: "/registry/roles/" + namespace + "/role3", 334 }, 335 gvr("rbac.authorization.k8s.io", "v1", "clusterroles"): { 336 Stub: `{"metadata": {"name": "crole3"}, "rules": [{"nonResourceURLs": ["/version"], "verbs": ["get"]}]}`, 337 ExpectedEtcdPath: "/registry/clusterroles/crole3", 338 }, 339 gvr("rbac.authorization.k8s.io", "v1", "rolebindings"): { 340 Stub: `{"metadata": {"name": "roleb3"}, "roleRef": {"apiGroup": "rbac.authorization.k8s.io", "kind": "ClusterRole", "name": "somecr"}, "subjects": [{"apiVersion": "rbac.authorization.k8s.io/v1alpha1", "kind": "Group", "name": "system:authenticated"}]}`, 341 ExpectedEtcdPath: "/registry/rolebindings/" + namespace + "/roleb3", 342 }, 343 gvr("rbac.authorization.k8s.io", "v1", "clusterrolebindings"): { 344 Stub: `{"metadata": {"name": "croleb3"}, "roleRef": {"apiGroup": "rbac.authorization.k8s.io", "kind": "ClusterRole", "name": "somecr"}, "subjects": [{"apiVersion": "rbac.authorization.k8s.io/v1alpha1", "kind": "Group", "name": "system:authenticated"}]}`, 345 ExpectedEtcdPath: "/registry/clusterrolebindings/croleb3", 346 }, 347 // -- 348 349 // k8s.io/kubernetes/pkg/apis/admissionregistration/v1 350 gvr("admissionregistration.k8s.io", "v1", "validatingwebhookconfigurations"): { 351 Stub: `{"metadata":{"name":"hook2","creationTimestamp":null},"webhooks":[{"name":"externaladmissionhook.k8s.io","clientConfig":{"service":{"namespace":"ns","name":"n"},"caBundle":null},"rules":[{"operations":["CREATE"],"apiGroups":["group"],"apiVersions":["version"],"resources":["resource"]}],"failurePolicy":"Ignore","sideEffects":"None","admissionReviewVersions":["v1beta1"]}]}`, 352 ExpectedEtcdPath: "/registry/validatingwebhookconfigurations/hook2", 353 }, 354 gvr("admissionregistration.k8s.io", "v1", "mutatingwebhookconfigurations"): { 355 Stub: `{"metadata":{"name":"hook2","creationTimestamp":null},"webhooks":[{"name":"externaladmissionhook.k8s.io","clientConfig":{"service":{"namespace":"ns","name":"n"},"caBundle":null},"rules":[{"operations":["CREATE"],"apiGroups":["group"],"apiVersions":["version"],"resources":["resource"]}],"failurePolicy":"Ignore","sideEffects":"None","admissionReviewVersions":["v1beta1"]}]}`, 356 ExpectedEtcdPath: "/registry/mutatingwebhookconfigurations/hook2", 357 }, 358 // -- 359 360 // k8s.io/kubernetes/pkg/apis/admissionregistration/v1beta1 361 gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies"): { 362 Stub: `{"metadata":{"name":"vap1b1","creationTimestamp":null},"spec":{"paramKind":{"apiVersion":"test.example.com/v1","kind":"Example"},"matchConstraints":{"resourceRules": [{"resourceNames": ["fakeName"], "apiGroups":["apps"],"apiVersions":["v1"],"operations":["CREATE", "UPDATE"], "resources":["deployments"]}]},"validations":[{"expression":"object.spec.replicas <= params.maxReplicas","message":"Too many replicas"}]}}`, 363 ExpectedEtcdPath: "/registry/validatingadmissionpolicies/vap1b1", 364 }, 365 gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicybindings"): { 366 Stub: `{"metadata":{"name":"pb1b1","creationTimestamp":null},"spec":{"policyName":"replicalimit-policy.example.com","paramRef":{"name":"replica-limit-test.example.com","parameterNotFoundAction":"Deny"},"validationActions":["Deny"]}}`, 367 ExpectedEtcdPath: "/registry/validatingadmissionpolicybindings/pb1b1", 368 }, 369 // -- 370 371 // k8s.io/kubernetes/pkg/apis/admissionregistration/v1alpha1 372 gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies"): { 373 Stub: `{"metadata":{"name":"vap1","creationTimestamp":null},"spec":{"paramKind":{"apiVersion":"test.example.com/v1","kind":"Example"},"matchConstraints":{"resourceRules": [{"resourceNames": ["fakeName"], "apiGroups":["apps"],"apiVersions":["v1"],"operations":["CREATE", "UPDATE"], "resources":["deployments"]}]},"validations":[{"expression":"object.spec.replicas <= params.maxReplicas","message":"Too many replicas"}]}}`, 374 ExpectedEtcdPath: "/registry/validatingadmissionpolicies/vap1", 375 ExpectedGVK: gvkP("admissionregistration.k8s.io", "v1beta1", "ValidatingAdmissionPolicy"), 376 }, 377 gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicybindings"): { 378 Stub: `{"metadata":{"name":"pb1","creationTimestamp":null},"spec":{"policyName":"replicalimit-policy.example.com","paramRef":{"name":"replica-limit-test.example.com"},"validationActions":["Deny"]}}`, 379 ExpectedEtcdPath: "/registry/validatingadmissionpolicybindings/pb1", 380 ExpectedGVK: gvkP("admissionregistration.k8s.io", "v1beta1", "ValidatingAdmissionPolicyBinding"), 381 }, 382 // -- 383 384 // k8s.io/kubernetes/pkg/apis/scheduling/v1 385 gvr("scheduling.k8s.io", "v1", "priorityclasses"): { 386 Stub: `{"metadata":{"name":"pc3"},"Value":1000}`, 387 ExpectedEtcdPath: "/registry/priorityclasses/pc3", 388 }, 389 // -- 390 391 // k8s.io/kube-aggregator/pkg/apis/apiregistration/v1 392 // depends on aggregator using the same ungrouped RESTOptionsGetter as the kube apiserver, not SimpleRestOptionsFactory in aggregator.go 393 gvr("apiregistration.k8s.io", "v1", "apiservices"): { 394 Stub: `{"metadata": {"name": "as2.foo.com"}, "spec": {"group": "foo.com", "version": "as2", "groupPriorityMinimum":100, "versionPriority":10}}`, 395 ExpectedEtcdPath: "/registry/apiregistration.k8s.io/apiservices/as2.foo.com", 396 }, 397 // -- 398 399 // k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1 400 gvr("apiextensions.k8s.io", "v1", "customresourcedefinitions"): { 401 Stub: `{"metadata": {"name": "openshiftwebconsoleconfigs.webconsole2.operator.openshift.io"},"spec": {` + 402 `"scope": "Cluster","group": "webconsole2.operator.openshift.io",` + 403 `"versions": [{"name":"v1alpha1","storage":true,"served":true,"schema":{"openAPIV3Schema":{"type":"object"}}}],` + 404 `"names": {"kind": "OpenShiftWebConsoleConfig","plural": "openshiftwebconsoleconfigs","singular": "openshiftwebconsoleconfig"}}}`, 405 ExpectedEtcdPath: "/registry/apiextensions.k8s.io/customresourcedefinitions/openshiftwebconsoleconfigs.webconsole2.operator.openshift.io", 406 ExpectedGVK: gvkP("apiextensions.k8s.io", "v1beta1", "CustomResourceDefinition"), 407 }, 408 gvr("cr.bar.com", "v1", "foos"): { 409 Stub: `{"kind": "Foo", "apiVersion": "cr.bar.com/v1", "metadata": {"name": "cr1foo"}, "color": "blue"}`, // requires TypeMeta due to CRD scheme's UnstructuredObjectTyper 410 ExpectedEtcdPath: "/registry/cr.bar.com/foos/" + namespace + "/cr1foo", 411 }, 412 gvr("custom.fancy.com", "v2", "pants"): { 413 Stub: `{"kind": "Pant", "apiVersion": "custom.fancy.com/v2", "metadata": {"name": "cr2pant"}, "isFancy": true}`, // requires TypeMeta due to CRD scheme's UnstructuredObjectTyper 414 ExpectedEtcdPath: "/registry/custom.fancy.com/pants/cr2pant", 415 }, 416 gvr("awesome.bears.com", "v1", "pandas"): { 417 Stub: `{"kind": "Panda", "apiVersion": "awesome.bears.com/v1", "metadata": {"name": "cr3panda"}, "spec":{"replicas": 100}}`, // requires TypeMeta due to CRD scheme's UnstructuredObjectTyper 418 ExpectedEtcdPath: "/registry/awesome.bears.com/pandas/cr3panda", 419 }, 420 gvr("awesome.bears.com", "v3", "pandas"): { 421 Stub: `{"kind": "Panda", "apiVersion": "awesome.bears.com/v3", "metadata": {"name": "cr4panda"}, "spec":{"replicas": 300}}`, // requires TypeMeta due to CRD scheme's UnstructuredObjectTyper 422 ExpectedEtcdPath: "/registry/awesome.bears.com/pandas/cr4panda", 423 ExpectedGVK: gvkP("awesome.bears.com", "v1", "Panda"), 424 }, 425 gvr("random.numbers.com", "v1", "integers"): { 426 Stub: `{"kind": "Integer", "apiVersion": "random.numbers.com/v1", "metadata": {"name": "fortytwo"}, "value": 42, "garbage": "oiujnasdf"}`, // requires TypeMeta due to CRD scheme's UnstructuredObjectTyper 427 ExpectedEtcdPath: "/registry/random.numbers.com/integers/fortytwo", 428 }, 429 // -- 430 431 // k8s.io/kubernetes/pkg/apis/node/v1 432 gvr("node.k8s.io", "v1", "runtimeclasses"): { 433 Stub: `{"metadata": {"name": "rc3"}, "handler": "h3"}`, 434 ExpectedEtcdPath: "/registry/runtimeclasses/rc3", 435 }, 436 // -- 437 438 // k8s.io/kubernetes/pkg/apis/resource/v1alpha2 439 gvr("resource.k8s.io", "v1alpha2", "resourceclasses"): { 440 Stub: `{"metadata": {"name": "class1name"}, "driverName": "example.com"}`, 441 ExpectedEtcdPath: "/registry/resourceclasses/class1name", 442 }, 443 gvr("resource.k8s.io", "v1alpha2", "resourceclaims"): { 444 Stub: `{"metadata": {"name": "claim1name"}, "spec": {"resourceClassName": "class1name", "allocationMode": "WaitForFirstConsumer"}}`, 445 ExpectedEtcdPath: "/registry/resourceclaims/" + namespace + "/claim1name", 446 }, 447 gvr("resource.k8s.io", "v1alpha2", "resourceclaimtemplates"): { 448 Stub: `{"metadata": {"name": "claimtemplate1name"}, "spec": {"spec": {"resourceClassName": "class1name", "allocationMode": "WaitForFirstConsumer"}}}`, 449 ExpectedEtcdPath: "/registry/resourceclaimtemplates/" + namespace + "/claimtemplate1name", 450 }, 451 gvr("resource.k8s.io", "v1alpha2", "podschedulingcontexts"): { 452 Stub: `{"metadata": {"name": "pod1name"}, "spec": {"selectedNode": "node1name", "potentialNodes": ["node1name", "node2name"]}}`, 453 ExpectedEtcdPath: "/registry/podschedulingcontexts/" + namespace + "/pod1name", 454 }, 455 // -- 456 457 // k8s.io/apiserver/pkg/apis/apiserverinternal/v1alpha1 458 gvr("internal.apiserver.k8s.io", "v1alpha1", "storageversions"): { 459 Stub: `{"metadata":{"name":"sv1.test"},"spec":{}}`, 460 ExpectedEtcdPath: "/registry/storageversions/sv1.test", 461 }, 462 // -- 463 464 } 465 466 // add csinodes 467 // k8s.io/kubernetes/pkg/apis/storage/v1 468 etcdStorageData[gvr("storage.k8s.io", "v1", "csinodes")] = StorageData{ 469 Stub: `{"metadata": {"name": "csini2"}, "spec": {"drivers": [{"name": "test-driver", "nodeID": "localhost", "topologyKeys": ["company.com/zone1", "company.com/zone2"]}]}}`, 470 ExpectedEtcdPath: "/registry/csinodes/csini2", 471 } 472 473 // add csidrivers 474 // k8s.io/kubernetes/pkg/apis/storage/v1 475 etcdStorageData[gvr("storage.k8s.io", "v1", "csidrivers")] = StorageData{ 476 Stub: `{"metadata": {"name": "csid2"}, "spec": {"attachRequired": true, "podInfoOnMount": true}}`, 477 ExpectedEtcdPath: "/registry/csidrivers/csid2", 478 } 479 480 return etcdStorageData 481 } 482 483 // StorageData contains information required to create an object and verify its storage in etcd 484 // It must be paired with a specific resource 485 type StorageData struct { 486 Stub string // Valid JSON stub to use during create 487 Prerequisites []Prerequisite // Optional, ordered list of JSON objects to create before stub 488 ExpectedEtcdPath string // Expected location of object in etcd, do not use any variables, constants, etc to derive this value - always supply the full raw string 489 ExpectedGVK *schema.GroupVersionKind // The GVK that we expect this object to be stored as - leave this nil to use the default 490 } 491 492 // Prerequisite contains information required to create a resource (but not verify it) 493 type Prerequisite struct { 494 GvrData schema.GroupVersionResource 495 Stub string 496 } 497 498 // GetCustomResourceDefinitionData returns the resource definitions that back the custom resources 499 // included in GetEtcdStorageData. They should be created using CreateTestCRDs before running any tests. 500 // We can switch this to v1 CRDs based on transitive call site analysis. 501 // Call sites: 502 // 1. TestDedupOwnerReferences - beta doesn't matter 503 // 2. TestWebhookAdmissionWithWatchCache/TestWebhookAdmissionWithoutWatchCache - beta doesn't matter 504 // 3. TestApplyStatus - the version fields don't matter. Pruning isn't checked, just ownership. 505 // 4. TestDryRun - versions and pruning don't matter 506 // 5. TestStorageVersionBootstrap - versions and pruning don't matter. 507 // 6. TestEtcdStoragePath - beta doesn't matter 508 // 7. TestCrossGroupStorage - beta doesn't matter 509 // 8. TestOverlappingCustomResourceCustomResourceDefinition - beta doesn't matter 510 // 9. TestOverlappingCustomResourceAPIService - beta doesn't matter 511 func GetCustomResourceDefinitionData() []*apiextensionsv1.CustomResourceDefinition { 512 return []*apiextensionsv1.CustomResourceDefinition{ 513 // namespaced 514 { 515 ObjectMeta: metav1.ObjectMeta{ 516 Name: "foos.cr.bar.com", 517 }, 518 Spec: apiextensionsv1.CustomResourceDefinitionSpec{ 519 Group: "cr.bar.com", 520 Scope: apiextensionsv1.NamespaceScoped, 521 Names: apiextensionsv1.CustomResourceDefinitionNames{ 522 Plural: "foos", 523 Kind: "Foo", 524 }, 525 Versions: []apiextensionsv1.CustomResourceDefinitionVersion{ 526 { 527 Name: "v1", 528 Served: true, 529 Storage: true, 530 Schema: fixtures.AllowAllSchema(), 531 }, 532 }, 533 }, 534 }, 535 // cluster scoped 536 { 537 ObjectMeta: metav1.ObjectMeta{ 538 Name: "pants.custom.fancy.com", 539 }, 540 Spec: apiextensionsv1.CustomResourceDefinitionSpec{ 541 Group: "custom.fancy.com", 542 Scope: apiextensionsv1.ClusterScoped, 543 Names: apiextensionsv1.CustomResourceDefinitionNames{ 544 Plural: "pants", 545 Kind: "Pant", 546 }, 547 Versions: []apiextensionsv1.CustomResourceDefinitionVersion{ 548 { 549 Name: "v2", 550 Served: true, 551 Storage: true, 552 Schema: fixtures.AllowAllSchema(), 553 }, 554 }, 555 }, 556 }, 557 // cluster scoped with legacy version field and pruning. 558 { 559 ObjectMeta: metav1.ObjectMeta{ 560 Name: "integers.random.numbers.com", 561 }, 562 Spec: apiextensionsv1.CustomResourceDefinitionSpec{ 563 Group: "random.numbers.com", 564 Scope: apiextensionsv1.ClusterScoped, 565 Names: apiextensionsv1.CustomResourceDefinitionNames{ 566 Plural: "integers", 567 Kind: "Integer", 568 }, 569 Versions: []apiextensionsv1.CustomResourceDefinitionVersion{ 570 { 571 Name: "v1", 572 Served: true, 573 Storage: true, 574 Schema: &apiextensionsv1.CustomResourceValidation{ 575 OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{ 576 Type: "object", 577 Properties: map[string]apiextensionsv1.JSONSchemaProps{ 578 "value": { 579 Type: "number", 580 }, 581 }, 582 }}, 583 }, 584 }, 585 }, 586 }, 587 // cluster scoped with versions field 588 { 589 ObjectMeta: metav1.ObjectMeta{ 590 Name: "pandas.awesome.bears.com", 591 }, 592 Spec: apiextensionsv1.CustomResourceDefinitionSpec{ 593 Group: "awesome.bears.com", 594 Versions: []apiextensionsv1.CustomResourceDefinitionVersion{ 595 { 596 Name: "v1", 597 Served: true, 598 Storage: true, 599 Schema: fixtures.AllowAllSchema(), 600 Subresources: &apiextensionsv1.CustomResourceSubresources{ 601 Status: &apiextensionsv1.CustomResourceSubresourceStatus{}, 602 Scale: &apiextensionsv1.CustomResourceSubresourceScale{ 603 SpecReplicasPath: ".spec.replicas", 604 StatusReplicasPath: ".status.replicas", 605 LabelSelectorPath: func() *string { path := ".status.selector"; return &path }(), 606 }, 607 }, 608 }, 609 { 610 Name: "v2", 611 Served: false, 612 Storage: false, 613 Schema: fixtures.AllowAllSchema(), 614 Subresources: &apiextensionsv1.CustomResourceSubresources{ 615 Status: &apiextensionsv1.CustomResourceSubresourceStatus{}, 616 Scale: &apiextensionsv1.CustomResourceSubresourceScale{ 617 SpecReplicasPath: ".spec.replicas", 618 StatusReplicasPath: ".status.replicas", 619 LabelSelectorPath: func() *string { path := ".status.selector"; return &path }(), 620 }, 621 }, 622 }, 623 { 624 Name: "v3", 625 Served: true, 626 Storage: false, 627 Schema: fixtures.AllowAllSchema(), 628 Subresources: &apiextensionsv1.CustomResourceSubresources{ 629 Status: &apiextensionsv1.CustomResourceSubresourceStatus{}, 630 Scale: &apiextensionsv1.CustomResourceSubresourceScale{ 631 SpecReplicasPath: ".spec.replicas", 632 StatusReplicasPath: ".status.replicas", 633 LabelSelectorPath: func() *string { path := ".status.selector"; return &path }(), 634 }, 635 }, 636 }, 637 }, 638 Scope: apiextensionsv1.ClusterScoped, 639 Names: apiextensionsv1.CustomResourceDefinitionNames{ 640 Plural: "pandas", 641 Kind: "Panda", 642 }, 643 }, 644 }, 645 } 646 } 647 648 func gvr(g, v, r string) schema.GroupVersionResource { 649 return schema.GroupVersionResource{Group: g, Version: v, Resource: r} 650 } 651 652 func gvkP(g, v, k string) *schema.GroupVersionKind { 653 return &schema.GroupVersionKind{Group: g, Version: v, Kind: k} 654 } 655 656 func gvk(g, v, k string) schema.GroupVersionKind { 657 return schema.GroupVersionKind{Group: g, Version: v, Kind: k} 658 }