...

Source file src/k8s.io/kubernetes/test/integration/etcd/data.go

Documentation: k8s.io/kubernetes/test/integration/etcd

     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/storagemigration/v1alpha1
   228  		gvr("storagemigration.k8s.io", "v1alpha1", "storageversionmigrations"): {
   229  			Stub:             `{"metadata": {"name": "test-migration"}, "spec":{"resource": {"group": "test-group", "resource": "test-resource", "version": "test-version"}}}`,
   230  			ExpectedEtcdPath: "/registry/storageversionmigrations/test-migration",
   231  		},
   232  		// --
   233  
   234  		// k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta1
   235  		gvr("flowcontrol.apiserver.k8s.io", "v1beta1", "flowschemas"): {
   236  			Stub:             `{"metadata": {"name": "va2"}, "spec": {"priorityLevelConfiguration": {"name": "name1"}}}`,
   237  			ExpectedEtcdPath: "/registry/flowschemas/va2",
   238  			ExpectedGVK:      gvkP("flowcontrol.apiserver.k8s.io", "v1", "FlowSchema"),
   239  		},
   240  		// --
   241  
   242  		// k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta1
   243  		gvr("flowcontrol.apiserver.k8s.io", "v1beta1", "prioritylevelconfigurations"): {
   244  			Stub:             `{"metadata": {"name": "conf2"}, "spec": {"type": "Limited", "limited": {"assuredConcurrencyShares":3, "limitResponse": {"type": "Reject"}}}}`,
   245  			ExpectedEtcdPath: "/registry/prioritylevelconfigurations/conf2",
   246  			ExpectedGVK:      gvkP("flowcontrol.apiserver.k8s.io", "v1", "PriorityLevelConfiguration"),
   247  		},
   248  		// --
   249  
   250  		// k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta2
   251  		gvr("flowcontrol.apiserver.k8s.io", "v1beta2", "flowschemas"): {
   252  			Stub:             `{"metadata": {"name": "fs-1"}, "spec": {"priorityLevelConfiguration": {"name": "name1"}}}`,
   253  			ExpectedEtcdPath: "/registry/flowschemas/fs-1",
   254  			ExpectedGVK:      gvkP("flowcontrol.apiserver.k8s.io", "v1", "FlowSchema"),
   255  		},
   256  		// --
   257  
   258  		// k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta2
   259  		gvr("flowcontrol.apiserver.k8s.io", "v1beta2", "prioritylevelconfigurations"): {
   260  			Stub:             `{"metadata": {"name": "conf3"}, "spec": {"type": "Limited", "limited": {"assuredConcurrencyShares":3, "limitResponse": {"type": "Reject"}}}}`,
   261  			ExpectedEtcdPath: "/registry/prioritylevelconfigurations/conf3",
   262  			ExpectedGVK:      gvkP("flowcontrol.apiserver.k8s.io", "v1", "PriorityLevelConfiguration"),
   263  		},
   264  		// --
   265  
   266  		// k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta3
   267  		gvr("flowcontrol.apiserver.k8s.io", "v1beta3", "flowschemas"): {
   268  			Stub:             `{"metadata": {"name": "fs-2"}, "spec": {"priorityLevelConfiguration": {"name": "name1"}}}`,
   269  			ExpectedEtcdPath: "/registry/flowschemas/fs-2",
   270  			ExpectedGVK:      gvkP("flowcontrol.apiserver.k8s.io", "v1", "FlowSchema"),
   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  			ExpectedGVK:      gvkP("flowcontrol.apiserver.k8s.io", "v1", "PriorityLevelConfiguration"),
   279  		},
   280  		// --
   281  
   282  		// k8s.io/kubernetes/pkg/apis/flowcontrol/v1
   283  		gvr("flowcontrol.apiserver.k8s.io", "v1", "flowschemas"): {
   284  			Stub:             `{"metadata": {"name": "fs-3"}, "spec": {"priorityLevelConfiguration": {"name": "name1"}}}`,
   285  			ExpectedEtcdPath: "/registry/flowschemas/fs-3",
   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  		},
   294  		// --
   295  
   296  		// k8s.io/kubernetes/pkg/apis/storage/v1
   297  		gvr("storage.k8s.io", "v1", "volumeattachments"): {
   298  			Stub:             `{"metadata": {"name": "va3"}, "spec": {"attacher": "gce", "nodeName": "localhost", "source": {"persistentVolumeName": "pv3"}}}`,
   299  			ExpectedEtcdPath: "/registry/volumeattachments/va3",
   300  		},
   301  		// --
   302  
   303  		// k8s.io/kubernetes/pkg/apis/storage/v1alpha1
   304  		gvr("storage.k8s.io", "v1alpha1", "volumeattributesclasses"): {
   305  			Stub:             `{"metadata": {"name": "vac1"}, "driverName": "example.com/driver", "parameters": {"foo": "bar"}}`,
   306  			ExpectedEtcdPath: "/registry/volumeattributesclasses/vac1",
   307  		},
   308  		// --
   309  
   310  		// k8s.io/kubernetes/pkg/apis/storage/v1
   311  		gvr("storage.k8s.io", "v1", "storageclasses"): {
   312  			Stub:             `{"metadata": {"name": "sc2"}, "provisioner": "aws"}`,
   313  			ExpectedEtcdPath: "/registry/storageclasses/sc2",
   314  		},
   315  		gvr("storage.k8s.io", "v1", "csistoragecapacities"): {
   316  			Stub:             `{"metadata": {"name": "csc-12345-3"}, "storageClassName": "sc1"}`,
   317  			ExpectedEtcdPath: "/registry/csistoragecapacities/" + namespace + "/csc-12345-3",
   318  		},
   319  		// --
   320  
   321  		// k8s.io/kubernetes/pkg/apis/rbac/v1
   322  		gvr("rbac.authorization.k8s.io", "v1", "roles"): {
   323  			Stub:             `{"metadata": {"name": "role3"}, "rules": [{"apiGroups": ["v1"], "resources": ["events"], "verbs": ["watch"]}]}`,
   324  			ExpectedEtcdPath: "/registry/roles/" + namespace + "/role3",
   325  		},
   326  		gvr("rbac.authorization.k8s.io", "v1", "clusterroles"): {
   327  			Stub:             `{"metadata": {"name": "crole3"}, "rules": [{"nonResourceURLs": ["/version"], "verbs": ["get"]}]}`,
   328  			ExpectedEtcdPath: "/registry/clusterroles/crole3",
   329  		},
   330  		gvr("rbac.authorization.k8s.io", "v1", "rolebindings"): {
   331  			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"}]}`,
   332  			ExpectedEtcdPath: "/registry/rolebindings/" + namespace + "/roleb3",
   333  		},
   334  		gvr("rbac.authorization.k8s.io", "v1", "clusterrolebindings"): {
   335  			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"}]}`,
   336  			ExpectedEtcdPath: "/registry/clusterrolebindings/croleb3",
   337  		},
   338  		// --
   339  
   340  		// k8s.io/kubernetes/pkg/apis/admissionregistration/v1
   341  		gvr("admissionregistration.k8s.io", "v1", "validatingwebhookconfigurations"): {
   342  			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"]}]}`,
   343  			ExpectedEtcdPath: "/registry/validatingwebhookconfigurations/hook2",
   344  		},
   345  		gvr("admissionregistration.k8s.io", "v1", "mutatingwebhookconfigurations"): {
   346  			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"]}]}`,
   347  			ExpectedEtcdPath: "/registry/mutatingwebhookconfigurations/hook2",
   348  		},
   349  		gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicies"): {
   350  			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"}]}}`,
   351  			ExpectedEtcdPath: "/registry/validatingadmissionpolicies/vap1",
   352  			ExpectedGVK:      gvkP("admissionregistration.k8s.io", "v1beta1", "ValidatingAdmissionPolicy"),
   353  		},
   354  		gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicybindings"): {
   355  			Stub:             `{"metadata":{"name":"pb1","creationTimestamp":null},"spec":{"policyName":"replicalimit-policy.example.com","paramRef":{"name":"replica-limit-test.example.com","parameterNotFoundAction":"Deny"},"validationActions":["Deny"]}}`,
   356  			ExpectedEtcdPath: "/registry/validatingadmissionpolicybindings/pb1",
   357  			ExpectedGVK:      gvkP("admissionregistration.k8s.io", "v1beta1", "ValidatingAdmissionPolicyBinding"),
   358  		},
   359  		// --
   360  
   361  		// k8s.io/kubernetes/pkg/apis/admissionregistration/v1beta1
   362  		gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies"): {
   363  			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"}]}}`,
   364  			ExpectedEtcdPath: "/registry/validatingadmissionpolicies/vap1b1",
   365  		},
   366  		gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicybindings"): {
   367  			Stub:             `{"metadata":{"name":"pb1b1","creationTimestamp":null},"spec":{"policyName":"replicalimit-policy.example.com","paramRef":{"name":"replica-limit-test.example.com","parameterNotFoundAction":"Deny"},"validationActions":["Deny"]}}`,
   368  			ExpectedEtcdPath: "/registry/validatingadmissionpolicybindings/pb1b1",
   369  		},
   370  		// --
   371  
   372  		// k8s.io/kubernetes/pkg/apis/admissionregistration/v1alpha1
   373  		gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies"): {
   374  			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"}]}}`,
   375  			ExpectedEtcdPath: "/registry/validatingadmissionpolicies/vap1a1",
   376  			ExpectedGVK:      gvkP("admissionregistration.k8s.io", "v1beta1", "ValidatingAdmissionPolicy"),
   377  		},
   378  		gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicybindings"): {
   379  			Stub:             `{"metadata":{"name":"pb1a1","creationTimestamp":null},"spec":{"policyName":"replicalimit-policy.example.com","paramRef":{"name":"replica-limit-test.example.com"},"validationActions":["Deny"]}}`,
   380  			ExpectedEtcdPath: "/registry/validatingadmissionpolicybindings/pb1a1",
   381  			ExpectedGVK:      gvkP("admissionregistration.k8s.io", "v1beta1", "ValidatingAdmissionPolicyBinding"),
   382  		},
   383  		// --
   384  
   385  		// k8s.io/kubernetes/pkg/apis/scheduling/v1
   386  		gvr("scheduling.k8s.io", "v1", "priorityclasses"): {
   387  			Stub:             `{"metadata":{"name":"pc3"},"Value":1000}`,
   388  			ExpectedEtcdPath: "/registry/priorityclasses/pc3",
   389  		},
   390  		// --
   391  
   392  		// k8s.io/kube-aggregator/pkg/apis/apiregistration/v1
   393  		// depends on aggregator using the same ungrouped RESTOptionsGetter as the kube apiserver, not SimpleRestOptionsFactory in aggregator.go
   394  		gvr("apiregistration.k8s.io", "v1", "apiservices"): {
   395  			Stub:             `{"metadata": {"name": "as2.foo.com"}, "spec": {"group": "foo.com", "version": "as2", "groupPriorityMinimum":100, "versionPriority":10}}`,
   396  			ExpectedEtcdPath: "/registry/apiregistration.k8s.io/apiservices/as2.foo.com",
   397  		},
   398  		// --
   399  
   400  		// k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1
   401  		gvr("apiextensions.k8s.io", "v1", "customresourcedefinitions"): {
   402  			Stub: `{"metadata": {"name": "openshiftwebconsoleconfigs.webconsole2.operator.openshift.io"},"spec": {` +
   403  				`"scope": "Cluster","group": "webconsole2.operator.openshift.io",` +
   404  				`"versions": [{"name":"v1alpha1","storage":true,"served":true,"schema":{"openAPIV3Schema":{"type":"object"}}}],` +
   405  				`"names": {"kind": "OpenShiftWebConsoleConfig","plural": "openshiftwebconsoleconfigs","singular": "openshiftwebconsoleconfig"}}}`,
   406  			ExpectedEtcdPath: "/registry/apiextensions.k8s.io/customresourcedefinitions/openshiftwebconsoleconfigs.webconsole2.operator.openshift.io",
   407  			ExpectedGVK:      gvkP("apiextensions.k8s.io", "v1beta1", "CustomResourceDefinition"),
   408  		},
   409  		gvr("cr.bar.com", "v1", "foos"): {
   410  			Stub:             `{"kind": "Foo", "apiVersion": "cr.bar.com/v1", "metadata": {"name": "cr1foo"}, "color": "blue"}`, // requires TypeMeta due to CRD scheme's UnstructuredObjectTyper
   411  			ExpectedEtcdPath: "/registry/cr.bar.com/foos/" + namespace + "/cr1foo",
   412  		},
   413  		gvr("custom.fancy.com", "v2", "pants"): {
   414  			Stub:             `{"kind": "Pant", "apiVersion": "custom.fancy.com/v2", "metadata": {"name": "cr2pant"}, "isFancy": true}`, // requires TypeMeta due to CRD scheme's UnstructuredObjectTyper
   415  			ExpectedEtcdPath: "/registry/custom.fancy.com/pants/cr2pant",
   416  		},
   417  		gvr("awesome.bears.com", "v1", "pandas"): {
   418  			Stub:             `{"kind": "Panda", "apiVersion": "awesome.bears.com/v1", "metadata": {"name": "cr3panda"}, "spec":{"replicas": 100}}`, // requires TypeMeta due to CRD scheme's UnstructuredObjectTyper
   419  			ExpectedEtcdPath: "/registry/awesome.bears.com/pandas/cr3panda",
   420  		},
   421  		gvr("awesome.bears.com", "v3", "pandas"): {
   422  			Stub:             `{"kind": "Panda", "apiVersion": "awesome.bears.com/v3", "metadata": {"name": "cr4panda"}, "spec":{"replicas": 300}}`, // requires TypeMeta due to CRD scheme's UnstructuredObjectTyper
   423  			ExpectedEtcdPath: "/registry/awesome.bears.com/pandas/cr4panda",
   424  			ExpectedGVK:      gvkP("awesome.bears.com", "v1", "Panda"),
   425  		},
   426  		gvr("random.numbers.com", "v1", "integers"): {
   427  			Stub:             `{"kind": "Integer", "apiVersion": "random.numbers.com/v1", "metadata": {"name": "fortytwo"}, "value": 42, "garbage": "oiujnasdf"}`, // requires TypeMeta due to CRD scheme's UnstructuredObjectTyper
   428  			ExpectedEtcdPath: "/registry/random.numbers.com/integers/fortytwo",
   429  		},
   430  		// --
   431  
   432  		// k8s.io/kubernetes/pkg/apis/node/v1
   433  		gvr("node.k8s.io", "v1", "runtimeclasses"): {
   434  			Stub:             `{"metadata": {"name": "rc3"}, "handler": "h3"}`,
   435  			ExpectedEtcdPath: "/registry/runtimeclasses/rc3",
   436  		},
   437  		// --
   438  
   439  		// k8s.io/kubernetes/pkg/apis/resource/v1alpha2
   440  		gvr("resource.k8s.io", "v1alpha2", "resourceclasses"): {
   441  			Stub:             `{"metadata": {"name": "class1name"}, "driverName": "example.com"}`,
   442  			ExpectedEtcdPath: "/registry/resourceclasses/class1name",
   443  		},
   444  		gvr("resource.k8s.io", "v1alpha2", "resourceclaims"): {
   445  			Stub:             `{"metadata": {"name": "claim1name"}, "spec": {"resourceClassName": "class1name", "allocationMode": "WaitForFirstConsumer"}}`,
   446  			ExpectedEtcdPath: "/registry/resourceclaims/" + namespace + "/claim1name",
   447  		},
   448  		gvr("resource.k8s.io", "v1alpha2", "resourceclaimtemplates"): {
   449  			Stub:             `{"metadata": {"name": "claimtemplate1name"}, "spec": {"spec": {"resourceClassName": "class1name", "allocationMode": "WaitForFirstConsumer"}}}`,
   450  			ExpectedEtcdPath: "/registry/resourceclaimtemplates/" + namespace + "/claimtemplate1name",
   451  		},
   452  		gvr("resource.k8s.io", "v1alpha2", "podschedulingcontexts"): {
   453  			Stub:             `{"metadata": {"name": "pod1name"}, "spec": {"selectedNode": "node1name", "potentialNodes": ["node1name", "node2name"]}}`,
   454  			ExpectedEtcdPath: "/registry/podschedulingcontexts/" + namespace + "/pod1name",
   455  		},
   456  		gvr("resource.k8s.io", "v1alpha2", "resourceclassparameters"): {
   457  			Stub:             `{"metadata": {"name": "class1parameters"}}`,
   458  			ExpectedEtcdPath: "/registry/resourceclassparameters/" + namespace + "/class1parameters",
   459  		},
   460  		gvr("resource.k8s.io", "v1alpha2", "resourceclaimparameters"): {
   461  			Stub:             `{"metadata": {"name": "claim1parameters"}}`,
   462  			ExpectedEtcdPath: "/registry/resourceclaimparameters/" + namespace + "/claim1parameters",
   463  		},
   464  		gvr("resource.k8s.io", "v1alpha2", "resourceslices"): {
   465  			Stub:             `{"metadata": {"name": "node1slice"}, "nodeName": "worker1", "driverName": "dra.example.com", "namedResources": {}}`,
   466  			ExpectedEtcdPath: "/registry/resourceslices/node1slice",
   467  		},
   468  		// --
   469  
   470  		// k8s.io/apiserver/pkg/apis/apiserverinternal/v1alpha1
   471  		gvr("internal.apiserver.k8s.io", "v1alpha1", "storageversions"): {
   472  			Stub:             `{"metadata":{"name":"sv1.test"},"spec":{}}`,
   473  			ExpectedEtcdPath: "/registry/storageversions/sv1.test",
   474  		},
   475  		// --
   476  
   477  	}
   478  
   479  	// add csinodes
   480  	// k8s.io/kubernetes/pkg/apis/storage/v1
   481  	etcdStorageData[gvr("storage.k8s.io", "v1", "csinodes")] = StorageData{
   482  		Stub:             `{"metadata": {"name": "csini2"}, "spec": {"drivers": [{"name": "test-driver", "nodeID": "localhost", "topologyKeys": ["company.com/zone1", "company.com/zone2"]}]}}`,
   483  		ExpectedEtcdPath: "/registry/csinodes/csini2",
   484  	}
   485  
   486  	// add csidrivers
   487  	// k8s.io/kubernetes/pkg/apis/storage/v1
   488  	etcdStorageData[gvr("storage.k8s.io", "v1", "csidrivers")] = StorageData{
   489  		Stub:             `{"metadata": {"name": "csid2"}, "spec": {"attachRequired": true, "podInfoOnMount": true}}`,
   490  		ExpectedEtcdPath: "/registry/csidrivers/csid2",
   491  	}
   492  
   493  	return etcdStorageData
   494  }
   495  
   496  // StorageData contains information required to create an object and verify its storage in etcd
   497  // It must be paired with a specific resource
   498  type StorageData struct {
   499  	Stub             string                   // Valid JSON stub to use during create
   500  	Prerequisites    []Prerequisite           // Optional, ordered list of JSON objects to create before stub
   501  	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
   502  	ExpectedGVK      *schema.GroupVersionKind // The GVK that we expect this object to be stored as - leave this nil to use the default
   503  }
   504  
   505  // Prerequisite contains information required to create a resource (but not verify it)
   506  type Prerequisite struct {
   507  	GvrData schema.GroupVersionResource
   508  	Stub    string
   509  }
   510  
   511  // GetCustomResourceDefinitionData returns the resource definitions that back the custom resources
   512  // included in GetEtcdStorageData.  They should be created using CreateTestCRDs before running any tests.
   513  // We can switch this to v1 CRDs based on transitive call site analysis.
   514  // Call sites:
   515  // 1. TestDedupOwnerReferences - beta doesn't matter
   516  // 2. TestWebhookAdmissionWithWatchCache/TestWebhookAdmissionWithoutWatchCache - beta doesn't matter
   517  // 3. TestApplyStatus - the version fields don't matter.  Pruning isn't checked, just ownership.
   518  // 4. TestDryRun - versions and pruning don't matter
   519  // 5. TestStorageVersionBootstrap - versions and pruning don't matter.
   520  // 6. TestEtcdStoragePath - beta doesn't matter
   521  // 7. TestCrossGroupStorage - beta doesn't matter
   522  // 8. TestOverlappingCustomResourceCustomResourceDefinition - beta doesn't matter
   523  // 9. TestOverlappingCustomResourceAPIService - beta doesn't matter
   524  func GetCustomResourceDefinitionData() []*apiextensionsv1.CustomResourceDefinition {
   525  	return []*apiextensionsv1.CustomResourceDefinition{
   526  		// namespaced
   527  		{
   528  			ObjectMeta: metav1.ObjectMeta{
   529  				Name: "foos.cr.bar.com",
   530  			},
   531  			Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   532  				Group: "cr.bar.com",
   533  				Scope: apiextensionsv1.NamespaceScoped,
   534  				Names: apiextensionsv1.CustomResourceDefinitionNames{
   535  					Plural: "foos",
   536  					Kind:   "Foo",
   537  				},
   538  				Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   539  					{
   540  						Name:    "v1",
   541  						Served:  true,
   542  						Storage: true,
   543  						Schema:  fixtures.AllowAllSchema(),
   544  					},
   545  				},
   546  			},
   547  		},
   548  		// cluster scoped
   549  		{
   550  			ObjectMeta: metav1.ObjectMeta{
   551  				Name: "pants.custom.fancy.com",
   552  			},
   553  			Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   554  				Group: "custom.fancy.com",
   555  				Scope: apiextensionsv1.ClusterScoped,
   556  				Names: apiextensionsv1.CustomResourceDefinitionNames{
   557  					Plural: "pants",
   558  					Kind:   "Pant",
   559  				},
   560  				Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   561  					{
   562  						Name:    "v2",
   563  						Served:  true,
   564  						Storage: true,
   565  						Schema:  fixtures.AllowAllSchema(),
   566  					},
   567  				},
   568  			},
   569  		},
   570  		// cluster scoped with legacy version field and pruning.
   571  		{
   572  			ObjectMeta: metav1.ObjectMeta{
   573  				Name: "integers.random.numbers.com",
   574  			},
   575  			Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   576  				Group: "random.numbers.com",
   577  				Scope: apiextensionsv1.ClusterScoped,
   578  				Names: apiextensionsv1.CustomResourceDefinitionNames{
   579  					Plural: "integers",
   580  					Kind:   "Integer",
   581  				},
   582  				Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   583  					{
   584  						Name:    "v1",
   585  						Served:  true,
   586  						Storage: true,
   587  						Schema: &apiextensionsv1.CustomResourceValidation{
   588  							OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
   589  								Type: "object",
   590  								Properties: map[string]apiextensionsv1.JSONSchemaProps{
   591  									"value": {
   592  										Type: "number",
   593  									},
   594  								},
   595  							}},
   596  					},
   597  				},
   598  			},
   599  		},
   600  		// cluster scoped with versions field
   601  		{
   602  			ObjectMeta: metav1.ObjectMeta{
   603  				Name: "pandas.awesome.bears.com",
   604  			},
   605  			Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   606  				Group: "awesome.bears.com",
   607  				Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   608  					{
   609  						Name:    "v1",
   610  						Served:  true,
   611  						Storage: true,
   612  						Schema:  fixtures.AllowAllSchema(),
   613  						Subresources: &apiextensionsv1.CustomResourceSubresources{
   614  							Status: &apiextensionsv1.CustomResourceSubresourceStatus{},
   615  							Scale: &apiextensionsv1.CustomResourceSubresourceScale{
   616  								SpecReplicasPath:   ".spec.replicas",
   617  								StatusReplicasPath: ".status.replicas",
   618  								LabelSelectorPath:  func() *string { path := ".status.selector"; return &path }(),
   619  							},
   620  						},
   621  					},
   622  					{
   623  						Name:    "v2",
   624  						Served:  false,
   625  						Storage: false,
   626  						Schema:  fixtures.AllowAllSchema(),
   627  						Subresources: &apiextensionsv1.CustomResourceSubresources{
   628  							Status: &apiextensionsv1.CustomResourceSubresourceStatus{},
   629  							Scale: &apiextensionsv1.CustomResourceSubresourceScale{
   630  								SpecReplicasPath:   ".spec.replicas",
   631  								StatusReplicasPath: ".status.replicas",
   632  								LabelSelectorPath:  func() *string { path := ".status.selector"; return &path }(),
   633  							},
   634  						},
   635  					},
   636  					{
   637  						Name:    "v3",
   638  						Served:  true,
   639  						Storage: false,
   640  						Schema:  fixtures.AllowAllSchema(),
   641  						Subresources: &apiextensionsv1.CustomResourceSubresources{
   642  							Status: &apiextensionsv1.CustomResourceSubresourceStatus{},
   643  							Scale: &apiextensionsv1.CustomResourceSubresourceScale{
   644  								SpecReplicasPath:   ".spec.replicas",
   645  								StatusReplicasPath: ".status.replicas",
   646  								LabelSelectorPath:  func() *string { path := ".status.selector"; return &path }(),
   647  							},
   648  						},
   649  					},
   650  				},
   651  				Scope: apiextensionsv1.ClusterScoped,
   652  				Names: apiextensionsv1.CustomResourceDefinitionNames{
   653  					Plural: "pandas",
   654  					Kind:   "Panda",
   655  				},
   656  			},
   657  		},
   658  	}
   659  }
   660  
   661  func gvr(g, v, r string) schema.GroupVersionResource {
   662  	return schema.GroupVersionResource{Group: g, Version: v, Resource: r}
   663  }
   664  
   665  func gvkP(g, v, k string) *schema.GroupVersionKind {
   666  	return &schema.GroupVersionKind{Group: g, Version: v, Kind: k}
   667  }
   668  
   669  func gvk(g, v, k string) schema.GroupVersionKind {
   670  	return schema.GroupVersionKind{Group: g, Version: v, Kind: k}
   671  }
   672  

View as plain text