mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-11-03 23:40:03 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			766 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			766 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
Copyright 2018 The Kubernetes Authors.
 | 
						|
 | 
						|
Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
you may not use this file except in compliance with the License.
 | 
						|
You may obtain a copy of the License at
 | 
						|
 | 
						|
    http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 | 
						|
Unless required by applicable law or agreed to in writing, software
 | 
						|
distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
See the License for the specific language governing permissions and
 | 
						|
limitations under the License.
 | 
						|
*/
 | 
						|
 | 
						|
package 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
 | 
						|
)
 | 
						|
 | 
						|
// 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()
 | 
						|
 | 
						|
// namespace used for all tests, do not change this
 | 
						|
const testNamespace = "dryrunnamespace"
 | 
						|
 | 
						|
func DryRunCreateTest(t *testing.T, rsc dynamic.ResourceInterface, obj *unstructured.Unstructured, gvResource schema.GroupVersionResource) {
 | 
						|
	createdObj, err := rsc.Create(obj, metav1.CreateOptions{DryRun: []string{metav1.DryRunAll}})
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("failed to dry-run create stub for %s: %#v", gvResource, err)
 | 
						|
	}
 | 
						|
	if obj.GroupVersionKind() != createdObj.GroupVersionKind() {
 | 
						|
		t.Fatalf("created object doesn't have the same gvk as original object: got %v, expected %v",
 | 
						|
			createdObj.GroupVersionKind(),
 | 
						|
			obj.GroupVersionKind())
 | 
						|
	}
 | 
						|
 | 
						|
	if _, err := rsc.Get(obj.GetName(), metav1.GetOptions{}); !errors.IsNotFound(err) {
 | 
						|
		t.Fatalf("object shouldn't exist: %v", err)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func DryRunPatchTest(t *testing.T, rsc dynamic.ResourceInterface, name string) {
 | 
						|
	patch := []byte(`{"metadata":{"annotations":{"patch": "true"}}}`)
 | 
						|
	obj, err := rsc.Patch(name, types.MergePatchType, patch, metav1.UpdateOptions{DryRun: []string{metav1.DryRunAll}})
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("failed to dry-run patch object: %v", err)
 | 
						|
	}
 | 
						|
	if v := obj.GetAnnotations()["patch"]; v != "true" {
 | 
						|
		t.Fatalf("dry-run patched annotations should be returned, got: %v", obj.GetAnnotations())
 | 
						|
	}
 | 
						|
	obj, err = rsc.Get(obj.GetName(), metav1.GetOptions{})
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("failed to get object: %v", err)
 | 
						|
	}
 | 
						|
	if v := obj.GetAnnotations()["patch"]; v == "true" {
 | 
						|
		t.Fatalf("dry-run patched annotations should not be persisted, got: %v", obj.GetAnnotations())
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func getReplicasOrFail(t *testing.T, obj *unstructured.Unstructured) int64 {
 | 
						|
	t.Helper()
 | 
						|
	replicas, found, err := unstructured.NestedInt64(obj.UnstructuredContent(), "spec", "replicas")
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("failed to get int64 for replicas: %v", err)
 | 
						|
	}
 | 
						|
	if !found {
 | 
						|
		t.Fatal("object doesn't have spec.replicas")
 | 
						|
	}
 | 
						|
	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) {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("failed to get object: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	replicas := getReplicasOrFail(t, obj)
 | 
						|
	patch := []byte(`{"spec":{"replicas":10}}`)
 | 
						|
	patchedObj, err := rsc.Patch(name, types.MergePatchType, patch, metav1.UpdateOptions{DryRun: []string{metav1.DryRunAll}}, "scale")
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("failed to dry-run patch object: %v", err)
 | 
						|
	}
 | 
						|
	if newReplicas := getReplicasOrFail(t, patchedObj); newReplicas != 10 {
 | 
						|
		t.Fatalf("dry-run patch to replicas didn't return new value: %v", newReplicas)
 | 
						|
	}
 | 
						|
	persistedObj, err := rsc.Get(name, metav1.GetOptions{}, "scale")
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("failed to get scale sub-resource")
 | 
						|
	}
 | 
						|
	if newReplicas := getReplicasOrFail(t, persistedObj); newReplicas != replicas {
 | 
						|
		t.Fatalf("number of replicas changed, expected %v, got %v", replicas, newReplicas)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func DryRunScaleUpdateTest(t *testing.T, rsc dynamic.ResourceInterface, name string) {
 | 
						|
	obj, err := rsc.Get(name, metav1.GetOptions{}, "scale")
 | 
						|
	if errors.IsNotFound(err) {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("failed to get object: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	replicas := getReplicasOrFail(t, obj)
 | 
						|
	unstructured.SetNestedField(obj.Object, int64(10), "spec", "replicas")
 | 
						|
	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)
 | 
						|
	}
 | 
						|
	if newReplicas := getReplicasOrFail(t, updatedObj); newReplicas != 10 {
 | 
						|
		t.Fatalf("dry-run update to replicas didn't return new value: %v", newReplicas)
 | 
						|
	}
 | 
						|
	persistedObj, err := rsc.Get(name, metav1.GetOptions{}, "scale")
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("failed to get scale sub-resource")
 | 
						|
	}
 | 
						|
	if newReplicas := getReplicasOrFail(t, persistedObj); newReplicas != replicas {
 | 
						|
		t.Fatalf("number of replicas changed, expected %v, got %v", replicas, newReplicas)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func DryRunUpdateTest(t *testing.T, rsc dynamic.ResourceInterface, name string) {
 | 
						|
	var err error
 | 
						|
	var obj *unstructured.Unstructured
 | 
						|
	for i := 0; i < 3; i++ {
 | 
						|
		obj, err = rsc.Get(name, metav1.GetOptions{})
 | 
						|
		if err != nil {
 | 
						|
			t.Fatalf("failed to retrieve object: %v", err)
 | 
						|
		}
 | 
						|
		obj.SetAnnotations(map[string]string{"update": "true"})
 | 
						|
		obj, err = rsc.Update(obj, metav1.UpdateOptions{DryRun: []string{metav1.DryRunAll}})
 | 
						|
		if err == nil || !errors.IsConflict(err) {
 | 
						|
			break
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("failed to dry-run update resource: %v", err)
 | 
						|
	}
 | 
						|
	if v := obj.GetAnnotations()["update"]; v != "true" {
 | 
						|
		t.Fatalf("dry-run updated annotations should be returned, got: %v", obj.GetAnnotations())
 | 
						|
	}
 | 
						|
 | 
						|
	obj, err = rsc.Get(obj.GetName(), metav1.GetOptions{})
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("failed to get object: %v", err)
 | 
						|
	}
 | 
						|
	if v := obj.GetAnnotations()["update"]; v == "true" {
 | 
						|
		t.Fatalf("dry-run updated annotations should not be persisted, got: %v", obj.GetAnnotations())
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func DryRunDeleteCollectionTest(t *testing.T, rsc dynamic.ResourceInterface, name string) {
 | 
						|
	err := rsc.DeleteCollection(&metav1.DeleteOptions{DryRun: []string{metav1.DryRunAll}}, metav1.ListOptions{})
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("dry-run delete collection failed: %v", err)
 | 
						|
	}
 | 
						|
	obj, err := rsc.Get(name, metav1.GetOptions{})
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("failed to get object: %v", err)
 | 
						|
	}
 | 
						|
	ts := obj.GetDeletionTimestamp()
 | 
						|
	if ts != nil {
 | 
						|
		t.Fatalf("object has a deletion timestamp after dry-run delete collection")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func DryRunDeleteTest(t *testing.T, rsc dynamic.ResourceInterface, name string) {
 | 
						|
	err := rsc.Delete(name, &metav1.DeleteOptions{DryRun: []string{metav1.DryRunAll}})
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("dry-run delete failed: %v", err)
 | 
						|
	}
 | 
						|
	obj, err := rsc.Get(name, metav1.GetOptions{})
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("failed to get object: %v", err)
 | 
						|
	}
 | 
						|
	ts := obj.GetDeletionTimestamp()
 | 
						|
	if ts != nil {
 | 
						|
		t.Fatalf("object has a deletion timestamp after dry-run delete")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// 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 {
 | 
						|
		t.Fatal(err)
 | 
						|
	}
 | 
						|
 | 
						|
	discoveryClient := cacheddiscovery.NewMemCacheClient(kubeClient.Discovery())
 | 
						|
	restMapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient)
 | 
						|
	restMapper.Reset()
 | 
						|
 | 
						|
	serverResources, err := kubeClient.Discovery().ServerResources()
 | 
						|
	if err != nil {
 | 
						|
		t.Fatal(err)
 | 
						|
	}
 | 
						|
	resourcesToTest := getResourcesToTest(serverResources, false, t)
 | 
						|
 | 
						|
	for _, resourceToTest := range resourcesToTest {
 | 
						|
		t.Run(resourceToTest.gvr.String(), func(t *testing.T) {
 | 
						|
			gvk := resourceToTest.gvk
 | 
						|
			gvResource := resourceToTest.gvr
 | 
						|
			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")
 | 
						|
			}
 | 
						|
 | 
						|
			testData, hasTest := dryrunData[gvResource]
 | 
						|
 | 
						|
			if !hasTest {
 | 
						|
				t.Fatalf("no test data for %s.  Please add a test for your new type to dryrunData.", 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)
 | 
						|
			if err != nil {
 | 
						|
				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)
 | 
						|
 | 
						|
			if _, err := rsc.Create(obj, metav1.CreateOptions{}); err != nil {
 | 
						|
				t.Fatalf("failed to create stub for %s: %#v", gvResource, err)
 | 
						|
			}
 | 
						|
 | 
						|
			DryRunUpdateTest(t, rsc, name)
 | 
						|
			DryRunPatchTest(t, rsc, name)
 | 
						|
			DryRunScalePatchTest(t, rsc, name)
 | 
						|
			DryRunScaleUpdateTest(t, rsc, name)
 | 
						|
			if resourceToTest.hasDeleteCollection {
 | 
						|
				DryRunDeleteCollectionTest(t, rsc, name)
 | 
						|
			}
 | 
						|
			DryRunDeleteTest(t, rsc, name)
 | 
						|
 | 
						|
			if err = rsc.Delete(obj.GetName(), metav1.NewDeleteOptions(0)); err != nil {
 | 
						|
				t.Fatalf("deleting final object failed: %v", err)
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
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
 | 
						|
}
 |