k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/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 }, 180 // -- 181 182 // k8s.io/kubernetes/pkg/apis/events/v1 183 gvr("events.k8s.io", "v1", "events"): { 184 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"}`, 185 ExpectedEtcdPath: "/registry/events/" + namespace + "/event3", 186 ExpectedGVK: gvkP("", "v1", "Event"), 187 }, 188 // -- 189 190 // k8s.io/kubernetes/pkg/apis/networking/v1 191 gvr("networking.k8s.io", "v1", "ingresses"): { 192 Stub: `{"metadata": {"name": "ingress3"}, "spec": {"defaultBackend": {"service":{"name":"service", "port":{"number": 5000}}}}}`, 193 ExpectedEtcdPath: "/registry/ingress/" + namespace + "/ingress3", 194 }, 195 gvr("networking.k8s.io", "v1", "ingressclasses"): { 196 Stub: `{"metadata": {"name": "ingressclass3"}, "spec": {"controller": "example.com/controller"}}`, 197 ExpectedEtcdPath: "/registry/ingressclasses/ingressclass3", 198 }, 199 gvr("networking.k8s.io", "v1", "networkpolicies"): { 200 Stub: `{"metadata": {"name": "np2"}, "spec": {"podSelector": {"matchLabels": {"e": "f"}}}}`, 201 ExpectedEtcdPath: "/registry/networkpolicies/" + namespace + "/np2", 202 }, 203 // -- 204 205 // k8s.io/kubernetes/pkg/apis/networking/v1alpha1 206 gvr("networking.k8s.io", "v1alpha1", "ipaddresses"): { 207 Stub: `{"metadata": {"name": "192.168.1.2"}, "spec": {"parentRef": {"resource": "services","name": "test", "namespace": "ns"}}}`, 208 ExpectedEtcdPath: "/registry/ipaddresses/192.168.1.2", 209 }, 210 // -- 211 212 // k8s.io/kubernetes/pkg/apis/networking/v1alpha1 213 gvr("networking.k8s.io", "v1alpha1", "servicecidrs"): { 214 Stub: `{"metadata": {"name": "range1"}, "spec": {"cidrs": ["192.168.0.0/16","fd00:1::/120"]}}`, 215 ExpectedEtcdPath: "/registry/servicecidrs/range1", 216 }, 217 // -- 218 219 // k8s.io/kubernetes/pkg/apis/policy/v1 220 gvr("policy", "v1", "poddisruptionbudgets"): { 221 Stub: `{"metadata": {"name": "pdbv1"}, "spec": {"selector": {"matchLabels": {"anokkey": "anokvalue"}}}}`, 222 ExpectedEtcdPath: "/registry/poddisruptionbudgets/" + namespace + "/pdbv1", 223 }, 224 // -- 225 226 // k8s.io/kubernetes/pkg/apis/storagemigration/v1alpha1 227 gvr("storagemigration.k8s.io", "v1alpha1", "storageversionmigrations"): { 228 Stub: `{"metadata": {"name": "test-migration"}, "spec":{"resource": {"group": "test-group", "resource": "test-resource", "version": "test-version"}}}`, 229 ExpectedEtcdPath: "/registry/storageversionmigrations/test-migration", 230 }, 231 // -- 232 233 // k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta1 234 gvr("flowcontrol.apiserver.k8s.io", "v1beta1", "flowschemas"): { 235 Stub: `{"metadata": {"name": "va2"}, "spec": {"priorityLevelConfiguration": {"name": "name1"}}}`, 236 ExpectedEtcdPath: "/registry/flowschemas/va2", 237 ExpectedGVK: gvkP("flowcontrol.apiserver.k8s.io", "v1", "FlowSchema"), 238 }, 239 // -- 240 241 // k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta1 242 gvr("flowcontrol.apiserver.k8s.io", "v1beta1", "prioritylevelconfigurations"): { 243 Stub: `{"metadata": {"name": "conf2"}, "spec": {"type": "Limited", "limited": {"assuredConcurrencyShares":3, "limitResponse": {"type": "Reject"}}}}`, 244 ExpectedEtcdPath: "/registry/prioritylevelconfigurations/conf2", 245 ExpectedGVK: gvkP("flowcontrol.apiserver.k8s.io", "v1", "PriorityLevelConfiguration"), 246 }, 247 // -- 248 249 // k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta2 250 gvr("flowcontrol.apiserver.k8s.io", "v1beta2", "flowschemas"): { 251 Stub: `{"metadata": {"name": "fs-1"}, "spec": {"priorityLevelConfiguration": {"name": "name1"}}}`, 252 ExpectedEtcdPath: "/registry/flowschemas/fs-1", 253 ExpectedGVK: gvkP("flowcontrol.apiserver.k8s.io", "v1", "FlowSchema"), 254 }, 255 // -- 256 257 // k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta2 258 gvr("flowcontrol.apiserver.k8s.io", "v1beta2", "prioritylevelconfigurations"): { 259 Stub: `{"metadata": {"name": "conf3"}, "spec": {"type": "Limited", "limited": {"assuredConcurrencyShares":3, "limitResponse": {"type": "Reject"}}}}`, 260 ExpectedEtcdPath: "/registry/prioritylevelconfigurations/conf3", 261 ExpectedGVK: gvkP("flowcontrol.apiserver.k8s.io", "v1", "PriorityLevelConfiguration"), 262 }, 263 // -- 264 265 // k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta3 266 gvr("flowcontrol.apiserver.k8s.io", "v1beta3", "flowschemas"): { 267 Stub: `{"metadata": {"name": "fs-2"}, "spec": {"priorityLevelConfiguration": {"name": "name1"}}}`, 268 ExpectedEtcdPath: "/registry/flowschemas/fs-2", 269 ExpectedGVK: gvkP("flowcontrol.apiserver.k8s.io", "v1", "FlowSchema"), 270 }, 271 // -- 272 273 // k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta3 274 gvr("flowcontrol.apiserver.k8s.io", "v1beta3", "prioritylevelconfigurations"): { 275 Stub: `{"metadata": {"name": "conf4"}, "spec": {"type": "Limited", "limited": {"nominalConcurrencyShares":3, "limitResponse": {"type": "Reject"}}}}`, 276 ExpectedEtcdPath: "/registry/prioritylevelconfigurations/conf4", 277 ExpectedGVK: gvkP("flowcontrol.apiserver.k8s.io", "v1", "PriorityLevelConfiguration"), 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 }, 286 // -- 287 288 // k8s.io/kubernetes/pkg/apis/flowcontrol/v1 289 gvr("flowcontrol.apiserver.k8s.io", "v1", "prioritylevelconfigurations"): { 290 Stub: `{"metadata": {"name": "conf5"}, "spec": {"type": "Limited", "limited": {"nominalConcurrencyShares":3, "limitResponse": {"type": "Reject"}}}}`, 291 ExpectedEtcdPath: "/registry/prioritylevelconfigurations/conf5", 292 }, 293 // -- 294 295 // k8s.io/kubernetes/pkg/apis/storage/v1 296 gvr("storage.k8s.io", "v1", "volumeattachments"): { 297 Stub: `{"metadata": {"name": "va3"}, "spec": {"attacher": "gce", "nodeName": "localhost", "source": {"persistentVolumeName": "pv3"}}}`, 298 ExpectedEtcdPath: "/registry/volumeattachments/va3", 299 }, 300 // -- 301 302 // k8s.io/kubernetes/pkg/apis/storage/v1alpha1 303 gvr("storage.k8s.io", "v1alpha1", "volumeattributesclasses"): { 304 Stub: `{"metadata": {"name": "vac1"}, "driverName": "example.com/driver", "parameters": {"foo": "bar"}}`, 305 ExpectedEtcdPath: "/registry/volumeattributesclasses/vac1", 306 }, 307 // -- 308 309 // k8s.io/kubernetes/pkg/apis/storage/v1 310 gvr("storage.k8s.io", "v1", "storageclasses"): { 311 Stub: `{"metadata": {"name": "sc2"}, "provisioner": "aws"}`, 312 ExpectedEtcdPath: "/registry/storageclasses/sc2", 313 }, 314 gvr("storage.k8s.io", "v1", "csistoragecapacities"): { 315 Stub: `{"metadata": {"name": "csc-12345-3"}, "storageClassName": "sc1"}`, 316 ExpectedEtcdPath: "/registry/csistoragecapacities/" + namespace + "/csc-12345-3", 317 }, 318 // -- 319 320 // k8s.io/kubernetes/pkg/apis/rbac/v1 321 gvr("rbac.authorization.k8s.io", "v1", "roles"): { 322 Stub: `{"metadata": {"name": "role3"}, "rules": [{"apiGroups": ["v1"], "resources": ["events"], "verbs": ["watch"]}]}`, 323 ExpectedEtcdPath: "/registry/roles/" + namespace + "/role3", 324 }, 325 gvr("rbac.authorization.k8s.io", "v1", "clusterroles"): { 326 Stub: `{"metadata": {"name": "crole3"}, "rules": [{"nonResourceURLs": ["/version"], "verbs": ["get"]}]}`, 327 ExpectedEtcdPath: "/registry/clusterroles/crole3", 328 }, 329 gvr("rbac.authorization.k8s.io", "v1", "rolebindings"): { 330 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"}]}`, 331 ExpectedEtcdPath: "/registry/rolebindings/" + namespace + "/roleb3", 332 }, 333 gvr("rbac.authorization.k8s.io", "v1", "clusterrolebindings"): { 334 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"}]}`, 335 ExpectedEtcdPath: "/registry/clusterrolebindings/croleb3", 336 }, 337 // -- 338 339 // k8s.io/kubernetes/pkg/apis/admissionregistration/v1 340 gvr("admissionregistration.k8s.io", "v1", "validatingwebhookconfigurations"): { 341 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"]}]}`, 342 ExpectedEtcdPath: "/registry/validatingwebhookconfigurations/hook2", 343 }, 344 gvr("admissionregistration.k8s.io", "v1", "mutatingwebhookconfigurations"): { 345 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"]}]}`, 346 ExpectedEtcdPath: "/registry/mutatingwebhookconfigurations/hook2", 347 }, 348 gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicies"): { 349 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"}]}}`, 350 ExpectedEtcdPath: "/registry/validatingadmissionpolicies/vap1", 351 ExpectedGVK: gvkP("admissionregistration.k8s.io", "v1beta1", "ValidatingAdmissionPolicy"), 352 }, 353 gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicybindings"): { 354 Stub: `{"metadata":{"name":"pb1","creationTimestamp":null},"spec":{"policyName":"replicalimit-policy.example.com","paramRef":{"name":"replica-limit-test.example.com","parameterNotFoundAction":"Deny"},"validationActions":["Deny"]}}`, 355 ExpectedEtcdPath: "/registry/validatingadmissionpolicybindings/pb1", 356 ExpectedGVK: gvkP("admissionregistration.k8s.io", "v1beta1", "ValidatingAdmissionPolicyBinding"), 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":"vap1a1","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/vap1a1", 375 ExpectedGVK: gvkP("admissionregistration.k8s.io", "v1beta1", "ValidatingAdmissionPolicy"), 376 }, 377 gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicybindings"): { 378 Stub: `{"metadata":{"name":"pb1a1","creationTimestamp":null},"spec":{"policyName":"replicalimit-policy.example.com","paramRef":{"name":"replica-limit-test.example.com"},"validationActions":["Deny"]}}`, 379 ExpectedEtcdPath: "/registry/validatingadmissionpolicybindings/pb1a1", 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 gvr("resource.k8s.io", "v1alpha2", "resourceclassparameters"): { 456 Stub: `{"metadata": {"name": "class1parameters"}}`, 457 ExpectedEtcdPath: "/registry/resourceclassparameters/" + namespace + "/class1parameters", 458 }, 459 gvr("resource.k8s.io", "v1alpha2", "resourceclaimparameters"): { 460 Stub: `{"metadata": {"name": "claim1parameters"}}`, 461 ExpectedEtcdPath: "/registry/resourceclaimparameters/" + namespace + "/claim1parameters", 462 }, 463 gvr("resource.k8s.io", "v1alpha2", "resourceslices"): { 464 Stub: `{"metadata": {"name": "node1slice"}, "nodeName": "worker1", "driverName": "dra.example.com", "namedResources": {}}`, 465 ExpectedEtcdPath: "/registry/resourceslices/node1slice", 466 }, 467 // -- 468 469 // k8s.io/apiserver/pkg/apis/apiserverinternal/v1alpha1 470 gvr("internal.apiserver.k8s.io", "v1alpha1", "storageversions"): { 471 Stub: `{"metadata":{"name":"sv1.test"},"spec":{}}`, 472 ExpectedEtcdPath: "/registry/storageversions/sv1.test", 473 }, 474 // -- 475 476 } 477 478 // add csinodes 479 // k8s.io/kubernetes/pkg/apis/storage/v1 480 etcdStorageData[gvr("storage.k8s.io", "v1", "csinodes")] = StorageData{ 481 Stub: `{"metadata": {"name": "csini2"}, "spec": {"drivers": [{"name": "test-driver", "nodeID": "localhost", "topologyKeys": ["company.com/zone1", "company.com/zone2"]}]}}`, 482 ExpectedEtcdPath: "/registry/csinodes/csini2", 483 } 484 485 // add csidrivers 486 // k8s.io/kubernetes/pkg/apis/storage/v1 487 etcdStorageData[gvr("storage.k8s.io", "v1", "csidrivers")] = StorageData{ 488 Stub: `{"metadata": {"name": "csid2"}, "spec": {"attachRequired": true, "podInfoOnMount": true}}`, 489 ExpectedEtcdPath: "/registry/csidrivers/csid2", 490 } 491 492 return etcdStorageData 493 } 494 495 // StorageData contains information required to create an object and verify its storage in etcd 496 // It must be paired with a specific resource 497 type StorageData struct { 498 Stub string // Valid JSON stub to use during create 499 Prerequisites []Prerequisite // Optional, ordered list of JSON objects to create before stub 500 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 501 ExpectedGVK *schema.GroupVersionKind // The GVK that we expect this object to be stored as - leave this nil to use the default 502 } 503 504 // Prerequisite contains information required to create a resource (but not verify it) 505 type Prerequisite struct { 506 GvrData schema.GroupVersionResource 507 Stub string 508 } 509 510 // GetCustomResourceDefinitionData returns the resource definitions that back the custom resources 511 // included in GetEtcdStorageData. They should be created using CreateTestCRDs before running any tests. 512 // We can switch this to v1 CRDs based on transitive call site analysis. 513 // Call sites: 514 // 1. TestDedupOwnerReferences - beta doesn't matter 515 // 2. TestWebhookAdmissionWithWatchCache/TestWebhookAdmissionWithoutWatchCache - beta doesn't matter 516 // 3. TestApplyStatus - the version fields don't matter. Pruning isn't checked, just ownership. 517 // 4. TestDryRun - versions and pruning don't matter 518 // 5. TestStorageVersionBootstrap - versions and pruning don't matter. 519 // 6. TestEtcdStoragePath - beta doesn't matter 520 // 7. TestCrossGroupStorage - beta doesn't matter 521 // 8. TestOverlappingCustomResourceCustomResourceDefinition - beta doesn't matter 522 // 9. TestOverlappingCustomResourceAPIService - beta doesn't matter 523 func GetCustomResourceDefinitionData() []*apiextensionsv1.CustomResourceDefinition { 524 return []*apiextensionsv1.CustomResourceDefinition{ 525 // namespaced 526 { 527 ObjectMeta: metav1.ObjectMeta{ 528 Name: "foos.cr.bar.com", 529 }, 530 Spec: apiextensionsv1.CustomResourceDefinitionSpec{ 531 Group: "cr.bar.com", 532 Scope: apiextensionsv1.NamespaceScoped, 533 Names: apiextensionsv1.CustomResourceDefinitionNames{ 534 Plural: "foos", 535 Kind: "Foo", 536 }, 537 Versions: []apiextensionsv1.CustomResourceDefinitionVersion{ 538 { 539 Name: "v1", 540 Served: true, 541 Storage: true, 542 Schema: fixtures.AllowAllSchema(), 543 }, 544 }, 545 }, 546 }, 547 // cluster scoped 548 { 549 ObjectMeta: metav1.ObjectMeta{ 550 Name: "pants.custom.fancy.com", 551 }, 552 Spec: apiextensionsv1.CustomResourceDefinitionSpec{ 553 Group: "custom.fancy.com", 554 Scope: apiextensionsv1.ClusterScoped, 555 Names: apiextensionsv1.CustomResourceDefinitionNames{ 556 Plural: "pants", 557 Kind: "Pant", 558 }, 559 Versions: []apiextensionsv1.CustomResourceDefinitionVersion{ 560 { 561 Name: "v2", 562 Served: true, 563 Storage: true, 564 Schema: fixtures.AllowAllSchema(), 565 }, 566 }, 567 }, 568 }, 569 // cluster scoped with legacy version field and pruning. 570 { 571 ObjectMeta: metav1.ObjectMeta{ 572 Name: "integers.random.numbers.com", 573 }, 574 Spec: apiextensionsv1.CustomResourceDefinitionSpec{ 575 Group: "random.numbers.com", 576 Scope: apiextensionsv1.ClusterScoped, 577 Names: apiextensionsv1.CustomResourceDefinitionNames{ 578 Plural: "integers", 579 Kind: "Integer", 580 }, 581 Versions: []apiextensionsv1.CustomResourceDefinitionVersion{ 582 { 583 Name: "v1", 584 Served: true, 585 Storage: true, 586 Schema: &apiextensionsv1.CustomResourceValidation{ 587 OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{ 588 Type: "object", 589 Properties: map[string]apiextensionsv1.JSONSchemaProps{ 590 "value": { 591 Type: "number", 592 }, 593 }, 594 }}, 595 }, 596 }, 597 }, 598 }, 599 // cluster scoped with versions field 600 { 601 ObjectMeta: metav1.ObjectMeta{ 602 Name: "pandas.awesome.bears.com", 603 }, 604 Spec: apiextensionsv1.CustomResourceDefinitionSpec{ 605 Group: "awesome.bears.com", 606 Versions: []apiextensionsv1.CustomResourceDefinitionVersion{ 607 { 608 Name: "v1", 609 Served: true, 610 Storage: true, 611 Schema: fixtures.AllowAllSchema(), 612 Subresources: &apiextensionsv1.CustomResourceSubresources{ 613 Status: &apiextensionsv1.CustomResourceSubresourceStatus{}, 614 Scale: &apiextensionsv1.CustomResourceSubresourceScale{ 615 SpecReplicasPath: ".spec.replicas", 616 StatusReplicasPath: ".status.replicas", 617 LabelSelectorPath: func() *string { path := ".status.selector"; return &path }(), 618 }, 619 }, 620 }, 621 { 622 Name: "v2", 623 Served: false, 624 Storage: false, 625 Schema: fixtures.AllowAllSchema(), 626 Subresources: &apiextensionsv1.CustomResourceSubresources{ 627 Status: &apiextensionsv1.CustomResourceSubresourceStatus{}, 628 Scale: &apiextensionsv1.CustomResourceSubresourceScale{ 629 SpecReplicasPath: ".spec.replicas", 630 StatusReplicasPath: ".status.replicas", 631 LabelSelectorPath: func() *string { path := ".status.selector"; return &path }(), 632 }, 633 }, 634 }, 635 { 636 Name: "v3", 637 Served: true, 638 Storage: false, 639 Schema: fixtures.AllowAllSchema(), 640 Subresources: &apiextensionsv1.CustomResourceSubresources{ 641 Status: &apiextensionsv1.CustomResourceSubresourceStatus{}, 642 Scale: &apiextensionsv1.CustomResourceSubresourceScale{ 643 SpecReplicasPath: ".spec.replicas", 644 StatusReplicasPath: ".status.replicas", 645 LabelSelectorPath: func() *string { path := ".status.selector"; return &path }(), 646 }, 647 }, 648 }, 649 }, 650 Scope: apiextensionsv1.ClusterScoped, 651 Names: apiextensionsv1.CustomResourceDefinitionNames{ 652 Plural: "pandas", 653 Kind: "Panda", 654 }, 655 }, 656 }, 657 } 658 } 659 660 func gvr(g, v, r string) schema.GroupVersionResource { 661 return schema.GroupVersionResource{Group: g, Version: v, Resource: r} 662 } 663 664 func gvkP(g, v, k string) *schema.GroupVersionKind { 665 return &schema.GroupVersionKind{Group: g, Version: v, Kind: k} 666 } 667 668 func gvk(g, v, k string) schema.GroupVersionKind { 669 return schema.GroupVersionKind{Group: g, Version: v, Kind: k} 670 }