Refactor dry run test to reuse ETCD storage data

This change updates the ETCD storage test so that its data is
exported.  Thus it can be used by other tests.  The dry run test was
updated to consume this data instead of having a duplicate copy.

The code to start a master that can be used for "one of every
resource" style tests was also factored out.  It is reused in the
dry run test as well.

This prevents these tests from drifting in the future and reduces
the long term maintenance burden.

Signed-off-by: Monis Khan <mkhan@redhat.com>
This commit is contained in:
Monis Khan
2018-10-18 15:47:51 -04:00
parent 8b36038b41
commit c16edb2738
8 changed files with 844 additions and 1190 deletions

View File

@@ -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
}