mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 12:15:52 +00:00
Merge pull request #70019 from enj/enj/t/shared_etcd_stubs
Refactor dry run test to reuse ETCD storage data
This commit is contained in:
commit
77a1199b6c
@ -17,28 +17,18 @@ go_test(
|
||||
"integration",
|
||||
],
|
||||
deps = [
|
||||
"//cmd/kube-apiserver/app:go_default_library",
|
||||
"//cmd/kube-apiserver/app/options:go_default_library",
|
||||
"//pkg/master:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/features:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/server/options:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/util/feature/testing:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/discovery/cached:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/dynamic:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/restmapper:go_default_library",
|
||||
"//test/integration/etcd:go_default_library",
|
||||
"//test/integration/framework:go_default_library",
|
||||
],
|
||||
)
|
||||
|
@ -17,354 +17,22 @@ limitations under the License.
|
||||
package dryrun
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apiserver/pkg/features"
|
||||
genericapiserveroptions "k8s.io/apiserver/pkg/server/options"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing"
|
||||
cacheddiscovery "k8s.io/client-go/discovery/cached"
|
||||
"k8s.io/client-go/dynamic"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/restmapper"
|
||||
"k8s.io/kubernetes/cmd/kube-apiserver/app"
|
||||
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
|
||||
"k8s.io/kubernetes/test/integration/framework"
|
||||
|
||||
// install all APIs
|
||||
_ "k8s.io/kubernetes/pkg/master" // TODO what else is needed
|
||||
"k8s.io/kubernetes/test/integration/etcd"
|
||||
)
|
||||
|
||||
// dryrun data for all persisted objects.
|
||||
var dryrunData = map[schema.GroupVersionResource]struct {
|
||||
stub string // Valid JSON stub to use during create
|
||||
}{
|
||||
// k8s.io/kubernetes/pkg/api/v1
|
||||
gvr("", "v1", "configmaps"): {
|
||||
stub: `{"data": {"foo": "bar"}, "metadata": {"name": "cm1"}}`,
|
||||
},
|
||||
gvr("", "v1", "services"): {
|
||||
stub: `{"metadata": {"name": "service1"}, "spec": {"externalName": "service1name", "ports": [{"port": 10000, "targetPort": 11000}], "selector": {"test": "data"}}}`,
|
||||
},
|
||||
gvr("", "v1", "podtemplates"): {
|
||||
stub: `{"metadata": {"name": "pt1name"}, "template": {"metadata": {"labels": {"pt": "01"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container9"}]}}}`,
|
||||
},
|
||||
gvr("", "v1", "pods"): {
|
||||
stub: `{"metadata": {"name": "pod1"}, "spec": {"containers": [{"image": "fedora:latest", "name": "container7", "resources": {"limits": {"cpu": "1M"}, "requests": {"cpu": "1M"}}}]}}`,
|
||||
},
|
||||
gvr("", "v1", "endpoints"): {
|
||||
stub: `{"metadata": {"name": "ep1name"}, "subsets": [{"addresses": [{"hostname": "bar-001", "ip": "192.168.3.1"}], "ports": [{"port": 8000}]}]}`,
|
||||
},
|
||||
gvr("", "v1", "resourcequotas"): {
|
||||
stub: `{"metadata": {"name": "rq1name"}, "spec": {"hard": {"cpu": "5M"}}}`,
|
||||
},
|
||||
gvr("", "v1", "limitranges"): {
|
||||
stub: `{"metadata": {"name": "lr1name"}, "spec": {"limits": [{"type": "Pod"}]}}`,
|
||||
},
|
||||
gvr("", "v1", "namespaces"): {
|
||||
stub: `{"metadata": {"name": "namespace2"}, "spec": {"finalizers": ["kubernetes"]}}`,
|
||||
},
|
||||
gvr("", "v1", "nodes"): {
|
||||
stub: `{"metadata": {"name": "node1"}, "spec": {"unschedulable": true}}`,
|
||||
},
|
||||
gvr("", "v1", "persistentvolumes"): {
|
||||
stub: `{"metadata": {"name": "pv1name"}, "spec": {"accessModes": ["ReadWriteOnce"], "capacity": {"storage": "3M"}, "hostPath": {"path": "/tmp/test/"}}}`,
|
||||
},
|
||||
gvr("", "v1", "events"): {
|
||||
stub: `{"involvedObject": {"namespace": "dryrunnamespace"}, "message": "some data here", "metadata": {"name": "event1"}}`,
|
||||
},
|
||||
gvr("", "v1", "persistentvolumeclaims"): {
|
||||
stub: `{"metadata": {"name": "pvc1"}, "spec": {"accessModes": ["ReadWriteOnce"], "resources": {"limits": {"storage": "1M"}, "requests": {"storage": "2M"}}, "selector": {"matchLabels": {"pvc": "stuff"}}}}`,
|
||||
},
|
||||
gvr("", "v1", "serviceaccounts"): {
|
||||
stub: `{"metadata": {"name": "sa1name"}, "secrets": [{"name": "secret00"}]}`,
|
||||
},
|
||||
gvr("", "v1", "secrets"): {
|
||||
stub: `{"data": {"key": "ZGF0YSBmaWxl"}, "metadata": {"name": "secret1"}}`,
|
||||
},
|
||||
gvr("", "v1", "replicationcontrollers"): {
|
||||
stub: `{"metadata": {"name": "rc1"}, "spec": {"selector": {"new": "stuff"}, "template": {"metadata": {"labels": {"new": "stuff"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container8"}]}}}}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/apps/v1beta1
|
||||
gvr("apps", "v1beta1", "statefulsets"): {
|
||||
stub: `{"metadata": {"name": "ss1"}, "spec": {"selector": {"matchLabels": {"a": "b"}}, "template": {"metadata": {"labels": {"a": "b"}}}}}`,
|
||||
},
|
||||
gvr("apps", "v1beta1", "deployments"): {
|
||||
stub: `{"metadata": {"name": "deployment2"}, "spec": {"selector": {"matchLabels": {"f": "z"}}, "template": {"metadata": {"labels": {"f": "z"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container6"}]}}}}`,
|
||||
},
|
||||
gvr("apps", "v1beta1", "controllerrevisions"): {
|
||||
stub: `{"metadata":{"name":"crs1"},"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}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/apps/v1beta2
|
||||
gvr("apps", "v1beta2", "statefulsets"): {
|
||||
stub: `{"metadata": {"name": "ss2"}, "spec": {"selector": {"matchLabels": {"a": "b"}}, "template": {"metadata": {"labels": {"a": "b"}}}}}`,
|
||||
},
|
||||
gvr("apps", "v1beta2", "deployments"): {
|
||||
stub: `{"metadata": {"name": "deployment3"}, "spec": {"selector": {"matchLabels": {"f": "z"}}, "template": {"metadata": {"labels": {"f": "z"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container6"}]}}}}`,
|
||||
},
|
||||
gvr("apps", "v1beta2", "daemonsets"): {
|
||||
stub: `{"metadata": {"name": "ds5"}, "spec": {"selector": {"matchLabels": {"a": "b"}}, "template": {"metadata": {"labels": {"a": "b"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container6"}]}}}}`,
|
||||
},
|
||||
gvr("apps", "v1beta2", "replicasets"): {
|
||||
stub: `{"metadata": {"name": "rs2"}, "spec": {"selector": {"matchLabels": {"g": "h"}}, "template": {"metadata": {"labels": {"g": "h"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container4"}]}}}}`,
|
||||
},
|
||||
gvr("apps", "v1beta2", "controllerrevisions"): {
|
||||
stub: `{"metadata":{"name":"crs2"},"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}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// 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": "fedora:latest", "name": "container6"}]}}}}`,
|
||||
},
|
||||
gvr("apps", "v1", "deployments"): {
|
||||
stub: `{"metadata": {"name": "deployment4"}, "spec": {"selector": {"matchLabels": {"f": "z"}}, "template": {"metadata": {"labels": {"f": "z"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container6"}]}}}}`,
|
||||
},
|
||||
gvr("apps", "v1", "statefulsets"): {
|
||||
stub: `{"metadata": {"name": "ss3"}, "spec": {"selector": {"matchLabels": {"a": "b"}}, "template": {"metadata": {"labels": {"a": "b"}}}}}`,
|
||||
},
|
||||
gvr("apps", "v1", "replicasets"): {
|
||||
stub: `{"metadata": {"name": "rs3"}, "spec": {"selector": {"matchLabels": {"g": "h"}}, "template": {"metadata": {"labels": {"g": "h"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container4"}]}}}}`,
|
||||
},
|
||||
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}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/autoscaling/v1
|
||||
gvr("autoscaling", "v1", "horizontalpodautoscalers"): {
|
||||
stub: `{"metadata": {"name": "hpa2"}, "spec": {"maxReplicas": 3, "scaleTargetRef": {"kind": "something", "name": "cross"}}}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/autoscaling/v2beta1
|
||||
gvr("autoscaling", "v2beta1", "horizontalpodautoscalers"): {
|
||||
stub: `{"metadata": {"name": "hpa1"}, "spec": {"maxReplicas": 3, "scaleTargetRef": {"kind": "something", "name": "cross"}}}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/autoscaling/v2beta2
|
||||
gvr("autoscaling", "v2beta2", "horizontalpodautoscalers"): {
|
||||
stub: `{"metadata": {"name": "hpa3"}, "spec": {"maxReplicas": 3, "scaleTargetRef": {"kind": "something", "name": "cross"}}}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// 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": "fedora:latest", "name": "container1"}], "dnsPolicy": "ClusterFirst", "restartPolicy": "Never"}}}}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/batch/v1beta1
|
||||
gvr("batch", "v1beta1", "cronjobs"): {
|
||||
stub: `{"metadata": {"name": "cjv1beta1"}, "spec": {"jobTemplate": {"spec": {"template": {"metadata": {"labels": {"controller-uid": "uid0"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container0"}], "dnsPolicy": "ClusterFirst", "restartPolicy": "Never"}}}}, "schedule": "* * * * *"}}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/batch/v2alpha1
|
||||
gvr("batch", "v2alpha1", "cronjobs"): {
|
||||
stub: `{"metadata": {"name": "cjv2alpha1"}, "spec": {"jobTemplate": {"spec": {"template": {"metadata": {"labels": {"controller-uid": "uid0"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container0"}], "dnsPolicy": "ClusterFirst", "restartPolicy": "Never"}}}}, "schedule": "* * * * *"}}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/certificates/v1beta1
|
||||
gvr("certificates.k8s.io", "v1beta1", "certificatesigningrequests"): {
|
||||
stub: `{"metadata": {"name": "csr1"}, "spec": {"request": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQnlqQ0NBVE1DQVFBd2dZa3hDekFKQmdOVkJBWVRBbFZUTVJNd0VRWURWUVFJRXdwRFlXeHBabTl5Ym1saApNUll3RkFZRFZRUUhFdzFOYjNWdWRHRnBiaUJXYVdWM01STXdFUVlEVlFRS0V3cEhiMjluYkdVZ1NXNWpNUjh3CkhRWURWUVFMRXhaSmJtWnZjbTFoZEdsdmJpQlVaV05vYm05c2IyZDVNUmN3RlFZRFZRUURFdzUzZDNjdVoyOXYKWjJ4bExtTnZiVENCbnpBTkJna3Foa2lHOXcwQkFRRUZBQU9CalFBd2dZa0NnWUVBcFp0WUpDSEo0VnBWWEhmVgpJbHN0UVRsTzRxQzAzaGpYK1prUHl2ZFlkMVE0K3FiQWVUd1htQ1VLWUhUaFZSZDVhWFNxbFB6eUlCd2llTVpyCldGbFJRZGRaMUl6WEFsVlJEV3dBbzYwS2VjcWVBWG5uVUsrNWZYb1RJL1VnV3NocmU4dEoreC9UTUhhUUtSL0oKY0lXUGhxYVFoc0p1elpidkFkR0E4MEJMeGRNQ0F3RUFBYUFBTUEwR0NTcUdTSWIzRFFFQkJRVUFBNEdCQUlobAo0UHZGcStlN2lwQVJnSTVaTStHWng2bXBDejQ0RFRvMEprd2ZSRGYrQnRyc2FDMHE2OGVUZjJYaFlPc3E0ZmtIClEwdUEwYVZvZzNmNWlKeENhM0hwNWd4YkpRNnpWNmtKMFRFc3VhYU9oRWtvOXNkcENvUE9uUkJtMmkvWFJEMkQKNmlOaDhmOHowU2hHc0ZxakRnRkh5RjNvK2xVeWorVUM2SDFRVzdibgotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0="}}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/coordination/v1beta1
|
||||
gvr("coordination.k8s.io", "v1beta1", "leases"): {
|
||||
stub: `{"metadata": {"name": "lease1"}, "spec": {"holderIdentity": "holder", "leaseDurationSeconds": 5}}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/events/v1beta1
|
||||
gvr("events.k8s.io", "v1beta1", "events"): {
|
||||
stub: `{"metadata": {"name": "event2"}, "regarding": {"namespace": "dryrunnamespace"}, "note": "some data here", "eventTime": "2017-08-09T15:04:05.000000Z", "reportingInstance": "node-xyz", "reportingController": "k8s.io/my-controller", "action": "DidNothing", "reason": "Laziness"}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/extensions/v1beta1
|
||||
gvr("extensions", "v1beta1", "daemonsets"): {
|
||||
stub: `{"metadata": {"name": "ds1"}, "spec": {"selector": {"matchLabels": {"u": "t"}}, "template": {"metadata": {"labels": {"u": "t"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container5"}]}}}}`,
|
||||
},
|
||||
gvr("extensions", "v1beta1", "podsecuritypolicies"): {
|
||||
stub: `{"metadata": {"name": "psp1"}, "spec": {"fsGroup": {"rule": "RunAsAny"}, "privileged": true, "runAsUser": {"rule": "RunAsAny"}, "seLinux": {"rule": "MustRunAs"}, "supplementalGroups": {"rule": "RunAsAny"}}}`,
|
||||
},
|
||||
gvr("extensions", "v1beta1", "ingresses"): {
|
||||
stub: `{"metadata": {"name": "ingress1"}, "spec": {"backend": {"serviceName": "service", "servicePort": 5000}}}`,
|
||||
},
|
||||
gvr("extensions", "v1beta1", "networkpolicies"): {
|
||||
stub: `{"metadata": {"name": "np1"}, "spec": {"podSelector": {"matchLabels": {"e": "f"}}}}`,
|
||||
},
|
||||
gvr("extensions", "v1beta1", "deployments"): {
|
||||
stub: `{"metadata": {"name": "deployment1"}, "spec": {"selector": {"matchLabels": {"f": "z"}}, "template": {"metadata": {"labels": {"f": "z"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container6"}]}}}}`,
|
||||
},
|
||||
gvr("extensions", "v1beta1", "replicasets"): {
|
||||
stub: `{"metadata": {"name": "rs1"}, "spec": {"selector": {"matchLabels": {"g": "h"}}, "template": {"metadata": {"labels": {"g": "h"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container4"}]}}}}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/networking/v1
|
||||
gvr("networking.k8s.io", "v1", "networkpolicies"): {
|
||||
stub: `{"metadata": {"name": "np2"}, "spec": {"podSelector": {"matchLabels": {"e": "f"}}}}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/policy/v1beta1
|
||||
gvr("policy", "v1beta1", "poddisruptionbudgets"): {
|
||||
stub: `{"metadata": {"name": "pdb1"}, "spec": {"selector": {"matchLabels": {"anokkey": "anokvalue"}}}}`,
|
||||
},
|
||||
gvr("policy", "v1beta1", "podsecuritypolicies"): {
|
||||
stub: `{"metadata": {"name": "psp2"}, "spec": {"fsGroup": {"rule": "RunAsAny"}, "privileged": true, "runAsUser": {"rule": "RunAsAny"}, "seLinux": {"rule": "MustRunAs"}, "supplementalGroups": {"rule": "RunAsAny"}}}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/storage/v1alpha1
|
||||
gvr("storage.k8s.io", "v1alpha1", "volumeattachments"): {
|
||||
stub: `{"metadata": {"name": "va1"}, "spec": {"attacher": "gce", "nodeName": "localhost", "source": {"persistentVolumeName": "pv1"}}}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/storage/v1beta1
|
||||
gvr("storage.k8s.io", "v1beta1", "volumeattachments"): {
|
||||
stub: `{"metadata": {"name": "va2"}, "spec": {"attacher": "gce", "nodeName": "localhost", "source": {"persistentVolumeName": "pv2"}}}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/storage/v1beta1
|
||||
gvr("storage.k8s.io", "v1beta1", "storageclasses"): {
|
||||
stub: `{"metadata": {"name": "sc1"}, "provisioner": "aws"}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/storage/v1
|
||||
gvr("storage.k8s.io", "v1", "storageclasses"): {
|
||||
stub: `{"metadata": {"name": "sc2"}, "provisioner": "aws"}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/settings/v1alpha1
|
||||
gvr("settings.k8s.io", "v1alpha1", "podpresets"): {
|
||||
stub: `{"metadata": {"name": "podpre1"}, "spec": {"env": [{"name": "FOO"}]}}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/rbac/v1alpha1
|
||||
gvr("rbac.authorization.k8s.io", "v1alpha1", "roles"): {
|
||||
stub: `{"metadata": {"name": "role1"}, "rules": [{"apiGroups": ["v1"], "resources": ["events"], "verbs": ["watch"]}]}`,
|
||||
},
|
||||
gvr("rbac.authorization.k8s.io", "v1alpha1", "clusterroles"): {
|
||||
stub: `{"metadata": {"name": "drcrole1"}, "rules": [{"nonResourceURLs": ["/version"], "verbs": ["get"]}]}`,
|
||||
},
|
||||
gvr("rbac.authorization.k8s.io", "v1alpha1", "rolebindings"): {
|
||||
stub: `{"metadata": {"name": "drroleb1"}, "roleRef": {"apiGroup": "rbac.authorization.k8s.io", "kind": "ClusterRole", "name": "somecr"}, "subjects": [{"apiVersion": "rbac.authorization.k8s.io/v1alpha1", "kind": "Group", "name": "system:authenticated"}]}`,
|
||||
},
|
||||
gvr("rbac.authorization.k8s.io", "v1alpha1", "clusterrolebindings"): {
|
||||
stub: `{"metadata": {"name": "drcroleb1"}, "roleRef": {"apiGroup": "rbac.authorization.k8s.io", "kind": "ClusterRole", "name": "somecr"}, "subjects": [{"apiVersion": "rbac.authorization.k8s.io/v1alpha1", "kind": "Group", "name": "system:authenticated"}]}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/rbac/v1beta1
|
||||
gvr("rbac.authorization.k8s.io", "v1beta1", "roles"): {
|
||||
stub: `{"metadata": {"name": "drrole2"}, "rules": [{"apiGroups": ["v1"], "resources": ["events"], "verbs": ["watch"]}]}`,
|
||||
},
|
||||
gvr("rbac.authorization.k8s.io", "v1beta1", "clusterroles"): {
|
||||
stub: `{"metadata": {"name": "drcrole2"}, "rules": [{"nonResourceURLs": ["/version"], "verbs": ["get"]}]}`,
|
||||
},
|
||||
gvr("rbac.authorization.k8s.io", "v1beta1", "rolebindings"): {
|
||||
stub: `{"metadata": {"name": "drroleb2"}, "roleRef": {"apiGroup": "rbac.authorization.k8s.io", "kind": "ClusterRole", "name": "somecr"}, "subjects": [{"apiVersion": "rbac.authorization.k8s.io/v1alpha1", "kind": "Group", "name": "system:authenticated"}]}`,
|
||||
},
|
||||
gvr("rbac.authorization.k8s.io", "v1beta1", "clusterrolebindings"): {
|
||||
stub: `{"metadata": {"name": "drcroleb2"}, "roleRef": {"apiGroup": "rbac.authorization.k8s.io", "kind": "ClusterRole", "name": "somecr"}, "subjects": [{"apiVersion": "rbac.authorization.k8s.io/v1alpha1", "kind": "Group", "name": "system:authenticated"}]}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/rbac/v1
|
||||
gvr("rbac.authorization.k8s.io", "v1", "roles"): {
|
||||
stub: `{"metadata": {"name": "drrole3"}, "rules": [{"apiGroups": ["v1"], "resources": ["events"], "verbs": ["watch"]}]}`,
|
||||
},
|
||||
gvr("rbac.authorization.k8s.io", "v1", "clusterroles"): {
|
||||
stub: `{"metadata": {"name": "drcrole3"}, "rules": [{"nonResourceURLs": ["/version"], "verbs": ["get"]}]}`,
|
||||
},
|
||||
gvr("rbac.authorization.k8s.io", "v1", "rolebindings"): {
|
||||
stub: `{"metadata": {"name": "drroleb3"}, "roleRef": {"apiGroup": "rbac.authorization.k8s.io", "kind": "ClusterRole", "name": "somecr"}, "subjects": [{"apiVersion": "rbac.authorization.k8s.io/v1alpha1", "kind": "Group", "name": "system:authenticated"}]}`,
|
||||
},
|
||||
gvr("rbac.authorization.k8s.io", "v1", "clusterrolebindings"): {
|
||||
stub: `{"metadata": {"name": "drcroleb3"}, "roleRef": {"apiGroup": "rbac.authorization.k8s.io", "kind": "ClusterRole", "name": "somecr"}, "subjects": [{"apiVersion": "rbac.authorization.k8s.io/v1alpha1", "kind": "Group", "name": "system:authenticated"}]}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/admissionregistration/v1alpha1
|
||||
gvr("admissionregistration.k8s.io", "v1alpha1", "initializerconfigurations"): {
|
||||
stub: `{"metadata":{"name":"ic1"},"initializers":[{"name":"initializer.k8s.io","rules":[{"apiGroups":["group"],"apiVersions":["version"],"resources":["resource"]}],"failurePolicy":"Ignore"}]}`,
|
||||
},
|
||||
// k8s.io/kubernetes/pkg/apis/admissionregistration/v1beta1
|
||||
gvr("admissionregistration.k8s.io", "v1beta1", "validatingwebhookconfigurations"): {
|
||||
stub: `{"metadata":{"name":"hook1","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"}]}`,
|
||||
},
|
||||
gvr("admissionregistration.k8s.io", "v1beta1", "mutatingwebhookconfigurations"): {
|
||||
stub: `{"metadata":{"name":"hook1","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"}]}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/scheduling/v1alpha1
|
||||
gvr("scheduling.k8s.io", "v1alpha1", "priorityclasses"): {
|
||||
stub: `{"metadata":{"name":"pc1"},"Value":1000}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/scheduling/v1beta1
|
||||
gvr("scheduling.k8s.io", "v1beta1", "priorityclasses"): {
|
||||
stub: `{"metadata":{"name":"pc2"},"Value":1000}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1
|
||||
// depends on aggregator using the same ungrouped RESTOptionsGetter as the kube apiserver, not SimpleRestOptionsFactory in aggregator.go
|
||||
gvr("apiregistration.k8s.io", "v1beta1", "apiservices"): {
|
||||
stub: `{"metadata": {"name": "dras1.foo.com"}, "spec": {"group": "foo.com", "version": "dras1", "groupPriorityMinimum":100, "versionPriority":10}}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// 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": "dras2.foo.com"}, "spec": {"group": "foo.com", "version": "dras2", "groupPriorityMinimum":100, "versionPriority":10}}`,
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1
|
||||
gvr("apiextensions.k8s.io", "v1beta1", "customresourcedefinitions"): {
|
||||
stub: `{"metadata": {"name": "openshiftwebconsoleconfigs.webconsole.operator.openshift.io"},"spec": {"scope": "Cluster","group": "webconsole.operator.openshift.io","version": "v1alpha1","names": {"kind": "OpenShiftWebConsoleConfig","plural": "openshiftwebconsoleconfigs","singular": "openshiftwebconsoleconfig"}}}`,
|
||||
},
|
||||
// --
|
||||
|
||||
}
|
||||
|
||||
// Only add kinds to this list when this a virtual resource with get and create verbs that doesn't actually
|
||||
// store into it's kind. We've used this downstream for mappings before.
|
||||
var kindWhiteList = sets.NewString()
|
||||
@ -418,18 +86,6 @@ func getReplicasOrFail(t *testing.T, obj *unstructured.Unstructured) int64 {
|
||||
return replicas
|
||||
}
|
||||
|
||||
func setReplicasOrFail(t *testing.T, obj *unstructured.Unstructured, replicas int64) {
|
||||
m, found, err := unstructured.NestedMap(obj.UnstructuredContent(), "spec")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get spec: %v", err)
|
||||
}
|
||||
if !found {
|
||||
t.Fatal("object doesn't have spec")
|
||||
}
|
||||
m["replicas"] = replicas
|
||||
unstructured.SetNestedMap(obj.UnstructuredContent(), m, "spec")
|
||||
}
|
||||
|
||||
func DryRunScalePatchTest(t *testing.T, rsc dynamic.ResourceInterface, name string) {
|
||||
obj, err := rsc.Get(name, metav1.GetOptions{}, "scale")
|
||||
if errors.IsNotFound(err) {
|
||||
@ -467,7 +123,9 @@ func DryRunScaleUpdateTest(t *testing.T, rsc dynamic.ResourceInterface, name str
|
||||
}
|
||||
|
||||
replicas := getReplicasOrFail(t, obj)
|
||||
unstructured.SetNestedField(obj.Object, int64(10), "spec", "replicas")
|
||||
if err := unstructured.SetNestedField(obj.Object, int64(10), "spec", "replicas"); err != nil {
|
||||
t.Fatalf("failed to set spec.replicas: %v", err)
|
||||
}
|
||||
updatedObj, err := rsc.Update(obj, metav1.UpdateOptions{DryRun: []string{metav1.DryRunAll}}, "scale")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to dry-run update scale sub-resource: %v", err)
|
||||
@ -546,42 +204,34 @@ func DryRunDeleteTest(t *testing.T, rsc dynamic.ResourceInterface, name string)
|
||||
|
||||
// TestDryRun tests dry-run on all types.
|
||||
func TestDryRun(t *testing.T) {
|
||||
certDir, _ := ioutil.TempDir("", "test-integration-dryrun")
|
||||
defer os.RemoveAll(certDir)
|
||||
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.DryRun, true)()
|
||||
clientConfig := startRealMasterOrDie(t, certDir)
|
||||
dClient := dynamic.NewForConfigOrDie(clientConfig)
|
||||
kubeClient := clientset.NewForConfigOrDie(clientConfig)
|
||||
if _, err := kubeClient.CoreV1().Namespaces().Create(&v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: testNamespace}}); err != nil {
|
||||
|
||||
master := etcd.StartRealMasterOrDie(t)
|
||||
defer master.Cleanup()
|
||||
|
||||
if _, err := master.Client.CoreV1().Namespaces().Create(&v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: testNamespace}}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
discoveryClient := cacheddiscovery.NewMemCacheClient(kubeClient.Discovery())
|
||||
restMapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient)
|
||||
restMapper.Reset()
|
||||
dryrunData := etcd.GetEtcdStorageData()
|
||||
|
||||
serverResources, err := kubeClient.Discovery().ServerResources()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
// dry run specific stub overrides
|
||||
for resource, stub := range map[schema.GroupVersionResource]string{
|
||||
// need to change event's namespace field to match dry run test
|
||||
gvr("", "v1", "events"): `{"involvedObject": {"namespace": "dryrunnamespace"}, "message": "some data here", "metadata": {"name": "event1"}}`,
|
||||
} {
|
||||
data := dryrunData[resource]
|
||||
data.Stub = stub
|
||||
dryrunData[resource] = data
|
||||
}
|
||||
resourcesToTest := getResourcesToTest(serverResources, false, t)
|
||||
|
||||
for _, resourceToTest := range resourcesToTest {
|
||||
t.Run(resourceToTest.gvr.String(), func(t *testing.T) {
|
||||
gvk := resourceToTest.gvk
|
||||
gvResource := resourceToTest.gvr
|
||||
for _, resourceToTest := range master.Resources {
|
||||
t.Run(resourceToTest.Mapping.Resource.String(), func(t *testing.T) {
|
||||
mapping := resourceToTest.Mapping
|
||||
gvk := resourceToTest.Mapping.GroupVersionKind
|
||||
gvResource := resourceToTest.Mapping.Resource
|
||||
kind := gvk.Kind
|
||||
|
||||
mapping := &meta.RESTMapping{
|
||||
Resource: resourceToTest.gvr,
|
||||
GroupVersionKind: resourceToTest.gvk,
|
||||
Scope: meta.RESTScopeRoot,
|
||||
}
|
||||
if resourceToTest.namespaced {
|
||||
mapping.Scope = meta.RESTScopeNamespace
|
||||
}
|
||||
|
||||
if kindWhiteList.Has(kind) {
|
||||
t.Skip("whitelisted")
|
||||
}
|
||||
@ -589,23 +239,14 @@ func TestDryRun(t *testing.T) {
|
||||
testData, hasTest := dryrunData[gvResource]
|
||||
|
||||
if !hasTest {
|
||||
t.Fatalf("no test data for %s. Please add a test for your new type to dryrunData.", gvResource)
|
||||
t.Fatalf("no test data for %s. Please add a test for your new type to etcd.GetEtcdStorageData().", gvResource)
|
||||
}
|
||||
|
||||
// we don't require GVK on the data we provide, so we fill it in here. We could, but that seems extraneous.
|
||||
typeMetaAdder := map[string]interface{}{}
|
||||
err := json.Unmarshal([]byte(testData.stub), &typeMetaAdder)
|
||||
rsc, obj, err := etcd.JSONToUnstructured(testData.Stub, testNamespace, mapping, master.Dynamic)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to unmarshal stub (%v): %v", testData.stub, err)
|
||||
t.Fatalf("failed to unmarshal stub (%v): %v", testData.Stub, err)
|
||||
}
|
||||
typeMetaAdder["apiVersion"] = mapping.GroupVersionKind.GroupVersion().String()
|
||||
typeMetaAdder["kind"] = mapping.GroupVersionKind.Kind
|
||||
|
||||
rsc := dClient.Resource(mapping.Resource).Namespace(testNamespace)
|
||||
if mapping.Scope == meta.RESTScopeRoot {
|
||||
rsc = dClient.Resource(mapping.Resource)
|
||||
}
|
||||
obj := &unstructured.Unstructured{Object: typeMetaAdder}
|
||||
name := obj.GetName()
|
||||
|
||||
DryRunCreateTest(t, rsc, obj, gvResource)
|
||||
@ -618,7 +259,7 @@ func TestDryRun(t *testing.T) {
|
||||
DryRunPatchTest(t, rsc, name)
|
||||
DryRunScalePatchTest(t, rsc, name)
|
||||
DryRunScaleUpdateTest(t, rsc, name)
|
||||
if resourceToTest.hasDeleteCollection {
|
||||
if resourceToTest.HasDeleteCollection {
|
||||
DryRunDeleteCollectionTest(t, rsc, name)
|
||||
}
|
||||
DryRunDeleteTest(t, rsc, name)
|
||||
@ -630,136 +271,6 @@ func TestDryRun(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func startRealMasterOrDie(t *testing.T, certDir string) *restclient.Config {
|
||||
_, defaultServiceClusterIPRange, err := net.ParseCIDR("10.0.0.0/24")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
listener, _, err := genericapiserveroptions.CreateListener("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
kubeAPIServerOptions := options.NewServerRunOptions()
|
||||
kubeAPIServerOptions.InsecureServing.BindPort = 0
|
||||
kubeAPIServerOptions.SecureServing.Listener = listener
|
||||
kubeAPIServerOptions.SecureServing.ServerCert.CertDirectory = certDir
|
||||
kubeAPIServerOptions.Etcd.StorageConfig.ServerList = []string{framework.GetEtcdURL()}
|
||||
kubeAPIServerOptions.Etcd.DefaultStorageMediaType = runtime.ContentTypeJSON // force json we can easily interpret the result in etcd
|
||||
kubeAPIServerOptions.ServiceClusterIPRange = *defaultServiceClusterIPRange
|
||||
kubeAPIServerOptions.Authorization.Modes = []string{"RBAC"}
|
||||
kubeAPIServerOptions.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
||||
completedOptions, err := app.Complete(kubeAPIServerOptions)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
kubeAPIServerOptions.APIEnablement.RuntimeConfig.Set("api/all=true")
|
||||
|
||||
kubeAPIServer, err := app.CreateServerChain(completedOptions, wait.NeverStop)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
kubeClientConfig := restclient.CopyConfig(kubeAPIServer.LoopbackClientConfig)
|
||||
|
||||
go func() {
|
||||
// Catch panics that occur in this go routine so we get a comprehensible failure
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
t.Errorf("Unexpected panic trying to start API master: %#v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := kubeAPIServer.PrepareRun().Run(wait.NeverStop); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
lastHealth := ""
|
||||
if err := wait.PollImmediate(time.Second, time.Minute, func() (done bool, err error) {
|
||||
// wait for the server to be healthy
|
||||
result := clientset.NewForConfigOrDie(kubeClientConfig).RESTClient().Get().AbsPath("/healthz").Do()
|
||||
content, _ := result.Raw()
|
||||
lastHealth = string(content)
|
||||
if errResult := result.Error(); errResult != nil {
|
||||
t.Log(errResult)
|
||||
return false, nil
|
||||
}
|
||||
var status int
|
||||
result.StatusCode(&status)
|
||||
return status == http.StatusOK, nil
|
||||
}); err != nil {
|
||||
t.Log(lastHealth)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// this test makes lots of requests, don't be slow
|
||||
kubeClientConfig.QPS = 99999
|
||||
kubeClientConfig.Burst = 9999
|
||||
|
||||
return kubeClientConfig
|
||||
}
|
||||
|
||||
func gvr(g, v, r string) schema.GroupVersionResource {
|
||||
return schema.GroupVersionResource{Group: g, Version: v, Resource: r}
|
||||
}
|
||||
|
||||
type resourceToTest struct {
|
||||
gvk schema.GroupVersionKind
|
||||
gvr schema.GroupVersionResource
|
||||
namespaced bool
|
||||
hasDeleteCollection bool
|
||||
}
|
||||
|
||||
func getResourcesToTest(serverResources []*metav1.APIResourceList, isOAPI bool, t *testing.T) []resourceToTest {
|
||||
resourcesToTest := []resourceToTest{}
|
||||
|
||||
for _, discoveryGroup := range serverResources {
|
||||
for _, discoveryResource := range discoveryGroup.APIResources {
|
||||
// this is a subresource, skip it
|
||||
if strings.Contains(discoveryResource.Name, "/") {
|
||||
continue
|
||||
}
|
||||
hasCreate := false
|
||||
hasGet := false
|
||||
hasDeleteCollection := false
|
||||
for _, verb := range discoveryResource.Verbs {
|
||||
if string(verb) == "get" {
|
||||
hasGet = true
|
||||
}
|
||||
if string(verb) == "create" {
|
||||
hasCreate = true
|
||||
}
|
||||
if string(verb) == "deletecollection" {
|
||||
hasDeleteCollection = true
|
||||
}
|
||||
}
|
||||
if !(hasCreate && hasGet) {
|
||||
continue
|
||||
}
|
||||
|
||||
resourceGV, err := schema.ParseGroupVersion(discoveryGroup.GroupVersion)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
gvk := resourceGV.WithKind(discoveryResource.Kind)
|
||||
if len(discoveryResource.Group) > 0 || len(discoveryResource.Version) > 0 {
|
||||
gvk = schema.GroupVersionKind{
|
||||
Group: discoveryResource.Group,
|
||||
Version: discoveryResource.Version,
|
||||
Kind: discoveryResource.Kind,
|
||||
}
|
||||
}
|
||||
gvr := resourceGV.WithResource(discoveryResource.Name)
|
||||
|
||||
resourcesToTest = append(resourcesToTest, resourceToTest{
|
||||
gvk: gvk,
|
||||
gvr: gvr,
|
||||
namespaced: discoveryResource.Namespaced,
|
||||
hasDeleteCollection: hasDeleteCollection,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return resourcesToTest
|
||||
}
|
||||
|
@ -1,9 +1,6 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_test",
|
||||
)
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
@ -12,31 +9,21 @@ go_test(
|
||||
"etcd_storage_path_test.go",
|
||||
"main_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
tags = [
|
||||
"etcd",
|
||||
"integration",
|
||||
],
|
||||
deps = [
|
||||
"//cmd/kube-apiserver/app:go_default_library",
|
||||
"//cmd/kube-apiserver/app/options:go_default_library",
|
||||
"//pkg/master:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/server/options:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/discovery/cached:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/dynamic:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/restmapper:go_default_library",
|
||||
"//test/integration:go_default_library",
|
||||
"//test/integration/framework:go_default_library",
|
||||
"//vendor/github.com/coreos/etcd/clientv3:go_default_library",
|
||||
],
|
||||
@ -54,3 +41,33 @@ filegroup(
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"data.go",
|
||||
"server.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/test/integration/etcd",
|
||||
deps = [
|
||||
"//cmd/kube-apiserver/app:go_default_library",
|
||||
"//cmd/kube-apiserver/app/options:go_default_library",
|
||||
"//pkg/master:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/server/options:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/discovery/cached:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/dynamic:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/restmapper:go_default_library",
|
||||
"//test/integration:go_default_library",
|
||||
"//test/integration/framework:go_default_library",
|
||||
"//vendor/github.com/coreos/etcd/clientv3:go_default_library",
|
||||
"//vendor/github.com/coreos/etcd/clientv3/concurrency:go_default_library",
|
||||
],
|
||||
)
|
||||
|
455
test/integration/etcd/data.go
Normal file
455
test/integration/etcd/data.go
Normal file
@ -0,0 +1,455 @@
|
||||
/*
|
||||
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 "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
// 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 map[schema.GroupVersionResource]StorageData{
|
||||
// k8s.io/kubernetes/pkg/api/v1
|
||||
gvr("", "v1", "configmaps"): {
|
||||
Stub: `{"data": {"foo": "bar"}, "metadata": {"name": "cm1"}}`,
|
||||
ExpectedEtcdPath: "/registry/configmaps/etcdstoragepathtestnamespace/cm1",
|
||||
},
|
||||
gvr("", "v1", "services"): {
|
||||
Stub: `{"metadata": {"name": "service1"}, "spec": {"externalName": "service1name", "ports": [{"port": 10000, "targetPort": 11000}], "selector": {"test": "data"}}}`,
|
||||
ExpectedEtcdPath: "/registry/services/specs/etcdstoragepathtestnamespace/service1",
|
||||
},
|
||||
gvr("", "v1", "podtemplates"): {
|
||||
Stub: `{"metadata": {"name": "pt1name"}, "template": {"metadata": {"labels": {"pt": "01"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container9"}]}}}`,
|
||||
ExpectedEtcdPath: "/registry/podtemplates/etcdstoragepathtestnamespace/pt1name",
|
||||
},
|
||||
gvr("", "v1", "pods"): {
|
||||
Stub: `{"metadata": {"name": "pod1"}, "spec": {"containers": [{"image": "fedora:latest", "name": "container7", "resources": {"limits": {"cpu": "1M"}, "requests": {"cpu": "1M"}}}]}}`,
|
||||
ExpectedEtcdPath: "/registry/pods/etcdstoragepathtestnamespace/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/etcdstoragepathtestnamespace/ep1name",
|
||||
},
|
||||
gvr("", "v1", "resourcequotas"): {
|
||||
Stub: `{"metadata": {"name": "rq1name"}, "spec": {"hard": {"cpu": "5M"}}}`,
|
||||
ExpectedEtcdPath: "/registry/resourcequotas/etcdstoragepathtestnamespace/rq1name",
|
||||
},
|
||||
gvr("", "v1", "limitranges"): {
|
||||
Stub: `{"metadata": {"name": "lr1name"}, "spec": {"limits": [{"type": "Pod"}]}}`,
|
||||
ExpectedEtcdPath: "/registry/limitranges/etcdstoragepathtestnamespace/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": "etcdstoragepathtestnamespace"}, "message": "some data here", "metadata": {"name": "event1"}}`,
|
||||
ExpectedEtcdPath: "/registry/events/etcdstoragepathtestnamespace/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/etcdstoragepathtestnamespace/pvc1",
|
||||
},
|
||||
gvr("", "v1", "serviceaccounts"): {
|
||||
Stub: `{"metadata": {"name": "sa1name"}, "secrets": [{"name": "secret00"}]}`,
|
||||
ExpectedEtcdPath: "/registry/serviceaccounts/etcdstoragepathtestnamespace/sa1name",
|
||||
},
|
||||
gvr("", "v1", "secrets"): {
|
||||
Stub: `{"data": {"key": "ZGF0YSBmaWxl"}, "metadata": {"name": "secret1"}}`,
|
||||
ExpectedEtcdPath: "/registry/secrets/etcdstoragepathtestnamespace/secret1",
|
||||
},
|
||||
gvr("", "v1", "replicationcontrollers"): {
|
||||
Stub: `{"metadata": {"name": "rc1"}, "spec": {"selector": {"new": "stuff"}, "template": {"metadata": {"labels": {"new": "stuff"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container8"}]}}}}`,
|
||||
ExpectedEtcdPath: "/registry/controllers/etcdstoragepathtestnamespace/rc1",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/apps/v1beta1
|
||||
gvr("apps", "v1beta1", "statefulsets"): {
|
||||
Stub: `{"metadata": {"name": "ss1"}, "spec": {"selector": {"matchLabels": {"a": "b"}}, "template": {"metadata": {"labels": {"a": "b"}}}}}`,
|
||||
ExpectedEtcdPath: "/registry/statefulsets/etcdstoragepathtestnamespace/ss1",
|
||||
ExpectedGVK: gvkP("apps", "v1", "StatefulSet"),
|
||||
},
|
||||
gvr("apps", "v1beta1", "deployments"): {
|
||||
Stub: `{"metadata": {"name": "deployment2"}, "spec": {"selector": {"matchLabels": {"f": "z"}}, "template": {"metadata": {"labels": {"f": "z"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container6"}]}}}}`,
|
||||
ExpectedEtcdPath: "/registry/deployments/etcdstoragepathtestnamespace/deployment2",
|
||||
ExpectedGVK: gvkP("apps", "v1", "Deployment"),
|
||||
},
|
||||
gvr("apps", "v1beta1", "controllerrevisions"): {
|
||||
Stub: `{"metadata":{"name":"crs1"},"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/etcdstoragepathtestnamespace/crs1",
|
||||
ExpectedGVK: gvkP("apps", "v1", "ControllerRevision"),
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/apps/v1beta2
|
||||
gvr("apps", "v1beta2", "statefulsets"): {
|
||||
Stub: `{"metadata": {"name": "ss2"}, "spec": {"selector": {"matchLabels": {"a": "b"}}, "template": {"metadata": {"labels": {"a": "b"}}}}}`,
|
||||
ExpectedEtcdPath: "/registry/statefulsets/etcdstoragepathtestnamespace/ss2",
|
||||
ExpectedGVK: gvkP("apps", "v1", "StatefulSet"),
|
||||
},
|
||||
gvr("apps", "v1beta2", "deployments"): {
|
||||
Stub: `{"metadata": {"name": "deployment3"}, "spec": {"selector": {"matchLabels": {"f": "z"}}, "template": {"metadata": {"labels": {"f": "z"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container6"}]}}}}`,
|
||||
ExpectedEtcdPath: "/registry/deployments/etcdstoragepathtestnamespace/deployment3",
|
||||
ExpectedGVK: gvkP("apps", "v1", "Deployment"),
|
||||
},
|
||||
gvr("apps", "v1beta2", "daemonsets"): {
|
||||
Stub: `{"metadata": {"name": "ds5"}, "spec": {"selector": {"matchLabels": {"a": "b"}}, "template": {"metadata": {"labels": {"a": "b"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container6"}]}}}}`,
|
||||
ExpectedEtcdPath: "/registry/daemonsets/etcdstoragepathtestnamespace/ds5",
|
||||
ExpectedGVK: gvkP("apps", "v1", "DaemonSet"),
|
||||
},
|
||||
gvr("apps", "v1beta2", "replicasets"): {
|
||||
Stub: `{"metadata": {"name": "rs2"}, "spec": {"selector": {"matchLabels": {"g": "h"}}, "template": {"metadata": {"labels": {"g": "h"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container4"}]}}}}`,
|
||||
ExpectedEtcdPath: "/registry/replicasets/etcdstoragepathtestnamespace/rs2",
|
||||
ExpectedGVK: gvkP("apps", "v1", "ReplicaSet"),
|
||||
},
|
||||
gvr("apps", "v1beta2", "controllerrevisions"): {
|
||||
Stub: `{"metadata":{"name":"crs2"},"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/etcdstoragepathtestnamespace/crs2",
|
||||
ExpectedGVK: gvkP("apps", "v1", "ControllerRevision"),
|
||||
},
|
||||
// --
|
||||
|
||||
// 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": "fedora:latest", "name": "container6"}]}}}}`,
|
||||
ExpectedEtcdPath: "/registry/daemonsets/etcdstoragepathtestnamespace/ds6",
|
||||
},
|
||||
gvr("apps", "v1", "deployments"): {
|
||||
Stub: `{"metadata": {"name": "deployment4"}, "spec": {"selector": {"matchLabels": {"f": "z"}}, "template": {"metadata": {"labels": {"f": "z"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container6"}]}}}}`,
|
||||
ExpectedEtcdPath: "/registry/deployments/etcdstoragepathtestnamespace/deployment4",
|
||||
},
|
||||
gvr("apps", "v1", "statefulsets"): {
|
||||
Stub: `{"metadata": {"name": "ss3"}, "spec": {"selector": {"matchLabels": {"a": "b"}}, "template": {"metadata": {"labels": {"a": "b"}}}}}`,
|
||||
ExpectedEtcdPath: "/registry/statefulsets/etcdstoragepathtestnamespace/ss3",
|
||||
},
|
||||
gvr("apps", "v1", "replicasets"): {
|
||||
Stub: `{"metadata": {"name": "rs3"}, "spec": {"selector": {"matchLabels": {"g": "h"}}, "template": {"metadata": {"labels": {"g": "h"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container4"}]}}}}`,
|
||||
ExpectedEtcdPath: "/registry/replicasets/etcdstoragepathtestnamespace/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/etcdstoragepathtestnamespace/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/etcdstoragepathtestnamespace/hpa2",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/autoscaling/v2beta1
|
||||
gvr("autoscaling", "v2beta1", "horizontalpodautoscalers"): {
|
||||
Stub: `{"metadata": {"name": "hpa1"}, "spec": {"maxReplicas": 3, "scaleTargetRef": {"kind": "something", "name": "cross"}}}`,
|
||||
ExpectedEtcdPath: "/registry/horizontalpodautoscalers/etcdstoragepathtestnamespace/hpa1",
|
||||
ExpectedGVK: gvkP("autoscaling", "v1", "HorizontalPodAutoscaler"),
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/autoscaling/v2beta2
|
||||
gvr("autoscaling", "v2beta2", "horizontalpodautoscalers"): {
|
||||
Stub: `{"metadata": {"name": "hpa3"}, "spec": {"maxReplicas": 3, "scaleTargetRef": {"kind": "something", "name": "cross"}}}`,
|
||||
ExpectedEtcdPath: "/registry/horizontalpodautoscalers/etcdstoragepathtestnamespace/hpa3",
|
||||
ExpectedGVK: gvkP("autoscaling", "v1", "HorizontalPodAutoscaler"),
|
||||
},
|
||||
// --
|
||||
|
||||
// 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": "fedora:latest", "name": "container1"}], "dnsPolicy": "ClusterFirst", "restartPolicy": "Never"}}}}`,
|
||||
ExpectedEtcdPath: "/registry/jobs/etcdstoragepathtestnamespace/job1",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/batch/v1beta1
|
||||
gvr("batch", "v1beta1", "cronjobs"): {
|
||||
Stub: `{"metadata": {"name": "cjv1beta1"}, "spec": {"jobTemplate": {"spec": {"template": {"metadata": {"labels": {"controller-uid": "uid0"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container0"}], "dnsPolicy": "ClusterFirst", "restartPolicy": "Never"}}}}, "schedule": "* * * * *"}}`,
|
||||
ExpectedEtcdPath: "/registry/cronjobs/etcdstoragepathtestnamespace/cjv1beta1",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/batch/v2alpha1
|
||||
gvr("batch", "v2alpha1", "cronjobs"): {
|
||||
Stub: `{"metadata": {"name": "cjv2alpha1"}, "spec": {"jobTemplate": {"spec": {"template": {"metadata": {"labels": {"controller-uid": "uid0"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container0"}], "dnsPolicy": "ClusterFirst", "restartPolicy": "Never"}}}}, "schedule": "* * * * *"}}`,
|
||||
ExpectedEtcdPath: "/registry/cronjobs/etcdstoragepathtestnamespace/cjv2alpha1",
|
||||
ExpectedGVK: gvkP("batch", "v1beta1", "CronJob"),
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/certificates/v1beta1
|
||||
gvr("certificates.k8s.io", "v1beta1", "certificatesigningrequests"): {
|
||||
Stub: `{"metadata": {"name": "csr1"}, "spec": {"request": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQnlqQ0NBVE1DQVFBd2dZa3hDekFKQmdOVkJBWVRBbFZUTVJNd0VRWURWUVFJRXdwRFlXeHBabTl5Ym1saApNUll3RkFZRFZRUUhFdzFOYjNWdWRHRnBiaUJXYVdWM01STXdFUVlEVlFRS0V3cEhiMjluYkdVZ1NXNWpNUjh3CkhRWURWUVFMRXhaSmJtWnZjbTFoZEdsdmJpQlVaV05vYm05c2IyZDVNUmN3RlFZRFZRUURFdzUzZDNjdVoyOXYKWjJ4bExtTnZiVENCbnpBTkJna3Foa2lHOXcwQkFRRUZBQU9CalFBd2dZa0NnWUVBcFp0WUpDSEo0VnBWWEhmVgpJbHN0UVRsTzRxQzAzaGpYK1prUHl2ZFlkMVE0K3FiQWVUd1htQ1VLWUhUaFZSZDVhWFNxbFB6eUlCd2llTVpyCldGbFJRZGRaMUl6WEFsVlJEV3dBbzYwS2VjcWVBWG5uVUsrNWZYb1RJL1VnV3NocmU4dEoreC9UTUhhUUtSL0oKY0lXUGhxYVFoc0p1elpidkFkR0E4MEJMeGRNQ0F3RUFBYUFBTUEwR0NTcUdTSWIzRFFFQkJRVUFBNEdCQUlobAo0UHZGcStlN2lwQVJnSTVaTStHWng2bXBDejQ0RFRvMEprd2ZSRGYrQnRyc2FDMHE2OGVUZjJYaFlPc3E0ZmtIClEwdUEwYVZvZzNmNWlKeENhM0hwNWd4YkpRNnpWNmtKMFRFc3VhYU9oRWtvOXNkcENvUE9uUkJtMmkvWFJEMkQKNmlOaDhmOHowU2hHc0ZxakRnRkh5RjNvK2xVeWorVUM2SDFRVzdibgotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0="}}`,
|
||||
ExpectedEtcdPath: "/registry/certificatesigningrequests/csr1",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/coordination/v1beta1
|
||||
gvr("coordination.k8s.io", "v1beta1", "leases"): {
|
||||
Stub: `{"metadata": {"name": "lease1"}, "spec": {"holderIdentity": "holder", "leaseDurationSeconds": 5}}`,
|
||||
ExpectedEtcdPath: "/registry/leases/etcdstoragepathtestnamespace/lease1",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/events/v1beta1
|
||||
gvr("events.k8s.io", "v1beta1", "events"): {
|
||||
Stub: `{"metadata": {"name": "event2"}, "regarding": {"namespace": "etcdstoragepathtestnamespace"}, "note": "some data here", "eventTime": "2017-08-09T15:04:05.000000Z", "reportingInstance": "node-xyz", "reportingController": "k8s.io/my-controller", "action": "DidNothing", "reason": "Laziness"}`,
|
||||
ExpectedEtcdPath: "/registry/events/etcdstoragepathtestnamespace/event2",
|
||||
ExpectedGVK: gvkP("", "v1", "Event"),
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/extensions/v1beta1
|
||||
gvr("extensions", "v1beta1", "daemonsets"): {
|
||||
Stub: `{"metadata": {"name": "ds1"}, "spec": {"selector": {"matchLabels": {"u": "t"}}, "template": {"metadata": {"labels": {"u": "t"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container5"}]}}}}`,
|
||||
ExpectedEtcdPath: "/registry/daemonsets/etcdstoragepathtestnamespace/ds1",
|
||||
ExpectedGVK: gvkP("apps", "v1", "DaemonSet"),
|
||||
},
|
||||
gvr("extensions", "v1beta1", "podsecuritypolicies"): {
|
||||
Stub: `{"metadata": {"name": "psp1"}, "spec": {"fsGroup": {"rule": "RunAsAny"}, "privileged": true, "runAsUser": {"rule": "RunAsAny"}, "seLinux": {"rule": "MustRunAs"}, "supplementalGroups": {"rule": "RunAsAny"}}}`,
|
||||
ExpectedEtcdPath: "/registry/podsecuritypolicy/psp1",
|
||||
ExpectedGVK: gvkP("policy", "v1beta1", "PodSecurityPolicy"),
|
||||
},
|
||||
gvr("extensions", "v1beta1", "ingresses"): {
|
||||
Stub: `{"metadata": {"name": "ingress1"}, "spec": {"backend": {"serviceName": "service", "servicePort": 5000}}}`,
|
||||
ExpectedEtcdPath: "/registry/ingress/etcdstoragepathtestnamespace/ingress1",
|
||||
},
|
||||
gvr("extensions", "v1beta1", "networkpolicies"): {
|
||||
Stub: `{"metadata": {"name": "np1"}, "spec": {"podSelector": {"matchLabels": {"e": "f"}}}}`,
|
||||
ExpectedEtcdPath: "/registry/networkpolicies/etcdstoragepathtestnamespace/np1",
|
||||
ExpectedGVK: gvkP("networking.k8s.io", "v1", "NetworkPolicy"),
|
||||
},
|
||||
gvr("extensions", "v1beta1", "deployments"): {
|
||||
Stub: `{"metadata": {"name": "deployment1"}, "spec": {"selector": {"matchLabels": {"f": "z"}}, "template": {"metadata": {"labels": {"f": "z"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container6"}]}}}}`,
|
||||
ExpectedEtcdPath: "/registry/deployments/etcdstoragepathtestnamespace/deployment1",
|
||||
ExpectedGVK: gvkP("apps", "v1", "Deployment"),
|
||||
},
|
||||
gvr("extensions", "v1beta1", "replicasets"): {
|
||||
Stub: `{"metadata": {"name": "rs1"}, "spec": {"selector": {"matchLabels": {"g": "h"}}, "template": {"metadata": {"labels": {"g": "h"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container4"}]}}}}`,
|
||||
ExpectedEtcdPath: "/registry/replicasets/etcdstoragepathtestnamespace/rs1",
|
||||
ExpectedGVK: gvkP("apps", "v1", "ReplicaSet"),
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/networking/v1
|
||||
gvr("networking.k8s.io", "v1", "networkpolicies"): {
|
||||
Stub: `{"metadata": {"name": "np2"}, "spec": {"podSelector": {"matchLabels": {"e": "f"}}}}`,
|
||||
ExpectedEtcdPath: "/registry/networkpolicies/etcdstoragepathtestnamespace/np2",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/policy/v1beta1
|
||||
gvr("policy", "v1beta1", "poddisruptionbudgets"): {
|
||||
Stub: `{"metadata": {"name": "pdb1"}, "spec": {"selector": {"matchLabels": {"anokkey": "anokvalue"}}}}`,
|
||||
ExpectedEtcdPath: "/registry/poddisruptionbudgets/etcdstoragepathtestnamespace/pdb1",
|
||||
},
|
||||
gvr("policy", "v1beta1", "podsecuritypolicies"): {
|
||||
Stub: `{"metadata": {"name": "psp2"}, "spec": {"fsGroup": {"rule": "RunAsAny"}, "privileged": true, "runAsUser": {"rule": "RunAsAny"}, "seLinux": {"rule": "MustRunAs"}, "supplementalGroups": {"rule": "RunAsAny"}}}`,
|
||||
ExpectedEtcdPath: "/registry/podsecuritypolicy/psp2",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/storage/v1alpha1
|
||||
gvr("storage.k8s.io", "v1alpha1", "volumeattachments"): {
|
||||
Stub: `{"metadata": {"name": "va1"}, "spec": {"attacher": "gce", "nodeName": "localhost", "source": {"persistentVolumeName": "pv1"}}}`,
|
||||
ExpectedEtcdPath: "/registry/volumeattachments/va1",
|
||||
ExpectedGVK: gvkP("storage.k8s.io", "v1beta1", "VolumeAttachment"),
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/storage/v1beta1
|
||||
gvr("storage.k8s.io", "v1beta1", "volumeattachments"): {
|
||||
Stub: `{"metadata": {"name": "va2"}, "spec": {"attacher": "gce", "nodeName": "localhost", "source": {"persistentVolumeName": "pv2"}}}`,
|
||||
ExpectedEtcdPath: "/registry/volumeattachments/va2",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/storage/v1beta1
|
||||
gvr("storage.k8s.io", "v1beta1", "storageclasses"): {
|
||||
Stub: `{"metadata": {"name": "sc1"}, "provisioner": "aws"}`,
|
||||
ExpectedEtcdPath: "/registry/storageclasses/sc1",
|
||||
ExpectedGVK: gvkP("storage.k8s.io", "v1", "StorageClass"),
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/storage/v1
|
||||
gvr("storage.k8s.io", "v1", "storageclasses"): {
|
||||
Stub: `{"metadata": {"name": "sc2"}, "provisioner": "aws"}`,
|
||||
ExpectedEtcdPath: "/registry/storageclasses/sc2",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/settings/v1alpha1
|
||||
gvr("settings.k8s.io", "v1alpha1", "podpresets"): {
|
||||
Stub: `{"metadata": {"name": "podpre1"}, "spec": {"env": [{"name": "FOO"}]}}`,
|
||||
ExpectedEtcdPath: "/registry/podpresets/etcdstoragepathtestnamespace/podpre1",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/rbac/v1alpha1
|
||||
gvr("rbac.authorization.k8s.io", "v1alpha1", "roles"): {
|
||||
Stub: `{"metadata": {"name": "role1"}, "rules": [{"apiGroups": ["v1"], "resources": ["events"], "verbs": ["watch"]}]}`,
|
||||
ExpectedEtcdPath: "/registry/roles/etcdstoragepathtestnamespace/role1",
|
||||
ExpectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "Role"),
|
||||
},
|
||||
gvr("rbac.authorization.k8s.io", "v1alpha1", "clusterroles"): {
|
||||
Stub: `{"metadata": {"name": "crole1"}, "rules": [{"nonResourceURLs": ["/version"], "verbs": ["get"]}]}`,
|
||||
ExpectedEtcdPath: "/registry/clusterroles/crole1",
|
||||
ExpectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "ClusterRole"),
|
||||
},
|
||||
gvr("rbac.authorization.k8s.io", "v1alpha1", "rolebindings"): {
|
||||
Stub: `{"metadata": {"name": "roleb1"}, "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/etcdstoragepathtestnamespace/roleb1",
|
||||
ExpectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "RoleBinding"),
|
||||
},
|
||||
gvr("rbac.authorization.k8s.io", "v1alpha1", "clusterrolebindings"): {
|
||||
Stub: `{"metadata": {"name": "croleb1"}, "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/croleb1",
|
||||
ExpectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "ClusterRoleBinding"),
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/rbac/v1beta1
|
||||
gvr("rbac.authorization.k8s.io", "v1beta1", "roles"): {
|
||||
Stub: `{"metadata": {"name": "role2"}, "rules": [{"apiGroups": ["v1"], "resources": ["events"], "verbs": ["watch"]}]}`,
|
||||
ExpectedEtcdPath: "/registry/roles/etcdstoragepathtestnamespace/role2",
|
||||
ExpectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "Role"),
|
||||
},
|
||||
gvr("rbac.authorization.k8s.io", "v1beta1", "clusterroles"): {
|
||||
Stub: `{"metadata": {"name": "crole2"}, "rules": [{"nonResourceURLs": ["/version"], "verbs": ["get"]}]}`,
|
||||
ExpectedEtcdPath: "/registry/clusterroles/crole2",
|
||||
ExpectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "ClusterRole"),
|
||||
},
|
||||
gvr("rbac.authorization.k8s.io", "v1beta1", "rolebindings"): {
|
||||
Stub: `{"metadata": {"name": "roleb2"}, "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/etcdstoragepathtestnamespace/roleb2",
|
||||
ExpectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "RoleBinding"),
|
||||
},
|
||||
gvr("rbac.authorization.k8s.io", "v1beta1", "clusterrolebindings"): {
|
||||
Stub: `{"metadata": {"name": "croleb2"}, "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/croleb2",
|
||||
ExpectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "ClusterRoleBinding"),
|
||||
},
|
||||
// --
|
||||
|
||||
// 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/etcdstoragepathtestnamespace/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/etcdstoragepathtestnamespace/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/v1alpha1
|
||||
gvr("admissionregistration.k8s.io", "v1alpha1", "initializerconfigurations"): {
|
||||
Stub: `{"metadata":{"name":"ic1"},"initializers":[{"name":"initializer.k8s.io","rules":[{"apiGroups":["group"],"apiVersions":["version"],"resources":["resource"]}],"failurePolicy":"Ignore"}]}`,
|
||||
ExpectedEtcdPath: "/registry/initializerconfigurations/ic1",
|
||||
},
|
||||
// k8s.io/kubernetes/pkg/apis/admissionregistration/v1beta1
|
||||
gvr("admissionregistration.k8s.io", "v1beta1", "validatingwebhookconfigurations"): {
|
||||
Stub: `{"metadata":{"name":"hook1","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"}]}`,
|
||||
ExpectedEtcdPath: "/registry/validatingwebhookconfigurations/hook1",
|
||||
},
|
||||
gvr("admissionregistration.k8s.io", "v1beta1", "mutatingwebhookconfigurations"): {
|
||||
Stub: `{"metadata":{"name":"hook1","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"}]}`,
|
||||
ExpectedEtcdPath: "/registry/mutatingwebhookconfigurations/hook1",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/scheduling/v1alpha1
|
||||
gvr("scheduling.k8s.io", "v1alpha1", "priorityclasses"): {
|
||||
Stub: `{"metadata":{"name":"pc1"},"Value":1000}`,
|
||||
ExpectedEtcdPath: "/registry/priorityclasses/pc1",
|
||||
ExpectedGVK: gvkP("scheduling.k8s.io", "v1beta1", "PriorityClass"),
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/scheduling/v1beta1
|
||||
gvr("scheduling.k8s.io", "v1beta1", "priorityclasses"): {
|
||||
Stub: `{"metadata":{"name":"pc2"},"Value":1000}`,
|
||||
ExpectedEtcdPath: "/registry/priorityclasses/pc2",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1
|
||||
// depends on aggregator using the same ungrouped RESTOptionsGetter as the kube apiserver, not SimpleRestOptionsFactory in aggregator.go
|
||||
gvr("apiregistration.k8s.io", "v1beta1", "apiservices"): {
|
||||
Stub: `{"metadata": {"name": "as1.foo.com"}, "spec": {"group": "foo.com", "version": "as1", "groupPriorityMinimum":100, "versionPriority":10}}`,
|
||||
ExpectedEtcdPath: "/registry/apiregistration.k8s.io/apiservices/as1.foo.com",
|
||||
},
|
||||
// --
|
||||
|
||||
// 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",
|
||||
ExpectedGVK: gvkP("apiregistration.k8s.io", "v1beta1", "APIService"),
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1
|
||||
gvr("apiextensions.k8s.io", "v1beta1", "customresourcedefinitions"): {
|
||||
Stub: `{"metadata": {"name": "openshiftwebconsoleconfigs.webconsole.operator.openshift.io"},"spec": {"scope": "Cluster","group": "webconsole.operator.openshift.io","version": "v1alpha1","names": {"kind": "OpenShiftWebConsoleConfig","plural": "openshiftwebconsoleconfigs","singular": "openshiftwebconsoleconfig"}}}`,
|
||||
ExpectedEtcdPath: "/registry/apiextensions.k8s.io/customresourcedefinitions/openshiftwebconsoleconfigs.webconsole.operator.openshift.io",
|
||||
},
|
||||
// --
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
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}
|
||||
}
|
@ -20,457 +20,23 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/clientv3"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
genericapiserveroptions "k8s.io/apiserver/pkg/server/options"
|
||||
cacheddiscovery "k8s.io/client-go/discovery/cached"
|
||||
"k8s.io/client-go/dynamic"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/restmapper"
|
||||
"k8s.io/kubernetes/cmd/kube-apiserver/app"
|
||||
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
|
||||
"k8s.io/kubernetes/test/integration"
|
||||
"k8s.io/kubernetes/test/integration/framework"
|
||||
|
||||
// install all APIs
|
||||
_ "k8s.io/kubernetes/pkg/master" // TODO what else is needed
|
||||
|
||||
"github.com/coreos/etcd/clientv3"
|
||||
)
|
||||
|
||||
// Etcd data for all persisted objects.
|
||||
var etcdStorageData = map[schema.GroupVersionResource]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
|
||||
}{
|
||||
// k8s.io/kubernetes/pkg/api/v1
|
||||
gvr("", "v1", "configmaps"): {
|
||||
stub: `{"data": {"foo": "bar"}, "metadata": {"name": "cm1"}}`,
|
||||
expectedEtcdPath: "/registry/configmaps/etcdstoragepathtestnamespace/cm1",
|
||||
},
|
||||
gvr("", "v1", "services"): {
|
||||
stub: `{"metadata": {"name": "service1"}, "spec": {"externalName": "service1name", "ports": [{"port": 10000, "targetPort": 11000}], "selector": {"test": "data"}}}`,
|
||||
expectedEtcdPath: "/registry/services/specs/etcdstoragepathtestnamespace/service1",
|
||||
},
|
||||
gvr("", "v1", "podtemplates"): {
|
||||
stub: `{"metadata": {"name": "pt1name"}, "template": {"metadata": {"labels": {"pt": "01"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container9"}]}}}`,
|
||||
expectedEtcdPath: "/registry/podtemplates/etcdstoragepathtestnamespace/pt1name",
|
||||
},
|
||||
gvr("", "v1", "pods"): {
|
||||
stub: `{"metadata": {"name": "pod1"}, "spec": {"containers": [{"image": "fedora:latest", "name": "container7", "resources": {"limits": {"cpu": "1M"}, "requests": {"cpu": "1M"}}}]}}`,
|
||||
expectedEtcdPath: "/registry/pods/etcdstoragepathtestnamespace/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/etcdstoragepathtestnamespace/ep1name",
|
||||
},
|
||||
gvr("", "v1", "resourcequotas"): {
|
||||
stub: `{"metadata": {"name": "rq1name"}, "spec": {"hard": {"cpu": "5M"}}}`,
|
||||
expectedEtcdPath: "/registry/resourcequotas/etcdstoragepathtestnamespace/rq1name",
|
||||
},
|
||||
gvr("", "v1", "limitranges"): {
|
||||
stub: `{"metadata": {"name": "lr1name"}, "spec": {"limits": [{"type": "Pod"}]}}`,
|
||||
expectedEtcdPath: "/registry/limitranges/etcdstoragepathtestnamespace/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": "etcdstoragepathtestnamespace"}, "message": "some data here", "metadata": {"name": "event1"}}`,
|
||||
expectedEtcdPath: "/registry/events/etcdstoragepathtestnamespace/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/etcdstoragepathtestnamespace/pvc1",
|
||||
},
|
||||
gvr("", "v1", "serviceaccounts"): {
|
||||
stub: `{"metadata": {"name": "sa1name"}, "secrets": [{"name": "secret00"}]}`,
|
||||
expectedEtcdPath: "/registry/serviceaccounts/etcdstoragepathtestnamespace/sa1name",
|
||||
},
|
||||
gvr("", "v1", "secrets"): {
|
||||
stub: `{"data": {"key": "ZGF0YSBmaWxl"}, "metadata": {"name": "secret1"}}`,
|
||||
expectedEtcdPath: "/registry/secrets/etcdstoragepathtestnamespace/secret1",
|
||||
},
|
||||
gvr("", "v1", "replicationcontrollers"): {
|
||||
stub: `{"metadata": {"name": "rc1"}, "spec": {"selector": {"new": "stuff"}, "template": {"metadata": {"labels": {"new": "stuff"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container8"}]}}}}`,
|
||||
expectedEtcdPath: "/registry/controllers/etcdstoragepathtestnamespace/rc1",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/apps/v1beta1
|
||||
gvr("apps", "v1beta1", "statefulsets"): {
|
||||
stub: `{"metadata": {"name": "ss1"}, "spec": {"selector": {"matchLabels": {"a": "b"}}, "template": {"metadata": {"labels": {"a": "b"}}}}}`,
|
||||
expectedEtcdPath: "/registry/statefulsets/etcdstoragepathtestnamespace/ss1",
|
||||
expectedGVK: gvkP("apps", "v1", "StatefulSet"),
|
||||
},
|
||||
gvr("apps", "v1beta1", "deployments"): {
|
||||
stub: `{"metadata": {"name": "deployment2"}, "spec": {"selector": {"matchLabels": {"f": "z"}}, "template": {"metadata": {"labels": {"f": "z"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container6"}]}}}}`,
|
||||
expectedEtcdPath: "/registry/deployments/etcdstoragepathtestnamespace/deployment2",
|
||||
expectedGVK: gvkP("apps", "v1", "Deployment"),
|
||||
},
|
||||
gvr("apps", "v1beta1", "controllerrevisions"): {
|
||||
stub: `{"metadata":{"name":"crs1"},"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/etcdstoragepathtestnamespace/crs1",
|
||||
expectedGVK: gvkP("apps", "v1", "ControllerRevision"),
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/apps/v1beta2
|
||||
gvr("apps", "v1beta2", "statefulsets"): {
|
||||
stub: `{"metadata": {"name": "ss2"}, "spec": {"selector": {"matchLabels": {"a": "b"}}, "template": {"metadata": {"labels": {"a": "b"}}}}}`,
|
||||
expectedEtcdPath: "/registry/statefulsets/etcdstoragepathtestnamespace/ss2",
|
||||
expectedGVK: gvkP("apps", "v1", "StatefulSet"),
|
||||
},
|
||||
gvr("apps", "v1beta2", "deployments"): {
|
||||
stub: `{"metadata": {"name": "deployment3"}, "spec": {"selector": {"matchLabels": {"f": "z"}}, "template": {"metadata": {"labels": {"f": "z"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container6"}]}}}}`,
|
||||
expectedEtcdPath: "/registry/deployments/etcdstoragepathtestnamespace/deployment3",
|
||||
expectedGVK: gvkP("apps", "v1", "Deployment"),
|
||||
},
|
||||
gvr("apps", "v1beta2", "daemonsets"): {
|
||||
stub: `{"metadata": {"name": "ds5"}, "spec": {"selector": {"matchLabels": {"a": "b"}}, "template": {"metadata": {"labels": {"a": "b"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container6"}]}}}}`,
|
||||
expectedEtcdPath: "/registry/daemonsets/etcdstoragepathtestnamespace/ds5",
|
||||
expectedGVK: gvkP("apps", "v1", "DaemonSet"),
|
||||
},
|
||||
gvr("apps", "v1beta2", "replicasets"): {
|
||||
stub: `{"metadata": {"name": "rs2"}, "spec": {"selector": {"matchLabels": {"g": "h"}}, "template": {"metadata": {"labels": {"g": "h"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container4"}]}}}}`,
|
||||
expectedEtcdPath: "/registry/replicasets/etcdstoragepathtestnamespace/rs2",
|
||||
expectedGVK: gvkP("apps", "v1", "ReplicaSet"),
|
||||
},
|
||||
gvr("apps", "v1beta2", "controllerrevisions"): {
|
||||
stub: `{"metadata":{"name":"crs2"},"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/etcdstoragepathtestnamespace/crs2",
|
||||
expectedGVK: gvkP("apps", "v1", "ControllerRevision"),
|
||||
},
|
||||
// --
|
||||
|
||||
// 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": "fedora:latest", "name": "container6"}]}}}}`,
|
||||
expectedEtcdPath: "/registry/daemonsets/etcdstoragepathtestnamespace/ds6",
|
||||
},
|
||||
gvr("apps", "v1", "deployments"): {
|
||||
stub: `{"metadata": {"name": "deployment4"}, "spec": {"selector": {"matchLabels": {"f": "z"}}, "template": {"metadata": {"labels": {"f": "z"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container6"}]}}}}`,
|
||||
expectedEtcdPath: "/registry/deployments/etcdstoragepathtestnamespace/deployment4",
|
||||
},
|
||||
gvr("apps", "v1", "statefulsets"): {
|
||||
stub: `{"metadata": {"name": "ss3"}, "spec": {"selector": {"matchLabels": {"a": "b"}}, "template": {"metadata": {"labels": {"a": "b"}}}}}`,
|
||||
expectedEtcdPath: "/registry/statefulsets/etcdstoragepathtestnamespace/ss3",
|
||||
},
|
||||
gvr("apps", "v1", "replicasets"): {
|
||||
stub: `{"metadata": {"name": "rs3"}, "spec": {"selector": {"matchLabels": {"g": "h"}}, "template": {"metadata": {"labels": {"g": "h"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container4"}]}}}}`,
|
||||
expectedEtcdPath: "/registry/replicasets/etcdstoragepathtestnamespace/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/etcdstoragepathtestnamespace/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/etcdstoragepathtestnamespace/hpa2",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/autoscaling/v2beta1
|
||||
gvr("autoscaling", "v2beta1", "horizontalpodautoscalers"): {
|
||||
stub: `{"metadata": {"name": "hpa1"}, "spec": {"maxReplicas": 3, "scaleTargetRef": {"kind": "something", "name": "cross"}}}`,
|
||||
expectedEtcdPath: "/registry/horizontalpodautoscalers/etcdstoragepathtestnamespace/hpa1",
|
||||
expectedGVK: gvkP("autoscaling", "v1", "HorizontalPodAutoscaler"),
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/autoscaling/v2beta2
|
||||
gvr("autoscaling", "v2beta2", "horizontalpodautoscalers"): {
|
||||
stub: `{"metadata": {"name": "hpa3"}, "spec": {"maxReplicas": 3, "scaleTargetRef": {"kind": "something", "name": "cross"}}}`,
|
||||
expectedEtcdPath: "/registry/horizontalpodautoscalers/etcdstoragepathtestnamespace/hpa3",
|
||||
expectedGVK: gvkP("autoscaling", "v1", "HorizontalPodAutoscaler"),
|
||||
},
|
||||
// --
|
||||
|
||||
// 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": "fedora:latest", "name": "container1"}], "dnsPolicy": "ClusterFirst", "restartPolicy": "Never"}}}}`,
|
||||
expectedEtcdPath: "/registry/jobs/etcdstoragepathtestnamespace/job1",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/batch/v1beta1
|
||||
gvr("batch", "v1beta1", "cronjobs"): {
|
||||
stub: `{"metadata": {"name": "cjv1beta1"}, "spec": {"jobTemplate": {"spec": {"template": {"metadata": {"labels": {"controller-uid": "uid0"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container0"}], "dnsPolicy": "ClusterFirst", "restartPolicy": "Never"}}}}, "schedule": "* * * * *"}}`,
|
||||
expectedEtcdPath: "/registry/cronjobs/etcdstoragepathtestnamespace/cjv1beta1",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/batch/v2alpha1
|
||||
gvr("batch", "v2alpha1", "cronjobs"): {
|
||||
stub: `{"metadata": {"name": "cjv2alpha1"}, "spec": {"jobTemplate": {"spec": {"template": {"metadata": {"labels": {"controller-uid": "uid0"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container0"}], "dnsPolicy": "ClusterFirst", "restartPolicy": "Never"}}}}, "schedule": "* * * * *"}}`,
|
||||
expectedEtcdPath: "/registry/cronjobs/etcdstoragepathtestnamespace/cjv2alpha1",
|
||||
expectedGVK: gvkP("batch", "v1beta1", "CronJob"),
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/certificates/v1beta1
|
||||
gvr("certificates.k8s.io", "v1beta1", "certificatesigningrequests"): {
|
||||
stub: `{"metadata": {"name": "csr1"}, "spec": {"request": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQnlqQ0NBVE1DQVFBd2dZa3hDekFKQmdOVkJBWVRBbFZUTVJNd0VRWURWUVFJRXdwRFlXeHBabTl5Ym1saApNUll3RkFZRFZRUUhFdzFOYjNWdWRHRnBiaUJXYVdWM01STXdFUVlEVlFRS0V3cEhiMjluYkdVZ1NXNWpNUjh3CkhRWURWUVFMRXhaSmJtWnZjbTFoZEdsdmJpQlVaV05vYm05c2IyZDVNUmN3RlFZRFZRUURFdzUzZDNjdVoyOXYKWjJ4bExtTnZiVENCbnpBTkJna3Foa2lHOXcwQkFRRUZBQU9CalFBd2dZa0NnWUVBcFp0WUpDSEo0VnBWWEhmVgpJbHN0UVRsTzRxQzAzaGpYK1prUHl2ZFlkMVE0K3FiQWVUd1htQ1VLWUhUaFZSZDVhWFNxbFB6eUlCd2llTVpyCldGbFJRZGRaMUl6WEFsVlJEV3dBbzYwS2VjcWVBWG5uVUsrNWZYb1RJL1VnV3NocmU4dEoreC9UTUhhUUtSL0oKY0lXUGhxYVFoc0p1elpidkFkR0E4MEJMeGRNQ0F3RUFBYUFBTUEwR0NTcUdTSWIzRFFFQkJRVUFBNEdCQUlobAo0UHZGcStlN2lwQVJnSTVaTStHWng2bXBDejQ0RFRvMEprd2ZSRGYrQnRyc2FDMHE2OGVUZjJYaFlPc3E0ZmtIClEwdUEwYVZvZzNmNWlKeENhM0hwNWd4YkpRNnpWNmtKMFRFc3VhYU9oRWtvOXNkcENvUE9uUkJtMmkvWFJEMkQKNmlOaDhmOHowU2hHc0ZxakRnRkh5RjNvK2xVeWorVUM2SDFRVzdibgotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0="}}`,
|
||||
expectedEtcdPath: "/registry/certificatesigningrequests/csr1",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/coordination/v1beta1
|
||||
gvr("coordination.k8s.io", "v1beta1", "leases"): {
|
||||
stub: `{"metadata": {"name": "lease1"}, "spec": {"holderIdentity": "holder", "leaseDurationSeconds": 5}}`,
|
||||
expectedEtcdPath: "/registry/leases/etcdstoragepathtestnamespace/lease1",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/events/v1beta1
|
||||
gvr("events.k8s.io", "v1beta1", "events"): {
|
||||
stub: `{"metadata": {"name": "event2"}, "regarding": {"namespace": "etcdstoragepathtestnamespace"}, "note": "some data here", "eventTime": "2017-08-09T15:04:05.000000Z", "reportingInstance": "node-xyz", "reportingController": "k8s.io/my-controller", "action": "DidNothing", "reason": "Laziness"}`,
|
||||
expectedEtcdPath: "/registry/events/etcdstoragepathtestnamespace/event2",
|
||||
expectedGVK: gvkP("", "v1", "Event"),
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/extensions/v1beta1
|
||||
gvr("extensions", "v1beta1", "daemonsets"): {
|
||||
stub: `{"metadata": {"name": "ds1"}, "spec": {"selector": {"matchLabels": {"u": "t"}}, "template": {"metadata": {"labels": {"u": "t"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container5"}]}}}}`,
|
||||
expectedEtcdPath: "/registry/daemonsets/etcdstoragepathtestnamespace/ds1",
|
||||
expectedGVK: gvkP("apps", "v1", "DaemonSet"),
|
||||
},
|
||||
gvr("extensions", "v1beta1", "podsecuritypolicies"): {
|
||||
stub: `{"metadata": {"name": "psp1"}, "spec": {"fsGroup": {"rule": "RunAsAny"}, "privileged": true, "runAsUser": {"rule": "RunAsAny"}, "seLinux": {"rule": "MustRunAs"}, "supplementalGroups": {"rule": "RunAsAny"}}}`,
|
||||
expectedEtcdPath: "/registry/podsecuritypolicy/psp1",
|
||||
expectedGVK: gvkP("policy", "v1beta1", "PodSecurityPolicy"),
|
||||
},
|
||||
gvr("extensions", "v1beta1", "ingresses"): {
|
||||
stub: `{"metadata": {"name": "ingress1"}, "spec": {"backend": {"serviceName": "service", "servicePort": 5000}}}`,
|
||||
expectedEtcdPath: "/registry/ingress/etcdstoragepathtestnamespace/ingress1",
|
||||
},
|
||||
gvr("extensions", "v1beta1", "networkpolicies"): {
|
||||
stub: `{"metadata": {"name": "np1"}, "spec": {"podSelector": {"matchLabels": {"e": "f"}}}}`,
|
||||
expectedEtcdPath: "/registry/networkpolicies/etcdstoragepathtestnamespace/np1",
|
||||
expectedGVK: gvkP("networking.k8s.io", "v1", "NetworkPolicy"),
|
||||
},
|
||||
gvr("extensions", "v1beta1", "deployments"): {
|
||||
stub: `{"metadata": {"name": "deployment1"}, "spec": {"selector": {"matchLabels": {"f": "z"}}, "template": {"metadata": {"labels": {"f": "z"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container6"}]}}}}`,
|
||||
expectedEtcdPath: "/registry/deployments/etcdstoragepathtestnamespace/deployment1",
|
||||
expectedGVK: gvkP("apps", "v1", "Deployment"),
|
||||
},
|
||||
gvr("extensions", "v1beta1", "replicasets"): {
|
||||
stub: `{"metadata": {"name": "rs1"}, "spec": {"selector": {"matchLabels": {"g": "h"}}, "template": {"metadata": {"labels": {"g": "h"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container4"}]}}}}`,
|
||||
expectedEtcdPath: "/registry/replicasets/etcdstoragepathtestnamespace/rs1",
|
||||
expectedGVK: gvkP("apps", "v1", "ReplicaSet"),
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/networking/v1
|
||||
gvr("networking.k8s.io", "v1", "networkpolicies"): {
|
||||
stub: `{"metadata": {"name": "np2"}, "spec": {"podSelector": {"matchLabels": {"e": "f"}}}}`,
|
||||
expectedEtcdPath: "/registry/networkpolicies/etcdstoragepathtestnamespace/np2",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/policy/v1beta1
|
||||
gvr("policy", "v1beta1", "poddisruptionbudgets"): {
|
||||
stub: `{"metadata": {"name": "pdb1"}, "spec": {"selector": {"matchLabels": {"anokkey": "anokvalue"}}}}`,
|
||||
expectedEtcdPath: "/registry/poddisruptionbudgets/etcdstoragepathtestnamespace/pdb1",
|
||||
},
|
||||
gvr("policy", "v1beta1", "podsecuritypolicies"): {
|
||||
stub: `{"metadata": {"name": "psp2"}, "spec": {"fsGroup": {"rule": "RunAsAny"}, "privileged": true, "runAsUser": {"rule": "RunAsAny"}, "seLinux": {"rule": "MustRunAs"}, "supplementalGroups": {"rule": "RunAsAny"}}}`,
|
||||
expectedEtcdPath: "/registry/podsecuritypolicy/psp2",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/storage/v1alpha1
|
||||
gvr("storage.k8s.io", "v1alpha1", "volumeattachments"): {
|
||||
stub: `{"metadata": {"name": "va1"}, "spec": {"attacher": "gce", "nodeName": "localhost", "source": {"persistentVolumeName": "pv1"}}}`,
|
||||
expectedEtcdPath: "/registry/volumeattachments/va1",
|
||||
expectedGVK: gvkP("storage.k8s.io", "v1beta1", "VolumeAttachment"),
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/storage/v1beta1
|
||||
gvr("storage.k8s.io", "v1beta1", "volumeattachments"): {
|
||||
stub: `{"metadata": {"name": "va2"}, "spec": {"attacher": "gce", "nodeName": "localhost", "source": {"persistentVolumeName": "pv2"}}}`,
|
||||
expectedEtcdPath: "/registry/volumeattachments/va2",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/storage/v1beta1
|
||||
gvr("storage.k8s.io", "v1beta1", "storageclasses"): {
|
||||
stub: `{"metadata": {"name": "sc1"}, "provisioner": "aws"}`,
|
||||
expectedEtcdPath: "/registry/storageclasses/sc1",
|
||||
expectedGVK: gvkP("storage.k8s.io", "v1", "StorageClass"),
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/storage/v1
|
||||
gvr("storage.k8s.io", "v1", "storageclasses"): {
|
||||
stub: `{"metadata": {"name": "sc2"}, "provisioner": "aws"}`,
|
||||
expectedEtcdPath: "/registry/storageclasses/sc2",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/settings/v1alpha1
|
||||
gvr("settings.k8s.io", "v1alpha1", "podpresets"): {
|
||||
stub: `{"metadata": {"name": "podpre1"}, "spec": {"env": [{"name": "FOO"}]}}`,
|
||||
expectedEtcdPath: "/registry/podpresets/etcdstoragepathtestnamespace/podpre1",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/rbac/v1alpha1
|
||||
gvr("rbac.authorization.k8s.io", "v1alpha1", "roles"): {
|
||||
stub: `{"metadata": {"name": "role1"}, "rules": [{"apiGroups": ["v1"], "resources": ["events"], "verbs": ["watch"]}]}`,
|
||||
expectedEtcdPath: "/registry/roles/etcdstoragepathtestnamespace/role1",
|
||||
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "Role"),
|
||||
},
|
||||
gvr("rbac.authorization.k8s.io", "v1alpha1", "clusterroles"): {
|
||||
stub: `{"metadata": {"name": "crole1"}, "rules": [{"nonResourceURLs": ["/version"], "verbs": ["get"]}]}`,
|
||||
expectedEtcdPath: "/registry/clusterroles/crole1",
|
||||
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "ClusterRole"),
|
||||
},
|
||||
gvr("rbac.authorization.k8s.io", "v1alpha1", "rolebindings"): {
|
||||
stub: `{"metadata": {"name": "roleb1"}, "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/etcdstoragepathtestnamespace/roleb1",
|
||||
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "RoleBinding"),
|
||||
},
|
||||
gvr("rbac.authorization.k8s.io", "v1alpha1", "clusterrolebindings"): {
|
||||
stub: `{"metadata": {"name": "croleb1"}, "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/croleb1",
|
||||
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "ClusterRoleBinding"),
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/rbac/v1beta1
|
||||
gvr("rbac.authorization.k8s.io", "v1beta1", "roles"): {
|
||||
stub: `{"metadata": {"name": "role2"}, "rules": [{"apiGroups": ["v1"], "resources": ["events"], "verbs": ["watch"]}]}`,
|
||||
expectedEtcdPath: "/registry/roles/etcdstoragepathtestnamespace/role2",
|
||||
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "Role"),
|
||||
},
|
||||
gvr("rbac.authorization.k8s.io", "v1beta1", "clusterroles"): {
|
||||
stub: `{"metadata": {"name": "crole2"}, "rules": [{"nonResourceURLs": ["/version"], "verbs": ["get"]}]}`,
|
||||
expectedEtcdPath: "/registry/clusterroles/crole2",
|
||||
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "ClusterRole"),
|
||||
},
|
||||
gvr("rbac.authorization.k8s.io", "v1beta1", "rolebindings"): {
|
||||
stub: `{"metadata": {"name": "roleb2"}, "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/etcdstoragepathtestnamespace/roleb2",
|
||||
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "RoleBinding"),
|
||||
},
|
||||
gvr("rbac.authorization.k8s.io", "v1beta1", "clusterrolebindings"): {
|
||||
stub: `{"metadata": {"name": "croleb2"}, "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/croleb2",
|
||||
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "ClusterRoleBinding"),
|
||||
},
|
||||
// --
|
||||
|
||||
// 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/etcdstoragepathtestnamespace/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/etcdstoragepathtestnamespace/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/v1alpha1
|
||||
gvr("admissionregistration.k8s.io", "v1alpha1", "initializerconfigurations"): {
|
||||
stub: `{"metadata":{"name":"ic1"},"initializers":[{"name":"initializer.k8s.io","rules":[{"apiGroups":["group"],"apiVersions":["version"],"resources":["resource"]}],"failurePolicy":"Ignore"}]}`,
|
||||
expectedEtcdPath: "/registry/initializerconfigurations/ic1",
|
||||
},
|
||||
// k8s.io/kubernetes/pkg/apis/admissionregistration/v1beta1
|
||||
gvr("admissionregistration.k8s.io", "v1beta1", "validatingwebhookconfigurations"): {
|
||||
stub: `{"metadata":{"name":"hook1","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"}]}`,
|
||||
expectedEtcdPath: "/registry/validatingwebhookconfigurations/hook1",
|
||||
},
|
||||
gvr("admissionregistration.k8s.io", "v1beta1", "mutatingwebhookconfigurations"): {
|
||||
stub: `{"metadata":{"name":"hook1","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"}]}`,
|
||||
expectedEtcdPath: "/registry/mutatingwebhookconfigurations/hook1",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/scheduling/v1alpha1
|
||||
gvr("scheduling.k8s.io", "v1alpha1", "priorityclasses"): {
|
||||
stub: `{"metadata":{"name":"pc1"},"Value":1000}`,
|
||||
expectedEtcdPath: "/registry/priorityclasses/pc1",
|
||||
expectedGVK: gvkP("scheduling.k8s.io", "v1beta1", "PriorityClass"),
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kubernetes/pkg/apis/scheduling/v1beta1
|
||||
gvr("scheduling.k8s.io", "v1beta1", "priorityclasses"): {
|
||||
stub: `{"metadata":{"name":"pc2"},"Value":1000}`,
|
||||
expectedEtcdPath: "/registry/priorityclasses/pc2",
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1
|
||||
// depends on aggregator using the same ungrouped RESTOptionsGetter as the kube apiserver, not SimpleRestOptionsFactory in aggregator.go
|
||||
gvr("apiregistration.k8s.io", "v1beta1", "apiservices"): {
|
||||
stub: `{"metadata": {"name": "as1.foo.com"}, "spec": {"group": "foo.com", "version": "as1", "groupPriorityMinimum":100, "versionPriority":10}}`,
|
||||
expectedEtcdPath: "/registry/apiregistration.k8s.io/apiservices/as1.foo.com",
|
||||
},
|
||||
// --
|
||||
|
||||
// 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",
|
||||
expectedGVK: gvkP("apiregistration.k8s.io", "v1beta1", "APIService"),
|
||||
},
|
||||
// --
|
||||
|
||||
// k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1
|
||||
gvr("apiextensions.k8s.io", "v1beta1", "customresourcedefinitions"): {
|
||||
stub: `{"metadata": {"name": "openshiftwebconsoleconfigs.webconsole.operator.openshift.io"},"spec": {"scope": "Cluster","group": "webconsole.operator.openshift.io","version": "v1alpha1","names": {"kind": "OpenShiftWebConsoleConfig","plural": "openshiftwebconsoleconfigs","singular": "openshiftwebconsoleconfig"}}}`,
|
||||
expectedEtcdPath: "/registry/apiextensions.k8s.io/customresourcedefinitions/openshiftwebconsoleconfigs.webconsole.operator.openshift.io",
|
||||
},
|
||||
// --
|
||||
|
||||
}
|
||||
|
||||
// Only add kinds to this list when this a virtual resource with get and create verbs that doesn't actually
|
||||
// store into it's kind. We've used this downstream for mappings before.
|
||||
var kindWhiteList = sets.NewString()
|
||||
@ -483,51 +49,30 @@ const testNamespace = "etcdstoragepathtestnamespace"
|
||||
// It will also fail when a type gets moved to a different location. Be very careful in this situation because
|
||||
// it essentially means that you will be break old clusters unless you create some migration path for the old data.
|
||||
func TestEtcdStoragePath(t *testing.T) {
|
||||
certDir, _ := ioutil.TempDir("", "test-integration-etcd")
|
||||
defer os.RemoveAll(certDir)
|
||||
master := StartRealMasterOrDie(t)
|
||||
defer master.Cleanup()
|
||||
defer dumpEtcdKVOnFailure(t, master.KV)
|
||||
|
||||
clientConfig, kvClient := startRealMasterOrDie(t, certDir)
|
||||
defer func() {
|
||||
dumpEtcdKVOnFailure(t, kvClient)
|
||||
}()
|
||||
client := &allClient{dynamicClient: master.Dynamic}
|
||||
|
||||
client := &allClient{dynamicClient: dynamic.NewForConfigOrDie(clientConfig)}
|
||||
kubeClient := clientset.NewForConfigOrDie(clientConfig)
|
||||
if _, err := kubeClient.CoreV1().Namespaces().Create(&v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: testNamespace}}); err != nil {
|
||||
if _, err := master.Client.CoreV1().Namespaces().Create(&v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: testNamespace}}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
discoveryClient := cacheddiscovery.NewMemCacheClient(kubeClient.Discovery())
|
||||
restMapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient)
|
||||
restMapper.Reset()
|
||||
|
||||
resourcesToPersist := []resourceToPersist{}
|
||||
serverResources, err := kubeClient.Discovery().ServerResources()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
resourcesToPersist = append(resourcesToPersist, getResourcesToPersist(serverResources, false, t)...)
|
||||
etcdStorageData := GetEtcdStorageData()
|
||||
|
||||
kindSeen := sets.NewString()
|
||||
pathSeen := map[string][]schema.GroupVersionResource{}
|
||||
etcdSeen := map[schema.GroupVersionResource]empty{}
|
||||
cohabitatingResources := map[string]map[schema.GroupVersionKind]empty{}
|
||||
|
||||
for _, resourceToPersist := range resourcesToPersist {
|
||||
t.Run(resourceToPersist.gvr.String(), func(t *testing.T) {
|
||||
gvk := resourceToPersist.gvk
|
||||
gvResource := resourceToPersist.gvr
|
||||
for _, resourceToPersist := range master.Resources {
|
||||
t.Run(resourceToPersist.Mapping.Resource.String(), func(t *testing.T) {
|
||||
mapping := resourceToPersist.Mapping
|
||||
gvk := resourceToPersist.Mapping.GroupVersionKind
|
||||
gvResource := resourceToPersist.Mapping.Resource
|
||||
kind := gvk.Kind
|
||||
|
||||
mapping := &meta.RESTMapping{
|
||||
Resource: resourceToPersist.gvr,
|
||||
GroupVersionKind: resourceToPersist.gvk,
|
||||
Scope: meta.RESTScopeRoot,
|
||||
}
|
||||
if resourceToPersist.namespaced {
|
||||
mapping.Scope = meta.RESTScopeNamespace
|
||||
}
|
||||
|
||||
if kindWhiteList.Has(kind) {
|
||||
kindSeen.Insert(kind)
|
||||
t.Skip("whitelisted")
|
||||
@ -537,18 +82,21 @@ func TestEtcdStoragePath(t *testing.T) {
|
||||
testData, hasTest := etcdStorageData[gvResource]
|
||||
|
||||
if !hasTest {
|
||||
t.Fatalf("no test data for %s. Please add a test for your new type to etcdStorageData.", gvResource)
|
||||
t.Fatalf("no test data for %s. Please add a test for your new type to GetEtcdStorageData().", gvResource)
|
||||
}
|
||||
|
||||
if len(testData.expectedEtcdPath) == 0 {
|
||||
if len(testData.ExpectedEtcdPath) == 0 {
|
||||
t.Fatalf("empty test data for %s", gvResource)
|
||||
}
|
||||
|
||||
shouldCreate := len(testData.stub) != 0 // try to create only if we have a stub
|
||||
shouldCreate := len(testData.Stub) != 0 // try to create only if we have a stub
|
||||
|
||||
var input *metaObject
|
||||
var (
|
||||
input *metaObject
|
||||
err error
|
||||
)
|
||||
if shouldCreate {
|
||||
if input, err = jsonToMetaObject([]byte(testData.stub)); err != nil || input.isEmpty() {
|
||||
if input, err = jsonToMetaObject([]byte(testData.Stub)); err != nil || input.isEmpty() {
|
||||
t.Fatalf("invalid test data for %s: %v", gvResource, err)
|
||||
}
|
||||
}
|
||||
@ -562,27 +110,27 @@ func TestEtcdStoragePath(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
|
||||
if err := client.createPrerequisites(restMapper, testNamespace, testData.prerequisites, all); err != nil {
|
||||
if err := client.createPrerequisites(master.Mapper, testNamespace, testData.Prerequisites, all); err != nil {
|
||||
t.Fatalf("failed to create prerequisites for %s: %#v", gvResource, err)
|
||||
}
|
||||
|
||||
if shouldCreate { // do not try to create items with no stub
|
||||
if err := client.create(testData.stub, testNamespace, mapping, all); err != nil {
|
||||
if err := client.create(testData.Stub, testNamespace, mapping, all); err != nil {
|
||||
t.Fatalf("failed to create stub for %s: %#v", gvResource, err)
|
||||
}
|
||||
}
|
||||
|
||||
output, err := getFromEtcd(kvClient, testData.expectedEtcdPath)
|
||||
output, err := getFromEtcd(master.KV, testData.ExpectedEtcdPath)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get from etcd for %s: %#v", gvResource, err)
|
||||
}
|
||||
|
||||
expectedGVK := gvk
|
||||
if testData.expectedGVK != nil {
|
||||
if gvk == *testData.expectedGVK {
|
||||
t.Errorf("GVK override %s for %s is unnecessary or something was changed incorrectly", testData.expectedGVK, gvk)
|
||||
if testData.ExpectedGVK != nil {
|
||||
if gvk == *testData.ExpectedGVK {
|
||||
t.Errorf("GVK override %s for %s is unnecessary or something was changed incorrectly", testData.ExpectedGVK, gvk)
|
||||
}
|
||||
expectedGVK = *testData.expectedGVK
|
||||
expectedGVK = *testData.ExpectedGVK
|
||||
}
|
||||
|
||||
actualGVK := output.getGVK()
|
||||
@ -594,8 +142,8 @@ func TestEtcdStoragePath(t *testing.T) {
|
||||
t.Errorf("Test stub for %s does not match: %s", kind, diff.ObjectGoPrintDiff(input, output))
|
||||
}
|
||||
|
||||
addGVKToEtcdBucket(cohabitatingResources, actualGVK, getEtcdBucket(testData.expectedEtcdPath))
|
||||
pathSeen[testData.expectedEtcdPath] = append(pathSeen[testData.expectedEtcdPath], mapping.Resource)
|
||||
addGVKToEtcdBucket(cohabitatingResources, actualGVK, getEtcdBucket(testData.ExpectedEtcdPath))
|
||||
pathSeen[testData.ExpectedEtcdPath] = append(pathSeen[testData.ExpectedEtcdPath], mapping.Resource)
|
||||
})
|
||||
}
|
||||
|
||||
@ -627,81 +175,6 @@ func TestEtcdStoragePath(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func startRealMasterOrDie(t *testing.T, certDir string) (*restclient.Config, clientv3.KV) {
|
||||
_, defaultServiceClusterIPRange, err := net.ParseCIDR("10.0.0.0/24")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
listener, _, err := genericapiserveroptions.CreateListener("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
kubeAPIServerOptions := options.NewServerRunOptions()
|
||||
kubeAPIServerOptions.InsecureServing.BindPort = 0
|
||||
kubeAPIServerOptions.SecureServing.Listener = listener
|
||||
kubeAPIServerOptions.SecureServing.ServerCert.CertDirectory = certDir
|
||||
kubeAPIServerOptions.Etcd.StorageConfig.ServerList = []string{framework.GetEtcdURL()}
|
||||
kubeAPIServerOptions.Etcd.DefaultStorageMediaType = runtime.ContentTypeJSON // force json we can easily interpret the result in etcd
|
||||
kubeAPIServerOptions.ServiceClusterIPRange = *defaultServiceClusterIPRange
|
||||
kubeAPIServerOptions.Authorization.Modes = []string{"RBAC"}
|
||||
kubeAPIServerOptions.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
||||
completedOptions, err := app.Complete(kubeAPIServerOptions)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
kubeAPIServerOptions.APIEnablement.RuntimeConfig.Set("api/all=true")
|
||||
|
||||
kubeAPIServer, err := app.CreateServerChain(completedOptions, wait.NeverStop)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
kubeClientConfig := restclient.CopyConfig(kubeAPIServer.LoopbackClientConfig)
|
||||
|
||||
go func() {
|
||||
// Catch panics that occur in this go routine so we get a comprehensible failure
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
t.Errorf("Unexpected panic trying to start API master: %#v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := kubeAPIServer.PrepareRun().Run(wait.NeverStop); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
lastHealth := ""
|
||||
if err := wait.PollImmediate(time.Second, time.Minute, func() (done bool, err error) {
|
||||
// wait for the server to be healthy
|
||||
result := clientset.NewForConfigOrDie(kubeClientConfig).RESTClient().Get().AbsPath("/healthz").Do()
|
||||
content, _ := result.Raw()
|
||||
lastHealth = string(content)
|
||||
if errResult := result.Error(); errResult != nil {
|
||||
t.Log(errResult)
|
||||
return false, nil
|
||||
}
|
||||
var status int
|
||||
result.StatusCode(&status)
|
||||
return status == http.StatusOK, nil
|
||||
}); err != nil {
|
||||
t.Log(lastHealth)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// this test makes lots of requests, don't be slow
|
||||
kubeClientConfig.QPS = 99999
|
||||
kubeClientConfig.Burst = 9999
|
||||
|
||||
kvClient, err := integration.GetEtcdKVClient(kubeAPIServerOptions.Etcd.StorageConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return kubeClientConfig, kvClient
|
||||
}
|
||||
|
||||
func dumpEtcdKVOnFailure(t *testing.T, kvClient clientv3.KV) {
|
||||
if t.Failed() {
|
||||
response, err := kvClient.Get(context.Background(), "/", clientv3.WithPrefix())
|
||||
@ -758,11 +231,6 @@ func (obj *metaObject) isEmpty() bool {
|
||||
return obj == nil || *obj == metaObject{} // compare to zero value since all fields are strings
|
||||
}
|
||||
|
||||
type prerequisite struct {
|
||||
gvrData schema.GroupVersionResource
|
||||
stub string
|
||||
}
|
||||
|
||||
type empty struct{}
|
||||
|
||||
type cleanupData struct {
|
||||
@ -770,14 +238,6 @@ type cleanupData struct {
|
||||
resource schema.GroupVersionResource
|
||||
}
|
||||
|
||||
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 jsonToMetaObject(stub []byte) (*metaObject, error) {
|
||||
obj := &metaObject{}
|
||||
if err := json.Unmarshal(stub, obj); err != nil {
|
||||
@ -805,25 +265,18 @@ type allClient struct {
|
||||
}
|
||||
|
||||
func (c *allClient) create(stub, ns string, mapping *meta.RESTMapping, all *[]cleanupData) error {
|
||||
// we don't require GVK on the data we provide, so we fill it in here. We could, but that seems extraneous.
|
||||
typeMetaAdder := map[string]interface{}{}
|
||||
err := json.Unmarshal([]byte(stub), &typeMetaAdder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
typeMetaAdder["apiVersion"] = mapping.GroupVersionKind.GroupVersion().String()
|
||||
typeMetaAdder["kind"] = mapping.GroupVersionKind.Kind
|
||||
|
||||
if mapping.Scope == meta.RESTScopeRoot {
|
||||
ns = ""
|
||||
}
|
||||
obj := &unstructured.Unstructured{Object: typeMetaAdder}
|
||||
actual, err := c.dynamicClient.Resource(mapping.Resource).Namespace(ns).Create(obj, metav1.CreateOptions{})
|
||||
resourceClient, obj, err := JSONToUnstructured(stub, ns, mapping, c.dynamicClient)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*all = append(*all, cleanupData{actual, mapping.Resource})
|
||||
actual, err := resourceClient.Create(obj, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*all = append(*all, cleanupData{obj: actual, resource: mapping.Resource})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -839,9 +292,9 @@ func (c *allClient) cleanup(all *[]cleanupData) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *allClient) createPrerequisites(mapper meta.RESTMapper, ns string, prerequisites []prerequisite, all *[]cleanupData) error {
|
||||
func (c *allClient) createPrerequisites(mapper meta.RESTMapper, ns string, prerequisites []Prerequisite, all *[]cleanupData) error {
|
||||
for _, prerequisite := range prerequisites {
|
||||
gvk, err := mapper.KindFor(prerequisite.gvrData)
|
||||
gvk, err := mapper.KindFor(prerequisite.GvrData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -849,7 +302,7 @@ func (c *allClient) createPrerequisites(mapper meta.RESTMapper, ns string, prere
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.create(prerequisite.stub, ns, mapping, all); err != nil {
|
||||
if err := c.create(prerequisite.Stub, ns, mapping, all); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -895,58 +348,3 @@ func diffMapKeys(a, b interface{}, stringer func(interface{}) string) []string {
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
type resourceToPersist struct {
|
||||
gvk schema.GroupVersionKind
|
||||
gvr schema.GroupVersionResource
|
||||
golangType reflect.Type
|
||||
namespaced bool
|
||||
}
|
||||
|
||||
func getResourcesToPersist(serverResources []*metav1.APIResourceList, isOAPI bool, t *testing.T) []resourceToPersist {
|
||||
resourcesToPersist := []resourceToPersist{}
|
||||
|
||||
for _, discoveryGroup := range serverResources {
|
||||
for _, discoveryResource := range discoveryGroup.APIResources {
|
||||
// this is a subresource, skip it
|
||||
if strings.Contains(discoveryResource.Name, "/") {
|
||||
continue
|
||||
}
|
||||
hasCreate := false
|
||||
hasGet := false
|
||||
for _, verb := range discoveryResource.Verbs {
|
||||
if string(verb) == "get" {
|
||||
hasGet = true
|
||||
}
|
||||
if string(verb) == "create" {
|
||||
hasCreate = true
|
||||
}
|
||||
}
|
||||
if !(hasCreate && hasGet) {
|
||||
continue
|
||||
}
|
||||
|
||||
resourceGV, err := schema.ParseGroupVersion(discoveryGroup.GroupVersion)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
gvk := resourceGV.WithKind(discoveryResource.Kind)
|
||||
if len(discoveryResource.Group) > 0 || len(discoveryResource.Version) > 0 {
|
||||
gvk = schema.GroupVersionKind{
|
||||
Group: discoveryResource.Group,
|
||||
Version: discoveryResource.Version,
|
||||
Kind: discoveryResource.Kind,
|
||||
}
|
||||
}
|
||||
gvr := resourceGV.WithResource(discoveryResource.Name)
|
||||
|
||||
resourcesToPersist = append(resourcesToPersist, resourceToPersist{
|
||||
gvk: gvk,
|
||||
gvr: gvr,
|
||||
namespaced: discoveryResource.Namespaced,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return resourcesToPersist
|
||||
}
|
||||
|
283
test/integration/etcd/server.go
Normal file
283
test/integration/etcd/server.go
Normal file
@ -0,0 +1,283 @@
|
||||
/*
|
||||
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 (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/clientv3"
|
||||
"github.com/coreos/etcd/clientv3/concurrency"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
genericapiserveroptions "k8s.io/apiserver/pkg/server/options"
|
||||
cacheddiscovery "k8s.io/client-go/discovery/cached"
|
||||
"k8s.io/client-go/dynamic"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/restmapper"
|
||||
"k8s.io/kubernetes/cmd/kube-apiserver/app"
|
||||
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
|
||||
"k8s.io/kubernetes/test/integration"
|
||||
"k8s.io/kubernetes/test/integration/framework"
|
||||
|
||||
// install all APIs
|
||||
_ "k8s.io/kubernetes/pkg/master"
|
||||
)
|
||||
|
||||
// StartRealMasterOrDie starts an API master that is appropriate for use in tests that require one of every resource
|
||||
func StartRealMasterOrDie(t *testing.T) *Master {
|
||||
certDir, err := ioutil.TempDir("", t.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, defaultServiceClusterIPRange, err := net.ParseCIDR("10.0.0.0/24")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
listener, _, err := genericapiserveroptions.CreateListener("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
kubeAPIServerOptions := options.NewServerRunOptions()
|
||||
kubeAPIServerOptions.InsecureServing.BindPort = 0
|
||||
kubeAPIServerOptions.SecureServing.Listener = listener
|
||||
kubeAPIServerOptions.SecureServing.ServerCert.CertDirectory = certDir
|
||||
kubeAPIServerOptions.Etcd.StorageConfig.ServerList = []string{framework.GetEtcdURL()}
|
||||
kubeAPIServerOptions.Etcd.DefaultStorageMediaType = runtime.ContentTypeJSON // force json we can easily interpret the result in etcd
|
||||
kubeAPIServerOptions.ServiceClusterIPRange = *defaultServiceClusterIPRange
|
||||
kubeAPIServerOptions.Authorization.Modes = []string{"RBAC"}
|
||||
kubeAPIServerOptions.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
||||
completedOptions, err := app.Complete(kubeAPIServerOptions)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := completedOptions.APIEnablement.RuntimeConfig.Set("api/all=true"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// get etcd client before starting API server
|
||||
rawClient, kvClient, err := integration.GetEtcdClients(completedOptions.Etcd.StorageConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// get a leased session
|
||||
session, err := concurrency.NewSession(rawClient)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// then build and use an etcd lock
|
||||
// this prevents more than one of these masters from running at the same time
|
||||
lock := concurrency.NewLocker(session, "kube_integration_etcd_raw")
|
||||
lock.Lock()
|
||||
|
||||
// make sure we start with a clean slate
|
||||
if _, err := kvClient.Delete(context.Background(), "/registry/", clientv3.WithPrefix()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
|
||||
kubeAPIServer, err := app.CreateServerChain(completedOptions, stopCh)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
kubeClientConfig := restclient.CopyConfig(kubeAPIServer.LoopbackClientConfig)
|
||||
|
||||
// we make lots of requests, don't be slow
|
||||
kubeClientConfig.QPS = 99999
|
||||
kubeClientConfig.Burst = 9999
|
||||
|
||||
kubeClient := clientset.NewForConfigOrDie(kubeClientConfig)
|
||||
|
||||
go func() {
|
||||
// Catch panics that occur in this go routine so we get a comprehensible failure
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
t.Errorf("Unexpected panic trying to start API master: %#v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := kubeAPIServer.PrepareRun().Run(stopCh); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
lastHealth := ""
|
||||
if err := wait.PollImmediate(time.Second, time.Minute, func() (done bool, err error) {
|
||||
// wait for the server to be healthy
|
||||
result := kubeClient.RESTClient().Get().AbsPath("/healthz").Do()
|
||||
content, _ := result.Raw()
|
||||
lastHealth = string(content)
|
||||
if errResult := result.Error(); errResult != nil {
|
||||
t.Log(errResult)
|
||||
return false, nil
|
||||
}
|
||||
var status int
|
||||
result.StatusCode(&status)
|
||||
return status == http.StatusOK, nil
|
||||
}); err != nil {
|
||||
t.Log(lastHealth)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// force cached discovery reset
|
||||
discoveryClient := cacheddiscovery.NewMemCacheClient(kubeClient.Discovery())
|
||||
restMapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient)
|
||||
restMapper.Reset()
|
||||
|
||||
serverResources, err := kubeClient.Discovery().ServerResources()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cleanup := func() {
|
||||
if err := os.RemoveAll(certDir); err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
close(stopCh)
|
||||
lock.Unlock()
|
||||
}
|
||||
|
||||
return &Master{
|
||||
Client: kubeClient,
|
||||
Dynamic: dynamic.NewForConfigOrDie(kubeClientConfig),
|
||||
Config: kubeClientConfig,
|
||||
KV: kvClient,
|
||||
Mapper: restMapper,
|
||||
Resources: GetResources(t, serverResources),
|
||||
Cleanup: cleanup,
|
||||
}
|
||||
}
|
||||
|
||||
// Master represents a running API server that is ready for use
|
||||
// The Cleanup func must be deferred to prevent resource leaks
|
||||
type Master struct {
|
||||
Client clientset.Interface
|
||||
Dynamic dynamic.Interface
|
||||
Config *restclient.Config
|
||||
KV clientv3.KV
|
||||
Mapper meta.RESTMapper
|
||||
Resources []Resource
|
||||
Cleanup func()
|
||||
}
|
||||
|
||||
// Resource contains REST mapping information for a specific resource and extra metadata such as delete collection support
|
||||
type Resource struct {
|
||||
Mapping *meta.RESTMapping
|
||||
HasDeleteCollection bool
|
||||
}
|
||||
|
||||
// GetResources fetches the Resources associated with serverResources that support get and create
|
||||
func GetResources(t *testing.T, serverResources []*metav1.APIResourceList) []Resource {
|
||||
var resources []Resource
|
||||
|
||||
for _, discoveryGroup := range serverResources {
|
||||
for _, discoveryResource := range discoveryGroup.APIResources {
|
||||
// this is a subresource, skip it
|
||||
if strings.Contains(discoveryResource.Name, "/") {
|
||||
continue
|
||||
}
|
||||
hasCreate := false
|
||||
hasGet := false
|
||||
hasDeleteCollection := false
|
||||
for _, verb := range discoveryResource.Verbs {
|
||||
if verb == "get" {
|
||||
hasGet = true
|
||||
}
|
||||
if verb == "create" {
|
||||
hasCreate = true
|
||||
}
|
||||
if verb == "deletecollection" {
|
||||
hasDeleteCollection = true
|
||||
}
|
||||
}
|
||||
if !(hasCreate && hasGet) {
|
||||
continue
|
||||
}
|
||||
|
||||
resourceGV, err := schema.ParseGroupVersion(discoveryGroup.GroupVersion)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
gvk := resourceGV.WithKind(discoveryResource.Kind)
|
||||
if len(discoveryResource.Group) > 0 || len(discoveryResource.Version) > 0 {
|
||||
gvk = schema.GroupVersionKind{
|
||||
Group: discoveryResource.Group,
|
||||
Version: discoveryResource.Version,
|
||||
Kind: discoveryResource.Kind,
|
||||
}
|
||||
}
|
||||
gvr := resourceGV.WithResource(discoveryResource.Name)
|
||||
|
||||
resources = append(resources, Resource{
|
||||
Mapping: &meta.RESTMapping{
|
||||
Resource: gvr,
|
||||
GroupVersionKind: gvk,
|
||||
Scope: scope(discoveryResource.Namespaced),
|
||||
},
|
||||
HasDeleteCollection: hasDeleteCollection,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return resources
|
||||
}
|
||||
|
||||
func scope(namespaced bool) meta.RESTScope {
|
||||
if namespaced {
|
||||
return meta.RESTScopeNamespace
|
||||
}
|
||||
return meta.RESTScopeRoot
|
||||
}
|
||||
|
||||
// JSONToUnstructured converts a JSON stub to unstructured.Unstructured and
|
||||
// returns a dynamic resource client that can be used to interact with it
|
||||
func JSONToUnstructured(stub, namespace string, mapping *meta.RESTMapping, dynamicClient dynamic.Interface) (dynamic.ResourceInterface, *unstructured.Unstructured, error) {
|
||||
typeMetaAdder := map[string]interface{}{}
|
||||
if err := json.Unmarshal([]byte(stub), &typeMetaAdder); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// we don't require GVK on the data we provide, so we fill it in here. We could, but that seems extraneous.
|
||||
typeMetaAdder["apiVersion"] = mapping.GroupVersionKind.GroupVersion().String()
|
||||
typeMetaAdder["kind"] = mapping.GroupVersionKind.Kind
|
||||
|
||||
if mapping.Scope == meta.RESTScopeRoot {
|
||||
namespace = ""
|
||||
}
|
||||
|
||||
return dynamicClient.Resource(mapping.Resource).Namespace(namespace), &unstructured.Unstructured{Object: typeMetaAdder}, nil
|
||||
}
|
@ -228,7 +228,7 @@ func (e *transformTest) createSecret(name, namespace string) (*corev1.Secret, er
|
||||
}
|
||||
|
||||
func (e *transformTest) readRawRecordFromETCD(path string) (*clientv3.GetResponse, error) {
|
||||
etcdClient, err := integration.GetEtcdKVClient(e.kubeAPIServer.ServerOpts.Etcd.StorageConfig)
|
||||
_, etcdClient, err := integration.GetEtcdClients(e.kubeAPIServer.ServerOpts.Etcd.StorageConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create etcd client: %v", err)
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ func WaitForPodToDisappear(podClient coreclient.PodInterface, podName string, in
|
||||
})
|
||||
}
|
||||
|
||||
func GetEtcdKVClient(config storagebackend.Config) (clientv3.KV, error) {
|
||||
func GetEtcdClients(config storagebackend.Config) (*clientv3.Client, clientv3.KV, error) {
|
||||
tlsInfo := transport.TLSInfo{
|
||||
CertFile: config.CertFile,
|
||||
KeyFile: config.KeyFile,
|
||||
@ -76,7 +76,7 @@ func GetEtcdKVClient(config storagebackend.Config) (clientv3.KV, error) {
|
||||
|
||||
tlsConfig, err := tlsInfo.ClientConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
cfg := clientv3.Config{
|
||||
@ -86,8 +86,8 @@ func GetEtcdKVClient(config storagebackend.Config) (clientv3.KV, error) {
|
||||
|
||||
c, err := clientv3.New(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return clientv3.NewKV(c), nil
|
||||
return c, clientv3.NewKV(c), nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user