Files
kubernetes/test/integration/etcd/data.go
Patrick Ohly b51d68bb87 DRA: bump API v1alpha2 -> v1alpha3
This is in preparation for revamping the resource.k8s.io completely. Because
there will be no support for transitioning from v1alpha2 to v1alpha3, the
roundtrip test data for that API in 1.29 and 1.30 gets removed.

Repeating the version in the import name of the API packages is not really
required. It was done for a while to support simpler grepping for usage of
alpha APIs, but there are better ways for that now. So during this transition,
"resourceapi" gets used instead of "resourcev1alpha3" and the version gets
dropped from informer and lister imports. The advantage is that the next bump
to v1beta1 will affect fewer source code lines.

Only source code where the version really matters (like API registration)
retains the versioned import.
2024-07-21 17:28:13 +02:00

639 lines
35 KiB
Go

/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package etcd
import (
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubernetes/test/utils/image"
)
// GetEtcdStorageData returns etcd data for all persisted objects.
// It is exported so that it can be reused across multiple tests.
// It returns a new map on every invocation to prevent different tests from mutating shared state.
func GetEtcdStorageData() map[schema.GroupVersionResource]StorageData {
return GetEtcdStorageDataForNamespace("etcdstoragepathtestnamespace")
}
// GetEtcdStorageDataForNamespace returns etcd data for all persisted objects.
// It is exported so that it can be reused across multiple tests.
// It returns a new map on every invocation to prevent different tests from mutating shared state.
// Namespaced objects keys are computed for the specified namespace.
func GetEtcdStorageDataForNamespace(namespace string) map[schema.GroupVersionResource]StorageData {
image := image.GetE2EImage(image.BusyBox)
etcdStorageData := map[schema.GroupVersionResource]StorageData{
// k8s.io/kubernetes/pkg/api/v1
gvr("", "v1", "configmaps"): {
Stub: `{"data": {"foo": "bar"}, "metadata": {"name": "cm1"}}`,
ExpectedEtcdPath: "/registry/configmaps/" + namespace + "/cm1",
},
gvr("", "v1", "services"): {
Stub: `{"metadata": {"name": "service1"}, "spec": {"type": "LoadBalancer", "ports": [{"port": 10000, "targetPort": 11000}], "selector": {"test": "data"}}}`,
ExpectedEtcdPath: "/registry/services/specs/" + namespace + "/service1",
},
gvr("", "v1", "podtemplates"): {
Stub: `{"metadata": {"name": "pt1name"}, "template": {"metadata": {"labels": {"pt": "01"}}, "spec": {"containers": [{"image": "` + image + `", "name": "container9"}]}}}`,
ExpectedEtcdPath: "/registry/podtemplates/" + namespace + "/pt1name",
},
gvr("", "v1", "pods"): {
Stub: `{"metadata": {"name": "pod1"}, "spec": {"containers": [{"image": "` + image + `", "name": "container7", "resources": {"limits": {"cpu": "1M"}, "requests": {"cpu": "1M"}}}]}}`,
ExpectedEtcdPath: "/registry/pods/" + namespace + "/pod1",
},
gvr("", "v1", "endpoints"): {
Stub: `{"metadata": {"name": "ep1name"}, "subsets": [{"addresses": [{"hostname": "bar-001", "ip": "192.168.3.1"}], "ports": [{"port": 8000}]}]}`,
ExpectedEtcdPath: "/registry/services/endpoints/" + namespace + "/ep1name",
},
gvr("", "v1", "resourcequotas"): {
Stub: `{"metadata": {"name": "rq1name"}, "spec": {"hard": {"cpu": "5M"}}}`,
ExpectedEtcdPath: "/registry/resourcequotas/" + namespace + "/rq1name",
},
gvr("", "v1", "limitranges"): {
Stub: `{"metadata": {"name": "lr1name"}, "spec": {"limits": [{"type": "Pod"}]}}`,
ExpectedEtcdPath: "/registry/limitranges/" + namespace + "/lr1name",
},
gvr("", "v1", "namespaces"): {
Stub: `{"metadata": {"name": "namespace1"}, "spec": {"finalizers": ["kubernetes"]}}`,
ExpectedEtcdPath: "/registry/namespaces/namespace1",
},
gvr("", "v1", "nodes"): {
Stub: `{"metadata": {"name": "node1"}, "spec": {"unschedulable": true}}`,
ExpectedEtcdPath: "/registry/minions/node1",
},
gvr("", "v1", "persistentvolumes"): {
Stub: `{"metadata": {"name": "pv1name"}, "spec": {"accessModes": ["ReadWriteOnce"], "capacity": {"storage": "3M"}, "hostPath": {"path": "/tmp/test/"}}}`,
ExpectedEtcdPath: "/registry/persistentvolumes/pv1name",
},
gvr("", "v1", "events"): {
Stub: `{"involvedObject": {"namespace": "` + namespace + `"}, "message": "some data here", "metadata": {"name": "event1"}}`,
ExpectedEtcdPath: "/registry/events/" + namespace + "/event1",
},
gvr("", "v1", "persistentvolumeclaims"): {
Stub: `{"metadata": {"name": "pvc1"}, "spec": {"accessModes": ["ReadWriteOnce"], "resources": {"limits": {"storage": "1M"}, "requests": {"storage": "2M"}}, "selector": {"matchLabels": {"pvc": "stuff"}}}}`,
ExpectedEtcdPath: "/registry/persistentvolumeclaims/" + namespace + "/pvc1",
},
gvr("", "v1", "serviceaccounts"): {
Stub: `{"metadata": {"name": "sa1name"}, "secrets": [{"name": "secret00"}]}`,
ExpectedEtcdPath: "/registry/serviceaccounts/" + namespace + "/sa1name",
},
gvr("", "v1", "secrets"): {
Stub: `{"data": {"key": "ZGF0YSBmaWxl"}, "metadata": {"name": "secret1"}}`,
ExpectedEtcdPath: "/registry/secrets/" + namespace + "/secret1",
},
gvr("", "v1", "replicationcontrollers"): {
Stub: `{"metadata": {"name": "rc1"}, "spec": {"selector": {"new": "stuff"}, "template": {"metadata": {"labels": {"new": "stuff"}}, "spec": {"containers": [{"image": "` + image + `", "name": "container8"}]}}}}`,
ExpectedEtcdPath: "/registry/controllers/" + namespace + "/rc1",
},
// --
// k8s.io/kubernetes/pkg/apis/apps/v1
gvr("apps", "v1", "daemonsets"): {
Stub: `{"metadata": {"name": "ds6"}, "spec": {"selector": {"matchLabels": {"a": "b"}}, "template": {"metadata": {"labels": {"a": "b"}}, "spec": {"containers": [{"image": "` + image + `", "name": "container6"}]}}}}`,
ExpectedEtcdPath: "/registry/daemonsets/" + namespace + "/ds6",
},
gvr("apps", "v1", "deployments"): {
Stub: `{"metadata": {"name": "deployment4"}, "spec": {"selector": {"matchLabels": {"f": "z"}}, "template": {"metadata": {"labels": {"f": "z"}}, "spec": {"containers": [{"image": "` + image + `", "name": "container6"}]}}}}`,
ExpectedEtcdPath: "/registry/deployments/" + namespace + "/deployment4",
},
gvr("apps", "v1", "statefulsets"): {
Stub: `{"metadata": {"name": "ss3"}, "spec": {"selector": {"matchLabels": {"a": "b"}}, "template": {"metadata": {"labels": {"a": "b"}}}}}`,
ExpectedEtcdPath: "/registry/statefulsets/" + namespace + "/ss3",
},
gvr("apps", "v1", "replicasets"): {
Stub: `{"metadata": {"name": "rs3"}, "spec": {"selector": {"matchLabels": {"g": "h"}}, "template": {"metadata": {"labels": {"g": "h"}}, "spec": {"containers": [{"image": "` + image + `", "name": "container4"}]}}}}`,
ExpectedEtcdPath: "/registry/replicasets/" + namespace + "/rs3",
},
gvr("apps", "v1", "controllerrevisions"): {
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}`,
ExpectedEtcdPath: "/registry/controllerrevisions/" + namespace + "/crs3",
},
// --
// k8s.io/kubernetes/pkg/apis/autoscaling/v1
gvr("autoscaling", "v1", "horizontalpodautoscalers"): {
Stub: `{"metadata": {"name": "hpa2"}, "spec": {"maxReplicas": 3, "scaleTargetRef": {"kind": "something", "name": "cross"}}}`,
ExpectedEtcdPath: "/registry/horizontalpodautoscalers/" + namespace + "/hpa2",
ExpectedGVK: gvkP("autoscaling", "v2", "HorizontalPodAutoscaler"),
},
// --
// k8s.io/kubernetes/pkg/apis/autoscaling/v2
gvr("autoscaling", "v2", "horizontalpodautoscalers"): {
Stub: `{"metadata": {"name": "hpa4"}, "spec": {"maxReplicas": 3, "scaleTargetRef": {"kind": "something", "name": "cross"}}}`,
ExpectedEtcdPath: "/registry/horizontalpodautoscalers/" + namespace + "/hpa4",
},
// --
// k8s.io/kubernetes/pkg/apis/batch/v1
gvr("batch", "v1", "jobs"): {
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"}}}}`,
ExpectedEtcdPath: "/registry/jobs/" + namespace + "/job1",
},
gvr("batch", "v1", "cronjobs"): {
Stub: `{"metadata": {"name": "cjv1"}, "spec": {"jobTemplate": {"spec": {"template": {"metadata": {"labels": {"controller-uid": "uid0"}}, "spec": {"containers": [{"image": "` + image + `", "name": "container0"}], "dnsPolicy": "ClusterFirst", "restartPolicy": "Never"}}}}, "schedule": "* * * * *"}}`,
ExpectedEtcdPath: "/registry/cronjobs/" + namespace + "/cjv1",
},
// --
// k8s.io/kubernetes/pkg/apis/certificates/v1
gvr("certificates.k8s.io", "v1", "certificatesigningrequests"): {
Stub: `{"metadata": {"name": "csr2"}, "spec": {"signerName":"example.com/signer", "usages":["any"], "request": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQnlqQ0NBVE1DQVFBd2dZa3hDekFKQmdOVkJBWVRBbFZUTVJNd0VRWURWUVFJRXdwRFlXeHBabTl5Ym1saApNUll3RkFZRFZRUUhFdzFOYjNWdWRHRnBiaUJXYVdWM01STXdFUVlEVlFRS0V3cEhiMjluYkdVZ1NXNWpNUjh3CkhRWURWUVFMRXhaSmJtWnZjbTFoZEdsdmJpQlVaV05vYm05c2IyZDVNUmN3RlFZRFZRUURFdzUzZDNjdVoyOXYKWjJ4bExtTnZiVENCbnpBTkJna3Foa2lHOXcwQkFRRUZBQU9CalFBd2dZa0NnWUVBcFp0WUpDSEo0VnBWWEhmVgpJbHN0UVRsTzRxQzAzaGpYK1prUHl2ZFlkMVE0K3FiQWVUd1htQ1VLWUhUaFZSZDVhWFNxbFB6eUlCd2llTVpyCldGbFJRZGRaMUl6WEFsVlJEV3dBbzYwS2VjcWVBWG5uVUsrNWZYb1RJL1VnV3NocmU4dEoreC9UTUhhUUtSL0oKY0lXUGhxYVFoc0p1elpidkFkR0E4MEJMeGRNQ0F3RUFBYUFBTUEwR0NTcUdTSWIzRFFFQkJRVUFBNEdCQUlobAo0UHZGcStlN2lwQVJnSTVaTStHWng2bXBDejQ0RFRvMEprd2ZSRGYrQnRyc2FDMHE2OGVUZjJYaFlPc3E0ZmtIClEwdUEwYVZvZzNmNWlKeENhM0hwNWd4YkpRNnpWNmtKMFRFc3VhYU9oRWtvOXNkcENvUE9uUkJtMmkvWFJEMkQKNmlOaDhmOHowU2hHc0ZxakRnRkh5RjNvK2xVeWorVUM2SDFRVzdibgotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0="}}`,
ExpectedEtcdPath: "/registry/certificatesigningrequests/csr2",
},
// --
// k8s.io/kubernetes/pkg/apis/certificates/v1alpha1
gvr("certificates.k8s.io", "v1alpha1", "clustertrustbundles"): {
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"}}`,
ExpectedEtcdPath: "/registry/clustertrustbundles/example.com:signer:abc",
},
// --
// k8s.io/kubernetes/pkg/apis/coordination/v1
gvr("coordination.k8s.io", "v1", "leases"): {
Stub: `{"metadata": {"name": "leasev1"}, "spec": {"holderIdentity": "holder", "leaseDurationSeconds": 5}}`,
ExpectedEtcdPath: "/registry/leases/" + namespace + "/leasev1",
},
// --
// k8s.io/kubernetes/pkg/apis/discovery/v1
gvr("discovery.k8s.io", "v1", "endpointslices"): {
Stub: `{"metadata": {"name": "slicev1"}, "addressType": "IPv4", "protocol": "TCP", "ports": [], "endpoints": []}`,
ExpectedEtcdPath: "/registry/endpointslices/" + namespace + "/slicev1",
},
// --
// k8s.io/kubernetes/pkg/apis/events/v1
gvr("events.k8s.io", "v1", "events"): {
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"}`,
ExpectedEtcdPath: "/registry/events/" + namespace + "/event3",
ExpectedGVK: gvkP("", "v1", "Event"),
},
// --
// k8s.io/kubernetes/pkg/apis/networking/v1
gvr("networking.k8s.io", "v1", "ingresses"): {
Stub: `{"metadata": {"name": "ingress3"}, "spec": {"defaultBackend": {"service":{"name":"service", "port":{"number": 5000}}}}}`,
ExpectedEtcdPath: "/registry/ingress/" + namespace + "/ingress3",
},
gvr("networking.k8s.io", "v1", "ingressclasses"): {
Stub: `{"metadata": {"name": "ingressclass3"}, "spec": {"controller": "example.com/controller"}}`,
ExpectedEtcdPath: "/registry/ingressclasses/ingressclass3",
},
gvr("networking.k8s.io", "v1", "networkpolicies"): {
Stub: `{"metadata": {"name": "np2"}, "spec": {"podSelector": {"matchLabels": {"e": "f"}}}}`,
ExpectedEtcdPath: "/registry/networkpolicies/" + namespace + "/np2",
},
// --
// k8s.io/kubernetes/pkg/apis/networking/v1beta1
gvr("networking.k8s.io", "v1beta1", "ipaddresses"): {
Stub: `{"metadata": {"name": "192.168.1.3"}, "spec": {"parentRef": {"resource": "services","name": "test", "namespace": "ns"}}}`,
ExpectedEtcdPath: "/registry/ipaddresses/192.168.1.3",
},
// --
// k8s.io/kubernetes/pkg/apis/networking/v1beta1
gvr("networking.k8s.io", "v1beta1", "servicecidrs"): {
Stub: `{"metadata": {"name": "range-b1"}, "spec": {"cidrs": ["192.168.0.0/16","fd00:1::/120"]}}`,
ExpectedEtcdPath: "/registry/servicecidrs/range-b1",
},
// --
// k8s.io/kubernetes/pkg/apis/policy/v1
gvr("policy", "v1", "poddisruptionbudgets"): {
Stub: `{"metadata": {"name": "pdbv1"}, "spec": {"selector": {"matchLabels": {"anokkey": "anokvalue"}}}}`,
ExpectedEtcdPath: "/registry/poddisruptionbudgets/" + namespace + "/pdbv1",
},
// --
// k8s.io/kubernetes/pkg/apis/storagemigration/v1alpha1
gvr("storagemigration.k8s.io", "v1alpha1", "storageversionmigrations"): {
Stub: `{"metadata": {"name": "test-migration"}, "spec":{"resource": {"group": "test-group", "resource": "test-resource", "version": "test-version"}}}`,
ExpectedEtcdPath: "/registry/storageversionmigrations/test-migration",
},
// --
// k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta3
gvr("flowcontrol.apiserver.k8s.io", "v1beta3", "flowschemas"): {
Stub: `{"metadata": {"name": "fs-2"}, "spec": {"priorityLevelConfiguration": {"name": "name1"}}}`,
ExpectedEtcdPath: "/registry/flowschemas/fs-2",
ExpectedGVK: gvkP("flowcontrol.apiserver.k8s.io", "v1", "FlowSchema"),
},
// --
// k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta3
gvr("flowcontrol.apiserver.k8s.io", "v1beta3", "prioritylevelconfigurations"): {
Stub: `{"metadata": {"name": "conf4"}, "spec": {"type": "Limited", "limited": {"nominalConcurrencyShares":3, "limitResponse": {"type": "Reject"}}}}`,
ExpectedEtcdPath: "/registry/prioritylevelconfigurations/conf4",
ExpectedGVK: gvkP("flowcontrol.apiserver.k8s.io", "v1", "PriorityLevelConfiguration"),
},
// --
// k8s.io/kubernetes/pkg/apis/flowcontrol/v1
gvr("flowcontrol.apiserver.k8s.io", "v1", "flowschemas"): {
Stub: `{"metadata": {"name": "fs-3"}, "spec": {"priorityLevelConfiguration": {"name": "name1"}}}`,
ExpectedEtcdPath: "/registry/flowschemas/fs-3",
},
// --
// k8s.io/kubernetes/pkg/apis/flowcontrol/v1
gvr("flowcontrol.apiserver.k8s.io", "v1", "prioritylevelconfigurations"): {
Stub: `{"metadata": {"name": "conf5"}, "spec": {"type": "Limited", "limited": {"nominalConcurrencyShares":3, "limitResponse": {"type": "Reject"}}}}`,
ExpectedEtcdPath: "/registry/prioritylevelconfigurations/conf5",
},
// --
// k8s.io/kubernetes/pkg/apis/storage/v1
gvr("storage.k8s.io", "v1", "volumeattachments"): {
Stub: `{"metadata": {"name": "va3"}, "spec": {"attacher": "gce", "nodeName": "localhost", "source": {"persistentVolumeName": "pv3"}}}`,
ExpectedEtcdPath: "/registry/volumeattachments/va3",
},
// --
// k8s.io/kubernetes/pkg/apis/storage/v1alpha1
gvr("storage.k8s.io", "v1alpha1", "volumeattributesclasses"): {
Stub: `{"metadata": {"name": "vac1"}, "driverName": "example.com/driver", "parameters": {"foo": "bar"}}`,
ExpectedEtcdPath: "/registry/volumeattributesclasses/vac1",
},
// --
// k8s.io/kubernetes/pkg/apis/storage/v1
gvr("storage.k8s.io", "v1", "storageclasses"): {
Stub: `{"metadata": {"name": "sc2"}, "provisioner": "aws"}`,
ExpectedEtcdPath: "/registry/storageclasses/sc2",
},
gvr("storage.k8s.io", "v1", "csistoragecapacities"): {
Stub: `{"metadata": {"name": "csc-12345-3"}, "storageClassName": "sc1"}`,
ExpectedEtcdPath: "/registry/csistoragecapacities/" + namespace + "/csc-12345-3",
},
// --
// k8s.io/kubernetes/pkg/apis/rbac/v1
gvr("rbac.authorization.k8s.io", "v1", "roles"): {
Stub: `{"metadata": {"name": "role3"}, "rules": [{"apiGroups": ["v1"], "resources": ["events"], "verbs": ["watch"]}]}`,
ExpectedEtcdPath: "/registry/roles/" + namespace + "/role3",
},
gvr("rbac.authorization.k8s.io", "v1", "clusterroles"): {
Stub: `{"metadata": {"name": "crole3"}, "rules": [{"nonResourceURLs": ["/version"], "verbs": ["get"]}]}`,
ExpectedEtcdPath: "/registry/clusterroles/crole3",
},
gvr("rbac.authorization.k8s.io", "v1", "rolebindings"): {
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"}]}`,
ExpectedEtcdPath: "/registry/rolebindings/" + namespace + "/roleb3",
},
gvr("rbac.authorization.k8s.io", "v1", "clusterrolebindings"): {
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"}]}`,
ExpectedEtcdPath: "/registry/clusterrolebindings/croleb3",
},
// --
// k8s.io/kubernetes/pkg/apis/admissionregistration/v1
gvr("admissionregistration.k8s.io", "v1", "validatingwebhookconfigurations"): {
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"]}]}`,
ExpectedEtcdPath: "/registry/validatingwebhookconfigurations/hook2",
},
gvr("admissionregistration.k8s.io", "v1", "mutatingwebhookconfigurations"): {
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"]}]}`,
ExpectedEtcdPath: "/registry/mutatingwebhookconfigurations/hook2",
},
gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicies"): {
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"}]}}`,
ExpectedEtcdPath: "/registry/validatingadmissionpolicies/vap1",
},
gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicybindings"): {
Stub: `{"metadata":{"name":"pb1","creationTimestamp":null},"spec":{"policyName":"replicalimit-policy.example.com","paramRef":{"name":"replica-limit-test.example.com","parameterNotFoundAction":"Deny"},"validationActions":["Deny"]}}`,
ExpectedEtcdPath: "/registry/validatingadmissionpolicybindings/pb1",
},
// --
// k8s.io/kubernetes/pkg/apis/admissionregistration/v1beta1
gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies"): {
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"}]}}`,
ExpectedEtcdPath: "/registry/validatingadmissionpolicies/vap1b1",
ExpectedGVK: gvkP("admissionregistration.k8s.io", "v1", "ValidatingAdmissionPolicy"),
},
gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicybindings"): {
Stub: `{"metadata":{"name":"pb1b1","creationTimestamp":null},"spec":{"policyName":"replicalimit-policy.example.com","paramRef":{"name":"replica-limit-test.example.com","parameterNotFoundAction":"Deny"},"validationActions":["Deny"]}}`,
ExpectedEtcdPath: "/registry/validatingadmissionpolicybindings/pb1b1",
ExpectedGVK: gvkP("admissionregistration.k8s.io", "v1", "ValidatingAdmissionPolicyBinding"),
},
// --
// k8s.io/kubernetes/pkg/apis/admissionregistration/v1alpha1
gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies"): {
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"}]}}`,
ExpectedEtcdPath: "/registry/validatingadmissionpolicies/vap1a1",
ExpectedGVK: gvkP("admissionregistration.k8s.io", "v1", "ValidatingAdmissionPolicy"),
},
gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicybindings"): {
Stub: `{"metadata":{"name":"pb1a1","creationTimestamp":null},"spec":{"policyName":"replicalimit-policy.example.com","paramRef":{"name":"replica-limit-test.example.com"},"validationActions":["Deny"]}}`,
ExpectedEtcdPath: "/registry/validatingadmissionpolicybindings/pb1a1",
ExpectedGVK: gvkP("admissionregistration.k8s.io", "v1", "ValidatingAdmissionPolicyBinding"),
},
// --
// k8s.io/kubernetes/pkg/apis/scheduling/v1
gvr("scheduling.k8s.io", "v1", "priorityclasses"): {
Stub: `{"metadata":{"name":"pc3"},"Value":1000}`,
ExpectedEtcdPath: "/registry/priorityclasses/pc3",
},
// --
// k8s.io/kube-aggregator/pkg/apis/apiregistration/v1
// depends on aggregator using the same ungrouped RESTOptionsGetter as the kube apiserver, not SimpleRestOptionsFactory in aggregator.go
gvr("apiregistration.k8s.io", "v1", "apiservices"): {
Stub: `{"metadata": {"name": "as2.foo.com"}, "spec": {"group": "foo.com", "version": "as2", "groupPriorityMinimum":100, "versionPriority":10}}`,
ExpectedEtcdPath: "/registry/apiregistration.k8s.io/apiservices/as2.foo.com",
},
// --
// k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1
gvr("apiextensions.k8s.io", "v1", "customresourcedefinitions"): {
Stub: `{"metadata": {"name": "openshiftwebconsoleconfigs.webconsole2.operator.openshift.io"},"spec": {` +
`"scope": "Cluster","group": "webconsole2.operator.openshift.io",` +
`"versions": [{"name":"v1alpha1","storage":true,"served":true,"schema":{"openAPIV3Schema":{"type":"object"}}}],` +
`"names": {"kind": "OpenShiftWebConsoleConfig","plural": "openshiftwebconsoleconfigs","singular": "openshiftwebconsoleconfig"}}}`,
ExpectedEtcdPath: "/registry/apiextensions.k8s.io/customresourcedefinitions/openshiftwebconsoleconfigs.webconsole2.operator.openshift.io",
ExpectedGVK: gvkP("apiextensions.k8s.io", "v1beta1", "CustomResourceDefinition"),
},
gvr("cr.bar.com", "v1", "foos"): {
Stub: `{"kind": "Foo", "apiVersion": "cr.bar.com/v1", "metadata": {"name": "cr1foo"}, "color": "blue"}`, // requires TypeMeta due to CRD scheme's UnstructuredObjectTyper
ExpectedEtcdPath: "/registry/cr.bar.com/foos/" + namespace + "/cr1foo",
},
gvr("custom.fancy.com", "v2", "pants"): {
Stub: `{"kind": "Pant", "apiVersion": "custom.fancy.com/v2", "metadata": {"name": "cr2pant"}, "isFancy": true}`, // requires TypeMeta due to CRD scheme's UnstructuredObjectTyper
ExpectedEtcdPath: "/registry/custom.fancy.com/pants/cr2pant",
},
gvr("awesome.bears.com", "v1", "pandas"): {
Stub: `{"kind": "Panda", "apiVersion": "awesome.bears.com/v1", "metadata": {"name": "cr3panda"}, "spec":{"replicas": 100}}`, // requires TypeMeta due to CRD scheme's UnstructuredObjectTyper
ExpectedEtcdPath: "/registry/awesome.bears.com/pandas/cr3panda",
},
gvr("awesome.bears.com", "v3", "pandas"): {
Stub: `{"kind": "Panda", "apiVersion": "awesome.bears.com/v3", "metadata": {"name": "cr4panda"}, "spec":{"replicas": 300}}`, // requires TypeMeta due to CRD scheme's UnstructuredObjectTyper
ExpectedEtcdPath: "/registry/awesome.bears.com/pandas/cr4panda",
ExpectedGVK: gvkP("awesome.bears.com", "v1", "Panda"),
},
gvr("random.numbers.com", "v1", "integers"): {
Stub: `{"kind": "Integer", "apiVersion": "random.numbers.com/v1", "metadata": {"name": "fortytwo"}, "value": 42, "garbage": "oiujnasdf"}`, // requires TypeMeta due to CRD scheme's UnstructuredObjectTyper
ExpectedEtcdPath: "/registry/random.numbers.com/integers/fortytwo",
},
// --
// k8s.io/kubernetes/pkg/apis/node/v1
gvr("node.k8s.io", "v1", "runtimeclasses"): {
Stub: `{"metadata": {"name": "rc3"}, "handler": "h3"}`,
ExpectedEtcdPath: "/registry/runtimeclasses/rc3",
},
// --
// k8s.io/kubernetes/pkg/apis/resource/v1alpha3
gvr("resource.k8s.io", "v1alpha3", "resourceclasses"): {
Stub: `{"metadata": {"name": "class1name"}, "driverName": "example.com"}`,
ExpectedEtcdPath: "/registry/resourceclasses/class1name",
},
gvr("resource.k8s.io", "v1alpha3", "resourceclaims"): {
Stub: `{"metadata": {"name": "claim1name"}, "spec": {"resourceClassName": "class1name", "allocationMode": "WaitForFirstConsumer"}}`,
ExpectedEtcdPath: "/registry/resourceclaims/" + namespace + "/claim1name",
},
gvr("resource.k8s.io", "v1alpha3", "resourceclaimtemplates"): {
Stub: `{"metadata": {"name": "claimtemplate1name"}, "spec": {"spec": {"resourceClassName": "class1name", "allocationMode": "WaitForFirstConsumer"}}}`,
ExpectedEtcdPath: "/registry/resourceclaimtemplates/" + namespace + "/claimtemplate1name",
},
gvr("resource.k8s.io", "v1alpha3", "podschedulingcontexts"): {
Stub: `{"metadata": {"name": "pod1name"}, "spec": {"selectedNode": "node1name", "potentialNodes": ["node1name", "node2name"]}}`,
ExpectedEtcdPath: "/registry/podschedulingcontexts/" + namespace + "/pod1name",
},
gvr("resource.k8s.io", "v1alpha3", "resourceclassparameters"): {
Stub: `{"metadata": {"name": "class1parameters"}}`,
ExpectedEtcdPath: "/registry/resourceclassparameters/" + namespace + "/class1parameters",
},
gvr("resource.k8s.io", "v1alpha3", "resourceclaimparameters"): {
Stub: `{"metadata": {"name": "claim1parameters"}}`,
ExpectedEtcdPath: "/registry/resourceclaimparameters/" + namespace + "/claim1parameters",
},
gvr("resource.k8s.io", "v1alpha3", "resourceslices"): {
Stub: `{"metadata": {"name": "node1slice"}, "nodeName": "worker1", "driverName": "dra.example.com", "namedResources": {}}`,
ExpectedEtcdPath: "/registry/resourceslices/node1slice",
},
// --
// k8s.io/apiserver/pkg/apis/apiserverinternal/v1alpha1
gvr("internal.apiserver.k8s.io", "v1alpha1", "storageversions"): {
Stub: `{"metadata":{"name":"sv1.test"},"spec":{}}`,
ExpectedEtcdPath: "/registry/storageversions/sv1.test",
},
// --
}
// add csinodes
// k8s.io/kubernetes/pkg/apis/storage/v1
etcdStorageData[gvr("storage.k8s.io", "v1", "csinodes")] = StorageData{
Stub: `{"metadata": {"name": "csini2"}, "spec": {"drivers": [{"name": "test-driver", "nodeID": "localhost", "topologyKeys": ["company.com/zone1", "company.com/zone2"]}]}}`,
ExpectedEtcdPath: "/registry/csinodes/csini2",
}
// add csidrivers
// k8s.io/kubernetes/pkg/apis/storage/v1
etcdStorageData[gvr("storage.k8s.io", "v1", "csidrivers")] = StorageData{
Stub: `{"metadata": {"name": "csid2"}, "spec": {"attachRequired": true, "podInfoOnMount": true}}`,
ExpectedEtcdPath: "/registry/csidrivers/csid2",
}
return etcdStorageData
}
// StorageData contains information required to create an object and verify its storage in etcd
// It must be paired with a specific resource
type StorageData struct {
Stub string // Valid JSON stub to use during create
Prerequisites []Prerequisite // Optional, ordered list of JSON objects to create before stub
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
ExpectedGVK *schema.GroupVersionKind // The GVK that we expect this object to be stored as - leave this nil to use the default
}
// Prerequisite contains information required to create a resource (but not verify it)
type Prerequisite struct {
GvrData schema.GroupVersionResource
Stub string
}
// GetCustomResourceDefinitionData returns the resource definitions that back the custom resources
// included in GetEtcdStorageData. They should be created using CreateTestCRDs before running any tests.
// We can switch this to v1 CRDs based on transitive call site analysis.
// Call sites:
// 1. TestDedupOwnerReferences - beta doesn't matter
// 2. TestWebhookAdmissionWithWatchCache/TestWebhookAdmissionWithoutWatchCache - beta doesn't matter
// 3. TestApplyStatus - the version fields don't matter. Pruning isn't checked, just ownership.
// 4. TestDryRun - versions and pruning don't matter
// 5. TestStorageVersionBootstrap - versions and pruning don't matter.
// 6. TestEtcdStoragePath - beta doesn't matter
// 7. TestCrossGroupStorage - beta doesn't matter
// 8. TestOverlappingCustomResourceCustomResourceDefinition - beta doesn't matter
// 9. TestOverlappingCustomResourceAPIService - beta doesn't matter
func GetCustomResourceDefinitionData() []*apiextensionsv1.CustomResourceDefinition {
return []*apiextensionsv1.CustomResourceDefinition{
// namespaced
{
ObjectMeta: metav1.ObjectMeta{
Name: "foos.cr.bar.com",
},
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
Group: "cr.bar.com",
Scope: apiextensionsv1.NamespaceScoped,
Names: apiextensionsv1.CustomResourceDefinitionNames{
Plural: "foos",
Kind: "Foo",
},
Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
{
Name: "v1",
Served: true,
Storage: true,
Schema: fixtures.AllowAllSchema(),
},
},
},
},
// cluster scoped
{
ObjectMeta: metav1.ObjectMeta{
Name: "pants.custom.fancy.com",
},
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
Group: "custom.fancy.com",
Scope: apiextensionsv1.ClusterScoped,
Names: apiextensionsv1.CustomResourceDefinitionNames{
Plural: "pants",
Kind: "Pant",
},
Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
{
Name: "v2",
Served: true,
Storage: true,
Schema: fixtures.AllowAllSchema(),
},
},
},
},
// cluster scoped with legacy version field and pruning.
{
ObjectMeta: metav1.ObjectMeta{
Name: "integers.random.numbers.com",
},
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
Group: "random.numbers.com",
Scope: apiextensionsv1.ClusterScoped,
Names: apiextensionsv1.CustomResourceDefinitionNames{
Plural: "integers",
Kind: "Integer",
},
Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
{
Name: "v1",
Served: true,
Storage: true,
Schema: &apiextensionsv1.CustomResourceValidation{
OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
Type: "object",
Properties: map[string]apiextensionsv1.JSONSchemaProps{
"value": {
Type: "number",
},
},
}},
},
},
},
},
// cluster scoped with versions field
{
ObjectMeta: metav1.ObjectMeta{
Name: "pandas.awesome.bears.com",
},
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
Group: "awesome.bears.com",
Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
{
Name: "v1",
Served: true,
Storage: true,
Schema: fixtures.AllowAllSchema(),
Subresources: &apiextensionsv1.CustomResourceSubresources{
Status: &apiextensionsv1.CustomResourceSubresourceStatus{},
Scale: &apiextensionsv1.CustomResourceSubresourceScale{
SpecReplicasPath: ".spec.replicas",
StatusReplicasPath: ".status.replicas",
LabelSelectorPath: func() *string { path := ".status.selector"; return &path }(),
},
},
},
{
Name: "v2",
Served: false,
Storage: false,
Schema: fixtures.AllowAllSchema(),
Subresources: &apiextensionsv1.CustomResourceSubresources{
Status: &apiextensionsv1.CustomResourceSubresourceStatus{},
Scale: &apiextensionsv1.CustomResourceSubresourceScale{
SpecReplicasPath: ".spec.replicas",
StatusReplicasPath: ".status.replicas",
LabelSelectorPath: func() *string { path := ".status.selector"; return &path }(),
},
},
},
{
Name: "v3",
Served: true,
Storage: false,
Schema: fixtures.AllowAllSchema(),
Subresources: &apiextensionsv1.CustomResourceSubresources{
Status: &apiextensionsv1.CustomResourceSubresourceStatus{},
Scale: &apiextensionsv1.CustomResourceSubresourceScale{
SpecReplicasPath: ".spec.replicas",
StatusReplicasPath: ".status.replicas",
LabelSelectorPath: func() *string { path := ".status.selector"; return &path }(),
},
},
},
},
Scope: apiextensionsv1.ClusterScoped,
Names: apiextensionsv1.CustomResourceDefinitionNames{
Plural: "pandas",
Kind: "Panda",
},
},
},
}
}
func gvr(g, v, r string) schema.GroupVersionResource {
return schema.GroupVersionResource{Group: g, Version: v, Resource: r}
}
func gvkP(g, v, k string) *schema.GroupVersionKind {
return &schema.GroupVersionKind{Group: g, Version: v, Kind: k}
}
func gvk(g, v, k string) schema.GroupVersionKind {
return schema.GroupVersionKind{Group: g, Version: v, Kind: k}
}