From 1ae95b5c51b6791be94bb72cbdf06f3cbada9530 Mon Sep 17 00:00:00 2001 From: duanmengkk Date: Wed, 6 Sep 2023 16:57:26 +0800 Subject: [PATCH] init scheduler module and koslet module Signed-off-by: duanmengkk --- cmd/koslet/app/server.go | 7 + cmd/koslet/main.go | 15 + cmd/scheduler/main.go | 18 + go.mod | 34 +- go.sum | 23 + vendor/github.com/docker/distribution/LICENSE | 202 + .../docker/distribution/digestset/set.go | 247 + .../docker/distribution/reference/helpers.go | 42 + .../distribution/reference/normalize.go | 199 + .../distribution/reference/reference.go | 433 + .../docker/distribution/reference/regexp.go | 143 + .../google/go-cmp/cmp/cmpopts/equate.go | 156 + .../google/go-cmp/cmp/cmpopts/ignore.go | 206 + .../google/go-cmp/cmp/cmpopts/sort.go | 147 + .../go-cmp/cmp/cmpopts/struct_filter.go | 189 + .../google/go-cmp/cmp/cmpopts/xform.go | 36 + vendor/github.com/moby/sys/mountinfo/LICENSE | 202 + vendor/github.com/moby/sys/mountinfo/doc.go | 44 + .../moby/sys/mountinfo/mounted_linux.go | 101 + .../moby/sys/mountinfo/mounted_unix.go | 53 + .../moby/sys/mountinfo/mountinfo.go | 67 + .../moby/sys/mountinfo/mountinfo_bsd.go | 56 + .../moby/sys/mountinfo/mountinfo_filters.go | 63 + .../sys/mountinfo/mountinfo_freebsdlike.go | 14 + .../moby/sys/mountinfo/mountinfo_linux.go | 214 + .../moby/sys/mountinfo/mountinfo_openbsd.go | 11 + .../sys/mountinfo/mountinfo_unsupported.go | 19 + .../moby/sys/mountinfo/mountinfo_windows.go | 10 + .../opencontainers/go-digest/.mailmap | 4 + .../opencontainers/go-digest/.pullapprove.yml | 28 + .../opencontainers/go-digest/.travis.yml | 5 + .../opencontainers/go-digest/CONTRIBUTING.md | 72 + .../opencontainers/go-digest/LICENSE | 192 + .../opencontainers/go-digest/LICENSE.docs | 425 + .../opencontainers/go-digest/MAINTAINERS | 5 + .../opencontainers/go-digest/README.md | 96 + .../opencontainers/go-digest/algorithm.go | 193 + .../opencontainers/go-digest/digest.go | 157 + .../opencontainers/go-digest/digester.go | 40 + .../opencontainers/go-digest/doc.go | 62 + .../opencontainers/go-digest/verifiers.go | 46 + .../github.com/opencontainers/selinux/LICENSE | 201 + .../opencontainers/selinux/go-selinux/doc.go | 14 + .../selinux/go-selinux/label/label.go | 97 + .../selinux/go-selinux/label/label_linux.go | 196 + .../selinux/go-selinux/label/label_stub.go | 49 + .../selinux/go-selinux/rchcon.go | 22 + .../selinux/go-selinux/rchcon_go115.go | 21 + .../selinux/go-selinux/selinux.go | 304 + .../selinux/go-selinux/selinux_linux.go | 1262 +++ .../selinux/go-selinux/selinux_stub.go | 164 + .../selinux/go-selinux/xattrs_linux.go | 71 + .../selinux/pkg/pwalk/README.md | 48 + .../opencontainers/selinux/pkg/pwalk/pwalk.go | 115 + .../selinux/pkg/pwalkdir/README.md | 54 + .../selinux/pkg/pwalkdir/pwalkdir.go | 116 + .../kubernetes/fake/clientset_generated.go | 428 + .../k8s.io/client-go/kubernetes/fake/doc.go | 20 + .../client-go/kubernetes/fake/register.go | 154 + .../admissionregistration/v1/fake/doc.go | 20 + .../fake/fake_admissionregistration_client.go | 44 + .../fake/fake_mutatingwebhookconfiguration.go | 146 + .../fake_validatingwebhookconfiguration.go | 146 + .../v1alpha1/fake/doc.go | 20 + .../fake/fake_admissionregistration_client.go | 44 + .../fake/fake_validatingadmissionpolicy.go | 146 + .../fake_validatingadmissionpolicybinding.go | 146 + .../admissionregistration/v1beta1/fake/doc.go | 20 + .../fake/fake_admissionregistration_client.go | 44 + .../fake/fake_mutatingwebhookconfiguration.go | 146 + .../fake_validatingwebhookconfiguration.go | 146 + .../apiserverinternal/v1alpha1/fake/doc.go | 20 + .../fake/fake_apiserverinternal_client.go | 40 + .../v1alpha1/fake/fake_storageversion.go | 179 + .../kubernetes/typed/apps/v1/fake/doc.go | 20 + .../typed/apps/v1/fake/fake_apps_client.go | 56 + .../apps/v1/fake/fake_controllerrevision.go | 155 + .../typed/apps/v1/fake/fake_daemonset.go | 190 + .../typed/apps/v1/fake/fake_deployment.go | 233 + .../typed/apps/v1/fake/fake_replicaset.go | 233 + .../typed/apps/v1/fake/fake_statefulset.go | 233 + .../kubernetes/typed/apps/v1beta1/fake/doc.go | 20 + .../apps/v1beta1/fake/fake_apps_client.go | 48 + .../v1beta1/fake/fake_controllerrevision.go | 155 + .../apps/v1beta1/fake/fake_deployment.go | 190 + .../apps/v1beta1/fake/fake_statefulset.go | 190 + .../kubernetes/typed/apps/v1beta2/fake/doc.go | 20 + .../apps/v1beta2/fake/fake_apps_client.go | 56 + .../v1beta2/fake/fake_controllerrevision.go | 155 + .../typed/apps/v1beta2/fake/fake_daemonset.go | 190 + .../apps/v1beta2/fake/fake_deployment.go | 190 + .../apps/v1beta2/fake/fake_replicaset.go | 190 + .../apps/v1beta2/fake/fake_statefulset.go | 231 + .../typed/authentication/v1/fake/doc.go | 20 + .../v1/fake/fake_authentication_client.go | 40 + .../v1/fake/fake_tokenreview.go | 47 + .../typed/authentication/v1alpha1/fake/doc.go | 20 + .../fake/fake_authentication_client.go | 40 + .../v1alpha1/fake/fake_selfsubjectreview.go | 47 + .../typed/authentication/v1beta1/fake/doc.go | 20 + .../fake/fake_authentication_client.go | 40 + .../v1beta1/fake/fake_tokenreview.go | 47 + .../typed/authorization/v1/fake/doc.go | 20 + .../v1/fake/fake_authorization_client.go | 52 + .../v1/fake/fake_localsubjectaccessreview.go | 49 + .../v1/fake/fake_selfsubjectaccessreview.go | 47 + .../v1/fake/fake_selfsubjectrulesreview.go | 47 + .../v1/fake/fake_subjectaccessreview.go | 47 + .../typed/authorization/v1beta1/fake/doc.go | 20 + .../v1beta1/fake/fake_authorization_client.go | 52 + .../fake/fake_localsubjectaccessreview.go | 49 + .../fake/fake_selfsubjectaccessreview.go | 47 + .../fake/fake_selfsubjectrulesreview.go | 47 + .../v1beta1/fake/fake_subjectaccessreview.go | 47 + .../typed/autoscaling/v1/fake/doc.go | 20 + .../v1/fake/fake_autoscaling_client.go | 40 + .../v1/fake/fake_horizontalpodautoscaler.go | 190 + .../typed/autoscaling/v2/fake/doc.go | 20 + .../v2/fake/fake_autoscaling_client.go | 40 + .../v2/fake/fake_horizontalpodautoscaler.go | 190 + .../typed/autoscaling/v2beta1/fake/doc.go | 20 + .../v2beta1/fake/fake_autoscaling_client.go | 40 + .../fake/fake_horizontalpodautoscaler.go | 190 + .../typed/autoscaling/v2beta2/fake/doc.go | 20 + .../v2beta2/fake/fake_autoscaling_client.go | 40 + .../fake/fake_horizontalpodautoscaler.go | 190 + .../kubernetes/typed/batch/v1/fake/doc.go | 20 + .../typed/batch/v1/fake/fake_batch_client.go | 44 + .../typed/batch/v1/fake/fake_cronjob.go | 190 + .../typed/batch/v1/fake/fake_job.go | 190 + .../typed/batch/v1beta1/fake/doc.go | 20 + .../batch/v1beta1/fake/fake_batch_client.go | 40 + .../typed/batch/v1beta1/fake/fake_cronjob.go | 190 + .../typed/certificates/v1/fake/doc.go | 20 + .../v1/fake/fake_certificates_client.go | 40 + .../v1/fake/fake_certificatesigningrequest.go | 189 + .../typed/certificates/v1beta1/fake/doc.go | 20 + .../v1beta1/fake/fake_certificates_client.go | 40 + .../fake/fake_certificatesigningrequest.go | 179 + ...ake_certificatesigningrequest_expansion.go | 34 + .../typed/coordination/v1/fake/doc.go | 20 + .../v1/fake/fake_coordination_client.go | 40 + .../typed/coordination/v1/fake/fake_lease.go | 155 + .../typed/coordination/v1beta1/fake/doc.go | 20 + .../v1beta1/fake/fake_coordination_client.go | 40 + .../coordination/v1beta1/fake/fake_lease.go | 155 + .../kubernetes/typed/core/v1/fake/doc.go | 20 + .../core/v1/fake/fake_componentstatus.go | 146 + .../typed/core/v1/fake/fake_configmap.go | 155 + .../typed/core/v1/fake/fake_core_client.go | 100 + .../typed/core/v1/fake/fake_endpoints.go | 155 + .../typed/core/v1/fake/fake_event.go | 155 + .../core/v1/fake/fake_event_expansion.go | 101 + .../typed/core/v1/fake/fake_limitrange.go | 155 + .../typed/core/v1/fake/fake_namespace.go | 171 + .../core/v1/fake/fake_namespace_expansion.go | 40 + .../typed/core/v1/fake/fake_node.go | 179 + .../typed/core/v1/fake/fake_node_expansion.go | 38 + .../core/v1/fake/fake_persistentvolume.go | 179 + .../v1/fake/fake_persistentvolumeclaim.go | 190 + .../kubernetes/typed/core/v1/fake/fake_pod.go | 201 + .../typed/core/v1/fake/fake_pod_expansion.go | 112 + .../typed/core/v1/fake/fake_podtemplate.go | 155 + .../v1/fake/fake_replicationcontroller.go | 213 + .../typed/core/v1/fake/fake_resourcequota.go | 190 + .../typed/core/v1/fake/fake_secret.go | 155 + .../typed/core/v1/fake/fake_service.go | 182 + .../core/v1/fake/fake_service_expansion.go | 26 + .../typed/core/v1/fake/fake_serviceaccount.go | 167 + .../kubernetes/typed/discovery/v1/fake/doc.go | 20 + .../v1/fake/fake_discovery_client.go | 40 + .../discovery/v1/fake/fake_endpointslice.go | 155 + .../typed/discovery/v1beta1/fake/doc.go | 20 + .../v1beta1/fake/fake_discovery_client.go | 40 + .../v1beta1/fake/fake_endpointslice.go | 155 + .../kubernetes/typed/events/v1/fake/doc.go | 20 + .../typed/events/v1/fake/fake_event.go | 155 + .../events/v1/fake/fake_events_client.go | 40 + .../typed/events/v1beta1/fake/doc.go | 20 + .../typed/events/v1beta1/fake/fake_event.go | 155 + .../v1beta1/fake/fake_event_expansion.go | 66 + .../events/v1beta1/fake/fake_events_client.go | 40 + .../typed/extensions/v1beta1/fake/doc.go | 20 + .../extensions/v1beta1/fake/fake_daemonset.go | 190 + .../v1beta1/fake/fake_deployment.go | 231 + .../v1beta1/fake/fake_deployment_expansion.go | 36 + .../v1beta1/fake/fake_extensions_client.go | 60 + .../extensions/v1beta1/fake/fake_ingress.go | 190 + .../v1beta1/fake/fake_networkpolicy.go | 190 + .../v1beta1/fake/fake_podsecuritypolicy.go | 146 + .../v1beta1/fake/fake_replicaset.go | 231 + .../typed/flowcontrol/v1alpha1/fake/doc.go | 20 + .../v1alpha1/fake/fake_flowcontrol_client.go | 44 + .../v1alpha1/fake/fake_flowschema.go | 179 + .../fake/fake_prioritylevelconfiguration.go | 179 + .../typed/flowcontrol/v1beta1/fake/doc.go | 20 + .../v1beta1/fake/fake_flowcontrol_client.go | 44 + .../v1beta1/fake/fake_flowschema.go | 179 + .../fake/fake_prioritylevelconfiguration.go | 179 + .../typed/flowcontrol/v1beta2/fake/doc.go | 20 + .../v1beta2/fake/fake_flowcontrol_client.go | 44 + .../v1beta2/fake/fake_flowschema.go | 179 + .../fake/fake_prioritylevelconfiguration.go | 179 + .../typed/flowcontrol/v1beta3/fake/doc.go | 20 + .../v1beta3/fake/fake_flowcontrol_client.go | 44 + .../v1beta3/fake/fake_flowschema.go | 179 + .../fake/fake_prioritylevelconfiguration.go | 179 + .../typed/networking/v1/fake/doc.go | 20 + .../typed/networking/v1/fake/fake_ingress.go | 190 + .../networking/v1/fake/fake_ingressclass.go | 146 + .../v1/fake/fake_networking_client.go | 48 + .../networking/v1/fake/fake_networkpolicy.go | 190 + .../typed/networking/v1alpha1/fake/doc.go | 20 + .../v1alpha1/fake/fake_clustercidr.go | 146 + .../v1alpha1/fake/fake_networking_client.go | 40 + .../typed/networking/v1beta1/fake/doc.go | 20 + .../networking/v1beta1/fake/fake_ingress.go | 190 + .../v1beta1/fake/fake_ingressclass.go | 146 + .../v1beta1/fake/fake_networking_client.go | 44 + .../kubernetes/typed/node/v1/fake/doc.go | 20 + .../typed/node/v1/fake/fake_node_client.go | 40 + .../typed/node/v1/fake/fake_runtimeclass.go | 146 + .../typed/node/v1alpha1/fake/doc.go | 20 + .../node/v1alpha1/fake/fake_node_client.go | 40 + .../node/v1alpha1/fake/fake_runtimeclass.go | 146 + .../kubernetes/typed/node/v1beta1/fake/doc.go | 20 + .../node/v1beta1/fake/fake_node_client.go | 40 + .../node/v1beta1/fake/fake_runtimeclass.go | 146 + .../kubernetes/typed/policy/v1/fake/doc.go | 20 + .../typed/policy/v1/fake/fake_eviction.go | 25 + .../policy/v1/fake/fake_eviction_expansion.go | 37 + .../v1/fake/fake_poddisruptionbudget.go | 190 + .../policy/v1/fake/fake_policy_client.go | 44 + .../typed/policy/v1beta1/fake/doc.go | 20 + .../policy/v1beta1/fake/fake_eviction.go | 25 + .../v1beta1/fake/fake_eviction_expansion.go | 37 + .../v1beta1/fake/fake_poddisruptionbudget.go | 190 + .../v1beta1/fake/fake_podsecuritypolicy.go | 146 + .../policy/v1beta1/fake/fake_policy_client.go | 48 + .../kubernetes/typed/rbac/v1/fake/doc.go | 20 + .../typed/rbac/v1/fake/fake_clusterrole.go | 146 + .../rbac/v1/fake/fake_clusterrolebinding.go | 146 + .../typed/rbac/v1/fake/fake_rbac_client.go | 52 + .../typed/rbac/v1/fake/fake_role.go | 155 + .../typed/rbac/v1/fake/fake_rolebinding.go | 155 + .../typed/rbac/v1alpha1/fake/doc.go | 20 + .../rbac/v1alpha1/fake/fake_clusterrole.go | 146 + .../v1alpha1/fake/fake_clusterrolebinding.go | 146 + .../rbac/v1alpha1/fake/fake_rbac_client.go | 52 + .../typed/rbac/v1alpha1/fake/fake_role.go | 155 + .../rbac/v1alpha1/fake/fake_rolebinding.go | 155 + .../kubernetes/typed/rbac/v1beta1/fake/doc.go | 20 + .../rbac/v1beta1/fake/fake_clusterrole.go | 146 + .../v1beta1/fake/fake_clusterrolebinding.go | 146 + .../rbac/v1beta1/fake/fake_rbac_client.go | 52 + .../typed/rbac/v1beta1/fake/fake_role.go | 155 + .../rbac/v1beta1/fake/fake_rolebinding.go | 155 + .../typed/resource/v1alpha1/fake/doc.go | 20 + .../v1alpha1/fake/fake_podscheduling.go | 190 + .../v1alpha1/fake/fake_resource_client.go | 52 + .../v1alpha1/fake/fake_resourceclaim.go | 190 + .../fake/fake_resourceclaimtemplate.go | 155 + .../v1alpha1/fake/fake_resourceclass.go | 146 + .../typed/scheduling/v1/fake/doc.go | 20 + .../scheduling/v1/fake/fake_priorityclass.go | 146 + .../v1/fake/fake_scheduling_client.go | 40 + .../typed/scheduling/v1alpha1/fake/doc.go | 20 + .../v1alpha1/fake/fake_priorityclass.go | 146 + .../v1alpha1/fake/fake_scheduling_client.go | 40 + .../typed/scheduling/v1beta1/fake/doc.go | 20 + .../v1beta1/fake/fake_priorityclass.go | 146 + .../v1beta1/fake/fake_scheduling_client.go | 40 + .../kubernetes/typed/storage/v1/fake/doc.go | 20 + .../typed/storage/v1/fake/fake_csidriver.go | 146 + .../typed/storage/v1/fake/fake_csinode.go | 146 + .../v1/fake/fake_csistoragecapacity.go | 155 + .../storage/v1/fake/fake_storage_client.go | 56 + .../storage/v1/fake/fake_storageclass.go | 146 + .../storage/v1/fake/fake_volumeattachment.go | 179 + .../typed/storage/v1alpha1/fake/doc.go | 20 + .../v1alpha1/fake/fake_csistoragecapacity.go | 155 + .../v1alpha1/fake/fake_storage_client.go | 44 + .../v1alpha1/fake/fake_volumeattachment.go | 179 + .../typed/storage/v1beta1/fake/doc.go | 20 + .../storage/v1beta1/fake/fake_csidriver.go | 146 + .../storage/v1beta1/fake/fake_csinode.go | 146 + .../v1beta1/fake/fake_csistoragecapacity.go | 155 + .../v1beta1/fake/fake_storage_client.go | 56 + .../storage/v1beta1/fake/fake_storageclass.go | 146 + .../v1beta1/fake/fake_volumeattachment.go | 179 + vendor/k8s.io/client-go/rest/fake/fake.go | 118 + vendor/k8s.io/cloud-provider/CONTRIBUTING.md | 9 + vendor/k8s.io/cloud-provider/LICENSE | 201 + vendor/k8s.io/cloud-provider/OWNERS | 29 + vendor/k8s.io/cloud-provider/README.md | 33 + .../k8s.io/cloud-provider/SECURITY_CONTACTS | 20 + vendor/k8s.io/cloud-provider/cloud.go | 313 + .../k8s.io/cloud-provider/code-of-conduct.md | 3 + vendor/k8s.io/cloud-provider/doc.go | 18 + vendor/k8s.io/cloud-provider/plugins.go | 174 + vendor/k8s.io/cloud-provider/ports.go | 23 + .../k8s.io/cloud-provider/volume/constants.go | 26 + .../cloud-provider/volume/helpers/rounding.go | 165 + .../cloud-provider/volume/helpers/zones.go | 313 + .../cli/globalflag/globalflags.go | 50 + .../config/options/leaderelectionconfig.go | 53 + .../config/validation/validation.go | 61 + vendor/k8s.io/component-base/configz/OWNERS | 16 + .../k8s.io/component-base/configz/configz.go | 125 + .../component-base/version/verflag/verflag.go | 111 + vendor/k8s.io/component-helpers/LICENSE | 202 + .../node/topology/helpers.go | 58 + .../node/util/sysctl/sysctl.go | 100 + .../scheduling/corev1/doc.go | 23 + .../scheduling/corev1/helpers.go | 101 + .../corev1/nodeaffinity/nodeaffinity.go | 324 + .../storage/ephemeral/ephemeral.go | 57 + .../storage/volume/helpers.go | 70 + .../storage/volume/pv_helpers.go | 342 + .../csi-translation-lib/CONTRIBUTING.md | 7 + vendor/k8s.io/csi-translation-lib/LICENSE | 201 + vendor/k8s.io/csi-translation-lib/OWNERS | 11 + vendor/k8s.io/csi-translation-lib/README.md | 30 + .../csi-translation-lib/SECURITY_CONTACTS | 18 + .../csi-translation-lib/code-of-conduct.md | 3 + .../csi-translation-lib/plugins/aws_ebs.go | 304 + .../csi-translation-lib/plugins/azure_disk.go | 308 + .../csi-translation-lib/plugins/azure_file.go | 282 + .../csi-translation-lib/plugins/const.go | 21 + .../csi-translation-lib/plugins/gce_pd.go | 399 + .../plugins/in_tree_volume.go | 397 + .../plugins/openstack_cinder.go | 184 + .../csi-translation-lib/plugins/portworx.go | 145 + .../k8s.io/csi-translation-lib/plugins/rbd.go | 325 + .../plugins/vsphere_volume.go | 302 + .../k8s.io/csi-translation-lib/translate.go | 212 + .../dynamic-resource-allocation/LICENSE | 202 + .../resourceclaim/resourceclaim.go | 81 + vendor/k8s.io/kube-scheduler/LICENSE | 202 + vendor/k8s.io/kube-scheduler/config/v1/doc.go | 21 + .../kube-scheduler/config/v1/register.go | 50 + .../k8s.io/kube-scheduler/config/v1/types.go | 391 + .../config/v1/types_pluginargs.go | 225 + .../config/v1/zz_generated.deepcopy.go | 609 ++ .../kube-scheduler/config/v1beta2/doc.go | 21 + .../kube-scheduler/config/v1beta2/register.go | 50 + .../kube-scheduler/config/v1beta2/types.go | 369 + .../config/v1beta2/types_pluginargs.go | 225 + .../config/v1beta2/zz_generated.deepcopy.go | 614 ++ .../kube-scheduler/config/v1beta3/doc.go | 21 + .../kube-scheduler/config/v1beta3/register.go | 50 + .../kube-scheduler/config/v1beta3/types.go | 377 + .../config/v1beta3/types_pluginargs.go | 225 + .../config/v1beta3/zz_generated.deepcopy.go | 604 ++ .../k8s.io/kube-scheduler/extender/v1/doc.go | 20 + .../kube-scheduler/extender/v1/types.go | 132 + .../extender/v1/zz_generated.deepcopy.go | 347 + vendor/k8s.io/kubernetes/LICENSE | 202 + .../cmd/kube-scheduler/app/config/config.go | 79 + .../kube-scheduler/app/options/configfile.go | 121 + .../kube-scheduler/app/options/deprecated.go | 55 + .../cmd/kube-scheduler/app/options/options.go | 379 + .../cmd/kube-scheduler/app/server.go | 364 + .../kubernetes/pkg/api/legacyscheme/scheme.go | 37 + .../k8s.io/kubernetes/pkg/api/service/OWNERS | 5 + .../k8s.io/kubernetes/pkg/api/service/util.go | 86 + .../k8s.io/kubernetes/pkg/api/v1/pod/util.go | 386 + .../kubernetes/pkg/api/v1/resource/helpers.go | 303 + vendor/k8s.io/kubernetes/pkg/apis/apps/OWNERS | 8 + vendor/k8s.io/kubernetes/pkg/apis/apps/doc.go | 19 + .../kubernetes/pkg/apis/apps/register.go | 66 + .../k8s.io/kubernetes/pkg/apis/apps/types.go | 916 ++ .../pkg/apis/apps/zz_generated.deepcopy.go | 850 ++ .../kubernetes/pkg/apis/autoscaling/OWNERS | 12 + .../pkg/apis/autoscaling/annotations.go | 38 + .../kubernetes/pkg/apis/autoscaling/doc.go | 19 + .../pkg/apis/autoscaling/helpers.go | 58 + .../pkg/apis/autoscaling/register.go | 55 + .../kubernetes/pkg/apis/autoscaling/types.go | 554 ++ .../apis/autoscaling/zz_generated.deepcopy.go | 670 ++ vendor/k8s.io/kubernetes/pkg/apis/core/OWNERS | 4 + .../pkg/apis/core/annotation_key_constants.go | 129 + vendor/k8s.io/kubernetes/pkg/apis/core/doc.go | 24 + .../pkg/apis/core/helper/helpers.go | 515 + .../k8s.io/kubernetes/pkg/apis/core/json.go | 31 + .../pkg/apis/core/objectreference.go | 37 + .../kubernetes/pkg/apis/core/pods/helpers.go | 96 + .../kubernetes/pkg/apis/core/register.go | 102 + .../kubernetes/pkg/apis/core/resource.go | 58 + .../k8s.io/kubernetes/pkg/apis/core/taint.go | 42 + .../kubernetes/pkg/apis/core/toleration.go | 30 + .../k8s.io/kubernetes/pkg/apis/core/types.go | 5907 ++++++++++++ .../k8s.io/kubernetes/pkg/apis/core/v1/OWNERS | 24 + .../kubernetes/pkg/apis/core/v1/conversion.go | 544 ++ .../kubernetes/pkg/apis/core/v1/defaults.go | 454 + .../k8s.io/kubernetes/pkg/apis/core/v1/doc.go | 23 + .../pkg/apis/core/v1/helper/helpers.go | 431 + .../kubernetes/pkg/apis/core/v1/register.go | 46 + .../apis/core/v1/zz_generated.conversion.go | 8522 +++++++++++++++++ .../pkg/apis/core/v1/zz_generated.defaults.go | 1040 ++ .../pkg/apis/core/validation/OWNERS | 22 + .../pkg/apis/core/validation/doc.go | 19 + .../pkg/apis/core/validation/events.go | 193 + .../pkg/apis/core/validation/validation.go | 7174 ++++++++++++++ .../pkg/apis/core/zz_generated.deepcopy.go | 6153 ++++++++++++ .../pkg/capabilities/capabilities.go | 94 + .../k8s.io/kubernetes/pkg/capabilities/doc.go | 18 + .../kubernetes/pkg/cluster/ports/doc.go | 19 + .../kubernetes/pkg/cluster/ports/ports.go | 46 + vendor/k8s.io/kubernetes/pkg/features/OWNERS | 4 + .../kubernetes/pkg/features/kube_features.go | 1190 +++ vendor/k8s.io/kubernetes/pkg/fieldpath/doc.go | 19 + .../kubernetes/pkg/fieldpath/fieldpath.go | 110 + .../pkg/kubelet/server/metrics/metrics.go | 101 + .../kubernetes/pkg/proxy/util/endpoints.go | 64 + .../kubernetes/pkg/proxy/util/network.go | 39 + .../k8s.io/kubernetes/pkg/proxy/util/utils.go | 598 ++ vendor/k8s.io/kubernetes/pkg/scheduler/OWNERS | 8 + .../pkg/scheduler/apis/config/OWNERS | 11 + .../pkg/scheduler/apis/config/doc.go | 20 + .../scheduler/apis/config/latest/latest.go | 43 + .../pkg/scheduler/apis/config/register.go | 50 + .../scheduler/apis/config/scheme/scheme.go | 52 + .../pkg/scheduler/apis/config/types.go | 338 + .../scheduler/apis/config/types_pluginargs.go | 214 + .../scheduler/apis/config/v1/conversion.go | 107 + .../apis/config/v1/default_plugins.go | 162 + .../pkg/scheduler/apis/config/v1/defaults.go | 242 + .../pkg/scheduler/apis/config/v1/doc.go | 24 + .../pkg/scheduler/apis/config/v1/register.go | 42 + .../apis/config/v1/zz_generated.conversion.go | 944 ++ .../apis/config/v1/zz_generated.deepcopy.go | 22 + .../apis/config/v1/zz_generated.defaults.go | 73 + .../apis/config/v1beta2/conversion.go | 117 + .../apis/config/v1beta2/default_plugins.go | 186 + .../scheduler/apis/config/v1beta2/defaults.go | 241 + .../pkg/scheduler/apis/config/v1beta2/doc.go | 24 + .../scheduler/apis/config/v1beta2/register.go | 42 + .../config/v1beta2/zz_generated.conversion.go | 943 ++ .../config/v1beta2/zz_generated.deepcopy.go | 22 + .../config/v1beta2/zz_generated.defaults.go | 73 + .../apis/config/v1beta3/conversion.go | 118 + .../apis/config/v1beta3/default_plugins.go | 144 + .../scheduler/apis/config/v1beta3/defaults.go | 242 + .../pkg/scheduler/apis/config/v1beta3/doc.go | 24 + .../scheduler/apis/config/v1beta3/register.go | 42 + .../config/v1beta3/zz_generated.conversion.go | 933 ++ .../config/v1beta3/zz_generated.deepcopy.go | 22 + .../config/v1beta3/zz_generated.defaults.go | 73 + .../apis/config/validation/validation.go | 334 + .../validation/validation_pluginargs.go | 328 + .../apis/config/zz_generated.deepcopy.go | 562 ++ .../kubernetes/pkg/scheduler/eventhandlers.go | 543 ++ .../kubernetes/pkg/scheduler/extender.go | 444 + .../pkg/scheduler/framework/cycle_state.go | 110 + .../pkg/scheduler/framework/extender.go | 72 + .../pkg/scheduler/framework/interface.go | 768 ++ .../pkg/scheduler/framework/listers.go | 42 + .../framework/parallelize/error_channel.go | 59 + .../framework/parallelize/parallelism.go | 65 + .../pkg/scheduler/framework/plugins/README.md | 3 + .../plugins/defaultbinder/default_binder.go | 62 + .../defaultpreemption/default_preemption.go | 317 + .../framework/plugins/dynamicresources/OWNERS | 8 + .../dynamicresources/dynamicresources.go | 804 ++ .../framework/plugins/feature/feature.go | 30 + .../plugins/helper/normalize_score.go | 55 + .../framework/plugins/helper/shape_score.go | 52 + .../framework/plugins/helper/spread.go | 116 + .../framework/plugins/helper/taint.go | 28 + .../plugins/imagelocality/image_locality.go | 126 + .../plugins/interpodaffinity/filtering.go | 390 + .../plugins/interpodaffinity/plugin.go | 133 + .../plugins/interpodaffinity/scoring.go | 291 + .../framework/plugins/names/names.go | 44 + .../plugins/nodeaffinity/node_affinity.go | 309 + .../framework/plugins/nodename/node_name.go | 74 + .../framework/plugins/nodeports/node_ports.go | 146 + .../noderesources/balanced_allocation.go | 130 + .../framework/plugins/noderesources/fit.go | 342 + .../plugins/noderesources/least_allocated.go | 57 + .../plugins/noderesources/most_allocated.go | 61 + .../requested_to_capacity_ratio.go | 70 + .../noderesources/resource_allocation.go | 146 + .../plugins/noderesources/test_util.go | 56 + .../nodeunschedulable/node_unschedulable.go | 80 + .../framework/plugins/nodevolumelimits/csi.go | 392 + .../plugins/nodevolumelimits/non_csi.go | 538 ++ .../plugins/nodevolumelimits/utils.go | 96 + .../plugins/podtopologyspread/common.go | 159 + .../plugins/podtopologyspread/filtering.go | 394 + .../plugins/podtopologyspread/plugin.go | 148 + .../plugins/podtopologyspread/scoring.go | 309 + .../plugins/queuesort/priority_sort.go | 51 + .../scheduler/framework/plugins/registry.go | 87 + .../schedulinggates/scheduling_gates.go | 67 + .../plugins/selectorspread/selector_spread.go | 234 + .../tainttoleration/taint_toleration.go | 172 + .../framework/plugins/volumebinding/OWNERS | 10 + .../plugins/volumebinding/assume_cache.go | 456 + .../framework/plugins/volumebinding/binder.go | 1069 +++ .../plugins/volumebinding/fake_binder.go | 72 + .../plugins/volumebinding/metrics/metrics.go | 55 + .../framework/plugins/volumebinding/scorer.go | 54 + .../plugins/volumebinding/test_utils.go | 206 + .../plugins/volumebinding/volume_binding.go | 398 + .../volumerestrictions/volume_restrictions.go | 215 + .../plugins/volumezone/volume_zone.go | 206 + .../framework/preemption/preemption.go | 635 ++ .../scheduler/framework/runtime/framework.go | 1374 +++ .../framework/runtime/metrics_recorder.go | 101 + .../scheduler/framework/runtime/registry.go | 100 + .../framework/runtime/waiting_pods_map.go | 165 + .../pkg/scheduler/framework/types.go | 929 ++ .../pkg/scheduler/internal/cache/cache.go | 770 ++ .../internal/cache/debugger/comparer.go | 135 + .../internal/cache/debugger/debugger.go | 72 + .../internal/cache/debugger/dumper.go | 88 + .../internal/cache/debugger/signal.go | 26 + .../internal/cache/debugger/signal_windows.go | 23 + .../pkg/scheduler/internal/cache/interface.go | 122 + .../pkg/scheduler/internal/cache/node_tree.go | 143 + .../pkg/scheduler/internal/cache/snapshot.go | 198 + .../pkg/scheduler/internal/heap/heap.go | 246 + .../pkg/scheduler/internal/queue/events.go | 87 + .../internal/queue/scheduling_queue.go | 1118 +++ .../pkg/scheduler/internal/queue/testing.go | 55 + .../pkg/scheduler/metrics/metric_recorder.go | 79 + .../pkg/scheduler/metrics/metrics.go | 264 + .../pkg/scheduler/metrics/profile_metrics.go | 49 + .../scheduler/metrics/resources/resources.go | 201 + .../pkg/scheduler/profile/profile.go | 116 + .../kubernetes/pkg/scheduler/schedule_one.go | 942 ++ .../kubernetes/pkg/scheduler/scheduler.go | 456 + .../pkg/scheduler/util/pod_resources.go | 78 + .../kubernetes/pkg/scheduler/util/utils.go | 161 + .../pkg/securitycontext/accessors.go | 474 + .../kubernetes/pkg/securitycontext/doc.go | 18 + .../kubernetes/pkg/securitycontext/fake.go | 46 + .../kubernetes/pkg/securitycontext/util.go | 260 + .../kubernetes/pkg/util/parsers/parsers.go | 54 + vendor/k8s.io/kubernetes/pkg/volume/OWNERS | 8 + vendor/k8s.io/kubernetes/pkg/volume/doc.go | 19 + .../kubernetes/pkg/volume/metrics_block.go | 92 + .../kubernetes/pkg/volume/metrics_cached.go | 74 + .../kubernetes/pkg/volume/metrics_du.go | 85 + .../kubernetes/pkg/volume/metrics_errors.go | 94 + .../kubernetes/pkg/volume/metrics_nil.go | 35 + .../kubernetes/pkg/volume/metrics_statfs.go | 75 + .../pkg/volume/noop_expandable_plugin.go | 81 + .../k8s.io/kubernetes/pkg/volume/plugins.go | 1104 +++ .../pkg/volume/util/atomic_writer.go | 468 + .../pkg/volume/util/attach_limit.go | 70 + .../kubernetes/pkg/volume/util/device_util.go | 34 + .../pkg/volume/util/device_util_linux.go | 301 + .../volume/util/device_util_unsupported.go | 43 + .../k8s.io/kubernetes/pkg/volume/util/doc.go | 18 + .../kubernetes/pkg/volume/util/finalizer.go | 25 + .../kubernetes/pkg/volume/util/fs/fs.go | 148 + .../pkg/volume/util/fs/fs_unsupported.go | 40 + .../pkg/volume/util/fs/fs_windows.go | 117 + .../util/fsquota/common/quota_linux_common.go | 101 + .../fsquota/common/quota_linux_common_impl.go | 287 + .../pkg/volume/util/fsquota/project.go | 358 + .../pkg/volume/util/fsquota/quota.go | 50 + .../pkg/volume/util/fsquota/quota_linux.go | 452 + .../volume/util/fsquota/quota_unsupported.go | 59 + .../pkg/volume/util/hostutil/fake_hostutil.go | 124 + .../pkg/volume/util/hostutil/hostutil.go | 112 + .../volume/util/hostutil/hostutil_linux.go | 333 + .../util/hostutil/hostutil_unsupported.go | 109 + .../volume/util/hostutil/hostutil_windows.go | 131 + .../kubernetes/pkg/volume/util/io_util.go | 51 + .../kubernetes/pkg/volume/util/metrics.go | 161 + .../pkg/volume/util/nested_volumes.go | 114 + .../util/recyclerclient/recycler_client.go | 266 + .../kubernetes/pkg/volume/util/resize_util.go | 389 + .../kubernetes/pkg/volume/util/selinux.go | 198 + .../pkg/volume/util/storageclass.go | 85 + .../kubernetes/pkg/volume/util/subpath/OWNERS | 12 + .../pkg/volume/util/subpath/subpath.go | 92 + .../pkg/volume/util/subpath/subpath_linux.go | 609 ++ .../util/subpath/subpath_unsupported.go | 55 + .../volume/util/subpath/subpath_windows.go | 379 + .../kubernetes/pkg/volume/util/types/types.go | 168 + .../k8s.io/kubernetes/pkg/volume/util/util.go | 775 ++ .../volumepathhandler/volume_path_handler.go | 296 + .../volume_path_handler_linux.go | 229 + .../volume_path_handler_unsupported.go | 49 + vendor/k8s.io/kubernetes/pkg/volume/volume.go | 310 + .../kubernetes/pkg/volume/volume_linux.go | 212 + .../pkg/volume/volume_unsupported.go | 29 + vendor/k8s.io/mount-utils/LICENSE | 201 + vendor/k8s.io/mount-utils/OWNERS | 15 + vendor/k8s.io/mount-utils/README.md | 31 + vendor/k8s.io/mount-utils/SECURITY_CONTACTS | 18 + vendor/k8s.io/mount-utils/code-of-conduct.md | 3 + vendor/k8s.io/mount-utils/doc.go | 18 + vendor/k8s.io/mount-utils/fake_mounter.go | 242 + vendor/k8s.io/mount-utils/mount.go | 370 + .../k8s.io/mount-utils/mount_helper_common.go | 157 + .../k8s.io/mount-utils/mount_helper_unix.go | 201 + .../mount-utils/mount_helper_windows.go | 111 + vendor/k8s.io/mount-utils/mount_linux.go | 805 ++ .../k8s.io/mount-utils/mount_unsupported.go | 105 + vendor/k8s.io/mount-utils/mount_windows.go | 355 + vendor/k8s.io/mount-utils/resizefs_linux.go | 266 + .../mount-utils/resizefs_unsupported.go | 46 + vendor/k8s.io/utils/io/README.md | 4 + vendor/k8s.io/utils/io/read.go | 98 + vendor/k8s.io/utils/keymutex/hashed.go | 58 + vendor/k8s.io/utils/keymutex/keymutex.go | 27 + vendor/k8s.io/utils/nsenter/OWNERS | 10 + vendor/k8s.io/utils/nsenter/README.md | 4 + vendor/k8s.io/utils/nsenter/nsenter.go | 259 + .../utils/nsenter/nsenter_unsupported.go | 80 + vendor/k8s.io/utils/strings/escape.go | 36 + vendor/k8s.io/utils/strings/line_delimiter.go | 64 + vendor/k8s.io/utils/strings/strings.go | 46 + vendor/modules.txt | 231 +- 620 files changed, 121874 insertions(+), 13 deletions(-) create mode 100644 cmd/koslet/app/server.go create mode 100644 cmd/koslet/main.go create mode 100644 cmd/scheduler/main.go create mode 100644 vendor/github.com/docker/distribution/LICENSE create mode 100644 vendor/github.com/docker/distribution/digestset/set.go create mode 100644 vendor/github.com/docker/distribution/reference/helpers.go create mode 100644 vendor/github.com/docker/distribution/reference/normalize.go create mode 100644 vendor/github.com/docker/distribution/reference/reference.go create mode 100644 vendor/github.com/docker/distribution/reference/regexp.go create mode 100644 vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go create mode 100644 vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go create mode 100644 vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go create mode 100644 vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go create mode 100644 vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go create mode 100644 vendor/github.com/moby/sys/mountinfo/LICENSE create mode 100644 vendor/github.com/moby/sys/mountinfo/doc.go create mode 100644 vendor/github.com/moby/sys/mountinfo/mounted_linux.go create mode 100644 vendor/github.com/moby/sys/mountinfo/mounted_unix.go create mode 100644 vendor/github.com/moby/sys/mountinfo/mountinfo.go create mode 100644 vendor/github.com/moby/sys/mountinfo/mountinfo_bsd.go create mode 100644 vendor/github.com/moby/sys/mountinfo/mountinfo_filters.go create mode 100644 vendor/github.com/moby/sys/mountinfo/mountinfo_freebsdlike.go create mode 100644 vendor/github.com/moby/sys/mountinfo/mountinfo_linux.go create mode 100644 vendor/github.com/moby/sys/mountinfo/mountinfo_openbsd.go create mode 100644 vendor/github.com/moby/sys/mountinfo/mountinfo_unsupported.go create mode 100644 vendor/github.com/moby/sys/mountinfo/mountinfo_windows.go create mode 100644 vendor/github.com/opencontainers/go-digest/.mailmap create mode 100644 vendor/github.com/opencontainers/go-digest/.pullapprove.yml create mode 100644 vendor/github.com/opencontainers/go-digest/.travis.yml create mode 100644 vendor/github.com/opencontainers/go-digest/CONTRIBUTING.md create mode 100644 vendor/github.com/opencontainers/go-digest/LICENSE create mode 100644 vendor/github.com/opencontainers/go-digest/LICENSE.docs create mode 100644 vendor/github.com/opencontainers/go-digest/MAINTAINERS create mode 100644 vendor/github.com/opencontainers/go-digest/README.md create mode 100644 vendor/github.com/opencontainers/go-digest/algorithm.go create mode 100644 vendor/github.com/opencontainers/go-digest/digest.go create mode 100644 vendor/github.com/opencontainers/go-digest/digester.go create mode 100644 vendor/github.com/opencontainers/go-digest/doc.go create mode 100644 vendor/github.com/opencontainers/go-digest/verifiers.go create mode 100644 vendor/github.com/opencontainers/selinux/LICENSE create mode 100644 vendor/github.com/opencontainers/selinux/go-selinux/doc.go create mode 100644 vendor/github.com/opencontainers/selinux/go-selinux/label/label.go create mode 100644 vendor/github.com/opencontainers/selinux/go-selinux/label/label_linux.go create mode 100644 vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go create mode 100644 vendor/github.com/opencontainers/selinux/go-selinux/rchcon.go create mode 100644 vendor/github.com/opencontainers/selinux/go-selinux/rchcon_go115.go create mode 100644 vendor/github.com/opencontainers/selinux/go-selinux/selinux.go create mode 100644 vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go create mode 100644 vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go create mode 100644 vendor/github.com/opencontainers/selinux/go-selinux/xattrs_linux.go create mode 100644 vendor/github.com/opencontainers/selinux/pkg/pwalk/README.md create mode 100644 vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go create mode 100644 vendor/github.com/opencontainers/selinux/pkg/pwalkdir/README.md create mode 100644 vendor/github.com/opencontainers/selinux/pkg/pwalkdir/pwalkdir.go create mode 100644 vendor/k8s.io/client-go/kubernetes/fake/clientset_generated.go create mode 100644 vendor/k8s.io/client-go/kubernetes/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/fake/register.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1/fake/fake_admissionregistration_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1/fake/fake_mutatingwebhookconfiguration.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1/fake/fake_validatingwebhookconfiguration.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake/fake_admissionregistration_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake/fake_validatingadmissionpolicy.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake/fake_validatingadmissionpolicybinding.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/fake/fake_admissionregistration_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/fake/fake_mutatingwebhookconfiguration.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/fake/fake_validatingwebhookconfiguration.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apiserverinternal/v1alpha1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apiserverinternal/v1alpha1/fake/fake_apiserverinternal_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apiserverinternal/v1alpha1/fake/fake_storageversion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_apps_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_controllerrevision.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_daemonset.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_deployment.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_replicaset.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_statefulset.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake/fake_apps_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake/fake_controllerrevision.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake/fake_deployment.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake/fake_statefulset.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_apps_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_controllerrevision.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_daemonset.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_deployment.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_replicaset.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_statefulset.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authentication/v1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authentication/v1/fake/fake_authentication_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authentication/v1/fake/fake_tokenreview.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authentication/v1alpha1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authentication/v1alpha1/fake/fake_authentication_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authentication/v1alpha1/fake/fake_selfsubjectreview.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authentication/v1beta1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authentication/v1beta1/fake/fake_authentication_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authentication/v1beta1/fake/fake_tokenreview.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/fake_authorization_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/fake_localsubjectaccessreview.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/fake_selfsubjectaccessreview.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/fake_selfsubjectrulesreview.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/fake_subjectaccessreview.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/fake_authorization_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/fake_localsubjectaccessreview.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/fake_selfsubjectaccessreview.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/fake_selfsubjectrulesreview.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/fake_subjectaccessreview.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v1/fake/fake_autoscaling_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v1/fake/fake_horizontalpodautoscaler.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2/fake/fake_autoscaling_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2/fake/fake_horizontalpodautoscaler.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1/fake/fake_autoscaling_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1/fake/fake_horizontalpodautoscaler.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta2/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta2/fake/fake_autoscaling_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta2/fake/fake_horizontalpodautoscaler.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/batch/v1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/batch/v1/fake/fake_batch_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/batch/v1/fake/fake_cronjob.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/batch/v1/fake/fake_job.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/batch/v1beta1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/batch/v1beta1/fake/fake_batch_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/batch/v1beta1/fake/fake_cronjob.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/certificates/v1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/certificates/v1/fake/fake_certificates_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/certificates/v1/fake/fake_certificatesigningrequest.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake/fake_certificates_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake/fake_certificatesigningrequest.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake/fake_certificatesigningrequest_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/coordination/v1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/coordination/v1/fake/fake_coordination_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/coordination/v1/fake/fake_lease.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/coordination/v1beta1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/coordination/v1beta1/fake/fake_coordination_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/coordination/v1beta1/fake/fake_lease.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_componentstatus.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_configmap.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_core_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_endpoints.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_event.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_event_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_limitrange.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_namespace.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_namespace_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_node.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_node_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_persistentvolume.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_persistentvolumeclaim.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_pod.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_pod_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_podtemplate.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_replicationcontroller.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_resourcequota.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_secret.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_service.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_service_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_serviceaccount.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/discovery/v1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/discovery/v1/fake/fake_discovery_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/discovery/v1/fake/fake_endpointslice.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/discovery/v1beta1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/discovery/v1beta1/fake/fake_discovery_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/discovery/v1beta1/fake/fake_endpointslice.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/events/v1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/events/v1/fake/fake_event.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/events/v1/fake/fake_events_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/events/v1beta1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/events/v1beta1/fake/fake_event.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/events/v1beta1/fake/fake_event_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/events/v1beta1/fake/fake_events_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_daemonset.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_deployment.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_deployment_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_extensions_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_ingress.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_networkpolicy.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_podsecuritypolicy.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_replicaset.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1/fake/fake_flowcontrol_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1/fake/fake_flowschema.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1/fake/fake_prioritylevelconfiguration.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1/fake/fake_flowcontrol_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1/fake/fake_flowschema.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1/fake/fake_prioritylevelconfiguration.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2/fake/fake_flowcontrol_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2/fake/fake_flowschema.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2/fake/fake_prioritylevelconfiguration.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3/fake/fake_flowcontrol_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3/fake/fake_flowschema.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3/fake/fake_prioritylevelconfiguration.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1/fake/fake_ingress.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1/fake/fake_ingressclass.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1/fake/fake_networking_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1/fake/fake_networkpolicy.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1alpha1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1alpha1/fake/fake_clustercidr.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1alpha1/fake/fake_networking_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/fake/fake_ingress.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/fake/fake_ingressclass.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/fake/fake_networking_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/node/v1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/node/v1/fake/fake_node_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/node/v1/fake/fake_runtimeclass.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/node/v1alpha1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/node/v1alpha1/fake/fake_node_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/node/v1alpha1/fake/fake_runtimeclass.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/node/v1beta1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/node/v1beta1/fake/fake_node_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/node/v1beta1/fake/fake_runtimeclass.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/policy/v1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_eviction.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_eviction_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_poddisruptionbudget.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_policy_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/fake_eviction.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/fake_eviction_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/fake_poddisruptionbudget.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/fake_podsecuritypolicy.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/fake_policy_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/fake_clusterrole.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/fake_clusterrolebinding.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/fake_rbac_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/fake_role.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/fake_rolebinding.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/fake_clusterrole.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/fake_clusterrolebinding.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/fake_rbac_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/fake_role.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/fake_rolebinding.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/fake_clusterrole.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/fake_clusterrolebinding.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/fake_rbac_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/fake_role.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/fake_rolebinding.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/fake_podscheduling.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/fake_resource_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/fake_resourceclaim.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/fake_resourceclaimtemplate.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/fake_resourceclass.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1/fake/fake_priorityclass.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1/fake/fake_scheduling_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1/fake/fake_priorityclass.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1/fake/fake_scheduling_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1beta1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1beta1/fake/fake_priorityclass.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1beta1/fake/fake_scheduling_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_csidriver.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_csinode.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_csistoragecapacity.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_storage_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_storageclass.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_volumeattachment.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1alpha1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1alpha1/fake/fake_csistoragecapacity.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1alpha1/fake/fake_storage_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1alpha1/fake/fake_volumeattachment.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_csidriver.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_csinode.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_csistoragecapacity.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_storage_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_storageclass.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_volumeattachment.go create mode 100644 vendor/k8s.io/client-go/rest/fake/fake.go create mode 100644 vendor/k8s.io/cloud-provider/CONTRIBUTING.md create mode 100644 vendor/k8s.io/cloud-provider/LICENSE create mode 100644 vendor/k8s.io/cloud-provider/OWNERS create mode 100644 vendor/k8s.io/cloud-provider/README.md create mode 100644 vendor/k8s.io/cloud-provider/SECURITY_CONTACTS create mode 100644 vendor/k8s.io/cloud-provider/cloud.go create mode 100644 vendor/k8s.io/cloud-provider/code-of-conduct.md create mode 100644 vendor/k8s.io/cloud-provider/doc.go create mode 100644 vendor/k8s.io/cloud-provider/plugins.go create mode 100644 vendor/k8s.io/cloud-provider/ports.go create mode 100644 vendor/k8s.io/cloud-provider/volume/constants.go create mode 100644 vendor/k8s.io/cloud-provider/volume/helpers/rounding.go create mode 100644 vendor/k8s.io/cloud-provider/volume/helpers/zones.go create mode 100644 vendor/k8s.io/component-base/cli/globalflag/globalflags.go create mode 100644 vendor/k8s.io/component-base/config/options/leaderelectionconfig.go create mode 100644 vendor/k8s.io/component-base/config/validation/validation.go create mode 100644 vendor/k8s.io/component-base/configz/OWNERS create mode 100644 vendor/k8s.io/component-base/configz/configz.go create mode 100644 vendor/k8s.io/component-base/version/verflag/verflag.go create mode 100644 vendor/k8s.io/component-helpers/LICENSE create mode 100644 vendor/k8s.io/component-helpers/node/topology/helpers.go create mode 100644 vendor/k8s.io/component-helpers/node/util/sysctl/sysctl.go create mode 100644 vendor/k8s.io/component-helpers/scheduling/corev1/doc.go create mode 100644 vendor/k8s.io/component-helpers/scheduling/corev1/helpers.go create mode 100644 vendor/k8s.io/component-helpers/scheduling/corev1/nodeaffinity/nodeaffinity.go create mode 100644 vendor/k8s.io/component-helpers/storage/ephemeral/ephemeral.go create mode 100644 vendor/k8s.io/component-helpers/storage/volume/helpers.go create mode 100644 vendor/k8s.io/component-helpers/storage/volume/pv_helpers.go create mode 100644 vendor/k8s.io/csi-translation-lib/CONTRIBUTING.md create mode 100644 vendor/k8s.io/csi-translation-lib/LICENSE create mode 100644 vendor/k8s.io/csi-translation-lib/OWNERS create mode 100644 vendor/k8s.io/csi-translation-lib/README.md create mode 100644 vendor/k8s.io/csi-translation-lib/SECURITY_CONTACTS create mode 100644 vendor/k8s.io/csi-translation-lib/code-of-conduct.md create mode 100644 vendor/k8s.io/csi-translation-lib/plugins/aws_ebs.go create mode 100644 vendor/k8s.io/csi-translation-lib/plugins/azure_disk.go create mode 100644 vendor/k8s.io/csi-translation-lib/plugins/azure_file.go create mode 100644 vendor/k8s.io/csi-translation-lib/plugins/const.go create mode 100644 vendor/k8s.io/csi-translation-lib/plugins/gce_pd.go create mode 100644 vendor/k8s.io/csi-translation-lib/plugins/in_tree_volume.go create mode 100644 vendor/k8s.io/csi-translation-lib/plugins/openstack_cinder.go create mode 100644 vendor/k8s.io/csi-translation-lib/plugins/portworx.go create mode 100644 vendor/k8s.io/csi-translation-lib/plugins/rbd.go create mode 100644 vendor/k8s.io/csi-translation-lib/plugins/vsphere_volume.go create mode 100644 vendor/k8s.io/csi-translation-lib/translate.go create mode 100644 vendor/k8s.io/dynamic-resource-allocation/LICENSE create mode 100644 vendor/k8s.io/dynamic-resource-allocation/resourceclaim/resourceclaim.go create mode 100644 vendor/k8s.io/kube-scheduler/LICENSE create mode 100644 vendor/k8s.io/kube-scheduler/config/v1/doc.go create mode 100644 vendor/k8s.io/kube-scheduler/config/v1/register.go create mode 100644 vendor/k8s.io/kube-scheduler/config/v1/types.go create mode 100644 vendor/k8s.io/kube-scheduler/config/v1/types_pluginargs.go create mode 100644 vendor/k8s.io/kube-scheduler/config/v1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/kube-scheduler/config/v1beta2/doc.go create mode 100644 vendor/k8s.io/kube-scheduler/config/v1beta2/register.go create mode 100644 vendor/k8s.io/kube-scheduler/config/v1beta2/types.go create mode 100644 vendor/k8s.io/kube-scheduler/config/v1beta2/types_pluginargs.go create mode 100644 vendor/k8s.io/kube-scheduler/config/v1beta2/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/kube-scheduler/config/v1beta3/doc.go create mode 100644 vendor/k8s.io/kube-scheduler/config/v1beta3/register.go create mode 100644 vendor/k8s.io/kube-scheduler/config/v1beta3/types.go create mode 100644 vendor/k8s.io/kube-scheduler/config/v1beta3/types_pluginargs.go create mode 100644 vendor/k8s.io/kube-scheduler/config/v1beta3/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/kube-scheduler/extender/v1/doc.go create mode 100644 vendor/k8s.io/kube-scheduler/extender/v1/types.go create mode 100644 vendor/k8s.io/kube-scheduler/extender/v1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/kubernetes/LICENSE create mode 100644 vendor/k8s.io/kubernetes/cmd/kube-scheduler/app/config/config.go create mode 100644 vendor/k8s.io/kubernetes/cmd/kube-scheduler/app/options/configfile.go create mode 100644 vendor/k8s.io/kubernetes/cmd/kube-scheduler/app/options/deprecated.go create mode 100644 vendor/k8s.io/kubernetes/cmd/kube-scheduler/app/options/options.go create mode 100644 vendor/k8s.io/kubernetes/cmd/kube-scheduler/app/server.go create mode 100644 vendor/k8s.io/kubernetes/pkg/api/legacyscheme/scheme.go create mode 100644 vendor/k8s.io/kubernetes/pkg/api/service/OWNERS create mode 100644 vendor/k8s.io/kubernetes/pkg/api/service/util.go create mode 100644 vendor/k8s.io/kubernetes/pkg/api/v1/pod/util.go create mode 100644 vendor/k8s.io/kubernetes/pkg/api/v1/resource/helpers.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/apps/OWNERS create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/apps/doc.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/apps/register.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/apps/types.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/apps/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/autoscaling/OWNERS create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/autoscaling/annotations.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/autoscaling/doc.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/autoscaling/helpers.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/autoscaling/register.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/autoscaling/types.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/autoscaling/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/OWNERS create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/annotation_key_constants.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/doc.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/helper/helpers.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/json.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/objectreference.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/pods/helpers.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/register.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/resource.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/taint.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/toleration.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/types.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/v1/OWNERS create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/v1/conversion.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/v1/defaults.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/v1/doc.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/v1/helper/helpers.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/v1/register.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/v1/zz_generated.conversion.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/v1/zz_generated.defaults.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/validation/OWNERS create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/validation/doc.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/validation/events.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/validation/validation.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/core/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/kubernetes/pkg/capabilities/capabilities.go create mode 100644 vendor/k8s.io/kubernetes/pkg/capabilities/doc.go create mode 100644 vendor/k8s.io/kubernetes/pkg/cluster/ports/doc.go create mode 100644 vendor/k8s.io/kubernetes/pkg/cluster/ports/ports.go create mode 100644 vendor/k8s.io/kubernetes/pkg/features/OWNERS create mode 100644 vendor/k8s.io/kubernetes/pkg/features/kube_features.go create mode 100644 vendor/k8s.io/kubernetes/pkg/fieldpath/doc.go create mode 100644 vendor/k8s.io/kubernetes/pkg/fieldpath/fieldpath.go create mode 100644 vendor/k8s.io/kubernetes/pkg/kubelet/server/metrics/metrics.go create mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/util/endpoints.go create mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/util/network.go create mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/util/utils.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/OWNERS create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/OWNERS create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/doc.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/latest/latest.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/register.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/scheme/scheme.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/types.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/types_pluginargs.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/conversion.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/default_plugins.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/defaults.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/doc.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/register.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/zz_generated.conversion.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/zz_generated.defaults.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/conversion.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/default_plugins.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/defaults.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/doc.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/register.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/zz_generated.conversion.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/zz_generated.defaults.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/conversion.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/default_plugins.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/defaults.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/doc.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/register.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/zz_generated.conversion.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/zz_generated.defaults.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/validation/validation.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/validation/validation_pluginargs.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/eventhandlers.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/extender.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/cycle_state.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/extender.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/interface.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/listers.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/parallelize/error_channel.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/parallelize/parallelism.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/README.md create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultbinder/default_binder.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultpreemption/default_preemption.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/dynamicresources/OWNERS create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/dynamicresources/dynamicresources.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature/feature.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper/normalize_score.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper/shape_score.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper/spread.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper/taint.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/imagelocality/image_locality.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity/filtering.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity/plugin.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity/scoring.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/names/names.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeaffinity/node_affinity.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodename/node_name.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeports/node_ports.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/balanced_allocation.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/fit.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/least_allocated.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/most_allocated.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/requested_to_capacity_ratio.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/resource_allocation.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/test_util.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeunschedulable/node_unschedulable.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodevolumelimits/csi.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodevolumelimits/non_csi.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodevolumelimits/utils.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread/common.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread/filtering.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread/plugin.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread/scoring.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/queuesort/priority_sort.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/registry.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/schedulinggates/scheduling_gates.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/selectorspread/selector_spread.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/tainttoleration/taint_toleration.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/OWNERS create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/assume_cache.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/binder.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/fake_binder.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/metrics/metrics.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/scorer.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/test_utils.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/volume_binding.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumerestrictions/volume_restrictions.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumezone/volume_zone.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/preemption/preemption.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/runtime/framework.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/runtime/metrics_recorder.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/runtime/registry.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/runtime/waiting_pods_map.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/framework/types.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/cache.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger/comparer.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger/debugger.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger/dumper.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger/signal.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger/signal_windows.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/interface.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/node_tree.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/snapshot.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/internal/heap/heap.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/internal/queue/events.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/internal/queue/scheduling_queue.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/internal/queue/testing.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/metrics/metric_recorder.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/metrics/metrics.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/metrics/profile_metrics.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/metrics/resources/resources.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/profile/profile.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/schedule_one.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/scheduler.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/util/pod_resources.go create mode 100644 vendor/k8s.io/kubernetes/pkg/scheduler/util/utils.go create mode 100644 vendor/k8s.io/kubernetes/pkg/securitycontext/accessors.go create mode 100644 vendor/k8s.io/kubernetes/pkg/securitycontext/doc.go create mode 100644 vendor/k8s.io/kubernetes/pkg/securitycontext/fake.go create mode 100644 vendor/k8s.io/kubernetes/pkg/securitycontext/util.go create mode 100644 vendor/k8s.io/kubernetes/pkg/util/parsers/parsers.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/OWNERS create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/doc.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/metrics_block.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/metrics_cached.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/metrics_du.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/metrics_errors.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/metrics_nil.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/metrics_statfs.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/noop_expandable_plugin.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/plugins.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/atomic_writer.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/attach_limit.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/device_util.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/device_util_linux.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/device_util_unsupported.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/doc.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/finalizer.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/fs/fs.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/fs/fs_unsupported.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/fs/fs_windows.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/common/quota_linux_common.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/common/quota_linux_common_impl.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/project.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/quota.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/quota_linux.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/quota_unsupported.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/hostutil/fake_hostutil.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/hostutil/hostutil.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/hostutil/hostutil_linux.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/hostutil/hostutil_unsupported.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/hostutil/hostutil_windows.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/io_util.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/metrics.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/nested_volumes.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/recyclerclient/recycler_client.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/resize_util.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/selinux.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/storageclass.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/subpath/OWNERS create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/subpath/subpath.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/subpath/subpath_linux.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/subpath/subpath_unsupported.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/subpath/subpath_windows.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/types/types.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/util.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/volumepathhandler/volume_path_handler.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/volumepathhandler/volume_path_handler_linux.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/util/volumepathhandler/volume_path_handler_unsupported.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/volume.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/volume_linux.go create mode 100644 vendor/k8s.io/kubernetes/pkg/volume/volume_unsupported.go create mode 100644 vendor/k8s.io/mount-utils/LICENSE create mode 100644 vendor/k8s.io/mount-utils/OWNERS create mode 100644 vendor/k8s.io/mount-utils/README.md create mode 100644 vendor/k8s.io/mount-utils/SECURITY_CONTACTS create mode 100644 vendor/k8s.io/mount-utils/code-of-conduct.md create mode 100644 vendor/k8s.io/mount-utils/doc.go create mode 100644 vendor/k8s.io/mount-utils/fake_mounter.go create mode 100644 vendor/k8s.io/mount-utils/mount.go create mode 100644 vendor/k8s.io/mount-utils/mount_helper_common.go create mode 100644 vendor/k8s.io/mount-utils/mount_helper_unix.go create mode 100644 vendor/k8s.io/mount-utils/mount_helper_windows.go create mode 100644 vendor/k8s.io/mount-utils/mount_linux.go create mode 100644 vendor/k8s.io/mount-utils/mount_unsupported.go create mode 100644 vendor/k8s.io/mount-utils/mount_windows.go create mode 100644 vendor/k8s.io/mount-utils/resizefs_linux.go create mode 100644 vendor/k8s.io/mount-utils/resizefs_unsupported.go create mode 100644 vendor/k8s.io/utils/io/README.md create mode 100644 vendor/k8s.io/utils/io/read.go create mode 100644 vendor/k8s.io/utils/keymutex/hashed.go create mode 100644 vendor/k8s.io/utils/keymutex/keymutex.go create mode 100644 vendor/k8s.io/utils/nsenter/OWNERS create mode 100644 vendor/k8s.io/utils/nsenter/README.md create mode 100644 vendor/k8s.io/utils/nsenter/nsenter.go create mode 100644 vendor/k8s.io/utils/nsenter/nsenter_unsupported.go create mode 100644 vendor/k8s.io/utils/strings/escape.go create mode 100644 vendor/k8s.io/utils/strings/line_delimiter.go create mode 100644 vendor/k8s.io/utils/strings/strings.go diff --git a/cmd/koslet/app/server.go b/cmd/koslet/app/server.go new file mode 100644 index 000000000..d5c17de62 --- /dev/null +++ b/cmd/koslet/app/server.go @@ -0,0 +1,7 @@ +package app + +import "github.com/spf13/cobra" + +func NewKosletCommand() *cobra.Command { + return nil +} diff --git a/cmd/koslet/main.go b/cmd/koslet/main.go new file mode 100644 index 000000000..c8d421e7f --- /dev/null +++ b/cmd/koslet/main.go @@ -0,0 +1,15 @@ +package main + +import ( + "os" + + "k8s.io/component-base/cli" + + "github.com/kosmos.io/kosmos/cmd/koslet/app" +) + +func main() { + command := app.NewKosletCommand() + code := cli.Run(command) + os.Exit(code) +} diff --git a/cmd/scheduler/main.go b/cmd/scheduler/main.go new file mode 100644 index 000000000..3b37f4731 --- /dev/null +++ b/cmd/scheduler/main.go @@ -0,0 +1,18 @@ +package main + +import ( + "os" + + "k8s.io/component-base/cli" + "k8s.io/kubernetes/cmd/kube-scheduler/app" +) + +func main() { + // Register custom plugins to the scheduler framework. + // Later they can consist of scheduler profile(s) and hence + // used by various kinds of workloads. + command := app.NewSchedulerCommand() + + code := cli.Run(command) + os.Exit(code) +} diff --git a/go.mod b/go.mod index 133c96608..ad4d5a974 100644 --- a/go.mod +++ b/go.mod @@ -31,6 +31,7 @@ require ( k8s.io/kube-aggregator v0.26.3 k8s.io/kube-openapi v0.0.0-20230303024457-afdc3dddf62d k8s.io/kubectl v0.26.3 + k8s.io/kubernetes v0.0.0-00010101000000-000000000000 k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 sigs.k8s.io/controller-runtime v0.14.5 ) @@ -50,6 +51,7 @@ require ( github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/docker/distribution v2.8.1+incompatible // indirect github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/evanphx/json-patch v4.12.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect @@ -92,12 +94,15 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect github.com/mitchellh/go-wordwrap v1.0.0 // indirect github.com/moby/spdystream v0.2.0 // indirect + github.com/moby/sys/mountinfo v0.6.2 // indirect github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/selinux v1.10.0 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/projectcalico/go-json v0.0.0-20161128004156-6219dc7339ba // indirect github.com/projectcalico/go-yaml-wrapper v0.0.0-20191112210931-090425220c54 // indirect @@ -146,8 +151,14 @@ require ( gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/cloud-provider v0.23.3 // indirect + k8s.io/component-helpers v0.26.3 // indirect + k8s.io/csi-translation-lib v0.23.3 // indirect + k8s.io/dynamic-resource-allocation v0.0.0 // indirect k8s.io/gengo v0.0.0-20220902162205-c0856e24416d // indirect k8s.io/kms v0.26.3 // indirect + k8s.io/kube-scheduler v0.0.0 // indirect + k8s.io/mount-utils v0.23.3 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.36 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kustomize/api v0.12.1 // indirect @@ -158,10 +169,31 @@ require ( replace ( golang.org/x/oauth2 => golang.org/x/oauth2 v0.1.0 + k8s.io/api => k8s.io/api v0.26.3 + k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.26.3 + k8s.io/apimachinery => k8s.io/apimachinery v0.26.3 + k8s.io/apiserver => k8s.io/apiserver v0.26.3 + k8s.io/cli-runtime => k8s.io/cli-runtime v0.26.3 + k8s.io/client-go => k8s.io/client-go v0.26.3 + k8s.io/cloud-provider => k8s.io/cloud-provider v0.26.3 + k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.26.3 + k8s.io/code-generator => k8s.io/code-generator v0.26.3 + k8s.io/component-base => k8s.io/component-base v0.26.3 + k8s.io/component-helpers => k8s.io/component-helpers v0.26.3 + k8s.io/controller-manager => k8s.io/controller-manager v0.26.3 k8s.io/cri-api => k8s.io/cri-api v0.26.3 + k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.26.3 + k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.26.3 + k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.26.3 + k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.26.3 k8s.io/kube-proxy => k8s.io/kube-proxy v0.26.3 k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.26.3 + k8s.io/kubectl => k8s.io/kubectl v0.26.3 k8s.io/kubelet => k8s.io/kubelet v0.26.3 - k8s.io/kubernetes => k8s.io/kubernetes v0.26.3 + k8s.io/kubernetes => k8s.io/kubernetes v1.26.3 k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.26.3 + k8s.io/metrics => k8s.io/metrics v0.26.3 + k8s.io/mount-utils => k8s.io/mount-utils v0.26.3 + k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.26.3 + k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.26.3 ) diff --git a/go.sum b/go.sum index c52fe56f9..125e018d6 100644 --- a/go.sum +++ b/go.sum @@ -121,6 +121,8 @@ github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= @@ -361,6 +363,8 @@ github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9 github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= +github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI= github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -386,6 +390,10 @@ github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/selinux v1.10.0 h1:rAiKF8hTcgLI3w0DHm6i0ylVVcOrlgR1kK99DRLDhyU= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -663,6 +671,7 @@ golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191003212358-c178f38b412c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1047,12 +1056,20 @@ k8s.io/cli-runtime v0.26.3 h1:3ULe0oI28xmgeLMVXIstB+ZL5CTGvWSMVMLeHxitIuc= k8s.io/cli-runtime v0.26.3/go.mod h1:5YEhXLV4kLt/OSy9yQwtSSNZU2Z7aTEYta1A+Jg4VC4= k8s.io/client-go v0.26.3 h1:k1UY+KXfkxV2ScEL3gilKcF7761xkYsSD6BC9szIu8s= k8s.io/client-go v0.26.3/go.mod h1:ZPNu9lm8/dbRIPAgteN30RSXea6vrCpFvq+MateTUuQ= +k8s.io/cloud-provider v0.26.3 h1:qN4f0+PvgOZyKIIct+90eedYj8/S4EKPpSD9S+3RCFE= +k8s.io/cloud-provider v0.26.3/go.mod h1:Hfxu0mvz426xlvz2tziw0m3ubr+sk05KKD4HPy2kwdY= k8s.io/cluster-bootstrap v0.26.3 h1:x+yLUle2BaGoAfHbqyzCabGLHR0caZ+9Cvr9BlExR7w= k8s.io/cluster-bootstrap v0.26.3/go.mod h1:/ycygTmZVqlJehSJQzV7RU6DH+MlW9TL0HEr/xQzDDI= k8s.io/code-generator v0.26.3 h1:DNYPsWoeFwmg4qFg97Z1cHSSv7KSG10mAEIFoZGTQM8= k8s.io/code-generator v0.26.3/go.mod h1:ryaiIKwfxEJEaywEzx3dhWOydpVctKYbqLajJf0O8dI= k8s.io/component-base v0.26.3 h1:oC0WMK/ggcbGDTkdcqefI4wIZRYdK3JySx9/HADpV0g= k8s.io/component-base v0.26.3/go.mod h1:5kj1kZYwSC6ZstHJN7oHBqcJC6yyn41eR+Sqa/mQc8E= +k8s.io/component-helpers v0.26.3 h1:eQ682yg1GiIGAsde+l2xL0P2yMYJOvypWsz6h6FtkZo= +k8s.io/component-helpers v0.26.3/go.mod h1:feC+CaxJXULs5TSD3lG8K5ecftOkF8eY0pHQgd7koEI= +k8s.io/csi-translation-lib v0.26.3 h1:XpC3yeBSz+qls9zk3Tqg6r2sZxFePGe1fIlSlmds5XA= +k8s.io/csi-translation-lib v0.26.3/go.mod h1:i++hspfN3AZsA5cYQ1QFnflIQhirsoc/8bOLkaVJG/g= +k8s.io/dynamic-resource-allocation v0.26.3 h1:WBI4xDoMySaH5VJe0y514O3rC4gyiJppC0EkDo6mHq0= +k8s.io/dynamic-resource-allocation v0.26.3/go.mod h1:8nUg20y2DgAv8v+Yuv7O5+rLZa7jbjsU3KvDcBiv2b8= k8s.io/gengo v0.0.0-20220902162205-c0856e24416d h1:U9tB195lKdzwqicbJvyJeOXV7Klv+wNAWENRnXEGi08= k8s.io/gengo v0.0.0-20220902162205-c0856e24416d/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= @@ -1064,8 +1081,14 @@ k8s.io/kube-aggregator v0.26.3 h1:nc4H5ymGkWPU3c9U9UM468JcmNENY/s/mDYVW3t3uRo= k8s.io/kube-aggregator v0.26.3/go.mod h1:SgBESB/+PfZAyceTPIanfQ7GtX9G/+mjfUbTHg3Twbo= k8s.io/kube-openapi v0.0.0-20230303024457-afdc3dddf62d h1:VcFq5n7wCJB2FQMCIHfC+f+jNcGgNMar1uKd6rVlifU= k8s.io/kube-openapi v0.0.0-20230303024457-afdc3dddf62d/go.mod h1:y5VtZWM9sHHc2ZodIH/6SHzXj+TPU5USoA8lcIeKEKY= +k8s.io/kube-scheduler v0.26.3 h1:IOMIG5dUILnJIMnCbTUQokTb37Sd28vexquBSeajk6c= +k8s.io/kube-scheduler v0.26.3/go.mod h1:mbym95ZdWOaftRMmdLRcAam9MCNf7iUjnPfZTl8uHTA= k8s.io/kubectl v0.26.3 h1:bZ5SgFyeEXw6XTc1Qji0iNdtqAC76lmeIIQULg2wNXM= k8s.io/kubectl v0.26.3/go.mod h1:02+gv7Qn4dupzN3fi/9OvqqdW+uG/4Zi56vc4Zmsp1g= +k8s.io/kubernetes v1.26.3 h1:LtjNGNNpCTRyrWhDJMwTWDX+4h+GLwfULS8pu0xzSdk= +k8s.io/kubernetes v1.26.3/go.mod h1:NxzR7U7mS+OGa3J/qweI86Pek//mlfHqDgt6NNGdz8g= +k8s.io/mount-utils v0.26.3 h1:FxMDiPLCkrYgonfSaKHWltLNkyTg3Q/Xrwn94uwhd8k= +k8s.io/mount-utils v0.26.3/go.mod h1:95yx9K6N37y8YZ0/lUh9U6ITosMODNaW0/v4wvaa0Xw= k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 h1:KTgPnR10d5zhztWptI952TNtt/4u5h3IzDXkdIMuo2Y= k8s.io/utils v0.0.0-20221128185143-99ec85e7a448/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/vendor/github.com/docker/distribution/LICENSE b/vendor/github.com/docker/distribution/LICENSE new file mode 100644 index 000000000..e06d20818 --- /dev/null +++ b/vendor/github.com/docker/distribution/LICENSE @@ -0,0 +1,202 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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. + diff --git a/vendor/github.com/docker/distribution/digestset/set.go b/vendor/github.com/docker/distribution/digestset/set.go new file mode 100644 index 000000000..71327dca7 --- /dev/null +++ b/vendor/github.com/docker/distribution/digestset/set.go @@ -0,0 +1,247 @@ +package digestset + +import ( + "errors" + "sort" + "strings" + "sync" + + digest "github.com/opencontainers/go-digest" +) + +var ( + // ErrDigestNotFound is used when a matching digest + // could not be found in a set. + ErrDigestNotFound = errors.New("digest not found") + + // ErrDigestAmbiguous is used when multiple digests + // are found in a set. None of the matching digests + // should be considered valid matches. + ErrDigestAmbiguous = errors.New("ambiguous digest string") +) + +// Set is used to hold a unique set of digests which +// may be easily referenced by easily referenced by a string +// representation of the digest as well as short representation. +// The uniqueness of the short representation is based on other +// digests in the set. If digests are omitted from this set, +// collisions in a larger set may not be detected, therefore it +// is important to always do short representation lookups on +// the complete set of digests. To mitigate collisions, an +// appropriately long short code should be used. +type Set struct { + mutex sync.RWMutex + entries digestEntries +} + +// NewSet creates an empty set of digests +// which may have digests added. +func NewSet() *Set { + return &Set{ + entries: digestEntries{}, + } +} + +// checkShortMatch checks whether two digests match as either whole +// values or short values. This function does not test equality, +// rather whether the second value could match against the first +// value. +func checkShortMatch(alg digest.Algorithm, hex, shortAlg, shortHex string) bool { + if len(hex) == len(shortHex) { + if hex != shortHex { + return false + } + if len(shortAlg) > 0 && string(alg) != shortAlg { + return false + } + } else if !strings.HasPrefix(hex, shortHex) { + return false + } else if len(shortAlg) > 0 && string(alg) != shortAlg { + return false + } + return true +} + +// Lookup looks for a digest matching the given string representation. +// If no digests could be found ErrDigestNotFound will be returned +// with an empty digest value. If multiple matches are found +// ErrDigestAmbiguous will be returned with an empty digest value. +func (dst *Set) Lookup(d string) (digest.Digest, error) { + dst.mutex.RLock() + defer dst.mutex.RUnlock() + if len(dst.entries) == 0 { + return "", ErrDigestNotFound + } + var ( + searchFunc func(int) bool + alg digest.Algorithm + hex string + ) + dgst, err := digest.Parse(d) + if err == digest.ErrDigestInvalidFormat { + hex = d + searchFunc = func(i int) bool { + return dst.entries[i].val >= d + } + } else { + hex = dgst.Hex() + alg = dgst.Algorithm() + searchFunc = func(i int) bool { + if dst.entries[i].val == hex { + return dst.entries[i].alg >= alg + } + return dst.entries[i].val >= hex + } + } + idx := sort.Search(len(dst.entries), searchFunc) + if idx == len(dst.entries) || !checkShortMatch(dst.entries[idx].alg, dst.entries[idx].val, string(alg), hex) { + return "", ErrDigestNotFound + } + if dst.entries[idx].alg == alg && dst.entries[idx].val == hex { + return dst.entries[idx].digest, nil + } + if idx+1 < len(dst.entries) && checkShortMatch(dst.entries[idx+1].alg, dst.entries[idx+1].val, string(alg), hex) { + return "", ErrDigestAmbiguous + } + + return dst.entries[idx].digest, nil +} + +// Add adds the given digest to the set. An error will be returned +// if the given digest is invalid. If the digest already exists in the +// set, this operation will be a no-op. +func (dst *Set) Add(d digest.Digest) error { + if err := d.Validate(); err != nil { + return err + } + dst.mutex.Lock() + defer dst.mutex.Unlock() + entry := &digestEntry{alg: d.Algorithm(), val: d.Hex(), digest: d} + searchFunc := func(i int) bool { + if dst.entries[i].val == entry.val { + return dst.entries[i].alg >= entry.alg + } + return dst.entries[i].val >= entry.val + } + idx := sort.Search(len(dst.entries), searchFunc) + if idx == len(dst.entries) { + dst.entries = append(dst.entries, entry) + return nil + } else if dst.entries[idx].digest == d { + return nil + } + + entries := append(dst.entries, nil) + copy(entries[idx+1:], entries[idx:len(entries)-1]) + entries[idx] = entry + dst.entries = entries + return nil +} + +// Remove removes the given digest from the set. An err will be +// returned if the given digest is invalid. If the digest does +// not exist in the set, this operation will be a no-op. +func (dst *Set) Remove(d digest.Digest) error { + if err := d.Validate(); err != nil { + return err + } + dst.mutex.Lock() + defer dst.mutex.Unlock() + entry := &digestEntry{alg: d.Algorithm(), val: d.Hex(), digest: d} + searchFunc := func(i int) bool { + if dst.entries[i].val == entry.val { + return dst.entries[i].alg >= entry.alg + } + return dst.entries[i].val >= entry.val + } + idx := sort.Search(len(dst.entries), searchFunc) + // Not found if idx is after or value at idx is not digest + if idx == len(dst.entries) || dst.entries[idx].digest != d { + return nil + } + + entries := dst.entries + copy(entries[idx:], entries[idx+1:]) + entries = entries[:len(entries)-1] + dst.entries = entries + + return nil +} + +// All returns all the digests in the set +func (dst *Set) All() []digest.Digest { + dst.mutex.RLock() + defer dst.mutex.RUnlock() + retValues := make([]digest.Digest, len(dst.entries)) + for i := range dst.entries { + retValues[i] = dst.entries[i].digest + } + + return retValues +} + +// ShortCodeTable returns a map of Digest to unique short codes. The +// length represents the minimum value, the maximum length may be the +// entire value of digest if uniqueness cannot be achieved without the +// full value. This function will attempt to make short codes as short +// as possible to be unique. +func ShortCodeTable(dst *Set, length int) map[digest.Digest]string { + dst.mutex.RLock() + defer dst.mutex.RUnlock() + m := make(map[digest.Digest]string, len(dst.entries)) + l := length + resetIdx := 0 + for i := 0; i < len(dst.entries); i++ { + var short string + extended := true + for extended { + extended = false + if len(dst.entries[i].val) <= l { + short = dst.entries[i].digest.String() + } else { + short = dst.entries[i].val[:l] + for j := i + 1; j < len(dst.entries); j++ { + if checkShortMatch(dst.entries[j].alg, dst.entries[j].val, "", short) { + if j > resetIdx { + resetIdx = j + } + extended = true + } else { + break + } + } + if extended { + l++ + } + } + } + m[dst.entries[i].digest] = short + if i >= resetIdx { + l = length + } + } + return m +} + +type digestEntry struct { + alg digest.Algorithm + val string + digest digest.Digest +} + +type digestEntries []*digestEntry + +func (d digestEntries) Len() int { + return len(d) +} + +func (d digestEntries) Less(i, j int) bool { + if d[i].val != d[j].val { + return d[i].val < d[j].val + } + return d[i].alg < d[j].alg +} + +func (d digestEntries) Swap(i, j int) { + d[i], d[j] = d[j], d[i] +} diff --git a/vendor/github.com/docker/distribution/reference/helpers.go b/vendor/github.com/docker/distribution/reference/helpers.go new file mode 100644 index 000000000..978df7eab --- /dev/null +++ b/vendor/github.com/docker/distribution/reference/helpers.go @@ -0,0 +1,42 @@ +package reference + +import "path" + +// IsNameOnly returns true if reference only contains a repo name. +func IsNameOnly(ref Named) bool { + if _, ok := ref.(NamedTagged); ok { + return false + } + if _, ok := ref.(Canonical); ok { + return false + } + return true +} + +// FamiliarName returns the familiar name string +// for the given named, familiarizing if needed. +func FamiliarName(ref Named) string { + if nn, ok := ref.(normalizedNamed); ok { + return nn.Familiar().Name() + } + return ref.Name() +} + +// FamiliarString returns the familiar string representation +// for the given reference, familiarizing if needed. +func FamiliarString(ref Reference) string { + if nn, ok := ref.(normalizedNamed); ok { + return nn.Familiar().String() + } + return ref.String() +} + +// FamiliarMatch reports whether ref matches the specified pattern. +// See https://godoc.org/path#Match for supported patterns. +func FamiliarMatch(pattern string, ref Reference) (bool, error) { + matched, err := path.Match(pattern, FamiliarString(ref)) + if namedRef, isNamed := ref.(Named); isNamed && !matched { + matched, _ = path.Match(pattern, FamiliarName(namedRef)) + } + return matched, err +} diff --git a/vendor/github.com/docker/distribution/reference/normalize.go b/vendor/github.com/docker/distribution/reference/normalize.go new file mode 100644 index 000000000..b3dfb7a6d --- /dev/null +++ b/vendor/github.com/docker/distribution/reference/normalize.go @@ -0,0 +1,199 @@ +package reference + +import ( + "errors" + "fmt" + "strings" + + "github.com/docker/distribution/digestset" + "github.com/opencontainers/go-digest" +) + +var ( + legacyDefaultDomain = "index.docker.io" + defaultDomain = "docker.io" + officialRepoName = "library" + defaultTag = "latest" +) + +// normalizedNamed represents a name which has been +// normalized and has a familiar form. A familiar name +// is what is used in Docker UI. An example normalized +// name is "docker.io/library/ubuntu" and corresponding +// familiar name of "ubuntu". +type normalizedNamed interface { + Named + Familiar() Named +} + +// ParseNormalizedNamed parses a string into a named reference +// transforming a familiar name from Docker UI to a fully +// qualified reference. If the value may be an identifier +// use ParseAnyReference. +func ParseNormalizedNamed(s string) (Named, error) { + if ok := anchoredIdentifierRegexp.MatchString(s); ok { + return nil, fmt.Errorf("invalid repository name (%s), cannot specify 64-byte hexadecimal strings", s) + } + domain, remainder := splitDockerDomain(s) + var remoteName string + if tagSep := strings.IndexRune(remainder, ':'); tagSep > -1 { + remoteName = remainder[:tagSep] + } else { + remoteName = remainder + } + if strings.ToLower(remoteName) != remoteName { + return nil, errors.New("invalid reference format: repository name must be lowercase") + } + + ref, err := Parse(domain + "/" + remainder) + if err != nil { + return nil, err + } + named, isNamed := ref.(Named) + if !isNamed { + return nil, fmt.Errorf("reference %s has no name", ref.String()) + } + return named, nil +} + +// ParseDockerRef normalizes the image reference following the docker convention. This is added +// mainly for backward compatibility. +// The reference returned can only be either tagged or digested. For reference contains both tag +// and digest, the function returns digested reference, e.g. docker.io/library/busybox:latest@ +// sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa will be returned as +// docker.io/library/busybox@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa. +func ParseDockerRef(ref string) (Named, error) { + named, err := ParseNormalizedNamed(ref) + if err != nil { + return nil, err + } + if _, ok := named.(NamedTagged); ok { + if canonical, ok := named.(Canonical); ok { + // The reference is both tagged and digested, only + // return digested. + newNamed, err := WithName(canonical.Name()) + if err != nil { + return nil, err + } + newCanonical, err := WithDigest(newNamed, canonical.Digest()) + if err != nil { + return nil, err + } + return newCanonical, nil + } + } + return TagNameOnly(named), nil +} + +// splitDockerDomain splits a repository name to domain and remotename string. +// If no valid domain is found, the default domain is used. Repository name +// needs to be already validated before. +func splitDockerDomain(name string) (domain, remainder string) { + i := strings.IndexRune(name, '/') + if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost") { + domain, remainder = defaultDomain, name + } else { + domain, remainder = name[:i], name[i+1:] + } + if domain == legacyDefaultDomain { + domain = defaultDomain + } + if domain == defaultDomain && !strings.ContainsRune(remainder, '/') { + remainder = officialRepoName + "/" + remainder + } + return +} + +// familiarizeName returns a shortened version of the name familiar +// to to the Docker UI. Familiar names have the default domain +// "docker.io" and "library/" repository prefix removed. +// For example, "docker.io/library/redis" will have the familiar +// name "redis" and "docker.io/dmcgowan/myapp" will be "dmcgowan/myapp". +// Returns a familiarized named only reference. +func familiarizeName(named namedRepository) repository { + repo := repository{ + domain: named.Domain(), + path: named.Path(), + } + + if repo.domain == defaultDomain { + repo.domain = "" + // Handle official repositories which have the pattern "library/" + if split := strings.Split(repo.path, "/"); len(split) == 2 && split[0] == officialRepoName { + repo.path = split[1] + } + } + return repo +} + +func (r reference) Familiar() Named { + return reference{ + namedRepository: familiarizeName(r.namedRepository), + tag: r.tag, + digest: r.digest, + } +} + +func (r repository) Familiar() Named { + return familiarizeName(r) +} + +func (t taggedReference) Familiar() Named { + return taggedReference{ + namedRepository: familiarizeName(t.namedRepository), + tag: t.tag, + } +} + +func (c canonicalReference) Familiar() Named { + return canonicalReference{ + namedRepository: familiarizeName(c.namedRepository), + digest: c.digest, + } +} + +// TagNameOnly adds the default tag "latest" to a reference if it only has +// a repo name. +func TagNameOnly(ref Named) Named { + if IsNameOnly(ref) { + namedTagged, err := WithTag(ref, defaultTag) + if err != nil { + // Default tag must be valid, to create a NamedTagged + // type with non-validated input the WithTag function + // should be used instead + panic(err) + } + return namedTagged + } + return ref +} + +// ParseAnyReference parses a reference string as a possible identifier, +// full digest, or familiar name. +func ParseAnyReference(ref string) (Reference, error) { + if ok := anchoredIdentifierRegexp.MatchString(ref); ok { + return digestReference("sha256:" + ref), nil + } + if dgst, err := digest.Parse(ref); err == nil { + return digestReference(dgst), nil + } + + return ParseNormalizedNamed(ref) +} + +// ParseAnyReferenceWithSet parses a reference string as a possible short +// identifier to be matched in a digest set, a full digest, or familiar name. +func ParseAnyReferenceWithSet(ref string, ds *digestset.Set) (Reference, error) { + if ok := anchoredShortIdentifierRegexp.MatchString(ref); ok { + dgst, err := ds.Lookup(ref) + if err == nil { + return digestReference(dgst), nil + } + } else { + if dgst, err := digest.Parse(ref); err == nil { + return digestReference(dgst), nil + } + } + + return ParseNormalizedNamed(ref) +} diff --git a/vendor/github.com/docker/distribution/reference/reference.go b/vendor/github.com/docker/distribution/reference/reference.go new file mode 100644 index 000000000..8c0c23b2f --- /dev/null +++ b/vendor/github.com/docker/distribution/reference/reference.go @@ -0,0 +1,433 @@ +// Package reference provides a general type to represent any way of referencing images within the registry. +// Its main purpose is to abstract tags and digests (content-addressable hash). +// +// Grammar +// +// reference := name [ ":" tag ] [ "@" digest ] +// name := [domain '/'] path-component ['/' path-component]* +// domain := domain-component ['.' domain-component]* [':' port-number] +// domain-component := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/ +// port-number := /[0-9]+/ +// path-component := alpha-numeric [separator alpha-numeric]* +// alpha-numeric := /[a-z0-9]+/ +// separator := /[_.]|__|[-]*/ +// +// tag := /[\w][\w.-]{0,127}/ +// +// digest := digest-algorithm ":" digest-hex +// digest-algorithm := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ]* +// digest-algorithm-separator := /[+.-_]/ +// digest-algorithm-component := /[A-Za-z][A-Za-z0-9]*/ +// digest-hex := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value +// +// identifier := /[a-f0-9]{64}/ +// short-identifier := /[a-f0-9]{6,64}/ +package reference + +import ( + "errors" + "fmt" + "strings" + + "github.com/opencontainers/go-digest" +) + +const ( + // NameTotalLengthMax is the maximum total number of characters in a repository name. + NameTotalLengthMax = 255 +) + +var ( + // ErrReferenceInvalidFormat represents an error while trying to parse a string as a reference. + ErrReferenceInvalidFormat = errors.New("invalid reference format") + + // ErrTagInvalidFormat represents an error while trying to parse a string as a tag. + ErrTagInvalidFormat = errors.New("invalid tag format") + + // ErrDigestInvalidFormat represents an error while trying to parse a string as a tag. + ErrDigestInvalidFormat = errors.New("invalid digest format") + + // ErrNameContainsUppercase is returned for invalid repository names that contain uppercase characters. + ErrNameContainsUppercase = errors.New("repository name must be lowercase") + + // ErrNameEmpty is returned for empty, invalid repository names. + ErrNameEmpty = errors.New("repository name must have at least one component") + + // ErrNameTooLong is returned when a repository name is longer than NameTotalLengthMax. + ErrNameTooLong = fmt.Errorf("repository name must not be more than %v characters", NameTotalLengthMax) + + // ErrNameNotCanonical is returned when a name is not canonical. + ErrNameNotCanonical = errors.New("repository name must be canonical") +) + +// Reference is an opaque object reference identifier that may include +// modifiers such as a hostname, name, tag, and digest. +type Reference interface { + // String returns the full reference + String() string +} + +// Field provides a wrapper type for resolving correct reference types when +// working with encoding. +type Field struct { + reference Reference +} + +// AsField wraps a reference in a Field for encoding. +func AsField(reference Reference) Field { + return Field{reference} +} + +// Reference unwraps the reference type from the field to +// return the Reference object. This object should be +// of the appropriate type to further check for different +// reference types. +func (f Field) Reference() Reference { + return f.reference +} + +// MarshalText serializes the field to byte text which +// is the string of the reference. +func (f Field) MarshalText() (p []byte, err error) { + return []byte(f.reference.String()), nil +} + +// UnmarshalText parses text bytes by invoking the +// reference parser to ensure the appropriately +// typed reference object is wrapped by field. +func (f *Field) UnmarshalText(p []byte) error { + r, err := Parse(string(p)) + if err != nil { + return err + } + + f.reference = r + return nil +} + +// Named is an object with a full name +type Named interface { + Reference + Name() string +} + +// Tagged is an object which has a tag +type Tagged interface { + Reference + Tag() string +} + +// NamedTagged is an object including a name and tag. +type NamedTagged interface { + Named + Tag() string +} + +// Digested is an object which has a digest +// in which it can be referenced by +type Digested interface { + Reference + Digest() digest.Digest +} + +// Canonical reference is an object with a fully unique +// name including a name with domain and digest +type Canonical interface { + Named + Digest() digest.Digest +} + +// namedRepository is a reference to a repository with a name. +// A namedRepository has both domain and path components. +type namedRepository interface { + Named + Domain() string + Path() string +} + +// Domain returns the domain part of the Named reference +func Domain(named Named) string { + if r, ok := named.(namedRepository); ok { + return r.Domain() + } + domain, _ := splitDomain(named.Name()) + return domain +} + +// Path returns the name without the domain part of the Named reference +func Path(named Named) (name string) { + if r, ok := named.(namedRepository); ok { + return r.Path() + } + _, path := splitDomain(named.Name()) + return path +} + +func splitDomain(name string) (string, string) { + match := anchoredNameRegexp.FindStringSubmatch(name) + if len(match) != 3 { + return "", name + } + return match[1], match[2] +} + +// SplitHostname splits a named reference into a +// hostname and name string. If no valid hostname is +// found, the hostname is empty and the full value +// is returned as name +// DEPRECATED: Use Domain or Path +func SplitHostname(named Named) (string, string) { + if r, ok := named.(namedRepository); ok { + return r.Domain(), r.Path() + } + return splitDomain(named.Name()) +} + +// Parse parses s and returns a syntactically valid Reference. +// If an error was encountered it is returned, along with a nil Reference. +// NOTE: Parse will not handle short digests. +func Parse(s string) (Reference, error) { + matches := ReferenceRegexp.FindStringSubmatch(s) + if matches == nil { + if s == "" { + return nil, ErrNameEmpty + } + if ReferenceRegexp.FindStringSubmatch(strings.ToLower(s)) != nil { + return nil, ErrNameContainsUppercase + } + return nil, ErrReferenceInvalidFormat + } + + if len(matches[1]) > NameTotalLengthMax { + return nil, ErrNameTooLong + } + + var repo repository + + nameMatch := anchoredNameRegexp.FindStringSubmatch(matches[1]) + if len(nameMatch) == 3 { + repo.domain = nameMatch[1] + repo.path = nameMatch[2] + } else { + repo.domain = "" + repo.path = matches[1] + } + + ref := reference{ + namedRepository: repo, + tag: matches[2], + } + if matches[3] != "" { + var err error + ref.digest, err = digest.Parse(matches[3]) + if err != nil { + return nil, err + } + } + + r := getBestReferenceType(ref) + if r == nil { + return nil, ErrNameEmpty + } + + return r, nil +} + +// ParseNamed parses s and returns a syntactically valid reference implementing +// the Named interface. The reference must have a name and be in the canonical +// form, otherwise an error is returned. +// If an error was encountered it is returned, along with a nil Reference. +// NOTE: ParseNamed will not handle short digests. +func ParseNamed(s string) (Named, error) { + named, err := ParseNormalizedNamed(s) + if err != nil { + return nil, err + } + if named.String() != s { + return nil, ErrNameNotCanonical + } + return named, nil +} + +// WithName returns a named object representing the given string. If the input +// is invalid ErrReferenceInvalidFormat will be returned. +func WithName(name string) (Named, error) { + if len(name) > NameTotalLengthMax { + return nil, ErrNameTooLong + } + + match := anchoredNameRegexp.FindStringSubmatch(name) + if match == nil || len(match) != 3 { + return nil, ErrReferenceInvalidFormat + } + return repository{ + domain: match[1], + path: match[2], + }, nil +} + +// WithTag combines the name from "name" and the tag from "tag" to form a +// reference incorporating both the name and the tag. +func WithTag(name Named, tag string) (NamedTagged, error) { + if !anchoredTagRegexp.MatchString(tag) { + return nil, ErrTagInvalidFormat + } + var repo repository + if r, ok := name.(namedRepository); ok { + repo.domain = r.Domain() + repo.path = r.Path() + } else { + repo.path = name.Name() + } + if canonical, ok := name.(Canonical); ok { + return reference{ + namedRepository: repo, + tag: tag, + digest: canonical.Digest(), + }, nil + } + return taggedReference{ + namedRepository: repo, + tag: tag, + }, nil +} + +// WithDigest combines the name from "name" and the digest from "digest" to form +// a reference incorporating both the name and the digest. +func WithDigest(name Named, digest digest.Digest) (Canonical, error) { + if !anchoredDigestRegexp.MatchString(digest.String()) { + return nil, ErrDigestInvalidFormat + } + var repo repository + if r, ok := name.(namedRepository); ok { + repo.domain = r.Domain() + repo.path = r.Path() + } else { + repo.path = name.Name() + } + if tagged, ok := name.(Tagged); ok { + return reference{ + namedRepository: repo, + tag: tagged.Tag(), + digest: digest, + }, nil + } + return canonicalReference{ + namedRepository: repo, + digest: digest, + }, nil +} + +// TrimNamed removes any tag or digest from the named reference. +func TrimNamed(ref Named) Named { + domain, path := SplitHostname(ref) + return repository{ + domain: domain, + path: path, + } +} + +func getBestReferenceType(ref reference) Reference { + if ref.Name() == "" { + // Allow digest only references + if ref.digest != "" { + return digestReference(ref.digest) + } + return nil + } + if ref.tag == "" { + if ref.digest != "" { + return canonicalReference{ + namedRepository: ref.namedRepository, + digest: ref.digest, + } + } + return ref.namedRepository + } + if ref.digest == "" { + return taggedReference{ + namedRepository: ref.namedRepository, + tag: ref.tag, + } + } + + return ref +} + +type reference struct { + namedRepository + tag string + digest digest.Digest +} + +func (r reference) String() string { + return r.Name() + ":" + r.tag + "@" + r.digest.String() +} + +func (r reference) Tag() string { + return r.tag +} + +func (r reference) Digest() digest.Digest { + return r.digest +} + +type repository struct { + domain string + path string +} + +func (r repository) String() string { + return r.Name() +} + +func (r repository) Name() string { + if r.domain == "" { + return r.path + } + return r.domain + "/" + r.path +} + +func (r repository) Domain() string { + return r.domain +} + +func (r repository) Path() string { + return r.path +} + +type digestReference digest.Digest + +func (d digestReference) String() string { + return digest.Digest(d).String() +} + +func (d digestReference) Digest() digest.Digest { + return digest.Digest(d) +} + +type taggedReference struct { + namedRepository + tag string +} + +func (t taggedReference) String() string { + return t.Name() + ":" + t.tag +} + +func (t taggedReference) Tag() string { + return t.tag +} + +type canonicalReference struct { + namedRepository + digest digest.Digest +} + +func (c canonicalReference) String() string { + return c.Name() + "@" + c.digest.String() +} + +func (c canonicalReference) Digest() digest.Digest { + return c.digest +} diff --git a/vendor/github.com/docker/distribution/reference/regexp.go b/vendor/github.com/docker/distribution/reference/regexp.go new file mode 100644 index 000000000..786034932 --- /dev/null +++ b/vendor/github.com/docker/distribution/reference/regexp.go @@ -0,0 +1,143 @@ +package reference + +import "regexp" + +var ( + // alphaNumericRegexp defines the alpha numeric atom, typically a + // component of names. This only allows lower case characters and digits. + alphaNumericRegexp = match(`[a-z0-9]+`) + + // separatorRegexp defines the separators allowed to be embedded in name + // components. This allow one period, one or two underscore and multiple + // dashes. + separatorRegexp = match(`(?:[._]|__|[-]*)`) + + // nameComponentRegexp restricts registry path component names to start + // with at least one letter or number, with following parts able to be + // separated by one period, one or two underscore and multiple dashes. + nameComponentRegexp = expression( + alphaNumericRegexp, + optional(repeated(separatorRegexp, alphaNumericRegexp))) + + // domainComponentRegexp restricts the registry domain component of a + // repository name to start with a component as defined by DomainRegexp + // and followed by an optional port. + domainComponentRegexp = match(`(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`) + + // DomainRegexp defines the structure of potential domain components + // that may be part of image names. This is purposely a subset of what is + // allowed by DNS to ensure backwards compatibility with Docker image + // names. + DomainRegexp = expression( + domainComponentRegexp, + optional(repeated(literal(`.`), domainComponentRegexp)), + optional(literal(`:`), match(`[0-9]+`))) + + // TagRegexp matches valid tag names. From docker/docker:graph/tags.go. + TagRegexp = match(`[\w][\w.-]{0,127}`) + + // anchoredTagRegexp matches valid tag names, anchored at the start and + // end of the matched string. + anchoredTagRegexp = anchored(TagRegexp) + + // DigestRegexp matches valid digests. + DigestRegexp = match(`[A-Za-z][A-Za-z0-9]*(?:[-_+.][A-Za-z][A-Za-z0-9]*)*[:][[:xdigit:]]{32,}`) + + // anchoredDigestRegexp matches valid digests, anchored at the start and + // end of the matched string. + anchoredDigestRegexp = anchored(DigestRegexp) + + // NameRegexp is the format for the name component of references. The + // regexp has capturing groups for the domain and name part omitting + // the separating forward slash from either. + NameRegexp = expression( + optional(DomainRegexp, literal(`/`)), + nameComponentRegexp, + optional(repeated(literal(`/`), nameComponentRegexp))) + + // anchoredNameRegexp is used to parse a name value, capturing the + // domain and trailing components. + anchoredNameRegexp = anchored( + optional(capture(DomainRegexp), literal(`/`)), + capture(nameComponentRegexp, + optional(repeated(literal(`/`), nameComponentRegexp)))) + + // ReferenceRegexp is the full supported format of a reference. The regexp + // is anchored and has capturing groups for name, tag, and digest + // components. + ReferenceRegexp = anchored(capture(NameRegexp), + optional(literal(":"), capture(TagRegexp)), + optional(literal("@"), capture(DigestRegexp))) + + // IdentifierRegexp is the format for string identifier used as a + // content addressable identifier using sha256. These identifiers + // are like digests without the algorithm, since sha256 is used. + IdentifierRegexp = match(`([a-f0-9]{64})`) + + // ShortIdentifierRegexp is the format used to represent a prefix + // of an identifier. A prefix may be used to match a sha256 identifier + // within a list of trusted identifiers. + ShortIdentifierRegexp = match(`([a-f0-9]{6,64})`) + + // anchoredIdentifierRegexp is used to check or match an + // identifier value, anchored at start and end of string. + anchoredIdentifierRegexp = anchored(IdentifierRegexp) + + // anchoredShortIdentifierRegexp is used to check if a value + // is a possible identifier prefix, anchored at start and end + // of string. + anchoredShortIdentifierRegexp = anchored(ShortIdentifierRegexp) +) + +// match compiles the string to a regular expression. +var match = regexp.MustCompile + +// literal compiles s into a literal regular expression, escaping any regexp +// reserved characters. +func literal(s string) *regexp.Regexp { + re := match(regexp.QuoteMeta(s)) + + if _, complete := re.LiteralPrefix(); !complete { + panic("must be a literal") + } + + return re +} + +// expression defines a full expression, where each regular expression must +// follow the previous. +func expression(res ...*regexp.Regexp) *regexp.Regexp { + var s string + for _, re := range res { + s += re.String() + } + + return match(s) +} + +// optional wraps the expression in a non-capturing group and makes the +// production optional. +func optional(res ...*regexp.Regexp) *regexp.Regexp { + return match(group(expression(res...)).String() + `?`) +} + +// repeated wraps the regexp in a non-capturing group to get one or more +// matches. +func repeated(res ...*regexp.Regexp) *regexp.Regexp { + return match(group(expression(res...)).String() + `+`) +} + +// group wraps the regexp in a non-capturing group. +func group(res ...*regexp.Regexp) *regexp.Regexp { + return match(`(?:` + expression(res...).String() + `)`) +} + +// capture wraps the expression in a capturing group. +func capture(res ...*regexp.Regexp) *regexp.Regexp { + return match(`(` + expression(res...).String() + `)`) +} + +// anchored anchors the regular expression by adding start and end delimiters. +func anchored(res ...*regexp.Regexp) *regexp.Regexp { + return match(`^` + expression(res...).String() + `$`) +} diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go new file mode 100644 index 000000000..e54a76c7e --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go @@ -0,0 +1,156 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package cmpopts provides common options for the cmp package. +package cmpopts + +import ( + "errors" + "math" + "reflect" + "time" + + "github.com/google/go-cmp/cmp" +) + +func equateAlways(_, _ interface{}) bool { return true } + +// EquateEmpty returns a Comparer option that determines all maps and slices +// with a length of zero to be equal, regardless of whether they are nil. +// +// EquateEmpty can be used in conjunction with SortSlices and SortMaps. +func EquateEmpty() cmp.Option { + return cmp.FilterValues(isEmpty, cmp.Comparer(equateAlways)) +} + +func isEmpty(x, y interface{}) bool { + vx, vy := reflect.ValueOf(x), reflect.ValueOf(y) + return (x != nil && y != nil && vx.Type() == vy.Type()) && + (vx.Kind() == reflect.Slice || vx.Kind() == reflect.Map) && + (vx.Len() == 0 && vy.Len() == 0) +} + +// EquateApprox returns a Comparer option that determines float32 or float64 +// values to be equal if they are within a relative fraction or absolute margin. +// This option is not used when either x or y is NaN or infinite. +// +// The fraction determines that the difference of two values must be within the +// smaller fraction of the two values, while the margin determines that the two +// values must be within some absolute margin. +// To express only a fraction or only a margin, use 0 for the other parameter. +// The fraction and margin must be non-negative. +// +// The mathematical expression used is equivalent to: +// +// |x-y| ≤ max(fraction*min(|x|, |y|), margin) +// +// EquateApprox can be used in conjunction with EquateNaNs. +func EquateApprox(fraction, margin float64) cmp.Option { + if margin < 0 || fraction < 0 || math.IsNaN(margin) || math.IsNaN(fraction) { + panic("margin or fraction must be a non-negative number") + } + a := approximator{fraction, margin} + return cmp.Options{ + cmp.FilterValues(areRealF64s, cmp.Comparer(a.compareF64)), + cmp.FilterValues(areRealF32s, cmp.Comparer(a.compareF32)), + } +} + +type approximator struct{ frac, marg float64 } + +func areRealF64s(x, y float64) bool { + return !math.IsNaN(x) && !math.IsNaN(y) && !math.IsInf(x, 0) && !math.IsInf(y, 0) +} +func areRealF32s(x, y float32) bool { + return areRealF64s(float64(x), float64(y)) +} +func (a approximator) compareF64(x, y float64) bool { + relMarg := a.frac * math.Min(math.Abs(x), math.Abs(y)) + return math.Abs(x-y) <= math.Max(a.marg, relMarg) +} +func (a approximator) compareF32(x, y float32) bool { + return a.compareF64(float64(x), float64(y)) +} + +// EquateNaNs returns a Comparer option that determines float32 and float64 +// NaN values to be equal. +// +// EquateNaNs can be used in conjunction with EquateApprox. +func EquateNaNs() cmp.Option { + return cmp.Options{ + cmp.FilterValues(areNaNsF64s, cmp.Comparer(equateAlways)), + cmp.FilterValues(areNaNsF32s, cmp.Comparer(equateAlways)), + } +} + +func areNaNsF64s(x, y float64) bool { + return math.IsNaN(x) && math.IsNaN(y) +} +func areNaNsF32s(x, y float32) bool { + return areNaNsF64s(float64(x), float64(y)) +} + +// EquateApproxTime returns a Comparer option that determines two non-zero +// time.Time values to be equal if they are within some margin of one another. +// If both times have a monotonic clock reading, then the monotonic time +// difference will be used. The margin must be non-negative. +func EquateApproxTime(margin time.Duration) cmp.Option { + if margin < 0 { + panic("margin must be a non-negative number") + } + a := timeApproximator{margin} + return cmp.FilterValues(areNonZeroTimes, cmp.Comparer(a.compare)) +} + +func areNonZeroTimes(x, y time.Time) bool { + return !x.IsZero() && !y.IsZero() +} + +type timeApproximator struct { + margin time.Duration +} + +func (a timeApproximator) compare(x, y time.Time) bool { + // Avoid subtracting times to avoid overflow when the + // difference is larger than the largest representable duration. + if x.After(y) { + // Ensure x is always before y + x, y = y, x + } + // We're within the margin if x+margin >= y. + // Note: time.Time doesn't have AfterOrEqual method hence the negation. + return !x.Add(a.margin).Before(y) +} + +// AnyError is an error that matches any non-nil error. +var AnyError anyError + +type anyError struct{} + +func (anyError) Error() string { return "any error" } +func (anyError) Is(err error) bool { return err != nil } + +// EquateErrors returns a Comparer option that determines errors to be equal +// if errors.Is reports them to match. The AnyError error can be used to +// match any non-nil error. +func EquateErrors() cmp.Option { + return cmp.FilterValues(areConcreteErrors, cmp.Comparer(compareErrors)) +} + +// areConcreteErrors reports whether x and y are types that implement error. +// The input types are deliberately of the interface{} type rather than the +// error type so that we can handle situations where the current type is an +// interface{}, but the underlying concrete types both happen to implement +// the error interface. +func areConcreteErrors(x, y interface{}) bool { + _, ok1 := x.(error) + _, ok2 := y.(error) + return ok1 && ok2 +} + +func compareErrors(x, y interface{}) bool { + xe := x.(error) + ye := y.(error) + return errors.Is(xe, ye) || errors.Is(ye, xe) +} diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go new file mode 100644 index 000000000..80c60617e --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go @@ -0,0 +1,206 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cmpopts + +import ( + "fmt" + "reflect" + "unicode" + "unicode/utf8" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/internal/function" +) + +// IgnoreFields returns an Option that ignores fields of the +// given names on a single struct type. It respects the names of exported fields +// that are forwarded due to struct embedding. +// The struct type is specified by passing in a value of that type. +// +// The name may be a dot-delimited string (e.g., "Foo.Bar") to ignore a +// specific sub-field that is embedded or nested within the parent struct. +func IgnoreFields(typ interface{}, names ...string) cmp.Option { + sf := newStructFilter(typ, names...) + return cmp.FilterPath(sf.filter, cmp.Ignore()) +} + +// IgnoreTypes returns an Option that ignores all values assignable to +// certain types, which are specified by passing in a value of each type. +func IgnoreTypes(typs ...interface{}) cmp.Option { + tf := newTypeFilter(typs...) + return cmp.FilterPath(tf.filter, cmp.Ignore()) +} + +type typeFilter []reflect.Type + +func newTypeFilter(typs ...interface{}) (tf typeFilter) { + for _, typ := range typs { + t := reflect.TypeOf(typ) + if t == nil { + // This occurs if someone tries to pass in sync.Locker(nil) + panic("cannot determine type; consider using IgnoreInterfaces") + } + tf = append(tf, t) + } + return tf +} +func (tf typeFilter) filter(p cmp.Path) bool { + if len(p) < 1 { + return false + } + t := p.Last().Type() + for _, ti := range tf { + if t.AssignableTo(ti) { + return true + } + } + return false +} + +// IgnoreInterfaces returns an Option that ignores all values or references of +// values assignable to certain interface types. These interfaces are specified +// by passing in an anonymous struct with the interface types embedded in it. +// For example, to ignore sync.Locker, pass in struct{sync.Locker}{}. +func IgnoreInterfaces(ifaces interface{}) cmp.Option { + tf := newIfaceFilter(ifaces) + return cmp.FilterPath(tf.filter, cmp.Ignore()) +} + +type ifaceFilter []reflect.Type + +func newIfaceFilter(ifaces interface{}) (tf ifaceFilter) { + t := reflect.TypeOf(ifaces) + if ifaces == nil || t.Name() != "" || t.Kind() != reflect.Struct { + panic("input must be an anonymous struct") + } + for i := 0; i < t.NumField(); i++ { + fi := t.Field(i) + switch { + case !fi.Anonymous: + panic("struct cannot have named fields") + case fi.Type.Kind() != reflect.Interface: + panic("embedded field must be an interface type") + case fi.Type.NumMethod() == 0: + // This matches everything; why would you ever want this? + panic("cannot ignore empty interface") + default: + tf = append(tf, fi.Type) + } + } + return tf +} +func (tf ifaceFilter) filter(p cmp.Path) bool { + if len(p) < 1 { + return false + } + t := p.Last().Type() + for _, ti := range tf { + if t.AssignableTo(ti) { + return true + } + if t.Kind() != reflect.Ptr && reflect.PtrTo(t).AssignableTo(ti) { + return true + } + } + return false +} + +// IgnoreUnexported returns an Option that only ignores the immediate unexported +// fields of a struct, including anonymous fields of unexported types. +// In particular, unexported fields within the struct's exported fields +// of struct types, including anonymous fields, will not be ignored unless the +// type of the field itself is also passed to IgnoreUnexported. +// +// Avoid ignoring unexported fields of a type which you do not control (i.e. a +// type from another repository), as changes to the implementation of such types +// may change how the comparison behaves. Prefer a custom Comparer instead. +func IgnoreUnexported(typs ...interface{}) cmp.Option { + ux := newUnexportedFilter(typs...) + return cmp.FilterPath(ux.filter, cmp.Ignore()) +} + +type unexportedFilter struct{ m map[reflect.Type]bool } + +func newUnexportedFilter(typs ...interface{}) unexportedFilter { + ux := unexportedFilter{m: make(map[reflect.Type]bool)} + for _, typ := range typs { + t := reflect.TypeOf(typ) + if t == nil || t.Kind() != reflect.Struct { + panic(fmt.Sprintf("%T must be a non-pointer struct", typ)) + } + ux.m[t] = true + } + return ux +} +func (xf unexportedFilter) filter(p cmp.Path) bool { + sf, ok := p.Index(-1).(cmp.StructField) + if !ok { + return false + } + return xf.m[p.Index(-2).Type()] && !isExported(sf.Name()) +} + +// isExported reports whether the identifier is exported. +func isExported(id string) bool { + r, _ := utf8.DecodeRuneInString(id) + return unicode.IsUpper(r) +} + +// IgnoreSliceElements returns an Option that ignores elements of []V. +// The discard function must be of the form "func(T) bool" which is used to +// ignore slice elements of type V, where V is assignable to T. +// Elements are ignored if the function reports true. +func IgnoreSliceElements(discardFunc interface{}) cmp.Option { + vf := reflect.ValueOf(discardFunc) + if !function.IsType(vf.Type(), function.ValuePredicate) || vf.IsNil() { + panic(fmt.Sprintf("invalid discard function: %T", discardFunc)) + } + return cmp.FilterPath(func(p cmp.Path) bool { + si, ok := p.Index(-1).(cmp.SliceIndex) + if !ok { + return false + } + if !si.Type().AssignableTo(vf.Type().In(0)) { + return false + } + vx, vy := si.Values() + if vx.IsValid() && vf.Call([]reflect.Value{vx})[0].Bool() { + return true + } + if vy.IsValid() && vf.Call([]reflect.Value{vy})[0].Bool() { + return true + } + return false + }, cmp.Ignore()) +} + +// IgnoreMapEntries returns an Option that ignores entries of map[K]V. +// The discard function must be of the form "func(T, R) bool" which is used to +// ignore map entries of type K and V, where K and V are assignable to T and R. +// Entries are ignored if the function reports true. +func IgnoreMapEntries(discardFunc interface{}) cmp.Option { + vf := reflect.ValueOf(discardFunc) + if !function.IsType(vf.Type(), function.KeyValuePredicate) || vf.IsNil() { + panic(fmt.Sprintf("invalid discard function: %T", discardFunc)) + } + return cmp.FilterPath(func(p cmp.Path) bool { + mi, ok := p.Index(-1).(cmp.MapIndex) + if !ok { + return false + } + if !mi.Key().Type().AssignableTo(vf.Type().In(0)) || !mi.Type().AssignableTo(vf.Type().In(1)) { + return false + } + k := mi.Key() + vx, vy := mi.Values() + if vx.IsValid() && vf.Call([]reflect.Value{k, vx})[0].Bool() { + return true + } + if vy.IsValid() && vf.Call([]reflect.Value{k, vy})[0].Bool() { + return true + } + return false + }, cmp.Ignore()) +} diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go new file mode 100644 index 000000000..0eb2a758c --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go @@ -0,0 +1,147 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cmpopts + +import ( + "fmt" + "reflect" + "sort" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/internal/function" +) + +// SortSlices returns a Transformer option that sorts all []V. +// The less function must be of the form "func(T, T) bool" which is used to +// sort any slice with element type V that is assignable to T. +// +// The less function must be: +// - Deterministic: less(x, y) == less(x, y) +// - Irreflexive: !less(x, x) +// - Transitive: if !less(x, y) and !less(y, z), then !less(x, z) +// +// The less function does not have to be "total". That is, if !less(x, y) and +// !less(y, x) for two elements x and y, their relative order is maintained. +// +// SortSlices can be used in conjunction with EquateEmpty. +func SortSlices(lessFunc interface{}) cmp.Option { + vf := reflect.ValueOf(lessFunc) + if !function.IsType(vf.Type(), function.Less) || vf.IsNil() { + panic(fmt.Sprintf("invalid less function: %T", lessFunc)) + } + ss := sliceSorter{vf.Type().In(0), vf} + return cmp.FilterValues(ss.filter, cmp.Transformer("cmpopts.SortSlices", ss.sort)) +} + +type sliceSorter struct { + in reflect.Type // T + fnc reflect.Value // func(T, T) bool +} + +func (ss sliceSorter) filter(x, y interface{}) bool { + vx, vy := reflect.ValueOf(x), reflect.ValueOf(y) + if !(x != nil && y != nil && vx.Type() == vy.Type()) || + !(vx.Kind() == reflect.Slice && vx.Type().Elem().AssignableTo(ss.in)) || + (vx.Len() <= 1 && vy.Len() <= 1) { + return false + } + // Check whether the slices are already sorted to avoid an infinite + // recursion cycle applying the same transform to itself. + ok1 := sort.SliceIsSorted(x, func(i, j int) bool { return ss.less(vx, i, j) }) + ok2 := sort.SliceIsSorted(y, func(i, j int) bool { return ss.less(vy, i, j) }) + return !ok1 || !ok2 +} +func (ss sliceSorter) sort(x interface{}) interface{} { + src := reflect.ValueOf(x) + dst := reflect.MakeSlice(src.Type(), src.Len(), src.Len()) + for i := 0; i < src.Len(); i++ { + dst.Index(i).Set(src.Index(i)) + } + sort.SliceStable(dst.Interface(), func(i, j int) bool { return ss.less(dst, i, j) }) + ss.checkSort(dst) + return dst.Interface() +} +func (ss sliceSorter) checkSort(v reflect.Value) { + start := -1 // Start of a sequence of equal elements. + for i := 1; i < v.Len(); i++ { + if ss.less(v, i-1, i) { + // Check that first and last elements in v[start:i] are equal. + if start >= 0 && (ss.less(v, start, i-1) || ss.less(v, i-1, start)) { + panic(fmt.Sprintf("incomparable values detected: want equal elements: %v", v.Slice(start, i))) + } + start = -1 + } else if start == -1 { + start = i + } + } +} +func (ss sliceSorter) less(v reflect.Value, i, j int) bool { + vx, vy := v.Index(i), v.Index(j) + return ss.fnc.Call([]reflect.Value{vx, vy})[0].Bool() +} + +// SortMaps returns a Transformer option that flattens map[K]V types to be a +// sorted []struct{K, V}. The less function must be of the form +// "func(T, T) bool" which is used to sort any map with key K that is +// assignable to T. +// +// Flattening the map into a slice has the property that cmp.Equal is able to +// use Comparers on K or the K.Equal method if it exists. +// +// The less function must be: +// - Deterministic: less(x, y) == less(x, y) +// - Irreflexive: !less(x, x) +// - Transitive: if !less(x, y) and !less(y, z), then !less(x, z) +// - Total: if x != y, then either less(x, y) or less(y, x) +// +// SortMaps can be used in conjunction with EquateEmpty. +func SortMaps(lessFunc interface{}) cmp.Option { + vf := reflect.ValueOf(lessFunc) + if !function.IsType(vf.Type(), function.Less) || vf.IsNil() { + panic(fmt.Sprintf("invalid less function: %T", lessFunc)) + } + ms := mapSorter{vf.Type().In(0), vf} + return cmp.FilterValues(ms.filter, cmp.Transformer("cmpopts.SortMaps", ms.sort)) +} + +type mapSorter struct { + in reflect.Type // T + fnc reflect.Value // func(T, T) bool +} + +func (ms mapSorter) filter(x, y interface{}) bool { + vx, vy := reflect.ValueOf(x), reflect.ValueOf(y) + return (x != nil && y != nil && vx.Type() == vy.Type()) && + (vx.Kind() == reflect.Map && vx.Type().Key().AssignableTo(ms.in)) && + (vx.Len() != 0 || vy.Len() != 0) +} +func (ms mapSorter) sort(x interface{}) interface{} { + src := reflect.ValueOf(x) + outType := reflect.StructOf([]reflect.StructField{ + {Name: "K", Type: src.Type().Key()}, + {Name: "V", Type: src.Type().Elem()}, + }) + dst := reflect.MakeSlice(reflect.SliceOf(outType), src.Len(), src.Len()) + for i, k := range src.MapKeys() { + v := reflect.New(outType).Elem() + v.Field(0).Set(k) + v.Field(1).Set(src.MapIndex(k)) + dst.Index(i).Set(v) + } + sort.Slice(dst.Interface(), func(i, j int) bool { return ms.less(dst, i, j) }) + ms.checkSort(dst) + return dst.Interface() +} +func (ms mapSorter) checkSort(v reflect.Value) { + for i := 1; i < v.Len(); i++ { + if !ms.less(v, i-1, i) { + panic(fmt.Sprintf("partial order detected: want %v < %v", v.Index(i-1), v.Index(i))) + } + } +} +func (ms mapSorter) less(v reflect.Value, i, j int) bool { + vx, vy := v.Index(i).Field(0), v.Index(j).Field(0) + return ms.fnc.Call([]reflect.Value{vx, vy})[0].Bool() +} diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go new file mode 100644 index 000000000..ca11a4024 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go @@ -0,0 +1,189 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cmpopts + +import ( + "fmt" + "reflect" + "strings" + + "github.com/google/go-cmp/cmp" +) + +// filterField returns a new Option where opt is only evaluated on paths that +// include a specific exported field on a single struct type. +// The struct type is specified by passing in a value of that type. +// +// The name may be a dot-delimited string (e.g., "Foo.Bar") to select a +// specific sub-field that is embedded or nested within the parent struct. +func filterField(typ interface{}, name string, opt cmp.Option) cmp.Option { + // TODO: This is currently unexported over concerns of how helper filters + // can be composed together easily. + // TODO: Add tests for FilterField. + + sf := newStructFilter(typ, name) + return cmp.FilterPath(sf.filter, opt) +} + +type structFilter struct { + t reflect.Type // The root struct type to match on + ft fieldTree // Tree of fields to match on +} + +func newStructFilter(typ interface{}, names ...string) structFilter { + // TODO: Perhaps allow * as a special identifier to allow ignoring any + // number of path steps until the next field match? + // This could be useful when a concrete struct gets transformed into + // an anonymous struct where it is not possible to specify that by type, + // but the transformer happens to provide guarantees about the names of + // the transformed fields. + + t := reflect.TypeOf(typ) + if t == nil || t.Kind() != reflect.Struct { + panic(fmt.Sprintf("%T must be a non-pointer struct", typ)) + } + var ft fieldTree + for _, name := range names { + cname, err := canonicalName(t, name) + if err != nil { + panic(fmt.Sprintf("%s: %v", strings.Join(cname, "."), err)) + } + ft.insert(cname) + } + return structFilter{t, ft} +} + +func (sf structFilter) filter(p cmp.Path) bool { + for i, ps := range p { + if ps.Type().AssignableTo(sf.t) && sf.ft.matchPrefix(p[i+1:]) { + return true + } + } + return false +} + +// fieldTree represents a set of dot-separated identifiers. +// +// For example, inserting the following selectors: +// +// Foo +// Foo.Bar.Baz +// Foo.Buzz +// Nuka.Cola.Quantum +// +// Results in a tree of the form: +// +// {sub: { +// "Foo": {ok: true, sub: { +// "Bar": {sub: { +// "Baz": {ok: true}, +// }}, +// "Buzz": {ok: true}, +// }}, +// "Nuka": {sub: { +// "Cola": {sub: { +// "Quantum": {ok: true}, +// }}, +// }}, +// }} +type fieldTree struct { + ok bool // Whether this is a specified node + sub map[string]fieldTree // The sub-tree of fields under this node +} + +// insert inserts a sequence of field accesses into the tree. +func (ft *fieldTree) insert(cname []string) { + if ft.sub == nil { + ft.sub = make(map[string]fieldTree) + } + if len(cname) == 0 { + ft.ok = true + return + } + sub := ft.sub[cname[0]] + sub.insert(cname[1:]) + ft.sub[cname[0]] = sub +} + +// matchPrefix reports whether any selector in the fieldTree matches +// the start of path p. +func (ft fieldTree) matchPrefix(p cmp.Path) bool { + for _, ps := range p { + switch ps := ps.(type) { + case cmp.StructField: + ft = ft.sub[ps.Name()] + if ft.ok { + return true + } + if len(ft.sub) == 0 { + return false + } + case cmp.Indirect: + default: + return false + } + } + return false +} + +// canonicalName returns a list of identifiers where any struct field access +// through an embedded field is expanded to include the names of the embedded +// types themselves. +// +// For example, suppose field "Foo" is not directly in the parent struct, +// but actually from an embedded struct of type "Bar". Then, the canonical name +// of "Foo" is actually "Bar.Foo". +// +// Suppose field "Foo" is not directly in the parent struct, but actually +// a field in two different embedded structs of types "Bar" and "Baz". +// Then the selector "Foo" causes a panic since it is ambiguous which one it +// refers to. The user must specify either "Bar.Foo" or "Baz.Foo". +func canonicalName(t reflect.Type, sel string) ([]string, error) { + var name string + sel = strings.TrimPrefix(sel, ".") + if sel == "" { + return nil, fmt.Errorf("name must not be empty") + } + if i := strings.IndexByte(sel, '.'); i < 0 { + name, sel = sel, "" + } else { + name, sel = sel[:i], sel[i:] + } + + // Type must be a struct or pointer to struct. + if t.Kind() == reflect.Ptr { + t = t.Elem() + } + if t.Kind() != reflect.Struct { + return nil, fmt.Errorf("%v must be a struct", t) + } + + // Find the canonical name for this current field name. + // If the field exists in an embedded struct, then it will be expanded. + sf, _ := t.FieldByName(name) + if !isExported(name) { + // Avoid using reflect.Type.FieldByName for unexported fields due to + // buggy behavior with regard to embeddeding and unexported fields. + // See https://golang.org/issue/4876 for details. + sf = reflect.StructField{} + for i := 0; i < t.NumField() && sf.Name == ""; i++ { + if t.Field(i).Name == name { + sf = t.Field(i) + } + } + } + if sf.Name == "" { + return []string{name}, fmt.Errorf("does not exist") + } + var ss []string + for i := range sf.Index { + ss = append(ss, t.FieldByIndex(sf.Index[:i+1]).Name) + } + if sel == "" { + return ss, nil + } + ssPost, err := canonicalName(sf.Type, sel) + return append(ss, ssPost...), err +} diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go new file mode 100644 index 000000000..8812443a2 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go @@ -0,0 +1,36 @@ +// Copyright 2018, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cmpopts + +import ( + "github.com/google/go-cmp/cmp" +) + +type xformFilter struct{ xform cmp.Option } + +func (xf xformFilter) filter(p cmp.Path) bool { + for _, ps := range p { + if t, ok := ps.(cmp.Transform); ok && t.Option() == xf.xform { + return false + } + } + return true +} + +// AcyclicTransformer returns a Transformer with a filter applied that ensures +// that the transformer cannot be recursively applied upon its own output. +// +// An example use case is a transformer that splits a string by lines: +// +// AcyclicTransformer("SplitLines", func(s string) []string{ +// return strings.Split(s, "\n") +// }) +// +// Had this been an unfiltered Transformer instead, this would result in an +// infinite cycle converting a string to []string to [][]string and so on. +func AcyclicTransformer(name string, xformFunc interface{}) cmp.Option { + xf := xformFilter{cmp.Transformer(name, xformFunc)} + return cmp.FilterPath(xf.filter, xf.xform) +} diff --git a/vendor/github.com/moby/sys/mountinfo/LICENSE b/vendor/github.com/moby/sys/mountinfo/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/github.com/moby/sys/mountinfo/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/vendor/github.com/moby/sys/mountinfo/doc.go b/vendor/github.com/moby/sys/mountinfo/doc.go new file mode 100644 index 000000000..b80e05efd --- /dev/null +++ b/vendor/github.com/moby/sys/mountinfo/doc.go @@ -0,0 +1,44 @@ +// Package mountinfo provides a set of functions to retrieve information about OS mounts. +// +// Currently it supports Linux. For historical reasons, there is also some support for FreeBSD and OpenBSD, +// and a shallow implementation for Windows, but in general this is Linux-only package, so +// the rest of the document only applies to Linux, unless explicitly specified otherwise. +// +// In Linux, information about mounts seen by the current process is available from +// /proc/self/mountinfo. Note that due to mount namespaces, different processes can +// see different mounts. A per-process mountinfo table is available from /proc//mountinfo, +// where is a numerical process identifier. +// +// In general, /proc is not a very efficient interface, and mountinfo is not an exception. +// For example, there is no way to get information about a specific mount point (i.e. it +// is all-or-nothing). This package tries to hide the /proc ineffectiveness by using +// parse filters while reading mountinfo. A filter can skip some entries, or stop +// processing the rest of the file once the needed information is found. +// +// For mountinfo filters that accept path as an argument, the path must be absolute, +// having all symlinks resolved, and being cleaned (i.e. no extra slashes or dots). +// One way to achieve all of the above is to employ filepath.Abs followed by +// filepath.EvalSymlinks (the latter calls filepath.Clean on the result so +// there is no need to explicitly call filepath.Clean). +// +// NOTE that in many cases there is no need to consult mountinfo at all. Here are some +// of the cases where mountinfo should not be parsed: +// +// 1. Before performing a mount. Usually, this is not needed, but if required (say to +// prevent over-mounts), to check whether a directory is mounted, call os.Lstat +// on it and its parent directory, and compare their st.Sys().(*syscall.Stat_t).Dev +// fields -- if they differ, then the directory is the mount point. NOTE this does +// not work for bind mounts. Optionally, the filesystem type can also be checked +// by calling unix.Statfs and checking the Type field (i.e. filesystem type). +// +// 2. After performing a mount. If there is no error returned, the mount succeeded; +// checking the mount table for a new mount is redundant and expensive. +// +// 3. Before performing an unmount. It is more efficient to do an unmount and ignore +// a specific error (EINVAL) which tells the directory is not mounted. +// +// 4. After performing an unmount. If there is no error returned, the unmount succeeded. +// +// 5. To find the mount point root of a specific directory. You can perform os.Stat() +// on the directory and traverse up until the Dev field of a parent directory differs. +package mountinfo diff --git a/vendor/github.com/moby/sys/mountinfo/mounted_linux.go b/vendor/github.com/moby/sys/mountinfo/mounted_linux.go new file mode 100644 index 000000000..e78e72619 --- /dev/null +++ b/vendor/github.com/moby/sys/mountinfo/mounted_linux.go @@ -0,0 +1,101 @@ +package mountinfo + +import ( + "os" + "path/filepath" + + "golang.org/x/sys/unix" +) + +// MountedFast is a method of detecting a mount point without reading +// mountinfo from procfs. A caller can only trust the result if no error +// and sure == true are returned. Otherwise, other methods (e.g. parsing +// /proc/mounts) have to be used. If unsure, use Mounted instead (which +// uses MountedFast, but falls back to parsing mountinfo if needed). +// +// If a non-existent path is specified, an appropriate error is returned. +// In case the caller is not interested in this particular error, it should +// be handled separately using e.g. errors.Is(err, fs.ErrNotExist). +// +// This function is only available on Linux. When available (since kernel +// v5.6), openat2(2) syscall is used to reliably detect all mounts. Otherwise, +// the implementation falls back to using stat(2), which can reliably detect +// normal (but not bind) mounts. +func MountedFast(path string) (mounted, sure bool, err error) { + // Root is always mounted. + if path == string(os.PathSeparator) { + return true, true, nil + } + + path, err = normalizePath(path) + if err != nil { + return false, false, err + } + mounted, sure, err = mountedFast(path) + return +} + +// mountedByOpenat2 is a method of detecting a mount that works for all kinds +// of mounts (incl. bind mounts), but requires a recent (v5.6+) linux kernel. +func mountedByOpenat2(path string) (bool, error) { + dir, last := filepath.Split(path) + + dirfd, err := unix.Openat2(unix.AT_FDCWD, dir, &unix.OpenHow{ + Flags: unix.O_PATH | unix.O_CLOEXEC, + }) + if err != nil { + return false, &os.PathError{Op: "openat2", Path: dir, Err: err} + } + fd, err := unix.Openat2(dirfd, last, &unix.OpenHow{ + Flags: unix.O_PATH | unix.O_CLOEXEC | unix.O_NOFOLLOW, + Resolve: unix.RESOLVE_NO_XDEV, + }) + _ = unix.Close(dirfd) + switch err { //nolint:errorlint // unix errors are bare + case nil: // definitely not a mount + _ = unix.Close(fd) + return false, nil + case unix.EXDEV: // definitely a mount + return true, nil + } + // not sure + return false, &os.PathError{Op: "openat2", Path: path, Err: err} +} + +// mountedFast is similar to MountedFast, except it expects a normalized path. +func mountedFast(path string) (mounted, sure bool, err error) { + // Root is always mounted. + if path == string(os.PathSeparator) { + return true, true, nil + } + + // Try a fast path, using openat2() with RESOLVE_NO_XDEV. + mounted, err = mountedByOpenat2(path) + if err == nil { + return mounted, true, nil + } + + // Another fast path: compare st.st_dev fields. + mounted, err = mountedByStat(path) + // This does not work for bind mounts, so false negative + // is possible, therefore only trust if return is true. + if mounted && err == nil { + return true, true, nil + } + + return +} + +func mounted(path string) (bool, error) { + path, err := normalizePath(path) + if err != nil { + return false, err + } + mounted, sure, err := mountedFast(path) + if sure && err == nil { + return mounted, nil + } + + // Fallback to parsing mountinfo. + return mountedByMountinfo(path) +} diff --git a/vendor/github.com/moby/sys/mountinfo/mounted_unix.go b/vendor/github.com/moby/sys/mountinfo/mounted_unix.go new file mode 100644 index 000000000..c7b7678f9 --- /dev/null +++ b/vendor/github.com/moby/sys/mountinfo/mounted_unix.go @@ -0,0 +1,53 @@ +//go:build linux || freebsd || openbsd || darwin +// +build linux freebsd openbsd darwin + +package mountinfo + +import ( + "os" + "path/filepath" + + "golang.org/x/sys/unix" +) + +func mountedByStat(path string) (bool, error) { + var st unix.Stat_t + + if err := unix.Lstat(path, &st); err != nil { + return false, &os.PathError{Op: "stat", Path: path, Err: err} + } + dev := st.Dev + parent := filepath.Dir(path) + if err := unix.Lstat(parent, &st); err != nil { + return false, &os.PathError{Op: "stat", Path: parent, Err: err} + } + if dev != st.Dev { + // Device differs from that of parent, + // so definitely a mount point. + return true, nil + } + // NB: this does not detect bind mounts on Linux. + return false, nil +} + +func normalizePath(path string) (realPath string, err error) { + if realPath, err = filepath.Abs(path); err != nil { + return "", err + } + if realPath, err = filepath.EvalSymlinks(realPath); err != nil { + return "", err + } + if _, err := os.Stat(realPath); err != nil { + return "", err + } + return realPath, nil +} + +func mountedByMountinfo(path string) (bool, error) { + entries, err := GetMounts(SingleEntryFilter(path)) + if err != nil { + return false, err + } + + return len(entries) > 0, nil +} diff --git a/vendor/github.com/moby/sys/mountinfo/mountinfo.go b/vendor/github.com/moby/sys/mountinfo/mountinfo.go new file mode 100644 index 000000000..574aeb876 --- /dev/null +++ b/vendor/github.com/moby/sys/mountinfo/mountinfo.go @@ -0,0 +1,67 @@ +package mountinfo + +import ( + "os" +) + +// GetMounts retrieves a list of mounts for the current running process, +// with an optional filter applied (use nil for no filter). +func GetMounts(f FilterFunc) ([]*Info, error) { + return parseMountTable(f) +} + +// Mounted determines if a specified path is a mount point. In case of any +// error, false (and an error) is returned. +// +// If a non-existent path is specified, an appropriate error is returned. +// In case the caller is not interested in this particular error, it should +// be handled separately using e.g. errors.Is(err, fs.ErrNotExist). +func Mounted(path string) (bool, error) { + // root is always mounted + if path == string(os.PathSeparator) { + return true, nil + } + return mounted(path) +} + +// Info reveals information about a particular mounted filesystem. This +// struct is populated from the content in the /proc//mountinfo file. +type Info struct { + // ID is a unique identifier of the mount (may be reused after umount). + ID int + + // Parent is the ID of the parent mount (or of self for the root + // of this mount namespace's mount tree). + Parent int + + // Major and Minor are the major and the minor components of the Dev + // field of unix.Stat_t structure returned by unix.*Stat calls for + // files on this filesystem. + Major, Minor int + + // Root is the pathname of the directory in the filesystem which forms + // the root of this mount. + Root string + + // Mountpoint is the pathname of the mount point relative to the + // process's root directory. + Mountpoint string + + // Options is a comma-separated list of mount options. + Options string + + // Optional are zero or more fields of the form "tag[:value]", + // separated by a space. Currently, the possible optional fields are + // "shared", "master", "propagate_from", and "unbindable". For more + // information, see mount_namespaces(7) Linux man page. + Optional string + + // FSType is the filesystem type in the form "type[.subtype]". + FSType string + + // Source is filesystem-specific information, or "none". + Source string + + // VFSOptions is a comma-separated list of superblock options. + VFSOptions string +} diff --git a/vendor/github.com/moby/sys/mountinfo/mountinfo_bsd.go b/vendor/github.com/moby/sys/mountinfo/mountinfo_bsd.go new file mode 100644 index 000000000..8420f58c7 --- /dev/null +++ b/vendor/github.com/moby/sys/mountinfo/mountinfo_bsd.go @@ -0,0 +1,56 @@ +//go:build freebsd || openbsd || darwin +// +build freebsd openbsd darwin + +package mountinfo + +import "golang.org/x/sys/unix" + +// parseMountTable returns information about mounted filesystems +func parseMountTable(filter FilterFunc) ([]*Info, error) { + count, err := unix.Getfsstat(nil, unix.MNT_WAIT) + if err != nil { + return nil, err + } + + entries := make([]unix.Statfs_t, count) + _, err = unix.Getfsstat(entries, unix.MNT_WAIT) + if err != nil { + return nil, err + } + + var out []*Info + for _, entry := range entries { + var skip, stop bool + mountinfo := getMountinfo(&entry) + + if filter != nil { + // filter out entries we're not interested in + skip, stop = filter(mountinfo) + if skip { + continue + } + } + + out = append(out, mountinfo) + if stop { + break + } + } + return out, nil +} + +func mounted(path string) (bool, error) { + path, err := normalizePath(path) + if err != nil { + return false, err + } + // Fast path: compare st.st_dev fields. + // This should always work for FreeBSD and OpenBSD. + mounted, err := mountedByStat(path) + if err == nil { + return mounted, nil + } + + // Fallback to parsing mountinfo + return mountedByMountinfo(path) +} diff --git a/vendor/github.com/moby/sys/mountinfo/mountinfo_filters.go b/vendor/github.com/moby/sys/mountinfo/mountinfo_filters.go new file mode 100644 index 000000000..16079c3c5 --- /dev/null +++ b/vendor/github.com/moby/sys/mountinfo/mountinfo_filters.go @@ -0,0 +1,63 @@ +package mountinfo + +import "strings" + +// FilterFunc is a type defining a callback function for GetMount(), +// used to filter out mountinfo entries we're not interested in, +// and/or stop further processing if we found what we wanted. +// +// It takes a pointer to the Info struct (fully populated with all available +// fields on the GOOS platform), and returns two booleans: +// +// skip: true if the entry should be skipped; +// +// stop: true if parsing should be stopped after the entry. +type FilterFunc func(*Info) (skip, stop bool) + +// PrefixFilter discards all entries whose mount points do not start with, or +// are equal to the path specified in prefix. The prefix path must be absolute, +// have all symlinks resolved, and cleaned (i.e. no extra slashes or dots). +// +// PrefixFilter treats prefix as a path, not a partial prefix, which means that +// given "/foo", "/foo/bar" and "/foobar" entries, PrefixFilter("/foo") returns +// "/foo" and "/foo/bar", and discards "/foobar". +func PrefixFilter(prefix string) FilterFunc { + return func(m *Info) (bool, bool) { + skip := !strings.HasPrefix(m.Mountpoint+"/", prefix+"/") + return skip, false + } +} + +// SingleEntryFilter looks for a specific entry. +func SingleEntryFilter(mp string) FilterFunc { + return func(m *Info) (bool, bool) { + if m.Mountpoint == mp { + return false, true // don't skip, stop now + } + return true, false // skip, keep going + } +} + +// ParentsFilter returns all entries whose mount points +// can be parents of a path specified, discarding others. +// +// For example, given /var/lib/docker/something, entries +// like /var/lib/docker, /var and / are returned. +func ParentsFilter(path string) FilterFunc { + return func(m *Info) (bool, bool) { + skip := !strings.HasPrefix(path, m.Mountpoint) + return skip, false + } +} + +// FSTypeFilter returns all entries that match provided fstype(s). +func FSTypeFilter(fstype ...string) FilterFunc { + return func(m *Info) (bool, bool) { + for _, t := range fstype { + if m.FSType == t { + return false, false // don't skip, keep going + } + } + return true, false // skip, keep going + } +} diff --git a/vendor/github.com/moby/sys/mountinfo/mountinfo_freebsdlike.go b/vendor/github.com/moby/sys/mountinfo/mountinfo_freebsdlike.go new file mode 100644 index 000000000..ecaaa7a9c --- /dev/null +++ b/vendor/github.com/moby/sys/mountinfo/mountinfo_freebsdlike.go @@ -0,0 +1,14 @@ +//go:build freebsd || darwin +// +build freebsd darwin + +package mountinfo + +import "golang.org/x/sys/unix" + +func getMountinfo(entry *unix.Statfs_t) *Info { + return &Info{ + Mountpoint: unix.ByteSliceToString(entry.Mntonname[:]), + FSType: unix.ByteSliceToString(entry.Fstypename[:]), + Source: unix.ByteSliceToString(entry.Mntfromname[:]), + } +} diff --git a/vendor/github.com/moby/sys/mountinfo/mountinfo_linux.go b/vendor/github.com/moby/sys/mountinfo/mountinfo_linux.go new file mode 100644 index 000000000..59332b07b --- /dev/null +++ b/vendor/github.com/moby/sys/mountinfo/mountinfo_linux.go @@ -0,0 +1,214 @@ +package mountinfo + +import ( + "bufio" + "fmt" + "io" + "os" + "strconv" + "strings" +) + +// GetMountsFromReader retrieves a list of mounts from the +// reader provided, with an optional filter applied (use nil +// for no filter). This can be useful in tests or benchmarks +// that provide fake mountinfo data, or when a source other +// than /proc/self/mountinfo needs to be read from. +// +// This function is Linux-specific. +func GetMountsFromReader(r io.Reader, filter FilterFunc) ([]*Info, error) { + s := bufio.NewScanner(r) + out := []*Info{} + for s.Scan() { + var err error + + /* + See http://man7.org/linux/man-pages/man5/proc.5.html + + 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue + (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) + + (1) mount ID: unique identifier of the mount (may be reused after umount) + (2) parent ID: ID of parent (or of self for the top of the mount tree) + (3) major:minor: value of st_dev for files on filesystem + (4) root: root of the mount within the filesystem + (5) mount point: mount point relative to the process's root + (6) mount options: per mount options + (7) optional fields: zero or more fields of the form "tag[:value]" + (8) separator: marks the end of the optional fields + (9) filesystem type: name of filesystem of the form "type[.subtype]" + (10) mount source: filesystem specific information or "none" + (11) super options: per super block options + + In other words, we have: + * 6 mandatory fields (1)..(6) + * 0 or more optional fields (7) + * a separator field (8) + * 3 mandatory fields (9)..(11) + */ + + text := s.Text() + fields := strings.Split(text, " ") + numFields := len(fields) + if numFields < 10 { + // should be at least 10 fields + return nil, fmt.Errorf("parsing '%s' failed: not enough fields (%d)", text, numFields) + } + + // separator field + sepIdx := numFields - 4 + // In Linux <= 3.9 mounting a cifs with spaces in a share + // name (like "//srv/My Docs") _may_ end up having a space + // in the last field of mountinfo (like "unc=//serv/My Docs"). + // Since kernel 3.10-rc1, cifs option "unc=" is ignored, + // so spaces should not appear. + // + // Check for a separator, and work around the spaces bug + for fields[sepIdx] != "-" { + sepIdx-- + if sepIdx == 5 { + return nil, fmt.Errorf("parsing '%s' failed: missing - separator", text) + } + } + + p := &Info{} + + p.Mountpoint, err = unescape(fields[4]) + if err != nil { + return nil, fmt.Errorf("parsing '%s' failed: mount point: %w", fields[4], err) + } + p.FSType, err = unescape(fields[sepIdx+1]) + if err != nil { + return nil, fmt.Errorf("parsing '%s' failed: fstype: %w", fields[sepIdx+1], err) + } + p.Source, err = unescape(fields[sepIdx+2]) + if err != nil { + return nil, fmt.Errorf("parsing '%s' failed: source: %w", fields[sepIdx+2], err) + } + p.VFSOptions = fields[sepIdx+3] + + // ignore any numbers parsing errors, as there should not be any + p.ID, _ = strconv.Atoi(fields[0]) + p.Parent, _ = strconv.Atoi(fields[1]) + mm := strings.SplitN(fields[2], ":", 3) + if len(mm) != 2 { + return nil, fmt.Errorf("parsing '%s' failed: unexpected major:minor pair %s", text, mm) + } + p.Major, _ = strconv.Atoi(mm[0]) + p.Minor, _ = strconv.Atoi(mm[1]) + + p.Root, err = unescape(fields[3]) + if err != nil { + return nil, fmt.Errorf("parsing '%s' failed: root: %w", fields[3], err) + } + + p.Options = fields[5] + + // zero or more optional fields + p.Optional = strings.Join(fields[6:sepIdx], " ") + + // Run the filter after parsing all fields. + var skip, stop bool + if filter != nil { + skip, stop = filter(p) + if skip { + continue + } + } + + out = append(out, p) + if stop { + break + } + } + if err := s.Err(); err != nil { + return nil, err + } + return out, nil +} + +func parseMountTable(filter FilterFunc) ([]*Info, error) { + f, err := os.Open("/proc/self/mountinfo") + if err != nil { + return nil, err + } + defer f.Close() + + return GetMountsFromReader(f, filter) +} + +// PidMountInfo retrieves the list of mounts from a given process' mount +// namespace. Unless there is a need to get mounts from a mount namespace +// different from that of a calling process, use GetMounts. +// +// This function is Linux-specific. +// +// Deprecated: this will be removed before v1; use GetMountsFromReader with +// opened /proc//mountinfo as an argument instead. +func PidMountInfo(pid int) ([]*Info, error) { + f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid)) + if err != nil { + return nil, err + } + defer f.Close() + + return GetMountsFromReader(f, nil) +} + +// A few specific characters in mountinfo path entries (root and mountpoint) +// are escaped using a backslash followed by a character's ascii code in octal. +// +// space -- as \040 +// tab (aka \t) -- as \011 +// newline (aka \n) -- as \012 +// backslash (aka \\) -- as \134 +// +// This function converts path from mountinfo back, i.e. it unescapes the above sequences. +func unescape(path string) (string, error) { + // try to avoid copying + if strings.IndexByte(path, '\\') == -1 { + return path, nil + } + + // The following code is UTF-8 transparent as it only looks for some + // specific characters (backslash and 0..7) with values < utf8.RuneSelf, + // and everything else is passed through as is. + buf := make([]byte, len(path)) + bufLen := 0 + for i := 0; i < len(path); i++ { + if path[i] != '\\' { + buf[bufLen] = path[i] + bufLen++ + continue + } + s := path[i:] + if len(s) < 4 { + // too short + return "", fmt.Errorf("bad escape sequence %q: too short", s) + } + c := s[1] + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7': + v := c - '0' + for j := 2; j < 4; j++ { // one digit already; two more + if s[j] < '0' || s[j] > '7' { + return "", fmt.Errorf("bad escape sequence %q: not a digit", s[:3]) + } + x := s[j] - '0' + v = (v << 3) | x + } + if v > 255 { + return "", fmt.Errorf("bad escape sequence %q: out of range" + s[:3]) + } + buf[bufLen] = v + bufLen++ + i += 3 + continue + default: + return "", fmt.Errorf("bad escape sequence %q: not a digit" + s[:3]) + + } + } + + return string(buf[:bufLen]), nil +} diff --git a/vendor/github.com/moby/sys/mountinfo/mountinfo_openbsd.go b/vendor/github.com/moby/sys/mountinfo/mountinfo_openbsd.go new file mode 100644 index 000000000..f682c2d3b --- /dev/null +++ b/vendor/github.com/moby/sys/mountinfo/mountinfo_openbsd.go @@ -0,0 +1,11 @@ +package mountinfo + +import "golang.org/x/sys/unix" + +func getMountinfo(entry *unix.Statfs_t) *Info { + return &Info{ + Mountpoint: unix.ByteSliceToString(entry.F_mntonname[:]), + FSType: unix.ByteSliceToString(entry.F_fstypename[:]), + Source: unix.ByteSliceToString(entry.F_mntfromname[:]), + } +} diff --git a/vendor/github.com/moby/sys/mountinfo/mountinfo_unsupported.go b/vendor/github.com/moby/sys/mountinfo/mountinfo_unsupported.go new file mode 100644 index 000000000..c2e64bc81 --- /dev/null +++ b/vendor/github.com/moby/sys/mountinfo/mountinfo_unsupported.go @@ -0,0 +1,19 @@ +//go:build !windows && !linux && !freebsd && !openbsd && !darwin +// +build !windows,!linux,!freebsd,!openbsd,!darwin + +package mountinfo + +import ( + "fmt" + "runtime" +) + +var errNotImplemented = fmt.Errorf("not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) + +func parseMountTable(_ FilterFunc) ([]*Info, error) { + return nil, errNotImplemented +} + +func mounted(path string) (bool, error) { + return false, errNotImplemented +} diff --git a/vendor/github.com/moby/sys/mountinfo/mountinfo_windows.go b/vendor/github.com/moby/sys/mountinfo/mountinfo_windows.go new file mode 100644 index 000000000..13fad165e --- /dev/null +++ b/vendor/github.com/moby/sys/mountinfo/mountinfo_windows.go @@ -0,0 +1,10 @@ +package mountinfo + +func parseMountTable(_ FilterFunc) ([]*Info, error) { + // Do NOT return an error! + return nil, nil +} + +func mounted(_ string) (bool, error) { + return false, nil +} diff --git a/vendor/github.com/opencontainers/go-digest/.mailmap b/vendor/github.com/opencontainers/go-digest/.mailmap new file mode 100644 index 000000000..eaf8b2f9e --- /dev/null +++ b/vendor/github.com/opencontainers/go-digest/.mailmap @@ -0,0 +1,4 @@ +Aaron Lehmann +Derek McGowan +Stephen J Day +Haibing Zhou diff --git a/vendor/github.com/opencontainers/go-digest/.pullapprove.yml b/vendor/github.com/opencontainers/go-digest/.pullapprove.yml new file mode 100644 index 000000000..b6165f83c --- /dev/null +++ b/vendor/github.com/opencontainers/go-digest/.pullapprove.yml @@ -0,0 +1,28 @@ +version: 2 + +requirements: + signed_off_by: + required: true + +always_pending: + title_regex: '^WIP' + explanation: 'Work in progress...' + +group_defaults: + required: 2 + approve_by_comment: + enabled: true + approve_regex: '^LGTM' + reject_regex: '^Rejected' + reset_on_push: + enabled: true + author_approval: + ignored: true + conditions: + branches: + - master + +groups: + go-digest: + teams: + - go-digest-maintainers diff --git a/vendor/github.com/opencontainers/go-digest/.travis.yml b/vendor/github.com/opencontainers/go-digest/.travis.yml new file mode 100644 index 000000000..5775f885c --- /dev/null +++ b/vendor/github.com/opencontainers/go-digest/.travis.yml @@ -0,0 +1,5 @@ +language: go +go: + - 1.12.x + - 1.13.x + - master diff --git a/vendor/github.com/opencontainers/go-digest/CONTRIBUTING.md b/vendor/github.com/opencontainers/go-digest/CONTRIBUTING.md new file mode 100644 index 000000000..e4d962ac1 --- /dev/null +++ b/vendor/github.com/opencontainers/go-digest/CONTRIBUTING.md @@ -0,0 +1,72 @@ +# Contributing to Docker open source projects + +Want to hack on this project? Awesome! Here are instructions to get you started. + +This project is a part of the [Docker](https://www.docker.com) project, and follows +the same rules and principles. If you're already familiar with the way +Docker does things, you'll feel right at home. + +Otherwise, go read Docker's +[contributions guidelines](https://github.com/docker/docker/blob/master/CONTRIBUTING.md), +[issue triaging](https://github.com/docker/docker/blob/master/project/ISSUE-TRIAGE.md), +[review process](https://github.com/docker/docker/blob/master/project/REVIEWING.md) and +[branches and tags](https://github.com/docker/docker/blob/master/project/BRANCHES-AND-TAGS.md). + +For an in-depth description of our contribution process, visit the +contributors guide: [Understand how to contribute](https://docs.docker.com/opensource/workflow/make-a-contribution/) + +### Sign your work + +The sign-off is a simple line at the end of the explanation for the patch. Your +signature certifies that you wrote the patch or otherwise have the right to pass +it on as an open-source patch. The rules are pretty simple: if you can certify +the below (from [developercertificate.org](http://developercertificate.org/)): + +``` +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +1 Letterman Drive +Suite D4700 +San Francisco, CA, 94129 + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. +``` + +Then you just add a line to every git commit message: + + Signed-off-by: Joe Smith + +Use your real name (sorry, no pseudonyms or anonymous contributions.) + +If you set your `user.name` and `user.email` git configs, you can sign your +commit automatically with `git commit -s`. diff --git a/vendor/github.com/opencontainers/go-digest/LICENSE b/vendor/github.com/opencontainers/go-digest/LICENSE new file mode 100644 index 000000000..3ac8ab648 --- /dev/null +++ b/vendor/github.com/opencontainers/go-digest/LICENSE @@ -0,0 +1,192 @@ + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2019, 2020 OCI Contributors + Copyright 2016 Docker, Inc. + + 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 + + https://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. diff --git a/vendor/github.com/opencontainers/go-digest/LICENSE.docs b/vendor/github.com/opencontainers/go-digest/LICENSE.docs new file mode 100644 index 000000000..e26cd4fc8 --- /dev/null +++ b/vendor/github.com/opencontainers/go-digest/LICENSE.docs @@ -0,0 +1,425 @@ +Attribution-ShareAlike 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More_considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution-ShareAlike 4.0 International Public +License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution-ShareAlike 4.0 International Public License ("Public +License"). To the extent this Public License may be interpreted as a +contract, You are granted the Licensed Rights in consideration of Your +acceptance of these terms and conditions, and the Licensor grants You +such rights in consideration of benefits the Licensor receives from +making the Licensed Material available under these terms and +conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. BY-SA Compatible License means a license listed at + creativecommons.org/compatiblelicenses, approved by Creative + Commons as essentially the equivalent of this Public License. + + d. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + e. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + f. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + g. License Elements means the license attributes listed in the name + of a Creative Commons Public License. The License Elements of this + Public License are Attribution and ShareAlike. + + h. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + i. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + j. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + k. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + l. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + m. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. Additional offer from the Licensor -- Adapted Material. + Every recipient of Adapted Material from You + automatically receives an offer from the Licensor to + exercise the Licensed Rights in the Adapted Material + under the conditions of the Adapter's License You apply. + + c. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + b. ShareAlike. + + In addition to the conditions in Section 3(a), if You Share + Adapted Material You produce, the following conditions also apply. + + 1. The Adapter's License You apply must be a Creative Commons + license with the same License Elements, this version or + later, or a BY-SA Compatible License. + + 2. You must include the text of, or the URI or hyperlink to, the + Adapter's License You apply. You may satisfy this condition + in any reasonable manner based on the medium, means, and + context in which You Share Adapted Material. + + 3. You may not offer or impose any additional or different terms + or conditions on, or apply any Effective Technological + Measures to, Adapted Material that restrict exercise of the + rights granted under the Adapter's License You apply. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material, + + including for purposes of Section 3(b); and + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public licenses. +Notwithstanding, Creative Commons may elect to apply one of its public +licenses to material it publishes and in those instances will be +considered the "Licensor." Except for the limited purpose of indicating +that material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the public +licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/vendor/github.com/opencontainers/go-digest/MAINTAINERS b/vendor/github.com/opencontainers/go-digest/MAINTAINERS new file mode 100644 index 000000000..843b1b206 --- /dev/null +++ b/vendor/github.com/opencontainers/go-digest/MAINTAINERS @@ -0,0 +1,5 @@ +Derek McGowan (@dmcgowan) +Stephen Day (@stevvooe) +Vincent Batts (@vbatts) +Akihiro Suda (@AkihiroSuda) +Sebastiaan van Stijn (@thaJeztah) diff --git a/vendor/github.com/opencontainers/go-digest/README.md b/vendor/github.com/opencontainers/go-digest/README.md new file mode 100644 index 000000000..a11287207 --- /dev/null +++ b/vendor/github.com/opencontainers/go-digest/README.md @@ -0,0 +1,96 @@ +# go-digest + +[![GoDoc](https://godoc.org/github.com/opencontainers/go-digest?status.svg)](https://godoc.org/github.com/opencontainers/go-digest) [![Go Report Card](https://goreportcard.com/badge/github.com/opencontainers/go-digest)](https://goreportcard.com/report/github.com/opencontainers/go-digest) [![Build Status](https://travis-ci.org/opencontainers/go-digest.svg?branch=master)](https://travis-ci.org/opencontainers/go-digest) + +Common digest package used across the container ecosystem. + +Please see the [godoc](https://godoc.org/github.com/opencontainers/go-digest) for more information. + +# What is a digest? + +A digest is just a [hash](https://en.wikipedia.org/wiki/Hash_function). + +The most common use case for a digest is to create a content identifier for use in [Content Addressable Storage](https://en.wikipedia.org/wiki/Content-addressable_storage) systems: + +```go +id := digest.FromBytes([]byte("my content")) +``` + +In the example above, the id can be used to uniquely identify the byte slice "my content". +This allows two disparate applications to agree on a verifiable identifier without having to trust one another. + +An identifying digest can be verified, as follows: + +```go +if id != digest.FromBytes([]byte("my content")) { + return errors.New("the content has changed!") +} +``` + +A `Verifier` type can be used to handle cases where an `io.Reader` makes more sense: + +```go +rd := getContent() +verifier := id.Verifier() +io.Copy(verifier, rd) + +if !verifier.Verified() { + return errors.New("the content has changed!") +} +``` + +Using [Merkle DAGs](https://en.wikipedia.org/wiki/Merkle_tree), this can power a rich, safe, content distribution system. + +# Usage + +While the [godoc](https://godoc.org/github.com/opencontainers/go-digest) is considered the best resource, a few important items need to be called out when using this package. + +1. Make sure to import the hash implementations into your application or the package will panic. + You should have something like the following in the main (or other entrypoint) of your application: + + ```go + import ( + _ "crypto/sha256" + _ "crypto/sha512" + ) + ``` + This may seem inconvenient but it allows you replace the hash + implementations with others, such as https://github.com/stevvooe/resumable. + +2. Even though `digest.Digest` may be assemblable as a string, _always_ verify your input with `digest.Parse` or use `Digest.Validate` when accepting untrusted input. + While there are measures to avoid common problems, this will ensure you have valid digests in the rest of your application. + +3. While alternative encodings of hash values (digests) are possible (for example, base64), this package deals exclusively with hex-encoded digests. + +# Stability + +The Go API, at this stage, is considered stable, unless otherwise noted. + +As always, before using a package export, read the [godoc](https://godoc.org/github.com/opencontainers/go-digest). + +# Contributing + +This package is considered fairly complete. +It has been in production in thousands (millions?) of deployments and is fairly battle-hardened. +New additions will be met with skepticism. +If you think there is a missing feature, please file a bug clearly describing the problem and the alternatives you tried before submitting a PR. + +## Code of Conduct + +Participation in the OpenContainers community is governed by [OpenContainer's Code of Conduct][code-of-conduct]. + +## Security + +If you find an issue, please follow the [security][security] protocol to report it. + +# Copyright and license + +Copyright © 2019, 2020 OCI Contributors +Copyright © 2016 Docker, Inc. +All rights reserved, except as follows. +Code is released under the [Apache 2.0 license](LICENSE). +This `README.md` file and the [`CONTRIBUTING.md`](CONTRIBUTING.md) file are licensed under the Creative Commons Attribution 4.0 International License under the terms and conditions set forth in the file [`LICENSE.docs`](LICENSE.docs). +You may obtain a duplicate copy of the same license, titled CC BY-SA 4.0, at http://creativecommons.org/licenses/by-sa/4.0/. + +[security]: https://github.com/opencontainers/org/blob/master/security +[code-of-conduct]: https://github.com/opencontainers/org/blob/master/CODE_OF_CONDUCT.md diff --git a/vendor/github.com/opencontainers/go-digest/algorithm.go b/vendor/github.com/opencontainers/go-digest/algorithm.go new file mode 100644 index 000000000..490951dc3 --- /dev/null +++ b/vendor/github.com/opencontainers/go-digest/algorithm.go @@ -0,0 +1,193 @@ +// Copyright 2019, 2020 OCI Contributors +// Copyright 2017 Docker, Inc. +// +// 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 +// +// https://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 digest + +import ( + "crypto" + "fmt" + "hash" + "io" + "regexp" +) + +// Algorithm identifies and implementation of a digester by an identifier. +// Note the that this defines both the hash algorithm used and the string +// encoding. +type Algorithm string + +// supported digest types +const ( + SHA256 Algorithm = "sha256" // sha256 with hex encoding (lower case only) + SHA384 Algorithm = "sha384" // sha384 with hex encoding (lower case only) + SHA512 Algorithm = "sha512" // sha512 with hex encoding (lower case only) + + // Canonical is the primary digest algorithm used with the distribution + // project. Other digests may be used but this one is the primary storage + // digest. + Canonical = SHA256 +) + +var ( + // TODO(stevvooe): Follow the pattern of the standard crypto package for + // registration of digests. Effectively, we are a registerable set and + // common symbol access. + + // algorithms maps values to hash.Hash implementations. Other algorithms + // may be available but they cannot be calculated by the digest package. + algorithms = map[Algorithm]crypto.Hash{ + SHA256: crypto.SHA256, + SHA384: crypto.SHA384, + SHA512: crypto.SHA512, + } + + // anchoredEncodedRegexps contains anchored regular expressions for hex-encoded digests. + // Note that /A-F/ disallowed. + anchoredEncodedRegexps = map[Algorithm]*regexp.Regexp{ + SHA256: regexp.MustCompile(`^[a-f0-9]{64}$`), + SHA384: regexp.MustCompile(`^[a-f0-9]{96}$`), + SHA512: regexp.MustCompile(`^[a-f0-9]{128}$`), + } +) + +// Available returns true if the digest type is available for use. If this +// returns false, Digester and Hash will return nil. +func (a Algorithm) Available() bool { + h, ok := algorithms[a] + if !ok { + return false + } + + // check availability of the hash, as well + return h.Available() +} + +func (a Algorithm) String() string { + return string(a) +} + +// Size returns number of bytes returned by the hash. +func (a Algorithm) Size() int { + h, ok := algorithms[a] + if !ok { + return 0 + } + return h.Size() +} + +// Set implemented to allow use of Algorithm as a command line flag. +func (a *Algorithm) Set(value string) error { + if value == "" { + *a = Canonical + } else { + // just do a type conversion, support is queried with Available. + *a = Algorithm(value) + } + + if !a.Available() { + return ErrDigestUnsupported + } + + return nil +} + +// Digester returns a new digester for the specified algorithm. If the algorithm +// does not have a digester implementation, nil will be returned. This can be +// checked by calling Available before calling Digester. +func (a Algorithm) Digester() Digester { + return &digester{ + alg: a, + hash: a.Hash(), + } +} + +// Hash returns a new hash as used by the algorithm. If not available, the +// method will panic. Check Algorithm.Available() before calling. +func (a Algorithm) Hash() hash.Hash { + if !a.Available() { + // Empty algorithm string is invalid + if a == "" { + panic(fmt.Sprintf("empty digest algorithm, validate before calling Algorithm.Hash()")) + } + + // NOTE(stevvooe): A missing hash is usually a programming error that + // must be resolved at compile time. We don't import in the digest + // package to allow users to choose their hash implementation (such as + // when using stevvooe/resumable or a hardware accelerated package). + // + // Applications that may want to resolve the hash at runtime should + // call Algorithm.Available before call Algorithm.Hash(). + panic(fmt.Sprintf("%v not available (make sure it is imported)", a)) + } + + return algorithms[a].New() +} + +// Encode encodes the raw bytes of a digest, typically from a hash.Hash, into +// the encoded portion of the digest. +func (a Algorithm) Encode(d []byte) string { + // TODO(stevvooe): Currently, all algorithms use a hex encoding. When we + // add support for back registration, we can modify this accordingly. + return fmt.Sprintf("%x", d) +} + +// FromReader returns the digest of the reader using the algorithm. +func (a Algorithm) FromReader(rd io.Reader) (Digest, error) { + digester := a.Digester() + + if _, err := io.Copy(digester.Hash(), rd); err != nil { + return "", err + } + + return digester.Digest(), nil +} + +// FromBytes digests the input and returns a Digest. +func (a Algorithm) FromBytes(p []byte) Digest { + digester := a.Digester() + + if _, err := digester.Hash().Write(p); err != nil { + // Writes to a Hash should never fail. None of the existing + // hash implementations in the stdlib or hashes vendored + // here can return errors from Write. Having a panic in this + // condition instead of having FromBytes return an error value + // avoids unnecessary error handling paths in all callers. + panic("write to hash function returned error: " + err.Error()) + } + + return digester.Digest() +} + +// FromString digests the string input and returns a Digest. +func (a Algorithm) FromString(s string) Digest { + return a.FromBytes([]byte(s)) +} + +// Validate validates the encoded portion string +func (a Algorithm) Validate(encoded string) error { + r, ok := anchoredEncodedRegexps[a] + if !ok { + return ErrDigestUnsupported + } + // Digests much always be hex-encoded, ensuring that their hex portion will + // always be size*2 + if a.Size()*2 != len(encoded) { + return ErrDigestInvalidLength + } + if r.MatchString(encoded) { + return nil + } + return ErrDigestInvalidFormat +} diff --git a/vendor/github.com/opencontainers/go-digest/digest.go b/vendor/github.com/opencontainers/go-digest/digest.go new file mode 100644 index 000000000..518b5e715 --- /dev/null +++ b/vendor/github.com/opencontainers/go-digest/digest.go @@ -0,0 +1,157 @@ +// Copyright 2019, 2020 OCI Contributors +// Copyright 2017 Docker, Inc. +// +// 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 +// +// https://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 digest + +import ( + "fmt" + "hash" + "io" + "regexp" + "strings" +) + +// Digest allows simple protection of hex formatted digest strings, prefixed +// by their algorithm. Strings of type Digest have some guarantee of being in +// the correct format and it provides quick access to the components of a +// digest string. +// +// The following is an example of the contents of Digest types: +// +// sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc +// +// This allows to abstract the digest behind this type and work only in those +// terms. +type Digest string + +// NewDigest returns a Digest from alg and a hash.Hash object. +func NewDigest(alg Algorithm, h hash.Hash) Digest { + return NewDigestFromBytes(alg, h.Sum(nil)) +} + +// NewDigestFromBytes returns a new digest from the byte contents of p. +// Typically, this can come from hash.Hash.Sum(...) or xxx.SumXXX(...) +// functions. This is also useful for rebuilding digests from binary +// serializations. +func NewDigestFromBytes(alg Algorithm, p []byte) Digest { + return NewDigestFromEncoded(alg, alg.Encode(p)) +} + +// NewDigestFromHex is deprecated. Please use NewDigestFromEncoded. +func NewDigestFromHex(alg, hex string) Digest { + return NewDigestFromEncoded(Algorithm(alg), hex) +} + +// NewDigestFromEncoded returns a Digest from alg and the encoded digest. +func NewDigestFromEncoded(alg Algorithm, encoded string) Digest { + return Digest(fmt.Sprintf("%s:%s", alg, encoded)) +} + +// DigestRegexp matches valid digest types. +var DigestRegexp = regexp.MustCompile(`[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+`) + +// DigestRegexpAnchored matches valid digest types, anchored to the start and end of the match. +var DigestRegexpAnchored = regexp.MustCompile(`^` + DigestRegexp.String() + `$`) + +var ( + // ErrDigestInvalidFormat returned when digest format invalid. + ErrDigestInvalidFormat = fmt.Errorf("invalid checksum digest format") + + // ErrDigestInvalidLength returned when digest has invalid length. + ErrDigestInvalidLength = fmt.Errorf("invalid checksum digest length") + + // ErrDigestUnsupported returned when the digest algorithm is unsupported. + ErrDigestUnsupported = fmt.Errorf("unsupported digest algorithm") +) + +// Parse parses s and returns the validated digest object. An error will +// be returned if the format is invalid. +func Parse(s string) (Digest, error) { + d := Digest(s) + return d, d.Validate() +} + +// FromReader consumes the content of rd until io.EOF, returning canonical digest. +func FromReader(rd io.Reader) (Digest, error) { + return Canonical.FromReader(rd) +} + +// FromBytes digests the input and returns a Digest. +func FromBytes(p []byte) Digest { + return Canonical.FromBytes(p) +} + +// FromString digests the input and returns a Digest. +func FromString(s string) Digest { + return Canonical.FromString(s) +} + +// Validate checks that the contents of d is a valid digest, returning an +// error if not. +func (d Digest) Validate() error { + s := string(d) + i := strings.Index(s, ":") + if i <= 0 || i+1 == len(s) { + return ErrDigestInvalidFormat + } + algorithm, encoded := Algorithm(s[:i]), s[i+1:] + if !algorithm.Available() { + if !DigestRegexpAnchored.MatchString(s) { + return ErrDigestInvalidFormat + } + return ErrDigestUnsupported + } + return algorithm.Validate(encoded) +} + +// Algorithm returns the algorithm portion of the digest. This will panic if +// the underlying digest is not in a valid format. +func (d Digest) Algorithm() Algorithm { + return Algorithm(d[:d.sepIndex()]) +} + +// Verifier returns a writer object that can be used to verify a stream of +// content against the digest. If the digest is invalid, the method will panic. +func (d Digest) Verifier() Verifier { + return hashVerifier{ + hash: d.Algorithm().Hash(), + digest: d, + } +} + +// Encoded returns the encoded portion of the digest. This will panic if the +// underlying digest is not in a valid format. +func (d Digest) Encoded() string { + return string(d[d.sepIndex()+1:]) +} + +// Hex is deprecated. Please use Digest.Encoded. +func (d Digest) Hex() string { + return d.Encoded() +} + +func (d Digest) String() string { + return string(d) +} + +func (d Digest) sepIndex() int { + i := strings.Index(string(d), ":") + + if i < 0 { + panic(fmt.Sprintf("no ':' separator in digest %q", d)) + } + + return i +} diff --git a/vendor/github.com/opencontainers/go-digest/digester.go b/vendor/github.com/opencontainers/go-digest/digester.go new file mode 100644 index 000000000..ede907757 --- /dev/null +++ b/vendor/github.com/opencontainers/go-digest/digester.go @@ -0,0 +1,40 @@ +// Copyright 2019, 2020 OCI Contributors +// Copyright 2017 Docker, Inc. +// +// 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 +// +// https://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 digest + +import "hash" + +// Digester calculates the digest of written data. Writes should go directly +// to the return value of Hash, while calling Digest will return the current +// value of the digest. +type Digester interface { + Hash() hash.Hash // provides direct access to underlying hash instance. + Digest() Digest +} + +// digester provides a simple digester definition that embeds a hasher. +type digester struct { + alg Algorithm + hash hash.Hash +} + +func (d *digester) Hash() hash.Hash { + return d.hash +} + +func (d *digester) Digest() Digest { + return NewDigest(d.alg, d.hash) +} diff --git a/vendor/github.com/opencontainers/go-digest/doc.go b/vendor/github.com/opencontainers/go-digest/doc.go new file mode 100644 index 000000000..83d3a936c --- /dev/null +++ b/vendor/github.com/opencontainers/go-digest/doc.go @@ -0,0 +1,62 @@ +// Copyright 2019, 2020 OCI Contributors +// Copyright 2017 Docker, Inc. +// +// 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 +// +// https://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 digest provides a generalized type to opaquely represent message +// digests and their operations within the registry. The Digest type is +// designed to serve as a flexible identifier in a content-addressable system. +// More importantly, it provides tools and wrappers to work with +// hash.Hash-based digests with little effort. +// +// Basics +// +// The format of a digest is simply a string with two parts, dubbed the +// "algorithm" and the "digest", separated by a colon: +// +// : +// +// An example of a sha256 digest representation follows: +// +// sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc +// +// The "algorithm" portion defines both the hashing algorithm used to calculate +// the digest and the encoding of the resulting digest, which defaults to "hex" +// if not otherwise specified. Currently, all supported algorithms have their +// digests encoded in hex strings. +// +// In the example above, the string "sha256" is the algorithm and the hex bytes +// are the "digest". +// +// Because the Digest type is simply a string, once a valid Digest is +// obtained, comparisons are cheap, quick and simple to express with the +// standard equality operator. +// +// Verification +// +// The main benefit of using the Digest type is simple verification against a +// given digest. The Verifier interface, modeled after the stdlib hash.Hash +// interface, provides a common write sink for digest verification. After +// writing is complete, calling the Verifier.Verified method will indicate +// whether or not the stream of bytes matches the target digest. +// +// Missing Features +// +// In addition to the above, we intend to add the following features to this +// package: +// +// 1. A Digester type that supports write sink digest calculation. +// +// 2. Suspend and resume of ongoing digest calculations to support efficient digest verification in the registry. +// +package digest diff --git a/vendor/github.com/opencontainers/go-digest/verifiers.go b/vendor/github.com/opencontainers/go-digest/verifiers.go new file mode 100644 index 000000000..afef506f4 --- /dev/null +++ b/vendor/github.com/opencontainers/go-digest/verifiers.go @@ -0,0 +1,46 @@ +// Copyright 2019, 2020 OCI Contributors +// Copyright 2017 Docker, Inc. +// +// 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 +// +// https://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 digest + +import ( + "hash" + "io" +) + +// Verifier presents a general verification interface to be used with message +// digests and other byte stream verifications. Users instantiate a Verifier +// from one of the various methods, write the data under test to it then check +// the result with the Verified method. +type Verifier interface { + io.Writer + + // Verified will return true if the content written to Verifier matches + // the digest. + Verified() bool +} + +type hashVerifier struct { + digest Digest + hash hash.Hash +} + +func (hv hashVerifier) Write(p []byte) (n int, err error) { + return hv.hash.Write(p) +} + +func (hv hashVerifier) Verified() bool { + return hv.digest == NewDigest(hv.digest.Algorithm(), hv.hash) +} diff --git a/vendor/github.com/opencontainers/selinux/LICENSE b/vendor/github.com/opencontainers/selinux/LICENSE new file mode 100644 index 000000000..8dada3eda --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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. diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/doc.go b/vendor/github.com/opencontainers/selinux/go-selinux/doc.go new file mode 100644 index 000000000..0ac7d819e --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/go-selinux/doc.go @@ -0,0 +1,14 @@ +/* +Package selinux provides a high-level interface for interacting with selinux. + +Usage: + + import "github.com/opencontainers/selinux/go-selinux" + + // Ensure that selinux is enforcing mode. + if selinux.EnforceMode() != selinux.Enforcing { + selinux.SetEnforceMode(selinux.Enforcing) + } + +*/ +package selinux diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go new file mode 100644 index 000000000..fea096c18 --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go @@ -0,0 +1,97 @@ +package label + +import ( + "fmt" + + "github.com/opencontainers/selinux/go-selinux" +) + +// Deprecated: use selinux.ROFileLabel +var ROMountLabel = selinux.ROFileLabel + +// SetProcessLabel takes a process label and tells the kernel to assign the +// label to the next program executed by the current process. +// Deprecated: use selinux.SetExecLabel +var SetProcessLabel = selinux.SetExecLabel + +// ProcessLabel returns the process label that the kernel will assign +// to the next program executed by the current process. If "" is returned +// this indicates that the default labeling will happen for the process. +// Deprecated: use selinux.ExecLabel +var ProcessLabel = selinux.ExecLabel + +// SetSocketLabel takes a process label and tells the kernel to assign the +// label to the next socket that gets created +// Deprecated: use selinux.SetSocketLabel +var SetSocketLabel = selinux.SetSocketLabel + +// SocketLabel retrieves the current default socket label setting +// Deprecated: use selinux.SocketLabel +var SocketLabel = selinux.SocketLabel + +// SetKeyLabel takes a process label and tells the kernel to assign the +// label to the next kernel keyring that gets created +// Deprecated: use selinux.SetKeyLabel +var SetKeyLabel = selinux.SetKeyLabel + +// KeyLabel retrieves the current default kernel keyring label setting +// Deprecated: use selinux.KeyLabel +var KeyLabel = selinux.KeyLabel + +// FileLabel returns the label for specified path +// Deprecated: use selinux.FileLabel +var FileLabel = selinux.FileLabel + +// PidLabel will return the label of the process running with the specified pid +// Deprecated: use selinux.PidLabel +var PidLabel = selinux.PidLabel + +// Init initialises the labeling system +func Init() { + _ = selinux.GetEnabled() +} + +// ClearLabels will clear all reserved labels +// Deprecated: use selinux.ClearLabels +var ClearLabels = selinux.ClearLabels + +// ReserveLabel will record the fact that the MCS label has already been used. +// This will prevent InitLabels from using the MCS label in a newly created +// container +// Deprecated: use selinux.ReserveLabel +func ReserveLabel(label string) error { + selinux.ReserveLabel(label) + return nil +} + +// ReleaseLabel will remove the reservation of the MCS label. +// This will allow InitLabels to use the MCS label in a newly created +// containers +// Deprecated: use selinux.ReleaseLabel +func ReleaseLabel(label string) error { + selinux.ReleaseLabel(label) + return nil +} + +// DupSecOpt takes a process label and returns security options that +// can be used to set duplicate labels on future container processes +// Deprecated: use selinux.DupSecOpt +var DupSecOpt = selinux.DupSecOpt + +// FormatMountLabel returns a string to be used by the mount command. +// The format of this string will be used to alter the labeling of the mountpoint. +// The string returned is suitable to be used as the options field of the mount command. +// If you need to have additional mount point options, you can pass them in as +// the first parameter. Second parameter is the label that you wish to apply +// to all content in the mount point. +func FormatMountLabel(src, mountLabel string) string { + if mountLabel != "" { + switch src { + case "": + src = fmt.Sprintf("context=%q", mountLabel) + default: + src = fmt.Sprintf("%s,context=%q", src, mountLabel) + } + } + return src +} diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_linux.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_linux.go new file mode 100644 index 000000000..12de0ae5d --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_linux.go @@ -0,0 +1,196 @@ +package label + +import ( + "errors" + "fmt" + "os" + "os/user" + "strings" + + "github.com/opencontainers/selinux/go-selinux" +) + +// Valid Label Options +var validOptions = map[string]bool{ + "disable": true, + "type": true, + "filetype": true, + "user": true, + "role": true, + "level": true, +} + +var ErrIncompatibleLabel = errors.New("Bad SELinux option z and Z can not be used together") + +// InitLabels returns the process label and file labels to be used within +// the container. A list of options can be passed into this function to alter +// the labels. The labels returned will include a random MCS String, that is +// guaranteed to be unique. +// If the disabled flag is passed in, the process label will not be set, but the mount label will be set +// to the container_file label with the maximum category. This label is not usable by any confined label. +func InitLabels(options []string) (plabel string, mlabel string, retErr error) { + if !selinux.GetEnabled() { + return "", "", nil + } + processLabel, mountLabel := selinux.ContainerLabels() + if processLabel != "" { + defer func() { + if retErr != nil { + selinux.ReleaseLabel(mountLabel) + } + }() + pcon, err := selinux.NewContext(processLabel) + if err != nil { + return "", "", err + } + mcsLevel := pcon["level"] + mcon, err := selinux.NewContext(mountLabel) + if err != nil { + return "", "", err + } + for _, opt := range options { + if opt == "disable" { + selinux.ReleaseLabel(mountLabel) + return "", selinux.PrivContainerMountLabel(), nil + } + if i := strings.Index(opt, ":"); i == -1 { + return "", "", fmt.Errorf("Bad label option %q, valid options 'disable' or \n'user, role, level, type, filetype' followed by ':' and a value", opt) + } + con := strings.SplitN(opt, ":", 2) + if !validOptions[con[0]] { + return "", "", fmt.Errorf("Bad label option %q, valid options 'disable, user, role, level, type, filetype'", con[0]) + } + if con[0] == "filetype" { + mcon["type"] = con[1] + continue + } + pcon[con[0]] = con[1] + if con[0] == "level" || con[0] == "user" { + mcon[con[0]] = con[1] + } + } + if pcon.Get() != processLabel { + if pcon["level"] != mcsLevel { + selinux.ReleaseLabel(processLabel) + } + processLabel = pcon.Get() + selinux.ReserveLabel(processLabel) + } + mountLabel = mcon.Get() + } + return processLabel, mountLabel, nil +} + +// Deprecated: The GenLabels function is only to be used during the transition +// to the official API. Use InitLabels(strings.Fields(options)) instead. +func GenLabels(options string) (string, string, error) { + return InitLabels(strings.Fields(options)) +} + +// SetFileLabel modifies the "path" label to the specified file label +func SetFileLabel(path string, fileLabel string) error { + if !selinux.GetEnabled() || fileLabel == "" { + return nil + } + return selinux.SetFileLabel(path, fileLabel) +} + +// SetFileCreateLabel tells the kernel the label for all files to be created +func SetFileCreateLabel(fileLabel string) error { + if !selinux.GetEnabled() { + return nil + } + return selinux.SetFSCreateLabel(fileLabel) +} + +// Relabel changes the label of path and all the entries beneath the path. +// It changes the MCS label to s0 if shared is true. +// This will allow all containers to share the content. +// +// The path itself is guaranteed to be relabeled last. +func Relabel(path string, fileLabel string, shared bool) error { + if !selinux.GetEnabled() || fileLabel == "" { + return nil + } + + exclude_paths := map[string]bool{ + "/": true, + "/bin": true, + "/boot": true, + "/dev": true, + "/etc": true, + "/etc/passwd": true, + "/etc/pki": true, + "/etc/shadow": true, + "/home": true, + "/lib": true, + "/lib64": true, + "/media": true, + "/opt": true, + "/proc": true, + "/root": true, + "/run": true, + "/sbin": true, + "/srv": true, + "/sys": true, + "/tmp": true, + "/usr": true, + "/var": true, + "/var/lib": true, + "/var/log": true, + } + + if home := os.Getenv("HOME"); home != "" { + exclude_paths[home] = true + } + + if sudoUser := os.Getenv("SUDO_USER"); sudoUser != "" { + if usr, err := user.Lookup(sudoUser); err == nil { + exclude_paths[usr.HomeDir] = true + } + } + + if path != "/" { + path = strings.TrimSuffix(path, "/") + } + if exclude_paths[path] { + return fmt.Errorf("SELinux relabeling of %s is not allowed", path) + } + + if shared { + c, err := selinux.NewContext(fileLabel) + if err != nil { + return err + } + + c["level"] = "s0" + fileLabel = c.Get() + } + if err := selinux.Chcon(path, fileLabel, true); err != nil { + return err + } + return nil +} + +// DisableSecOpt returns a security opt that can disable labeling +// support for future container processes +// Deprecated: use selinux.DisableSecOpt +var DisableSecOpt = selinux.DisableSecOpt + +// Validate checks that the label does not include unexpected options +func Validate(label string) error { + if strings.Contains(label, "z") && strings.Contains(label, "Z") { + return ErrIncompatibleLabel + } + return nil +} + +// RelabelNeeded checks whether the user requested a relabel +func RelabelNeeded(label string) bool { + return strings.Contains(label, "z") || strings.Contains(label, "Z") +} + +// IsShared checks that the label includes a "shared" mark +func IsShared(label string) bool { + return strings.Contains(label, "z") +} diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go new file mode 100644 index 000000000..02d206239 --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go @@ -0,0 +1,49 @@ +// +build !linux + +package label + +// InitLabels returns the process label and file labels to be used within +// the container. A list of options can be passed into this function to alter +// the labels. +func InitLabels(options []string) (string, string, error) { + return "", "", nil +} + +// Deprecated: The GenLabels function is only to be used during the transition +// to the official API. Use InitLabels(strings.Fields(options)) instead. +func GenLabels(options string) (string, string, error) { + return "", "", nil +} + +func SetFileLabel(path string, fileLabel string) error { + return nil +} + +func SetFileCreateLabel(fileLabel string) error { + return nil +} + +func Relabel(path string, fileLabel string, shared bool) error { + return nil +} + +// DisableSecOpt returns a security opt that can disable labeling +// support for future container processes +func DisableSecOpt() []string { + return nil +} + +// Validate checks that the label does not include unexpected options +func Validate(label string) error { + return nil +} + +// RelabelNeeded checks whether the user requested a relabel +func RelabelNeeded(label string) bool { + return false +} + +// IsShared checks that the label includes a "shared" mark +func IsShared(label string) bool { + return false +} diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/rchcon.go b/vendor/github.com/opencontainers/selinux/go-selinux/rchcon.go new file mode 100644 index 000000000..897ecbac4 --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/go-selinux/rchcon.go @@ -0,0 +1,22 @@ +// +build linux,go1.16 + +package selinux + +import ( + "errors" + "io/fs" + "os" + + "github.com/opencontainers/selinux/pkg/pwalkdir" +) + +func rchcon(fpath, label string) error { + return pwalkdir.Walk(fpath, func(p string, _ fs.DirEntry, _ error) error { + e := setFileLabel(p, label) + // Walk a file tree can race with removal, so ignore ENOENT. + if errors.Is(e, os.ErrNotExist) { + return nil + } + return e + }) +} diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/rchcon_go115.go b/vendor/github.com/opencontainers/selinux/go-selinux/rchcon_go115.go new file mode 100644 index 000000000..2c8b033ce --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/go-selinux/rchcon_go115.go @@ -0,0 +1,21 @@ +// +build linux,!go1.16 + +package selinux + +import ( + "errors" + "os" + + "github.com/opencontainers/selinux/pkg/pwalk" +) + +func rchcon(fpath, label string) error { + return pwalk.Walk(fpath, func(p string, _ os.FileInfo, _ error) error { + e := setFileLabel(p, label) + // Walk a file tree can race with removal, so ignore ENOENT. + if errors.Is(e, os.ErrNotExist) { + return nil + } + return e + }) +} diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go new file mode 100644 index 000000000..5a59d151f --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go @@ -0,0 +1,304 @@ +package selinux + +import ( + "errors" +) + +const ( + // Enforcing constant indicate SELinux is in enforcing mode + Enforcing = 1 + // Permissive constant to indicate SELinux is in permissive mode + Permissive = 0 + // Disabled constant to indicate SELinux is disabled + Disabled = -1 + // maxCategory is the maximum number of categories used within containers + maxCategory = 1024 + // DefaultCategoryRange is the upper bound on the category range + DefaultCategoryRange = uint32(maxCategory) +) + +var ( + // ErrMCSAlreadyExists is returned when trying to allocate a duplicate MCS. + ErrMCSAlreadyExists = errors.New("MCS label already exists") + // ErrEmptyPath is returned when an empty path has been specified. + ErrEmptyPath = errors.New("empty path") + + // InvalidLabel is returned when an invalid label is specified. + InvalidLabel = errors.New("Invalid Label") + + // ErrIncomparable is returned two levels are not comparable + ErrIncomparable = errors.New("incomparable levels") + // ErrLevelSyntax is returned when a sensitivity or category do not have correct syntax in a level + ErrLevelSyntax = errors.New("invalid level syntax") + + // ErrContextMissing is returned if a requested context is not found in a file. + ErrContextMissing = errors.New("context does not have a match") + // ErrVerifierNil is returned when a context verifier function is nil. + ErrVerifierNil = errors.New("verifier function is nil") + + // CategoryRange allows the upper bound on the category range to be adjusted + CategoryRange = DefaultCategoryRange + + privContainerMountLabel string +) + +// Context is a representation of the SELinux label broken into 4 parts +type Context map[string]string + +// SetDisabled disables SELinux support for the package +func SetDisabled() { + setDisabled() +} + +// GetEnabled returns whether SELinux is currently enabled. +func GetEnabled() bool { + return getEnabled() +} + +// ClassIndex returns the int index for an object class in the loaded policy, +// or -1 and an error +func ClassIndex(class string) (int, error) { + return classIndex(class) +} + +// SetFileLabel sets the SELinux label for this path, following symlinks, +// or returns an error. +func SetFileLabel(fpath string, label string) error { + return setFileLabel(fpath, label) +} + +// LsetFileLabel sets the SELinux label for this path, not following symlinks, +// or returns an error. +func LsetFileLabel(fpath string, label string) error { + return lSetFileLabel(fpath, label) +} + +// FileLabel returns the SELinux label for this path, following symlinks, +// or returns an error. +func FileLabel(fpath string) (string, error) { + return fileLabel(fpath) +} + +// LfileLabel returns the SELinux label for this path, not following symlinks, +// or returns an error. +func LfileLabel(fpath string) (string, error) { + return lFileLabel(fpath) +} + +// SetFSCreateLabel tells the kernel what label to use for all file system objects +// created by this task. +// Set the label to an empty string to return to the default label. Calls to SetFSCreateLabel +// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until file system +// objects created by this task are finished to guarantee another goroutine does not migrate +// to the current thread before execution is complete. +func SetFSCreateLabel(label string) error { + return setFSCreateLabel(label) +} + +// FSCreateLabel returns the default label the kernel which the kernel is using +// for file system objects created by this task. "" indicates default. +func FSCreateLabel() (string, error) { + return fsCreateLabel() +} + +// CurrentLabel returns the SELinux label of the current process thread, or an error. +func CurrentLabel() (string, error) { + return currentLabel() +} + +// PidLabel returns the SELinux label of the given pid, or an error. +func PidLabel(pid int) (string, error) { + return pidLabel(pid) +} + +// ExecLabel returns the SELinux label that the kernel will use for any programs +// that are executed by the current process thread, or an error. +func ExecLabel() (string, error) { + return execLabel() +} + +// CanonicalizeContext takes a context string and writes it to the kernel +// the function then returns the context that the kernel will use. Use this +// function to check if two contexts are equivalent +func CanonicalizeContext(val string) (string, error) { + return canonicalizeContext(val) +} + +// ComputeCreateContext requests the type transition from source to target for +// class from the kernel. +func ComputeCreateContext(source string, target string, class string) (string, error) { + return computeCreateContext(source, target, class) +} + +// CalculateGlbLub computes the glb (greatest lower bound) and lub (least upper bound) +// of a source and target range. +// The glblub is calculated as the greater of the low sensitivities and +// the lower of the high sensitivities and the and of each category bitset. +func CalculateGlbLub(sourceRange, targetRange string) (string, error) { + return calculateGlbLub(sourceRange, targetRange) +} + +// SetExecLabel sets the SELinux label that the kernel will use for any programs +// that are executed by the current process thread, or an error. Calls to SetExecLabel +// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until execution +// of the program is finished to guarantee another goroutine does not migrate to the current +// thread before execution is complete. +func SetExecLabel(label string) error { + return setExecLabel(label) +} + +// SetTaskLabel sets the SELinux label for the current thread, or an error. +// This requires the dyntransition permission. Calls to SetTaskLabel should +// be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() to guarantee +// the current thread does not run in a new mislabeled thread. +func SetTaskLabel(label string) error { + return setTaskLabel(label) +} + +// SetSocketLabel takes a process label and tells the kernel to assign the +// label to the next socket that gets created. Calls to SetSocketLabel +// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until +// the the socket is created to guarantee another goroutine does not migrate +// to the current thread before execution is complete. +func SetSocketLabel(label string) error { + return setSocketLabel(label) +} + +// SocketLabel retrieves the current socket label setting +func SocketLabel() (string, error) { + return socketLabel() +} + +// PeerLabel retrieves the label of the client on the other side of a socket +func PeerLabel(fd uintptr) (string, error) { + return peerLabel(fd) +} + +// SetKeyLabel takes a process label and tells the kernel to assign the +// label to the next kernel keyring that gets created. Calls to SetKeyLabel +// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until +// the kernel keyring is created to guarantee another goroutine does not migrate +// to the current thread before execution is complete. +func SetKeyLabel(label string) error { + return setKeyLabel(label) +} + +// KeyLabel retrieves the current kernel keyring label setting +func KeyLabel() (string, error) { + return keyLabel() +} + +// Get returns the Context as a string +func (c Context) Get() string { + return c.get() +} + +// NewContext creates a new Context struct from the specified label +func NewContext(label string) (Context, error) { + return newContext(label) +} + +// ClearLabels clears all reserved labels +func ClearLabels() { + clearLabels() +} + +// ReserveLabel reserves the MLS/MCS level component of the specified label +func ReserveLabel(label string) { + reserveLabel(label) +} + +// EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled +func EnforceMode() int { + return enforceMode() +} + +// SetEnforceMode sets the current SELinux mode Enforcing, Permissive. +// Disabled is not valid, since this needs to be set at boot time. +func SetEnforceMode(mode int) error { + return setEnforceMode(mode) +} + +// DefaultEnforceMode returns the systems default SELinux mode Enforcing, +// Permissive or Disabled. Note this is is just the default at boot time. +// EnforceMode tells you the systems current mode. +func DefaultEnforceMode() int { + return defaultEnforceMode() +} + +// ReleaseLabel un-reserves the MLS/MCS Level field of the specified label, +// allowing it to be used by another process. +func ReleaseLabel(label string) { + releaseLabel(label) +} + +// ROFileLabel returns the specified SELinux readonly file label +func ROFileLabel() string { + return roFileLabel() +} + +// KVMContainerLabels returns the default processLabel and mountLabel to be used +// for kvm containers by the calling process. +func KVMContainerLabels() (string, string) { + return kvmContainerLabels() +} + +// InitContainerLabels returns the default processLabel and file labels to be +// used for containers running an init system like systemd by the calling process. +func InitContainerLabels() (string, string) { + return initContainerLabels() +} + +// ContainerLabels returns an allocated processLabel and fileLabel to be used for +// container labeling by the calling process. +func ContainerLabels() (processLabel string, fileLabel string) { + return containerLabels() +} + +// SecurityCheckContext validates that the SELinux label is understood by the kernel +func SecurityCheckContext(val string) error { + return securityCheckContext(val) +} + +// CopyLevel returns a label with the MLS/MCS level from src label replaced on +// the dest label. +func CopyLevel(src, dest string) (string, error) { + return copyLevel(src, dest) +} + +// Chcon changes the fpath file object to the SELinux label label. +// If fpath is a directory and recurse is true, then Chcon walks the +// directory tree setting the label. +// +// The fpath itself is guaranteed to be relabeled last. +func Chcon(fpath string, label string, recurse bool) error { + return chcon(fpath, label, recurse) +} + +// DupSecOpt takes an SELinux process label and returns security options that +// can be used to set the SELinux Type and Level for future container processes. +func DupSecOpt(src string) ([]string, error) { + return dupSecOpt(src) +} + +// DisableSecOpt returns a security opt that can be used to disable SELinux +// labeling support for future container processes. +func DisableSecOpt() []string { + return disableSecOpt() +} + +// GetDefaultContextWithLevel gets a single context for the specified SELinux user +// identity that is reachable from the specified scon context. The context is based +// on the per-user /etc/selinux/{SELINUXTYPE}/contexts/users/ if it exists, +// and falls back to the global /etc/selinux/{SELINUXTYPE}/contexts/default_contexts +// file. +func GetDefaultContextWithLevel(user, level, scon string) (string, error) { + return getDefaultContextWithLevel(user, level, scon) +} + +// PrivContainerMountLabel returns mount label for privileged containers +func PrivContainerMountLabel() string { + // Make sure label is initialized. + _ = label("") + return privContainerMountLabel +} diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go new file mode 100644 index 000000000..ee602ab96 --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go @@ -0,0 +1,1262 @@ +package selinux + +import ( + "bufio" + "bytes" + "crypto/rand" + "encoding/binary" + "errors" + "fmt" + "io" + "io/ioutil" + "math/big" + "os" + "path" + "path/filepath" + "strconv" + "strings" + "sync" + + "golang.org/x/sys/unix" +) + +const ( + minSensLen = 2 + contextFile = "/usr/share/containers/selinux/contexts" + selinuxDir = "/etc/selinux/" + selinuxUsersDir = "contexts/users" + defaultContexts = "contexts/default_contexts" + selinuxConfig = selinuxDir + "config" + selinuxfsMount = "/sys/fs/selinux" + selinuxTypeTag = "SELINUXTYPE" + selinuxTag = "SELINUX" + xattrNameSelinux = "security.selinux" +) + +type selinuxState struct { + enabledSet bool + enabled bool + selinuxfsOnce sync.Once + selinuxfs string + mcsList map[string]bool + sync.Mutex +} + +type level struct { + sens uint + cats *big.Int +} + +type mlsRange struct { + low *level + high *level +} + +type defaultSECtx struct { + user, level, scon string + userRdr, defaultRdr io.Reader + + verifier func(string) error +} + +type levelItem byte + +const ( + sensitivity levelItem = 's' + category levelItem = 'c' +) + +var ( + readOnlyFileLabel string + state = selinuxState{ + mcsList: make(map[string]bool), + } + + // for attrPath() + attrPathOnce sync.Once + haveThreadSelf bool + + // for policyRoot() + policyRootOnce sync.Once + policyRootVal string + + // for label() + loadLabelsOnce sync.Once + labels map[string]string +) + +func policyRoot() string { + policyRootOnce.Do(func() { + policyRootVal = filepath.Join(selinuxDir, readConfig(selinuxTypeTag)) + }) + + return policyRootVal +} + +func (s *selinuxState) setEnable(enabled bool) bool { + s.Lock() + defer s.Unlock() + s.enabledSet = true + s.enabled = enabled + return s.enabled +} + +func (s *selinuxState) getEnabled() bool { + s.Lock() + enabled := s.enabled + enabledSet := s.enabledSet + s.Unlock() + if enabledSet { + return enabled + } + + enabled = false + if fs := getSelinuxMountPoint(); fs != "" { + if con, _ := CurrentLabel(); con != "kernel" { + enabled = true + } + } + return s.setEnable(enabled) +} + +// setDisabled disables SELinux support for the package +func setDisabled() { + state.setEnable(false) +} + +func verifySELinuxfsMount(mnt string) bool { + var buf unix.Statfs_t + for { + err := unix.Statfs(mnt, &buf) + if err == nil { + break + } + if err == unix.EAGAIN || err == unix.EINTR { //nolint:errorlint // unix errors are bare + continue + } + return false + } + + if uint32(buf.Type) != uint32(unix.SELINUX_MAGIC) { + return false + } + if (buf.Flags & unix.ST_RDONLY) != 0 { + return false + } + + return true +} + +func findSELinuxfs() string { + // fast path: check the default mount first + if verifySELinuxfsMount(selinuxfsMount) { + return selinuxfsMount + } + + // check if selinuxfs is available before going the slow path + fs, err := ioutil.ReadFile("/proc/filesystems") + if err != nil { + return "" + } + if !bytes.Contains(fs, []byte("\tselinuxfs\n")) { + return "" + } + + // slow path: try to find among the mounts + f, err := os.Open("/proc/self/mountinfo") + if err != nil { + return "" + } + defer f.Close() + + scanner := bufio.NewScanner(f) + for { + mnt := findSELinuxfsMount(scanner) + if mnt == "" { // error or not found + return "" + } + if verifySELinuxfsMount(mnt) { + return mnt + } + } +} + +// findSELinuxfsMount returns a next selinuxfs mount point found, +// if there is one, or an empty string in case of EOF or error. +func findSELinuxfsMount(s *bufio.Scanner) string { + for s.Scan() { + txt := s.Bytes() + // The first field after - is fs type. + // Safe as spaces in mountpoints are encoded as \040 + if !bytes.Contains(txt, []byte(" - selinuxfs ")) { + continue + } + const mPos = 5 // mount point is 5th field + fields := bytes.SplitN(txt, []byte(" "), mPos+1) + if len(fields) < mPos+1 { + continue + } + return string(fields[mPos-1]) + } + + return "" +} + +func (s *selinuxState) getSELinuxfs() string { + s.selinuxfsOnce.Do(func() { + s.selinuxfs = findSELinuxfs() + }) + + return s.selinuxfs +} + +// getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs +// filesystem or an empty string if no mountpoint is found. Selinuxfs is +// a proc-like pseudo-filesystem that exposes the SELinux policy API to +// processes. The existence of an selinuxfs mount is used to determine +// whether SELinux is currently enabled or not. +func getSelinuxMountPoint() string { + return state.getSELinuxfs() +} + +// getEnabled returns whether SELinux is currently enabled. +func getEnabled() bool { + return state.getEnabled() +} + +func readConfig(target string) string { + in, err := os.Open(selinuxConfig) + if err != nil { + return "" + } + defer in.Close() + + scanner := bufio.NewScanner(in) + + for scanner.Scan() { + line := bytes.TrimSpace(scanner.Bytes()) + if len(line) == 0 { + // Skip blank lines + continue + } + if line[0] == ';' || line[0] == '#' { + // Skip comments + continue + } + fields := bytes.SplitN(line, []byte{'='}, 2) + if len(fields) != 2 { + continue + } + if bytes.Equal(fields[0], []byte(target)) { + return string(bytes.Trim(fields[1], `"`)) + } + } + return "" +} + +func isProcHandle(fh *os.File) error { + var buf unix.Statfs_t + + for { + err := unix.Fstatfs(int(fh.Fd()), &buf) + if err == nil { + break + } + if err != unix.EINTR { //nolint:errorlint // unix errors are bare + return &os.PathError{Op: "fstatfs", Path: fh.Name(), Err: err} + } + } + if buf.Type != unix.PROC_SUPER_MAGIC { + return fmt.Errorf("file %q is not on procfs", fh.Name()) + } + + return nil +} + +func readCon(fpath string) (string, error) { + if fpath == "" { + return "", ErrEmptyPath + } + + in, err := os.Open(fpath) + if err != nil { + return "", err + } + defer in.Close() + + if err := isProcHandle(in); err != nil { + return "", err + } + return readConFd(in) +} + +func readConFd(in *os.File) (string, error) { + data, err := ioutil.ReadAll(in) + if err != nil { + return "", err + } + return string(bytes.TrimSuffix(data, []byte{0})), nil +} + +// classIndex returns the int index for an object class in the loaded policy, +// or -1 and an error +func classIndex(class string) (int, error) { + permpath := fmt.Sprintf("class/%s/index", class) + indexpath := filepath.Join(getSelinuxMountPoint(), permpath) + + indexB, err := ioutil.ReadFile(indexpath) + if err != nil { + return -1, err + } + index, err := strconv.Atoi(string(indexB)) + if err != nil { + return -1, err + } + + return index, nil +} + +// lSetFileLabel sets the SELinux label for this path, not following symlinks, +// or returns an error. +func lSetFileLabel(fpath string, label string) error { + if fpath == "" { + return ErrEmptyPath + } + for { + err := unix.Lsetxattr(fpath, xattrNameSelinux, []byte(label), 0) + if err == nil { + break + } + if err != unix.EINTR { //nolint:errorlint // unix errors are bare + return &os.PathError{Op: "lsetxattr", Path: fpath, Err: err} + } + } + + return nil +} + +// setFileLabel sets the SELinux label for this path, following symlinks, +// or returns an error. +func setFileLabel(fpath string, label string) error { + if fpath == "" { + return ErrEmptyPath + } + for { + err := unix.Setxattr(fpath, xattrNameSelinux, []byte(label), 0) + if err == nil { + break + } + if err != unix.EINTR { //nolint:errorlint // unix errors are bare + return &os.PathError{Op: "setxattr", Path: fpath, Err: err} + } + } + + return nil +} + +// fileLabel returns the SELinux label for this path, following symlinks, +// or returns an error. +func fileLabel(fpath string) (string, error) { + if fpath == "" { + return "", ErrEmptyPath + } + + label, err := getxattr(fpath, xattrNameSelinux) + if err != nil { + return "", &os.PathError{Op: "getxattr", Path: fpath, Err: err} + } + // Trim the NUL byte at the end of the byte buffer, if present. + if len(label) > 0 && label[len(label)-1] == '\x00' { + label = label[:len(label)-1] + } + return string(label), nil +} + +// lFileLabel returns the SELinux label for this path, not following symlinks, +// or returns an error. +func lFileLabel(fpath string) (string, error) { + if fpath == "" { + return "", ErrEmptyPath + } + + label, err := lgetxattr(fpath, xattrNameSelinux) + if err != nil { + return "", &os.PathError{Op: "lgetxattr", Path: fpath, Err: err} + } + // Trim the NUL byte at the end of the byte buffer, if present. + if len(label) > 0 && label[len(label)-1] == '\x00' { + label = label[:len(label)-1] + } + return string(label), nil +} + +// setFSCreateLabel tells kernel the label to create all file system objects +// created by this task. Setting label="" to return to default. +func setFSCreateLabel(label string) error { + return writeAttr("fscreate", label) +} + +// fsCreateLabel returns the default label the kernel which the kernel is using +// for file system objects created by this task. "" indicates default. +func fsCreateLabel() (string, error) { + return readAttr("fscreate") +} + +// currentLabel returns the SELinux label of the current process thread, or an error. +func currentLabel() (string, error) { + return readAttr("current") +} + +// pidLabel returns the SELinux label of the given pid, or an error. +func pidLabel(pid int) (string, error) { + return readCon(fmt.Sprintf("/proc/%d/attr/current", pid)) +} + +// ExecLabel returns the SELinux label that the kernel will use for any programs +// that are executed by the current process thread, or an error. +func execLabel() (string, error) { + return readAttr("exec") +} + +func writeCon(fpath, val string) error { + if fpath == "" { + return ErrEmptyPath + } + if val == "" { + if !getEnabled() { + return nil + } + } + + out, err := os.OpenFile(fpath, os.O_WRONLY, 0) + if err != nil { + return err + } + defer out.Close() + + if err := isProcHandle(out); err != nil { + return err + } + + if val != "" { + _, err = out.Write([]byte(val)) + } else { + _, err = out.Write(nil) + } + if err != nil { + return err + } + return nil +} + +func attrPath(attr string) string { + // Linux >= 3.17 provides this + const threadSelfPrefix = "/proc/thread-self/attr" + + attrPathOnce.Do(func() { + st, err := os.Stat(threadSelfPrefix) + if err == nil && st.Mode().IsDir() { + haveThreadSelf = true + } + }) + + if haveThreadSelf { + return path.Join(threadSelfPrefix, attr) + } + + return path.Join("/proc/self/task/", strconv.Itoa(unix.Gettid()), "/attr/", attr) +} + +func readAttr(attr string) (string, error) { + return readCon(attrPath(attr)) +} + +func writeAttr(attr, val string) error { + return writeCon(attrPath(attr), val) +} + +// canonicalizeContext takes a context string and writes it to the kernel +// the function then returns the context that the kernel will use. Use this +// function to check if two contexts are equivalent +func canonicalizeContext(val string) (string, error) { + return readWriteCon(filepath.Join(getSelinuxMountPoint(), "context"), val) +} + +// computeCreateContext requests the type transition from source to target for +// class from the kernel. +func computeCreateContext(source string, target string, class string) (string, error) { + classidx, err := classIndex(class) + if err != nil { + return "", err + } + + return readWriteCon(filepath.Join(getSelinuxMountPoint(), "create"), fmt.Sprintf("%s %s %d", source, target, classidx)) +} + +// catsToBitset stores categories in a bitset. +func catsToBitset(cats string) (*big.Int, error) { + bitset := new(big.Int) + + catlist := strings.Split(cats, ",") + for _, r := range catlist { + ranges := strings.SplitN(r, ".", 2) + if len(ranges) > 1 { + catstart, err := parseLevelItem(ranges[0], category) + if err != nil { + return nil, err + } + catend, err := parseLevelItem(ranges[1], category) + if err != nil { + return nil, err + } + for i := catstart; i <= catend; i++ { + bitset.SetBit(bitset, int(i), 1) + } + } else { + cat, err := parseLevelItem(ranges[0], category) + if err != nil { + return nil, err + } + bitset.SetBit(bitset, int(cat), 1) + } + } + + return bitset, nil +} + +// parseLevelItem parses and verifies that a sensitivity or category are valid +func parseLevelItem(s string, sep levelItem) (uint, error) { + if len(s) < minSensLen || levelItem(s[0]) != sep { + return 0, ErrLevelSyntax + } + val, err := strconv.ParseUint(s[1:], 10, 32) + if err != nil { + return 0, err + } + + return uint(val), nil +} + +// parseLevel fills a level from a string that contains +// a sensitivity and categories +func (l *level) parseLevel(levelStr string) error { + lvl := strings.SplitN(levelStr, ":", 2) + sens, err := parseLevelItem(lvl[0], sensitivity) + if err != nil { + return fmt.Errorf("failed to parse sensitivity: %w", err) + } + l.sens = sens + if len(lvl) > 1 { + cats, err := catsToBitset(lvl[1]) + if err != nil { + return fmt.Errorf("failed to parse categories: %w", err) + } + l.cats = cats + } + + return nil +} + +// rangeStrToMLSRange marshals a string representation of a range. +func rangeStrToMLSRange(rangeStr string) (*mlsRange, error) { + mlsRange := &mlsRange{} + levelSlice := strings.SplitN(rangeStr, "-", 2) + + switch len(levelSlice) { + // rangeStr that has a low and a high level, e.g. s4:c0.c1023-s6:c0.c1023 + case 2: + mlsRange.high = &level{} + if err := mlsRange.high.parseLevel(levelSlice[1]); err != nil { + return nil, fmt.Errorf("failed to parse high level %q: %w", levelSlice[1], err) + } + fallthrough + // rangeStr that is single level, e.g. s6:c0,c3,c5,c30.c1023 + case 1: + mlsRange.low = &level{} + if err := mlsRange.low.parseLevel(levelSlice[0]); err != nil { + return nil, fmt.Errorf("failed to parse low level %q: %w", levelSlice[0], err) + } + } + + if mlsRange.high == nil { + mlsRange.high = mlsRange.low + } + + return mlsRange, nil +} + +// bitsetToStr takes a category bitset and returns it in the +// canonical selinux syntax +func bitsetToStr(c *big.Int) string { + var str string + + length := 0 + for i := int(c.TrailingZeroBits()); i < c.BitLen(); i++ { + if c.Bit(i) == 0 { + continue + } + if length == 0 { + if str != "" { + str += "," + } + str += "c" + strconv.Itoa(i) + } + if c.Bit(i+1) == 1 { + length++ + continue + } + if length == 1 { + str += ",c" + strconv.Itoa(i) + } else if length > 1 { + str += ".c" + strconv.Itoa(i) + } + length = 0 + } + + return str +} + +func (l1 *level) equal(l2 *level) bool { + if l2 == nil || l1 == nil { + return l1 == l2 + } + if l1.sens != l2.sens { + return false + } + if l2.cats == nil || l1.cats == nil { + return l2.cats == l1.cats + } + return l1.cats.Cmp(l2.cats) == 0 +} + +// String returns an mlsRange as a string. +func (m mlsRange) String() string { + low := "s" + strconv.Itoa(int(m.low.sens)) + if m.low.cats != nil && m.low.cats.BitLen() > 0 { + low += ":" + bitsetToStr(m.low.cats) + } + + if m.low.equal(m.high) { + return low + } + + high := "s" + strconv.Itoa(int(m.high.sens)) + if m.high.cats != nil && m.high.cats.BitLen() > 0 { + high += ":" + bitsetToStr(m.high.cats) + } + + return low + "-" + high +} + +func max(a, b uint) uint { + if a > b { + return a + } + return b +} + +func min(a, b uint) uint { + if a < b { + return a + } + return b +} + +// calculateGlbLub computes the glb (greatest lower bound) and lub (least upper bound) +// of a source and target range. +// The glblub is calculated as the greater of the low sensitivities and +// the lower of the high sensitivities and the and of each category bitset. +func calculateGlbLub(sourceRange, targetRange string) (string, error) { + s, err := rangeStrToMLSRange(sourceRange) + if err != nil { + return "", err + } + t, err := rangeStrToMLSRange(targetRange) + if err != nil { + return "", err + } + + if s.high.sens < t.low.sens || t.high.sens < s.low.sens { + /* these ranges have no common sensitivities */ + return "", ErrIncomparable + } + + outrange := &mlsRange{low: &level{}, high: &level{}} + + /* take the greatest of the low */ + outrange.low.sens = max(s.low.sens, t.low.sens) + + /* take the least of the high */ + outrange.high.sens = min(s.high.sens, t.high.sens) + + /* find the intersecting categories */ + if s.low.cats != nil && t.low.cats != nil { + outrange.low.cats = new(big.Int) + outrange.low.cats.And(s.low.cats, t.low.cats) + } + if s.high.cats != nil && t.high.cats != nil { + outrange.high.cats = new(big.Int) + outrange.high.cats.And(s.high.cats, t.high.cats) + } + + return outrange.String(), nil +} + +func readWriteCon(fpath string, val string) (string, error) { + if fpath == "" { + return "", ErrEmptyPath + } + f, err := os.OpenFile(fpath, os.O_RDWR, 0) + if err != nil { + return "", err + } + defer f.Close() + + _, err = f.Write([]byte(val)) + if err != nil { + return "", err + } + + return readConFd(f) +} + +// setExecLabel sets the SELinux label that the kernel will use for any programs +// that are executed by the current process thread, or an error. +func setExecLabel(label string) error { + return writeAttr("exec", label) +} + +// setTaskLabel sets the SELinux label for the current thread, or an error. +// This requires the dyntransition permission. +func setTaskLabel(label string) error { + return writeAttr("current", label) +} + +// setSocketLabel takes a process label and tells the kernel to assign the +// label to the next socket that gets created +func setSocketLabel(label string) error { + return writeAttr("sockcreate", label) +} + +// socketLabel retrieves the current socket label setting +func socketLabel() (string, error) { + return readAttr("sockcreate") +} + +// peerLabel retrieves the label of the client on the other side of a socket +func peerLabel(fd uintptr) (string, error) { + label, err := unix.GetsockoptString(int(fd), unix.SOL_SOCKET, unix.SO_PEERSEC) + if err != nil { + return "", &os.PathError{Op: "getsockopt", Path: "fd " + strconv.Itoa(int(fd)), Err: err} + } + return label, nil +} + +// setKeyLabel takes a process label and tells the kernel to assign the +// label to the next kernel keyring that gets created +func setKeyLabel(label string) error { + err := writeCon("/proc/self/attr/keycreate", label) + if errors.Is(err, os.ErrNotExist) { + return nil + } + if label == "" && errors.Is(err, os.ErrPermission) { + return nil + } + return err +} + +// keyLabel retrieves the current kernel keyring label setting +func keyLabel() (string, error) { + return readCon("/proc/self/attr/keycreate") +} + +// get returns the Context as a string +func (c Context) get() string { + if level := c["level"]; level != "" { + return c["user"] + ":" + c["role"] + ":" + c["type"] + ":" + level + } + return c["user"] + ":" + c["role"] + ":" + c["type"] +} + +// newContext creates a new Context struct from the specified label +func newContext(label string) (Context, error) { + c := make(Context) + + if len(label) != 0 { + con := strings.SplitN(label, ":", 4) + if len(con) < 3 { + return c, InvalidLabel + } + c["user"] = con[0] + c["role"] = con[1] + c["type"] = con[2] + if len(con) > 3 { + c["level"] = con[3] + } + } + return c, nil +} + +// clearLabels clears all reserved labels +func clearLabels() { + state.Lock() + state.mcsList = make(map[string]bool) + state.Unlock() +} + +// reserveLabel reserves the MLS/MCS level component of the specified label +func reserveLabel(label string) { + if len(label) != 0 { + con := strings.SplitN(label, ":", 4) + if len(con) > 3 { + _ = mcsAdd(con[3]) + } + } +} + +func selinuxEnforcePath() string { + return path.Join(getSelinuxMountPoint(), "enforce") +} + +// enforceMode returns the current SELinux mode Enforcing, Permissive, Disabled +func enforceMode() int { + var enforce int + + enforceB, err := ioutil.ReadFile(selinuxEnforcePath()) + if err != nil { + return -1 + } + enforce, err = strconv.Atoi(string(enforceB)) + if err != nil { + return -1 + } + return enforce +} + +// setEnforceMode sets the current SELinux mode Enforcing, Permissive. +// Disabled is not valid, since this needs to be set at boot time. +func setEnforceMode(mode int) error { + return ioutil.WriteFile(selinuxEnforcePath(), []byte(strconv.Itoa(mode)), 0o644) +} + +// defaultEnforceMode returns the systems default SELinux mode Enforcing, +// Permissive or Disabled. Note this is is just the default at boot time. +// EnforceMode tells you the systems current mode. +func defaultEnforceMode() int { + switch readConfig(selinuxTag) { + case "enforcing": + return Enforcing + case "permissive": + return Permissive + } + return Disabled +} + +func mcsAdd(mcs string) error { + if mcs == "" { + return nil + } + state.Lock() + defer state.Unlock() + if state.mcsList[mcs] { + return ErrMCSAlreadyExists + } + state.mcsList[mcs] = true + return nil +} + +func mcsDelete(mcs string) { + if mcs == "" { + return + } + state.Lock() + defer state.Unlock() + state.mcsList[mcs] = false +} + +func intToMcs(id int, catRange uint32) string { + var ( + SETSIZE = int(catRange) + TIER = SETSIZE + ORD = id + ) + + if id < 1 || id > 523776 { + return "" + } + + for ORD > TIER { + ORD -= TIER + TIER-- + } + TIER = SETSIZE - TIER + ORD += TIER + return fmt.Sprintf("s0:c%d,c%d", TIER, ORD) +} + +func uniqMcs(catRange uint32) string { + var ( + n uint32 + c1, c2 uint32 + mcs string + ) + + for { + _ = binary.Read(rand.Reader, binary.LittleEndian, &n) + c1 = n % catRange + _ = binary.Read(rand.Reader, binary.LittleEndian, &n) + c2 = n % catRange + if c1 == c2 { + continue + } else if c1 > c2 { + c1, c2 = c2, c1 + } + mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2) + if err := mcsAdd(mcs); err != nil { + continue + } + break + } + return mcs +} + +// releaseLabel un-reserves the MLS/MCS Level field of the specified label, +// allowing it to be used by another process. +func releaseLabel(label string) { + if len(label) != 0 { + con := strings.SplitN(label, ":", 4) + if len(con) > 3 { + mcsDelete(con[3]) + } + } +} + +// roFileLabel returns the specified SELinux readonly file label +func roFileLabel() string { + return readOnlyFileLabel +} + +func openContextFile() (*os.File, error) { + if f, err := os.Open(contextFile); err == nil { + return f, nil + } + return os.Open(filepath.Join(policyRoot(), "/contexts/lxc_contexts")) +} + +func loadLabels() { + labels = make(map[string]string) + in, err := openContextFile() + if err != nil { + return + } + defer in.Close() + + scanner := bufio.NewScanner(in) + + for scanner.Scan() { + line := bytes.TrimSpace(scanner.Bytes()) + if len(line) == 0 { + // Skip blank lines + continue + } + if line[0] == ';' || line[0] == '#' { + // Skip comments + continue + } + fields := bytes.SplitN(line, []byte{'='}, 2) + if len(fields) != 2 { + continue + } + key, val := bytes.TrimSpace(fields[0]), bytes.TrimSpace(fields[1]) + labels[string(key)] = string(bytes.Trim(val, `"`)) + } + + con, _ := NewContext(labels["file"]) + con["level"] = fmt.Sprintf("s0:c%d,c%d", maxCategory-2, maxCategory-1) + privContainerMountLabel = con.get() + reserveLabel(privContainerMountLabel) +} + +func label(key string) string { + loadLabelsOnce.Do(func() { + loadLabels() + }) + return labels[key] +} + +// kvmContainerLabels returns the default processLabel and mountLabel to be used +// for kvm containers by the calling process. +func kvmContainerLabels() (string, string) { + processLabel := label("kvm_process") + if processLabel == "" { + processLabel = label("process") + } + + return addMcs(processLabel, label("file")) +} + +// initContainerLabels returns the default processLabel and file labels to be +// used for containers running an init system like systemd by the calling process. +func initContainerLabels() (string, string) { + processLabel := label("init_process") + if processLabel == "" { + processLabel = label("process") + } + + return addMcs(processLabel, label("file")) +} + +// containerLabels returns an allocated processLabel and fileLabel to be used for +// container labeling by the calling process. +func containerLabels() (processLabel string, fileLabel string) { + if !getEnabled() { + return "", "" + } + + processLabel = label("process") + fileLabel = label("file") + readOnlyFileLabel = label("ro_file") + + if processLabel == "" || fileLabel == "" { + return "", fileLabel + } + + if readOnlyFileLabel == "" { + readOnlyFileLabel = fileLabel + } + + return addMcs(processLabel, fileLabel) +} + +func addMcs(processLabel, fileLabel string) (string, string) { + scon, _ := NewContext(processLabel) + if scon["level"] != "" { + mcs := uniqMcs(CategoryRange) + scon["level"] = mcs + processLabel = scon.Get() + scon, _ = NewContext(fileLabel) + scon["level"] = mcs + fileLabel = scon.Get() + } + return processLabel, fileLabel +} + +// securityCheckContext validates that the SELinux label is understood by the kernel +func securityCheckContext(val string) error { + return ioutil.WriteFile(path.Join(getSelinuxMountPoint(), "context"), []byte(val), 0o644) +} + +// copyLevel returns a label with the MLS/MCS level from src label replaced on +// the dest label. +func copyLevel(src, dest string) (string, error) { + if src == "" { + return "", nil + } + if err := SecurityCheckContext(src); err != nil { + return "", err + } + if err := SecurityCheckContext(dest); err != nil { + return "", err + } + scon, err := NewContext(src) + if err != nil { + return "", err + } + tcon, err := NewContext(dest) + if err != nil { + return "", err + } + mcsDelete(tcon["level"]) + _ = mcsAdd(scon["level"]) + tcon["level"] = scon["level"] + return tcon.Get(), nil +} + +// Prevent users from relabeling system files +func badPrefix(fpath string) error { + if fpath == "" { + return ErrEmptyPath + } + + badPrefixes := []string{"/usr"} + for _, prefix := range badPrefixes { + if strings.HasPrefix(fpath, prefix) { + return fmt.Errorf("relabeling content in %s is not allowed", prefix) + } + } + return nil +} + +// chcon changes the fpath file object to the SELinux label label. +// If fpath is a directory and recurse is true, then chcon walks the +// directory tree setting the label. +func chcon(fpath string, label string, recurse bool) error { + if fpath == "" { + return ErrEmptyPath + } + if label == "" { + return nil + } + if err := badPrefix(fpath); err != nil { + return err + } + + if !recurse { + return setFileLabel(fpath, label) + } + + return rchcon(fpath, label) +} + +// dupSecOpt takes an SELinux process label and returns security options that +// can be used to set the SELinux Type and Level for future container processes. +func dupSecOpt(src string) ([]string, error) { + if src == "" { + return nil, nil + } + con, err := NewContext(src) + if err != nil { + return nil, err + } + if con["user"] == "" || + con["role"] == "" || + con["type"] == "" { + return nil, nil + } + dup := []string{ + "user:" + con["user"], + "role:" + con["role"], + "type:" + con["type"], + } + + if con["level"] != "" { + dup = append(dup, "level:"+con["level"]) + } + + return dup, nil +} + +// disableSecOpt returns a security opt that can be used to disable SELinux +// labeling support for future container processes. +func disableSecOpt() []string { + return []string{"disable"} +} + +// findUserInContext scans the reader for a valid SELinux context +// match that is verified with the verifier. Invalid contexts are +// skipped. It returns a matched context or an empty string if no +// match is found. If a scanner error occurs, it is returned. +func findUserInContext(context Context, r io.Reader, verifier func(string) error) (string, error) { + fromRole := context["role"] + fromType := context["type"] + scanner := bufio.NewScanner(r) + + for scanner.Scan() { + fromConns := strings.Fields(scanner.Text()) + if len(fromConns) == 0 { + // Skip blank lines + continue + } + + line := fromConns[0] + + if line[0] == ';' || line[0] == '#' { + // Skip comments + continue + } + + // user context files contexts are formatted as + // role_r:type_t:s0 where the user is missing. + lineArr := strings.SplitN(line, ":", 4) + // skip context with typo, or role and type do not match + if len(lineArr) != 3 || + lineArr[0] != fromRole || + lineArr[1] != fromType { + continue + } + + for _, cc := range fromConns[1:] { + toConns := strings.SplitN(cc, ":", 4) + if len(toConns) != 3 { + continue + } + + context["role"] = toConns[0] + context["type"] = toConns[1] + + outConn := context.get() + if err := verifier(outConn); err != nil { + continue + } + + return outConn, nil + } + } + if err := scanner.Err(); err != nil { + return "", fmt.Errorf("failed to scan for context: %w", err) + } + + return "", nil +} + +func getDefaultContextFromReaders(c *defaultSECtx) (string, error) { + if c.verifier == nil { + return "", ErrVerifierNil + } + + context, err := newContext(c.scon) + if err != nil { + return "", fmt.Errorf("failed to create label for %s: %w", c.scon, err) + } + + // set so the verifier validates the matched context with the provided user and level. + context["user"] = c.user + context["level"] = c.level + + conn, err := findUserInContext(context, c.userRdr, c.verifier) + if err != nil { + return "", err + } + + if conn != "" { + return conn, nil + } + + conn, err = findUserInContext(context, c.defaultRdr, c.verifier) + if err != nil { + return "", err + } + + if conn != "" { + return conn, nil + } + + return "", fmt.Errorf("context %q not found: %w", c.scon, ErrContextMissing) +} + +func getDefaultContextWithLevel(user, level, scon string) (string, error) { + userPath := filepath.Join(policyRoot(), selinuxUsersDir, user) + fu, err := os.Open(userPath) + if err != nil { + return "", err + } + defer fu.Close() + + defaultPath := filepath.Join(policyRoot(), defaultContexts) + fd, err := os.Open(defaultPath) + if err != nil { + return "", err + } + defer fd.Close() + + c := defaultSECtx{ + user: user, + level: level, + scon: scon, + userRdr: fu, + defaultRdr: fd, + verifier: securityCheckContext, + } + + return getDefaultContextFromReaders(&c) +} diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go new file mode 100644 index 000000000..78743b020 --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go @@ -0,0 +1,164 @@ +// +build !linux + +package selinux + +func setDisabled() { +} + +func getEnabled() bool { + return false +} + +func classIndex(class string) (int, error) { + return -1, nil +} + +func setFileLabel(fpath string, label string) error { + return nil +} + +func lSetFileLabel(fpath string, label string) error { + return nil +} + +func fileLabel(fpath string) (string, error) { + return "", nil +} + +func lFileLabel(fpath string) (string, error) { + return "", nil +} + +func setFSCreateLabel(label string) error { + return nil +} + +func fsCreateLabel() (string, error) { + return "", nil +} + +func currentLabel() (string, error) { + return "", nil +} + +func pidLabel(pid int) (string, error) { + return "", nil +} + +func execLabel() (string, error) { + return "", nil +} + +func canonicalizeContext(val string) (string, error) { + return "", nil +} + +func computeCreateContext(source string, target string, class string) (string, error) { + return "", nil +} + +func calculateGlbLub(sourceRange, targetRange string) (string, error) { + return "", nil +} + +func setExecLabel(label string) error { + return nil +} + +func setTaskLabel(label string) error { + return nil +} + +func setSocketLabel(label string) error { + return nil +} + +func socketLabel() (string, error) { + return "", nil +} + +func peerLabel(fd uintptr) (string, error) { + return "", nil +} + +func setKeyLabel(label string) error { + return nil +} + +func keyLabel() (string, error) { + return "", nil +} + +func (c Context) get() string { + return "" +} + +func newContext(label string) (Context, error) { + c := make(Context) + return c, nil +} + +func clearLabels() { +} + +func reserveLabel(label string) { +} + +func enforceMode() int { + return Disabled +} + +func setEnforceMode(mode int) error { + return nil +} + +func defaultEnforceMode() int { + return Disabled +} + +func releaseLabel(label string) { +} + +func roFileLabel() string { + return "" +} + +func kvmContainerLabels() (string, string) { + return "", "" +} + +func initContainerLabels() (string, string) { + return "", "" +} + +func containerLabels() (processLabel string, fileLabel string) { + return "", "" +} + +func securityCheckContext(val string) error { + return nil +} + +func copyLevel(src, dest string) (string, error) { + return "", nil +} + +func chcon(fpath string, label string, recurse bool) error { + return nil +} + +func dupSecOpt(src string) ([]string, error) { + return nil, nil +} + +func disableSecOpt() []string { + return []string{"disable"} +} + +func getDefaultContextWithLevel(user, level, scon string) (string, error) { + return "", nil +} + +func label(_ string) string { + return "" +} diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/xattrs_linux.go b/vendor/github.com/opencontainers/selinux/go-selinux/xattrs_linux.go new file mode 100644 index 000000000..9e473ca16 --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/go-selinux/xattrs_linux.go @@ -0,0 +1,71 @@ +package selinux + +import ( + "golang.org/x/sys/unix" +) + +// lgetxattr returns a []byte slice containing the value of +// an extended attribute attr set for path. +func lgetxattr(path, attr string) ([]byte, error) { + // Start with a 128 length byte array + dest := make([]byte, 128) + sz, errno := doLgetxattr(path, attr, dest) + for errno == unix.ERANGE { //nolint:errorlint // unix errors are bare + // Buffer too small, use zero-sized buffer to get the actual size + sz, errno = doLgetxattr(path, attr, []byte{}) + if errno != nil { + return nil, errno + } + + dest = make([]byte, sz) + sz, errno = doLgetxattr(path, attr, dest) + } + if errno != nil { + return nil, errno + } + + return dest[:sz], nil +} + +// doLgetxattr is a wrapper that retries on EINTR +func doLgetxattr(path, attr string, dest []byte) (int, error) { + for { + sz, err := unix.Lgetxattr(path, attr, dest) + if err != unix.EINTR { //nolint:errorlint // unix errors are bare + return sz, err + } + } +} + +// getxattr returns a []byte slice containing the value of +// an extended attribute attr set for path. +func getxattr(path, attr string) ([]byte, error) { + // Start with a 128 length byte array + dest := make([]byte, 128) + sz, errno := dogetxattr(path, attr, dest) + for errno == unix.ERANGE { //nolint:errorlint // unix errors are bare + // Buffer too small, use zero-sized buffer to get the actual size + sz, errno = dogetxattr(path, attr, []byte{}) + if errno != nil { + return nil, errno + } + + dest = make([]byte, sz) + sz, errno = dogetxattr(path, attr, dest) + } + if errno != nil { + return nil, errno + } + + return dest[:sz], nil +} + +// dogetxattr is a wrapper that retries on EINTR +func dogetxattr(path, attr string, dest []byte) (int, error) { + for { + sz, err := unix.Getxattr(path, attr, dest) + if err != unix.EINTR { //nolint:errorlint // unix errors are bare + return sz, err + } + } +} diff --git a/vendor/github.com/opencontainers/selinux/pkg/pwalk/README.md b/vendor/github.com/opencontainers/selinux/pkg/pwalk/README.md new file mode 100644 index 000000000..7e78dce01 --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/pkg/pwalk/README.md @@ -0,0 +1,48 @@ +## pwalk: parallel implementation of filepath.Walk + +This is a wrapper for [filepath.Walk](https://pkg.go.dev/path/filepath?tab=doc#Walk) +which may speed it up by calling multiple callback functions (WalkFunc) in parallel, +utilizing goroutines. + +By default, it utilizes 2\*runtime.NumCPU() goroutines for callbacks. +This can be changed by using WalkN function which has the additional +parameter, specifying the number of goroutines (concurrency). + +### pwalk vs pwalkdir + +This package is deprecated in favor of +[pwalkdir](https://pkg.go.dev/github.com/opencontainers/selinux/pkg/pwalkdir), +which is faster, but requires at least Go 1.16. + +### Caveats + +Please note the following limitations of this code: + +* Unlike filepath.Walk, the order of calls is non-deterministic; + +* Only primitive error handling is supported: + + * filepath.SkipDir is not supported; + + * no errors are ever passed to WalkFunc; + + * once any error is returned from any WalkFunc instance, no more new calls + to WalkFunc are made, and the error is returned to the caller of Walk; + + * if more than one walkFunc instance will return an error, only one + of such errors will be propagated and returned by Walk, others + will be silently discarded. + +### Documentation + +For the official documentation, see +https://pkg.go.dev/github.com/opencontainers/selinux/pkg/pwalk?tab=doc + +### Benchmarks + +For a WalkFunc that consists solely of the return statement, this +implementation is about 10% slower than the standard library's +filepath.Walk. + +Otherwise (if a WalkFunc is doing something) this is usually faster, +except when the WalkN(..., 1) is used. diff --git a/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go b/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go new file mode 100644 index 000000000..202c80da5 --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go @@ -0,0 +1,115 @@ +package pwalk + +import ( + "fmt" + "os" + "path/filepath" + "runtime" + "sync" +) + +type WalkFunc = filepath.WalkFunc + +// Walk is a wrapper for filepath.Walk which can call multiple walkFn +// in parallel, allowing to handle each item concurrently. A maximum of +// twice the runtime.NumCPU() walkFn will be called at any one time. +// If you want to change the maximum, use WalkN instead. +// +// The order of calls is non-deterministic. +// +// Note that this implementation only supports primitive error handling: +// +// - no errors are ever passed to walkFn; +// +// - once a walkFn returns any error, all further processing stops +// and the error is returned to the caller of Walk; +// +// - filepath.SkipDir is not supported; +// +// - if more than one walkFn instance will return an error, only one +// of such errors will be propagated and returned by Walk, others +// will be silently discarded. +func Walk(root string, walkFn WalkFunc) error { + return WalkN(root, walkFn, runtime.NumCPU()*2) +} + +// WalkN is a wrapper for filepath.Walk which can call multiple walkFn +// in parallel, allowing to handle each item concurrently. A maximum of +// num walkFn will be called at any one time. +// +// Please see Walk documentation for caveats of using this function. +func WalkN(root string, walkFn WalkFunc, num int) error { + // make sure limit is sensible + if num < 1 { + return fmt.Errorf("walk(%q): num must be > 0", root) + } + + files := make(chan *walkArgs, 2*num) + errCh := make(chan error, 1) // get the first error, ignore others + + // Start walking a tree asap + var ( + err error + wg sync.WaitGroup + + rootLen = len(root) + rootEntry *walkArgs + ) + wg.Add(1) + go func() { + err = filepath.Walk(root, func(p string, info os.FileInfo, err error) error { + if err != nil { + close(files) + return err + } + if len(p) == rootLen { + // Root entry is processed separately below. + rootEntry = &walkArgs{path: p, info: &info} + return nil + } + // add a file to the queue unless a callback sent an error + select { + case e := <-errCh: + close(files) + return e + default: + files <- &walkArgs{path: p, info: &info} + return nil + } + }) + if err == nil { + close(files) + } + wg.Done() + }() + + wg.Add(num) + for i := 0; i < num; i++ { + go func() { + for file := range files { + if e := walkFn(file.path, *file.info, nil); e != nil { + select { + case errCh <- e: // sent ok + default: // buffer full + } + } + } + wg.Done() + }() + } + + wg.Wait() + + if err == nil { + err = walkFn(rootEntry.path, *rootEntry.info, nil) + } + + return err +} + +// walkArgs holds the arguments that were passed to the Walk or WalkN +// functions. +type walkArgs struct { + path string + info *os.FileInfo +} diff --git a/vendor/github.com/opencontainers/selinux/pkg/pwalkdir/README.md b/vendor/github.com/opencontainers/selinux/pkg/pwalkdir/README.md new file mode 100644 index 000000000..068ac4005 --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/pkg/pwalkdir/README.md @@ -0,0 +1,54 @@ +## pwalkdir: parallel implementation of filepath.WalkDir + +This is a wrapper for [filepath.WalkDir](https://pkg.go.dev/path/filepath#WalkDir) +which may speed it up by calling multiple callback functions (WalkDirFunc) +in parallel, utilizing goroutines. + +By default, it utilizes 2\*runtime.NumCPU() goroutines for callbacks. +This can be changed by using WalkN function which has the additional +parameter, specifying the number of goroutines (concurrency). + +### pwalk vs pwalkdir + +This package is very similar to +[pwalk](https://pkg.go.dev/github.com/opencontainers/selinux/pkg/pwalkdir), +but utilizes `filepath.WalkDir` (added to Go 1.16), which does not call stat(2) +on every entry and is therefore faster (up to 3x, depending on usage scenario). + +Users who are OK with requiring Go 1.16+ should switch to this +implementation. + +### Caveats + +Please note the following limitations of this code: + +* Unlike filepath.WalkDir, the order of calls is non-deterministic; + +* Only primitive error handling is supported: + + * fs.SkipDir is not supported; + + * no errors are ever passed to WalkDirFunc; + + * once any error is returned from any walkDirFunc instance, no more calls + to WalkDirFunc are made, and the error is returned to the caller of WalkDir; + + * if more than one WalkDirFunc instance will return an error, only one + of such errors will be propagated to and returned by WalkDir, others + will be silently discarded. + +### Documentation + +For the official documentation, see +https://pkg.go.dev/github.com/opencontainers/selinux/pkg/pwalkdir + +### Benchmarks + +For a WalkDirFunc that consists solely of the return statement, this +implementation is about 15% slower than the standard library's +filepath.WalkDir. + +Otherwise (if a WalkDirFunc is actually doing something) this is usually +faster, except when the WalkDirN(..., 1) is used. Run `go test -bench .` +to see how different operations can benefit from it, as well as how the +level of paralellism affects the speed. diff --git a/vendor/github.com/opencontainers/selinux/pkg/pwalkdir/pwalkdir.go b/vendor/github.com/opencontainers/selinux/pkg/pwalkdir/pwalkdir.go new file mode 100644 index 000000000..a5796b2c4 --- /dev/null +++ b/vendor/github.com/opencontainers/selinux/pkg/pwalkdir/pwalkdir.go @@ -0,0 +1,116 @@ +//go:build go1.16 +// +build go1.16 + +package pwalkdir + +import ( + "fmt" + "io/fs" + "path/filepath" + "runtime" + "sync" +) + +// Walk is a wrapper for filepath.WalkDir which can call multiple walkFn +// in parallel, allowing to handle each item concurrently. A maximum of +// twice the runtime.NumCPU() walkFn will be called at any one time. +// If you want to change the maximum, use WalkN instead. +// +// The order of calls is non-deterministic. +// +// Note that this implementation only supports primitive error handling: +// +// - no errors are ever passed to walkFn; +// +// - once a walkFn returns any error, all further processing stops +// and the error is returned to the caller of Walk; +// +// - filepath.SkipDir is not supported; +// +// - if more than one walkFn instance will return an error, only one +// of such errors will be propagated and returned by Walk, others +// will be silently discarded. +func Walk(root string, walkFn fs.WalkDirFunc) error { + return WalkN(root, walkFn, runtime.NumCPU()*2) +} + +// WalkN is a wrapper for filepath.WalkDir which can call multiple walkFn +// in parallel, allowing to handle each item concurrently. A maximum of +// num walkFn will be called at any one time. +// +// Please see Walk documentation for caveats of using this function. +func WalkN(root string, walkFn fs.WalkDirFunc, num int) error { + // make sure limit is sensible + if num < 1 { + return fmt.Errorf("walk(%q): num must be > 0", root) + } + + files := make(chan *walkArgs, 2*num) + errCh := make(chan error, 1) // Get the first error, ignore others. + + // Start walking a tree asap. + var ( + err error + wg sync.WaitGroup + + rootLen = len(root) + rootEntry *walkArgs + ) + wg.Add(1) + go func() { + err = filepath.WalkDir(root, func(p string, entry fs.DirEntry, err error) error { + if err != nil { + close(files) + return err + } + if len(p) == rootLen { + // Root entry is processed separately below. + rootEntry = &walkArgs{path: p, entry: entry} + return nil + } + // Add a file to the queue unless a callback sent an error. + select { + case e := <-errCh: + close(files) + return e + default: + files <- &walkArgs{path: p, entry: entry} + return nil + } + }) + if err == nil { + close(files) + } + wg.Done() + }() + + wg.Add(num) + for i := 0; i < num; i++ { + go func() { + for file := range files { + if e := walkFn(file.path, file.entry, nil); e != nil { + select { + case errCh <- e: // sent ok + default: // buffer full + } + } + } + wg.Done() + }() + } + + wg.Wait() + + if err == nil { + err = walkFn(rootEntry.path, rootEntry.entry, nil) + } + + return err +} + +// walkArgs holds the arguments that were passed to the Walk or WalkN +// functions. +type walkArgs struct { + path string + entry fs.DirEntry +} diff --git a/vendor/k8s.io/client-go/kubernetes/fake/clientset_generated.go b/vendor/k8s.io/client-go/kubernetes/fake/clientset_generated.go new file mode 100644 index 000000000..f4d621941 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/fake/clientset_generated.go @@ -0,0 +1,428 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/discovery" + fakediscovery "k8s.io/client-go/discovery/fake" + clientset "k8s.io/client-go/kubernetes" + admissionregistrationv1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1" + fakeadmissionregistrationv1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1/fake" + admissionregistrationv1alpha1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1" + fakeadmissionregistrationv1alpha1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake" + admissionregistrationv1beta1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1" + fakeadmissionregistrationv1beta1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/fake" + internalv1alpha1 "k8s.io/client-go/kubernetes/typed/apiserverinternal/v1alpha1" + fakeinternalv1alpha1 "k8s.io/client-go/kubernetes/typed/apiserverinternal/v1alpha1/fake" + appsv1 "k8s.io/client-go/kubernetes/typed/apps/v1" + fakeappsv1 "k8s.io/client-go/kubernetes/typed/apps/v1/fake" + appsv1beta1 "k8s.io/client-go/kubernetes/typed/apps/v1beta1" + fakeappsv1beta1 "k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake" + appsv1beta2 "k8s.io/client-go/kubernetes/typed/apps/v1beta2" + fakeappsv1beta2 "k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake" + authenticationv1 "k8s.io/client-go/kubernetes/typed/authentication/v1" + fakeauthenticationv1 "k8s.io/client-go/kubernetes/typed/authentication/v1/fake" + authenticationv1alpha1 "k8s.io/client-go/kubernetes/typed/authentication/v1alpha1" + fakeauthenticationv1alpha1 "k8s.io/client-go/kubernetes/typed/authentication/v1alpha1/fake" + authenticationv1beta1 "k8s.io/client-go/kubernetes/typed/authentication/v1beta1" + fakeauthenticationv1beta1 "k8s.io/client-go/kubernetes/typed/authentication/v1beta1/fake" + authorizationv1 "k8s.io/client-go/kubernetes/typed/authorization/v1" + fakeauthorizationv1 "k8s.io/client-go/kubernetes/typed/authorization/v1/fake" + authorizationv1beta1 "k8s.io/client-go/kubernetes/typed/authorization/v1beta1" + fakeauthorizationv1beta1 "k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake" + autoscalingv1 "k8s.io/client-go/kubernetes/typed/autoscaling/v1" + fakeautoscalingv1 "k8s.io/client-go/kubernetes/typed/autoscaling/v1/fake" + autoscalingv2 "k8s.io/client-go/kubernetes/typed/autoscaling/v2" + fakeautoscalingv2 "k8s.io/client-go/kubernetes/typed/autoscaling/v2/fake" + autoscalingv2beta1 "k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1" + fakeautoscalingv2beta1 "k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1/fake" + autoscalingv2beta2 "k8s.io/client-go/kubernetes/typed/autoscaling/v2beta2" + fakeautoscalingv2beta2 "k8s.io/client-go/kubernetes/typed/autoscaling/v2beta2/fake" + batchv1 "k8s.io/client-go/kubernetes/typed/batch/v1" + fakebatchv1 "k8s.io/client-go/kubernetes/typed/batch/v1/fake" + batchv1beta1 "k8s.io/client-go/kubernetes/typed/batch/v1beta1" + fakebatchv1beta1 "k8s.io/client-go/kubernetes/typed/batch/v1beta1/fake" + certificatesv1 "k8s.io/client-go/kubernetes/typed/certificates/v1" + fakecertificatesv1 "k8s.io/client-go/kubernetes/typed/certificates/v1/fake" + certificatesv1beta1 "k8s.io/client-go/kubernetes/typed/certificates/v1beta1" + fakecertificatesv1beta1 "k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake" + coordinationv1 "k8s.io/client-go/kubernetes/typed/coordination/v1" + fakecoordinationv1 "k8s.io/client-go/kubernetes/typed/coordination/v1/fake" + coordinationv1beta1 "k8s.io/client-go/kubernetes/typed/coordination/v1beta1" + fakecoordinationv1beta1 "k8s.io/client-go/kubernetes/typed/coordination/v1beta1/fake" + corev1 "k8s.io/client-go/kubernetes/typed/core/v1" + fakecorev1 "k8s.io/client-go/kubernetes/typed/core/v1/fake" + discoveryv1 "k8s.io/client-go/kubernetes/typed/discovery/v1" + fakediscoveryv1 "k8s.io/client-go/kubernetes/typed/discovery/v1/fake" + discoveryv1beta1 "k8s.io/client-go/kubernetes/typed/discovery/v1beta1" + fakediscoveryv1beta1 "k8s.io/client-go/kubernetes/typed/discovery/v1beta1/fake" + eventsv1 "k8s.io/client-go/kubernetes/typed/events/v1" + fakeeventsv1 "k8s.io/client-go/kubernetes/typed/events/v1/fake" + eventsv1beta1 "k8s.io/client-go/kubernetes/typed/events/v1beta1" + fakeeventsv1beta1 "k8s.io/client-go/kubernetes/typed/events/v1beta1/fake" + extensionsv1beta1 "k8s.io/client-go/kubernetes/typed/extensions/v1beta1" + fakeextensionsv1beta1 "k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake" + flowcontrolv1alpha1 "k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1" + fakeflowcontrolv1alpha1 "k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1/fake" + flowcontrolv1beta1 "k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1" + fakeflowcontrolv1beta1 "k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1/fake" + flowcontrolv1beta2 "k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2" + fakeflowcontrolv1beta2 "k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2/fake" + flowcontrolv1beta3 "k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3" + fakeflowcontrolv1beta3 "k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3/fake" + networkingv1 "k8s.io/client-go/kubernetes/typed/networking/v1" + fakenetworkingv1 "k8s.io/client-go/kubernetes/typed/networking/v1/fake" + networkingv1alpha1 "k8s.io/client-go/kubernetes/typed/networking/v1alpha1" + fakenetworkingv1alpha1 "k8s.io/client-go/kubernetes/typed/networking/v1alpha1/fake" + networkingv1beta1 "k8s.io/client-go/kubernetes/typed/networking/v1beta1" + fakenetworkingv1beta1 "k8s.io/client-go/kubernetes/typed/networking/v1beta1/fake" + nodev1 "k8s.io/client-go/kubernetes/typed/node/v1" + fakenodev1 "k8s.io/client-go/kubernetes/typed/node/v1/fake" + nodev1alpha1 "k8s.io/client-go/kubernetes/typed/node/v1alpha1" + fakenodev1alpha1 "k8s.io/client-go/kubernetes/typed/node/v1alpha1/fake" + nodev1beta1 "k8s.io/client-go/kubernetes/typed/node/v1beta1" + fakenodev1beta1 "k8s.io/client-go/kubernetes/typed/node/v1beta1/fake" + policyv1 "k8s.io/client-go/kubernetes/typed/policy/v1" + fakepolicyv1 "k8s.io/client-go/kubernetes/typed/policy/v1/fake" + policyv1beta1 "k8s.io/client-go/kubernetes/typed/policy/v1beta1" + fakepolicyv1beta1 "k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake" + rbacv1 "k8s.io/client-go/kubernetes/typed/rbac/v1" + fakerbacv1 "k8s.io/client-go/kubernetes/typed/rbac/v1/fake" + rbacv1alpha1 "k8s.io/client-go/kubernetes/typed/rbac/v1alpha1" + fakerbacv1alpha1 "k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake" + rbacv1beta1 "k8s.io/client-go/kubernetes/typed/rbac/v1beta1" + fakerbacv1beta1 "k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake" + resourcev1alpha1 "k8s.io/client-go/kubernetes/typed/resource/v1alpha1" + fakeresourcev1alpha1 "k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake" + schedulingv1 "k8s.io/client-go/kubernetes/typed/scheduling/v1" + fakeschedulingv1 "k8s.io/client-go/kubernetes/typed/scheduling/v1/fake" + schedulingv1alpha1 "k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1" + fakeschedulingv1alpha1 "k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1/fake" + schedulingv1beta1 "k8s.io/client-go/kubernetes/typed/scheduling/v1beta1" + fakeschedulingv1beta1 "k8s.io/client-go/kubernetes/typed/scheduling/v1beta1/fake" + storagev1 "k8s.io/client-go/kubernetes/typed/storage/v1" + fakestoragev1 "k8s.io/client-go/kubernetes/typed/storage/v1/fake" + storagev1alpha1 "k8s.io/client-go/kubernetes/typed/storage/v1alpha1" + fakestoragev1alpha1 "k8s.io/client-go/kubernetes/typed/storage/v1alpha1/fake" + storagev1beta1 "k8s.io/client-go/kubernetes/typed/storage/v1beta1" + fakestoragev1beta1 "k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake" + "k8s.io/client-go/testing" +) + +// NewSimpleClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +func NewSimpleClientset(objects ...runtime.Object) *Clientset { + o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{tracker: o} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +// Clientset implements clientset.Interface. Meant to be embedded into a +// struct to get a default implementation. This makes faking out just the method +// you want to test easier. +type Clientset struct { + testing.Fake + discovery *fakediscovery.FakeDiscovery + tracker testing.ObjectTracker +} + +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + return c.discovery +} + +func (c *Clientset) Tracker() testing.ObjectTracker { + return c.tracker +} + +var ( + _ clientset.Interface = &Clientset{} + _ testing.FakeClient = &Clientset{} +) + +// AdmissionregistrationV1 retrieves the AdmissionregistrationV1Client +func (c *Clientset) AdmissionregistrationV1() admissionregistrationv1.AdmissionregistrationV1Interface { + return &fakeadmissionregistrationv1.FakeAdmissionregistrationV1{Fake: &c.Fake} +} + +// AdmissionregistrationV1alpha1 retrieves the AdmissionregistrationV1alpha1Client +func (c *Clientset) AdmissionregistrationV1alpha1() admissionregistrationv1alpha1.AdmissionregistrationV1alpha1Interface { + return &fakeadmissionregistrationv1alpha1.FakeAdmissionregistrationV1alpha1{Fake: &c.Fake} +} + +// AdmissionregistrationV1beta1 retrieves the AdmissionregistrationV1beta1Client +func (c *Clientset) AdmissionregistrationV1beta1() admissionregistrationv1beta1.AdmissionregistrationV1beta1Interface { + return &fakeadmissionregistrationv1beta1.FakeAdmissionregistrationV1beta1{Fake: &c.Fake} +} + +// InternalV1alpha1 retrieves the InternalV1alpha1Client +func (c *Clientset) InternalV1alpha1() internalv1alpha1.InternalV1alpha1Interface { + return &fakeinternalv1alpha1.FakeInternalV1alpha1{Fake: &c.Fake} +} + +// AppsV1 retrieves the AppsV1Client +func (c *Clientset) AppsV1() appsv1.AppsV1Interface { + return &fakeappsv1.FakeAppsV1{Fake: &c.Fake} +} + +// AppsV1beta1 retrieves the AppsV1beta1Client +func (c *Clientset) AppsV1beta1() appsv1beta1.AppsV1beta1Interface { + return &fakeappsv1beta1.FakeAppsV1beta1{Fake: &c.Fake} +} + +// AppsV1beta2 retrieves the AppsV1beta2Client +func (c *Clientset) AppsV1beta2() appsv1beta2.AppsV1beta2Interface { + return &fakeappsv1beta2.FakeAppsV1beta2{Fake: &c.Fake} +} + +// AuthenticationV1 retrieves the AuthenticationV1Client +func (c *Clientset) AuthenticationV1() authenticationv1.AuthenticationV1Interface { + return &fakeauthenticationv1.FakeAuthenticationV1{Fake: &c.Fake} +} + +// AuthenticationV1alpha1 retrieves the AuthenticationV1alpha1Client +func (c *Clientset) AuthenticationV1alpha1() authenticationv1alpha1.AuthenticationV1alpha1Interface { + return &fakeauthenticationv1alpha1.FakeAuthenticationV1alpha1{Fake: &c.Fake} +} + +// AuthenticationV1beta1 retrieves the AuthenticationV1beta1Client +func (c *Clientset) AuthenticationV1beta1() authenticationv1beta1.AuthenticationV1beta1Interface { + return &fakeauthenticationv1beta1.FakeAuthenticationV1beta1{Fake: &c.Fake} +} + +// AuthorizationV1 retrieves the AuthorizationV1Client +func (c *Clientset) AuthorizationV1() authorizationv1.AuthorizationV1Interface { + return &fakeauthorizationv1.FakeAuthorizationV1{Fake: &c.Fake} +} + +// AuthorizationV1beta1 retrieves the AuthorizationV1beta1Client +func (c *Clientset) AuthorizationV1beta1() authorizationv1beta1.AuthorizationV1beta1Interface { + return &fakeauthorizationv1beta1.FakeAuthorizationV1beta1{Fake: &c.Fake} +} + +// AutoscalingV1 retrieves the AutoscalingV1Client +func (c *Clientset) AutoscalingV1() autoscalingv1.AutoscalingV1Interface { + return &fakeautoscalingv1.FakeAutoscalingV1{Fake: &c.Fake} +} + +// AutoscalingV2 retrieves the AutoscalingV2Client +func (c *Clientset) AutoscalingV2() autoscalingv2.AutoscalingV2Interface { + return &fakeautoscalingv2.FakeAutoscalingV2{Fake: &c.Fake} +} + +// AutoscalingV2beta1 retrieves the AutoscalingV2beta1Client +func (c *Clientset) AutoscalingV2beta1() autoscalingv2beta1.AutoscalingV2beta1Interface { + return &fakeautoscalingv2beta1.FakeAutoscalingV2beta1{Fake: &c.Fake} +} + +// AutoscalingV2beta2 retrieves the AutoscalingV2beta2Client +func (c *Clientset) AutoscalingV2beta2() autoscalingv2beta2.AutoscalingV2beta2Interface { + return &fakeautoscalingv2beta2.FakeAutoscalingV2beta2{Fake: &c.Fake} +} + +// BatchV1 retrieves the BatchV1Client +func (c *Clientset) BatchV1() batchv1.BatchV1Interface { + return &fakebatchv1.FakeBatchV1{Fake: &c.Fake} +} + +// BatchV1beta1 retrieves the BatchV1beta1Client +func (c *Clientset) BatchV1beta1() batchv1beta1.BatchV1beta1Interface { + return &fakebatchv1beta1.FakeBatchV1beta1{Fake: &c.Fake} +} + +// CertificatesV1 retrieves the CertificatesV1Client +func (c *Clientset) CertificatesV1() certificatesv1.CertificatesV1Interface { + return &fakecertificatesv1.FakeCertificatesV1{Fake: &c.Fake} +} + +// CertificatesV1beta1 retrieves the CertificatesV1beta1Client +func (c *Clientset) CertificatesV1beta1() certificatesv1beta1.CertificatesV1beta1Interface { + return &fakecertificatesv1beta1.FakeCertificatesV1beta1{Fake: &c.Fake} +} + +// CoordinationV1beta1 retrieves the CoordinationV1beta1Client +func (c *Clientset) CoordinationV1beta1() coordinationv1beta1.CoordinationV1beta1Interface { + return &fakecoordinationv1beta1.FakeCoordinationV1beta1{Fake: &c.Fake} +} + +// CoordinationV1 retrieves the CoordinationV1Client +func (c *Clientset) CoordinationV1() coordinationv1.CoordinationV1Interface { + return &fakecoordinationv1.FakeCoordinationV1{Fake: &c.Fake} +} + +// CoreV1 retrieves the CoreV1Client +func (c *Clientset) CoreV1() corev1.CoreV1Interface { + return &fakecorev1.FakeCoreV1{Fake: &c.Fake} +} + +// DiscoveryV1 retrieves the DiscoveryV1Client +func (c *Clientset) DiscoveryV1() discoveryv1.DiscoveryV1Interface { + return &fakediscoveryv1.FakeDiscoveryV1{Fake: &c.Fake} +} + +// DiscoveryV1beta1 retrieves the DiscoveryV1beta1Client +func (c *Clientset) DiscoveryV1beta1() discoveryv1beta1.DiscoveryV1beta1Interface { + return &fakediscoveryv1beta1.FakeDiscoveryV1beta1{Fake: &c.Fake} +} + +// EventsV1 retrieves the EventsV1Client +func (c *Clientset) EventsV1() eventsv1.EventsV1Interface { + return &fakeeventsv1.FakeEventsV1{Fake: &c.Fake} +} + +// EventsV1beta1 retrieves the EventsV1beta1Client +func (c *Clientset) EventsV1beta1() eventsv1beta1.EventsV1beta1Interface { + return &fakeeventsv1beta1.FakeEventsV1beta1{Fake: &c.Fake} +} + +// ExtensionsV1beta1 retrieves the ExtensionsV1beta1Client +func (c *Clientset) ExtensionsV1beta1() extensionsv1beta1.ExtensionsV1beta1Interface { + return &fakeextensionsv1beta1.FakeExtensionsV1beta1{Fake: &c.Fake} +} + +// FlowcontrolV1alpha1 retrieves the FlowcontrolV1alpha1Client +func (c *Clientset) FlowcontrolV1alpha1() flowcontrolv1alpha1.FlowcontrolV1alpha1Interface { + return &fakeflowcontrolv1alpha1.FakeFlowcontrolV1alpha1{Fake: &c.Fake} +} + +// FlowcontrolV1beta1 retrieves the FlowcontrolV1beta1Client +func (c *Clientset) FlowcontrolV1beta1() flowcontrolv1beta1.FlowcontrolV1beta1Interface { + return &fakeflowcontrolv1beta1.FakeFlowcontrolV1beta1{Fake: &c.Fake} +} + +// FlowcontrolV1beta2 retrieves the FlowcontrolV1beta2Client +func (c *Clientset) FlowcontrolV1beta2() flowcontrolv1beta2.FlowcontrolV1beta2Interface { + return &fakeflowcontrolv1beta2.FakeFlowcontrolV1beta2{Fake: &c.Fake} +} + +// FlowcontrolV1beta3 retrieves the FlowcontrolV1beta3Client +func (c *Clientset) FlowcontrolV1beta3() flowcontrolv1beta3.FlowcontrolV1beta3Interface { + return &fakeflowcontrolv1beta3.FakeFlowcontrolV1beta3{Fake: &c.Fake} +} + +// NetworkingV1 retrieves the NetworkingV1Client +func (c *Clientset) NetworkingV1() networkingv1.NetworkingV1Interface { + return &fakenetworkingv1.FakeNetworkingV1{Fake: &c.Fake} +} + +// NetworkingV1alpha1 retrieves the NetworkingV1alpha1Client +func (c *Clientset) NetworkingV1alpha1() networkingv1alpha1.NetworkingV1alpha1Interface { + return &fakenetworkingv1alpha1.FakeNetworkingV1alpha1{Fake: &c.Fake} +} + +// NetworkingV1beta1 retrieves the NetworkingV1beta1Client +func (c *Clientset) NetworkingV1beta1() networkingv1beta1.NetworkingV1beta1Interface { + return &fakenetworkingv1beta1.FakeNetworkingV1beta1{Fake: &c.Fake} +} + +// NodeV1 retrieves the NodeV1Client +func (c *Clientset) NodeV1() nodev1.NodeV1Interface { + return &fakenodev1.FakeNodeV1{Fake: &c.Fake} +} + +// NodeV1alpha1 retrieves the NodeV1alpha1Client +func (c *Clientset) NodeV1alpha1() nodev1alpha1.NodeV1alpha1Interface { + return &fakenodev1alpha1.FakeNodeV1alpha1{Fake: &c.Fake} +} + +// NodeV1beta1 retrieves the NodeV1beta1Client +func (c *Clientset) NodeV1beta1() nodev1beta1.NodeV1beta1Interface { + return &fakenodev1beta1.FakeNodeV1beta1{Fake: &c.Fake} +} + +// PolicyV1 retrieves the PolicyV1Client +func (c *Clientset) PolicyV1() policyv1.PolicyV1Interface { + return &fakepolicyv1.FakePolicyV1{Fake: &c.Fake} +} + +// PolicyV1beta1 retrieves the PolicyV1beta1Client +func (c *Clientset) PolicyV1beta1() policyv1beta1.PolicyV1beta1Interface { + return &fakepolicyv1beta1.FakePolicyV1beta1{Fake: &c.Fake} +} + +// RbacV1 retrieves the RbacV1Client +func (c *Clientset) RbacV1() rbacv1.RbacV1Interface { + return &fakerbacv1.FakeRbacV1{Fake: &c.Fake} +} + +// RbacV1beta1 retrieves the RbacV1beta1Client +func (c *Clientset) RbacV1beta1() rbacv1beta1.RbacV1beta1Interface { + return &fakerbacv1beta1.FakeRbacV1beta1{Fake: &c.Fake} +} + +// RbacV1alpha1 retrieves the RbacV1alpha1Client +func (c *Clientset) RbacV1alpha1() rbacv1alpha1.RbacV1alpha1Interface { + return &fakerbacv1alpha1.FakeRbacV1alpha1{Fake: &c.Fake} +} + +// ResourceV1alpha1 retrieves the ResourceV1alpha1Client +func (c *Clientset) ResourceV1alpha1() resourcev1alpha1.ResourceV1alpha1Interface { + return &fakeresourcev1alpha1.FakeResourceV1alpha1{Fake: &c.Fake} +} + +// SchedulingV1alpha1 retrieves the SchedulingV1alpha1Client +func (c *Clientset) SchedulingV1alpha1() schedulingv1alpha1.SchedulingV1alpha1Interface { + return &fakeschedulingv1alpha1.FakeSchedulingV1alpha1{Fake: &c.Fake} +} + +// SchedulingV1beta1 retrieves the SchedulingV1beta1Client +func (c *Clientset) SchedulingV1beta1() schedulingv1beta1.SchedulingV1beta1Interface { + return &fakeschedulingv1beta1.FakeSchedulingV1beta1{Fake: &c.Fake} +} + +// SchedulingV1 retrieves the SchedulingV1Client +func (c *Clientset) SchedulingV1() schedulingv1.SchedulingV1Interface { + return &fakeschedulingv1.FakeSchedulingV1{Fake: &c.Fake} +} + +// StorageV1beta1 retrieves the StorageV1beta1Client +func (c *Clientset) StorageV1beta1() storagev1beta1.StorageV1beta1Interface { + return &fakestoragev1beta1.FakeStorageV1beta1{Fake: &c.Fake} +} + +// StorageV1 retrieves the StorageV1Client +func (c *Clientset) StorageV1() storagev1.StorageV1Interface { + return &fakestoragev1.FakeStorageV1{Fake: &c.Fake} +} + +// StorageV1alpha1 retrieves the StorageV1alpha1Client +func (c *Clientset) StorageV1alpha1() storagev1alpha1.StorageV1alpha1Interface { + return &fakestoragev1alpha1.FakeStorageV1alpha1{Fake: &c.Fake} +} diff --git a/vendor/k8s.io/client-go/kubernetes/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/fake/doc.go new file mode 100644 index 000000000..9b99e7167 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated fake clientset. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/fake/register.go b/vendor/k8s.io/client-go/kubernetes/fake/register.go new file mode 100644 index 000000000..30f42e25d --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/fake/register.go @@ -0,0 +1,154 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + admissionregistrationv1 "k8s.io/api/admissionregistration/v1" + admissionregistrationv1alpha1 "k8s.io/api/admissionregistration/v1alpha1" + admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" + internalv1alpha1 "k8s.io/api/apiserverinternal/v1alpha1" + appsv1 "k8s.io/api/apps/v1" + appsv1beta1 "k8s.io/api/apps/v1beta1" + appsv1beta2 "k8s.io/api/apps/v1beta2" + authenticationv1 "k8s.io/api/authentication/v1" + authenticationv1alpha1 "k8s.io/api/authentication/v1alpha1" + authenticationv1beta1 "k8s.io/api/authentication/v1beta1" + authorizationv1 "k8s.io/api/authorization/v1" + authorizationv1beta1 "k8s.io/api/authorization/v1beta1" + autoscalingv1 "k8s.io/api/autoscaling/v1" + autoscalingv2 "k8s.io/api/autoscaling/v2" + autoscalingv2beta1 "k8s.io/api/autoscaling/v2beta1" + autoscalingv2beta2 "k8s.io/api/autoscaling/v2beta2" + batchv1 "k8s.io/api/batch/v1" + batchv1beta1 "k8s.io/api/batch/v1beta1" + certificatesv1 "k8s.io/api/certificates/v1" + certificatesv1beta1 "k8s.io/api/certificates/v1beta1" + coordinationv1 "k8s.io/api/coordination/v1" + coordinationv1beta1 "k8s.io/api/coordination/v1beta1" + corev1 "k8s.io/api/core/v1" + discoveryv1 "k8s.io/api/discovery/v1" + discoveryv1beta1 "k8s.io/api/discovery/v1beta1" + eventsv1 "k8s.io/api/events/v1" + eventsv1beta1 "k8s.io/api/events/v1beta1" + extensionsv1beta1 "k8s.io/api/extensions/v1beta1" + flowcontrolv1alpha1 "k8s.io/api/flowcontrol/v1alpha1" + flowcontrolv1beta1 "k8s.io/api/flowcontrol/v1beta1" + flowcontrolv1beta2 "k8s.io/api/flowcontrol/v1beta2" + flowcontrolv1beta3 "k8s.io/api/flowcontrol/v1beta3" + networkingv1 "k8s.io/api/networking/v1" + networkingv1alpha1 "k8s.io/api/networking/v1alpha1" + networkingv1beta1 "k8s.io/api/networking/v1beta1" + nodev1 "k8s.io/api/node/v1" + nodev1alpha1 "k8s.io/api/node/v1alpha1" + nodev1beta1 "k8s.io/api/node/v1beta1" + policyv1 "k8s.io/api/policy/v1" + policyv1beta1 "k8s.io/api/policy/v1beta1" + rbacv1 "k8s.io/api/rbac/v1" + rbacv1alpha1 "k8s.io/api/rbac/v1alpha1" + rbacv1beta1 "k8s.io/api/rbac/v1beta1" + resourcev1alpha1 "k8s.io/api/resource/v1alpha1" + schedulingv1 "k8s.io/api/scheduling/v1" + schedulingv1alpha1 "k8s.io/api/scheduling/v1alpha1" + schedulingv1beta1 "k8s.io/api/scheduling/v1beta1" + storagev1 "k8s.io/api/storage/v1" + storagev1alpha1 "k8s.io/api/storage/v1alpha1" + storagev1beta1 "k8s.io/api/storage/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" +) + +var scheme = runtime.NewScheme() +var codecs = serializer.NewCodecFactory(scheme) + +var localSchemeBuilder = runtime.SchemeBuilder{ + admissionregistrationv1.AddToScheme, + admissionregistrationv1alpha1.AddToScheme, + admissionregistrationv1beta1.AddToScheme, + internalv1alpha1.AddToScheme, + appsv1.AddToScheme, + appsv1beta1.AddToScheme, + appsv1beta2.AddToScheme, + authenticationv1.AddToScheme, + authenticationv1alpha1.AddToScheme, + authenticationv1beta1.AddToScheme, + authorizationv1.AddToScheme, + authorizationv1beta1.AddToScheme, + autoscalingv1.AddToScheme, + autoscalingv2.AddToScheme, + autoscalingv2beta1.AddToScheme, + autoscalingv2beta2.AddToScheme, + batchv1.AddToScheme, + batchv1beta1.AddToScheme, + certificatesv1.AddToScheme, + certificatesv1beta1.AddToScheme, + coordinationv1beta1.AddToScheme, + coordinationv1.AddToScheme, + corev1.AddToScheme, + discoveryv1.AddToScheme, + discoveryv1beta1.AddToScheme, + eventsv1.AddToScheme, + eventsv1beta1.AddToScheme, + extensionsv1beta1.AddToScheme, + flowcontrolv1alpha1.AddToScheme, + flowcontrolv1beta1.AddToScheme, + flowcontrolv1beta2.AddToScheme, + flowcontrolv1beta3.AddToScheme, + networkingv1.AddToScheme, + networkingv1alpha1.AddToScheme, + networkingv1beta1.AddToScheme, + nodev1.AddToScheme, + nodev1alpha1.AddToScheme, + nodev1beta1.AddToScheme, + policyv1.AddToScheme, + policyv1beta1.AddToScheme, + rbacv1.AddToScheme, + rbacv1beta1.AddToScheme, + rbacv1alpha1.AddToScheme, + resourcev1alpha1.AddToScheme, + schedulingv1alpha1.AddToScheme, + schedulingv1beta1.AddToScheme, + schedulingv1.AddToScheme, + storagev1beta1.AddToScheme, + storagev1.AddToScheme, + storagev1alpha1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(scheme)) +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1/fake/fake_admissionregistration_client.go b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1/fake/fake_admissionregistration_client.go new file mode 100644 index 000000000..a5a570ad1 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1/fake/fake_admissionregistration_client.go @@ -0,0 +1,44 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeAdmissionregistrationV1 struct { + *testing.Fake +} + +func (c *FakeAdmissionregistrationV1) MutatingWebhookConfigurations() v1.MutatingWebhookConfigurationInterface { + return &FakeMutatingWebhookConfigurations{c} +} + +func (c *FakeAdmissionregistrationV1) ValidatingWebhookConfigurations() v1.ValidatingWebhookConfigurationInterface { + return &FakeValidatingWebhookConfigurations{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeAdmissionregistrationV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1/fake/fake_mutatingwebhookconfiguration.go b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1/fake/fake_mutatingwebhookconfiguration.go new file mode 100644 index 000000000..bbd4cf007 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1/fake/fake_mutatingwebhookconfiguration.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + admissionregistrationv1 "k8s.io/api/admissionregistration/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsadmissionregistrationv1 "k8s.io/client-go/applyconfigurations/admissionregistration/v1" + testing "k8s.io/client-go/testing" +) + +// FakeMutatingWebhookConfigurations implements MutatingWebhookConfigurationInterface +type FakeMutatingWebhookConfigurations struct { + Fake *FakeAdmissionregistrationV1 +} + +var mutatingwebhookconfigurationsResource = schema.GroupVersionResource{Group: "admissionregistration.k8s.io", Version: "v1", Resource: "mutatingwebhookconfigurations"} + +var mutatingwebhookconfigurationsKind = schema.GroupVersionKind{Group: "admissionregistration.k8s.io", Version: "v1", Kind: "MutatingWebhookConfiguration"} + +// Get takes name of the mutatingWebhookConfiguration, and returns the corresponding mutatingWebhookConfiguration object, and an error if there is any. +func (c *FakeMutatingWebhookConfigurations) Get(ctx context.Context, name string, options v1.GetOptions) (result *admissionregistrationv1.MutatingWebhookConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(mutatingwebhookconfigurationsResource, name), &admissionregistrationv1.MutatingWebhookConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*admissionregistrationv1.MutatingWebhookConfiguration), err +} + +// List takes label and field selectors, and returns the list of MutatingWebhookConfigurations that match those selectors. +func (c *FakeMutatingWebhookConfigurations) List(ctx context.Context, opts v1.ListOptions) (result *admissionregistrationv1.MutatingWebhookConfigurationList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(mutatingwebhookconfigurationsResource, mutatingwebhookconfigurationsKind, opts), &admissionregistrationv1.MutatingWebhookConfigurationList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &admissionregistrationv1.MutatingWebhookConfigurationList{ListMeta: obj.(*admissionregistrationv1.MutatingWebhookConfigurationList).ListMeta} + for _, item := range obj.(*admissionregistrationv1.MutatingWebhookConfigurationList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested mutatingWebhookConfigurations. +func (c *FakeMutatingWebhookConfigurations) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(mutatingwebhookconfigurationsResource, opts)) +} + +// Create takes the representation of a mutatingWebhookConfiguration and creates it. Returns the server's representation of the mutatingWebhookConfiguration, and an error, if there is any. +func (c *FakeMutatingWebhookConfigurations) Create(ctx context.Context, mutatingWebhookConfiguration *admissionregistrationv1.MutatingWebhookConfiguration, opts v1.CreateOptions) (result *admissionregistrationv1.MutatingWebhookConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(mutatingwebhookconfigurationsResource, mutatingWebhookConfiguration), &admissionregistrationv1.MutatingWebhookConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*admissionregistrationv1.MutatingWebhookConfiguration), err +} + +// Update takes the representation of a mutatingWebhookConfiguration and updates it. Returns the server's representation of the mutatingWebhookConfiguration, and an error, if there is any. +func (c *FakeMutatingWebhookConfigurations) Update(ctx context.Context, mutatingWebhookConfiguration *admissionregistrationv1.MutatingWebhookConfiguration, opts v1.UpdateOptions) (result *admissionregistrationv1.MutatingWebhookConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(mutatingwebhookconfigurationsResource, mutatingWebhookConfiguration), &admissionregistrationv1.MutatingWebhookConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*admissionregistrationv1.MutatingWebhookConfiguration), err +} + +// Delete takes name of the mutatingWebhookConfiguration and deletes it. Returns an error if one occurs. +func (c *FakeMutatingWebhookConfigurations) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(mutatingwebhookconfigurationsResource, name, opts), &admissionregistrationv1.MutatingWebhookConfiguration{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeMutatingWebhookConfigurations) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(mutatingwebhookconfigurationsResource, listOpts) + + _, err := c.Fake.Invokes(action, &admissionregistrationv1.MutatingWebhookConfigurationList{}) + return err +} + +// Patch applies the patch and returns the patched mutatingWebhookConfiguration. +func (c *FakeMutatingWebhookConfigurations) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *admissionregistrationv1.MutatingWebhookConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(mutatingwebhookconfigurationsResource, name, pt, data, subresources...), &admissionregistrationv1.MutatingWebhookConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*admissionregistrationv1.MutatingWebhookConfiguration), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied mutatingWebhookConfiguration. +func (c *FakeMutatingWebhookConfigurations) Apply(ctx context.Context, mutatingWebhookConfiguration *applyconfigurationsadmissionregistrationv1.MutatingWebhookConfigurationApplyConfiguration, opts v1.ApplyOptions) (result *admissionregistrationv1.MutatingWebhookConfiguration, err error) { + if mutatingWebhookConfiguration == nil { + return nil, fmt.Errorf("mutatingWebhookConfiguration provided to Apply must not be nil") + } + data, err := json.Marshal(mutatingWebhookConfiguration) + if err != nil { + return nil, err + } + name := mutatingWebhookConfiguration.Name + if name == nil { + return nil, fmt.Errorf("mutatingWebhookConfiguration.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(mutatingwebhookconfigurationsResource, *name, types.ApplyPatchType, data), &admissionregistrationv1.MutatingWebhookConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*admissionregistrationv1.MutatingWebhookConfiguration), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1/fake/fake_validatingwebhookconfiguration.go b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1/fake/fake_validatingwebhookconfiguration.go new file mode 100644 index 000000000..ee769dd3c --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1/fake/fake_validatingwebhookconfiguration.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + admissionregistrationv1 "k8s.io/api/admissionregistration/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsadmissionregistrationv1 "k8s.io/client-go/applyconfigurations/admissionregistration/v1" + testing "k8s.io/client-go/testing" +) + +// FakeValidatingWebhookConfigurations implements ValidatingWebhookConfigurationInterface +type FakeValidatingWebhookConfigurations struct { + Fake *FakeAdmissionregistrationV1 +} + +var validatingwebhookconfigurationsResource = schema.GroupVersionResource{Group: "admissionregistration.k8s.io", Version: "v1", Resource: "validatingwebhookconfigurations"} + +var validatingwebhookconfigurationsKind = schema.GroupVersionKind{Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingWebhookConfiguration"} + +// Get takes name of the validatingWebhookConfiguration, and returns the corresponding validatingWebhookConfiguration object, and an error if there is any. +func (c *FakeValidatingWebhookConfigurations) Get(ctx context.Context, name string, options v1.GetOptions) (result *admissionregistrationv1.ValidatingWebhookConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(validatingwebhookconfigurationsResource, name), &admissionregistrationv1.ValidatingWebhookConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*admissionregistrationv1.ValidatingWebhookConfiguration), err +} + +// List takes label and field selectors, and returns the list of ValidatingWebhookConfigurations that match those selectors. +func (c *FakeValidatingWebhookConfigurations) List(ctx context.Context, opts v1.ListOptions) (result *admissionregistrationv1.ValidatingWebhookConfigurationList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(validatingwebhookconfigurationsResource, validatingwebhookconfigurationsKind, opts), &admissionregistrationv1.ValidatingWebhookConfigurationList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &admissionregistrationv1.ValidatingWebhookConfigurationList{ListMeta: obj.(*admissionregistrationv1.ValidatingWebhookConfigurationList).ListMeta} + for _, item := range obj.(*admissionregistrationv1.ValidatingWebhookConfigurationList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested validatingWebhookConfigurations. +func (c *FakeValidatingWebhookConfigurations) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(validatingwebhookconfigurationsResource, opts)) +} + +// Create takes the representation of a validatingWebhookConfiguration and creates it. Returns the server's representation of the validatingWebhookConfiguration, and an error, if there is any. +func (c *FakeValidatingWebhookConfigurations) Create(ctx context.Context, validatingWebhookConfiguration *admissionregistrationv1.ValidatingWebhookConfiguration, opts v1.CreateOptions) (result *admissionregistrationv1.ValidatingWebhookConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(validatingwebhookconfigurationsResource, validatingWebhookConfiguration), &admissionregistrationv1.ValidatingWebhookConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*admissionregistrationv1.ValidatingWebhookConfiguration), err +} + +// Update takes the representation of a validatingWebhookConfiguration and updates it. Returns the server's representation of the validatingWebhookConfiguration, and an error, if there is any. +func (c *FakeValidatingWebhookConfigurations) Update(ctx context.Context, validatingWebhookConfiguration *admissionregistrationv1.ValidatingWebhookConfiguration, opts v1.UpdateOptions) (result *admissionregistrationv1.ValidatingWebhookConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(validatingwebhookconfigurationsResource, validatingWebhookConfiguration), &admissionregistrationv1.ValidatingWebhookConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*admissionregistrationv1.ValidatingWebhookConfiguration), err +} + +// Delete takes name of the validatingWebhookConfiguration and deletes it. Returns an error if one occurs. +func (c *FakeValidatingWebhookConfigurations) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(validatingwebhookconfigurationsResource, name, opts), &admissionregistrationv1.ValidatingWebhookConfiguration{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeValidatingWebhookConfigurations) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(validatingwebhookconfigurationsResource, listOpts) + + _, err := c.Fake.Invokes(action, &admissionregistrationv1.ValidatingWebhookConfigurationList{}) + return err +} + +// Patch applies the patch and returns the patched validatingWebhookConfiguration. +func (c *FakeValidatingWebhookConfigurations) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *admissionregistrationv1.ValidatingWebhookConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(validatingwebhookconfigurationsResource, name, pt, data, subresources...), &admissionregistrationv1.ValidatingWebhookConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*admissionregistrationv1.ValidatingWebhookConfiguration), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied validatingWebhookConfiguration. +func (c *FakeValidatingWebhookConfigurations) Apply(ctx context.Context, validatingWebhookConfiguration *applyconfigurationsadmissionregistrationv1.ValidatingWebhookConfigurationApplyConfiguration, opts v1.ApplyOptions) (result *admissionregistrationv1.ValidatingWebhookConfiguration, err error) { + if validatingWebhookConfiguration == nil { + return nil, fmt.Errorf("validatingWebhookConfiguration provided to Apply must not be nil") + } + data, err := json.Marshal(validatingWebhookConfiguration) + if err != nil { + return nil, err + } + name := validatingWebhookConfiguration.Name + if name == nil { + return nil, fmt.Errorf("validatingWebhookConfiguration.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(validatingwebhookconfigurationsResource, *name, types.ApplyPatchType, data), &admissionregistrationv1.ValidatingWebhookConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*admissionregistrationv1.ValidatingWebhookConfiguration), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake/fake_admissionregistration_client.go b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake/fake_admissionregistration_client.go new file mode 100644 index 000000000..dc0e30ca4 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake/fake_admissionregistration_client.go @@ -0,0 +1,44 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeAdmissionregistrationV1alpha1 struct { + *testing.Fake +} + +func (c *FakeAdmissionregistrationV1alpha1) ValidatingAdmissionPolicies() v1alpha1.ValidatingAdmissionPolicyInterface { + return &FakeValidatingAdmissionPolicies{c} +} + +func (c *FakeAdmissionregistrationV1alpha1) ValidatingAdmissionPolicyBindings() v1alpha1.ValidatingAdmissionPolicyBindingInterface { + return &FakeValidatingAdmissionPolicyBindings{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeAdmissionregistrationV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake/fake_validatingadmissionpolicy.go b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake/fake_validatingadmissionpolicy.go new file mode 100644 index 000000000..2fed66b44 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake/fake_validatingadmissionpolicy.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1alpha1 "k8s.io/api/admissionregistration/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + admissionregistrationv1alpha1 "k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1" + testing "k8s.io/client-go/testing" +) + +// FakeValidatingAdmissionPolicies implements ValidatingAdmissionPolicyInterface +type FakeValidatingAdmissionPolicies struct { + Fake *FakeAdmissionregistrationV1alpha1 +} + +var validatingadmissionpoliciesResource = schema.GroupVersionResource{Group: "admissionregistration.k8s.io", Version: "v1alpha1", Resource: "validatingadmissionpolicies"} + +var validatingadmissionpoliciesKind = schema.GroupVersionKind{Group: "admissionregistration.k8s.io", Version: "v1alpha1", Kind: "ValidatingAdmissionPolicy"} + +// Get takes name of the validatingAdmissionPolicy, and returns the corresponding validatingAdmissionPolicy object, and an error if there is any. +func (c *FakeValidatingAdmissionPolicies) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ValidatingAdmissionPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(validatingadmissionpoliciesResource, name), &v1alpha1.ValidatingAdmissionPolicy{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ValidatingAdmissionPolicy), err +} + +// List takes label and field selectors, and returns the list of ValidatingAdmissionPolicies that match those selectors. +func (c *FakeValidatingAdmissionPolicies) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ValidatingAdmissionPolicyList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(validatingadmissionpoliciesResource, validatingadmissionpoliciesKind, opts), &v1alpha1.ValidatingAdmissionPolicyList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.ValidatingAdmissionPolicyList{ListMeta: obj.(*v1alpha1.ValidatingAdmissionPolicyList).ListMeta} + for _, item := range obj.(*v1alpha1.ValidatingAdmissionPolicyList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested validatingAdmissionPolicies. +func (c *FakeValidatingAdmissionPolicies) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(validatingadmissionpoliciesResource, opts)) +} + +// Create takes the representation of a validatingAdmissionPolicy and creates it. Returns the server's representation of the validatingAdmissionPolicy, and an error, if there is any. +func (c *FakeValidatingAdmissionPolicies) Create(ctx context.Context, validatingAdmissionPolicy *v1alpha1.ValidatingAdmissionPolicy, opts v1.CreateOptions) (result *v1alpha1.ValidatingAdmissionPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(validatingadmissionpoliciesResource, validatingAdmissionPolicy), &v1alpha1.ValidatingAdmissionPolicy{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ValidatingAdmissionPolicy), err +} + +// Update takes the representation of a validatingAdmissionPolicy and updates it. Returns the server's representation of the validatingAdmissionPolicy, and an error, if there is any. +func (c *FakeValidatingAdmissionPolicies) Update(ctx context.Context, validatingAdmissionPolicy *v1alpha1.ValidatingAdmissionPolicy, opts v1.UpdateOptions) (result *v1alpha1.ValidatingAdmissionPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(validatingadmissionpoliciesResource, validatingAdmissionPolicy), &v1alpha1.ValidatingAdmissionPolicy{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ValidatingAdmissionPolicy), err +} + +// Delete takes name of the validatingAdmissionPolicy and deletes it. Returns an error if one occurs. +func (c *FakeValidatingAdmissionPolicies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(validatingadmissionpoliciesResource, name, opts), &v1alpha1.ValidatingAdmissionPolicy{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeValidatingAdmissionPolicies) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(validatingadmissionpoliciesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.ValidatingAdmissionPolicyList{}) + return err +} + +// Patch applies the patch and returns the patched validatingAdmissionPolicy. +func (c *FakeValidatingAdmissionPolicies) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ValidatingAdmissionPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(validatingadmissionpoliciesResource, name, pt, data, subresources...), &v1alpha1.ValidatingAdmissionPolicy{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ValidatingAdmissionPolicy), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied validatingAdmissionPolicy. +func (c *FakeValidatingAdmissionPolicies) Apply(ctx context.Context, validatingAdmissionPolicy *admissionregistrationv1alpha1.ValidatingAdmissionPolicyApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.ValidatingAdmissionPolicy, err error) { + if validatingAdmissionPolicy == nil { + return nil, fmt.Errorf("validatingAdmissionPolicy provided to Apply must not be nil") + } + data, err := json.Marshal(validatingAdmissionPolicy) + if err != nil { + return nil, err + } + name := validatingAdmissionPolicy.Name + if name == nil { + return nil, fmt.Errorf("validatingAdmissionPolicy.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(validatingadmissionpoliciesResource, *name, types.ApplyPatchType, data), &v1alpha1.ValidatingAdmissionPolicy{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ValidatingAdmissionPolicy), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake/fake_validatingadmissionpolicybinding.go b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake/fake_validatingadmissionpolicybinding.go new file mode 100644 index 000000000..7c9cb88aa --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake/fake_validatingadmissionpolicybinding.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1alpha1 "k8s.io/api/admissionregistration/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + admissionregistrationv1alpha1 "k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1" + testing "k8s.io/client-go/testing" +) + +// FakeValidatingAdmissionPolicyBindings implements ValidatingAdmissionPolicyBindingInterface +type FakeValidatingAdmissionPolicyBindings struct { + Fake *FakeAdmissionregistrationV1alpha1 +} + +var validatingadmissionpolicybindingsResource = schema.GroupVersionResource{Group: "admissionregistration.k8s.io", Version: "v1alpha1", Resource: "validatingadmissionpolicybindings"} + +var validatingadmissionpolicybindingsKind = schema.GroupVersionKind{Group: "admissionregistration.k8s.io", Version: "v1alpha1", Kind: "ValidatingAdmissionPolicyBinding"} + +// Get takes name of the validatingAdmissionPolicyBinding, and returns the corresponding validatingAdmissionPolicyBinding object, and an error if there is any. +func (c *FakeValidatingAdmissionPolicyBindings) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ValidatingAdmissionPolicyBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(validatingadmissionpolicybindingsResource, name), &v1alpha1.ValidatingAdmissionPolicyBinding{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ValidatingAdmissionPolicyBinding), err +} + +// List takes label and field selectors, and returns the list of ValidatingAdmissionPolicyBindings that match those selectors. +func (c *FakeValidatingAdmissionPolicyBindings) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ValidatingAdmissionPolicyBindingList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(validatingadmissionpolicybindingsResource, validatingadmissionpolicybindingsKind, opts), &v1alpha1.ValidatingAdmissionPolicyBindingList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.ValidatingAdmissionPolicyBindingList{ListMeta: obj.(*v1alpha1.ValidatingAdmissionPolicyBindingList).ListMeta} + for _, item := range obj.(*v1alpha1.ValidatingAdmissionPolicyBindingList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested validatingAdmissionPolicyBindings. +func (c *FakeValidatingAdmissionPolicyBindings) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(validatingadmissionpolicybindingsResource, opts)) +} + +// Create takes the representation of a validatingAdmissionPolicyBinding and creates it. Returns the server's representation of the validatingAdmissionPolicyBinding, and an error, if there is any. +func (c *FakeValidatingAdmissionPolicyBindings) Create(ctx context.Context, validatingAdmissionPolicyBinding *v1alpha1.ValidatingAdmissionPolicyBinding, opts v1.CreateOptions) (result *v1alpha1.ValidatingAdmissionPolicyBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(validatingadmissionpolicybindingsResource, validatingAdmissionPolicyBinding), &v1alpha1.ValidatingAdmissionPolicyBinding{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ValidatingAdmissionPolicyBinding), err +} + +// Update takes the representation of a validatingAdmissionPolicyBinding and updates it. Returns the server's representation of the validatingAdmissionPolicyBinding, and an error, if there is any. +func (c *FakeValidatingAdmissionPolicyBindings) Update(ctx context.Context, validatingAdmissionPolicyBinding *v1alpha1.ValidatingAdmissionPolicyBinding, opts v1.UpdateOptions) (result *v1alpha1.ValidatingAdmissionPolicyBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(validatingadmissionpolicybindingsResource, validatingAdmissionPolicyBinding), &v1alpha1.ValidatingAdmissionPolicyBinding{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ValidatingAdmissionPolicyBinding), err +} + +// Delete takes name of the validatingAdmissionPolicyBinding and deletes it. Returns an error if one occurs. +func (c *FakeValidatingAdmissionPolicyBindings) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(validatingadmissionpolicybindingsResource, name, opts), &v1alpha1.ValidatingAdmissionPolicyBinding{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeValidatingAdmissionPolicyBindings) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(validatingadmissionpolicybindingsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.ValidatingAdmissionPolicyBindingList{}) + return err +} + +// Patch applies the patch and returns the patched validatingAdmissionPolicyBinding. +func (c *FakeValidatingAdmissionPolicyBindings) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ValidatingAdmissionPolicyBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(validatingadmissionpolicybindingsResource, name, pt, data, subresources...), &v1alpha1.ValidatingAdmissionPolicyBinding{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ValidatingAdmissionPolicyBinding), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied validatingAdmissionPolicyBinding. +func (c *FakeValidatingAdmissionPolicyBindings) Apply(ctx context.Context, validatingAdmissionPolicyBinding *admissionregistrationv1alpha1.ValidatingAdmissionPolicyBindingApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.ValidatingAdmissionPolicyBinding, err error) { + if validatingAdmissionPolicyBinding == nil { + return nil, fmt.Errorf("validatingAdmissionPolicyBinding provided to Apply must not be nil") + } + data, err := json.Marshal(validatingAdmissionPolicyBinding) + if err != nil { + return nil, err + } + name := validatingAdmissionPolicyBinding.Name + if name == nil { + return nil, fmt.Errorf("validatingAdmissionPolicyBinding.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(validatingadmissionpolicybindingsResource, *name, types.ApplyPatchType, data), &v1alpha1.ValidatingAdmissionPolicyBinding{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ValidatingAdmissionPolicyBinding), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/fake/fake_admissionregistration_client.go b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/fake/fake_admissionregistration_client.go new file mode 100644 index 000000000..1a988ddba --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/fake/fake_admissionregistration_client.go @@ -0,0 +1,44 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1beta1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeAdmissionregistrationV1beta1 struct { + *testing.Fake +} + +func (c *FakeAdmissionregistrationV1beta1) MutatingWebhookConfigurations() v1beta1.MutatingWebhookConfigurationInterface { + return &FakeMutatingWebhookConfigurations{c} +} + +func (c *FakeAdmissionregistrationV1beta1) ValidatingWebhookConfigurations() v1beta1.ValidatingWebhookConfigurationInterface { + return &FakeValidatingWebhookConfigurations{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeAdmissionregistrationV1beta1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/fake/fake_mutatingwebhookconfiguration.go b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/fake/fake_mutatingwebhookconfiguration.go new file mode 100644 index 000000000..a06bb7db1 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/fake/fake_mutatingwebhookconfiguration.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/admissionregistration/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + admissionregistrationv1beta1 "k8s.io/client-go/applyconfigurations/admissionregistration/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeMutatingWebhookConfigurations implements MutatingWebhookConfigurationInterface +type FakeMutatingWebhookConfigurations struct { + Fake *FakeAdmissionregistrationV1beta1 +} + +var mutatingwebhookconfigurationsResource = schema.GroupVersionResource{Group: "admissionregistration.k8s.io", Version: "v1beta1", Resource: "mutatingwebhookconfigurations"} + +var mutatingwebhookconfigurationsKind = schema.GroupVersionKind{Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "MutatingWebhookConfiguration"} + +// Get takes name of the mutatingWebhookConfiguration, and returns the corresponding mutatingWebhookConfiguration object, and an error if there is any. +func (c *FakeMutatingWebhookConfigurations) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.MutatingWebhookConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(mutatingwebhookconfigurationsResource, name), &v1beta1.MutatingWebhookConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.MutatingWebhookConfiguration), err +} + +// List takes label and field selectors, and returns the list of MutatingWebhookConfigurations that match those selectors. +func (c *FakeMutatingWebhookConfigurations) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.MutatingWebhookConfigurationList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(mutatingwebhookconfigurationsResource, mutatingwebhookconfigurationsKind, opts), &v1beta1.MutatingWebhookConfigurationList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.MutatingWebhookConfigurationList{ListMeta: obj.(*v1beta1.MutatingWebhookConfigurationList).ListMeta} + for _, item := range obj.(*v1beta1.MutatingWebhookConfigurationList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested mutatingWebhookConfigurations. +func (c *FakeMutatingWebhookConfigurations) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(mutatingwebhookconfigurationsResource, opts)) +} + +// Create takes the representation of a mutatingWebhookConfiguration and creates it. Returns the server's representation of the mutatingWebhookConfiguration, and an error, if there is any. +func (c *FakeMutatingWebhookConfigurations) Create(ctx context.Context, mutatingWebhookConfiguration *v1beta1.MutatingWebhookConfiguration, opts v1.CreateOptions) (result *v1beta1.MutatingWebhookConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(mutatingwebhookconfigurationsResource, mutatingWebhookConfiguration), &v1beta1.MutatingWebhookConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.MutatingWebhookConfiguration), err +} + +// Update takes the representation of a mutatingWebhookConfiguration and updates it. Returns the server's representation of the mutatingWebhookConfiguration, and an error, if there is any. +func (c *FakeMutatingWebhookConfigurations) Update(ctx context.Context, mutatingWebhookConfiguration *v1beta1.MutatingWebhookConfiguration, opts v1.UpdateOptions) (result *v1beta1.MutatingWebhookConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(mutatingwebhookconfigurationsResource, mutatingWebhookConfiguration), &v1beta1.MutatingWebhookConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.MutatingWebhookConfiguration), err +} + +// Delete takes name of the mutatingWebhookConfiguration and deletes it. Returns an error if one occurs. +func (c *FakeMutatingWebhookConfigurations) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(mutatingwebhookconfigurationsResource, name, opts), &v1beta1.MutatingWebhookConfiguration{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeMutatingWebhookConfigurations) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(mutatingwebhookconfigurationsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.MutatingWebhookConfigurationList{}) + return err +} + +// Patch applies the patch and returns the patched mutatingWebhookConfiguration. +func (c *FakeMutatingWebhookConfigurations) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.MutatingWebhookConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(mutatingwebhookconfigurationsResource, name, pt, data, subresources...), &v1beta1.MutatingWebhookConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.MutatingWebhookConfiguration), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied mutatingWebhookConfiguration. +func (c *FakeMutatingWebhookConfigurations) Apply(ctx context.Context, mutatingWebhookConfiguration *admissionregistrationv1beta1.MutatingWebhookConfigurationApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.MutatingWebhookConfiguration, err error) { + if mutatingWebhookConfiguration == nil { + return nil, fmt.Errorf("mutatingWebhookConfiguration provided to Apply must not be nil") + } + data, err := json.Marshal(mutatingWebhookConfiguration) + if err != nil { + return nil, err + } + name := mutatingWebhookConfiguration.Name + if name == nil { + return nil, fmt.Errorf("mutatingWebhookConfiguration.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(mutatingwebhookconfigurationsResource, *name, types.ApplyPatchType, data), &v1beta1.MutatingWebhookConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.MutatingWebhookConfiguration), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/fake/fake_validatingwebhookconfiguration.go b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/fake/fake_validatingwebhookconfiguration.go new file mode 100644 index 000000000..27495b31d --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/fake/fake_validatingwebhookconfiguration.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/admissionregistration/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + admissionregistrationv1beta1 "k8s.io/client-go/applyconfigurations/admissionregistration/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeValidatingWebhookConfigurations implements ValidatingWebhookConfigurationInterface +type FakeValidatingWebhookConfigurations struct { + Fake *FakeAdmissionregistrationV1beta1 +} + +var validatingwebhookconfigurationsResource = schema.GroupVersionResource{Group: "admissionregistration.k8s.io", Version: "v1beta1", Resource: "validatingwebhookconfigurations"} + +var validatingwebhookconfigurationsKind = schema.GroupVersionKind{Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "ValidatingWebhookConfiguration"} + +// Get takes name of the validatingWebhookConfiguration, and returns the corresponding validatingWebhookConfiguration object, and an error if there is any. +func (c *FakeValidatingWebhookConfigurations) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.ValidatingWebhookConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(validatingwebhookconfigurationsResource, name), &v1beta1.ValidatingWebhookConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ValidatingWebhookConfiguration), err +} + +// List takes label and field selectors, and returns the list of ValidatingWebhookConfigurations that match those selectors. +func (c *FakeValidatingWebhookConfigurations) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.ValidatingWebhookConfigurationList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(validatingwebhookconfigurationsResource, validatingwebhookconfigurationsKind, opts), &v1beta1.ValidatingWebhookConfigurationList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.ValidatingWebhookConfigurationList{ListMeta: obj.(*v1beta1.ValidatingWebhookConfigurationList).ListMeta} + for _, item := range obj.(*v1beta1.ValidatingWebhookConfigurationList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested validatingWebhookConfigurations. +func (c *FakeValidatingWebhookConfigurations) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(validatingwebhookconfigurationsResource, opts)) +} + +// Create takes the representation of a validatingWebhookConfiguration and creates it. Returns the server's representation of the validatingWebhookConfiguration, and an error, if there is any. +func (c *FakeValidatingWebhookConfigurations) Create(ctx context.Context, validatingWebhookConfiguration *v1beta1.ValidatingWebhookConfiguration, opts v1.CreateOptions) (result *v1beta1.ValidatingWebhookConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(validatingwebhookconfigurationsResource, validatingWebhookConfiguration), &v1beta1.ValidatingWebhookConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ValidatingWebhookConfiguration), err +} + +// Update takes the representation of a validatingWebhookConfiguration and updates it. Returns the server's representation of the validatingWebhookConfiguration, and an error, if there is any. +func (c *FakeValidatingWebhookConfigurations) Update(ctx context.Context, validatingWebhookConfiguration *v1beta1.ValidatingWebhookConfiguration, opts v1.UpdateOptions) (result *v1beta1.ValidatingWebhookConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(validatingwebhookconfigurationsResource, validatingWebhookConfiguration), &v1beta1.ValidatingWebhookConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ValidatingWebhookConfiguration), err +} + +// Delete takes name of the validatingWebhookConfiguration and deletes it. Returns an error if one occurs. +func (c *FakeValidatingWebhookConfigurations) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(validatingwebhookconfigurationsResource, name, opts), &v1beta1.ValidatingWebhookConfiguration{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeValidatingWebhookConfigurations) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(validatingwebhookconfigurationsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.ValidatingWebhookConfigurationList{}) + return err +} + +// Patch applies the patch and returns the patched validatingWebhookConfiguration. +func (c *FakeValidatingWebhookConfigurations) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.ValidatingWebhookConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(validatingwebhookconfigurationsResource, name, pt, data, subresources...), &v1beta1.ValidatingWebhookConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ValidatingWebhookConfiguration), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied validatingWebhookConfiguration. +func (c *FakeValidatingWebhookConfigurations) Apply(ctx context.Context, validatingWebhookConfiguration *admissionregistrationv1beta1.ValidatingWebhookConfigurationApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.ValidatingWebhookConfiguration, err error) { + if validatingWebhookConfiguration == nil { + return nil, fmt.Errorf("validatingWebhookConfiguration provided to Apply must not be nil") + } + data, err := json.Marshal(validatingWebhookConfiguration) + if err != nil { + return nil, err + } + name := validatingWebhookConfiguration.Name + if name == nil { + return nil, fmt.Errorf("validatingWebhookConfiguration.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(validatingwebhookconfigurationsResource, *name, types.ApplyPatchType, data), &v1beta1.ValidatingWebhookConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ValidatingWebhookConfiguration), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/apiserverinternal/v1alpha1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/apiserverinternal/v1alpha1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/apiserverinternal/v1alpha1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/apiserverinternal/v1alpha1/fake/fake_apiserverinternal_client.go b/vendor/k8s.io/client-go/kubernetes/typed/apiserverinternal/v1alpha1/fake/fake_apiserverinternal_client.go new file mode 100644 index 000000000..0960a5e81 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/apiserverinternal/v1alpha1/fake/fake_apiserverinternal_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "k8s.io/client-go/kubernetes/typed/apiserverinternal/v1alpha1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeInternalV1alpha1 struct { + *testing.Fake +} + +func (c *FakeInternalV1alpha1) StorageVersions() v1alpha1.StorageVersionInterface { + return &FakeStorageVersions{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeInternalV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/apiserverinternal/v1alpha1/fake/fake_storageversion.go b/vendor/k8s.io/client-go/kubernetes/typed/apiserverinternal/v1alpha1/fake/fake_storageversion.go new file mode 100644 index 000000000..8b6a84d7a --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/apiserverinternal/v1alpha1/fake/fake_storageversion.go @@ -0,0 +1,179 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1alpha1 "k8s.io/api/apiserverinternal/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + apiserverinternalv1alpha1 "k8s.io/client-go/applyconfigurations/apiserverinternal/v1alpha1" + testing "k8s.io/client-go/testing" +) + +// FakeStorageVersions implements StorageVersionInterface +type FakeStorageVersions struct { + Fake *FakeInternalV1alpha1 +} + +var storageversionsResource = schema.GroupVersionResource{Group: "internal.apiserver.k8s.io", Version: "v1alpha1", Resource: "storageversions"} + +var storageversionsKind = schema.GroupVersionKind{Group: "internal.apiserver.k8s.io", Version: "v1alpha1", Kind: "StorageVersion"} + +// Get takes name of the storageVersion, and returns the corresponding storageVersion object, and an error if there is any. +func (c *FakeStorageVersions) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.StorageVersion, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(storageversionsResource, name), &v1alpha1.StorageVersion{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.StorageVersion), err +} + +// List takes label and field selectors, and returns the list of StorageVersions that match those selectors. +func (c *FakeStorageVersions) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.StorageVersionList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(storageversionsResource, storageversionsKind, opts), &v1alpha1.StorageVersionList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.StorageVersionList{ListMeta: obj.(*v1alpha1.StorageVersionList).ListMeta} + for _, item := range obj.(*v1alpha1.StorageVersionList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested storageVersions. +func (c *FakeStorageVersions) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(storageversionsResource, opts)) +} + +// Create takes the representation of a storageVersion and creates it. Returns the server's representation of the storageVersion, and an error, if there is any. +func (c *FakeStorageVersions) Create(ctx context.Context, storageVersion *v1alpha1.StorageVersion, opts v1.CreateOptions) (result *v1alpha1.StorageVersion, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(storageversionsResource, storageVersion), &v1alpha1.StorageVersion{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.StorageVersion), err +} + +// Update takes the representation of a storageVersion and updates it. Returns the server's representation of the storageVersion, and an error, if there is any. +func (c *FakeStorageVersions) Update(ctx context.Context, storageVersion *v1alpha1.StorageVersion, opts v1.UpdateOptions) (result *v1alpha1.StorageVersion, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(storageversionsResource, storageVersion), &v1alpha1.StorageVersion{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.StorageVersion), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeStorageVersions) UpdateStatus(ctx context.Context, storageVersion *v1alpha1.StorageVersion, opts v1.UpdateOptions) (*v1alpha1.StorageVersion, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(storageversionsResource, "status", storageVersion), &v1alpha1.StorageVersion{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.StorageVersion), err +} + +// Delete takes name of the storageVersion and deletes it. Returns an error if one occurs. +func (c *FakeStorageVersions) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(storageversionsResource, name, opts), &v1alpha1.StorageVersion{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeStorageVersions) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(storageversionsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.StorageVersionList{}) + return err +} + +// Patch applies the patch and returns the patched storageVersion. +func (c *FakeStorageVersions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.StorageVersion, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(storageversionsResource, name, pt, data, subresources...), &v1alpha1.StorageVersion{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.StorageVersion), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied storageVersion. +func (c *FakeStorageVersions) Apply(ctx context.Context, storageVersion *apiserverinternalv1alpha1.StorageVersionApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.StorageVersion, err error) { + if storageVersion == nil { + return nil, fmt.Errorf("storageVersion provided to Apply must not be nil") + } + data, err := json.Marshal(storageVersion) + if err != nil { + return nil, err + } + name := storageVersion.Name + if name == nil { + return nil, fmt.Errorf("storageVersion.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(storageversionsResource, *name, types.ApplyPatchType, data), &v1alpha1.StorageVersion{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.StorageVersion), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeStorageVersions) ApplyStatus(ctx context.Context, storageVersion *apiserverinternalv1alpha1.StorageVersionApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.StorageVersion, err error) { + if storageVersion == nil { + return nil, fmt.Errorf("storageVersion provided to Apply must not be nil") + } + data, err := json.Marshal(storageVersion) + if err != nil { + return nil, err + } + name := storageVersion.Name + if name == nil { + return nil, fmt.Errorf("storageVersion.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(storageversionsResource, *name, types.ApplyPatchType, data, "status"), &v1alpha1.StorageVersion{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.StorageVersion), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_apps_client.go b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_apps_client.go new file mode 100644 index 000000000..458df0fa3 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_apps_client.go @@ -0,0 +1,56 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/client-go/kubernetes/typed/apps/v1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeAppsV1 struct { + *testing.Fake +} + +func (c *FakeAppsV1) ControllerRevisions(namespace string) v1.ControllerRevisionInterface { + return &FakeControllerRevisions{c, namespace} +} + +func (c *FakeAppsV1) DaemonSets(namespace string) v1.DaemonSetInterface { + return &FakeDaemonSets{c, namespace} +} + +func (c *FakeAppsV1) Deployments(namespace string) v1.DeploymentInterface { + return &FakeDeployments{c, namespace} +} + +func (c *FakeAppsV1) ReplicaSets(namespace string) v1.ReplicaSetInterface { + return &FakeReplicaSets{c, namespace} +} + +func (c *FakeAppsV1) StatefulSets(namespace string) v1.StatefulSetInterface { + return &FakeStatefulSets{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeAppsV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_controllerrevision.go b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_controllerrevision.go new file mode 100644 index 000000000..1116d6dff --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_controllerrevision.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + appsv1 "k8s.io/api/apps/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsappsv1 "k8s.io/client-go/applyconfigurations/apps/v1" + testing "k8s.io/client-go/testing" +) + +// FakeControllerRevisions implements ControllerRevisionInterface +type FakeControllerRevisions struct { + Fake *FakeAppsV1 + ns string +} + +var controllerrevisionsResource = schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "controllerrevisions"} + +var controllerrevisionsKind = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "ControllerRevision"} + +// Get takes name of the controllerRevision, and returns the corresponding controllerRevision object, and an error if there is any. +func (c *FakeControllerRevisions) Get(ctx context.Context, name string, options v1.GetOptions) (result *appsv1.ControllerRevision, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(controllerrevisionsResource, c.ns, name), &appsv1.ControllerRevision{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.ControllerRevision), err +} + +// List takes label and field selectors, and returns the list of ControllerRevisions that match those selectors. +func (c *FakeControllerRevisions) List(ctx context.Context, opts v1.ListOptions) (result *appsv1.ControllerRevisionList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(controllerrevisionsResource, controllerrevisionsKind, c.ns, opts), &appsv1.ControllerRevisionList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &appsv1.ControllerRevisionList{ListMeta: obj.(*appsv1.ControllerRevisionList).ListMeta} + for _, item := range obj.(*appsv1.ControllerRevisionList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested controllerRevisions. +func (c *FakeControllerRevisions) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(controllerrevisionsResource, c.ns, opts)) + +} + +// Create takes the representation of a controllerRevision and creates it. Returns the server's representation of the controllerRevision, and an error, if there is any. +func (c *FakeControllerRevisions) Create(ctx context.Context, controllerRevision *appsv1.ControllerRevision, opts v1.CreateOptions) (result *appsv1.ControllerRevision, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(controllerrevisionsResource, c.ns, controllerRevision), &appsv1.ControllerRevision{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.ControllerRevision), err +} + +// Update takes the representation of a controllerRevision and updates it. Returns the server's representation of the controllerRevision, and an error, if there is any. +func (c *FakeControllerRevisions) Update(ctx context.Context, controllerRevision *appsv1.ControllerRevision, opts v1.UpdateOptions) (result *appsv1.ControllerRevision, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(controllerrevisionsResource, c.ns, controllerRevision), &appsv1.ControllerRevision{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.ControllerRevision), err +} + +// Delete takes name of the controllerRevision and deletes it. Returns an error if one occurs. +func (c *FakeControllerRevisions) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(controllerrevisionsResource, c.ns, name, opts), &appsv1.ControllerRevision{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeControllerRevisions) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(controllerrevisionsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &appsv1.ControllerRevisionList{}) + return err +} + +// Patch applies the patch and returns the patched controllerRevision. +func (c *FakeControllerRevisions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *appsv1.ControllerRevision, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(controllerrevisionsResource, c.ns, name, pt, data, subresources...), &appsv1.ControllerRevision{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.ControllerRevision), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied controllerRevision. +func (c *FakeControllerRevisions) Apply(ctx context.Context, controllerRevision *applyconfigurationsappsv1.ControllerRevisionApplyConfiguration, opts v1.ApplyOptions) (result *appsv1.ControllerRevision, err error) { + if controllerRevision == nil { + return nil, fmt.Errorf("controllerRevision provided to Apply must not be nil") + } + data, err := json.Marshal(controllerRevision) + if err != nil { + return nil, err + } + name := controllerRevision.Name + if name == nil { + return nil, fmt.Errorf("controllerRevision.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(controllerrevisionsResource, c.ns, *name, types.ApplyPatchType, data), &appsv1.ControllerRevision{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.ControllerRevision), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_daemonset.go b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_daemonset.go new file mode 100644 index 000000000..00c28df9b --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_daemonset.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + appsv1 "k8s.io/api/apps/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsappsv1 "k8s.io/client-go/applyconfigurations/apps/v1" + testing "k8s.io/client-go/testing" +) + +// FakeDaemonSets implements DaemonSetInterface +type FakeDaemonSets struct { + Fake *FakeAppsV1 + ns string +} + +var daemonsetsResource = schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "daemonsets"} + +var daemonsetsKind = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "DaemonSet"} + +// Get takes name of the daemonSet, and returns the corresponding daemonSet object, and an error if there is any. +func (c *FakeDaemonSets) Get(ctx context.Context, name string, options v1.GetOptions) (result *appsv1.DaemonSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(daemonsetsResource, c.ns, name), &appsv1.DaemonSet{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.DaemonSet), err +} + +// List takes label and field selectors, and returns the list of DaemonSets that match those selectors. +func (c *FakeDaemonSets) List(ctx context.Context, opts v1.ListOptions) (result *appsv1.DaemonSetList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(daemonsetsResource, daemonsetsKind, c.ns, opts), &appsv1.DaemonSetList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &appsv1.DaemonSetList{ListMeta: obj.(*appsv1.DaemonSetList).ListMeta} + for _, item := range obj.(*appsv1.DaemonSetList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested daemonSets. +func (c *FakeDaemonSets) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(daemonsetsResource, c.ns, opts)) + +} + +// Create takes the representation of a daemonSet and creates it. Returns the server's representation of the daemonSet, and an error, if there is any. +func (c *FakeDaemonSets) Create(ctx context.Context, daemonSet *appsv1.DaemonSet, opts v1.CreateOptions) (result *appsv1.DaemonSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(daemonsetsResource, c.ns, daemonSet), &appsv1.DaemonSet{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.DaemonSet), err +} + +// Update takes the representation of a daemonSet and updates it. Returns the server's representation of the daemonSet, and an error, if there is any. +func (c *FakeDaemonSets) Update(ctx context.Context, daemonSet *appsv1.DaemonSet, opts v1.UpdateOptions) (result *appsv1.DaemonSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(daemonsetsResource, c.ns, daemonSet), &appsv1.DaemonSet{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.DaemonSet), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeDaemonSets) UpdateStatus(ctx context.Context, daemonSet *appsv1.DaemonSet, opts v1.UpdateOptions) (*appsv1.DaemonSet, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(daemonsetsResource, "status", c.ns, daemonSet), &appsv1.DaemonSet{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.DaemonSet), err +} + +// Delete takes name of the daemonSet and deletes it. Returns an error if one occurs. +func (c *FakeDaemonSets) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(daemonsetsResource, c.ns, name, opts), &appsv1.DaemonSet{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeDaemonSets) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(daemonsetsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &appsv1.DaemonSetList{}) + return err +} + +// Patch applies the patch and returns the patched daemonSet. +func (c *FakeDaemonSets) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *appsv1.DaemonSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(daemonsetsResource, c.ns, name, pt, data, subresources...), &appsv1.DaemonSet{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.DaemonSet), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied daemonSet. +func (c *FakeDaemonSets) Apply(ctx context.Context, daemonSet *applyconfigurationsappsv1.DaemonSetApplyConfiguration, opts v1.ApplyOptions) (result *appsv1.DaemonSet, err error) { + if daemonSet == nil { + return nil, fmt.Errorf("daemonSet provided to Apply must not be nil") + } + data, err := json.Marshal(daemonSet) + if err != nil { + return nil, err + } + name := daemonSet.Name + if name == nil { + return nil, fmt.Errorf("daemonSet.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(daemonsetsResource, c.ns, *name, types.ApplyPatchType, data), &appsv1.DaemonSet{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.DaemonSet), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeDaemonSets) ApplyStatus(ctx context.Context, daemonSet *applyconfigurationsappsv1.DaemonSetApplyConfiguration, opts v1.ApplyOptions) (result *appsv1.DaemonSet, err error) { + if daemonSet == nil { + return nil, fmt.Errorf("daemonSet provided to Apply must not be nil") + } + data, err := json.Marshal(daemonSet) + if err != nil { + return nil, err + } + name := daemonSet.Name + if name == nil { + return nil, fmt.Errorf("daemonSet.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(daemonsetsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &appsv1.DaemonSet{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.DaemonSet), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_deployment.go b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_deployment.go new file mode 100644 index 000000000..8899824aa --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_deployment.go @@ -0,0 +1,233 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + appsv1 "k8s.io/api/apps/v1" + autoscalingv1 "k8s.io/api/autoscaling/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsappsv1 "k8s.io/client-go/applyconfigurations/apps/v1" + applyconfigurationsautoscalingv1 "k8s.io/client-go/applyconfigurations/autoscaling/v1" + testing "k8s.io/client-go/testing" +) + +// FakeDeployments implements DeploymentInterface +type FakeDeployments struct { + Fake *FakeAppsV1 + ns string +} + +var deploymentsResource = schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"} + +var deploymentsKind = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"} + +// Get takes name of the deployment, and returns the corresponding deployment object, and an error if there is any. +func (c *FakeDeployments) Get(ctx context.Context, name string, options v1.GetOptions) (result *appsv1.Deployment, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(deploymentsResource, c.ns, name), &appsv1.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.Deployment), err +} + +// List takes label and field selectors, and returns the list of Deployments that match those selectors. +func (c *FakeDeployments) List(ctx context.Context, opts v1.ListOptions) (result *appsv1.DeploymentList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(deploymentsResource, deploymentsKind, c.ns, opts), &appsv1.DeploymentList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &appsv1.DeploymentList{ListMeta: obj.(*appsv1.DeploymentList).ListMeta} + for _, item := range obj.(*appsv1.DeploymentList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested deployments. +func (c *FakeDeployments) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(deploymentsResource, c.ns, opts)) + +} + +// Create takes the representation of a deployment and creates it. Returns the server's representation of the deployment, and an error, if there is any. +func (c *FakeDeployments) Create(ctx context.Context, deployment *appsv1.Deployment, opts v1.CreateOptions) (result *appsv1.Deployment, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(deploymentsResource, c.ns, deployment), &appsv1.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.Deployment), err +} + +// Update takes the representation of a deployment and updates it. Returns the server's representation of the deployment, and an error, if there is any. +func (c *FakeDeployments) Update(ctx context.Context, deployment *appsv1.Deployment, opts v1.UpdateOptions) (result *appsv1.Deployment, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(deploymentsResource, c.ns, deployment), &appsv1.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.Deployment), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeDeployments) UpdateStatus(ctx context.Context, deployment *appsv1.Deployment, opts v1.UpdateOptions) (*appsv1.Deployment, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(deploymentsResource, "status", c.ns, deployment), &appsv1.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.Deployment), err +} + +// Delete takes name of the deployment and deletes it. Returns an error if one occurs. +func (c *FakeDeployments) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(deploymentsResource, c.ns, name, opts), &appsv1.Deployment{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeDeployments) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(deploymentsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &appsv1.DeploymentList{}) + return err +} + +// Patch applies the patch and returns the patched deployment. +func (c *FakeDeployments) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *appsv1.Deployment, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(deploymentsResource, c.ns, name, pt, data, subresources...), &appsv1.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.Deployment), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied deployment. +func (c *FakeDeployments) Apply(ctx context.Context, deployment *applyconfigurationsappsv1.DeploymentApplyConfiguration, opts v1.ApplyOptions) (result *appsv1.Deployment, err error) { + if deployment == nil { + return nil, fmt.Errorf("deployment provided to Apply must not be nil") + } + data, err := json.Marshal(deployment) + if err != nil { + return nil, err + } + name := deployment.Name + if name == nil { + return nil, fmt.Errorf("deployment.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(deploymentsResource, c.ns, *name, types.ApplyPatchType, data), &appsv1.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.Deployment), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeDeployments) ApplyStatus(ctx context.Context, deployment *applyconfigurationsappsv1.DeploymentApplyConfiguration, opts v1.ApplyOptions) (result *appsv1.Deployment, err error) { + if deployment == nil { + return nil, fmt.Errorf("deployment provided to Apply must not be nil") + } + data, err := json.Marshal(deployment) + if err != nil { + return nil, err + } + name := deployment.Name + if name == nil { + return nil, fmt.Errorf("deployment.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(deploymentsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &appsv1.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.Deployment), err +} + +// GetScale takes name of the deployment, and returns the corresponding scale object, and an error if there is any. +func (c *FakeDeployments) GetScale(ctx context.Context, deploymentName string, options v1.GetOptions) (result *autoscalingv1.Scale, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetSubresourceAction(deploymentsResource, c.ns, "scale", deploymentName), &autoscalingv1.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*autoscalingv1.Scale), err +} + +// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *FakeDeployments) UpdateScale(ctx context.Context, deploymentName string, scale *autoscalingv1.Scale, opts v1.UpdateOptions) (result *autoscalingv1.Scale, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(deploymentsResource, "scale", c.ns, scale), &autoscalingv1.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*autoscalingv1.Scale), err +} + +// ApplyScale takes top resource name and the apply declarative configuration for scale, +// applies it and returns the applied scale, and an error, if there is any. +func (c *FakeDeployments) ApplyScale(ctx context.Context, deploymentName string, scale *applyconfigurationsautoscalingv1.ScaleApplyConfiguration, opts v1.ApplyOptions) (result *autoscalingv1.Scale, err error) { + if scale == nil { + return nil, fmt.Errorf("scale provided to ApplyScale must not be nil") + } + data, err := json.Marshal(scale) + if err != nil { + return nil, err + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(deploymentsResource, c.ns, deploymentName, types.ApplyPatchType, data, "status"), &autoscalingv1.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*autoscalingv1.Scale), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_replicaset.go b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_replicaset.go new file mode 100644 index 000000000..39acfafeb --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_replicaset.go @@ -0,0 +1,233 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + appsv1 "k8s.io/api/apps/v1" + autoscalingv1 "k8s.io/api/autoscaling/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsappsv1 "k8s.io/client-go/applyconfigurations/apps/v1" + applyconfigurationsautoscalingv1 "k8s.io/client-go/applyconfigurations/autoscaling/v1" + testing "k8s.io/client-go/testing" +) + +// FakeReplicaSets implements ReplicaSetInterface +type FakeReplicaSets struct { + Fake *FakeAppsV1 + ns string +} + +var replicasetsResource = schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "replicasets"} + +var replicasetsKind = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "ReplicaSet"} + +// Get takes name of the replicaSet, and returns the corresponding replicaSet object, and an error if there is any. +func (c *FakeReplicaSets) Get(ctx context.Context, name string, options v1.GetOptions) (result *appsv1.ReplicaSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(replicasetsResource, c.ns, name), &appsv1.ReplicaSet{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.ReplicaSet), err +} + +// List takes label and field selectors, and returns the list of ReplicaSets that match those selectors. +func (c *FakeReplicaSets) List(ctx context.Context, opts v1.ListOptions) (result *appsv1.ReplicaSetList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(replicasetsResource, replicasetsKind, c.ns, opts), &appsv1.ReplicaSetList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &appsv1.ReplicaSetList{ListMeta: obj.(*appsv1.ReplicaSetList).ListMeta} + for _, item := range obj.(*appsv1.ReplicaSetList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested replicaSets. +func (c *FakeReplicaSets) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(replicasetsResource, c.ns, opts)) + +} + +// Create takes the representation of a replicaSet and creates it. Returns the server's representation of the replicaSet, and an error, if there is any. +func (c *FakeReplicaSets) Create(ctx context.Context, replicaSet *appsv1.ReplicaSet, opts v1.CreateOptions) (result *appsv1.ReplicaSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(replicasetsResource, c.ns, replicaSet), &appsv1.ReplicaSet{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.ReplicaSet), err +} + +// Update takes the representation of a replicaSet and updates it. Returns the server's representation of the replicaSet, and an error, if there is any. +func (c *FakeReplicaSets) Update(ctx context.Context, replicaSet *appsv1.ReplicaSet, opts v1.UpdateOptions) (result *appsv1.ReplicaSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(replicasetsResource, c.ns, replicaSet), &appsv1.ReplicaSet{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.ReplicaSet), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeReplicaSets) UpdateStatus(ctx context.Context, replicaSet *appsv1.ReplicaSet, opts v1.UpdateOptions) (*appsv1.ReplicaSet, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(replicasetsResource, "status", c.ns, replicaSet), &appsv1.ReplicaSet{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.ReplicaSet), err +} + +// Delete takes name of the replicaSet and deletes it. Returns an error if one occurs. +func (c *FakeReplicaSets) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(replicasetsResource, c.ns, name, opts), &appsv1.ReplicaSet{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeReplicaSets) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(replicasetsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &appsv1.ReplicaSetList{}) + return err +} + +// Patch applies the patch and returns the patched replicaSet. +func (c *FakeReplicaSets) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *appsv1.ReplicaSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(replicasetsResource, c.ns, name, pt, data, subresources...), &appsv1.ReplicaSet{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.ReplicaSet), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied replicaSet. +func (c *FakeReplicaSets) Apply(ctx context.Context, replicaSet *applyconfigurationsappsv1.ReplicaSetApplyConfiguration, opts v1.ApplyOptions) (result *appsv1.ReplicaSet, err error) { + if replicaSet == nil { + return nil, fmt.Errorf("replicaSet provided to Apply must not be nil") + } + data, err := json.Marshal(replicaSet) + if err != nil { + return nil, err + } + name := replicaSet.Name + if name == nil { + return nil, fmt.Errorf("replicaSet.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(replicasetsResource, c.ns, *name, types.ApplyPatchType, data), &appsv1.ReplicaSet{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.ReplicaSet), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeReplicaSets) ApplyStatus(ctx context.Context, replicaSet *applyconfigurationsappsv1.ReplicaSetApplyConfiguration, opts v1.ApplyOptions) (result *appsv1.ReplicaSet, err error) { + if replicaSet == nil { + return nil, fmt.Errorf("replicaSet provided to Apply must not be nil") + } + data, err := json.Marshal(replicaSet) + if err != nil { + return nil, err + } + name := replicaSet.Name + if name == nil { + return nil, fmt.Errorf("replicaSet.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(replicasetsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &appsv1.ReplicaSet{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.ReplicaSet), err +} + +// GetScale takes name of the replicaSet, and returns the corresponding scale object, and an error if there is any. +func (c *FakeReplicaSets) GetScale(ctx context.Context, replicaSetName string, options v1.GetOptions) (result *autoscalingv1.Scale, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetSubresourceAction(replicasetsResource, c.ns, "scale", replicaSetName), &autoscalingv1.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*autoscalingv1.Scale), err +} + +// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *FakeReplicaSets) UpdateScale(ctx context.Context, replicaSetName string, scale *autoscalingv1.Scale, opts v1.UpdateOptions) (result *autoscalingv1.Scale, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(replicasetsResource, "scale", c.ns, scale), &autoscalingv1.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*autoscalingv1.Scale), err +} + +// ApplyScale takes top resource name and the apply declarative configuration for scale, +// applies it and returns the applied scale, and an error, if there is any. +func (c *FakeReplicaSets) ApplyScale(ctx context.Context, replicaSetName string, scale *applyconfigurationsautoscalingv1.ScaleApplyConfiguration, opts v1.ApplyOptions) (result *autoscalingv1.Scale, err error) { + if scale == nil { + return nil, fmt.Errorf("scale provided to ApplyScale must not be nil") + } + data, err := json.Marshal(scale) + if err != nil { + return nil, err + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(replicasetsResource, c.ns, replicaSetName, types.ApplyPatchType, data, "status"), &autoscalingv1.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*autoscalingv1.Scale), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_statefulset.go b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_statefulset.go new file mode 100644 index 000000000..e04eb025d --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1/fake/fake_statefulset.go @@ -0,0 +1,233 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + appsv1 "k8s.io/api/apps/v1" + autoscalingv1 "k8s.io/api/autoscaling/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsappsv1 "k8s.io/client-go/applyconfigurations/apps/v1" + applyconfigurationsautoscalingv1 "k8s.io/client-go/applyconfigurations/autoscaling/v1" + testing "k8s.io/client-go/testing" +) + +// FakeStatefulSets implements StatefulSetInterface +type FakeStatefulSets struct { + Fake *FakeAppsV1 + ns string +} + +var statefulsetsResource = schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "statefulsets"} + +var statefulsetsKind = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "StatefulSet"} + +// Get takes name of the statefulSet, and returns the corresponding statefulSet object, and an error if there is any. +func (c *FakeStatefulSets) Get(ctx context.Context, name string, options v1.GetOptions) (result *appsv1.StatefulSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(statefulsetsResource, c.ns, name), &appsv1.StatefulSet{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.StatefulSet), err +} + +// List takes label and field selectors, and returns the list of StatefulSets that match those selectors. +func (c *FakeStatefulSets) List(ctx context.Context, opts v1.ListOptions) (result *appsv1.StatefulSetList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(statefulsetsResource, statefulsetsKind, c.ns, opts), &appsv1.StatefulSetList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &appsv1.StatefulSetList{ListMeta: obj.(*appsv1.StatefulSetList).ListMeta} + for _, item := range obj.(*appsv1.StatefulSetList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested statefulSets. +func (c *FakeStatefulSets) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(statefulsetsResource, c.ns, opts)) + +} + +// Create takes the representation of a statefulSet and creates it. Returns the server's representation of the statefulSet, and an error, if there is any. +func (c *FakeStatefulSets) Create(ctx context.Context, statefulSet *appsv1.StatefulSet, opts v1.CreateOptions) (result *appsv1.StatefulSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(statefulsetsResource, c.ns, statefulSet), &appsv1.StatefulSet{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.StatefulSet), err +} + +// Update takes the representation of a statefulSet and updates it. Returns the server's representation of the statefulSet, and an error, if there is any. +func (c *FakeStatefulSets) Update(ctx context.Context, statefulSet *appsv1.StatefulSet, opts v1.UpdateOptions) (result *appsv1.StatefulSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(statefulsetsResource, c.ns, statefulSet), &appsv1.StatefulSet{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.StatefulSet), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeStatefulSets) UpdateStatus(ctx context.Context, statefulSet *appsv1.StatefulSet, opts v1.UpdateOptions) (*appsv1.StatefulSet, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(statefulsetsResource, "status", c.ns, statefulSet), &appsv1.StatefulSet{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.StatefulSet), err +} + +// Delete takes name of the statefulSet and deletes it. Returns an error if one occurs. +func (c *FakeStatefulSets) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(statefulsetsResource, c.ns, name, opts), &appsv1.StatefulSet{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeStatefulSets) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(statefulsetsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &appsv1.StatefulSetList{}) + return err +} + +// Patch applies the patch and returns the patched statefulSet. +func (c *FakeStatefulSets) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *appsv1.StatefulSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(statefulsetsResource, c.ns, name, pt, data, subresources...), &appsv1.StatefulSet{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.StatefulSet), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied statefulSet. +func (c *FakeStatefulSets) Apply(ctx context.Context, statefulSet *applyconfigurationsappsv1.StatefulSetApplyConfiguration, opts v1.ApplyOptions) (result *appsv1.StatefulSet, err error) { + if statefulSet == nil { + return nil, fmt.Errorf("statefulSet provided to Apply must not be nil") + } + data, err := json.Marshal(statefulSet) + if err != nil { + return nil, err + } + name := statefulSet.Name + if name == nil { + return nil, fmt.Errorf("statefulSet.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(statefulsetsResource, c.ns, *name, types.ApplyPatchType, data), &appsv1.StatefulSet{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.StatefulSet), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeStatefulSets) ApplyStatus(ctx context.Context, statefulSet *applyconfigurationsappsv1.StatefulSetApplyConfiguration, opts v1.ApplyOptions) (result *appsv1.StatefulSet, err error) { + if statefulSet == nil { + return nil, fmt.Errorf("statefulSet provided to Apply must not be nil") + } + data, err := json.Marshal(statefulSet) + if err != nil { + return nil, err + } + name := statefulSet.Name + if name == nil { + return nil, fmt.Errorf("statefulSet.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(statefulsetsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &appsv1.StatefulSet{}) + + if obj == nil { + return nil, err + } + return obj.(*appsv1.StatefulSet), err +} + +// GetScale takes name of the statefulSet, and returns the corresponding scale object, and an error if there is any. +func (c *FakeStatefulSets) GetScale(ctx context.Context, statefulSetName string, options v1.GetOptions) (result *autoscalingv1.Scale, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetSubresourceAction(statefulsetsResource, c.ns, "scale", statefulSetName), &autoscalingv1.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*autoscalingv1.Scale), err +} + +// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *FakeStatefulSets) UpdateScale(ctx context.Context, statefulSetName string, scale *autoscalingv1.Scale, opts v1.UpdateOptions) (result *autoscalingv1.Scale, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(statefulsetsResource, "scale", c.ns, scale), &autoscalingv1.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*autoscalingv1.Scale), err +} + +// ApplyScale takes top resource name and the apply declarative configuration for scale, +// applies it and returns the applied scale, and an error, if there is any. +func (c *FakeStatefulSets) ApplyScale(ctx context.Context, statefulSetName string, scale *applyconfigurationsautoscalingv1.ScaleApplyConfiguration, opts v1.ApplyOptions) (result *autoscalingv1.Scale, err error) { + if scale == nil { + return nil, fmt.Errorf("scale provided to ApplyScale must not be nil") + } + data, err := json.Marshal(scale) + if err != nil { + return nil, err + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(statefulsetsResource, c.ns, statefulSetName, types.ApplyPatchType, data, "status"), &autoscalingv1.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*autoscalingv1.Scale), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake/fake_apps_client.go b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake/fake_apps_client.go new file mode 100644 index 000000000..8e65d78d2 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake/fake_apps_client.go @@ -0,0 +1,48 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1beta1 "k8s.io/client-go/kubernetes/typed/apps/v1beta1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeAppsV1beta1 struct { + *testing.Fake +} + +func (c *FakeAppsV1beta1) ControllerRevisions(namespace string) v1beta1.ControllerRevisionInterface { + return &FakeControllerRevisions{c, namespace} +} + +func (c *FakeAppsV1beta1) Deployments(namespace string) v1beta1.DeploymentInterface { + return &FakeDeployments{c, namespace} +} + +func (c *FakeAppsV1beta1) StatefulSets(namespace string) v1beta1.StatefulSetInterface { + return &FakeStatefulSets{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeAppsV1beta1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake/fake_controllerrevision.go b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake/fake_controllerrevision.go new file mode 100644 index 000000000..a4fb08c90 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake/fake_controllerrevision.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/apps/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + appsv1beta1 "k8s.io/client-go/applyconfigurations/apps/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeControllerRevisions implements ControllerRevisionInterface +type FakeControllerRevisions struct { + Fake *FakeAppsV1beta1 + ns string +} + +var controllerrevisionsResource = schema.GroupVersionResource{Group: "apps", Version: "v1beta1", Resource: "controllerrevisions"} + +var controllerrevisionsKind = schema.GroupVersionKind{Group: "apps", Version: "v1beta1", Kind: "ControllerRevision"} + +// Get takes name of the controllerRevision, and returns the corresponding controllerRevision object, and an error if there is any. +func (c *FakeControllerRevisions) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.ControllerRevision, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(controllerrevisionsResource, c.ns, name), &v1beta1.ControllerRevision{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ControllerRevision), err +} + +// List takes label and field selectors, and returns the list of ControllerRevisions that match those selectors. +func (c *FakeControllerRevisions) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.ControllerRevisionList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(controllerrevisionsResource, controllerrevisionsKind, c.ns, opts), &v1beta1.ControllerRevisionList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.ControllerRevisionList{ListMeta: obj.(*v1beta1.ControllerRevisionList).ListMeta} + for _, item := range obj.(*v1beta1.ControllerRevisionList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested controllerRevisions. +func (c *FakeControllerRevisions) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(controllerrevisionsResource, c.ns, opts)) + +} + +// Create takes the representation of a controllerRevision and creates it. Returns the server's representation of the controllerRevision, and an error, if there is any. +func (c *FakeControllerRevisions) Create(ctx context.Context, controllerRevision *v1beta1.ControllerRevision, opts v1.CreateOptions) (result *v1beta1.ControllerRevision, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(controllerrevisionsResource, c.ns, controllerRevision), &v1beta1.ControllerRevision{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ControllerRevision), err +} + +// Update takes the representation of a controllerRevision and updates it. Returns the server's representation of the controllerRevision, and an error, if there is any. +func (c *FakeControllerRevisions) Update(ctx context.Context, controllerRevision *v1beta1.ControllerRevision, opts v1.UpdateOptions) (result *v1beta1.ControllerRevision, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(controllerrevisionsResource, c.ns, controllerRevision), &v1beta1.ControllerRevision{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ControllerRevision), err +} + +// Delete takes name of the controllerRevision and deletes it. Returns an error if one occurs. +func (c *FakeControllerRevisions) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(controllerrevisionsResource, c.ns, name, opts), &v1beta1.ControllerRevision{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeControllerRevisions) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(controllerrevisionsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.ControllerRevisionList{}) + return err +} + +// Patch applies the patch and returns the patched controllerRevision. +func (c *FakeControllerRevisions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.ControllerRevision, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(controllerrevisionsResource, c.ns, name, pt, data, subresources...), &v1beta1.ControllerRevision{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ControllerRevision), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied controllerRevision. +func (c *FakeControllerRevisions) Apply(ctx context.Context, controllerRevision *appsv1beta1.ControllerRevisionApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.ControllerRevision, err error) { + if controllerRevision == nil { + return nil, fmt.Errorf("controllerRevision provided to Apply must not be nil") + } + data, err := json.Marshal(controllerRevision) + if err != nil { + return nil, err + } + name := controllerRevision.Name + if name == nil { + return nil, fmt.Errorf("controllerRevision.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(controllerrevisionsResource, c.ns, *name, types.ApplyPatchType, data), &v1beta1.ControllerRevision{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ControllerRevision), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake/fake_deployment.go b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake/fake_deployment.go new file mode 100644 index 000000000..2db29b481 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake/fake_deployment.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/apps/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + appsv1beta1 "k8s.io/client-go/applyconfigurations/apps/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeDeployments implements DeploymentInterface +type FakeDeployments struct { + Fake *FakeAppsV1beta1 + ns string +} + +var deploymentsResource = schema.GroupVersionResource{Group: "apps", Version: "v1beta1", Resource: "deployments"} + +var deploymentsKind = schema.GroupVersionKind{Group: "apps", Version: "v1beta1", Kind: "Deployment"} + +// Get takes name of the deployment, and returns the corresponding deployment object, and an error if there is any. +func (c *FakeDeployments) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.Deployment, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(deploymentsResource, c.ns, name), &v1beta1.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Deployment), err +} + +// List takes label and field selectors, and returns the list of Deployments that match those selectors. +func (c *FakeDeployments) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.DeploymentList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(deploymentsResource, deploymentsKind, c.ns, opts), &v1beta1.DeploymentList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.DeploymentList{ListMeta: obj.(*v1beta1.DeploymentList).ListMeta} + for _, item := range obj.(*v1beta1.DeploymentList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested deployments. +func (c *FakeDeployments) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(deploymentsResource, c.ns, opts)) + +} + +// Create takes the representation of a deployment and creates it. Returns the server's representation of the deployment, and an error, if there is any. +func (c *FakeDeployments) Create(ctx context.Context, deployment *v1beta1.Deployment, opts v1.CreateOptions) (result *v1beta1.Deployment, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(deploymentsResource, c.ns, deployment), &v1beta1.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Deployment), err +} + +// Update takes the representation of a deployment and updates it. Returns the server's representation of the deployment, and an error, if there is any. +func (c *FakeDeployments) Update(ctx context.Context, deployment *v1beta1.Deployment, opts v1.UpdateOptions) (result *v1beta1.Deployment, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(deploymentsResource, c.ns, deployment), &v1beta1.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Deployment), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeDeployments) UpdateStatus(ctx context.Context, deployment *v1beta1.Deployment, opts v1.UpdateOptions) (*v1beta1.Deployment, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(deploymentsResource, "status", c.ns, deployment), &v1beta1.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Deployment), err +} + +// Delete takes name of the deployment and deletes it. Returns an error if one occurs. +func (c *FakeDeployments) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(deploymentsResource, c.ns, name, opts), &v1beta1.Deployment{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeDeployments) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(deploymentsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.DeploymentList{}) + return err +} + +// Patch applies the patch and returns the patched deployment. +func (c *FakeDeployments) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Deployment, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(deploymentsResource, c.ns, name, pt, data, subresources...), &v1beta1.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Deployment), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied deployment. +func (c *FakeDeployments) Apply(ctx context.Context, deployment *appsv1beta1.DeploymentApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.Deployment, err error) { + if deployment == nil { + return nil, fmt.Errorf("deployment provided to Apply must not be nil") + } + data, err := json.Marshal(deployment) + if err != nil { + return nil, err + } + name := deployment.Name + if name == nil { + return nil, fmt.Errorf("deployment.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(deploymentsResource, c.ns, *name, types.ApplyPatchType, data), &v1beta1.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Deployment), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeDeployments) ApplyStatus(ctx context.Context, deployment *appsv1beta1.DeploymentApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.Deployment, err error) { + if deployment == nil { + return nil, fmt.Errorf("deployment provided to Apply must not be nil") + } + data, err := json.Marshal(deployment) + if err != nil { + return nil, err + } + name := deployment.Name + if name == nil { + return nil, fmt.Errorf("deployment.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(deploymentsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v1beta1.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Deployment), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake/fake_statefulset.go b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake/fake_statefulset.go new file mode 100644 index 000000000..b756a3239 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake/fake_statefulset.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/apps/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + appsv1beta1 "k8s.io/client-go/applyconfigurations/apps/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeStatefulSets implements StatefulSetInterface +type FakeStatefulSets struct { + Fake *FakeAppsV1beta1 + ns string +} + +var statefulsetsResource = schema.GroupVersionResource{Group: "apps", Version: "v1beta1", Resource: "statefulsets"} + +var statefulsetsKind = schema.GroupVersionKind{Group: "apps", Version: "v1beta1", Kind: "StatefulSet"} + +// Get takes name of the statefulSet, and returns the corresponding statefulSet object, and an error if there is any. +func (c *FakeStatefulSets) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.StatefulSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(statefulsetsResource, c.ns, name), &v1beta1.StatefulSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.StatefulSet), err +} + +// List takes label and field selectors, and returns the list of StatefulSets that match those selectors. +func (c *FakeStatefulSets) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.StatefulSetList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(statefulsetsResource, statefulsetsKind, c.ns, opts), &v1beta1.StatefulSetList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.StatefulSetList{ListMeta: obj.(*v1beta1.StatefulSetList).ListMeta} + for _, item := range obj.(*v1beta1.StatefulSetList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested statefulSets. +func (c *FakeStatefulSets) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(statefulsetsResource, c.ns, opts)) + +} + +// Create takes the representation of a statefulSet and creates it. Returns the server's representation of the statefulSet, and an error, if there is any. +func (c *FakeStatefulSets) Create(ctx context.Context, statefulSet *v1beta1.StatefulSet, opts v1.CreateOptions) (result *v1beta1.StatefulSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(statefulsetsResource, c.ns, statefulSet), &v1beta1.StatefulSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.StatefulSet), err +} + +// Update takes the representation of a statefulSet and updates it. Returns the server's representation of the statefulSet, and an error, if there is any. +func (c *FakeStatefulSets) Update(ctx context.Context, statefulSet *v1beta1.StatefulSet, opts v1.UpdateOptions) (result *v1beta1.StatefulSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(statefulsetsResource, c.ns, statefulSet), &v1beta1.StatefulSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.StatefulSet), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeStatefulSets) UpdateStatus(ctx context.Context, statefulSet *v1beta1.StatefulSet, opts v1.UpdateOptions) (*v1beta1.StatefulSet, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(statefulsetsResource, "status", c.ns, statefulSet), &v1beta1.StatefulSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.StatefulSet), err +} + +// Delete takes name of the statefulSet and deletes it. Returns an error if one occurs. +func (c *FakeStatefulSets) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(statefulsetsResource, c.ns, name, opts), &v1beta1.StatefulSet{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeStatefulSets) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(statefulsetsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.StatefulSetList{}) + return err +} + +// Patch applies the patch and returns the patched statefulSet. +func (c *FakeStatefulSets) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.StatefulSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(statefulsetsResource, c.ns, name, pt, data, subresources...), &v1beta1.StatefulSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.StatefulSet), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied statefulSet. +func (c *FakeStatefulSets) Apply(ctx context.Context, statefulSet *appsv1beta1.StatefulSetApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.StatefulSet, err error) { + if statefulSet == nil { + return nil, fmt.Errorf("statefulSet provided to Apply must not be nil") + } + data, err := json.Marshal(statefulSet) + if err != nil { + return nil, err + } + name := statefulSet.Name + if name == nil { + return nil, fmt.Errorf("statefulSet.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(statefulsetsResource, c.ns, *name, types.ApplyPatchType, data), &v1beta1.StatefulSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.StatefulSet), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeStatefulSets) ApplyStatus(ctx context.Context, statefulSet *appsv1beta1.StatefulSetApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.StatefulSet, err error) { + if statefulSet == nil { + return nil, fmt.Errorf("statefulSet provided to Apply must not be nil") + } + data, err := json.Marshal(statefulSet) + if err != nil { + return nil, err + } + name := statefulSet.Name + if name == nil { + return nil, fmt.Errorf("statefulSet.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(statefulsetsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v1beta1.StatefulSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.StatefulSet), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_apps_client.go b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_apps_client.go new file mode 100644 index 000000000..0ec34a2cd --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_apps_client.go @@ -0,0 +1,56 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1beta2 "k8s.io/client-go/kubernetes/typed/apps/v1beta2" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeAppsV1beta2 struct { + *testing.Fake +} + +func (c *FakeAppsV1beta2) ControllerRevisions(namespace string) v1beta2.ControllerRevisionInterface { + return &FakeControllerRevisions{c, namespace} +} + +func (c *FakeAppsV1beta2) DaemonSets(namespace string) v1beta2.DaemonSetInterface { + return &FakeDaemonSets{c, namespace} +} + +func (c *FakeAppsV1beta2) Deployments(namespace string) v1beta2.DeploymentInterface { + return &FakeDeployments{c, namespace} +} + +func (c *FakeAppsV1beta2) ReplicaSets(namespace string) v1beta2.ReplicaSetInterface { + return &FakeReplicaSets{c, namespace} +} + +func (c *FakeAppsV1beta2) StatefulSets(namespace string) v1beta2.StatefulSetInterface { + return &FakeStatefulSets{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeAppsV1beta2) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_controllerrevision.go b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_controllerrevision.go new file mode 100644 index 000000000..f3d71bf77 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_controllerrevision.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta2 "k8s.io/api/apps/v1beta2" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + appsv1beta2 "k8s.io/client-go/applyconfigurations/apps/v1beta2" + testing "k8s.io/client-go/testing" +) + +// FakeControllerRevisions implements ControllerRevisionInterface +type FakeControllerRevisions struct { + Fake *FakeAppsV1beta2 + ns string +} + +var controllerrevisionsResource = schema.GroupVersionResource{Group: "apps", Version: "v1beta2", Resource: "controllerrevisions"} + +var controllerrevisionsKind = schema.GroupVersionKind{Group: "apps", Version: "v1beta2", Kind: "ControllerRevision"} + +// Get takes name of the controllerRevision, and returns the corresponding controllerRevision object, and an error if there is any. +func (c *FakeControllerRevisions) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta2.ControllerRevision, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(controllerrevisionsResource, c.ns, name), &v1beta2.ControllerRevision{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.ControllerRevision), err +} + +// List takes label and field selectors, and returns the list of ControllerRevisions that match those selectors. +func (c *FakeControllerRevisions) List(ctx context.Context, opts v1.ListOptions) (result *v1beta2.ControllerRevisionList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(controllerrevisionsResource, controllerrevisionsKind, c.ns, opts), &v1beta2.ControllerRevisionList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta2.ControllerRevisionList{ListMeta: obj.(*v1beta2.ControllerRevisionList).ListMeta} + for _, item := range obj.(*v1beta2.ControllerRevisionList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested controllerRevisions. +func (c *FakeControllerRevisions) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(controllerrevisionsResource, c.ns, opts)) + +} + +// Create takes the representation of a controllerRevision and creates it. Returns the server's representation of the controllerRevision, and an error, if there is any. +func (c *FakeControllerRevisions) Create(ctx context.Context, controllerRevision *v1beta2.ControllerRevision, opts v1.CreateOptions) (result *v1beta2.ControllerRevision, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(controllerrevisionsResource, c.ns, controllerRevision), &v1beta2.ControllerRevision{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.ControllerRevision), err +} + +// Update takes the representation of a controllerRevision and updates it. Returns the server's representation of the controllerRevision, and an error, if there is any. +func (c *FakeControllerRevisions) Update(ctx context.Context, controllerRevision *v1beta2.ControllerRevision, opts v1.UpdateOptions) (result *v1beta2.ControllerRevision, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(controllerrevisionsResource, c.ns, controllerRevision), &v1beta2.ControllerRevision{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.ControllerRevision), err +} + +// Delete takes name of the controllerRevision and deletes it. Returns an error if one occurs. +func (c *FakeControllerRevisions) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(controllerrevisionsResource, c.ns, name, opts), &v1beta2.ControllerRevision{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeControllerRevisions) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(controllerrevisionsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta2.ControllerRevisionList{}) + return err +} + +// Patch applies the patch and returns the patched controllerRevision. +func (c *FakeControllerRevisions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta2.ControllerRevision, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(controllerrevisionsResource, c.ns, name, pt, data, subresources...), &v1beta2.ControllerRevision{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.ControllerRevision), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied controllerRevision. +func (c *FakeControllerRevisions) Apply(ctx context.Context, controllerRevision *appsv1beta2.ControllerRevisionApplyConfiguration, opts v1.ApplyOptions) (result *v1beta2.ControllerRevision, err error) { + if controllerRevision == nil { + return nil, fmt.Errorf("controllerRevision provided to Apply must not be nil") + } + data, err := json.Marshal(controllerRevision) + if err != nil { + return nil, err + } + name := controllerRevision.Name + if name == nil { + return nil, fmt.Errorf("controllerRevision.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(controllerrevisionsResource, c.ns, *name, types.ApplyPatchType, data), &v1beta2.ControllerRevision{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.ControllerRevision), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_daemonset.go b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_daemonset.go new file mode 100644 index 000000000..3ee0f7239 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_daemonset.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta2 "k8s.io/api/apps/v1beta2" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + appsv1beta2 "k8s.io/client-go/applyconfigurations/apps/v1beta2" + testing "k8s.io/client-go/testing" +) + +// FakeDaemonSets implements DaemonSetInterface +type FakeDaemonSets struct { + Fake *FakeAppsV1beta2 + ns string +} + +var daemonsetsResource = schema.GroupVersionResource{Group: "apps", Version: "v1beta2", Resource: "daemonsets"} + +var daemonsetsKind = schema.GroupVersionKind{Group: "apps", Version: "v1beta2", Kind: "DaemonSet"} + +// Get takes name of the daemonSet, and returns the corresponding daemonSet object, and an error if there is any. +func (c *FakeDaemonSets) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta2.DaemonSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(daemonsetsResource, c.ns, name), &v1beta2.DaemonSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.DaemonSet), err +} + +// List takes label and field selectors, and returns the list of DaemonSets that match those selectors. +func (c *FakeDaemonSets) List(ctx context.Context, opts v1.ListOptions) (result *v1beta2.DaemonSetList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(daemonsetsResource, daemonsetsKind, c.ns, opts), &v1beta2.DaemonSetList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta2.DaemonSetList{ListMeta: obj.(*v1beta2.DaemonSetList).ListMeta} + for _, item := range obj.(*v1beta2.DaemonSetList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested daemonSets. +func (c *FakeDaemonSets) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(daemonsetsResource, c.ns, opts)) + +} + +// Create takes the representation of a daemonSet and creates it. Returns the server's representation of the daemonSet, and an error, if there is any. +func (c *FakeDaemonSets) Create(ctx context.Context, daemonSet *v1beta2.DaemonSet, opts v1.CreateOptions) (result *v1beta2.DaemonSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(daemonsetsResource, c.ns, daemonSet), &v1beta2.DaemonSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.DaemonSet), err +} + +// Update takes the representation of a daemonSet and updates it. Returns the server's representation of the daemonSet, and an error, if there is any. +func (c *FakeDaemonSets) Update(ctx context.Context, daemonSet *v1beta2.DaemonSet, opts v1.UpdateOptions) (result *v1beta2.DaemonSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(daemonsetsResource, c.ns, daemonSet), &v1beta2.DaemonSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.DaemonSet), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeDaemonSets) UpdateStatus(ctx context.Context, daemonSet *v1beta2.DaemonSet, opts v1.UpdateOptions) (*v1beta2.DaemonSet, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(daemonsetsResource, "status", c.ns, daemonSet), &v1beta2.DaemonSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.DaemonSet), err +} + +// Delete takes name of the daemonSet and deletes it. Returns an error if one occurs. +func (c *FakeDaemonSets) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(daemonsetsResource, c.ns, name, opts), &v1beta2.DaemonSet{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeDaemonSets) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(daemonsetsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta2.DaemonSetList{}) + return err +} + +// Patch applies the patch and returns the patched daemonSet. +func (c *FakeDaemonSets) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta2.DaemonSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(daemonsetsResource, c.ns, name, pt, data, subresources...), &v1beta2.DaemonSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.DaemonSet), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied daemonSet. +func (c *FakeDaemonSets) Apply(ctx context.Context, daemonSet *appsv1beta2.DaemonSetApplyConfiguration, opts v1.ApplyOptions) (result *v1beta2.DaemonSet, err error) { + if daemonSet == nil { + return nil, fmt.Errorf("daemonSet provided to Apply must not be nil") + } + data, err := json.Marshal(daemonSet) + if err != nil { + return nil, err + } + name := daemonSet.Name + if name == nil { + return nil, fmt.Errorf("daemonSet.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(daemonsetsResource, c.ns, *name, types.ApplyPatchType, data), &v1beta2.DaemonSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.DaemonSet), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeDaemonSets) ApplyStatus(ctx context.Context, daemonSet *appsv1beta2.DaemonSetApplyConfiguration, opts v1.ApplyOptions) (result *v1beta2.DaemonSet, err error) { + if daemonSet == nil { + return nil, fmt.Errorf("daemonSet provided to Apply must not be nil") + } + data, err := json.Marshal(daemonSet) + if err != nil { + return nil, err + } + name := daemonSet.Name + if name == nil { + return nil, fmt.Errorf("daemonSet.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(daemonsetsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v1beta2.DaemonSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.DaemonSet), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_deployment.go b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_deployment.go new file mode 100644 index 000000000..38fb2a67c --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_deployment.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta2 "k8s.io/api/apps/v1beta2" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + appsv1beta2 "k8s.io/client-go/applyconfigurations/apps/v1beta2" + testing "k8s.io/client-go/testing" +) + +// FakeDeployments implements DeploymentInterface +type FakeDeployments struct { + Fake *FakeAppsV1beta2 + ns string +} + +var deploymentsResource = schema.GroupVersionResource{Group: "apps", Version: "v1beta2", Resource: "deployments"} + +var deploymentsKind = schema.GroupVersionKind{Group: "apps", Version: "v1beta2", Kind: "Deployment"} + +// Get takes name of the deployment, and returns the corresponding deployment object, and an error if there is any. +func (c *FakeDeployments) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta2.Deployment, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(deploymentsResource, c.ns, name), &v1beta2.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.Deployment), err +} + +// List takes label and field selectors, and returns the list of Deployments that match those selectors. +func (c *FakeDeployments) List(ctx context.Context, opts v1.ListOptions) (result *v1beta2.DeploymentList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(deploymentsResource, deploymentsKind, c.ns, opts), &v1beta2.DeploymentList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta2.DeploymentList{ListMeta: obj.(*v1beta2.DeploymentList).ListMeta} + for _, item := range obj.(*v1beta2.DeploymentList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested deployments. +func (c *FakeDeployments) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(deploymentsResource, c.ns, opts)) + +} + +// Create takes the representation of a deployment and creates it. Returns the server's representation of the deployment, and an error, if there is any. +func (c *FakeDeployments) Create(ctx context.Context, deployment *v1beta2.Deployment, opts v1.CreateOptions) (result *v1beta2.Deployment, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(deploymentsResource, c.ns, deployment), &v1beta2.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.Deployment), err +} + +// Update takes the representation of a deployment and updates it. Returns the server's representation of the deployment, and an error, if there is any. +func (c *FakeDeployments) Update(ctx context.Context, deployment *v1beta2.Deployment, opts v1.UpdateOptions) (result *v1beta2.Deployment, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(deploymentsResource, c.ns, deployment), &v1beta2.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.Deployment), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeDeployments) UpdateStatus(ctx context.Context, deployment *v1beta2.Deployment, opts v1.UpdateOptions) (*v1beta2.Deployment, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(deploymentsResource, "status", c.ns, deployment), &v1beta2.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.Deployment), err +} + +// Delete takes name of the deployment and deletes it. Returns an error if one occurs. +func (c *FakeDeployments) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(deploymentsResource, c.ns, name, opts), &v1beta2.Deployment{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeDeployments) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(deploymentsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta2.DeploymentList{}) + return err +} + +// Patch applies the patch and returns the patched deployment. +func (c *FakeDeployments) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta2.Deployment, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(deploymentsResource, c.ns, name, pt, data, subresources...), &v1beta2.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.Deployment), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied deployment. +func (c *FakeDeployments) Apply(ctx context.Context, deployment *appsv1beta2.DeploymentApplyConfiguration, opts v1.ApplyOptions) (result *v1beta2.Deployment, err error) { + if deployment == nil { + return nil, fmt.Errorf("deployment provided to Apply must not be nil") + } + data, err := json.Marshal(deployment) + if err != nil { + return nil, err + } + name := deployment.Name + if name == nil { + return nil, fmt.Errorf("deployment.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(deploymentsResource, c.ns, *name, types.ApplyPatchType, data), &v1beta2.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.Deployment), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeDeployments) ApplyStatus(ctx context.Context, deployment *appsv1beta2.DeploymentApplyConfiguration, opts v1.ApplyOptions) (result *v1beta2.Deployment, err error) { + if deployment == nil { + return nil, fmt.Errorf("deployment provided to Apply must not be nil") + } + data, err := json.Marshal(deployment) + if err != nil { + return nil, err + } + name := deployment.Name + if name == nil { + return nil, fmt.Errorf("deployment.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(deploymentsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v1beta2.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.Deployment), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_replicaset.go b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_replicaset.go new file mode 100644 index 000000000..2fb89cee0 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_replicaset.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta2 "k8s.io/api/apps/v1beta2" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + appsv1beta2 "k8s.io/client-go/applyconfigurations/apps/v1beta2" + testing "k8s.io/client-go/testing" +) + +// FakeReplicaSets implements ReplicaSetInterface +type FakeReplicaSets struct { + Fake *FakeAppsV1beta2 + ns string +} + +var replicasetsResource = schema.GroupVersionResource{Group: "apps", Version: "v1beta2", Resource: "replicasets"} + +var replicasetsKind = schema.GroupVersionKind{Group: "apps", Version: "v1beta2", Kind: "ReplicaSet"} + +// Get takes name of the replicaSet, and returns the corresponding replicaSet object, and an error if there is any. +func (c *FakeReplicaSets) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta2.ReplicaSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(replicasetsResource, c.ns, name), &v1beta2.ReplicaSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.ReplicaSet), err +} + +// List takes label and field selectors, and returns the list of ReplicaSets that match those selectors. +func (c *FakeReplicaSets) List(ctx context.Context, opts v1.ListOptions) (result *v1beta2.ReplicaSetList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(replicasetsResource, replicasetsKind, c.ns, opts), &v1beta2.ReplicaSetList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta2.ReplicaSetList{ListMeta: obj.(*v1beta2.ReplicaSetList).ListMeta} + for _, item := range obj.(*v1beta2.ReplicaSetList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested replicaSets. +func (c *FakeReplicaSets) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(replicasetsResource, c.ns, opts)) + +} + +// Create takes the representation of a replicaSet and creates it. Returns the server's representation of the replicaSet, and an error, if there is any. +func (c *FakeReplicaSets) Create(ctx context.Context, replicaSet *v1beta2.ReplicaSet, opts v1.CreateOptions) (result *v1beta2.ReplicaSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(replicasetsResource, c.ns, replicaSet), &v1beta2.ReplicaSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.ReplicaSet), err +} + +// Update takes the representation of a replicaSet and updates it. Returns the server's representation of the replicaSet, and an error, if there is any. +func (c *FakeReplicaSets) Update(ctx context.Context, replicaSet *v1beta2.ReplicaSet, opts v1.UpdateOptions) (result *v1beta2.ReplicaSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(replicasetsResource, c.ns, replicaSet), &v1beta2.ReplicaSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.ReplicaSet), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeReplicaSets) UpdateStatus(ctx context.Context, replicaSet *v1beta2.ReplicaSet, opts v1.UpdateOptions) (*v1beta2.ReplicaSet, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(replicasetsResource, "status", c.ns, replicaSet), &v1beta2.ReplicaSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.ReplicaSet), err +} + +// Delete takes name of the replicaSet and deletes it. Returns an error if one occurs. +func (c *FakeReplicaSets) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(replicasetsResource, c.ns, name, opts), &v1beta2.ReplicaSet{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeReplicaSets) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(replicasetsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta2.ReplicaSetList{}) + return err +} + +// Patch applies the patch and returns the patched replicaSet. +func (c *FakeReplicaSets) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta2.ReplicaSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(replicasetsResource, c.ns, name, pt, data, subresources...), &v1beta2.ReplicaSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.ReplicaSet), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied replicaSet. +func (c *FakeReplicaSets) Apply(ctx context.Context, replicaSet *appsv1beta2.ReplicaSetApplyConfiguration, opts v1.ApplyOptions) (result *v1beta2.ReplicaSet, err error) { + if replicaSet == nil { + return nil, fmt.Errorf("replicaSet provided to Apply must not be nil") + } + data, err := json.Marshal(replicaSet) + if err != nil { + return nil, err + } + name := replicaSet.Name + if name == nil { + return nil, fmt.Errorf("replicaSet.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(replicasetsResource, c.ns, *name, types.ApplyPatchType, data), &v1beta2.ReplicaSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.ReplicaSet), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeReplicaSets) ApplyStatus(ctx context.Context, replicaSet *appsv1beta2.ReplicaSetApplyConfiguration, opts v1.ApplyOptions) (result *v1beta2.ReplicaSet, err error) { + if replicaSet == nil { + return nil, fmt.Errorf("replicaSet provided to Apply must not be nil") + } + data, err := json.Marshal(replicaSet) + if err != nil { + return nil, err + } + name := replicaSet.Name + if name == nil { + return nil, fmt.Errorf("replicaSet.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(replicasetsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v1beta2.ReplicaSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.ReplicaSet), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_statefulset.go b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_statefulset.go new file mode 100644 index 000000000..cc9903c0f --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake/fake_statefulset.go @@ -0,0 +1,231 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta2 "k8s.io/api/apps/v1beta2" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + appsv1beta2 "k8s.io/client-go/applyconfigurations/apps/v1beta2" + testing "k8s.io/client-go/testing" +) + +// FakeStatefulSets implements StatefulSetInterface +type FakeStatefulSets struct { + Fake *FakeAppsV1beta2 + ns string +} + +var statefulsetsResource = schema.GroupVersionResource{Group: "apps", Version: "v1beta2", Resource: "statefulsets"} + +var statefulsetsKind = schema.GroupVersionKind{Group: "apps", Version: "v1beta2", Kind: "StatefulSet"} + +// Get takes name of the statefulSet, and returns the corresponding statefulSet object, and an error if there is any. +func (c *FakeStatefulSets) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta2.StatefulSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(statefulsetsResource, c.ns, name), &v1beta2.StatefulSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.StatefulSet), err +} + +// List takes label and field selectors, and returns the list of StatefulSets that match those selectors. +func (c *FakeStatefulSets) List(ctx context.Context, opts v1.ListOptions) (result *v1beta2.StatefulSetList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(statefulsetsResource, statefulsetsKind, c.ns, opts), &v1beta2.StatefulSetList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta2.StatefulSetList{ListMeta: obj.(*v1beta2.StatefulSetList).ListMeta} + for _, item := range obj.(*v1beta2.StatefulSetList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested statefulSets. +func (c *FakeStatefulSets) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(statefulsetsResource, c.ns, opts)) + +} + +// Create takes the representation of a statefulSet and creates it. Returns the server's representation of the statefulSet, and an error, if there is any. +func (c *FakeStatefulSets) Create(ctx context.Context, statefulSet *v1beta2.StatefulSet, opts v1.CreateOptions) (result *v1beta2.StatefulSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(statefulsetsResource, c.ns, statefulSet), &v1beta2.StatefulSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.StatefulSet), err +} + +// Update takes the representation of a statefulSet and updates it. Returns the server's representation of the statefulSet, and an error, if there is any. +func (c *FakeStatefulSets) Update(ctx context.Context, statefulSet *v1beta2.StatefulSet, opts v1.UpdateOptions) (result *v1beta2.StatefulSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(statefulsetsResource, c.ns, statefulSet), &v1beta2.StatefulSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.StatefulSet), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeStatefulSets) UpdateStatus(ctx context.Context, statefulSet *v1beta2.StatefulSet, opts v1.UpdateOptions) (*v1beta2.StatefulSet, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(statefulsetsResource, "status", c.ns, statefulSet), &v1beta2.StatefulSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.StatefulSet), err +} + +// Delete takes name of the statefulSet and deletes it. Returns an error if one occurs. +func (c *FakeStatefulSets) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(statefulsetsResource, c.ns, name, opts), &v1beta2.StatefulSet{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeStatefulSets) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(statefulsetsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta2.StatefulSetList{}) + return err +} + +// Patch applies the patch and returns the patched statefulSet. +func (c *FakeStatefulSets) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta2.StatefulSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(statefulsetsResource, c.ns, name, pt, data, subresources...), &v1beta2.StatefulSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.StatefulSet), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied statefulSet. +func (c *FakeStatefulSets) Apply(ctx context.Context, statefulSet *appsv1beta2.StatefulSetApplyConfiguration, opts v1.ApplyOptions) (result *v1beta2.StatefulSet, err error) { + if statefulSet == nil { + return nil, fmt.Errorf("statefulSet provided to Apply must not be nil") + } + data, err := json.Marshal(statefulSet) + if err != nil { + return nil, err + } + name := statefulSet.Name + if name == nil { + return nil, fmt.Errorf("statefulSet.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(statefulsetsResource, c.ns, *name, types.ApplyPatchType, data), &v1beta2.StatefulSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.StatefulSet), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeStatefulSets) ApplyStatus(ctx context.Context, statefulSet *appsv1beta2.StatefulSetApplyConfiguration, opts v1.ApplyOptions) (result *v1beta2.StatefulSet, err error) { + if statefulSet == nil { + return nil, fmt.Errorf("statefulSet provided to Apply must not be nil") + } + data, err := json.Marshal(statefulSet) + if err != nil { + return nil, err + } + name := statefulSet.Name + if name == nil { + return nil, fmt.Errorf("statefulSet.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(statefulsetsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v1beta2.StatefulSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.StatefulSet), err +} + +// GetScale takes name of the statefulSet, and returns the corresponding scale object, and an error if there is any. +func (c *FakeStatefulSets) GetScale(ctx context.Context, statefulSetName string, options v1.GetOptions) (result *v1beta2.Scale, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetSubresourceAction(statefulsetsResource, c.ns, "scale", statefulSetName), &v1beta2.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.Scale), err +} + +// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *FakeStatefulSets) UpdateScale(ctx context.Context, statefulSetName string, scale *v1beta2.Scale, opts v1.UpdateOptions) (result *v1beta2.Scale, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(statefulsetsResource, "scale", c.ns, scale), &v1beta2.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.Scale), err +} + +// ApplyScale takes top resource name and the apply declarative configuration for scale, +// applies it and returns the applied scale, and an error, if there is any. +func (c *FakeStatefulSets) ApplyScale(ctx context.Context, statefulSetName string, scale *appsv1beta2.ScaleApplyConfiguration, opts v1.ApplyOptions) (result *v1beta2.Scale, err error) { + if scale == nil { + return nil, fmt.Errorf("scale provided to ApplyScale must not be nil") + } + data, err := json.Marshal(scale) + if err != nil { + return nil, err + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(statefulsetsResource, c.ns, statefulSetName, types.ApplyPatchType, data, "status"), &v1beta2.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.Scale), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1/fake/fake_authentication_client.go b/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1/fake/fake_authentication_client.go new file mode 100644 index 000000000..ee06a6cdd --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1/fake/fake_authentication_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/client-go/kubernetes/typed/authentication/v1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeAuthenticationV1 struct { + *testing.Fake +} + +func (c *FakeAuthenticationV1) TokenReviews() v1.TokenReviewInterface { + return &FakeTokenReviews{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeAuthenticationV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1/fake/fake_tokenreview.go b/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1/fake/fake_tokenreview.go new file mode 100644 index 000000000..b85fcfbb8 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1/fake/fake_tokenreview.go @@ -0,0 +1,47 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/api/authentication/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + testing "k8s.io/client-go/testing" +) + +// FakeTokenReviews implements TokenReviewInterface +type FakeTokenReviews struct { + Fake *FakeAuthenticationV1 +} + +var tokenreviewsResource = schema.GroupVersionResource{Group: "authentication.k8s.io", Version: "v1", Resource: "tokenreviews"} + +var tokenreviewsKind = schema.GroupVersionKind{Group: "authentication.k8s.io", Version: "v1", Kind: "TokenReview"} + +// Create takes the representation of a tokenReview and creates it. Returns the server's representation of the tokenReview, and an error, if there is any. +func (c *FakeTokenReviews) Create(ctx context.Context, tokenReview *v1.TokenReview, opts metav1.CreateOptions) (result *v1.TokenReview, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(tokenreviewsResource, tokenReview), &v1.TokenReview{}) + if obj == nil { + return nil, err + } + return obj.(*v1.TokenReview), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1alpha1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1alpha1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1alpha1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1alpha1/fake/fake_authentication_client.go b/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1alpha1/fake/fake_authentication_client.go new file mode 100644 index 000000000..1a1a04f41 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1alpha1/fake/fake_authentication_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "k8s.io/client-go/kubernetes/typed/authentication/v1alpha1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeAuthenticationV1alpha1 struct { + *testing.Fake +} + +func (c *FakeAuthenticationV1alpha1) SelfSubjectReviews() v1alpha1.SelfSubjectReviewInterface { + return &FakeSelfSubjectReviews{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeAuthenticationV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1alpha1/fake/fake_selfsubjectreview.go b/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1alpha1/fake/fake_selfsubjectreview.go new file mode 100644 index 000000000..6bb1c2508 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1alpha1/fake/fake_selfsubjectreview.go @@ -0,0 +1,47 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1alpha1 "k8s.io/api/authentication/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + testing "k8s.io/client-go/testing" +) + +// FakeSelfSubjectReviews implements SelfSubjectReviewInterface +type FakeSelfSubjectReviews struct { + Fake *FakeAuthenticationV1alpha1 +} + +var selfsubjectreviewsResource = schema.GroupVersionResource{Group: "authentication.k8s.io", Version: "v1alpha1", Resource: "selfsubjectreviews"} + +var selfsubjectreviewsKind = schema.GroupVersionKind{Group: "authentication.k8s.io", Version: "v1alpha1", Kind: "SelfSubjectReview"} + +// Create takes the representation of a selfSubjectReview and creates it. Returns the server's representation of the selfSubjectReview, and an error, if there is any. +func (c *FakeSelfSubjectReviews) Create(ctx context.Context, selfSubjectReview *v1alpha1.SelfSubjectReview, opts v1.CreateOptions) (result *v1alpha1.SelfSubjectReview, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(selfsubjectreviewsResource, selfSubjectReview), &v1alpha1.SelfSubjectReview{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.SelfSubjectReview), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1beta1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1beta1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1beta1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1beta1/fake/fake_authentication_client.go b/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1beta1/fake/fake_authentication_client.go new file mode 100644 index 000000000..7299653ca --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1beta1/fake/fake_authentication_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1beta1 "k8s.io/client-go/kubernetes/typed/authentication/v1beta1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeAuthenticationV1beta1 struct { + *testing.Fake +} + +func (c *FakeAuthenticationV1beta1) TokenReviews() v1beta1.TokenReviewInterface { + return &FakeTokenReviews{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeAuthenticationV1beta1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1beta1/fake/fake_tokenreview.go b/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1beta1/fake/fake_tokenreview.go new file mode 100644 index 000000000..0da3ec6f4 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/authentication/v1beta1/fake/fake_tokenreview.go @@ -0,0 +1,47 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1beta1 "k8s.io/api/authentication/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + testing "k8s.io/client-go/testing" +) + +// FakeTokenReviews implements TokenReviewInterface +type FakeTokenReviews struct { + Fake *FakeAuthenticationV1beta1 +} + +var tokenreviewsResource = schema.GroupVersionResource{Group: "authentication.k8s.io", Version: "v1beta1", Resource: "tokenreviews"} + +var tokenreviewsKind = schema.GroupVersionKind{Group: "authentication.k8s.io", Version: "v1beta1", Kind: "TokenReview"} + +// Create takes the representation of a tokenReview and creates it. Returns the server's representation of the tokenReview, and an error, if there is any. +func (c *FakeTokenReviews) Create(ctx context.Context, tokenReview *v1beta1.TokenReview, opts v1.CreateOptions) (result *v1beta1.TokenReview, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(tokenreviewsResource, tokenReview), &v1beta1.TokenReview{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.TokenReview), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/fake_authorization_client.go b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/fake_authorization_client.go new file mode 100644 index 000000000..f7e823450 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/fake_authorization_client.go @@ -0,0 +1,52 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/client-go/kubernetes/typed/authorization/v1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeAuthorizationV1 struct { + *testing.Fake +} + +func (c *FakeAuthorizationV1) LocalSubjectAccessReviews(namespace string) v1.LocalSubjectAccessReviewInterface { + return &FakeLocalSubjectAccessReviews{c, namespace} +} + +func (c *FakeAuthorizationV1) SelfSubjectAccessReviews() v1.SelfSubjectAccessReviewInterface { + return &FakeSelfSubjectAccessReviews{c} +} + +func (c *FakeAuthorizationV1) SelfSubjectRulesReviews() v1.SelfSubjectRulesReviewInterface { + return &FakeSelfSubjectRulesReviews{c} +} + +func (c *FakeAuthorizationV1) SubjectAccessReviews() v1.SubjectAccessReviewInterface { + return &FakeSubjectAccessReviews{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeAuthorizationV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/fake_localsubjectaccessreview.go b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/fake_localsubjectaccessreview.go new file mode 100644 index 000000000..d74ae0a47 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/fake_localsubjectaccessreview.go @@ -0,0 +1,49 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/api/authorization/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + testing "k8s.io/client-go/testing" +) + +// FakeLocalSubjectAccessReviews implements LocalSubjectAccessReviewInterface +type FakeLocalSubjectAccessReviews struct { + Fake *FakeAuthorizationV1 + ns string +} + +var localsubjectaccessreviewsResource = schema.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1", Resource: "localsubjectaccessreviews"} + +var localsubjectaccessreviewsKind = schema.GroupVersionKind{Group: "authorization.k8s.io", Version: "v1", Kind: "LocalSubjectAccessReview"} + +// Create takes the representation of a localSubjectAccessReview and creates it. Returns the server's representation of the localSubjectAccessReview, and an error, if there is any. +func (c *FakeLocalSubjectAccessReviews) Create(ctx context.Context, localSubjectAccessReview *v1.LocalSubjectAccessReview, opts metav1.CreateOptions) (result *v1.LocalSubjectAccessReview, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(localsubjectaccessreviewsResource, c.ns, localSubjectAccessReview), &v1.LocalSubjectAccessReview{}) + + if obj == nil { + return nil, err + } + return obj.(*v1.LocalSubjectAccessReview), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/fake_selfsubjectaccessreview.go b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/fake_selfsubjectaccessreview.go new file mode 100644 index 000000000..80ebbbd45 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/fake_selfsubjectaccessreview.go @@ -0,0 +1,47 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/api/authorization/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + testing "k8s.io/client-go/testing" +) + +// FakeSelfSubjectAccessReviews implements SelfSubjectAccessReviewInterface +type FakeSelfSubjectAccessReviews struct { + Fake *FakeAuthorizationV1 +} + +var selfsubjectaccessreviewsResource = schema.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1", Resource: "selfsubjectaccessreviews"} + +var selfsubjectaccessreviewsKind = schema.GroupVersionKind{Group: "authorization.k8s.io", Version: "v1", Kind: "SelfSubjectAccessReview"} + +// Create takes the representation of a selfSubjectAccessReview and creates it. Returns the server's representation of the selfSubjectAccessReview, and an error, if there is any. +func (c *FakeSelfSubjectAccessReviews) Create(ctx context.Context, selfSubjectAccessReview *v1.SelfSubjectAccessReview, opts metav1.CreateOptions) (result *v1.SelfSubjectAccessReview, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(selfsubjectaccessreviewsResource, selfSubjectAccessReview), &v1.SelfSubjectAccessReview{}) + if obj == nil { + return nil, err + } + return obj.(*v1.SelfSubjectAccessReview), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/fake_selfsubjectrulesreview.go b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/fake_selfsubjectrulesreview.go new file mode 100644 index 000000000..dd70908ad --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/fake_selfsubjectrulesreview.go @@ -0,0 +1,47 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/api/authorization/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + testing "k8s.io/client-go/testing" +) + +// FakeSelfSubjectRulesReviews implements SelfSubjectRulesReviewInterface +type FakeSelfSubjectRulesReviews struct { + Fake *FakeAuthorizationV1 +} + +var selfsubjectrulesreviewsResource = schema.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1", Resource: "selfsubjectrulesreviews"} + +var selfsubjectrulesreviewsKind = schema.GroupVersionKind{Group: "authorization.k8s.io", Version: "v1", Kind: "SelfSubjectRulesReview"} + +// Create takes the representation of a selfSubjectRulesReview and creates it. Returns the server's representation of the selfSubjectRulesReview, and an error, if there is any. +func (c *FakeSelfSubjectRulesReviews) Create(ctx context.Context, selfSubjectRulesReview *v1.SelfSubjectRulesReview, opts metav1.CreateOptions) (result *v1.SelfSubjectRulesReview, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(selfsubjectrulesreviewsResource, selfSubjectRulesReview), &v1.SelfSubjectRulesReview{}) + if obj == nil { + return nil, err + } + return obj.(*v1.SelfSubjectRulesReview), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/fake_subjectaccessreview.go b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/fake_subjectaccessreview.go new file mode 100644 index 000000000..b480b2b41 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1/fake/fake_subjectaccessreview.go @@ -0,0 +1,47 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/api/authorization/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + testing "k8s.io/client-go/testing" +) + +// FakeSubjectAccessReviews implements SubjectAccessReviewInterface +type FakeSubjectAccessReviews struct { + Fake *FakeAuthorizationV1 +} + +var subjectaccessreviewsResource = schema.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1", Resource: "subjectaccessreviews"} + +var subjectaccessreviewsKind = schema.GroupVersionKind{Group: "authorization.k8s.io", Version: "v1", Kind: "SubjectAccessReview"} + +// Create takes the representation of a subjectAccessReview and creates it. Returns the server's representation of the subjectAccessReview, and an error, if there is any. +func (c *FakeSubjectAccessReviews) Create(ctx context.Context, subjectAccessReview *v1.SubjectAccessReview, opts metav1.CreateOptions) (result *v1.SubjectAccessReview, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(subjectaccessreviewsResource, subjectAccessReview), &v1.SubjectAccessReview{}) + if obj == nil { + return nil, err + } + return obj.(*v1.SubjectAccessReview), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/fake_authorization_client.go b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/fake_authorization_client.go new file mode 100644 index 000000000..8e328a57b --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/fake_authorization_client.go @@ -0,0 +1,52 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1beta1 "k8s.io/client-go/kubernetes/typed/authorization/v1beta1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeAuthorizationV1beta1 struct { + *testing.Fake +} + +func (c *FakeAuthorizationV1beta1) LocalSubjectAccessReviews(namespace string) v1beta1.LocalSubjectAccessReviewInterface { + return &FakeLocalSubjectAccessReviews{c, namespace} +} + +func (c *FakeAuthorizationV1beta1) SelfSubjectAccessReviews() v1beta1.SelfSubjectAccessReviewInterface { + return &FakeSelfSubjectAccessReviews{c} +} + +func (c *FakeAuthorizationV1beta1) SelfSubjectRulesReviews() v1beta1.SelfSubjectRulesReviewInterface { + return &FakeSelfSubjectRulesReviews{c} +} + +func (c *FakeAuthorizationV1beta1) SubjectAccessReviews() v1beta1.SubjectAccessReviewInterface { + return &FakeSubjectAccessReviews{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeAuthorizationV1beta1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/fake_localsubjectaccessreview.go b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/fake_localsubjectaccessreview.go new file mode 100644 index 000000000..2d3ba4462 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/fake_localsubjectaccessreview.go @@ -0,0 +1,49 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1beta1 "k8s.io/api/authorization/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + testing "k8s.io/client-go/testing" +) + +// FakeLocalSubjectAccessReviews implements LocalSubjectAccessReviewInterface +type FakeLocalSubjectAccessReviews struct { + Fake *FakeAuthorizationV1beta1 + ns string +} + +var localsubjectaccessreviewsResource = schema.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1beta1", Resource: "localsubjectaccessreviews"} + +var localsubjectaccessreviewsKind = schema.GroupVersionKind{Group: "authorization.k8s.io", Version: "v1beta1", Kind: "LocalSubjectAccessReview"} + +// Create takes the representation of a localSubjectAccessReview and creates it. Returns the server's representation of the localSubjectAccessReview, and an error, if there is any. +func (c *FakeLocalSubjectAccessReviews) Create(ctx context.Context, localSubjectAccessReview *v1beta1.LocalSubjectAccessReview, opts v1.CreateOptions) (result *v1beta1.LocalSubjectAccessReview, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(localsubjectaccessreviewsResource, c.ns, localSubjectAccessReview), &v1beta1.LocalSubjectAccessReview{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.LocalSubjectAccessReview), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/fake_selfsubjectaccessreview.go b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/fake_selfsubjectaccessreview.go new file mode 100644 index 000000000..febe90c77 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/fake_selfsubjectaccessreview.go @@ -0,0 +1,47 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1beta1 "k8s.io/api/authorization/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + testing "k8s.io/client-go/testing" +) + +// FakeSelfSubjectAccessReviews implements SelfSubjectAccessReviewInterface +type FakeSelfSubjectAccessReviews struct { + Fake *FakeAuthorizationV1beta1 +} + +var selfsubjectaccessreviewsResource = schema.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1beta1", Resource: "selfsubjectaccessreviews"} + +var selfsubjectaccessreviewsKind = schema.GroupVersionKind{Group: "authorization.k8s.io", Version: "v1beta1", Kind: "SelfSubjectAccessReview"} + +// Create takes the representation of a selfSubjectAccessReview and creates it. Returns the server's representation of the selfSubjectAccessReview, and an error, if there is any. +func (c *FakeSelfSubjectAccessReviews) Create(ctx context.Context, selfSubjectAccessReview *v1beta1.SelfSubjectAccessReview, opts v1.CreateOptions) (result *v1beta1.SelfSubjectAccessReview, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(selfsubjectaccessreviewsResource, selfSubjectAccessReview), &v1beta1.SelfSubjectAccessReview{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.SelfSubjectAccessReview), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/fake_selfsubjectrulesreview.go b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/fake_selfsubjectrulesreview.go new file mode 100644 index 000000000..02df06012 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/fake_selfsubjectrulesreview.go @@ -0,0 +1,47 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1beta1 "k8s.io/api/authorization/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + testing "k8s.io/client-go/testing" +) + +// FakeSelfSubjectRulesReviews implements SelfSubjectRulesReviewInterface +type FakeSelfSubjectRulesReviews struct { + Fake *FakeAuthorizationV1beta1 +} + +var selfsubjectrulesreviewsResource = schema.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1beta1", Resource: "selfsubjectrulesreviews"} + +var selfsubjectrulesreviewsKind = schema.GroupVersionKind{Group: "authorization.k8s.io", Version: "v1beta1", Kind: "SelfSubjectRulesReview"} + +// Create takes the representation of a selfSubjectRulesReview and creates it. Returns the server's representation of the selfSubjectRulesReview, and an error, if there is any. +func (c *FakeSelfSubjectRulesReviews) Create(ctx context.Context, selfSubjectRulesReview *v1beta1.SelfSubjectRulesReview, opts v1.CreateOptions) (result *v1beta1.SelfSubjectRulesReview, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(selfsubjectrulesreviewsResource, selfSubjectRulesReview), &v1beta1.SelfSubjectRulesReview{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.SelfSubjectRulesReview), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/fake_subjectaccessreview.go b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/fake_subjectaccessreview.go new file mode 100644 index 000000000..b5be913c4 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake/fake_subjectaccessreview.go @@ -0,0 +1,47 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1beta1 "k8s.io/api/authorization/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + testing "k8s.io/client-go/testing" +) + +// FakeSubjectAccessReviews implements SubjectAccessReviewInterface +type FakeSubjectAccessReviews struct { + Fake *FakeAuthorizationV1beta1 +} + +var subjectaccessreviewsResource = schema.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1beta1", Resource: "subjectaccessreviews"} + +var subjectaccessreviewsKind = schema.GroupVersionKind{Group: "authorization.k8s.io", Version: "v1beta1", Kind: "SubjectAccessReview"} + +// Create takes the representation of a subjectAccessReview and creates it. Returns the server's representation of the subjectAccessReview, and an error, if there is any. +func (c *FakeSubjectAccessReviews) Create(ctx context.Context, subjectAccessReview *v1beta1.SubjectAccessReview, opts v1.CreateOptions) (result *v1beta1.SubjectAccessReview, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(subjectaccessreviewsResource, subjectAccessReview), &v1beta1.SubjectAccessReview{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.SubjectAccessReview), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v1/fake/fake_autoscaling_client.go b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v1/fake/fake_autoscaling_client.go new file mode 100644 index 000000000..99e26fcf3 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v1/fake/fake_autoscaling_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/client-go/kubernetes/typed/autoscaling/v1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeAutoscalingV1 struct { + *testing.Fake +} + +func (c *FakeAutoscalingV1) HorizontalPodAutoscalers(namespace string) v1.HorizontalPodAutoscalerInterface { + return &FakeHorizontalPodAutoscalers{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeAutoscalingV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v1/fake/fake_horizontalpodautoscaler.go b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v1/fake/fake_horizontalpodautoscaler.go new file mode 100644 index 000000000..dcd47480b --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v1/fake/fake_horizontalpodautoscaler.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + autoscalingv1 "k8s.io/api/autoscaling/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsautoscalingv1 "k8s.io/client-go/applyconfigurations/autoscaling/v1" + testing "k8s.io/client-go/testing" +) + +// FakeHorizontalPodAutoscalers implements HorizontalPodAutoscalerInterface +type FakeHorizontalPodAutoscalers struct { + Fake *FakeAutoscalingV1 + ns string +} + +var horizontalpodautoscalersResource = schema.GroupVersionResource{Group: "autoscaling", Version: "v1", Resource: "horizontalpodautoscalers"} + +var horizontalpodautoscalersKind = schema.GroupVersionKind{Group: "autoscaling", Version: "v1", Kind: "HorizontalPodAutoscaler"} + +// Get takes name of the horizontalPodAutoscaler, and returns the corresponding horizontalPodAutoscaler object, and an error if there is any. +func (c *FakeHorizontalPodAutoscalers) Get(ctx context.Context, name string, options v1.GetOptions) (result *autoscalingv1.HorizontalPodAutoscaler, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(horizontalpodautoscalersResource, c.ns, name), &autoscalingv1.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*autoscalingv1.HorizontalPodAutoscaler), err +} + +// List takes label and field selectors, and returns the list of HorizontalPodAutoscalers that match those selectors. +func (c *FakeHorizontalPodAutoscalers) List(ctx context.Context, opts v1.ListOptions) (result *autoscalingv1.HorizontalPodAutoscalerList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(horizontalpodautoscalersResource, horizontalpodautoscalersKind, c.ns, opts), &autoscalingv1.HorizontalPodAutoscalerList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &autoscalingv1.HorizontalPodAutoscalerList{ListMeta: obj.(*autoscalingv1.HorizontalPodAutoscalerList).ListMeta} + for _, item := range obj.(*autoscalingv1.HorizontalPodAutoscalerList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested horizontalPodAutoscalers. +func (c *FakeHorizontalPodAutoscalers) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(horizontalpodautoscalersResource, c.ns, opts)) + +} + +// Create takes the representation of a horizontalPodAutoscaler and creates it. Returns the server's representation of the horizontalPodAutoscaler, and an error, if there is any. +func (c *FakeHorizontalPodAutoscalers) Create(ctx context.Context, horizontalPodAutoscaler *autoscalingv1.HorizontalPodAutoscaler, opts v1.CreateOptions) (result *autoscalingv1.HorizontalPodAutoscaler, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(horizontalpodautoscalersResource, c.ns, horizontalPodAutoscaler), &autoscalingv1.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*autoscalingv1.HorizontalPodAutoscaler), err +} + +// Update takes the representation of a horizontalPodAutoscaler and updates it. Returns the server's representation of the horizontalPodAutoscaler, and an error, if there is any. +func (c *FakeHorizontalPodAutoscalers) Update(ctx context.Context, horizontalPodAutoscaler *autoscalingv1.HorizontalPodAutoscaler, opts v1.UpdateOptions) (result *autoscalingv1.HorizontalPodAutoscaler, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(horizontalpodautoscalersResource, c.ns, horizontalPodAutoscaler), &autoscalingv1.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*autoscalingv1.HorizontalPodAutoscaler), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeHorizontalPodAutoscalers) UpdateStatus(ctx context.Context, horizontalPodAutoscaler *autoscalingv1.HorizontalPodAutoscaler, opts v1.UpdateOptions) (*autoscalingv1.HorizontalPodAutoscaler, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(horizontalpodautoscalersResource, "status", c.ns, horizontalPodAutoscaler), &autoscalingv1.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*autoscalingv1.HorizontalPodAutoscaler), err +} + +// Delete takes name of the horizontalPodAutoscaler and deletes it. Returns an error if one occurs. +func (c *FakeHorizontalPodAutoscalers) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(horizontalpodautoscalersResource, c.ns, name, opts), &autoscalingv1.HorizontalPodAutoscaler{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeHorizontalPodAutoscalers) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(horizontalpodautoscalersResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &autoscalingv1.HorizontalPodAutoscalerList{}) + return err +} + +// Patch applies the patch and returns the patched horizontalPodAutoscaler. +func (c *FakeHorizontalPodAutoscalers) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *autoscalingv1.HorizontalPodAutoscaler, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(horizontalpodautoscalersResource, c.ns, name, pt, data, subresources...), &autoscalingv1.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*autoscalingv1.HorizontalPodAutoscaler), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied horizontalPodAutoscaler. +func (c *FakeHorizontalPodAutoscalers) Apply(ctx context.Context, horizontalPodAutoscaler *applyconfigurationsautoscalingv1.HorizontalPodAutoscalerApplyConfiguration, opts v1.ApplyOptions) (result *autoscalingv1.HorizontalPodAutoscaler, err error) { + if horizontalPodAutoscaler == nil { + return nil, fmt.Errorf("horizontalPodAutoscaler provided to Apply must not be nil") + } + data, err := json.Marshal(horizontalPodAutoscaler) + if err != nil { + return nil, err + } + name := horizontalPodAutoscaler.Name + if name == nil { + return nil, fmt.Errorf("horizontalPodAutoscaler.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(horizontalpodautoscalersResource, c.ns, *name, types.ApplyPatchType, data), &autoscalingv1.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*autoscalingv1.HorizontalPodAutoscaler), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeHorizontalPodAutoscalers) ApplyStatus(ctx context.Context, horizontalPodAutoscaler *applyconfigurationsautoscalingv1.HorizontalPodAutoscalerApplyConfiguration, opts v1.ApplyOptions) (result *autoscalingv1.HorizontalPodAutoscaler, err error) { + if horizontalPodAutoscaler == nil { + return nil, fmt.Errorf("horizontalPodAutoscaler provided to Apply must not be nil") + } + data, err := json.Marshal(horizontalPodAutoscaler) + if err != nil { + return nil, err + } + name := horizontalPodAutoscaler.Name + if name == nil { + return nil, fmt.Errorf("horizontalPodAutoscaler.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(horizontalpodautoscalersResource, c.ns, *name, types.ApplyPatchType, data, "status"), &autoscalingv1.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*autoscalingv1.HorizontalPodAutoscaler), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2/fake/fake_autoscaling_client.go b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2/fake/fake_autoscaling_client.go new file mode 100644 index 000000000..d4b907f4b --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2/fake/fake_autoscaling_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v2 "k8s.io/client-go/kubernetes/typed/autoscaling/v2" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeAutoscalingV2 struct { + *testing.Fake +} + +func (c *FakeAutoscalingV2) HorizontalPodAutoscalers(namespace string) v2.HorizontalPodAutoscalerInterface { + return &FakeHorizontalPodAutoscalers{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeAutoscalingV2) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2/fake/fake_horizontalpodautoscaler.go b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2/fake/fake_horizontalpodautoscaler.go new file mode 100644 index 000000000..ca4b24704 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2/fake/fake_horizontalpodautoscaler.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v2 "k8s.io/api/autoscaling/v2" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + autoscalingv2 "k8s.io/client-go/applyconfigurations/autoscaling/v2" + testing "k8s.io/client-go/testing" +) + +// FakeHorizontalPodAutoscalers implements HorizontalPodAutoscalerInterface +type FakeHorizontalPodAutoscalers struct { + Fake *FakeAutoscalingV2 + ns string +} + +var horizontalpodautoscalersResource = schema.GroupVersionResource{Group: "autoscaling", Version: "v2", Resource: "horizontalpodautoscalers"} + +var horizontalpodautoscalersKind = schema.GroupVersionKind{Group: "autoscaling", Version: "v2", Kind: "HorizontalPodAutoscaler"} + +// Get takes name of the horizontalPodAutoscaler, and returns the corresponding horizontalPodAutoscaler object, and an error if there is any. +func (c *FakeHorizontalPodAutoscalers) Get(ctx context.Context, name string, options v1.GetOptions) (result *v2.HorizontalPodAutoscaler, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(horizontalpodautoscalersResource, c.ns, name), &v2.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*v2.HorizontalPodAutoscaler), err +} + +// List takes label and field selectors, and returns the list of HorizontalPodAutoscalers that match those selectors. +func (c *FakeHorizontalPodAutoscalers) List(ctx context.Context, opts v1.ListOptions) (result *v2.HorizontalPodAutoscalerList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(horizontalpodautoscalersResource, horizontalpodautoscalersKind, c.ns, opts), &v2.HorizontalPodAutoscalerList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v2.HorizontalPodAutoscalerList{ListMeta: obj.(*v2.HorizontalPodAutoscalerList).ListMeta} + for _, item := range obj.(*v2.HorizontalPodAutoscalerList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested horizontalPodAutoscalers. +func (c *FakeHorizontalPodAutoscalers) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(horizontalpodautoscalersResource, c.ns, opts)) + +} + +// Create takes the representation of a horizontalPodAutoscaler and creates it. Returns the server's representation of the horizontalPodAutoscaler, and an error, if there is any. +func (c *FakeHorizontalPodAutoscalers) Create(ctx context.Context, horizontalPodAutoscaler *v2.HorizontalPodAutoscaler, opts v1.CreateOptions) (result *v2.HorizontalPodAutoscaler, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(horizontalpodautoscalersResource, c.ns, horizontalPodAutoscaler), &v2.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*v2.HorizontalPodAutoscaler), err +} + +// Update takes the representation of a horizontalPodAutoscaler and updates it. Returns the server's representation of the horizontalPodAutoscaler, and an error, if there is any. +func (c *FakeHorizontalPodAutoscalers) Update(ctx context.Context, horizontalPodAutoscaler *v2.HorizontalPodAutoscaler, opts v1.UpdateOptions) (result *v2.HorizontalPodAutoscaler, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(horizontalpodautoscalersResource, c.ns, horizontalPodAutoscaler), &v2.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*v2.HorizontalPodAutoscaler), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeHorizontalPodAutoscalers) UpdateStatus(ctx context.Context, horizontalPodAutoscaler *v2.HorizontalPodAutoscaler, opts v1.UpdateOptions) (*v2.HorizontalPodAutoscaler, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(horizontalpodautoscalersResource, "status", c.ns, horizontalPodAutoscaler), &v2.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*v2.HorizontalPodAutoscaler), err +} + +// Delete takes name of the horizontalPodAutoscaler and deletes it. Returns an error if one occurs. +func (c *FakeHorizontalPodAutoscalers) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(horizontalpodautoscalersResource, c.ns, name, opts), &v2.HorizontalPodAutoscaler{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeHorizontalPodAutoscalers) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(horizontalpodautoscalersResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v2.HorizontalPodAutoscalerList{}) + return err +} + +// Patch applies the patch and returns the patched horizontalPodAutoscaler. +func (c *FakeHorizontalPodAutoscalers) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2.HorizontalPodAutoscaler, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(horizontalpodautoscalersResource, c.ns, name, pt, data, subresources...), &v2.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*v2.HorizontalPodAutoscaler), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied horizontalPodAutoscaler. +func (c *FakeHorizontalPodAutoscalers) Apply(ctx context.Context, horizontalPodAutoscaler *autoscalingv2.HorizontalPodAutoscalerApplyConfiguration, opts v1.ApplyOptions) (result *v2.HorizontalPodAutoscaler, err error) { + if horizontalPodAutoscaler == nil { + return nil, fmt.Errorf("horizontalPodAutoscaler provided to Apply must not be nil") + } + data, err := json.Marshal(horizontalPodAutoscaler) + if err != nil { + return nil, err + } + name := horizontalPodAutoscaler.Name + if name == nil { + return nil, fmt.Errorf("horizontalPodAutoscaler.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(horizontalpodautoscalersResource, c.ns, *name, types.ApplyPatchType, data), &v2.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*v2.HorizontalPodAutoscaler), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeHorizontalPodAutoscalers) ApplyStatus(ctx context.Context, horizontalPodAutoscaler *autoscalingv2.HorizontalPodAutoscalerApplyConfiguration, opts v1.ApplyOptions) (result *v2.HorizontalPodAutoscaler, err error) { + if horizontalPodAutoscaler == nil { + return nil, fmt.Errorf("horizontalPodAutoscaler provided to Apply must not be nil") + } + data, err := json.Marshal(horizontalPodAutoscaler) + if err != nil { + return nil, err + } + name := horizontalPodAutoscaler.Name + if name == nil { + return nil, fmt.Errorf("horizontalPodAutoscaler.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(horizontalpodautoscalersResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v2.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*v2.HorizontalPodAutoscaler), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1/fake/fake_autoscaling_client.go b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1/fake/fake_autoscaling_client.go new file mode 100644 index 000000000..be8e0f48e --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1/fake/fake_autoscaling_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v2beta1 "k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeAutoscalingV2beta1 struct { + *testing.Fake +} + +func (c *FakeAutoscalingV2beta1) HorizontalPodAutoscalers(namespace string) v2beta1.HorizontalPodAutoscalerInterface { + return &FakeHorizontalPodAutoscalers{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeAutoscalingV2beta1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1/fake/fake_horizontalpodautoscaler.go b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1/fake/fake_horizontalpodautoscaler.go new file mode 100644 index 000000000..2a750abdd --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1/fake/fake_horizontalpodautoscaler.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v2beta1 "k8s.io/api/autoscaling/v2beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + autoscalingv2beta1 "k8s.io/client-go/applyconfigurations/autoscaling/v2beta1" + testing "k8s.io/client-go/testing" +) + +// FakeHorizontalPodAutoscalers implements HorizontalPodAutoscalerInterface +type FakeHorizontalPodAutoscalers struct { + Fake *FakeAutoscalingV2beta1 + ns string +} + +var horizontalpodautoscalersResource = schema.GroupVersionResource{Group: "autoscaling", Version: "v2beta1", Resource: "horizontalpodautoscalers"} + +var horizontalpodautoscalersKind = schema.GroupVersionKind{Group: "autoscaling", Version: "v2beta1", Kind: "HorizontalPodAutoscaler"} + +// Get takes name of the horizontalPodAutoscaler, and returns the corresponding horizontalPodAutoscaler object, and an error if there is any. +func (c *FakeHorizontalPodAutoscalers) Get(ctx context.Context, name string, options v1.GetOptions) (result *v2beta1.HorizontalPodAutoscaler, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(horizontalpodautoscalersResource, c.ns, name), &v2beta1.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*v2beta1.HorizontalPodAutoscaler), err +} + +// List takes label and field selectors, and returns the list of HorizontalPodAutoscalers that match those selectors. +func (c *FakeHorizontalPodAutoscalers) List(ctx context.Context, opts v1.ListOptions) (result *v2beta1.HorizontalPodAutoscalerList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(horizontalpodautoscalersResource, horizontalpodautoscalersKind, c.ns, opts), &v2beta1.HorizontalPodAutoscalerList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v2beta1.HorizontalPodAutoscalerList{ListMeta: obj.(*v2beta1.HorizontalPodAutoscalerList).ListMeta} + for _, item := range obj.(*v2beta1.HorizontalPodAutoscalerList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested horizontalPodAutoscalers. +func (c *FakeHorizontalPodAutoscalers) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(horizontalpodautoscalersResource, c.ns, opts)) + +} + +// Create takes the representation of a horizontalPodAutoscaler and creates it. Returns the server's representation of the horizontalPodAutoscaler, and an error, if there is any. +func (c *FakeHorizontalPodAutoscalers) Create(ctx context.Context, horizontalPodAutoscaler *v2beta1.HorizontalPodAutoscaler, opts v1.CreateOptions) (result *v2beta1.HorizontalPodAutoscaler, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(horizontalpodautoscalersResource, c.ns, horizontalPodAutoscaler), &v2beta1.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*v2beta1.HorizontalPodAutoscaler), err +} + +// Update takes the representation of a horizontalPodAutoscaler and updates it. Returns the server's representation of the horizontalPodAutoscaler, and an error, if there is any. +func (c *FakeHorizontalPodAutoscalers) Update(ctx context.Context, horizontalPodAutoscaler *v2beta1.HorizontalPodAutoscaler, opts v1.UpdateOptions) (result *v2beta1.HorizontalPodAutoscaler, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(horizontalpodautoscalersResource, c.ns, horizontalPodAutoscaler), &v2beta1.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*v2beta1.HorizontalPodAutoscaler), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeHorizontalPodAutoscalers) UpdateStatus(ctx context.Context, horizontalPodAutoscaler *v2beta1.HorizontalPodAutoscaler, opts v1.UpdateOptions) (*v2beta1.HorizontalPodAutoscaler, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(horizontalpodautoscalersResource, "status", c.ns, horizontalPodAutoscaler), &v2beta1.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*v2beta1.HorizontalPodAutoscaler), err +} + +// Delete takes name of the horizontalPodAutoscaler and deletes it. Returns an error if one occurs. +func (c *FakeHorizontalPodAutoscalers) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(horizontalpodautoscalersResource, c.ns, name, opts), &v2beta1.HorizontalPodAutoscaler{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeHorizontalPodAutoscalers) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(horizontalpodautoscalersResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v2beta1.HorizontalPodAutoscalerList{}) + return err +} + +// Patch applies the patch and returns the patched horizontalPodAutoscaler. +func (c *FakeHorizontalPodAutoscalers) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2beta1.HorizontalPodAutoscaler, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(horizontalpodautoscalersResource, c.ns, name, pt, data, subresources...), &v2beta1.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*v2beta1.HorizontalPodAutoscaler), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied horizontalPodAutoscaler. +func (c *FakeHorizontalPodAutoscalers) Apply(ctx context.Context, horizontalPodAutoscaler *autoscalingv2beta1.HorizontalPodAutoscalerApplyConfiguration, opts v1.ApplyOptions) (result *v2beta1.HorizontalPodAutoscaler, err error) { + if horizontalPodAutoscaler == nil { + return nil, fmt.Errorf("horizontalPodAutoscaler provided to Apply must not be nil") + } + data, err := json.Marshal(horizontalPodAutoscaler) + if err != nil { + return nil, err + } + name := horizontalPodAutoscaler.Name + if name == nil { + return nil, fmt.Errorf("horizontalPodAutoscaler.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(horizontalpodautoscalersResource, c.ns, *name, types.ApplyPatchType, data), &v2beta1.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*v2beta1.HorizontalPodAutoscaler), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeHorizontalPodAutoscalers) ApplyStatus(ctx context.Context, horizontalPodAutoscaler *autoscalingv2beta1.HorizontalPodAutoscalerApplyConfiguration, opts v1.ApplyOptions) (result *v2beta1.HorizontalPodAutoscaler, err error) { + if horizontalPodAutoscaler == nil { + return nil, fmt.Errorf("horizontalPodAutoscaler provided to Apply must not be nil") + } + data, err := json.Marshal(horizontalPodAutoscaler) + if err != nil { + return nil, err + } + name := horizontalPodAutoscaler.Name + if name == nil { + return nil, fmt.Errorf("horizontalPodAutoscaler.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(horizontalpodautoscalersResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v2beta1.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*v2beta1.HorizontalPodAutoscaler), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta2/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta2/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta2/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta2/fake/fake_autoscaling_client.go b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta2/fake/fake_autoscaling_client.go new file mode 100644 index 000000000..8c36e0e81 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta2/fake/fake_autoscaling_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v2beta2 "k8s.io/client-go/kubernetes/typed/autoscaling/v2beta2" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeAutoscalingV2beta2 struct { + *testing.Fake +} + +func (c *FakeAutoscalingV2beta2) HorizontalPodAutoscalers(namespace string) v2beta2.HorizontalPodAutoscalerInterface { + return &FakeHorizontalPodAutoscalers{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeAutoscalingV2beta2) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta2/fake/fake_horizontalpodautoscaler.go b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta2/fake/fake_horizontalpodautoscaler.go new file mode 100644 index 000000000..00d642d85 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v2beta2/fake/fake_horizontalpodautoscaler.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v2beta2 "k8s.io/api/autoscaling/v2beta2" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + autoscalingv2beta2 "k8s.io/client-go/applyconfigurations/autoscaling/v2beta2" + testing "k8s.io/client-go/testing" +) + +// FakeHorizontalPodAutoscalers implements HorizontalPodAutoscalerInterface +type FakeHorizontalPodAutoscalers struct { + Fake *FakeAutoscalingV2beta2 + ns string +} + +var horizontalpodautoscalersResource = schema.GroupVersionResource{Group: "autoscaling", Version: "v2beta2", Resource: "horizontalpodautoscalers"} + +var horizontalpodautoscalersKind = schema.GroupVersionKind{Group: "autoscaling", Version: "v2beta2", Kind: "HorizontalPodAutoscaler"} + +// Get takes name of the horizontalPodAutoscaler, and returns the corresponding horizontalPodAutoscaler object, and an error if there is any. +func (c *FakeHorizontalPodAutoscalers) Get(ctx context.Context, name string, options v1.GetOptions) (result *v2beta2.HorizontalPodAutoscaler, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(horizontalpodautoscalersResource, c.ns, name), &v2beta2.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*v2beta2.HorizontalPodAutoscaler), err +} + +// List takes label and field selectors, and returns the list of HorizontalPodAutoscalers that match those selectors. +func (c *FakeHorizontalPodAutoscalers) List(ctx context.Context, opts v1.ListOptions) (result *v2beta2.HorizontalPodAutoscalerList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(horizontalpodautoscalersResource, horizontalpodautoscalersKind, c.ns, opts), &v2beta2.HorizontalPodAutoscalerList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v2beta2.HorizontalPodAutoscalerList{ListMeta: obj.(*v2beta2.HorizontalPodAutoscalerList).ListMeta} + for _, item := range obj.(*v2beta2.HorizontalPodAutoscalerList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested horizontalPodAutoscalers. +func (c *FakeHorizontalPodAutoscalers) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(horizontalpodautoscalersResource, c.ns, opts)) + +} + +// Create takes the representation of a horizontalPodAutoscaler and creates it. Returns the server's representation of the horizontalPodAutoscaler, and an error, if there is any. +func (c *FakeHorizontalPodAutoscalers) Create(ctx context.Context, horizontalPodAutoscaler *v2beta2.HorizontalPodAutoscaler, opts v1.CreateOptions) (result *v2beta2.HorizontalPodAutoscaler, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(horizontalpodautoscalersResource, c.ns, horizontalPodAutoscaler), &v2beta2.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*v2beta2.HorizontalPodAutoscaler), err +} + +// Update takes the representation of a horizontalPodAutoscaler and updates it. Returns the server's representation of the horizontalPodAutoscaler, and an error, if there is any. +func (c *FakeHorizontalPodAutoscalers) Update(ctx context.Context, horizontalPodAutoscaler *v2beta2.HorizontalPodAutoscaler, opts v1.UpdateOptions) (result *v2beta2.HorizontalPodAutoscaler, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(horizontalpodautoscalersResource, c.ns, horizontalPodAutoscaler), &v2beta2.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*v2beta2.HorizontalPodAutoscaler), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeHorizontalPodAutoscalers) UpdateStatus(ctx context.Context, horizontalPodAutoscaler *v2beta2.HorizontalPodAutoscaler, opts v1.UpdateOptions) (*v2beta2.HorizontalPodAutoscaler, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(horizontalpodautoscalersResource, "status", c.ns, horizontalPodAutoscaler), &v2beta2.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*v2beta2.HorizontalPodAutoscaler), err +} + +// Delete takes name of the horizontalPodAutoscaler and deletes it. Returns an error if one occurs. +func (c *FakeHorizontalPodAutoscalers) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(horizontalpodautoscalersResource, c.ns, name, opts), &v2beta2.HorizontalPodAutoscaler{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeHorizontalPodAutoscalers) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(horizontalpodautoscalersResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v2beta2.HorizontalPodAutoscalerList{}) + return err +} + +// Patch applies the patch and returns the patched horizontalPodAutoscaler. +func (c *FakeHorizontalPodAutoscalers) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2beta2.HorizontalPodAutoscaler, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(horizontalpodautoscalersResource, c.ns, name, pt, data, subresources...), &v2beta2.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*v2beta2.HorizontalPodAutoscaler), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied horizontalPodAutoscaler. +func (c *FakeHorizontalPodAutoscalers) Apply(ctx context.Context, horizontalPodAutoscaler *autoscalingv2beta2.HorizontalPodAutoscalerApplyConfiguration, opts v1.ApplyOptions) (result *v2beta2.HorizontalPodAutoscaler, err error) { + if horizontalPodAutoscaler == nil { + return nil, fmt.Errorf("horizontalPodAutoscaler provided to Apply must not be nil") + } + data, err := json.Marshal(horizontalPodAutoscaler) + if err != nil { + return nil, err + } + name := horizontalPodAutoscaler.Name + if name == nil { + return nil, fmt.Errorf("horizontalPodAutoscaler.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(horizontalpodautoscalersResource, c.ns, *name, types.ApplyPatchType, data), &v2beta2.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*v2beta2.HorizontalPodAutoscaler), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeHorizontalPodAutoscalers) ApplyStatus(ctx context.Context, horizontalPodAutoscaler *autoscalingv2beta2.HorizontalPodAutoscalerApplyConfiguration, opts v1.ApplyOptions) (result *v2beta2.HorizontalPodAutoscaler, err error) { + if horizontalPodAutoscaler == nil { + return nil, fmt.Errorf("horizontalPodAutoscaler provided to Apply must not be nil") + } + data, err := json.Marshal(horizontalPodAutoscaler) + if err != nil { + return nil, err + } + name := horizontalPodAutoscaler.Name + if name == nil { + return nil, fmt.Errorf("horizontalPodAutoscaler.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(horizontalpodautoscalersResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v2beta2.HorizontalPodAutoscaler{}) + + if obj == nil { + return nil, err + } + return obj.(*v2beta2.HorizontalPodAutoscaler), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/batch/v1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/batch/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/batch/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/batch/v1/fake/fake_batch_client.go b/vendor/k8s.io/client-go/kubernetes/typed/batch/v1/fake/fake_batch_client.go new file mode 100644 index 000000000..43d5b0d30 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/batch/v1/fake/fake_batch_client.go @@ -0,0 +1,44 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/client-go/kubernetes/typed/batch/v1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeBatchV1 struct { + *testing.Fake +} + +func (c *FakeBatchV1) CronJobs(namespace string) v1.CronJobInterface { + return &FakeCronJobs{c, namespace} +} + +func (c *FakeBatchV1) Jobs(namespace string) v1.JobInterface { + return &FakeJobs{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeBatchV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/batch/v1/fake/fake_cronjob.go b/vendor/k8s.io/client-go/kubernetes/typed/batch/v1/fake/fake_cronjob.go new file mode 100644 index 000000000..39f4ca023 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/batch/v1/fake/fake_cronjob.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + batchv1 "k8s.io/api/batch/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsbatchv1 "k8s.io/client-go/applyconfigurations/batch/v1" + testing "k8s.io/client-go/testing" +) + +// FakeCronJobs implements CronJobInterface +type FakeCronJobs struct { + Fake *FakeBatchV1 + ns string +} + +var cronjobsResource = schema.GroupVersionResource{Group: "batch", Version: "v1", Resource: "cronjobs"} + +var cronjobsKind = schema.GroupVersionKind{Group: "batch", Version: "v1", Kind: "CronJob"} + +// Get takes name of the cronJob, and returns the corresponding cronJob object, and an error if there is any. +func (c *FakeCronJobs) Get(ctx context.Context, name string, options v1.GetOptions) (result *batchv1.CronJob, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(cronjobsResource, c.ns, name), &batchv1.CronJob{}) + + if obj == nil { + return nil, err + } + return obj.(*batchv1.CronJob), err +} + +// List takes label and field selectors, and returns the list of CronJobs that match those selectors. +func (c *FakeCronJobs) List(ctx context.Context, opts v1.ListOptions) (result *batchv1.CronJobList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(cronjobsResource, cronjobsKind, c.ns, opts), &batchv1.CronJobList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &batchv1.CronJobList{ListMeta: obj.(*batchv1.CronJobList).ListMeta} + for _, item := range obj.(*batchv1.CronJobList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested cronJobs. +func (c *FakeCronJobs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(cronjobsResource, c.ns, opts)) + +} + +// Create takes the representation of a cronJob and creates it. Returns the server's representation of the cronJob, and an error, if there is any. +func (c *FakeCronJobs) Create(ctx context.Context, cronJob *batchv1.CronJob, opts v1.CreateOptions) (result *batchv1.CronJob, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(cronjobsResource, c.ns, cronJob), &batchv1.CronJob{}) + + if obj == nil { + return nil, err + } + return obj.(*batchv1.CronJob), err +} + +// Update takes the representation of a cronJob and updates it. Returns the server's representation of the cronJob, and an error, if there is any. +func (c *FakeCronJobs) Update(ctx context.Context, cronJob *batchv1.CronJob, opts v1.UpdateOptions) (result *batchv1.CronJob, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(cronjobsResource, c.ns, cronJob), &batchv1.CronJob{}) + + if obj == nil { + return nil, err + } + return obj.(*batchv1.CronJob), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeCronJobs) UpdateStatus(ctx context.Context, cronJob *batchv1.CronJob, opts v1.UpdateOptions) (*batchv1.CronJob, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(cronjobsResource, "status", c.ns, cronJob), &batchv1.CronJob{}) + + if obj == nil { + return nil, err + } + return obj.(*batchv1.CronJob), err +} + +// Delete takes name of the cronJob and deletes it. Returns an error if one occurs. +func (c *FakeCronJobs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(cronjobsResource, c.ns, name, opts), &batchv1.CronJob{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeCronJobs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(cronjobsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &batchv1.CronJobList{}) + return err +} + +// Patch applies the patch and returns the patched cronJob. +func (c *FakeCronJobs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *batchv1.CronJob, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(cronjobsResource, c.ns, name, pt, data, subresources...), &batchv1.CronJob{}) + + if obj == nil { + return nil, err + } + return obj.(*batchv1.CronJob), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied cronJob. +func (c *FakeCronJobs) Apply(ctx context.Context, cronJob *applyconfigurationsbatchv1.CronJobApplyConfiguration, opts v1.ApplyOptions) (result *batchv1.CronJob, err error) { + if cronJob == nil { + return nil, fmt.Errorf("cronJob provided to Apply must not be nil") + } + data, err := json.Marshal(cronJob) + if err != nil { + return nil, err + } + name := cronJob.Name + if name == nil { + return nil, fmt.Errorf("cronJob.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(cronjobsResource, c.ns, *name, types.ApplyPatchType, data), &batchv1.CronJob{}) + + if obj == nil { + return nil, err + } + return obj.(*batchv1.CronJob), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeCronJobs) ApplyStatus(ctx context.Context, cronJob *applyconfigurationsbatchv1.CronJobApplyConfiguration, opts v1.ApplyOptions) (result *batchv1.CronJob, err error) { + if cronJob == nil { + return nil, fmt.Errorf("cronJob provided to Apply must not be nil") + } + data, err := json.Marshal(cronJob) + if err != nil { + return nil, err + } + name := cronJob.Name + if name == nil { + return nil, fmt.Errorf("cronJob.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(cronjobsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &batchv1.CronJob{}) + + if obj == nil { + return nil, err + } + return obj.(*batchv1.CronJob), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/batch/v1/fake/fake_job.go b/vendor/k8s.io/client-go/kubernetes/typed/batch/v1/fake/fake_job.go new file mode 100644 index 000000000..c44cddb3c --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/batch/v1/fake/fake_job.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + batchv1 "k8s.io/api/batch/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsbatchv1 "k8s.io/client-go/applyconfigurations/batch/v1" + testing "k8s.io/client-go/testing" +) + +// FakeJobs implements JobInterface +type FakeJobs struct { + Fake *FakeBatchV1 + ns string +} + +var jobsResource = schema.GroupVersionResource{Group: "batch", Version: "v1", Resource: "jobs"} + +var jobsKind = schema.GroupVersionKind{Group: "batch", Version: "v1", Kind: "Job"} + +// Get takes name of the job, and returns the corresponding job object, and an error if there is any. +func (c *FakeJobs) Get(ctx context.Context, name string, options v1.GetOptions) (result *batchv1.Job, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(jobsResource, c.ns, name), &batchv1.Job{}) + + if obj == nil { + return nil, err + } + return obj.(*batchv1.Job), err +} + +// List takes label and field selectors, and returns the list of Jobs that match those selectors. +func (c *FakeJobs) List(ctx context.Context, opts v1.ListOptions) (result *batchv1.JobList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(jobsResource, jobsKind, c.ns, opts), &batchv1.JobList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &batchv1.JobList{ListMeta: obj.(*batchv1.JobList).ListMeta} + for _, item := range obj.(*batchv1.JobList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested jobs. +func (c *FakeJobs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(jobsResource, c.ns, opts)) + +} + +// Create takes the representation of a job and creates it. Returns the server's representation of the job, and an error, if there is any. +func (c *FakeJobs) Create(ctx context.Context, job *batchv1.Job, opts v1.CreateOptions) (result *batchv1.Job, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(jobsResource, c.ns, job), &batchv1.Job{}) + + if obj == nil { + return nil, err + } + return obj.(*batchv1.Job), err +} + +// Update takes the representation of a job and updates it. Returns the server's representation of the job, and an error, if there is any. +func (c *FakeJobs) Update(ctx context.Context, job *batchv1.Job, opts v1.UpdateOptions) (result *batchv1.Job, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(jobsResource, c.ns, job), &batchv1.Job{}) + + if obj == nil { + return nil, err + } + return obj.(*batchv1.Job), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeJobs) UpdateStatus(ctx context.Context, job *batchv1.Job, opts v1.UpdateOptions) (*batchv1.Job, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(jobsResource, "status", c.ns, job), &batchv1.Job{}) + + if obj == nil { + return nil, err + } + return obj.(*batchv1.Job), err +} + +// Delete takes name of the job and deletes it. Returns an error if one occurs. +func (c *FakeJobs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(jobsResource, c.ns, name, opts), &batchv1.Job{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeJobs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(jobsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &batchv1.JobList{}) + return err +} + +// Patch applies the patch and returns the patched job. +func (c *FakeJobs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *batchv1.Job, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(jobsResource, c.ns, name, pt, data, subresources...), &batchv1.Job{}) + + if obj == nil { + return nil, err + } + return obj.(*batchv1.Job), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied job. +func (c *FakeJobs) Apply(ctx context.Context, job *applyconfigurationsbatchv1.JobApplyConfiguration, opts v1.ApplyOptions) (result *batchv1.Job, err error) { + if job == nil { + return nil, fmt.Errorf("job provided to Apply must not be nil") + } + data, err := json.Marshal(job) + if err != nil { + return nil, err + } + name := job.Name + if name == nil { + return nil, fmt.Errorf("job.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(jobsResource, c.ns, *name, types.ApplyPatchType, data), &batchv1.Job{}) + + if obj == nil { + return nil, err + } + return obj.(*batchv1.Job), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeJobs) ApplyStatus(ctx context.Context, job *applyconfigurationsbatchv1.JobApplyConfiguration, opts v1.ApplyOptions) (result *batchv1.Job, err error) { + if job == nil { + return nil, fmt.Errorf("job provided to Apply must not be nil") + } + data, err := json.Marshal(job) + if err != nil { + return nil, err + } + name := job.Name + if name == nil { + return nil, fmt.Errorf("job.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(jobsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &batchv1.Job{}) + + if obj == nil { + return nil, err + } + return obj.(*batchv1.Job), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/batch/v1beta1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/batch/v1beta1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/batch/v1beta1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/batch/v1beta1/fake/fake_batch_client.go b/vendor/k8s.io/client-go/kubernetes/typed/batch/v1beta1/fake/fake_batch_client.go new file mode 100644 index 000000000..6f350aed9 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/batch/v1beta1/fake/fake_batch_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1beta1 "k8s.io/client-go/kubernetes/typed/batch/v1beta1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeBatchV1beta1 struct { + *testing.Fake +} + +func (c *FakeBatchV1beta1) CronJobs(namespace string) v1beta1.CronJobInterface { + return &FakeCronJobs{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeBatchV1beta1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/batch/v1beta1/fake/fake_cronjob.go b/vendor/k8s.io/client-go/kubernetes/typed/batch/v1beta1/fake/fake_cronjob.go new file mode 100644 index 000000000..a8bad764f --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/batch/v1beta1/fake/fake_cronjob.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/batch/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + batchv1beta1 "k8s.io/client-go/applyconfigurations/batch/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeCronJobs implements CronJobInterface +type FakeCronJobs struct { + Fake *FakeBatchV1beta1 + ns string +} + +var cronjobsResource = schema.GroupVersionResource{Group: "batch", Version: "v1beta1", Resource: "cronjobs"} + +var cronjobsKind = schema.GroupVersionKind{Group: "batch", Version: "v1beta1", Kind: "CronJob"} + +// Get takes name of the cronJob, and returns the corresponding cronJob object, and an error if there is any. +func (c *FakeCronJobs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.CronJob, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(cronjobsResource, c.ns, name), &v1beta1.CronJob{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CronJob), err +} + +// List takes label and field selectors, and returns the list of CronJobs that match those selectors. +func (c *FakeCronJobs) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.CronJobList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(cronjobsResource, cronjobsKind, c.ns, opts), &v1beta1.CronJobList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.CronJobList{ListMeta: obj.(*v1beta1.CronJobList).ListMeta} + for _, item := range obj.(*v1beta1.CronJobList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested cronJobs. +func (c *FakeCronJobs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(cronjobsResource, c.ns, opts)) + +} + +// Create takes the representation of a cronJob and creates it. Returns the server's representation of the cronJob, and an error, if there is any. +func (c *FakeCronJobs) Create(ctx context.Context, cronJob *v1beta1.CronJob, opts v1.CreateOptions) (result *v1beta1.CronJob, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(cronjobsResource, c.ns, cronJob), &v1beta1.CronJob{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CronJob), err +} + +// Update takes the representation of a cronJob and updates it. Returns the server's representation of the cronJob, and an error, if there is any. +func (c *FakeCronJobs) Update(ctx context.Context, cronJob *v1beta1.CronJob, opts v1.UpdateOptions) (result *v1beta1.CronJob, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(cronjobsResource, c.ns, cronJob), &v1beta1.CronJob{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CronJob), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeCronJobs) UpdateStatus(ctx context.Context, cronJob *v1beta1.CronJob, opts v1.UpdateOptions) (*v1beta1.CronJob, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(cronjobsResource, "status", c.ns, cronJob), &v1beta1.CronJob{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CronJob), err +} + +// Delete takes name of the cronJob and deletes it. Returns an error if one occurs. +func (c *FakeCronJobs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(cronjobsResource, c.ns, name, opts), &v1beta1.CronJob{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeCronJobs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(cronjobsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.CronJobList{}) + return err +} + +// Patch applies the patch and returns the patched cronJob. +func (c *FakeCronJobs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.CronJob, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(cronjobsResource, c.ns, name, pt, data, subresources...), &v1beta1.CronJob{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CronJob), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied cronJob. +func (c *FakeCronJobs) Apply(ctx context.Context, cronJob *batchv1beta1.CronJobApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.CronJob, err error) { + if cronJob == nil { + return nil, fmt.Errorf("cronJob provided to Apply must not be nil") + } + data, err := json.Marshal(cronJob) + if err != nil { + return nil, err + } + name := cronJob.Name + if name == nil { + return nil, fmt.Errorf("cronJob.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(cronjobsResource, c.ns, *name, types.ApplyPatchType, data), &v1beta1.CronJob{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CronJob), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeCronJobs) ApplyStatus(ctx context.Context, cronJob *batchv1beta1.CronJobApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.CronJob, err error) { + if cronJob == nil { + return nil, fmt.Errorf("cronJob provided to Apply must not be nil") + } + data, err := json.Marshal(cronJob) + if err != nil { + return nil, err + } + name := cronJob.Name + if name == nil { + return nil, fmt.Errorf("cronJob.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(cronjobsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v1beta1.CronJob{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CronJob), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/certificates/v1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/certificates/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/certificates/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/certificates/v1/fake/fake_certificates_client.go b/vendor/k8s.io/client-go/kubernetes/typed/certificates/v1/fake/fake_certificates_client.go new file mode 100644 index 000000000..4779d6169 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/certificates/v1/fake/fake_certificates_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/client-go/kubernetes/typed/certificates/v1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeCertificatesV1 struct { + *testing.Fake +} + +func (c *FakeCertificatesV1) CertificateSigningRequests() v1.CertificateSigningRequestInterface { + return &FakeCertificateSigningRequests{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeCertificatesV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/certificates/v1/fake/fake_certificatesigningrequest.go b/vendor/k8s.io/client-go/kubernetes/typed/certificates/v1/fake/fake_certificatesigningrequest.go new file mode 100644 index 000000000..90a1e6dc6 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/certificates/v1/fake/fake_certificatesigningrequest.go @@ -0,0 +1,189 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + certificatesv1 "k8s.io/api/certificates/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationscertificatesv1 "k8s.io/client-go/applyconfigurations/certificates/v1" + testing "k8s.io/client-go/testing" +) + +// FakeCertificateSigningRequests implements CertificateSigningRequestInterface +type FakeCertificateSigningRequests struct { + Fake *FakeCertificatesV1 +} + +var certificatesigningrequestsResource = schema.GroupVersionResource{Group: "certificates.k8s.io", Version: "v1", Resource: "certificatesigningrequests"} + +var certificatesigningrequestsKind = schema.GroupVersionKind{Group: "certificates.k8s.io", Version: "v1", Kind: "CertificateSigningRequest"} + +// Get takes name of the certificateSigningRequest, and returns the corresponding certificateSigningRequest object, and an error if there is any. +func (c *FakeCertificateSigningRequests) Get(ctx context.Context, name string, options v1.GetOptions) (result *certificatesv1.CertificateSigningRequest, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(certificatesigningrequestsResource, name), &certificatesv1.CertificateSigningRequest{}) + if obj == nil { + return nil, err + } + return obj.(*certificatesv1.CertificateSigningRequest), err +} + +// List takes label and field selectors, and returns the list of CertificateSigningRequests that match those selectors. +func (c *FakeCertificateSigningRequests) List(ctx context.Context, opts v1.ListOptions) (result *certificatesv1.CertificateSigningRequestList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(certificatesigningrequestsResource, certificatesigningrequestsKind, opts), &certificatesv1.CertificateSigningRequestList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &certificatesv1.CertificateSigningRequestList{ListMeta: obj.(*certificatesv1.CertificateSigningRequestList).ListMeta} + for _, item := range obj.(*certificatesv1.CertificateSigningRequestList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested certificateSigningRequests. +func (c *FakeCertificateSigningRequests) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(certificatesigningrequestsResource, opts)) +} + +// Create takes the representation of a certificateSigningRequest and creates it. Returns the server's representation of the certificateSigningRequest, and an error, if there is any. +func (c *FakeCertificateSigningRequests) Create(ctx context.Context, certificateSigningRequest *certificatesv1.CertificateSigningRequest, opts v1.CreateOptions) (result *certificatesv1.CertificateSigningRequest, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(certificatesigningrequestsResource, certificateSigningRequest), &certificatesv1.CertificateSigningRequest{}) + if obj == nil { + return nil, err + } + return obj.(*certificatesv1.CertificateSigningRequest), err +} + +// Update takes the representation of a certificateSigningRequest and updates it. Returns the server's representation of the certificateSigningRequest, and an error, if there is any. +func (c *FakeCertificateSigningRequests) Update(ctx context.Context, certificateSigningRequest *certificatesv1.CertificateSigningRequest, opts v1.UpdateOptions) (result *certificatesv1.CertificateSigningRequest, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(certificatesigningrequestsResource, certificateSigningRequest), &certificatesv1.CertificateSigningRequest{}) + if obj == nil { + return nil, err + } + return obj.(*certificatesv1.CertificateSigningRequest), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeCertificateSigningRequests) UpdateStatus(ctx context.Context, certificateSigningRequest *certificatesv1.CertificateSigningRequest, opts v1.UpdateOptions) (*certificatesv1.CertificateSigningRequest, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(certificatesigningrequestsResource, "status", certificateSigningRequest), &certificatesv1.CertificateSigningRequest{}) + if obj == nil { + return nil, err + } + return obj.(*certificatesv1.CertificateSigningRequest), err +} + +// Delete takes name of the certificateSigningRequest and deletes it. Returns an error if one occurs. +func (c *FakeCertificateSigningRequests) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(certificatesigningrequestsResource, name, opts), &certificatesv1.CertificateSigningRequest{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeCertificateSigningRequests) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(certificatesigningrequestsResource, listOpts) + + _, err := c.Fake.Invokes(action, &certificatesv1.CertificateSigningRequestList{}) + return err +} + +// Patch applies the patch and returns the patched certificateSigningRequest. +func (c *FakeCertificateSigningRequests) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *certificatesv1.CertificateSigningRequest, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(certificatesigningrequestsResource, name, pt, data, subresources...), &certificatesv1.CertificateSigningRequest{}) + if obj == nil { + return nil, err + } + return obj.(*certificatesv1.CertificateSigningRequest), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied certificateSigningRequest. +func (c *FakeCertificateSigningRequests) Apply(ctx context.Context, certificateSigningRequest *applyconfigurationscertificatesv1.CertificateSigningRequestApplyConfiguration, opts v1.ApplyOptions) (result *certificatesv1.CertificateSigningRequest, err error) { + if certificateSigningRequest == nil { + return nil, fmt.Errorf("certificateSigningRequest provided to Apply must not be nil") + } + data, err := json.Marshal(certificateSigningRequest) + if err != nil { + return nil, err + } + name := certificateSigningRequest.Name + if name == nil { + return nil, fmt.Errorf("certificateSigningRequest.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(certificatesigningrequestsResource, *name, types.ApplyPatchType, data), &certificatesv1.CertificateSigningRequest{}) + if obj == nil { + return nil, err + } + return obj.(*certificatesv1.CertificateSigningRequest), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeCertificateSigningRequests) ApplyStatus(ctx context.Context, certificateSigningRequest *applyconfigurationscertificatesv1.CertificateSigningRequestApplyConfiguration, opts v1.ApplyOptions) (result *certificatesv1.CertificateSigningRequest, err error) { + if certificateSigningRequest == nil { + return nil, fmt.Errorf("certificateSigningRequest provided to Apply must not be nil") + } + data, err := json.Marshal(certificateSigningRequest) + if err != nil { + return nil, err + } + name := certificateSigningRequest.Name + if name == nil { + return nil, fmt.Errorf("certificateSigningRequest.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(certificatesigningrequestsResource, *name, types.ApplyPatchType, data, "status"), &certificatesv1.CertificateSigningRequest{}) + if obj == nil { + return nil, err + } + return obj.(*certificatesv1.CertificateSigningRequest), err +} + +// UpdateApproval takes the representation of a certificateSigningRequest and updates it. Returns the server's representation of the certificateSigningRequest, and an error, if there is any. +func (c *FakeCertificateSigningRequests) UpdateApproval(ctx context.Context, certificateSigningRequestName string, certificateSigningRequest *certificatesv1.CertificateSigningRequest, opts v1.UpdateOptions) (result *certificatesv1.CertificateSigningRequest, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(certificatesigningrequestsResource, "approval", certificateSigningRequest), &certificatesv1.CertificateSigningRequest{}) + if obj == nil { + return nil, err + } + return obj.(*certificatesv1.CertificateSigningRequest), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake/fake_certificates_client.go b/vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake/fake_certificates_client.go new file mode 100644 index 000000000..29d8b088e --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake/fake_certificates_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1beta1 "k8s.io/client-go/kubernetes/typed/certificates/v1beta1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeCertificatesV1beta1 struct { + *testing.Fake +} + +func (c *FakeCertificatesV1beta1) CertificateSigningRequests() v1beta1.CertificateSigningRequestInterface { + return &FakeCertificateSigningRequests{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeCertificatesV1beta1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake/fake_certificatesigningrequest.go b/vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake/fake_certificatesigningrequest.go new file mode 100644 index 000000000..5a416150a --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake/fake_certificatesigningrequest.go @@ -0,0 +1,179 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/certificates/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + certificatesv1beta1 "k8s.io/client-go/applyconfigurations/certificates/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeCertificateSigningRequests implements CertificateSigningRequestInterface +type FakeCertificateSigningRequests struct { + Fake *FakeCertificatesV1beta1 +} + +var certificatesigningrequestsResource = schema.GroupVersionResource{Group: "certificates.k8s.io", Version: "v1beta1", Resource: "certificatesigningrequests"} + +var certificatesigningrequestsKind = schema.GroupVersionKind{Group: "certificates.k8s.io", Version: "v1beta1", Kind: "CertificateSigningRequest"} + +// Get takes name of the certificateSigningRequest, and returns the corresponding certificateSigningRequest object, and an error if there is any. +func (c *FakeCertificateSigningRequests) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.CertificateSigningRequest, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(certificatesigningrequestsResource, name), &v1beta1.CertificateSigningRequest{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CertificateSigningRequest), err +} + +// List takes label and field selectors, and returns the list of CertificateSigningRequests that match those selectors. +func (c *FakeCertificateSigningRequests) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.CertificateSigningRequestList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(certificatesigningrequestsResource, certificatesigningrequestsKind, opts), &v1beta1.CertificateSigningRequestList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.CertificateSigningRequestList{ListMeta: obj.(*v1beta1.CertificateSigningRequestList).ListMeta} + for _, item := range obj.(*v1beta1.CertificateSigningRequestList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested certificateSigningRequests. +func (c *FakeCertificateSigningRequests) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(certificatesigningrequestsResource, opts)) +} + +// Create takes the representation of a certificateSigningRequest and creates it. Returns the server's representation of the certificateSigningRequest, and an error, if there is any. +func (c *FakeCertificateSigningRequests) Create(ctx context.Context, certificateSigningRequest *v1beta1.CertificateSigningRequest, opts v1.CreateOptions) (result *v1beta1.CertificateSigningRequest, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(certificatesigningrequestsResource, certificateSigningRequest), &v1beta1.CertificateSigningRequest{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CertificateSigningRequest), err +} + +// Update takes the representation of a certificateSigningRequest and updates it. Returns the server's representation of the certificateSigningRequest, and an error, if there is any. +func (c *FakeCertificateSigningRequests) Update(ctx context.Context, certificateSigningRequest *v1beta1.CertificateSigningRequest, opts v1.UpdateOptions) (result *v1beta1.CertificateSigningRequest, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(certificatesigningrequestsResource, certificateSigningRequest), &v1beta1.CertificateSigningRequest{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CertificateSigningRequest), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeCertificateSigningRequests) UpdateStatus(ctx context.Context, certificateSigningRequest *v1beta1.CertificateSigningRequest, opts v1.UpdateOptions) (*v1beta1.CertificateSigningRequest, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(certificatesigningrequestsResource, "status", certificateSigningRequest), &v1beta1.CertificateSigningRequest{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CertificateSigningRequest), err +} + +// Delete takes name of the certificateSigningRequest and deletes it. Returns an error if one occurs. +func (c *FakeCertificateSigningRequests) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(certificatesigningrequestsResource, name, opts), &v1beta1.CertificateSigningRequest{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeCertificateSigningRequests) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(certificatesigningrequestsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.CertificateSigningRequestList{}) + return err +} + +// Patch applies the patch and returns the patched certificateSigningRequest. +func (c *FakeCertificateSigningRequests) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.CertificateSigningRequest, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(certificatesigningrequestsResource, name, pt, data, subresources...), &v1beta1.CertificateSigningRequest{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CertificateSigningRequest), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied certificateSigningRequest. +func (c *FakeCertificateSigningRequests) Apply(ctx context.Context, certificateSigningRequest *certificatesv1beta1.CertificateSigningRequestApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.CertificateSigningRequest, err error) { + if certificateSigningRequest == nil { + return nil, fmt.Errorf("certificateSigningRequest provided to Apply must not be nil") + } + data, err := json.Marshal(certificateSigningRequest) + if err != nil { + return nil, err + } + name := certificateSigningRequest.Name + if name == nil { + return nil, fmt.Errorf("certificateSigningRequest.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(certificatesigningrequestsResource, *name, types.ApplyPatchType, data), &v1beta1.CertificateSigningRequest{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CertificateSigningRequest), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeCertificateSigningRequests) ApplyStatus(ctx context.Context, certificateSigningRequest *certificatesv1beta1.CertificateSigningRequestApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.CertificateSigningRequest, err error) { + if certificateSigningRequest == nil { + return nil, fmt.Errorf("certificateSigningRequest provided to Apply must not be nil") + } + data, err := json.Marshal(certificateSigningRequest) + if err != nil { + return nil, err + } + name := certificateSigningRequest.Name + if name == nil { + return nil, fmt.Errorf("certificateSigningRequest.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(certificatesigningrequestsResource, *name, types.ApplyPatchType, data, "status"), &v1beta1.CertificateSigningRequest{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CertificateSigningRequest), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake/fake_certificatesigningrequest_expansion.go b/vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake/fake_certificatesigningrequest_expansion.go new file mode 100644 index 000000000..2c3eaf971 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake/fake_certificatesigningrequest_expansion.go @@ -0,0 +1,34 @@ +/* +Copyright 2017 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 fake + +import ( + "context" + + certificates "k8s.io/api/certificates/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + core "k8s.io/client-go/testing" +) + +func (c *FakeCertificateSigningRequests) UpdateApproval(ctx context.Context, certificateSigningRequest *certificates.CertificateSigningRequest, opts metav1.UpdateOptions) (result *certificates.CertificateSigningRequest, err error) { + obj, err := c.Fake. + Invokes(core.NewRootUpdateSubresourceAction(certificatesigningrequestsResource, "approval", certificateSigningRequest), &certificates.CertificateSigningRequest{}) + if obj == nil { + return nil, err + } + return obj.(*certificates.CertificateSigningRequest), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/coordination/v1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/coordination/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/coordination/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/coordination/v1/fake/fake_coordination_client.go b/vendor/k8s.io/client-go/kubernetes/typed/coordination/v1/fake/fake_coordination_client.go new file mode 100644 index 000000000..6920275b2 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/coordination/v1/fake/fake_coordination_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/client-go/kubernetes/typed/coordination/v1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeCoordinationV1 struct { + *testing.Fake +} + +func (c *FakeCoordinationV1) Leases(namespace string) v1.LeaseInterface { + return &FakeLeases{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeCoordinationV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/coordination/v1/fake/fake_lease.go b/vendor/k8s.io/client-go/kubernetes/typed/coordination/v1/fake/fake_lease.go new file mode 100644 index 000000000..c52c828ef --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/coordination/v1/fake/fake_lease.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + coordinationv1 "k8s.io/api/coordination/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationscoordinationv1 "k8s.io/client-go/applyconfigurations/coordination/v1" + testing "k8s.io/client-go/testing" +) + +// FakeLeases implements LeaseInterface +type FakeLeases struct { + Fake *FakeCoordinationV1 + ns string +} + +var leasesResource = schema.GroupVersionResource{Group: "coordination.k8s.io", Version: "v1", Resource: "leases"} + +var leasesKind = schema.GroupVersionKind{Group: "coordination.k8s.io", Version: "v1", Kind: "Lease"} + +// Get takes name of the lease, and returns the corresponding lease object, and an error if there is any. +func (c *FakeLeases) Get(ctx context.Context, name string, options v1.GetOptions) (result *coordinationv1.Lease, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(leasesResource, c.ns, name), &coordinationv1.Lease{}) + + if obj == nil { + return nil, err + } + return obj.(*coordinationv1.Lease), err +} + +// List takes label and field selectors, and returns the list of Leases that match those selectors. +func (c *FakeLeases) List(ctx context.Context, opts v1.ListOptions) (result *coordinationv1.LeaseList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(leasesResource, leasesKind, c.ns, opts), &coordinationv1.LeaseList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &coordinationv1.LeaseList{ListMeta: obj.(*coordinationv1.LeaseList).ListMeta} + for _, item := range obj.(*coordinationv1.LeaseList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested leases. +func (c *FakeLeases) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(leasesResource, c.ns, opts)) + +} + +// Create takes the representation of a lease and creates it. Returns the server's representation of the lease, and an error, if there is any. +func (c *FakeLeases) Create(ctx context.Context, lease *coordinationv1.Lease, opts v1.CreateOptions) (result *coordinationv1.Lease, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(leasesResource, c.ns, lease), &coordinationv1.Lease{}) + + if obj == nil { + return nil, err + } + return obj.(*coordinationv1.Lease), err +} + +// Update takes the representation of a lease and updates it. Returns the server's representation of the lease, and an error, if there is any. +func (c *FakeLeases) Update(ctx context.Context, lease *coordinationv1.Lease, opts v1.UpdateOptions) (result *coordinationv1.Lease, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(leasesResource, c.ns, lease), &coordinationv1.Lease{}) + + if obj == nil { + return nil, err + } + return obj.(*coordinationv1.Lease), err +} + +// Delete takes name of the lease and deletes it. Returns an error if one occurs. +func (c *FakeLeases) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(leasesResource, c.ns, name, opts), &coordinationv1.Lease{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeLeases) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(leasesResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &coordinationv1.LeaseList{}) + return err +} + +// Patch applies the patch and returns the patched lease. +func (c *FakeLeases) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *coordinationv1.Lease, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(leasesResource, c.ns, name, pt, data, subresources...), &coordinationv1.Lease{}) + + if obj == nil { + return nil, err + } + return obj.(*coordinationv1.Lease), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied lease. +func (c *FakeLeases) Apply(ctx context.Context, lease *applyconfigurationscoordinationv1.LeaseApplyConfiguration, opts v1.ApplyOptions) (result *coordinationv1.Lease, err error) { + if lease == nil { + return nil, fmt.Errorf("lease provided to Apply must not be nil") + } + data, err := json.Marshal(lease) + if err != nil { + return nil, err + } + name := lease.Name + if name == nil { + return nil, fmt.Errorf("lease.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(leasesResource, c.ns, *name, types.ApplyPatchType, data), &coordinationv1.Lease{}) + + if obj == nil { + return nil, err + } + return obj.(*coordinationv1.Lease), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/coordination/v1beta1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/coordination/v1beta1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/coordination/v1beta1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/coordination/v1beta1/fake/fake_coordination_client.go b/vendor/k8s.io/client-go/kubernetes/typed/coordination/v1beta1/fake/fake_coordination_client.go new file mode 100644 index 000000000..f583b466e --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/coordination/v1beta1/fake/fake_coordination_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1beta1 "k8s.io/client-go/kubernetes/typed/coordination/v1beta1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeCoordinationV1beta1 struct { + *testing.Fake +} + +func (c *FakeCoordinationV1beta1) Leases(namespace string) v1beta1.LeaseInterface { + return &FakeLeases{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeCoordinationV1beta1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/coordination/v1beta1/fake/fake_lease.go b/vendor/k8s.io/client-go/kubernetes/typed/coordination/v1beta1/fake/fake_lease.go new file mode 100644 index 000000000..15b6c401d --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/coordination/v1beta1/fake/fake_lease.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/coordination/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + coordinationv1beta1 "k8s.io/client-go/applyconfigurations/coordination/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeLeases implements LeaseInterface +type FakeLeases struct { + Fake *FakeCoordinationV1beta1 + ns string +} + +var leasesResource = schema.GroupVersionResource{Group: "coordination.k8s.io", Version: "v1beta1", Resource: "leases"} + +var leasesKind = schema.GroupVersionKind{Group: "coordination.k8s.io", Version: "v1beta1", Kind: "Lease"} + +// Get takes name of the lease, and returns the corresponding lease object, and an error if there is any. +func (c *FakeLeases) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.Lease, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(leasesResource, c.ns, name), &v1beta1.Lease{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Lease), err +} + +// List takes label and field selectors, and returns the list of Leases that match those selectors. +func (c *FakeLeases) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.LeaseList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(leasesResource, leasesKind, c.ns, opts), &v1beta1.LeaseList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.LeaseList{ListMeta: obj.(*v1beta1.LeaseList).ListMeta} + for _, item := range obj.(*v1beta1.LeaseList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested leases. +func (c *FakeLeases) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(leasesResource, c.ns, opts)) + +} + +// Create takes the representation of a lease and creates it. Returns the server's representation of the lease, and an error, if there is any. +func (c *FakeLeases) Create(ctx context.Context, lease *v1beta1.Lease, opts v1.CreateOptions) (result *v1beta1.Lease, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(leasesResource, c.ns, lease), &v1beta1.Lease{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Lease), err +} + +// Update takes the representation of a lease and updates it. Returns the server's representation of the lease, and an error, if there is any. +func (c *FakeLeases) Update(ctx context.Context, lease *v1beta1.Lease, opts v1.UpdateOptions) (result *v1beta1.Lease, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(leasesResource, c.ns, lease), &v1beta1.Lease{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Lease), err +} + +// Delete takes name of the lease and deletes it. Returns an error if one occurs. +func (c *FakeLeases) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(leasesResource, c.ns, name, opts), &v1beta1.Lease{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeLeases) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(leasesResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.LeaseList{}) + return err +} + +// Patch applies the patch and returns the patched lease. +func (c *FakeLeases) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Lease, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(leasesResource, c.ns, name, pt, data, subresources...), &v1beta1.Lease{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Lease), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied lease. +func (c *FakeLeases) Apply(ctx context.Context, lease *coordinationv1beta1.LeaseApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.Lease, err error) { + if lease == nil { + return nil, fmt.Errorf("lease provided to Apply must not be nil") + } + data, err := json.Marshal(lease) + if err != nil { + return nil, err + } + name := lease.Name + if name == nil { + return nil, fmt.Errorf("lease.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(leasesResource, c.ns, *name, types.ApplyPatchType, data), &v1beta1.Lease{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Lease), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_componentstatus.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_componentstatus.go new file mode 100644 index 000000000..7e5c02daa --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_componentstatus.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationscorev1 "k8s.io/client-go/applyconfigurations/core/v1" + testing "k8s.io/client-go/testing" +) + +// FakeComponentStatuses implements ComponentStatusInterface +type FakeComponentStatuses struct { + Fake *FakeCoreV1 +} + +var componentstatusesResource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "componentstatuses"} + +var componentstatusesKind = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ComponentStatus"} + +// Get takes name of the componentStatus, and returns the corresponding componentStatus object, and an error if there is any. +func (c *FakeComponentStatuses) Get(ctx context.Context, name string, options v1.GetOptions) (result *corev1.ComponentStatus, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(componentstatusesResource, name), &corev1.ComponentStatus{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.ComponentStatus), err +} + +// List takes label and field selectors, and returns the list of ComponentStatuses that match those selectors. +func (c *FakeComponentStatuses) List(ctx context.Context, opts v1.ListOptions) (result *corev1.ComponentStatusList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(componentstatusesResource, componentstatusesKind, opts), &corev1.ComponentStatusList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &corev1.ComponentStatusList{ListMeta: obj.(*corev1.ComponentStatusList).ListMeta} + for _, item := range obj.(*corev1.ComponentStatusList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested componentStatuses. +func (c *FakeComponentStatuses) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(componentstatusesResource, opts)) +} + +// Create takes the representation of a componentStatus and creates it. Returns the server's representation of the componentStatus, and an error, if there is any. +func (c *FakeComponentStatuses) Create(ctx context.Context, componentStatus *corev1.ComponentStatus, opts v1.CreateOptions) (result *corev1.ComponentStatus, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(componentstatusesResource, componentStatus), &corev1.ComponentStatus{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.ComponentStatus), err +} + +// Update takes the representation of a componentStatus and updates it. Returns the server's representation of the componentStatus, and an error, if there is any. +func (c *FakeComponentStatuses) Update(ctx context.Context, componentStatus *corev1.ComponentStatus, opts v1.UpdateOptions) (result *corev1.ComponentStatus, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(componentstatusesResource, componentStatus), &corev1.ComponentStatus{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.ComponentStatus), err +} + +// Delete takes name of the componentStatus and deletes it. Returns an error if one occurs. +func (c *FakeComponentStatuses) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(componentstatusesResource, name, opts), &corev1.ComponentStatus{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeComponentStatuses) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(componentstatusesResource, listOpts) + + _, err := c.Fake.Invokes(action, &corev1.ComponentStatusList{}) + return err +} + +// Patch applies the patch and returns the patched componentStatus. +func (c *FakeComponentStatuses) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *corev1.ComponentStatus, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(componentstatusesResource, name, pt, data, subresources...), &corev1.ComponentStatus{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.ComponentStatus), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied componentStatus. +func (c *FakeComponentStatuses) Apply(ctx context.Context, componentStatus *applyconfigurationscorev1.ComponentStatusApplyConfiguration, opts v1.ApplyOptions) (result *corev1.ComponentStatus, err error) { + if componentStatus == nil { + return nil, fmt.Errorf("componentStatus provided to Apply must not be nil") + } + data, err := json.Marshal(componentStatus) + if err != nil { + return nil, err + } + name := componentStatus.Name + if name == nil { + return nil, fmt.Errorf("componentStatus.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(componentstatusesResource, *name, types.ApplyPatchType, data), &corev1.ComponentStatus{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.ComponentStatus), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_configmap.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_configmap.go new file mode 100644 index 000000000..b74b376a9 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_configmap.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationscorev1 "k8s.io/client-go/applyconfigurations/core/v1" + testing "k8s.io/client-go/testing" +) + +// FakeConfigMaps implements ConfigMapInterface +type FakeConfigMaps struct { + Fake *FakeCoreV1 + ns string +} + +var configmapsResource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "configmaps"} + +var configmapsKind = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ConfigMap"} + +// Get takes name of the configMap, and returns the corresponding configMap object, and an error if there is any. +func (c *FakeConfigMaps) Get(ctx context.Context, name string, options v1.GetOptions) (result *corev1.ConfigMap, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(configmapsResource, c.ns, name), &corev1.ConfigMap{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ConfigMap), err +} + +// List takes label and field selectors, and returns the list of ConfigMaps that match those selectors. +func (c *FakeConfigMaps) List(ctx context.Context, opts v1.ListOptions) (result *corev1.ConfigMapList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(configmapsResource, configmapsKind, c.ns, opts), &corev1.ConfigMapList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &corev1.ConfigMapList{ListMeta: obj.(*corev1.ConfigMapList).ListMeta} + for _, item := range obj.(*corev1.ConfigMapList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested configMaps. +func (c *FakeConfigMaps) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(configmapsResource, c.ns, opts)) + +} + +// Create takes the representation of a configMap and creates it. Returns the server's representation of the configMap, and an error, if there is any. +func (c *FakeConfigMaps) Create(ctx context.Context, configMap *corev1.ConfigMap, opts v1.CreateOptions) (result *corev1.ConfigMap, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(configmapsResource, c.ns, configMap), &corev1.ConfigMap{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ConfigMap), err +} + +// Update takes the representation of a configMap and updates it. Returns the server's representation of the configMap, and an error, if there is any. +func (c *FakeConfigMaps) Update(ctx context.Context, configMap *corev1.ConfigMap, opts v1.UpdateOptions) (result *corev1.ConfigMap, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(configmapsResource, c.ns, configMap), &corev1.ConfigMap{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ConfigMap), err +} + +// Delete takes name of the configMap and deletes it. Returns an error if one occurs. +func (c *FakeConfigMaps) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(configmapsResource, c.ns, name, opts), &corev1.ConfigMap{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeConfigMaps) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(configmapsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &corev1.ConfigMapList{}) + return err +} + +// Patch applies the patch and returns the patched configMap. +func (c *FakeConfigMaps) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *corev1.ConfigMap, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(configmapsResource, c.ns, name, pt, data, subresources...), &corev1.ConfigMap{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ConfigMap), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied configMap. +func (c *FakeConfigMaps) Apply(ctx context.Context, configMap *applyconfigurationscorev1.ConfigMapApplyConfiguration, opts v1.ApplyOptions) (result *corev1.ConfigMap, err error) { + if configMap == nil { + return nil, fmt.Errorf("configMap provided to Apply must not be nil") + } + data, err := json.Marshal(configMap) + if err != nil { + return nil, err + } + name := configMap.Name + if name == nil { + return nil, fmt.Errorf("configMap.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(configmapsResource, c.ns, *name, types.ApplyPatchType, data), &corev1.ConfigMap{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ConfigMap), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_core_client.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_core_client.go new file mode 100644 index 000000000..5ad90943c --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_core_client.go @@ -0,0 +1,100 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/client-go/kubernetes/typed/core/v1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeCoreV1 struct { + *testing.Fake +} + +func (c *FakeCoreV1) ComponentStatuses() v1.ComponentStatusInterface { + return &FakeComponentStatuses{c} +} + +func (c *FakeCoreV1) ConfigMaps(namespace string) v1.ConfigMapInterface { + return &FakeConfigMaps{c, namespace} +} + +func (c *FakeCoreV1) Endpoints(namespace string) v1.EndpointsInterface { + return &FakeEndpoints{c, namespace} +} + +func (c *FakeCoreV1) Events(namespace string) v1.EventInterface { + return &FakeEvents{c, namespace} +} + +func (c *FakeCoreV1) LimitRanges(namespace string) v1.LimitRangeInterface { + return &FakeLimitRanges{c, namespace} +} + +func (c *FakeCoreV1) Namespaces() v1.NamespaceInterface { + return &FakeNamespaces{c} +} + +func (c *FakeCoreV1) Nodes() v1.NodeInterface { + return &FakeNodes{c} +} + +func (c *FakeCoreV1) PersistentVolumes() v1.PersistentVolumeInterface { + return &FakePersistentVolumes{c} +} + +func (c *FakeCoreV1) PersistentVolumeClaims(namespace string) v1.PersistentVolumeClaimInterface { + return &FakePersistentVolumeClaims{c, namespace} +} + +func (c *FakeCoreV1) Pods(namespace string) v1.PodInterface { + return &FakePods{c, namespace} +} + +func (c *FakeCoreV1) PodTemplates(namespace string) v1.PodTemplateInterface { + return &FakePodTemplates{c, namespace} +} + +func (c *FakeCoreV1) ReplicationControllers(namespace string) v1.ReplicationControllerInterface { + return &FakeReplicationControllers{c, namespace} +} + +func (c *FakeCoreV1) ResourceQuotas(namespace string) v1.ResourceQuotaInterface { + return &FakeResourceQuotas{c, namespace} +} + +func (c *FakeCoreV1) Secrets(namespace string) v1.SecretInterface { + return &FakeSecrets{c, namespace} +} + +func (c *FakeCoreV1) Services(namespace string) v1.ServiceInterface { + return &FakeServices{c, namespace} +} + +func (c *FakeCoreV1) ServiceAccounts(namespace string) v1.ServiceAccountInterface { + return &FakeServiceAccounts{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeCoreV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_endpoints.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_endpoints.go new file mode 100644 index 000000000..e9a515a1a --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_endpoints.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationscorev1 "k8s.io/client-go/applyconfigurations/core/v1" + testing "k8s.io/client-go/testing" +) + +// FakeEndpoints implements EndpointsInterface +type FakeEndpoints struct { + Fake *FakeCoreV1 + ns string +} + +var endpointsResource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "endpoints"} + +var endpointsKind = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Endpoints"} + +// Get takes name of the endpoints, and returns the corresponding endpoints object, and an error if there is any. +func (c *FakeEndpoints) Get(ctx context.Context, name string, options v1.GetOptions) (result *corev1.Endpoints, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(endpointsResource, c.ns, name), &corev1.Endpoints{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Endpoints), err +} + +// List takes label and field selectors, and returns the list of Endpoints that match those selectors. +func (c *FakeEndpoints) List(ctx context.Context, opts v1.ListOptions) (result *corev1.EndpointsList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(endpointsResource, endpointsKind, c.ns, opts), &corev1.EndpointsList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &corev1.EndpointsList{ListMeta: obj.(*corev1.EndpointsList).ListMeta} + for _, item := range obj.(*corev1.EndpointsList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested endpoints. +func (c *FakeEndpoints) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(endpointsResource, c.ns, opts)) + +} + +// Create takes the representation of a endpoints and creates it. Returns the server's representation of the endpoints, and an error, if there is any. +func (c *FakeEndpoints) Create(ctx context.Context, endpoints *corev1.Endpoints, opts v1.CreateOptions) (result *corev1.Endpoints, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(endpointsResource, c.ns, endpoints), &corev1.Endpoints{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Endpoints), err +} + +// Update takes the representation of a endpoints and updates it. Returns the server's representation of the endpoints, and an error, if there is any. +func (c *FakeEndpoints) Update(ctx context.Context, endpoints *corev1.Endpoints, opts v1.UpdateOptions) (result *corev1.Endpoints, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(endpointsResource, c.ns, endpoints), &corev1.Endpoints{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Endpoints), err +} + +// Delete takes name of the endpoints and deletes it. Returns an error if one occurs. +func (c *FakeEndpoints) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(endpointsResource, c.ns, name, opts), &corev1.Endpoints{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeEndpoints) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(endpointsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &corev1.EndpointsList{}) + return err +} + +// Patch applies the patch and returns the patched endpoints. +func (c *FakeEndpoints) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *corev1.Endpoints, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(endpointsResource, c.ns, name, pt, data, subresources...), &corev1.Endpoints{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Endpoints), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied endpoints. +func (c *FakeEndpoints) Apply(ctx context.Context, endpoints *applyconfigurationscorev1.EndpointsApplyConfiguration, opts v1.ApplyOptions) (result *corev1.Endpoints, err error) { + if endpoints == nil { + return nil, fmt.Errorf("endpoints provided to Apply must not be nil") + } + data, err := json.Marshal(endpoints) + if err != nil { + return nil, err + } + name := endpoints.Name + if name == nil { + return nil, fmt.Errorf("endpoints.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(endpointsResource, c.ns, *name, types.ApplyPatchType, data), &corev1.Endpoints{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Endpoints), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_event.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_event.go new file mode 100644 index 000000000..951883943 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_event.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationscorev1 "k8s.io/client-go/applyconfigurations/core/v1" + testing "k8s.io/client-go/testing" +) + +// FakeEvents implements EventInterface +type FakeEvents struct { + Fake *FakeCoreV1 + ns string +} + +var eventsResource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "events"} + +var eventsKind = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Event"} + +// Get takes name of the event, and returns the corresponding event object, and an error if there is any. +func (c *FakeEvents) Get(ctx context.Context, name string, options v1.GetOptions) (result *corev1.Event, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(eventsResource, c.ns, name), &corev1.Event{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Event), err +} + +// List takes label and field selectors, and returns the list of Events that match those selectors. +func (c *FakeEvents) List(ctx context.Context, opts v1.ListOptions) (result *corev1.EventList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(eventsResource, eventsKind, c.ns, opts), &corev1.EventList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &corev1.EventList{ListMeta: obj.(*corev1.EventList).ListMeta} + for _, item := range obj.(*corev1.EventList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested events. +func (c *FakeEvents) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(eventsResource, c.ns, opts)) + +} + +// Create takes the representation of a event and creates it. Returns the server's representation of the event, and an error, if there is any. +func (c *FakeEvents) Create(ctx context.Context, event *corev1.Event, opts v1.CreateOptions) (result *corev1.Event, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(eventsResource, c.ns, event), &corev1.Event{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Event), err +} + +// Update takes the representation of a event and updates it. Returns the server's representation of the event, and an error, if there is any. +func (c *FakeEvents) Update(ctx context.Context, event *corev1.Event, opts v1.UpdateOptions) (result *corev1.Event, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(eventsResource, c.ns, event), &corev1.Event{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Event), err +} + +// Delete takes name of the event and deletes it. Returns an error if one occurs. +func (c *FakeEvents) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(eventsResource, c.ns, name, opts), &corev1.Event{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeEvents) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(eventsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &corev1.EventList{}) + return err +} + +// Patch applies the patch and returns the patched event. +func (c *FakeEvents) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *corev1.Event, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(eventsResource, c.ns, name, pt, data, subresources...), &corev1.Event{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Event), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied event. +func (c *FakeEvents) Apply(ctx context.Context, event *applyconfigurationscorev1.EventApplyConfiguration, opts v1.ApplyOptions) (result *corev1.Event, err error) { + if event == nil { + return nil, fmt.Errorf("event provided to Apply must not be nil") + } + data, err := json.Marshal(event) + if err != nil { + return nil, err + } + name := event.Name + if name == nil { + return nil, fmt.Errorf("event.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(eventsResource, c.ns, *name, types.ApplyPatchType, data), &corev1.Event{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Event), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_event_expansion.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_event_expansion.go new file mode 100644 index 000000000..48282f86e --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_event_expansion.go @@ -0,0 +1,101 @@ +/* +Copyright 2014 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 fake + +import ( + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/runtime" + types "k8s.io/apimachinery/pkg/types" + core "k8s.io/client-go/testing" +) + +func (c *FakeEvents) CreateWithEventNamespace(event *v1.Event) (*v1.Event, error) { + var action core.CreateActionImpl + if c.ns != "" { + action = core.NewCreateAction(eventsResource, c.ns, event) + } else { + action = core.NewCreateAction(eventsResource, event.GetNamespace(), event) + } + obj, err := c.Fake.Invokes(action, event) + if obj == nil { + return nil, err + } + + return obj.(*v1.Event), err +} + +// Update replaces an existing event. Returns the copy of the event the server returns, or an error. +func (c *FakeEvents) UpdateWithEventNamespace(event *v1.Event) (*v1.Event, error) { + var action core.UpdateActionImpl + if c.ns != "" { + action = core.NewUpdateAction(eventsResource, c.ns, event) + } else { + action = core.NewUpdateAction(eventsResource, event.GetNamespace(), event) + } + obj, err := c.Fake.Invokes(action, event) + if obj == nil { + return nil, err + } + + return obj.(*v1.Event), err +} + +// PatchWithEventNamespace patches an existing event. Returns the copy of the event the server returns, or an error. +// TODO: Should take a PatchType as an argument probably. +func (c *FakeEvents) PatchWithEventNamespace(event *v1.Event, data []byte) (*v1.Event, error) { + // TODO: Should be configurable to support additional patch strategies. + pt := types.StrategicMergePatchType + var action core.PatchActionImpl + if c.ns != "" { + action = core.NewPatchAction(eventsResource, c.ns, event.Name, pt, data) + } else { + action = core.NewPatchAction(eventsResource, event.GetNamespace(), event.Name, pt, data) + } + obj, err := c.Fake.Invokes(action, event) + if obj == nil { + return nil, err + } + + return obj.(*v1.Event), err +} + +// Search returns a list of events matching the specified object. +func (c *FakeEvents) Search(scheme *runtime.Scheme, objOrRef runtime.Object) (*v1.EventList, error) { + var action core.ListActionImpl + if c.ns != "" { + action = core.NewListAction(eventsResource, eventsKind, c.ns, metav1.ListOptions{}) + } else { + action = core.NewListAction(eventsResource, eventsKind, v1.NamespaceDefault, metav1.ListOptions{}) + } + obj, err := c.Fake.Invokes(action, &v1.EventList{}) + if obj == nil { + return nil, err + } + + return obj.(*v1.EventList), err +} + +func (c *FakeEvents) GetFieldSelector(involvedObjectName, involvedObjectNamespace, involvedObjectKind, involvedObjectUID *string) fields.Selector { + action := core.GenericActionImpl{} + action.Verb = "get-field-selector" + action.Resource = eventsResource + + c.Fake.Invokes(action, nil) + return fields.Everything() +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_limitrange.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_limitrange.go new file mode 100644 index 000000000..7487285e9 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_limitrange.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationscorev1 "k8s.io/client-go/applyconfigurations/core/v1" + testing "k8s.io/client-go/testing" +) + +// FakeLimitRanges implements LimitRangeInterface +type FakeLimitRanges struct { + Fake *FakeCoreV1 + ns string +} + +var limitrangesResource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "limitranges"} + +var limitrangesKind = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "LimitRange"} + +// Get takes name of the limitRange, and returns the corresponding limitRange object, and an error if there is any. +func (c *FakeLimitRanges) Get(ctx context.Context, name string, options v1.GetOptions) (result *corev1.LimitRange, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(limitrangesResource, c.ns, name), &corev1.LimitRange{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.LimitRange), err +} + +// List takes label and field selectors, and returns the list of LimitRanges that match those selectors. +func (c *FakeLimitRanges) List(ctx context.Context, opts v1.ListOptions) (result *corev1.LimitRangeList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(limitrangesResource, limitrangesKind, c.ns, opts), &corev1.LimitRangeList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &corev1.LimitRangeList{ListMeta: obj.(*corev1.LimitRangeList).ListMeta} + for _, item := range obj.(*corev1.LimitRangeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested limitRanges. +func (c *FakeLimitRanges) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(limitrangesResource, c.ns, opts)) + +} + +// Create takes the representation of a limitRange and creates it. Returns the server's representation of the limitRange, and an error, if there is any. +func (c *FakeLimitRanges) Create(ctx context.Context, limitRange *corev1.LimitRange, opts v1.CreateOptions) (result *corev1.LimitRange, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(limitrangesResource, c.ns, limitRange), &corev1.LimitRange{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.LimitRange), err +} + +// Update takes the representation of a limitRange and updates it. Returns the server's representation of the limitRange, and an error, if there is any. +func (c *FakeLimitRanges) Update(ctx context.Context, limitRange *corev1.LimitRange, opts v1.UpdateOptions) (result *corev1.LimitRange, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(limitrangesResource, c.ns, limitRange), &corev1.LimitRange{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.LimitRange), err +} + +// Delete takes name of the limitRange and deletes it. Returns an error if one occurs. +func (c *FakeLimitRanges) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(limitrangesResource, c.ns, name, opts), &corev1.LimitRange{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeLimitRanges) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(limitrangesResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &corev1.LimitRangeList{}) + return err +} + +// Patch applies the patch and returns the patched limitRange. +func (c *FakeLimitRanges) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *corev1.LimitRange, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(limitrangesResource, c.ns, name, pt, data, subresources...), &corev1.LimitRange{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.LimitRange), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied limitRange. +func (c *FakeLimitRanges) Apply(ctx context.Context, limitRange *applyconfigurationscorev1.LimitRangeApplyConfiguration, opts v1.ApplyOptions) (result *corev1.LimitRange, err error) { + if limitRange == nil { + return nil, fmt.Errorf("limitRange provided to Apply must not be nil") + } + data, err := json.Marshal(limitRange) + if err != nil { + return nil, err + } + name := limitRange.Name + if name == nil { + return nil, fmt.Errorf("limitRange.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(limitrangesResource, c.ns, *name, types.ApplyPatchType, data), &corev1.LimitRange{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.LimitRange), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_namespace.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_namespace.go new file mode 100644 index 000000000..83ada9f72 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_namespace.go @@ -0,0 +1,171 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationscorev1 "k8s.io/client-go/applyconfigurations/core/v1" + testing "k8s.io/client-go/testing" +) + +// FakeNamespaces implements NamespaceInterface +type FakeNamespaces struct { + Fake *FakeCoreV1 +} + +var namespacesResource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "namespaces"} + +var namespacesKind = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Namespace"} + +// Get takes name of the namespace, and returns the corresponding namespace object, and an error if there is any. +func (c *FakeNamespaces) Get(ctx context.Context, name string, options v1.GetOptions) (result *corev1.Namespace, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(namespacesResource, name), &corev1.Namespace{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.Namespace), err +} + +// List takes label and field selectors, and returns the list of Namespaces that match those selectors. +func (c *FakeNamespaces) List(ctx context.Context, opts v1.ListOptions) (result *corev1.NamespaceList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(namespacesResource, namespacesKind, opts), &corev1.NamespaceList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &corev1.NamespaceList{ListMeta: obj.(*corev1.NamespaceList).ListMeta} + for _, item := range obj.(*corev1.NamespaceList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested namespaces. +func (c *FakeNamespaces) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(namespacesResource, opts)) +} + +// Create takes the representation of a namespace and creates it. Returns the server's representation of the namespace, and an error, if there is any. +func (c *FakeNamespaces) Create(ctx context.Context, namespace *corev1.Namespace, opts v1.CreateOptions) (result *corev1.Namespace, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(namespacesResource, namespace), &corev1.Namespace{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.Namespace), err +} + +// Update takes the representation of a namespace and updates it. Returns the server's representation of the namespace, and an error, if there is any. +func (c *FakeNamespaces) Update(ctx context.Context, namespace *corev1.Namespace, opts v1.UpdateOptions) (result *corev1.Namespace, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(namespacesResource, namespace), &corev1.Namespace{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.Namespace), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeNamespaces) UpdateStatus(ctx context.Context, namespace *corev1.Namespace, opts v1.UpdateOptions) (*corev1.Namespace, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(namespacesResource, "status", namespace), &corev1.Namespace{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.Namespace), err +} + +// Delete takes name of the namespace and deletes it. Returns an error if one occurs. +func (c *FakeNamespaces) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(namespacesResource, name, opts), &corev1.Namespace{}) + return err +} + +// Patch applies the patch and returns the patched namespace. +func (c *FakeNamespaces) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *corev1.Namespace, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(namespacesResource, name, pt, data, subresources...), &corev1.Namespace{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.Namespace), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied namespace. +func (c *FakeNamespaces) Apply(ctx context.Context, namespace *applyconfigurationscorev1.NamespaceApplyConfiguration, opts v1.ApplyOptions) (result *corev1.Namespace, err error) { + if namespace == nil { + return nil, fmt.Errorf("namespace provided to Apply must not be nil") + } + data, err := json.Marshal(namespace) + if err != nil { + return nil, err + } + name := namespace.Name + if name == nil { + return nil, fmt.Errorf("namespace.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(namespacesResource, *name, types.ApplyPatchType, data), &corev1.Namespace{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.Namespace), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeNamespaces) ApplyStatus(ctx context.Context, namespace *applyconfigurationscorev1.NamespaceApplyConfiguration, opts v1.ApplyOptions) (result *corev1.Namespace, err error) { + if namespace == nil { + return nil, fmt.Errorf("namespace provided to Apply must not be nil") + } + data, err := json.Marshal(namespace) + if err != nil { + return nil, err + } + name := namespace.Name + if name == nil { + return nil, fmt.Errorf("namespace.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(namespacesResource, *name, types.ApplyPatchType, data, "status"), &corev1.Namespace{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.Namespace), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_namespace_expansion.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_namespace_expansion.go new file mode 100644 index 000000000..d86b328a4 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_namespace_expansion.go @@ -0,0 +1,40 @@ +/* +Copyright 2014 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 fake + +import ( + "context" + + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + core "k8s.io/client-go/testing" +) + +func (c *FakeNamespaces) Finalize(ctx context.Context, namespace *v1.Namespace, opts metav1.UpdateOptions) (*v1.Namespace, error) { + action := core.CreateActionImpl{} + action.Verb = "create" + action.Resource = namespacesResource + action.Subresource = "finalize" + action.Object = namespace + + obj, err := c.Fake.Invokes(action, namespace) + if obj == nil { + return nil, err + } + + return obj.(*v1.Namespace), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_node.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_node.go new file mode 100644 index 000000000..82816deb4 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_node.go @@ -0,0 +1,179 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationscorev1 "k8s.io/client-go/applyconfigurations/core/v1" + testing "k8s.io/client-go/testing" +) + +// FakeNodes implements NodeInterface +type FakeNodes struct { + Fake *FakeCoreV1 +} + +var nodesResource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "nodes"} + +var nodesKind = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Node"} + +// Get takes name of the node, and returns the corresponding node object, and an error if there is any. +func (c *FakeNodes) Get(ctx context.Context, name string, options v1.GetOptions) (result *corev1.Node, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(nodesResource, name), &corev1.Node{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.Node), err +} + +// List takes label and field selectors, and returns the list of Nodes that match those selectors. +func (c *FakeNodes) List(ctx context.Context, opts v1.ListOptions) (result *corev1.NodeList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(nodesResource, nodesKind, opts), &corev1.NodeList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &corev1.NodeList{ListMeta: obj.(*corev1.NodeList).ListMeta} + for _, item := range obj.(*corev1.NodeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested nodes. +func (c *FakeNodes) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(nodesResource, opts)) +} + +// Create takes the representation of a node and creates it. Returns the server's representation of the node, and an error, if there is any. +func (c *FakeNodes) Create(ctx context.Context, node *corev1.Node, opts v1.CreateOptions) (result *corev1.Node, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(nodesResource, node), &corev1.Node{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.Node), err +} + +// Update takes the representation of a node and updates it. Returns the server's representation of the node, and an error, if there is any. +func (c *FakeNodes) Update(ctx context.Context, node *corev1.Node, opts v1.UpdateOptions) (result *corev1.Node, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(nodesResource, node), &corev1.Node{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.Node), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeNodes) UpdateStatus(ctx context.Context, node *corev1.Node, opts v1.UpdateOptions) (*corev1.Node, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(nodesResource, "status", node), &corev1.Node{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.Node), err +} + +// Delete takes name of the node and deletes it. Returns an error if one occurs. +func (c *FakeNodes) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(nodesResource, name, opts), &corev1.Node{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeNodes) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(nodesResource, listOpts) + + _, err := c.Fake.Invokes(action, &corev1.NodeList{}) + return err +} + +// Patch applies the patch and returns the patched node. +func (c *FakeNodes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *corev1.Node, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(nodesResource, name, pt, data, subresources...), &corev1.Node{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.Node), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied node. +func (c *FakeNodes) Apply(ctx context.Context, node *applyconfigurationscorev1.NodeApplyConfiguration, opts v1.ApplyOptions) (result *corev1.Node, err error) { + if node == nil { + return nil, fmt.Errorf("node provided to Apply must not be nil") + } + data, err := json.Marshal(node) + if err != nil { + return nil, err + } + name := node.Name + if name == nil { + return nil, fmt.Errorf("node.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(nodesResource, *name, types.ApplyPatchType, data), &corev1.Node{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.Node), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeNodes) ApplyStatus(ctx context.Context, node *applyconfigurationscorev1.NodeApplyConfiguration, opts v1.ApplyOptions) (result *corev1.Node, err error) { + if node == nil { + return nil, fmt.Errorf("node provided to Apply must not be nil") + } + data, err := json.Marshal(node) + if err != nil { + return nil, err + } + name := node.Name + if name == nil { + return nil, fmt.Errorf("node.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(nodesResource, *name, types.ApplyPatchType, data, "status"), &corev1.Node{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.Node), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_node_expansion.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_node_expansion.go new file mode 100644 index 000000000..eccf9fec6 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_node_expansion.go @@ -0,0 +1,38 @@ +/* +Copyright 2016 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 fake + +import ( + "context" + + v1 "k8s.io/api/core/v1" + types "k8s.io/apimachinery/pkg/types" + core "k8s.io/client-go/testing" +) + +// TODO: Should take a PatchType as an argument probably. +func (c *FakeNodes) PatchStatus(_ context.Context, nodeName string, data []byte) (*v1.Node, error) { + // TODO: Should be configurable to support additional patch strategies. + pt := types.StrategicMergePatchType + obj, err := c.Fake.Invokes( + core.NewRootPatchSubresourceAction(nodesResource, nodeName, pt, data, "status"), &v1.Node{}) + if obj == nil { + return nil, err + } + + return obj.(*v1.Node), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_persistentvolume.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_persistentvolume.go new file mode 100644 index 000000000..d071a45db --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_persistentvolume.go @@ -0,0 +1,179 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationscorev1 "k8s.io/client-go/applyconfigurations/core/v1" + testing "k8s.io/client-go/testing" +) + +// FakePersistentVolumes implements PersistentVolumeInterface +type FakePersistentVolumes struct { + Fake *FakeCoreV1 +} + +var persistentvolumesResource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "persistentvolumes"} + +var persistentvolumesKind = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "PersistentVolume"} + +// Get takes name of the persistentVolume, and returns the corresponding persistentVolume object, and an error if there is any. +func (c *FakePersistentVolumes) Get(ctx context.Context, name string, options v1.GetOptions) (result *corev1.PersistentVolume, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(persistentvolumesResource, name), &corev1.PersistentVolume{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.PersistentVolume), err +} + +// List takes label and field selectors, and returns the list of PersistentVolumes that match those selectors. +func (c *FakePersistentVolumes) List(ctx context.Context, opts v1.ListOptions) (result *corev1.PersistentVolumeList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(persistentvolumesResource, persistentvolumesKind, opts), &corev1.PersistentVolumeList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &corev1.PersistentVolumeList{ListMeta: obj.(*corev1.PersistentVolumeList).ListMeta} + for _, item := range obj.(*corev1.PersistentVolumeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested persistentVolumes. +func (c *FakePersistentVolumes) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(persistentvolumesResource, opts)) +} + +// Create takes the representation of a persistentVolume and creates it. Returns the server's representation of the persistentVolume, and an error, if there is any. +func (c *FakePersistentVolumes) Create(ctx context.Context, persistentVolume *corev1.PersistentVolume, opts v1.CreateOptions) (result *corev1.PersistentVolume, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(persistentvolumesResource, persistentVolume), &corev1.PersistentVolume{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.PersistentVolume), err +} + +// Update takes the representation of a persistentVolume and updates it. Returns the server's representation of the persistentVolume, and an error, if there is any. +func (c *FakePersistentVolumes) Update(ctx context.Context, persistentVolume *corev1.PersistentVolume, opts v1.UpdateOptions) (result *corev1.PersistentVolume, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(persistentvolumesResource, persistentVolume), &corev1.PersistentVolume{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.PersistentVolume), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakePersistentVolumes) UpdateStatus(ctx context.Context, persistentVolume *corev1.PersistentVolume, opts v1.UpdateOptions) (*corev1.PersistentVolume, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(persistentvolumesResource, "status", persistentVolume), &corev1.PersistentVolume{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.PersistentVolume), err +} + +// Delete takes name of the persistentVolume and deletes it. Returns an error if one occurs. +func (c *FakePersistentVolumes) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(persistentvolumesResource, name, opts), &corev1.PersistentVolume{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakePersistentVolumes) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(persistentvolumesResource, listOpts) + + _, err := c.Fake.Invokes(action, &corev1.PersistentVolumeList{}) + return err +} + +// Patch applies the patch and returns the patched persistentVolume. +func (c *FakePersistentVolumes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *corev1.PersistentVolume, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(persistentvolumesResource, name, pt, data, subresources...), &corev1.PersistentVolume{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.PersistentVolume), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied persistentVolume. +func (c *FakePersistentVolumes) Apply(ctx context.Context, persistentVolume *applyconfigurationscorev1.PersistentVolumeApplyConfiguration, opts v1.ApplyOptions) (result *corev1.PersistentVolume, err error) { + if persistentVolume == nil { + return nil, fmt.Errorf("persistentVolume provided to Apply must not be nil") + } + data, err := json.Marshal(persistentVolume) + if err != nil { + return nil, err + } + name := persistentVolume.Name + if name == nil { + return nil, fmt.Errorf("persistentVolume.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(persistentvolumesResource, *name, types.ApplyPatchType, data), &corev1.PersistentVolume{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.PersistentVolume), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakePersistentVolumes) ApplyStatus(ctx context.Context, persistentVolume *applyconfigurationscorev1.PersistentVolumeApplyConfiguration, opts v1.ApplyOptions) (result *corev1.PersistentVolume, err error) { + if persistentVolume == nil { + return nil, fmt.Errorf("persistentVolume provided to Apply must not be nil") + } + data, err := json.Marshal(persistentVolume) + if err != nil { + return nil, err + } + name := persistentVolume.Name + if name == nil { + return nil, fmt.Errorf("persistentVolume.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(persistentvolumesResource, *name, types.ApplyPatchType, data, "status"), &corev1.PersistentVolume{}) + if obj == nil { + return nil, err + } + return obj.(*corev1.PersistentVolume), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_persistentvolumeclaim.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_persistentvolumeclaim.go new file mode 100644 index 000000000..6e4cef260 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_persistentvolumeclaim.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationscorev1 "k8s.io/client-go/applyconfigurations/core/v1" + testing "k8s.io/client-go/testing" +) + +// FakePersistentVolumeClaims implements PersistentVolumeClaimInterface +type FakePersistentVolumeClaims struct { + Fake *FakeCoreV1 + ns string +} + +var persistentvolumeclaimsResource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "persistentvolumeclaims"} + +var persistentvolumeclaimsKind = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "PersistentVolumeClaim"} + +// Get takes name of the persistentVolumeClaim, and returns the corresponding persistentVolumeClaim object, and an error if there is any. +func (c *FakePersistentVolumeClaims) Get(ctx context.Context, name string, options v1.GetOptions) (result *corev1.PersistentVolumeClaim, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(persistentvolumeclaimsResource, c.ns, name), &corev1.PersistentVolumeClaim{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.PersistentVolumeClaim), err +} + +// List takes label and field selectors, and returns the list of PersistentVolumeClaims that match those selectors. +func (c *FakePersistentVolumeClaims) List(ctx context.Context, opts v1.ListOptions) (result *corev1.PersistentVolumeClaimList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(persistentvolumeclaimsResource, persistentvolumeclaimsKind, c.ns, opts), &corev1.PersistentVolumeClaimList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &corev1.PersistentVolumeClaimList{ListMeta: obj.(*corev1.PersistentVolumeClaimList).ListMeta} + for _, item := range obj.(*corev1.PersistentVolumeClaimList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested persistentVolumeClaims. +func (c *FakePersistentVolumeClaims) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(persistentvolumeclaimsResource, c.ns, opts)) + +} + +// Create takes the representation of a persistentVolumeClaim and creates it. Returns the server's representation of the persistentVolumeClaim, and an error, if there is any. +func (c *FakePersistentVolumeClaims) Create(ctx context.Context, persistentVolumeClaim *corev1.PersistentVolumeClaim, opts v1.CreateOptions) (result *corev1.PersistentVolumeClaim, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(persistentvolumeclaimsResource, c.ns, persistentVolumeClaim), &corev1.PersistentVolumeClaim{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.PersistentVolumeClaim), err +} + +// Update takes the representation of a persistentVolumeClaim and updates it. Returns the server's representation of the persistentVolumeClaim, and an error, if there is any. +func (c *FakePersistentVolumeClaims) Update(ctx context.Context, persistentVolumeClaim *corev1.PersistentVolumeClaim, opts v1.UpdateOptions) (result *corev1.PersistentVolumeClaim, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(persistentvolumeclaimsResource, c.ns, persistentVolumeClaim), &corev1.PersistentVolumeClaim{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.PersistentVolumeClaim), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakePersistentVolumeClaims) UpdateStatus(ctx context.Context, persistentVolumeClaim *corev1.PersistentVolumeClaim, opts v1.UpdateOptions) (*corev1.PersistentVolumeClaim, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(persistentvolumeclaimsResource, "status", c.ns, persistentVolumeClaim), &corev1.PersistentVolumeClaim{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.PersistentVolumeClaim), err +} + +// Delete takes name of the persistentVolumeClaim and deletes it. Returns an error if one occurs. +func (c *FakePersistentVolumeClaims) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(persistentvolumeclaimsResource, c.ns, name, opts), &corev1.PersistentVolumeClaim{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakePersistentVolumeClaims) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(persistentvolumeclaimsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &corev1.PersistentVolumeClaimList{}) + return err +} + +// Patch applies the patch and returns the patched persistentVolumeClaim. +func (c *FakePersistentVolumeClaims) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *corev1.PersistentVolumeClaim, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(persistentvolumeclaimsResource, c.ns, name, pt, data, subresources...), &corev1.PersistentVolumeClaim{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.PersistentVolumeClaim), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied persistentVolumeClaim. +func (c *FakePersistentVolumeClaims) Apply(ctx context.Context, persistentVolumeClaim *applyconfigurationscorev1.PersistentVolumeClaimApplyConfiguration, opts v1.ApplyOptions) (result *corev1.PersistentVolumeClaim, err error) { + if persistentVolumeClaim == nil { + return nil, fmt.Errorf("persistentVolumeClaim provided to Apply must not be nil") + } + data, err := json.Marshal(persistentVolumeClaim) + if err != nil { + return nil, err + } + name := persistentVolumeClaim.Name + if name == nil { + return nil, fmt.Errorf("persistentVolumeClaim.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(persistentvolumeclaimsResource, c.ns, *name, types.ApplyPatchType, data), &corev1.PersistentVolumeClaim{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.PersistentVolumeClaim), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakePersistentVolumeClaims) ApplyStatus(ctx context.Context, persistentVolumeClaim *applyconfigurationscorev1.PersistentVolumeClaimApplyConfiguration, opts v1.ApplyOptions) (result *corev1.PersistentVolumeClaim, err error) { + if persistentVolumeClaim == nil { + return nil, fmt.Errorf("persistentVolumeClaim provided to Apply must not be nil") + } + data, err := json.Marshal(persistentVolumeClaim) + if err != nil { + return nil, err + } + name := persistentVolumeClaim.Name + if name == nil { + return nil, fmt.Errorf("persistentVolumeClaim.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(persistentvolumeclaimsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &corev1.PersistentVolumeClaim{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.PersistentVolumeClaim), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_pod.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_pod.go new file mode 100644 index 000000000..38a147955 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_pod.go @@ -0,0 +1,201 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationscorev1 "k8s.io/client-go/applyconfigurations/core/v1" + testing "k8s.io/client-go/testing" +) + +// FakePods implements PodInterface +type FakePods struct { + Fake *FakeCoreV1 + ns string +} + +var podsResource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"} + +var podsKind = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"} + +// Get takes name of the pod, and returns the corresponding pod object, and an error if there is any. +func (c *FakePods) Get(ctx context.Context, name string, options v1.GetOptions) (result *corev1.Pod, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(podsResource, c.ns, name), &corev1.Pod{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Pod), err +} + +// List takes label and field selectors, and returns the list of Pods that match those selectors. +func (c *FakePods) List(ctx context.Context, opts v1.ListOptions) (result *corev1.PodList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(podsResource, podsKind, c.ns, opts), &corev1.PodList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &corev1.PodList{ListMeta: obj.(*corev1.PodList).ListMeta} + for _, item := range obj.(*corev1.PodList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested pods. +func (c *FakePods) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(podsResource, c.ns, opts)) + +} + +// Create takes the representation of a pod and creates it. Returns the server's representation of the pod, and an error, if there is any. +func (c *FakePods) Create(ctx context.Context, pod *corev1.Pod, opts v1.CreateOptions) (result *corev1.Pod, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(podsResource, c.ns, pod), &corev1.Pod{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Pod), err +} + +// Update takes the representation of a pod and updates it. Returns the server's representation of the pod, and an error, if there is any. +func (c *FakePods) Update(ctx context.Context, pod *corev1.Pod, opts v1.UpdateOptions) (result *corev1.Pod, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(podsResource, c.ns, pod), &corev1.Pod{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Pod), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakePods) UpdateStatus(ctx context.Context, pod *corev1.Pod, opts v1.UpdateOptions) (*corev1.Pod, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(podsResource, "status", c.ns, pod), &corev1.Pod{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Pod), err +} + +// Delete takes name of the pod and deletes it. Returns an error if one occurs. +func (c *FakePods) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(podsResource, c.ns, name, opts), &corev1.Pod{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakePods) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(podsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &corev1.PodList{}) + return err +} + +// Patch applies the patch and returns the patched pod. +func (c *FakePods) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *corev1.Pod, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(podsResource, c.ns, name, pt, data, subresources...), &corev1.Pod{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Pod), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied pod. +func (c *FakePods) Apply(ctx context.Context, pod *applyconfigurationscorev1.PodApplyConfiguration, opts v1.ApplyOptions) (result *corev1.Pod, err error) { + if pod == nil { + return nil, fmt.Errorf("pod provided to Apply must not be nil") + } + data, err := json.Marshal(pod) + if err != nil { + return nil, err + } + name := pod.Name + if name == nil { + return nil, fmt.Errorf("pod.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(podsResource, c.ns, *name, types.ApplyPatchType, data), &corev1.Pod{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Pod), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakePods) ApplyStatus(ctx context.Context, pod *applyconfigurationscorev1.PodApplyConfiguration, opts v1.ApplyOptions) (result *corev1.Pod, err error) { + if pod == nil { + return nil, fmt.Errorf("pod provided to Apply must not be nil") + } + data, err := json.Marshal(pod) + if err != nil { + return nil, err + } + name := pod.Name + if name == nil { + return nil, fmt.Errorf("pod.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(podsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &corev1.Pod{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Pod), err +} + +// UpdateEphemeralContainers takes the representation of a pod and updates it. Returns the server's representation of the pod, and an error, if there is any. +func (c *FakePods) UpdateEphemeralContainers(ctx context.Context, podName string, pod *corev1.Pod, opts v1.UpdateOptions) (result *corev1.Pod, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(podsResource, "ephemeralcontainers", c.ns, pod), &corev1.Pod{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Pod), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_pod_expansion.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_pod_expansion.go new file mode 100644 index 000000000..c814cadb0 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_pod_expansion.go @@ -0,0 +1,112 @@ +/* +Copyright 2014 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 fake + +import ( + "context" + "fmt" + "io" + "net/http" + "strings" + + v1 "k8s.io/api/core/v1" + policyv1 "k8s.io/api/policy/v1" + policyv1beta1 "k8s.io/api/policy/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/scheme" + restclient "k8s.io/client-go/rest" + fakerest "k8s.io/client-go/rest/fake" + core "k8s.io/client-go/testing" +) + +func (c *FakePods) Bind(ctx context.Context, binding *v1.Binding, opts metav1.CreateOptions) error { + action := core.CreateActionImpl{} + action.Verb = "create" + action.Namespace = binding.Namespace + action.Resource = podsResource + action.Subresource = "binding" + action.Object = binding + + _, err := c.Fake.Invokes(action, binding) + return err +} + +func (c *FakePods) GetBinding(name string) (result *v1.Binding, err error) { + obj, err := c.Fake. + Invokes(core.NewGetSubresourceAction(podsResource, c.ns, "binding", name), &v1.Binding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1.Binding), err +} + +func (c *FakePods) GetLogs(name string, opts *v1.PodLogOptions) *restclient.Request { + action := core.GenericActionImpl{} + action.Verb = "get" + action.Namespace = c.ns + action.Resource = podsResource + action.Subresource = "log" + action.Value = opts + + _, _ = c.Fake.Invokes(action, &v1.Pod{}) + fakeClient := &fakerest.RESTClient{ + Client: fakerest.CreateHTTPClient(func(request *http.Request) (*http.Response, error) { + resp := &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(strings.NewReader("fake logs")), + } + return resp, nil + }), + NegotiatedSerializer: scheme.Codecs.WithoutConversion(), + GroupVersion: podsKind.GroupVersion(), + VersionedAPIPath: fmt.Sprintf("/api/v1/namespaces/%s/pods/%s/log", c.ns, name), + } + return fakeClient.Request() +} + +func (c *FakePods) Evict(ctx context.Context, eviction *policyv1beta1.Eviction) error { + return c.EvictV1beta1(ctx, eviction) +} + +func (c *FakePods) EvictV1(ctx context.Context, eviction *policyv1.Eviction) error { + action := core.CreateActionImpl{} + action.Verb = "create" + action.Namespace = c.ns + action.Resource = podsResource + action.Subresource = "eviction" + action.Object = eviction + + _, err := c.Fake.Invokes(action, eviction) + return err +} + +func (c *FakePods) EvictV1beta1(ctx context.Context, eviction *policyv1beta1.Eviction) error { + action := core.CreateActionImpl{} + action.Verb = "create" + action.Namespace = c.ns + action.Resource = podsResource + action.Subresource = "eviction" + action.Object = eviction + + _, err := c.Fake.Invokes(action, eviction) + return err +} + +func (c *FakePods) ProxyGet(scheme, name, port, path string, params map[string]string) restclient.ResponseWrapper { + return c.Fake.InvokesProxy(core.NewProxyGetAction(podsResource, c.ns, scheme, name, port, path, params)) +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_podtemplate.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_podtemplate.go new file mode 100644 index 000000000..00711f36f --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_podtemplate.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationscorev1 "k8s.io/client-go/applyconfigurations/core/v1" + testing "k8s.io/client-go/testing" +) + +// FakePodTemplates implements PodTemplateInterface +type FakePodTemplates struct { + Fake *FakeCoreV1 + ns string +} + +var podtemplatesResource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "podtemplates"} + +var podtemplatesKind = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "PodTemplate"} + +// Get takes name of the podTemplate, and returns the corresponding podTemplate object, and an error if there is any. +func (c *FakePodTemplates) Get(ctx context.Context, name string, options v1.GetOptions) (result *corev1.PodTemplate, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(podtemplatesResource, c.ns, name), &corev1.PodTemplate{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.PodTemplate), err +} + +// List takes label and field selectors, and returns the list of PodTemplates that match those selectors. +func (c *FakePodTemplates) List(ctx context.Context, opts v1.ListOptions) (result *corev1.PodTemplateList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(podtemplatesResource, podtemplatesKind, c.ns, opts), &corev1.PodTemplateList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &corev1.PodTemplateList{ListMeta: obj.(*corev1.PodTemplateList).ListMeta} + for _, item := range obj.(*corev1.PodTemplateList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested podTemplates. +func (c *FakePodTemplates) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(podtemplatesResource, c.ns, opts)) + +} + +// Create takes the representation of a podTemplate and creates it. Returns the server's representation of the podTemplate, and an error, if there is any. +func (c *FakePodTemplates) Create(ctx context.Context, podTemplate *corev1.PodTemplate, opts v1.CreateOptions) (result *corev1.PodTemplate, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(podtemplatesResource, c.ns, podTemplate), &corev1.PodTemplate{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.PodTemplate), err +} + +// Update takes the representation of a podTemplate and updates it. Returns the server's representation of the podTemplate, and an error, if there is any. +func (c *FakePodTemplates) Update(ctx context.Context, podTemplate *corev1.PodTemplate, opts v1.UpdateOptions) (result *corev1.PodTemplate, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(podtemplatesResource, c.ns, podTemplate), &corev1.PodTemplate{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.PodTemplate), err +} + +// Delete takes name of the podTemplate and deletes it. Returns an error if one occurs. +func (c *FakePodTemplates) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(podtemplatesResource, c.ns, name, opts), &corev1.PodTemplate{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakePodTemplates) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(podtemplatesResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &corev1.PodTemplateList{}) + return err +} + +// Patch applies the patch and returns the patched podTemplate. +func (c *FakePodTemplates) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *corev1.PodTemplate, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(podtemplatesResource, c.ns, name, pt, data, subresources...), &corev1.PodTemplate{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.PodTemplate), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied podTemplate. +func (c *FakePodTemplates) Apply(ctx context.Context, podTemplate *applyconfigurationscorev1.PodTemplateApplyConfiguration, opts v1.ApplyOptions) (result *corev1.PodTemplate, err error) { + if podTemplate == nil { + return nil, fmt.Errorf("podTemplate provided to Apply must not be nil") + } + data, err := json.Marshal(podTemplate) + if err != nil { + return nil, err + } + name := podTemplate.Name + if name == nil { + return nil, fmt.Errorf("podTemplate.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(podtemplatesResource, c.ns, *name, types.ApplyPatchType, data), &corev1.PodTemplate{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.PodTemplate), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_replicationcontroller.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_replicationcontroller.go new file mode 100644 index 000000000..086f4dbf9 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_replicationcontroller.go @@ -0,0 +1,213 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + autoscalingv1 "k8s.io/api/autoscaling/v1" + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationscorev1 "k8s.io/client-go/applyconfigurations/core/v1" + testing "k8s.io/client-go/testing" +) + +// FakeReplicationControllers implements ReplicationControllerInterface +type FakeReplicationControllers struct { + Fake *FakeCoreV1 + ns string +} + +var replicationcontrollersResource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "replicationcontrollers"} + +var replicationcontrollersKind = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ReplicationController"} + +// Get takes name of the replicationController, and returns the corresponding replicationController object, and an error if there is any. +func (c *FakeReplicationControllers) Get(ctx context.Context, name string, options v1.GetOptions) (result *corev1.ReplicationController, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(replicationcontrollersResource, c.ns, name), &corev1.ReplicationController{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ReplicationController), err +} + +// List takes label and field selectors, and returns the list of ReplicationControllers that match those selectors. +func (c *FakeReplicationControllers) List(ctx context.Context, opts v1.ListOptions) (result *corev1.ReplicationControllerList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(replicationcontrollersResource, replicationcontrollersKind, c.ns, opts), &corev1.ReplicationControllerList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &corev1.ReplicationControllerList{ListMeta: obj.(*corev1.ReplicationControllerList).ListMeta} + for _, item := range obj.(*corev1.ReplicationControllerList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested replicationControllers. +func (c *FakeReplicationControllers) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(replicationcontrollersResource, c.ns, opts)) + +} + +// Create takes the representation of a replicationController and creates it. Returns the server's representation of the replicationController, and an error, if there is any. +func (c *FakeReplicationControllers) Create(ctx context.Context, replicationController *corev1.ReplicationController, opts v1.CreateOptions) (result *corev1.ReplicationController, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(replicationcontrollersResource, c.ns, replicationController), &corev1.ReplicationController{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ReplicationController), err +} + +// Update takes the representation of a replicationController and updates it. Returns the server's representation of the replicationController, and an error, if there is any. +func (c *FakeReplicationControllers) Update(ctx context.Context, replicationController *corev1.ReplicationController, opts v1.UpdateOptions) (result *corev1.ReplicationController, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(replicationcontrollersResource, c.ns, replicationController), &corev1.ReplicationController{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ReplicationController), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeReplicationControllers) UpdateStatus(ctx context.Context, replicationController *corev1.ReplicationController, opts v1.UpdateOptions) (*corev1.ReplicationController, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(replicationcontrollersResource, "status", c.ns, replicationController), &corev1.ReplicationController{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ReplicationController), err +} + +// Delete takes name of the replicationController and deletes it. Returns an error if one occurs. +func (c *FakeReplicationControllers) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(replicationcontrollersResource, c.ns, name, opts), &corev1.ReplicationController{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeReplicationControllers) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(replicationcontrollersResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &corev1.ReplicationControllerList{}) + return err +} + +// Patch applies the patch and returns the patched replicationController. +func (c *FakeReplicationControllers) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *corev1.ReplicationController, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(replicationcontrollersResource, c.ns, name, pt, data, subresources...), &corev1.ReplicationController{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ReplicationController), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied replicationController. +func (c *FakeReplicationControllers) Apply(ctx context.Context, replicationController *applyconfigurationscorev1.ReplicationControllerApplyConfiguration, opts v1.ApplyOptions) (result *corev1.ReplicationController, err error) { + if replicationController == nil { + return nil, fmt.Errorf("replicationController provided to Apply must not be nil") + } + data, err := json.Marshal(replicationController) + if err != nil { + return nil, err + } + name := replicationController.Name + if name == nil { + return nil, fmt.Errorf("replicationController.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(replicationcontrollersResource, c.ns, *name, types.ApplyPatchType, data), &corev1.ReplicationController{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ReplicationController), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeReplicationControllers) ApplyStatus(ctx context.Context, replicationController *applyconfigurationscorev1.ReplicationControllerApplyConfiguration, opts v1.ApplyOptions) (result *corev1.ReplicationController, err error) { + if replicationController == nil { + return nil, fmt.Errorf("replicationController provided to Apply must not be nil") + } + data, err := json.Marshal(replicationController) + if err != nil { + return nil, err + } + name := replicationController.Name + if name == nil { + return nil, fmt.Errorf("replicationController.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(replicationcontrollersResource, c.ns, *name, types.ApplyPatchType, data, "status"), &corev1.ReplicationController{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ReplicationController), err +} + +// GetScale takes name of the replicationController, and returns the corresponding scale object, and an error if there is any. +func (c *FakeReplicationControllers) GetScale(ctx context.Context, replicationControllerName string, options v1.GetOptions) (result *autoscalingv1.Scale, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetSubresourceAction(replicationcontrollersResource, c.ns, "scale", replicationControllerName), &autoscalingv1.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*autoscalingv1.Scale), err +} + +// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *FakeReplicationControllers) UpdateScale(ctx context.Context, replicationControllerName string, scale *autoscalingv1.Scale, opts v1.UpdateOptions) (result *autoscalingv1.Scale, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(replicationcontrollersResource, "scale", c.ns, scale), &autoscalingv1.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*autoscalingv1.Scale), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_resourcequota.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_resourcequota.go new file mode 100644 index 000000000..9e008a973 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_resourcequota.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationscorev1 "k8s.io/client-go/applyconfigurations/core/v1" + testing "k8s.io/client-go/testing" +) + +// FakeResourceQuotas implements ResourceQuotaInterface +type FakeResourceQuotas struct { + Fake *FakeCoreV1 + ns string +} + +var resourcequotasResource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "resourcequotas"} + +var resourcequotasKind = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ResourceQuota"} + +// Get takes name of the resourceQuota, and returns the corresponding resourceQuota object, and an error if there is any. +func (c *FakeResourceQuotas) Get(ctx context.Context, name string, options v1.GetOptions) (result *corev1.ResourceQuota, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(resourcequotasResource, c.ns, name), &corev1.ResourceQuota{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ResourceQuota), err +} + +// List takes label and field selectors, and returns the list of ResourceQuotas that match those selectors. +func (c *FakeResourceQuotas) List(ctx context.Context, opts v1.ListOptions) (result *corev1.ResourceQuotaList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(resourcequotasResource, resourcequotasKind, c.ns, opts), &corev1.ResourceQuotaList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &corev1.ResourceQuotaList{ListMeta: obj.(*corev1.ResourceQuotaList).ListMeta} + for _, item := range obj.(*corev1.ResourceQuotaList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested resourceQuotas. +func (c *FakeResourceQuotas) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(resourcequotasResource, c.ns, opts)) + +} + +// Create takes the representation of a resourceQuota and creates it. Returns the server's representation of the resourceQuota, and an error, if there is any. +func (c *FakeResourceQuotas) Create(ctx context.Context, resourceQuota *corev1.ResourceQuota, opts v1.CreateOptions) (result *corev1.ResourceQuota, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(resourcequotasResource, c.ns, resourceQuota), &corev1.ResourceQuota{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ResourceQuota), err +} + +// Update takes the representation of a resourceQuota and updates it. Returns the server's representation of the resourceQuota, and an error, if there is any. +func (c *FakeResourceQuotas) Update(ctx context.Context, resourceQuota *corev1.ResourceQuota, opts v1.UpdateOptions) (result *corev1.ResourceQuota, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(resourcequotasResource, c.ns, resourceQuota), &corev1.ResourceQuota{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ResourceQuota), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeResourceQuotas) UpdateStatus(ctx context.Context, resourceQuota *corev1.ResourceQuota, opts v1.UpdateOptions) (*corev1.ResourceQuota, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(resourcequotasResource, "status", c.ns, resourceQuota), &corev1.ResourceQuota{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ResourceQuota), err +} + +// Delete takes name of the resourceQuota and deletes it. Returns an error if one occurs. +func (c *FakeResourceQuotas) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(resourcequotasResource, c.ns, name, opts), &corev1.ResourceQuota{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeResourceQuotas) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(resourcequotasResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &corev1.ResourceQuotaList{}) + return err +} + +// Patch applies the patch and returns the patched resourceQuota. +func (c *FakeResourceQuotas) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *corev1.ResourceQuota, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(resourcequotasResource, c.ns, name, pt, data, subresources...), &corev1.ResourceQuota{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ResourceQuota), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied resourceQuota. +func (c *FakeResourceQuotas) Apply(ctx context.Context, resourceQuota *applyconfigurationscorev1.ResourceQuotaApplyConfiguration, opts v1.ApplyOptions) (result *corev1.ResourceQuota, err error) { + if resourceQuota == nil { + return nil, fmt.Errorf("resourceQuota provided to Apply must not be nil") + } + data, err := json.Marshal(resourceQuota) + if err != nil { + return nil, err + } + name := resourceQuota.Name + if name == nil { + return nil, fmt.Errorf("resourceQuota.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(resourcequotasResource, c.ns, *name, types.ApplyPatchType, data), &corev1.ResourceQuota{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ResourceQuota), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeResourceQuotas) ApplyStatus(ctx context.Context, resourceQuota *applyconfigurationscorev1.ResourceQuotaApplyConfiguration, opts v1.ApplyOptions) (result *corev1.ResourceQuota, err error) { + if resourceQuota == nil { + return nil, fmt.Errorf("resourceQuota provided to Apply must not be nil") + } + data, err := json.Marshal(resourceQuota) + if err != nil { + return nil, err + } + name := resourceQuota.Name + if name == nil { + return nil, fmt.Errorf("resourceQuota.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(resourcequotasResource, c.ns, *name, types.ApplyPatchType, data, "status"), &corev1.ResourceQuota{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ResourceQuota), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_secret.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_secret.go new file mode 100644 index 000000000..b46730533 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_secret.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationscorev1 "k8s.io/client-go/applyconfigurations/core/v1" + testing "k8s.io/client-go/testing" +) + +// FakeSecrets implements SecretInterface +type FakeSecrets struct { + Fake *FakeCoreV1 + ns string +} + +var secretsResource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "secrets"} + +var secretsKind = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Secret"} + +// Get takes name of the secret, and returns the corresponding secret object, and an error if there is any. +func (c *FakeSecrets) Get(ctx context.Context, name string, options v1.GetOptions) (result *corev1.Secret, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(secretsResource, c.ns, name), &corev1.Secret{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Secret), err +} + +// List takes label and field selectors, and returns the list of Secrets that match those selectors. +func (c *FakeSecrets) List(ctx context.Context, opts v1.ListOptions) (result *corev1.SecretList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(secretsResource, secretsKind, c.ns, opts), &corev1.SecretList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &corev1.SecretList{ListMeta: obj.(*corev1.SecretList).ListMeta} + for _, item := range obj.(*corev1.SecretList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested secrets. +func (c *FakeSecrets) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(secretsResource, c.ns, opts)) + +} + +// Create takes the representation of a secret and creates it. Returns the server's representation of the secret, and an error, if there is any. +func (c *FakeSecrets) Create(ctx context.Context, secret *corev1.Secret, opts v1.CreateOptions) (result *corev1.Secret, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(secretsResource, c.ns, secret), &corev1.Secret{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Secret), err +} + +// Update takes the representation of a secret and updates it. Returns the server's representation of the secret, and an error, if there is any. +func (c *FakeSecrets) Update(ctx context.Context, secret *corev1.Secret, opts v1.UpdateOptions) (result *corev1.Secret, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(secretsResource, c.ns, secret), &corev1.Secret{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Secret), err +} + +// Delete takes name of the secret and deletes it. Returns an error if one occurs. +func (c *FakeSecrets) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(secretsResource, c.ns, name, opts), &corev1.Secret{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeSecrets) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(secretsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &corev1.SecretList{}) + return err +} + +// Patch applies the patch and returns the patched secret. +func (c *FakeSecrets) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *corev1.Secret, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(secretsResource, c.ns, name, pt, data, subresources...), &corev1.Secret{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Secret), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied secret. +func (c *FakeSecrets) Apply(ctx context.Context, secret *applyconfigurationscorev1.SecretApplyConfiguration, opts v1.ApplyOptions) (result *corev1.Secret, err error) { + if secret == nil { + return nil, fmt.Errorf("secret provided to Apply must not be nil") + } + data, err := json.Marshal(secret) + if err != nil { + return nil, err + } + name := secret.Name + if name == nil { + return nil, fmt.Errorf("secret.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(secretsResource, c.ns, *name, types.ApplyPatchType, data), &corev1.Secret{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Secret), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_service.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_service.go new file mode 100644 index 000000000..bfbabec07 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_service.go @@ -0,0 +1,182 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationscorev1 "k8s.io/client-go/applyconfigurations/core/v1" + testing "k8s.io/client-go/testing" +) + +// FakeServices implements ServiceInterface +type FakeServices struct { + Fake *FakeCoreV1 + ns string +} + +var servicesResource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "services"} + +var servicesKind = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Service"} + +// Get takes name of the service, and returns the corresponding service object, and an error if there is any. +func (c *FakeServices) Get(ctx context.Context, name string, options v1.GetOptions) (result *corev1.Service, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(servicesResource, c.ns, name), &corev1.Service{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Service), err +} + +// List takes label and field selectors, and returns the list of Services that match those selectors. +func (c *FakeServices) List(ctx context.Context, opts v1.ListOptions) (result *corev1.ServiceList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(servicesResource, servicesKind, c.ns, opts), &corev1.ServiceList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &corev1.ServiceList{ListMeta: obj.(*corev1.ServiceList).ListMeta} + for _, item := range obj.(*corev1.ServiceList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested services. +func (c *FakeServices) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(servicesResource, c.ns, opts)) + +} + +// Create takes the representation of a service and creates it. Returns the server's representation of the service, and an error, if there is any. +func (c *FakeServices) Create(ctx context.Context, service *corev1.Service, opts v1.CreateOptions) (result *corev1.Service, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(servicesResource, c.ns, service), &corev1.Service{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Service), err +} + +// Update takes the representation of a service and updates it. Returns the server's representation of the service, and an error, if there is any. +func (c *FakeServices) Update(ctx context.Context, service *corev1.Service, opts v1.UpdateOptions) (result *corev1.Service, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(servicesResource, c.ns, service), &corev1.Service{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Service), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeServices) UpdateStatus(ctx context.Context, service *corev1.Service, opts v1.UpdateOptions) (*corev1.Service, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(servicesResource, "status", c.ns, service), &corev1.Service{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Service), err +} + +// Delete takes name of the service and deletes it. Returns an error if one occurs. +func (c *FakeServices) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(servicesResource, c.ns, name, opts), &corev1.Service{}) + + return err +} + +// Patch applies the patch and returns the patched service. +func (c *FakeServices) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *corev1.Service, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(servicesResource, c.ns, name, pt, data, subresources...), &corev1.Service{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Service), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied service. +func (c *FakeServices) Apply(ctx context.Context, service *applyconfigurationscorev1.ServiceApplyConfiguration, opts v1.ApplyOptions) (result *corev1.Service, err error) { + if service == nil { + return nil, fmt.Errorf("service provided to Apply must not be nil") + } + data, err := json.Marshal(service) + if err != nil { + return nil, err + } + name := service.Name + if name == nil { + return nil, fmt.Errorf("service.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(servicesResource, c.ns, *name, types.ApplyPatchType, data), &corev1.Service{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Service), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeServices) ApplyStatus(ctx context.Context, service *applyconfigurationscorev1.ServiceApplyConfiguration, opts v1.ApplyOptions) (result *corev1.Service, err error) { + if service == nil { + return nil, fmt.Errorf("service provided to Apply must not be nil") + } + data, err := json.Marshal(service) + if err != nil { + return nil, err + } + name := service.Name + if name == nil { + return nil, fmt.Errorf("service.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(servicesResource, c.ns, *name, types.ApplyPatchType, data, "status"), &corev1.Service{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.Service), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_service_expansion.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_service_expansion.go new file mode 100644 index 000000000..92e4930d7 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_service_expansion.go @@ -0,0 +1,26 @@ +/* +Copyright 2014 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 fake + +import ( + restclient "k8s.io/client-go/rest" + core "k8s.io/client-go/testing" +) + +func (c *FakeServices) ProxyGet(scheme, name, port, path string, params map[string]string) restclient.ResponseWrapper { + return c.Fake.InvokesProxy(core.NewProxyGetAction(servicesResource, c.ns, scheme, name, port, path, params)) +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_serviceaccount.go b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_serviceaccount.go new file mode 100644 index 000000000..ff468957a --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_serviceaccount.go @@ -0,0 +1,167 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + authenticationv1 "k8s.io/api/authentication/v1" + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationscorev1 "k8s.io/client-go/applyconfigurations/core/v1" + testing "k8s.io/client-go/testing" +) + +// FakeServiceAccounts implements ServiceAccountInterface +type FakeServiceAccounts struct { + Fake *FakeCoreV1 + ns string +} + +var serviceaccountsResource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "serviceaccounts"} + +var serviceaccountsKind = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ServiceAccount"} + +// Get takes name of the serviceAccount, and returns the corresponding serviceAccount object, and an error if there is any. +func (c *FakeServiceAccounts) Get(ctx context.Context, name string, options v1.GetOptions) (result *corev1.ServiceAccount, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(serviceaccountsResource, c.ns, name), &corev1.ServiceAccount{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ServiceAccount), err +} + +// List takes label and field selectors, and returns the list of ServiceAccounts that match those selectors. +func (c *FakeServiceAccounts) List(ctx context.Context, opts v1.ListOptions) (result *corev1.ServiceAccountList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(serviceaccountsResource, serviceaccountsKind, c.ns, opts), &corev1.ServiceAccountList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &corev1.ServiceAccountList{ListMeta: obj.(*corev1.ServiceAccountList).ListMeta} + for _, item := range obj.(*corev1.ServiceAccountList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested serviceAccounts. +func (c *FakeServiceAccounts) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(serviceaccountsResource, c.ns, opts)) + +} + +// Create takes the representation of a serviceAccount and creates it. Returns the server's representation of the serviceAccount, and an error, if there is any. +func (c *FakeServiceAccounts) Create(ctx context.Context, serviceAccount *corev1.ServiceAccount, opts v1.CreateOptions) (result *corev1.ServiceAccount, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(serviceaccountsResource, c.ns, serviceAccount), &corev1.ServiceAccount{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ServiceAccount), err +} + +// Update takes the representation of a serviceAccount and updates it. Returns the server's representation of the serviceAccount, and an error, if there is any. +func (c *FakeServiceAccounts) Update(ctx context.Context, serviceAccount *corev1.ServiceAccount, opts v1.UpdateOptions) (result *corev1.ServiceAccount, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(serviceaccountsResource, c.ns, serviceAccount), &corev1.ServiceAccount{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ServiceAccount), err +} + +// Delete takes name of the serviceAccount and deletes it. Returns an error if one occurs. +func (c *FakeServiceAccounts) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(serviceaccountsResource, c.ns, name, opts), &corev1.ServiceAccount{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeServiceAccounts) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(serviceaccountsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &corev1.ServiceAccountList{}) + return err +} + +// Patch applies the patch and returns the patched serviceAccount. +func (c *FakeServiceAccounts) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *corev1.ServiceAccount, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(serviceaccountsResource, c.ns, name, pt, data, subresources...), &corev1.ServiceAccount{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ServiceAccount), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied serviceAccount. +func (c *FakeServiceAccounts) Apply(ctx context.Context, serviceAccount *applyconfigurationscorev1.ServiceAccountApplyConfiguration, opts v1.ApplyOptions) (result *corev1.ServiceAccount, err error) { + if serviceAccount == nil { + return nil, fmt.Errorf("serviceAccount provided to Apply must not be nil") + } + data, err := json.Marshal(serviceAccount) + if err != nil { + return nil, err + } + name := serviceAccount.Name + if name == nil { + return nil, fmt.Errorf("serviceAccount.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(serviceaccountsResource, c.ns, *name, types.ApplyPatchType, data), &corev1.ServiceAccount{}) + + if obj == nil { + return nil, err + } + return obj.(*corev1.ServiceAccount), err +} + +// CreateToken takes the representation of a tokenRequest and creates it. Returns the server's representation of the tokenRequest, and an error, if there is any. +func (c *FakeServiceAccounts) CreateToken(ctx context.Context, serviceAccountName string, tokenRequest *authenticationv1.TokenRequest, opts v1.CreateOptions) (result *authenticationv1.TokenRequest, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateSubresourceAction(serviceaccountsResource, serviceAccountName, "token", c.ns, tokenRequest), &authenticationv1.TokenRequest{}) + + if obj == nil { + return nil, err + } + return obj.(*authenticationv1.TokenRequest), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/discovery/v1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/discovery/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/discovery/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/discovery/v1/fake/fake_discovery_client.go b/vendor/k8s.io/client-go/kubernetes/typed/discovery/v1/fake/fake_discovery_client.go new file mode 100644 index 000000000..1ca9b23f5 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/discovery/v1/fake/fake_discovery_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/client-go/kubernetes/typed/discovery/v1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeDiscoveryV1 struct { + *testing.Fake +} + +func (c *FakeDiscoveryV1) EndpointSlices(namespace string) v1.EndpointSliceInterface { + return &FakeEndpointSlices{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeDiscoveryV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/discovery/v1/fake/fake_endpointslice.go b/vendor/k8s.io/client-go/kubernetes/typed/discovery/v1/fake/fake_endpointslice.go new file mode 100644 index 000000000..20e58b151 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/discovery/v1/fake/fake_endpointslice.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + discoveryv1 "k8s.io/api/discovery/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsdiscoveryv1 "k8s.io/client-go/applyconfigurations/discovery/v1" + testing "k8s.io/client-go/testing" +) + +// FakeEndpointSlices implements EndpointSliceInterface +type FakeEndpointSlices struct { + Fake *FakeDiscoveryV1 + ns string +} + +var endpointslicesResource = schema.GroupVersionResource{Group: "discovery.k8s.io", Version: "v1", Resource: "endpointslices"} + +var endpointslicesKind = schema.GroupVersionKind{Group: "discovery.k8s.io", Version: "v1", Kind: "EndpointSlice"} + +// Get takes name of the endpointSlice, and returns the corresponding endpointSlice object, and an error if there is any. +func (c *FakeEndpointSlices) Get(ctx context.Context, name string, options v1.GetOptions) (result *discoveryv1.EndpointSlice, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(endpointslicesResource, c.ns, name), &discoveryv1.EndpointSlice{}) + + if obj == nil { + return nil, err + } + return obj.(*discoveryv1.EndpointSlice), err +} + +// List takes label and field selectors, and returns the list of EndpointSlices that match those selectors. +func (c *FakeEndpointSlices) List(ctx context.Context, opts v1.ListOptions) (result *discoveryv1.EndpointSliceList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(endpointslicesResource, endpointslicesKind, c.ns, opts), &discoveryv1.EndpointSliceList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &discoveryv1.EndpointSliceList{ListMeta: obj.(*discoveryv1.EndpointSliceList).ListMeta} + for _, item := range obj.(*discoveryv1.EndpointSliceList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested endpointSlices. +func (c *FakeEndpointSlices) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(endpointslicesResource, c.ns, opts)) + +} + +// Create takes the representation of a endpointSlice and creates it. Returns the server's representation of the endpointSlice, and an error, if there is any. +func (c *FakeEndpointSlices) Create(ctx context.Context, endpointSlice *discoveryv1.EndpointSlice, opts v1.CreateOptions) (result *discoveryv1.EndpointSlice, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(endpointslicesResource, c.ns, endpointSlice), &discoveryv1.EndpointSlice{}) + + if obj == nil { + return nil, err + } + return obj.(*discoveryv1.EndpointSlice), err +} + +// Update takes the representation of a endpointSlice and updates it. Returns the server's representation of the endpointSlice, and an error, if there is any. +func (c *FakeEndpointSlices) Update(ctx context.Context, endpointSlice *discoveryv1.EndpointSlice, opts v1.UpdateOptions) (result *discoveryv1.EndpointSlice, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(endpointslicesResource, c.ns, endpointSlice), &discoveryv1.EndpointSlice{}) + + if obj == nil { + return nil, err + } + return obj.(*discoveryv1.EndpointSlice), err +} + +// Delete takes name of the endpointSlice and deletes it. Returns an error if one occurs. +func (c *FakeEndpointSlices) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(endpointslicesResource, c.ns, name, opts), &discoveryv1.EndpointSlice{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeEndpointSlices) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(endpointslicesResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &discoveryv1.EndpointSliceList{}) + return err +} + +// Patch applies the patch and returns the patched endpointSlice. +func (c *FakeEndpointSlices) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *discoveryv1.EndpointSlice, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(endpointslicesResource, c.ns, name, pt, data, subresources...), &discoveryv1.EndpointSlice{}) + + if obj == nil { + return nil, err + } + return obj.(*discoveryv1.EndpointSlice), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied endpointSlice. +func (c *FakeEndpointSlices) Apply(ctx context.Context, endpointSlice *applyconfigurationsdiscoveryv1.EndpointSliceApplyConfiguration, opts v1.ApplyOptions) (result *discoveryv1.EndpointSlice, err error) { + if endpointSlice == nil { + return nil, fmt.Errorf("endpointSlice provided to Apply must not be nil") + } + data, err := json.Marshal(endpointSlice) + if err != nil { + return nil, err + } + name := endpointSlice.Name + if name == nil { + return nil, fmt.Errorf("endpointSlice.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(endpointslicesResource, c.ns, *name, types.ApplyPatchType, data), &discoveryv1.EndpointSlice{}) + + if obj == nil { + return nil, err + } + return obj.(*discoveryv1.EndpointSlice), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/discovery/v1beta1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/discovery/v1beta1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/discovery/v1beta1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/discovery/v1beta1/fake/fake_discovery_client.go b/vendor/k8s.io/client-go/kubernetes/typed/discovery/v1beta1/fake/fake_discovery_client.go new file mode 100644 index 000000000..e285de647 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/discovery/v1beta1/fake/fake_discovery_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1beta1 "k8s.io/client-go/kubernetes/typed/discovery/v1beta1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeDiscoveryV1beta1 struct { + *testing.Fake +} + +func (c *FakeDiscoveryV1beta1) EndpointSlices(namespace string) v1beta1.EndpointSliceInterface { + return &FakeEndpointSlices{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeDiscoveryV1beta1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/discovery/v1beta1/fake/fake_endpointslice.go b/vendor/k8s.io/client-go/kubernetes/typed/discovery/v1beta1/fake/fake_endpointslice.go new file mode 100644 index 000000000..249de3446 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/discovery/v1beta1/fake/fake_endpointslice.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/discovery/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + discoveryv1beta1 "k8s.io/client-go/applyconfigurations/discovery/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeEndpointSlices implements EndpointSliceInterface +type FakeEndpointSlices struct { + Fake *FakeDiscoveryV1beta1 + ns string +} + +var endpointslicesResource = schema.GroupVersionResource{Group: "discovery.k8s.io", Version: "v1beta1", Resource: "endpointslices"} + +var endpointslicesKind = schema.GroupVersionKind{Group: "discovery.k8s.io", Version: "v1beta1", Kind: "EndpointSlice"} + +// Get takes name of the endpointSlice, and returns the corresponding endpointSlice object, and an error if there is any. +func (c *FakeEndpointSlices) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.EndpointSlice, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(endpointslicesResource, c.ns, name), &v1beta1.EndpointSlice{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.EndpointSlice), err +} + +// List takes label and field selectors, and returns the list of EndpointSlices that match those selectors. +func (c *FakeEndpointSlices) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.EndpointSliceList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(endpointslicesResource, endpointslicesKind, c.ns, opts), &v1beta1.EndpointSliceList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.EndpointSliceList{ListMeta: obj.(*v1beta1.EndpointSliceList).ListMeta} + for _, item := range obj.(*v1beta1.EndpointSliceList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested endpointSlices. +func (c *FakeEndpointSlices) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(endpointslicesResource, c.ns, opts)) + +} + +// Create takes the representation of a endpointSlice and creates it. Returns the server's representation of the endpointSlice, and an error, if there is any. +func (c *FakeEndpointSlices) Create(ctx context.Context, endpointSlice *v1beta1.EndpointSlice, opts v1.CreateOptions) (result *v1beta1.EndpointSlice, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(endpointslicesResource, c.ns, endpointSlice), &v1beta1.EndpointSlice{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.EndpointSlice), err +} + +// Update takes the representation of a endpointSlice and updates it. Returns the server's representation of the endpointSlice, and an error, if there is any. +func (c *FakeEndpointSlices) Update(ctx context.Context, endpointSlice *v1beta1.EndpointSlice, opts v1.UpdateOptions) (result *v1beta1.EndpointSlice, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(endpointslicesResource, c.ns, endpointSlice), &v1beta1.EndpointSlice{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.EndpointSlice), err +} + +// Delete takes name of the endpointSlice and deletes it. Returns an error if one occurs. +func (c *FakeEndpointSlices) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(endpointslicesResource, c.ns, name, opts), &v1beta1.EndpointSlice{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeEndpointSlices) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(endpointslicesResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.EndpointSliceList{}) + return err +} + +// Patch applies the patch and returns the patched endpointSlice. +func (c *FakeEndpointSlices) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.EndpointSlice, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(endpointslicesResource, c.ns, name, pt, data, subresources...), &v1beta1.EndpointSlice{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.EndpointSlice), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied endpointSlice. +func (c *FakeEndpointSlices) Apply(ctx context.Context, endpointSlice *discoveryv1beta1.EndpointSliceApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.EndpointSlice, err error) { + if endpointSlice == nil { + return nil, fmt.Errorf("endpointSlice provided to Apply must not be nil") + } + data, err := json.Marshal(endpointSlice) + if err != nil { + return nil, err + } + name := endpointSlice.Name + if name == nil { + return nil, fmt.Errorf("endpointSlice.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(endpointslicesResource, c.ns, *name, types.ApplyPatchType, data), &v1beta1.EndpointSlice{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.EndpointSlice), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/events/v1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/events/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/events/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/events/v1/fake/fake_event.go b/vendor/k8s.io/client-go/kubernetes/typed/events/v1/fake/fake_event.go new file mode 100644 index 000000000..87ff13c82 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/events/v1/fake/fake_event.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + eventsv1 "k8s.io/api/events/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationseventsv1 "k8s.io/client-go/applyconfigurations/events/v1" + testing "k8s.io/client-go/testing" +) + +// FakeEvents implements EventInterface +type FakeEvents struct { + Fake *FakeEventsV1 + ns string +} + +var eventsResource = schema.GroupVersionResource{Group: "events.k8s.io", Version: "v1", Resource: "events"} + +var eventsKind = schema.GroupVersionKind{Group: "events.k8s.io", Version: "v1", Kind: "Event"} + +// Get takes name of the event, and returns the corresponding event object, and an error if there is any. +func (c *FakeEvents) Get(ctx context.Context, name string, options v1.GetOptions) (result *eventsv1.Event, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(eventsResource, c.ns, name), &eventsv1.Event{}) + + if obj == nil { + return nil, err + } + return obj.(*eventsv1.Event), err +} + +// List takes label and field selectors, and returns the list of Events that match those selectors. +func (c *FakeEvents) List(ctx context.Context, opts v1.ListOptions) (result *eventsv1.EventList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(eventsResource, eventsKind, c.ns, opts), &eventsv1.EventList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &eventsv1.EventList{ListMeta: obj.(*eventsv1.EventList).ListMeta} + for _, item := range obj.(*eventsv1.EventList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested events. +func (c *FakeEvents) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(eventsResource, c.ns, opts)) + +} + +// Create takes the representation of a event and creates it. Returns the server's representation of the event, and an error, if there is any. +func (c *FakeEvents) Create(ctx context.Context, event *eventsv1.Event, opts v1.CreateOptions) (result *eventsv1.Event, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(eventsResource, c.ns, event), &eventsv1.Event{}) + + if obj == nil { + return nil, err + } + return obj.(*eventsv1.Event), err +} + +// Update takes the representation of a event and updates it. Returns the server's representation of the event, and an error, if there is any. +func (c *FakeEvents) Update(ctx context.Context, event *eventsv1.Event, opts v1.UpdateOptions) (result *eventsv1.Event, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(eventsResource, c.ns, event), &eventsv1.Event{}) + + if obj == nil { + return nil, err + } + return obj.(*eventsv1.Event), err +} + +// Delete takes name of the event and deletes it. Returns an error if one occurs. +func (c *FakeEvents) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(eventsResource, c.ns, name, opts), &eventsv1.Event{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeEvents) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(eventsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &eventsv1.EventList{}) + return err +} + +// Patch applies the patch and returns the patched event. +func (c *FakeEvents) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *eventsv1.Event, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(eventsResource, c.ns, name, pt, data, subresources...), &eventsv1.Event{}) + + if obj == nil { + return nil, err + } + return obj.(*eventsv1.Event), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied event. +func (c *FakeEvents) Apply(ctx context.Context, event *applyconfigurationseventsv1.EventApplyConfiguration, opts v1.ApplyOptions) (result *eventsv1.Event, err error) { + if event == nil { + return nil, fmt.Errorf("event provided to Apply must not be nil") + } + data, err := json.Marshal(event) + if err != nil { + return nil, err + } + name := event.Name + if name == nil { + return nil, fmt.Errorf("event.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(eventsResource, c.ns, *name, types.ApplyPatchType, data), &eventsv1.Event{}) + + if obj == nil { + return nil, err + } + return obj.(*eventsv1.Event), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/events/v1/fake/fake_events_client.go b/vendor/k8s.io/client-go/kubernetes/typed/events/v1/fake/fake_events_client.go new file mode 100644 index 000000000..95ef2b307 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/events/v1/fake/fake_events_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/client-go/kubernetes/typed/events/v1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeEventsV1 struct { + *testing.Fake +} + +func (c *FakeEventsV1) Events(namespace string) v1.EventInterface { + return &FakeEvents{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeEventsV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/events/v1beta1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/events/v1beta1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/events/v1beta1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/events/v1beta1/fake/fake_event.go b/vendor/k8s.io/client-go/kubernetes/typed/events/v1beta1/fake/fake_event.go new file mode 100644 index 000000000..5481c4d3f --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/events/v1beta1/fake/fake_event.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/events/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + eventsv1beta1 "k8s.io/client-go/applyconfigurations/events/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeEvents implements EventInterface +type FakeEvents struct { + Fake *FakeEventsV1beta1 + ns string +} + +var eventsResource = schema.GroupVersionResource{Group: "events.k8s.io", Version: "v1beta1", Resource: "events"} + +var eventsKind = schema.GroupVersionKind{Group: "events.k8s.io", Version: "v1beta1", Kind: "Event"} + +// Get takes name of the event, and returns the corresponding event object, and an error if there is any. +func (c *FakeEvents) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.Event, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(eventsResource, c.ns, name), &v1beta1.Event{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Event), err +} + +// List takes label and field selectors, and returns the list of Events that match those selectors. +func (c *FakeEvents) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.EventList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(eventsResource, eventsKind, c.ns, opts), &v1beta1.EventList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.EventList{ListMeta: obj.(*v1beta1.EventList).ListMeta} + for _, item := range obj.(*v1beta1.EventList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested events. +func (c *FakeEvents) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(eventsResource, c.ns, opts)) + +} + +// Create takes the representation of a event and creates it. Returns the server's representation of the event, and an error, if there is any. +func (c *FakeEvents) Create(ctx context.Context, event *v1beta1.Event, opts v1.CreateOptions) (result *v1beta1.Event, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(eventsResource, c.ns, event), &v1beta1.Event{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Event), err +} + +// Update takes the representation of a event and updates it. Returns the server's representation of the event, and an error, if there is any. +func (c *FakeEvents) Update(ctx context.Context, event *v1beta1.Event, opts v1.UpdateOptions) (result *v1beta1.Event, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(eventsResource, c.ns, event), &v1beta1.Event{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Event), err +} + +// Delete takes name of the event and deletes it. Returns an error if one occurs. +func (c *FakeEvents) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(eventsResource, c.ns, name, opts), &v1beta1.Event{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeEvents) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(eventsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.EventList{}) + return err +} + +// Patch applies the patch and returns the patched event. +func (c *FakeEvents) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Event, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(eventsResource, c.ns, name, pt, data, subresources...), &v1beta1.Event{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Event), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied event. +func (c *FakeEvents) Apply(ctx context.Context, event *eventsv1beta1.EventApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.Event, err error) { + if event == nil { + return nil, fmt.Errorf("event provided to Apply must not be nil") + } + data, err := json.Marshal(event) + if err != nil { + return nil, err + } + name := event.Name + if name == nil { + return nil, fmt.Errorf("event.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(eventsResource, c.ns, *name, types.ApplyPatchType, data), &v1beta1.Event{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Event), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/events/v1beta1/fake/fake_event_expansion.go b/vendor/k8s.io/client-go/kubernetes/typed/events/v1beta1/fake/fake_event_expansion.go new file mode 100644 index 000000000..19c1b4415 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/events/v1beta1/fake/fake_event_expansion.go @@ -0,0 +1,66 @@ +/* +Copyright 2019 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 fake + +import ( + v1beta1 "k8s.io/api/events/v1beta1" + types "k8s.io/apimachinery/pkg/types" + core "k8s.io/client-go/testing" +) + +// CreateWithEventNamespace creats a new event. Returns the copy of the event the server returns, or an error. +func (c *FakeEvents) CreateWithEventNamespace(event *v1beta1.Event) (*v1beta1.Event, error) { + action := core.NewRootCreateAction(eventsResource, event) + if c.ns != "" { + action = core.NewCreateAction(eventsResource, c.ns, event) + } + obj, err := c.Fake.Invokes(action, event) + if obj == nil { + return nil, err + } + + return obj.(*v1beta1.Event), err +} + +// UpdateWithEventNamespace replaces an existing event. Returns the copy of the event the server returns, or an error. +func (c *FakeEvents) UpdateWithEventNamespace(event *v1beta1.Event) (*v1beta1.Event, error) { + action := core.NewRootUpdateAction(eventsResource, event) + if c.ns != "" { + action = core.NewUpdateAction(eventsResource, c.ns, event) + } + obj, err := c.Fake.Invokes(action, event) + if obj == nil { + return nil, err + } + + return obj.(*v1beta1.Event), err +} + +// PatchWithEventNamespace patches an existing event. Returns the copy of the event the server returns, or an error. +func (c *FakeEvents) PatchWithEventNamespace(event *v1beta1.Event, data []byte) (*v1beta1.Event, error) { + pt := types.StrategicMergePatchType + action := core.NewRootPatchAction(eventsResource, event.Name, pt, data) + if c.ns != "" { + action = core.NewPatchAction(eventsResource, c.ns, event.Name, pt, data) + } + obj, err := c.Fake.Invokes(action, event) + if obj == nil { + return nil, err + } + + return obj.(*v1beta1.Event), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/events/v1beta1/fake/fake_events_client.go b/vendor/k8s.io/client-go/kubernetes/typed/events/v1beta1/fake/fake_events_client.go new file mode 100644 index 000000000..875c774e3 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/events/v1beta1/fake/fake_events_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1beta1 "k8s.io/client-go/kubernetes/typed/events/v1beta1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeEventsV1beta1 struct { + *testing.Fake +} + +func (c *FakeEventsV1beta1) Events(namespace string) v1beta1.EventInterface { + return &FakeEvents{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeEventsV1beta1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_daemonset.go b/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_daemonset.go new file mode 100644 index 000000000..11c05f195 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_daemonset.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/extensions/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + extensionsv1beta1 "k8s.io/client-go/applyconfigurations/extensions/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeDaemonSets implements DaemonSetInterface +type FakeDaemonSets struct { + Fake *FakeExtensionsV1beta1 + ns string +} + +var daemonsetsResource = schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "daemonsets"} + +var daemonsetsKind = schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "DaemonSet"} + +// Get takes name of the daemonSet, and returns the corresponding daemonSet object, and an error if there is any. +func (c *FakeDaemonSets) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.DaemonSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(daemonsetsResource, c.ns, name), &v1beta1.DaemonSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.DaemonSet), err +} + +// List takes label and field selectors, and returns the list of DaemonSets that match those selectors. +func (c *FakeDaemonSets) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.DaemonSetList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(daemonsetsResource, daemonsetsKind, c.ns, opts), &v1beta1.DaemonSetList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.DaemonSetList{ListMeta: obj.(*v1beta1.DaemonSetList).ListMeta} + for _, item := range obj.(*v1beta1.DaemonSetList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested daemonSets. +func (c *FakeDaemonSets) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(daemonsetsResource, c.ns, opts)) + +} + +// Create takes the representation of a daemonSet and creates it. Returns the server's representation of the daemonSet, and an error, if there is any. +func (c *FakeDaemonSets) Create(ctx context.Context, daemonSet *v1beta1.DaemonSet, opts v1.CreateOptions) (result *v1beta1.DaemonSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(daemonsetsResource, c.ns, daemonSet), &v1beta1.DaemonSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.DaemonSet), err +} + +// Update takes the representation of a daemonSet and updates it. Returns the server's representation of the daemonSet, and an error, if there is any. +func (c *FakeDaemonSets) Update(ctx context.Context, daemonSet *v1beta1.DaemonSet, opts v1.UpdateOptions) (result *v1beta1.DaemonSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(daemonsetsResource, c.ns, daemonSet), &v1beta1.DaemonSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.DaemonSet), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeDaemonSets) UpdateStatus(ctx context.Context, daemonSet *v1beta1.DaemonSet, opts v1.UpdateOptions) (*v1beta1.DaemonSet, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(daemonsetsResource, "status", c.ns, daemonSet), &v1beta1.DaemonSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.DaemonSet), err +} + +// Delete takes name of the daemonSet and deletes it. Returns an error if one occurs. +func (c *FakeDaemonSets) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(daemonsetsResource, c.ns, name, opts), &v1beta1.DaemonSet{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeDaemonSets) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(daemonsetsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.DaemonSetList{}) + return err +} + +// Patch applies the patch and returns the patched daemonSet. +func (c *FakeDaemonSets) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.DaemonSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(daemonsetsResource, c.ns, name, pt, data, subresources...), &v1beta1.DaemonSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.DaemonSet), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied daemonSet. +func (c *FakeDaemonSets) Apply(ctx context.Context, daemonSet *extensionsv1beta1.DaemonSetApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.DaemonSet, err error) { + if daemonSet == nil { + return nil, fmt.Errorf("daemonSet provided to Apply must not be nil") + } + data, err := json.Marshal(daemonSet) + if err != nil { + return nil, err + } + name := daemonSet.Name + if name == nil { + return nil, fmt.Errorf("daemonSet.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(daemonsetsResource, c.ns, *name, types.ApplyPatchType, data), &v1beta1.DaemonSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.DaemonSet), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeDaemonSets) ApplyStatus(ctx context.Context, daemonSet *extensionsv1beta1.DaemonSetApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.DaemonSet, err error) { + if daemonSet == nil { + return nil, fmt.Errorf("daemonSet provided to Apply must not be nil") + } + data, err := json.Marshal(daemonSet) + if err != nil { + return nil, err + } + name := daemonSet.Name + if name == nil { + return nil, fmt.Errorf("daemonSet.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(daemonsetsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v1beta1.DaemonSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.DaemonSet), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_deployment.go b/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_deployment.go new file mode 100644 index 000000000..9edf85d60 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_deployment.go @@ -0,0 +1,231 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/extensions/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + extensionsv1beta1 "k8s.io/client-go/applyconfigurations/extensions/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeDeployments implements DeploymentInterface +type FakeDeployments struct { + Fake *FakeExtensionsV1beta1 + ns string +} + +var deploymentsResource = schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "deployments"} + +var deploymentsKind = schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "Deployment"} + +// Get takes name of the deployment, and returns the corresponding deployment object, and an error if there is any. +func (c *FakeDeployments) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.Deployment, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(deploymentsResource, c.ns, name), &v1beta1.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Deployment), err +} + +// List takes label and field selectors, and returns the list of Deployments that match those selectors. +func (c *FakeDeployments) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.DeploymentList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(deploymentsResource, deploymentsKind, c.ns, opts), &v1beta1.DeploymentList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.DeploymentList{ListMeta: obj.(*v1beta1.DeploymentList).ListMeta} + for _, item := range obj.(*v1beta1.DeploymentList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested deployments. +func (c *FakeDeployments) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(deploymentsResource, c.ns, opts)) + +} + +// Create takes the representation of a deployment and creates it. Returns the server's representation of the deployment, and an error, if there is any. +func (c *FakeDeployments) Create(ctx context.Context, deployment *v1beta1.Deployment, opts v1.CreateOptions) (result *v1beta1.Deployment, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(deploymentsResource, c.ns, deployment), &v1beta1.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Deployment), err +} + +// Update takes the representation of a deployment and updates it. Returns the server's representation of the deployment, and an error, if there is any. +func (c *FakeDeployments) Update(ctx context.Context, deployment *v1beta1.Deployment, opts v1.UpdateOptions) (result *v1beta1.Deployment, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(deploymentsResource, c.ns, deployment), &v1beta1.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Deployment), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeDeployments) UpdateStatus(ctx context.Context, deployment *v1beta1.Deployment, opts v1.UpdateOptions) (*v1beta1.Deployment, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(deploymentsResource, "status", c.ns, deployment), &v1beta1.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Deployment), err +} + +// Delete takes name of the deployment and deletes it. Returns an error if one occurs. +func (c *FakeDeployments) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(deploymentsResource, c.ns, name, opts), &v1beta1.Deployment{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeDeployments) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(deploymentsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.DeploymentList{}) + return err +} + +// Patch applies the patch and returns the patched deployment. +func (c *FakeDeployments) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Deployment, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(deploymentsResource, c.ns, name, pt, data, subresources...), &v1beta1.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Deployment), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied deployment. +func (c *FakeDeployments) Apply(ctx context.Context, deployment *extensionsv1beta1.DeploymentApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.Deployment, err error) { + if deployment == nil { + return nil, fmt.Errorf("deployment provided to Apply must not be nil") + } + data, err := json.Marshal(deployment) + if err != nil { + return nil, err + } + name := deployment.Name + if name == nil { + return nil, fmt.Errorf("deployment.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(deploymentsResource, c.ns, *name, types.ApplyPatchType, data), &v1beta1.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Deployment), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeDeployments) ApplyStatus(ctx context.Context, deployment *extensionsv1beta1.DeploymentApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.Deployment, err error) { + if deployment == nil { + return nil, fmt.Errorf("deployment provided to Apply must not be nil") + } + data, err := json.Marshal(deployment) + if err != nil { + return nil, err + } + name := deployment.Name + if name == nil { + return nil, fmt.Errorf("deployment.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(deploymentsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v1beta1.Deployment{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Deployment), err +} + +// GetScale takes name of the deployment, and returns the corresponding scale object, and an error if there is any. +func (c *FakeDeployments) GetScale(ctx context.Context, deploymentName string, options v1.GetOptions) (result *v1beta1.Scale, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetSubresourceAction(deploymentsResource, c.ns, "scale", deploymentName), &v1beta1.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Scale), err +} + +// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *FakeDeployments) UpdateScale(ctx context.Context, deploymentName string, scale *v1beta1.Scale, opts v1.UpdateOptions) (result *v1beta1.Scale, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(deploymentsResource, "scale", c.ns, scale), &v1beta1.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Scale), err +} + +// ApplyScale takes top resource name and the apply declarative configuration for scale, +// applies it and returns the applied scale, and an error, if there is any. +func (c *FakeDeployments) ApplyScale(ctx context.Context, deploymentName string, scale *extensionsv1beta1.ScaleApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.Scale, err error) { + if scale == nil { + return nil, fmt.Errorf("scale provided to ApplyScale must not be nil") + } + data, err := json.Marshal(scale) + if err != nil { + return nil, err + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(deploymentsResource, c.ns, deploymentName, types.ApplyPatchType, data, "status"), &v1beta1.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Scale), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_deployment_expansion.go b/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_deployment_expansion.go new file mode 100644 index 000000000..6ea1acd85 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_deployment_expansion.go @@ -0,0 +1,36 @@ +/* +Copyright 2014 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 fake + +import ( + "context" + + "k8s.io/api/extensions/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + core "k8s.io/client-go/testing" +) + +func (c *FakeDeployments) Rollback(ctx context.Context, deploymentRollback *v1beta1.DeploymentRollback, opts metav1.CreateOptions) error { + action := core.CreateActionImpl{} + action.Verb = "create" + action.Resource = deploymentsResource + action.Subresource = "rollback" + action.Object = deploymentRollback + + _, err := c.Fake.Invokes(action, deploymentRollback) + return err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_extensions_client.go b/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_extensions_client.go new file mode 100644 index 000000000..36c0d51bc --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_extensions_client.go @@ -0,0 +1,60 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1beta1 "k8s.io/client-go/kubernetes/typed/extensions/v1beta1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeExtensionsV1beta1 struct { + *testing.Fake +} + +func (c *FakeExtensionsV1beta1) DaemonSets(namespace string) v1beta1.DaemonSetInterface { + return &FakeDaemonSets{c, namespace} +} + +func (c *FakeExtensionsV1beta1) Deployments(namespace string) v1beta1.DeploymentInterface { + return &FakeDeployments{c, namespace} +} + +func (c *FakeExtensionsV1beta1) Ingresses(namespace string) v1beta1.IngressInterface { + return &FakeIngresses{c, namespace} +} + +func (c *FakeExtensionsV1beta1) NetworkPolicies(namespace string) v1beta1.NetworkPolicyInterface { + return &FakeNetworkPolicies{c, namespace} +} + +func (c *FakeExtensionsV1beta1) PodSecurityPolicies() v1beta1.PodSecurityPolicyInterface { + return &FakePodSecurityPolicies{c} +} + +func (c *FakeExtensionsV1beta1) ReplicaSets(namespace string) v1beta1.ReplicaSetInterface { + return &FakeReplicaSets{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeExtensionsV1beta1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_ingress.go b/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_ingress.go new file mode 100644 index 000000000..d3bbd1abc --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_ingress.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/extensions/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + extensionsv1beta1 "k8s.io/client-go/applyconfigurations/extensions/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeIngresses implements IngressInterface +type FakeIngresses struct { + Fake *FakeExtensionsV1beta1 + ns string +} + +var ingressesResource = schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "ingresses"} + +var ingressesKind = schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "Ingress"} + +// Get takes name of the ingress, and returns the corresponding ingress object, and an error if there is any. +func (c *FakeIngresses) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.Ingress, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(ingressesResource, c.ns, name), &v1beta1.Ingress{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Ingress), err +} + +// List takes label and field selectors, and returns the list of Ingresses that match those selectors. +func (c *FakeIngresses) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.IngressList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(ingressesResource, ingressesKind, c.ns, opts), &v1beta1.IngressList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.IngressList{ListMeta: obj.(*v1beta1.IngressList).ListMeta} + for _, item := range obj.(*v1beta1.IngressList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested ingresses. +func (c *FakeIngresses) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(ingressesResource, c.ns, opts)) + +} + +// Create takes the representation of a ingress and creates it. Returns the server's representation of the ingress, and an error, if there is any. +func (c *FakeIngresses) Create(ctx context.Context, ingress *v1beta1.Ingress, opts v1.CreateOptions) (result *v1beta1.Ingress, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(ingressesResource, c.ns, ingress), &v1beta1.Ingress{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Ingress), err +} + +// Update takes the representation of a ingress and updates it. Returns the server's representation of the ingress, and an error, if there is any. +func (c *FakeIngresses) Update(ctx context.Context, ingress *v1beta1.Ingress, opts v1.UpdateOptions) (result *v1beta1.Ingress, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(ingressesResource, c.ns, ingress), &v1beta1.Ingress{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Ingress), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeIngresses) UpdateStatus(ctx context.Context, ingress *v1beta1.Ingress, opts v1.UpdateOptions) (*v1beta1.Ingress, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(ingressesResource, "status", c.ns, ingress), &v1beta1.Ingress{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Ingress), err +} + +// Delete takes name of the ingress and deletes it. Returns an error if one occurs. +func (c *FakeIngresses) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(ingressesResource, c.ns, name, opts), &v1beta1.Ingress{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeIngresses) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(ingressesResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.IngressList{}) + return err +} + +// Patch applies the patch and returns the patched ingress. +func (c *FakeIngresses) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Ingress, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(ingressesResource, c.ns, name, pt, data, subresources...), &v1beta1.Ingress{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Ingress), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied ingress. +func (c *FakeIngresses) Apply(ctx context.Context, ingress *extensionsv1beta1.IngressApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.Ingress, err error) { + if ingress == nil { + return nil, fmt.Errorf("ingress provided to Apply must not be nil") + } + data, err := json.Marshal(ingress) + if err != nil { + return nil, err + } + name := ingress.Name + if name == nil { + return nil, fmt.Errorf("ingress.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(ingressesResource, c.ns, *name, types.ApplyPatchType, data), &v1beta1.Ingress{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Ingress), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeIngresses) ApplyStatus(ctx context.Context, ingress *extensionsv1beta1.IngressApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.Ingress, err error) { + if ingress == nil { + return nil, fmt.Errorf("ingress provided to Apply must not be nil") + } + data, err := json.Marshal(ingress) + if err != nil { + return nil, err + } + name := ingress.Name + if name == nil { + return nil, fmt.Errorf("ingress.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(ingressesResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v1beta1.Ingress{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Ingress), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_networkpolicy.go b/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_networkpolicy.go new file mode 100644 index 000000000..1ff5d8c99 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_networkpolicy.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/extensions/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + extensionsv1beta1 "k8s.io/client-go/applyconfigurations/extensions/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeNetworkPolicies implements NetworkPolicyInterface +type FakeNetworkPolicies struct { + Fake *FakeExtensionsV1beta1 + ns string +} + +var networkpoliciesResource = schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "networkpolicies"} + +var networkpoliciesKind = schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "NetworkPolicy"} + +// Get takes name of the networkPolicy, and returns the corresponding networkPolicy object, and an error if there is any. +func (c *FakeNetworkPolicies) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.NetworkPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(networkpoliciesResource, c.ns, name), &v1beta1.NetworkPolicy{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.NetworkPolicy), err +} + +// List takes label and field selectors, and returns the list of NetworkPolicies that match those selectors. +func (c *FakeNetworkPolicies) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.NetworkPolicyList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(networkpoliciesResource, networkpoliciesKind, c.ns, opts), &v1beta1.NetworkPolicyList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.NetworkPolicyList{ListMeta: obj.(*v1beta1.NetworkPolicyList).ListMeta} + for _, item := range obj.(*v1beta1.NetworkPolicyList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested networkPolicies. +func (c *FakeNetworkPolicies) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(networkpoliciesResource, c.ns, opts)) + +} + +// Create takes the representation of a networkPolicy and creates it. Returns the server's representation of the networkPolicy, and an error, if there is any. +func (c *FakeNetworkPolicies) Create(ctx context.Context, networkPolicy *v1beta1.NetworkPolicy, opts v1.CreateOptions) (result *v1beta1.NetworkPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(networkpoliciesResource, c.ns, networkPolicy), &v1beta1.NetworkPolicy{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.NetworkPolicy), err +} + +// Update takes the representation of a networkPolicy and updates it. Returns the server's representation of the networkPolicy, and an error, if there is any. +func (c *FakeNetworkPolicies) Update(ctx context.Context, networkPolicy *v1beta1.NetworkPolicy, opts v1.UpdateOptions) (result *v1beta1.NetworkPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(networkpoliciesResource, c.ns, networkPolicy), &v1beta1.NetworkPolicy{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.NetworkPolicy), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeNetworkPolicies) UpdateStatus(ctx context.Context, networkPolicy *v1beta1.NetworkPolicy, opts v1.UpdateOptions) (*v1beta1.NetworkPolicy, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(networkpoliciesResource, "status", c.ns, networkPolicy), &v1beta1.NetworkPolicy{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.NetworkPolicy), err +} + +// Delete takes name of the networkPolicy and deletes it. Returns an error if one occurs. +func (c *FakeNetworkPolicies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(networkpoliciesResource, c.ns, name, opts), &v1beta1.NetworkPolicy{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeNetworkPolicies) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(networkpoliciesResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.NetworkPolicyList{}) + return err +} + +// Patch applies the patch and returns the patched networkPolicy. +func (c *FakeNetworkPolicies) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.NetworkPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(networkpoliciesResource, c.ns, name, pt, data, subresources...), &v1beta1.NetworkPolicy{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.NetworkPolicy), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied networkPolicy. +func (c *FakeNetworkPolicies) Apply(ctx context.Context, networkPolicy *extensionsv1beta1.NetworkPolicyApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.NetworkPolicy, err error) { + if networkPolicy == nil { + return nil, fmt.Errorf("networkPolicy provided to Apply must not be nil") + } + data, err := json.Marshal(networkPolicy) + if err != nil { + return nil, err + } + name := networkPolicy.Name + if name == nil { + return nil, fmt.Errorf("networkPolicy.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(networkpoliciesResource, c.ns, *name, types.ApplyPatchType, data), &v1beta1.NetworkPolicy{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.NetworkPolicy), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeNetworkPolicies) ApplyStatus(ctx context.Context, networkPolicy *extensionsv1beta1.NetworkPolicyApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.NetworkPolicy, err error) { + if networkPolicy == nil { + return nil, fmt.Errorf("networkPolicy provided to Apply must not be nil") + } + data, err := json.Marshal(networkPolicy) + if err != nil { + return nil, err + } + name := networkPolicy.Name + if name == nil { + return nil, fmt.Errorf("networkPolicy.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(networkpoliciesResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v1beta1.NetworkPolicy{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.NetworkPolicy), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_podsecuritypolicy.go b/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_podsecuritypolicy.go new file mode 100644 index 000000000..dd53fd5bd --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_podsecuritypolicy.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/extensions/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + extensionsv1beta1 "k8s.io/client-go/applyconfigurations/extensions/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakePodSecurityPolicies implements PodSecurityPolicyInterface +type FakePodSecurityPolicies struct { + Fake *FakeExtensionsV1beta1 +} + +var podsecuritypoliciesResource = schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "podsecuritypolicies"} + +var podsecuritypoliciesKind = schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "PodSecurityPolicy"} + +// Get takes name of the podSecurityPolicy, and returns the corresponding podSecurityPolicy object, and an error if there is any. +func (c *FakePodSecurityPolicies) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.PodSecurityPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(podsecuritypoliciesResource, name), &v1beta1.PodSecurityPolicy{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PodSecurityPolicy), err +} + +// List takes label and field selectors, and returns the list of PodSecurityPolicies that match those selectors. +func (c *FakePodSecurityPolicies) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.PodSecurityPolicyList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(podsecuritypoliciesResource, podsecuritypoliciesKind, opts), &v1beta1.PodSecurityPolicyList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.PodSecurityPolicyList{ListMeta: obj.(*v1beta1.PodSecurityPolicyList).ListMeta} + for _, item := range obj.(*v1beta1.PodSecurityPolicyList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested podSecurityPolicies. +func (c *FakePodSecurityPolicies) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(podsecuritypoliciesResource, opts)) +} + +// Create takes the representation of a podSecurityPolicy and creates it. Returns the server's representation of the podSecurityPolicy, and an error, if there is any. +func (c *FakePodSecurityPolicies) Create(ctx context.Context, podSecurityPolicy *v1beta1.PodSecurityPolicy, opts v1.CreateOptions) (result *v1beta1.PodSecurityPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(podsecuritypoliciesResource, podSecurityPolicy), &v1beta1.PodSecurityPolicy{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PodSecurityPolicy), err +} + +// Update takes the representation of a podSecurityPolicy and updates it. Returns the server's representation of the podSecurityPolicy, and an error, if there is any. +func (c *FakePodSecurityPolicies) Update(ctx context.Context, podSecurityPolicy *v1beta1.PodSecurityPolicy, opts v1.UpdateOptions) (result *v1beta1.PodSecurityPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(podsecuritypoliciesResource, podSecurityPolicy), &v1beta1.PodSecurityPolicy{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PodSecurityPolicy), err +} + +// Delete takes name of the podSecurityPolicy and deletes it. Returns an error if one occurs. +func (c *FakePodSecurityPolicies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(podsecuritypoliciesResource, name, opts), &v1beta1.PodSecurityPolicy{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakePodSecurityPolicies) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(podsecuritypoliciesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.PodSecurityPolicyList{}) + return err +} + +// Patch applies the patch and returns the patched podSecurityPolicy. +func (c *FakePodSecurityPolicies) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.PodSecurityPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(podsecuritypoliciesResource, name, pt, data, subresources...), &v1beta1.PodSecurityPolicy{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PodSecurityPolicy), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied podSecurityPolicy. +func (c *FakePodSecurityPolicies) Apply(ctx context.Context, podSecurityPolicy *extensionsv1beta1.PodSecurityPolicyApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.PodSecurityPolicy, err error) { + if podSecurityPolicy == nil { + return nil, fmt.Errorf("podSecurityPolicy provided to Apply must not be nil") + } + data, err := json.Marshal(podSecurityPolicy) + if err != nil { + return nil, err + } + name := podSecurityPolicy.Name + if name == nil { + return nil, fmt.Errorf("podSecurityPolicy.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(podsecuritypoliciesResource, *name, types.ApplyPatchType, data), &v1beta1.PodSecurityPolicy{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PodSecurityPolicy), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_replicaset.go b/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_replicaset.go new file mode 100644 index 000000000..d6d35e493 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake/fake_replicaset.go @@ -0,0 +1,231 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/extensions/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + extensionsv1beta1 "k8s.io/client-go/applyconfigurations/extensions/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeReplicaSets implements ReplicaSetInterface +type FakeReplicaSets struct { + Fake *FakeExtensionsV1beta1 + ns string +} + +var replicasetsResource = schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "replicasets"} + +var replicasetsKind = schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "ReplicaSet"} + +// Get takes name of the replicaSet, and returns the corresponding replicaSet object, and an error if there is any. +func (c *FakeReplicaSets) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.ReplicaSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(replicasetsResource, c.ns, name), &v1beta1.ReplicaSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ReplicaSet), err +} + +// List takes label and field selectors, and returns the list of ReplicaSets that match those selectors. +func (c *FakeReplicaSets) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.ReplicaSetList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(replicasetsResource, replicasetsKind, c.ns, opts), &v1beta1.ReplicaSetList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.ReplicaSetList{ListMeta: obj.(*v1beta1.ReplicaSetList).ListMeta} + for _, item := range obj.(*v1beta1.ReplicaSetList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested replicaSets. +func (c *FakeReplicaSets) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(replicasetsResource, c.ns, opts)) + +} + +// Create takes the representation of a replicaSet and creates it. Returns the server's representation of the replicaSet, and an error, if there is any. +func (c *FakeReplicaSets) Create(ctx context.Context, replicaSet *v1beta1.ReplicaSet, opts v1.CreateOptions) (result *v1beta1.ReplicaSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(replicasetsResource, c.ns, replicaSet), &v1beta1.ReplicaSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ReplicaSet), err +} + +// Update takes the representation of a replicaSet and updates it. Returns the server's representation of the replicaSet, and an error, if there is any. +func (c *FakeReplicaSets) Update(ctx context.Context, replicaSet *v1beta1.ReplicaSet, opts v1.UpdateOptions) (result *v1beta1.ReplicaSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(replicasetsResource, c.ns, replicaSet), &v1beta1.ReplicaSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ReplicaSet), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeReplicaSets) UpdateStatus(ctx context.Context, replicaSet *v1beta1.ReplicaSet, opts v1.UpdateOptions) (*v1beta1.ReplicaSet, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(replicasetsResource, "status", c.ns, replicaSet), &v1beta1.ReplicaSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ReplicaSet), err +} + +// Delete takes name of the replicaSet and deletes it. Returns an error if one occurs. +func (c *FakeReplicaSets) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(replicasetsResource, c.ns, name, opts), &v1beta1.ReplicaSet{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeReplicaSets) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(replicasetsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.ReplicaSetList{}) + return err +} + +// Patch applies the patch and returns the patched replicaSet. +func (c *FakeReplicaSets) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.ReplicaSet, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(replicasetsResource, c.ns, name, pt, data, subresources...), &v1beta1.ReplicaSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ReplicaSet), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied replicaSet. +func (c *FakeReplicaSets) Apply(ctx context.Context, replicaSet *extensionsv1beta1.ReplicaSetApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.ReplicaSet, err error) { + if replicaSet == nil { + return nil, fmt.Errorf("replicaSet provided to Apply must not be nil") + } + data, err := json.Marshal(replicaSet) + if err != nil { + return nil, err + } + name := replicaSet.Name + if name == nil { + return nil, fmt.Errorf("replicaSet.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(replicasetsResource, c.ns, *name, types.ApplyPatchType, data), &v1beta1.ReplicaSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ReplicaSet), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeReplicaSets) ApplyStatus(ctx context.Context, replicaSet *extensionsv1beta1.ReplicaSetApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.ReplicaSet, err error) { + if replicaSet == nil { + return nil, fmt.Errorf("replicaSet provided to Apply must not be nil") + } + data, err := json.Marshal(replicaSet) + if err != nil { + return nil, err + } + name := replicaSet.Name + if name == nil { + return nil, fmt.Errorf("replicaSet.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(replicasetsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v1beta1.ReplicaSet{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ReplicaSet), err +} + +// GetScale takes name of the replicaSet, and returns the corresponding scale object, and an error if there is any. +func (c *FakeReplicaSets) GetScale(ctx context.Context, replicaSetName string, options v1.GetOptions) (result *v1beta1.Scale, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetSubresourceAction(replicasetsResource, c.ns, "scale", replicaSetName), &v1beta1.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Scale), err +} + +// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *FakeReplicaSets) UpdateScale(ctx context.Context, replicaSetName string, scale *v1beta1.Scale, opts v1.UpdateOptions) (result *v1beta1.Scale, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(replicasetsResource, "scale", c.ns, scale), &v1beta1.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Scale), err +} + +// ApplyScale takes top resource name and the apply declarative configuration for scale, +// applies it and returns the applied scale, and an error, if there is any. +func (c *FakeReplicaSets) ApplyScale(ctx context.Context, replicaSetName string, scale *extensionsv1beta1.ScaleApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.Scale, err error) { + if scale == nil { + return nil, fmt.Errorf("scale provided to ApplyScale must not be nil") + } + data, err := json.Marshal(scale) + if err != nil { + return nil, err + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(replicasetsResource, c.ns, replicaSetName, types.ApplyPatchType, data, "status"), &v1beta1.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Scale), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1/fake/fake_flowcontrol_client.go b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1/fake/fake_flowcontrol_client.go new file mode 100644 index 000000000..72d5eff0c --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1/fake/fake_flowcontrol_client.go @@ -0,0 +1,44 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeFlowcontrolV1alpha1 struct { + *testing.Fake +} + +func (c *FakeFlowcontrolV1alpha1) FlowSchemas() v1alpha1.FlowSchemaInterface { + return &FakeFlowSchemas{c} +} + +func (c *FakeFlowcontrolV1alpha1) PriorityLevelConfigurations() v1alpha1.PriorityLevelConfigurationInterface { + return &FakePriorityLevelConfigurations{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeFlowcontrolV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1/fake/fake_flowschema.go b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1/fake/fake_flowschema.go new file mode 100644 index 000000000..06730a1ea --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1/fake/fake_flowschema.go @@ -0,0 +1,179 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1alpha1 "k8s.io/api/flowcontrol/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + flowcontrolv1alpha1 "k8s.io/client-go/applyconfigurations/flowcontrol/v1alpha1" + testing "k8s.io/client-go/testing" +) + +// FakeFlowSchemas implements FlowSchemaInterface +type FakeFlowSchemas struct { + Fake *FakeFlowcontrolV1alpha1 +} + +var flowschemasResource = schema.GroupVersionResource{Group: "flowcontrol.apiserver.k8s.io", Version: "v1alpha1", Resource: "flowschemas"} + +var flowschemasKind = schema.GroupVersionKind{Group: "flowcontrol.apiserver.k8s.io", Version: "v1alpha1", Kind: "FlowSchema"} + +// Get takes name of the flowSchema, and returns the corresponding flowSchema object, and an error if there is any. +func (c *FakeFlowSchemas) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.FlowSchema, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(flowschemasResource, name), &v1alpha1.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.FlowSchema), err +} + +// List takes label and field selectors, and returns the list of FlowSchemas that match those selectors. +func (c *FakeFlowSchemas) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.FlowSchemaList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(flowschemasResource, flowschemasKind, opts), &v1alpha1.FlowSchemaList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.FlowSchemaList{ListMeta: obj.(*v1alpha1.FlowSchemaList).ListMeta} + for _, item := range obj.(*v1alpha1.FlowSchemaList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested flowSchemas. +func (c *FakeFlowSchemas) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(flowschemasResource, opts)) +} + +// Create takes the representation of a flowSchema and creates it. Returns the server's representation of the flowSchema, and an error, if there is any. +func (c *FakeFlowSchemas) Create(ctx context.Context, flowSchema *v1alpha1.FlowSchema, opts v1.CreateOptions) (result *v1alpha1.FlowSchema, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(flowschemasResource, flowSchema), &v1alpha1.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.FlowSchema), err +} + +// Update takes the representation of a flowSchema and updates it. Returns the server's representation of the flowSchema, and an error, if there is any. +func (c *FakeFlowSchemas) Update(ctx context.Context, flowSchema *v1alpha1.FlowSchema, opts v1.UpdateOptions) (result *v1alpha1.FlowSchema, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(flowschemasResource, flowSchema), &v1alpha1.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.FlowSchema), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeFlowSchemas) UpdateStatus(ctx context.Context, flowSchema *v1alpha1.FlowSchema, opts v1.UpdateOptions) (*v1alpha1.FlowSchema, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(flowschemasResource, "status", flowSchema), &v1alpha1.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.FlowSchema), err +} + +// Delete takes name of the flowSchema and deletes it. Returns an error if one occurs. +func (c *FakeFlowSchemas) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(flowschemasResource, name, opts), &v1alpha1.FlowSchema{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeFlowSchemas) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(flowschemasResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.FlowSchemaList{}) + return err +} + +// Patch applies the patch and returns the patched flowSchema. +func (c *FakeFlowSchemas) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.FlowSchema, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(flowschemasResource, name, pt, data, subresources...), &v1alpha1.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.FlowSchema), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied flowSchema. +func (c *FakeFlowSchemas) Apply(ctx context.Context, flowSchema *flowcontrolv1alpha1.FlowSchemaApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.FlowSchema, err error) { + if flowSchema == nil { + return nil, fmt.Errorf("flowSchema provided to Apply must not be nil") + } + data, err := json.Marshal(flowSchema) + if err != nil { + return nil, err + } + name := flowSchema.Name + if name == nil { + return nil, fmt.Errorf("flowSchema.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(flowschemasResource, *name, types.ApplyPatchType, data), &v1alpha1.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.FlowSchema), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeFlowSchemas) ApplyStatus(ctx context.Context, flowSchema *flowcontrolv1alpha1.FlowSchemaApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.FlowSchema, err error) { + if flowSchema == nil { + return nil, fmt.Errorf("flowSchema provided to Apply must not be nil") + } + data, err := json.Marshal(flowSchema) + if err != nil { + return nil, err + } + name := flowSchema.Name + if name == nil { + return nil, fmt.Errorf("flowSchema.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(flowschemasResource, *name, types.ApplyPatchType, data, "status"), &v1alpha1.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.FlowSchema), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1/fake/fake_prioritylevelconfiguration.go b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1/fake/fake_prioritylevelconfiguration.go new file mode 100644 index 000000000..0e7228254 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1/fake/fake_prioritylevelconfiguration.go @@ -0,0 +1,179 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1alpha1 "k8s.io/api/flowcontrol/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + flowcontrolv1alpha1 "k8s.io/client-go/applyconfigurations/flowcontrol/v1alpha1" + testing "k8s.io/client-go/testing" +) + +// FakePriorityLevelConfigurations implements PriorityLevelConfigurationInterface +type FakePriorityLevelConfigurations struct { + Fake *FakeFlowcontrolV1alpha1 +} + +var prioritylevelconfigurationsResource = schema.GroupVersionResource{Group: "flowcontrol.apiserver.k8s.io", Version: "v1alpha1", Resource: "prioritylevelconfigurations"} + +var prioritylevelconfigurationsKind = schema.GroupVersionKind{Group: "flowcontrol.apiserver.k8s.io", Version: "v1alpha1", Kind: "PriorityLevelConfiguration"} + +// Get takes name of the priorityLevelConfiguration, and returns the corresponding priorityLevelConfiguration object, and an error if there is any. +func (c *FakePriorityLevelConfigurations) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.PriorityLevelConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(prioritylevelconfigurationsResource, name), &v1alpha1.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.PriorityLevelConfiguration), err +} + +// List takes label and field selectors, and returns the list of PriorityLevelConfigurations that match those selectors. +func (c *FakePriorityLevelConfigurations) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.PriorityLevelConfigurationList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(prioritylevelconfigurationsResource, prioritylevelconfigurationsKind, opts), &v1alpha1.PriorityLevelConfigurationList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.PriorityLevelConfigurationList{ListMeta: obj.(*v1alpha1.PriorityLevelConfigurationList).ListMeta} + for _, item := range obj.(*v1alpha1.PriorityLevelConfigurationList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested priorityLevelConfigurations. +func (c *FakePriorityLevelConfigurations) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(prioritylevelconfigurationsResource, opts)) +} + +// Create takes the representation of a priorityLevelConfiguration and creates it. Returns the server's representation of the priorityLevelConfiguration, and an error, if there is any. +func (c *FakePriorityLevelConfigurations) Create(ctx context.Context, priorityLevelConfiguration *v1alpha1.PriorityLevelConfiguration, opts v1.CreateOptions) (result *v1alpha1.PriorityLevelConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(prioritylevelconfigurationsResource, priorityLevelConfiguration), &v1alpha1.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.PriorityLevelConfiguration), err +} + +// Update takes the representation of a priorityLevelConfiguration and updates it. Returns the server's representation of the priorityLevelConfiguration, and an error, if there is any. +func (c *FakePriorityLevelConfigurations) Update(ctx context.Context, priorityLevelConfiguration *v1alpha1.PriorityLevelConfiguration, opts v1.UpdateOptions) (result *v1alpha1.PriorityLevelConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(prioritylevelconfigurationsResource, priorityLevelConfiguration), &v1alpha1.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.PriorityLevelConfiguration), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakePriorityLevelConfigurations) UpdateStatus(ctx context.Context, priorityLevelConfiguration *v1alpha1.PriorityLevelConfiguration, opts v1.UpdateOptions) (*v1alpha1.PriorityLevelConfiguration, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(prioritylevelconfigurationsResource, "status", priorityLevelConfiguration), &v1alpha1.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.PriorityLevelConfiguration), err +} + +// Delete takes name of the priorityLevelConfiguration and deletes it. Returns an error if one occurs. +func (c *FakePriorityLevelConfigurations) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(prioritylevelconfigurationsResource, name, opts), &v1alpha1.PriorityLevelConfiguration{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakePriorityLevelConfigurations) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(prioritylevelconfigurationsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.PriorityLevelConfigurationList{}) + return err +} + +// Patch applies the patch and returns the patched priorityLevelConfiguration. +func (c *FakePriorityLevelConfigurations) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.PriorityLevelConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(prioritylevelconfigurationsResource, name, pt, data, subresources...), &v1alpha1.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.PriorityLevelConfiguration), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied priorityLevelConfiguration. +func (c *FakePriorityLevelConfigurations) Apply(ctx context.Context, priorityLevelConfiguration *flowcontrolv1alpha1.PriorityLevelConfigurationApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.PriorityLevelConfiguration, err error) { + if priorityLevelConfiguration == nil { + return nil, fmt.Errorf("priorityLevelConfiguration provided to Apply must not be nil") + } + data, err := json.Marshal(priorityLevelConfiguration) + if err != nil { + return nil, err + } + name := priorityLevelConfiguration.Name + if name == nil { + return nil, fmt.Errorf("priorityLevelConfiguration.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(prioritylevelconfigurationsResource, *name, types.ApplyPatchType, data), &v1alpha1.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.PriorityLevelConfiguration), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakePriorityLevelConfigurations) ApplyStatus(ctx context.Context, priorityLevelConfiguration *flowcontrolv1alpha1.PriorityLevelConfigurationApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.PriorityLevelConfiguration, err error) { + if priorityLevelConfiguration == nil { + return nil, fmt.Errorf("priorityLevelConfiguration provided to Apply must not be nil") + } + data, err := json.Marshal(priorityLevelConfiguration) + if err != nil { + return nil, err + } + name := priorityLevelConfiguration.Name + if name == nil { + return nil, fmt.Errorf("priorityLevelConfiguration.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(prioritylevelconfigurationsResource, *name, types.ApplyPatchType, data, "status"), &v1alpha1.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.PriorityLevelConfiguration), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1/fake/fake_flowcontrol_client.go b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1/fake/fake_flowcontrol_client.go new file mode 100644 index 000000000..1bd58d088 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1/fake/fake_flowcontrol_client.go @@ -0,0 +1,44 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1beta1 "k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeFlowcontrolV1beta1 struct { + *testing.Fake +} + +func (c *FakeFlowcontrolV1beta1) FlowSchemas() v1beta1.FlowSchemaInterface { + return &FakeFlowSchemas{c} +} + +func (c *FakeFlowcontrolV1beta1) PriorityLevelConfigurations() v1beta1.PriorityLevelConfigurationInterface { + return &FakePriorityLevelConfigurations{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeFlowcontrolV1beta1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1/fake/fake_flowschema.go b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1/fake/fake_flowschema.go new file mode 100644 index 000000000..58d5ed14e --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1/fake/fake_flowschema.go @@ -0,0 +1,179 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/flowcontrol/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + flowcontrolv1beta1 "k8s.io/client-go/applyconfigurations/flowcontrol/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeFlowSchemas implements FlowSchemaInterface +type FakeFlowSchemas struct { + Fake *FakeFlowcontrolV1beta1 +} + +var flowschemasResource = schema.GroupVersionResource{Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta1", Resource: "flowschemas"} + +var flowschemasKind = schema.GroupVersionKind{Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta1", Kind: "FlowSchema"} + +// Get takes name of the flowSchema, and returns the corresponding flowSchema object, and an error if there is any. +func (c *FakeFlowSchemas) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.FlowSchema, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(flowschemasResource, name), &v1beta1.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.FlowSchema), err +} + +// List takes label and field selectors, and returns the list of FlowSchemas that match those selectors. +func (c *FakeFlowSchemas) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.FlowSchemaList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(flowschemasResource, flowschemasKind, opts), &v1beta1.FlowSchemaList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.FlowSchemaList{ListMeta: obj.(*v1beta1.FlowSchemaList).ListMeta} + for _, item := range obj.(*v1beta1.FlowSchemaList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested flowSchemas. +func (c *FakeFlowSchemas) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(flowschemasResource, opts)) +} + +// Create takes the representation of a flowSchema and creates it. Returns the server's representation of the flowSchema, and an error, if there is any. +func (c *FakeFlowSchemas) Create(ctx context.Context, flowSchema *v1beta1.FlowSchema, opts v1.CreateOptions) (result *v1beta1.FlowSchema, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(flowschemasResource, flowSchema), &v1beta1.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.FlowSchema), err +} + +// Update takes the representation of a flowSchema and updates it. Returns the server's representation of the flowSchema, and an error, if there is any. +func (c *FakeFlowSchemas) Update(ctx context.Context, flowSchema *v1beta1.FlowSchema, opts v1.UpdateOptions) (result *v1beta1.FlowSchema, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(flowschemasResource, flowSchema), &v1beta1.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.FlowSchema), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeFlowSchemas) UpdateStatus(ctx context.Context, flowSchema *v1beta1.FlowSchema, opts v1.UpdateOptions) (*v1beta1.FlowSchema, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(flowschemasResource, "status", flowSchema), &v1beta1.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.FlowSchema), err +} + +// Delete takes name of the flowSchema and deletes it. Returns an error if one occurs. +func (c *FakeFlowSchemas) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(flowschemasResource, name, opts), &v1beta1.FlowSchema{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeFlowSchemas) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(flowschemasResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.FlowSchemaList{}) + return err +} + +// Patch applies the patch and returns the patched flowSchema. +func (c *FakeFlowSchemas) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.FlowSchema, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(flowschemasResource, name, pt, data, subresources...), &v1beta1.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.FlowSchema), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied flowSchema. +func (c *FakeFlowSchemas) Apply(ctx context.Context, flowSchema *flowcontrolv1beta1.FlowSchemaApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.FlowSchema, err error) { + if flowSchema == nil { + return nil, fmt.Errorf("flowSchema provided to Apply must not be nil") + } + data, err := json.Marshal(flowSchema) + if err != nil { + return nil, err + } + name := flowSchema.Name + if name == nil { + return nil, fmt.Errorf("flowSchema.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(flowschemasResource, *name, types.ApplyPatchType, data), &v1beta1.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.FlowSchema), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeFlowSchemas) ApplyStatus(ctx context.Context, flowSchema *flowcontrolv1beta1.FlowSchemaApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.FlowSchema, err error) { + if flowSchema == nil { + return nil, fmt.Errorf("flowSchema provided to Apply must not be nil") + } + data, err := json.Marshal(flowSchema) + if err != nil { + return nil, err + } + name := flowSchema.Name + if name == nil { + return nil, fmt.Errorf("flowSchema.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(flowschemasResource, *name, types.ApplyPatchType, data, "status"), &v1beta1.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.FlowSchema), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1/fake/fake_prioritylevelconfiguration.go b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1/fake/fake_prioritylevelconfiguration.go new file mode 100644 index 000000000..19fc62beb --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1/fake/fake_prioritylevelconfiguration.go @@ -0,0 +1,179 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/flowcontrol/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + flowcontrolv1beta1 "k8s.io/client-go/applyconfigurations/flowcontrol/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakePriorityLevelConfigurations implements PriorityLevelConfigurationInterface +type FakePriorityLevelConfigurations struct { + Fake *FakeFlowcontrolV1beta1 +} + +var prioritylevelconfigurationsResource = schema.GroupVersionResource{Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta1", Resource: "prioritylevelconfigurations"} + +var prioritylevelconfigurationsKind = schema.GroupVersionKind{Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta1", Kind: "PriorityLevelConfiguration"} + +// Get takes name of the priorityLevelConfiguration, and returns the corresponding priorityLevelConfiguration object, and an error if there is any. +func (c *FakePriorityLevelConfigurations) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.PriorityLevelConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(prioritylevelconfigurationsResource, name), &v1beta1.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PriorityLevelConfiguration), err +} + +// List takes label and field selectors, and returns the list of PriorityLevelConfigurations that match those selectors. +func (c *FakePriorityLevelConfigurations) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.PriorityLevelConfigurationList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(prioritylevelconfigurationsResource, prioritylevelconfigurationsKind, opts), &v1beta1.PriorityLevelConfigurationList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.PriorityLevelConfigurationList{ListMeta: obj.(*v1beta1.PriorityLevelConfigurationList).ListMeta} + for _, item := range obj.(*v1beta1.PriorityLevelConfigurationList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested priorityLevelConfigurations. +func (c *FakePriorityLevelConfigurations) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(prioritylevelconfigurationsResource, opts)) +} + +// Create takes the representation of a priorityLevelConfiguration and creates it. Returns the server's representation of the priorityLevelConfiguration, and an error, if there is any. +func (c *FakePriorityLevelConfigurations) Create(ctx context.Context, priorityLevelConfiguration *v1beta1.PriorityLevelConfiguration, opts v1.CreateOptions) (result *v1beta1.PriorityLevelConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(prioritylevelconfigurationsResource, priorityLevelConfiguration), &v1beta1.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PriorityLevelConfiguration), err +} + +// Update takes the representation of a priorityLevelConfiguration and updates it. Returns the server's representation of the priorityLevelConfiguration, and an error, if there is any. +func (c *FakePriorityLevelConfigurations) Update(ctx context.Context, priorityLevelConfiguration *v1beta1.PriorityLevelConfiguration, opts v1.UpdateOptions) (result *v1beta1.PriorityLevelConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(prioritylevelconfigurationsResource, priorityLevelConfiguration), &v1beta1.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PriorityLevelConfiguration), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakePriorityLevelConfigurations) UpdateStatus(ctx context.Context, priorityLevelConfiguration *v1beta1.PriorityLevelConfiguration, opts v1.UpdateOptions) (*v1beta1.PriorityLevelConfiguration, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(prioritylevelconfigurationsResource, "status", priorityLevelConfiguration), &v1beta1.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PriorityLevelConfiguration), err +} + +// Delete takes name of the priorityLevelConfiguration and deletes it. Returns an error if one occurs. +func (c *FakePriorityLevelConfigurations) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(prioritylevelconfigurationsResource, name, opts), &v1beta1.PriorityLevelConfiguration{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakePriorityLevelConfigurations) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(prioritylevelconfigurationsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.PriorityLevelConfigurationList{}) + return err +} + +// Patch applies the patch and returns the patched priorityLevelConfiguration. +func (c *FakePriorityLevelConfigurations) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.PriorityLevelConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(prioritylevelconfigurationsResource, name, pt, data, subresources...), &v1beta1.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PriorityLevelConfiguration), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied priorityLevelConfiguration. +func (c *FakePriorityLevelConfigurations) Apply(ctx context.Context, priorityLevelConfiguration *flowcontrolv1beta1.PriorityLevelConfigurationApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.PriorityLevelConfiguration, err error) { + if priorityLevelConfiguration == nil { + return nil, fmt.Errorf("priorityLevelConfiguration provided to Apply must not be nil") + } + data, err := json.Marshal(priorityLevelConfiguration) + if err != nil { + return nil, err + } + name := priorityLevelConfiguration.Name + if name == nil { + return nil, fmt.Errorf("priorityLevelConfiguration.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(prioritylevelconfigurationsResource, *name, types.ApplyPatchType, data), &v1beta1.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PriorityLevelConfiguration), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakePriorityLevelConfigurations) ApplyStatus(ctx context.Context, priorityLevelConfiguration *flowcontrolv1beta1.PriorityLevelConfigurationApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.PriorityLevelConfiguration, err error) { + if priorityLevelConfiguration == nil { + return nil, fmt.Errorf("priorityLevelConfiguration provided to Apply must not be nil") + } + data, err := json.Marshal(priorityLevelConfiguration) + if err != nil { + return nil, err + } + name := priorityLevelConfiguration.Name + if name == nil { + return nil, fmt.Errorf("priorityLevelConfiguration.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(prioritylevelconfigurationsResource, *name, types.ApplyPatchType, data, "status"), &v1beta1.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PriorityLevelConfiguration), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2/fake/fake_flowcontrol_client.go b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2/fake/fake_flowcontrol_client.go new file mode 100644 index 000000000..9f36b3b7a --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2/fake/fake_flowcontrol_client.go @@ -0,0 +1,44 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1beta2 "k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeFlowcontrolV1beta2 struct { + *testing.Fake +} + +func (c *FakeFlowcontrolV1beta2) FlowSchemas() v1beta2.FlowSchemaInterface { + return &FakeFlowSchemas{c} +} + +func (c *FakeFlowcontrolV1beta2) PriorityLevelConfigurations() v1beta2.PriorityLevelConfigurationInterface { + return &FakePriorityLevelConfigurations{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeFlowcontrolV1beta2) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2/fake/fake_flowschema.go b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2/fake/fake_flowschema.go new file mode 100644 index 000000000..e4603eba7 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2/fake/fake_flowschema.go @@ -0,0 +1,179 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta2 "k8s.io/api/flowcontrol/v1beta2" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + flowcontrolv1beta2 "k8s.io/client-go/applyconfigurations/flowcontrol/v1beta2" + testing "k8s.io/client-go/testing" +) + +// FakeFlowSchemas implements FlowSchemaInterface +type FakeFlowSchemas struct { + Fake *FakeFlowcontrolV1beta2 +} + +var flowschemasResource = schema.GroupVersionResource{Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta2", Resource: "flowschemas"} + +var flowschemasKind = schema.GroupVersionKind{Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta2", Kind: "FlowSchema"} + +// Get takes name of the flowSchema, and returns the corresponding flowSchema object, and an error if there is any. +func (c *FakeFlowSchemas) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta2.FlowSchema, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(flowschemasResource, name), &v1beta2.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta2.FlowSchema), err +} + +// List takes label and field selectors, and returns the list of FlowSchemas that match those selectors. +func (c *FakeFlowSchemas) List(ctx context.Context, opts v1.ListOptions) (result *v1beta2.FlowSchemaList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(flowschemasResource, flowschemasKind, opts), &v1beta2.FlowSchemaList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta2.FlowSchemaList{ListMeta: obj.(*v1beta2.FlowSchemaList).ListMeta} + for _, item := range obj.(*v1beta2.FlowSchemaList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested flowSchemas. +func (c *FakeFlowSchemas) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(flowschemasResource, opts)) +} + +// Create takes the representation of a flowSchema and creates it. Returns the server's representation of the flowSchema, and an error, if there is any. +func (c *FakeFlowSchemas) Create(ctx context.Context, flowSchema *v1beta2.FlowSchema, opts v1.CreateOptions) (result *v1beta2.FlowSchema, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(flowschemasResource, flowSchema), &v1beta2.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta2.FlowSchema), err +} + +// Update takes the representation of a flowSchema and updates it. Returns the server's representation of the flowSchema, and an error, if there is any. +func (c *FakeFlowSchemas) Update(ctx context.Context, flowSchema *v1beta2.FlowSchema, opts v1.UpdateOptions) (result *v1beta2.FlowSchema, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(flowschemasResource, flowSchema), &v1beta2.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta2.FlowSchema), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeFlowSchemas) UpdateStatus(ctx context.Context, flowSchema *v1beta2.FlowSchema, opts v1.UpdateOptions) (*v1beta2.FlowSchema, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(flowschemasResource, "status", flowSchema), &v1beta2.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta2.FlowSchema), err +} + +// Delete takes name of the flowSchema and deletes it. Returns an error if one occurs. +func (c *FakeFlowSchemas) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(flowschemasResource, name, opts), &v1beta2.FlowSchema{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeFlowSchemas) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(flowschemasResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta2.FlowSchemaList{}) + return err +} + +// Patch applies the patch and returns the patched flowSchema. +func (c *FakeFlowSchemas) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta2.FlowSchema, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(flowschemasResource, name, pt, data, subresources...), &v1beta2.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta2.FlowSchema), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied flowSchema. +func (c *FakeFlowSchemas) Apply(ctx context.Context, flowSchema *flowcontrolv1beta2.FlowSchemaApplyConfiguration, opts v1.ApplyOptions) (result *v1beta2.FlowSchema, err error) { + if flowSchema == nil { + return nil, fmt.Errorf("flowSchema provided to Apply must not be nil") + } + data, err := json.Marshal(flowSchema) + if err != nil { + return nil, err + } + name := flowSchema.Name + if name == nil { + return nil, fmt.Errorf("flowSchema.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(flowschemasResource, *name, types.ApplyPatchType, data), &v1beta2.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta2.FlowSchema), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeFlowSchemas) ApplyStatus(ctx context.Context, flowSchema *flowcontrolv1beta2.FlowSchemaApplyConfiguration, opts v1.ApplyOptions) (result *v1beta2.FlowSchema, err error) { + if flowSchema == nil { + return nil, fmt.Errorf("flowSchema provided to Apply must not be nil") + } + data, err := json.Marshal(flowSchema) + if err != nil { + return nil, err + } + name := flowSchema.Name + if name == nil { + return nil, fmt.Errorf("flowSchema.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(flowschemasResource, *name, types.ApplyPatchType, data, "status"), &v1beta2.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta2.FlowSchema), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2/fake/fake_prioritylevelconfiguration.go b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2/fake/fake_prioritylevelconfiguration.go new file mode 100644 index 000000000..e1979d075 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2/fake/fake_prioritylevelconfiguration.go @@ -0,0 +1,179 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta2 "k8s.io/api/flowcontrol/v1beta2" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + flowcontrolv1beta2 "k8s.io/client-go/applyconfigurations/flowcontrol/v1beta2" + testing "k8s.io/client-go/testing" +) + +// FakePriorityLevelConfigurations implements PriorityLevelConfigurationInterface +type FakePriorityLevelConfigurations struct { + Fake *FakeFlowcontrolV1beta2 +} + +var prioritylevelconfigurationsResource = schema.GroupVersionResource{Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta2", Resource: "prioritylevelconfigurations"} + +var prioritylevelconfigurationsKind = schema.GroupVersionKind{Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta2", Kind: "PriorityLevelConfiguration"} + +// Get takes name of the priorityLevelConfiguration, and returns the corresponding priorityLevelConfiguration object, and an error if there is any. +func (c *FakePriorityLevelConfigurations) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta2.PriorityLevelConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(prioritylevelconfigurationsResource, name), &v1beta2.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta2.PriorityLevelConfiguration), err +} + +// List takes label and field selectors, and returns the list of PriorityLevelConfigurations that match those selectors. +func (c *FakePriorityLevelConfigurations) List(ctx context.Context, opts v1.ListOptions) (result *v1beta2.PriorityLevelConfigurationList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(prioritylevelconfigurationsResource, prioritylevelconfigurationsKind, opts), &v1beta2.PriorityLevelConfigurationList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta2.PriorityLevelConfigurationList{ListMeta: obj.(*v1beta2.PriorityLevelConfigurationList).ListMeta} + for _, item := range obj.(*v1beta2.PriorityLevelConfigurationList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested priorityLevelConfigurations. +func (c *FakePriorityLevelConfigurations) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(prioritylevelconfigurationsResource, opts)) +} + +// Create takes the representation of a priorityLevelConfiguration and creates it. Returns the server's representation of the priorityLevelConfiguration, and an error, if there is any. +func (c *FakePriorityLevelConfigurations) Create(ctx context.Context, priorityLevelConfiguration *v1beta2.PriorityLevelConfiguration, opts v1.CreateOptions) (result *v1beta2.PriorityLevelConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(prioritylevelconfigurationsResource, priorityLevelConfiguration), &v1beta2.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta2.PriorityLevelConfiguration), err +} + +// Update takes the representation of a priorityLevelConfiguration and updates it. Returns the server's representation of the priorityLevelConfiguration, and an error, if there is any. +func (c *FakePriorityLevelConfigurations) Update(ctx context.Context, priorityLevelConfiguration *v1beta2.PriorityLevelConfiguration, opts v1.UpdateOptions) (result *v1beta2.PriorityLevelConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(prioritylevelconfigurationsResource, priorityLevelConfiguration), &v1beta2.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta2.PriorityLevelConfiguration), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakePriorityLevelConfigurations) UpdateStatus(ctx context.Context, priorityLevelConfiguration *v1beta2.PriorityLevelConfiguration, opts v1.UpdateOptions) (*v1beta2.PriorityLevelConfiguration, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(prioritylevelconfigurationsResource, "status", priorityLevelConfiguration), &v1beta2.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta2.PriorityLevelConfiguration), err +} + +// Delete takes name of the priorityLevelConfiguration and deletes it. Returns an error if one occurs. +func (c *FakePriorityLevelConfigurations) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(prioritylevelconfigurationsResource, name, opts), &v1beta2.PriorityLevelConfiguration{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakePriorityLevelConfigurations) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(prioritylevelconfigurationsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta2.PriorityLevelConfigurationList{}) + return err +} + +// Patch applies the patch and returns the patched priorityLevelConfiguration. +func (c *FakePriorityLevelConfigurations) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta2.PriorityLevelConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(prioritylevelconfigurationsResource, name, pt, data, subresources...), &v1beta2.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta2.PriorityLevelConfiguration), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied priorityLevelConfiguration. +func (c *FakePriorityLevelConfigurations) Apply(ctx context.Context, priorityLevelConfiguration *flowcontrolv1beta2.PriorityLevelConfigurationApplyConfiguration, opts v1.ApplyOptions) (result *v1beta2.PriorityLevelConfiguration, err error) { + if priorityLevelConfiguration == nil { + return nil, fmt.Errorf("priorityLevelConfiguration provided to Apply must not be nil") + } + data, err := json.Marshal(priorityLevelConfiguration) + if err != nil { + return nil, err + } + name := priorityLevelConfiguration.Name + if name == nil { + return nil, fmt.Errorf("priorityLevelConfiguration.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(prioritylevelconfigurationsResource, *name, types.ApplyPatchType, data), &v1beta2.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta2.PriorityLevelConfiguration), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakePriorityLevelConfigurations) ApplyStatus(ctx context.Context, priorityLevelConfiguration *flowcontrolv1beta2.PriorityLevelConfigurationApplyConfiguration, opts v1.ApplyOptions) (result *v1beta2.PriorityLevelConfiguration, err error) { + if priorityLevelConfiguration == nil { + return nil, fmt.Errorf("priorityLevelConfiguration provided to Apply must not be nil") + } + data, err := json.Marshal(priorityLevelConfiguration) + if err != nil { + return nil, err + } + name := priorityLevelConfiguration.Name + if name == nil { + return nil, fmt.Errorf("priorityLevelConfiguration.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(prioritylevelconfigurationsResource, *name, types.ApplyPatchType, data, "status"), &v1beta2.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta2.PriorityLevelConfiguration), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3/fake/fake_flowcontrol_client.go b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3/fake/fake_flowcontrol_client.go new file mode 100644 index 000000000..1cb0198d0 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3/fake/fake_flowcontrol_client.go @@ -0,0 +1,44 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1beta3 "k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeFlowcontrolV1beta3 struct { + *testing.Fake +} + +func (c *FakeFlowcontrolV1beta3) FlowSchemas() v1beta3.FlowSchemaInterface { + return &FakeFlowSchemas{c} +} + +func (c *FakeFlowcontrolV1beta3) PriorityLevelConfigurations() v1beta3.PriorityLevelConfigurationInterface { + return &FakePriorityLevelConfigurations{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeFlowcontrolV1beta3) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3/fake/fake_flowschema.go b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3/fake/fake_flowschema.go new file mode 100644 index 000000000..d6a8bdc32 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3/fake/fake_flowschema.go @@ -0,0 +1,179 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta3 "k8s.io/api/flowcontrol/v1beta3" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + flowcontrolv1beta3 "k8s.io/client-go/applyconfigurations/flowcontrol/v1beta3" + testing "k8s.io/client-go/testing" +) + +// FakeFlowSchemas implements FlowSchemaInterface +type FakeFlowSchemas struct { + Fake *FakeFlowcontrolV1beta3 +} + +var flowschemasResource = schema.GroupVersionResource{Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta3", Resource: "flowschemas"} + +var flowschemasKind = schema.GroupVersionKind{Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta3", Kind: "FlowSchema"} + +// Get takes name of the flowSchema, and returns the corresponding flowSchema object, and an error if there is any. +func (c *FakeFlowSchemas) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta3.FlowSchema, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(flowschemasResource, name), &v1beta3.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta3.FlowSchema), err +} + +// List takes label and field selectors, and returns the list of FlowSchemas that match those selectors. +func (c *FakeFlowSchemas) List(ctx context.Context, opts v1.ListOptions) (result *v1beta3.FlowSchemaList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(flowschemasResource, flowschemasKind, opts), &v1beta3.FlowSchemaList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta3.FlowSchemaList{ListMeta: obj.(*v1beta3.FlowSchemaList).ListMeta} + for _, item := range obj.(*v1beta3.FlowSchemaList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested flowSchemas. +func (c *FakeFlowSchemas) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(flowschemasResource, opts)) +} + +// Create takes the representation of a flowSchema and creates it. Returns the server's representation of the flowSchema, and an error, if there is any. +func (c *FakeFlowSchemas) Create(ctx context.Context, flowSchema *v1beta3.FlowSchema, opts v1.CreateOptions) (result *v1beta3.FlowSchema, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(flowschemasResource, flowSchema), &v1beta3.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta3.FlowSchema), err +} + +// Update takes the representation of a flowSchema and updates it. Returns the server's representation of the flowSchema, and an error, if there is any. +func (c *FakeFlowSchemas) Update(ctx context.Context, flowSchema *v1beta3.FlowSchema, opts v1.UpdateOptions) (result *v1beta3.FlowSchema, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(flowschemasResource, flowSchema), &v1beta3.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta3.FlowSchema), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeFlowSchemas) UpdateStatus(ctx context.Context, flowSchema *v1beta3.FlowSchema, opts v1.UpdateOptions) (*v1beta3.FlowSchema, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(flowschemasResource, "status", flowSchema), &v1beta3.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta3.FlowSchema), err +} + +// Delete takes name of the flowSchema and deletes it. Returns an error if one occurs. +func (c *FakeFlowSchemas) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(flowschemasResource, name, opts), &v1beta3.FlowSchema{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeFlowSchemas) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(flowschemasResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta3.FlowSchemaList{}) + return err +} + +// Patch applies the patch and returns the patched flowSchema. +func (c *FakeFlowSchemas) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta3.FlowSchema, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(flowschemasResource, name, pt, data, subresources...), &v1beta3.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta3.FlowSchema), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied flowSchema. +func (c *FakeFlowSchemas) Apply(ctx context.Context, flowSchema *flowcontrolv1beta3.FlowSchemaApplyConfiguration, opts v1.ApplyOptions) (result *v1beta3.FlowSchema, err error) { + if flowSchema == nil { + return nil, fmt.Errorf("flowSchema provided to Apply must not be nil") + } + data, err := json.Marshal(flowSchema) + if err != nil { + return nil, err + } + name := flowSchema.Name + if name == nil { + return nil, fmt.Errorf("flowSchema.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(flowschemasResource, *name, types.ApplyPatchType, data), &v1beta3.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta3.FlowSchema), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeFlowSchemas) ApplyStatus(ctx context.Context, flowSchema *flowcontrolv1beta3.FlowSchemaApplyConfiguration, opts v1.ApplyOptions) (result *v1beta3.FlowSchema, err error) { + if flowSchema == nil { + return nil, fmt.Errorf("flowSchema provided to Apply must not be nil") + } + data, err := json.Marshal(flowSchema) + if err != nil { + return nil, err + } + name := flowSchema.Name + if name == nil { + return nil, fmt.Errorf("flowSchema.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(flowschemasResource, *name, types.ApplyPatchType, data, "status"), &v1beta3.FlowSchema{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta3.FlowSchema), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3/fake/fake_prioritylevelconfiguration.go b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3/fake/fake_prioritylevelconfiguration.go new file mode 100644 index 000000000..5fbc57da7 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3/fake/fake_prioritylevelconfiguration.go @@ -0,0 +1,179 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta3 "k8s.io/api/flowcontrol/v1beta3" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + flowcontrolv1beta3 "k8s.io/client-go/applyconfigurations/flowcontrol/v1beta3" + testing "k8s.io/client-go/testing" +) + +// FakePriorityLevelConfigurations implements PriorityLevelConfigurationInterface +type FakePriorityLevelConfigurations struct { + Fake *FakeFlowcontrolV1beta3 +} + +var prioritylevelconfigurationsResource = schema.GroupVersionResource{Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta3", Resource: "prioritylevelconfigurations"} + +var prioritylevelconfigurationsKind = schema.GroupVersionKind{Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta3", Kind: "PriorityLevelConfiguration"} + +// Get takes name of the priorityLevelConfiguration, and returns the corresponding priorityLevelConfiguration object, and an error if there is any. +func (c *FakePriorityLevelConfigurations) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta3.PriorityLevelConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(prioritylevelconfigurationsResource, name), &v1beta3.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta3.PriorityLevelConfiguration), err +} + +// List takes label and field selectors, and returns the list of PriorityLevelConfigurations that match those selectors. +func (c *FakePriorityLevelConfigurations) List(ctx context.Context, opts v1.ListOptions) (result *v1beta3.PriorityLevelConfigurationList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(prioritylevelconfigurationsResource, prioritylevelconfigurationsKind, opts), &v1beta3.PriorityLevelConfigurationList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta3.PriorityLevelConfigurationList{ListMeta: obj.(*v1beta3.PriorityLevelConfigurationList).ListMeta} + for _, item := range obj.(*v1beta3.PriorityLevelConfigurationList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested priorityLevelConfigurations. +func (c *FakePriorityLevelConfigurations) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(prioritylevelconfigurationsResource, opts)) +} + +// Create takes the representation of a priorityLevelConfiguration and creates it. Returns the server's representation of the priorityLevelConfiguration, and an error, if there is any. +func (c *FakePriorityLevelConfigurations) Create(ctx context.Context, priorityLevelConfiguration *v1beta3.PriorityLevelConfiguration, opts v1.CreateOptions) (result *v1beta3.PriorityLevelConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(prioritylevelconfigurationsResource, priorityLevelConfiguration), &v1beta3.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta3.PriorityLevelConfiguration), err +} + +// Update takes the representation of a priorityLevelConfiguration and updates it. Returns the server's representation of the priorityLevelConfiguration, and an error, if there is any. +func (c *FakePriorityLevelConfigurations) Update(ctx context.Context, priorityLevelConfiguration *v1beta3.PriorityLevelConfiguration, opts v1.UpdateOptions) (result *v1beta3.PriorityLevelConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(prioritylevelconfigurationsResource, priorityLevelConfiguration), &v1beta3.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta3.PriorityLevelConfiguration), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakePriorityLevelConfigurations) UpdateStatus(ctx context.Context, priorityLevelConfiguration *v1beta3.PriorityLevelConfiguration, opts v1.UpdateOptions) (*v1beta3.PriorityLevelConfiguration, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(prioritylevelconfigurationsResource, "status", priorityLevelConfiguration), &v1beta3.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta3.PriorityLevelConfiguration), err +} + +// Delete takes name of the priorityLevelConfiguration and deletes it. Returns an error if one occurs. +func (c *FakePriorityLevelConfigurations) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(prioritylevelconfigurationsResource, name, opts), &v1beta3.PriorityLevelConfiguration{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakePriorityLevelConfigurations) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(prioritylevelconfigurationsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta3.PriorityLevelConfigurationList{}) + return err +} + +// Patch applies the patch and returns the patched priorityLevelConfiguration. +func (c *FakePriorityLevelConfigurations) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta3.PriorityLevelConfiguration, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(prioritylevelconfigurationsResource, name, pt, data, subresources...), &v1beta3.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta3.PriorityLevelConfiguration), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied priorityLevelConfiguration. +func (c *FakePriorityLevelConfigurations) Apply(ctx context.Context, priorityLevelConfiguration *flowcontrolv1beta3.PriorityLevelConfigurationApplyConfiguration, opts v1.ApplyOptions) (result *v1beta3.PriorityLevelConfiguration, err error) { + if priorityLevelConfiguration == nil { + return nil, fmt.Errorf("priorityLevelConfiguration provided to Apply must not be nil") + } + data, err := json.Marshal(priorityLevelConfiguration) + if err != nil { + return nil, err + } + name := priorityLevelConfiguration.Name + if name == nil { + return nil, fmt.Errorf("priorityLevelConfiguration.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(prioritylevelconfigurationsResource, *name, types.ApplyPatchType, data), &v1beta3.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta3.PriorityLevelConfiguration), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakePriorityLevelConfigurations) ApplyStatus(ctx context.Context, priorityLevelConfiguration *flowcontrolv1beta3.PriorityLevelConfigurationApplyConfiguration, opts v1.ApplyOptions) (result *v1beta3.PriorityLevelConfiguration, err error) { + if priorityLevelConfiguration == nil { + return nil, fmt.Errorf("priorityLevelConfiguration provided to Apply must not be nil") + } + data, err := json.Marshal(priorityLevelConfiguration) + if err != nil { + return nil, err + } + name := priorityLevelConfiguration.Name + if name == nil { + return nil, fmt.Errorf("priorityLevelConfiguration.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(prioritylevelconfigurationsResource, *name, types.ApplyPatchType, data, "status"), &v1beta3.PriorityLevelConfiguration{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta3.PriorityLevelConfiguration), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/networking/v1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/networking/v1/fake/fake_ingress.go b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1/fake/fake_ingress.go new file mode 100644 index 000000000..8ffcd7f97 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1/fake/fake_ingress.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + networkingv1 "k8s.io/api/networking/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsnetworkingv1 "k8s.io/client-go/applyconfigurations/networking/v1" + testing "k8s.io/client-go/testing" +) + +// FakeIngresses implements IngressInterface +type FakeIngresses struct { + Fake *FakeNetworkingV1 + ns string +} + +var ingressesResource = schema.GroupVersionResource{Group: "networking.k8s.io", Version: "v1", Resource: "ingresses"} + +var ingressesKind = schema.GroupVersionKind{Group: "networking.k8s.io", Version: "v1", Kind: "Ingress"} + +// Get takes name of the ingress, and returns the corresponding ingress object, and an error if there is any. +func (c *FakeIngresses) Get(ctx context.Context, name string, options v1.GetOptions) (result *networkingv1.Ingress, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(ingressesResource, c.ns, name), &networkingv1.Ingress{}) + + if obj == nil { + return nil, err + } + return obj.(*networkingv1.Ingress), err +} + +// List takes label and field selectors, and returns the list of Ingresses that match those selectors. +func (c *FakeIngresses) List(ctx context.Context, opts v1.ListOptions) (result *networkingv1.IngressList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(ingressesResource, ingressesKind, c.ns, opts), &networkingv1.IngressList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &networkingv1.IngressList{ListMeta: obj.(*networkingv1.IngressList).ListMeta} + for _, item := range obj.(*networkingv1.IngressList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested ingresses. +func (c *FakeIngresses) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(ingressesResource, c.ns, opts)) + +} + +// Create takes the representation of a ingress and creates it. Returns the server's representation of the ingress, and an error, if there is any. +func (c *FakeIngresses) Create(ctx context.Context, ingress *networkingv1.Ingress, opts v1.CreateOptions) (result *networkingv1.Ingress, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(ingressesResource, c.ns, ingress), &networkingv1.Ingress{}) + + if obj == nil { + return nil, err + } + return obj.(*networkingv1.Ingress), err +} + +// Update takes the representation of a ingress and updates it. Returns the server's representation of the ingress, and an error, if there is any. +func (c *FakeIngresses) Update(ctx context.Context, ingress *networkingv1.Ingress, opts v1.UpdateOptions) (result *networkingv1.Ingress, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(ingressesResource, c.ns, ingress), &networkingv1.Ingress{}) + + if obj == nil { + return nil, err + } + return obj.(*networkingv1.Ingress), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeIngresses) UpdateStatus(ctx context.Context, ingress *networkingv1.Ingress, opts v1.UpdateOptions) (*networkingv1.Ingress, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(ingressesResource, "status", c.ns, ingress), &networkingv1.Ingress{}) + + if obj == nil { + return nil, err + } + return obj.(*networkingv1.Ingress), err +} + +// Delete takes name of the ingress and deletes it. Returns an error if one occurs. +func (c *FakeIngresses) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(ingressesResource, c.ns, name, opts), &networkingv1.Ingress{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeIngresses) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(ingressesResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &networkingv1.IngressList{}) + return err +} + +// Patch applies the patch and returns the patched ingress. +func (c *FakeIngresses) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *networkingv1.Ingress, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(ingressesResource, c.ns, name, pt, data, subresources...), &networkingv1.Ingress{}) + + if obj == nil { + return nil, err + } + return obj.(*networkingv1.Ingress), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied ingress. +func (c *FakeIngresses) Apply(ctx context.Context, ingress *applyconfigurationsnetworkingv1.IngressApplyConfiguration, opts v1.ApplyOptions) (result *networkingv1.Ingress, err error) { + if ingress == nil { + return nil, fmt.Errorf("ingress provided to Apply must not be nil") + } + data, err := json.Marshal(ingress) + if err != nil { + return nil, err + } + name := ingress.Name + if name == nil { + return nil, fmt.Errorf("ingress.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(ingressesResource, c.ns, *name, types.ApplyPatchType, data), &networkingv1.Ingress{}) + + if obj == nil { + return nil, err + } + return obj.(*networkingv1.Ingress), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeIngresses) ApplyStatus(ctx context.Context, ingress *applyconfigurationsnetworkingv1.IngressApplyConfiguration, opts v1.ApplyOptions) (result *networkingv1.Ingress, err error) { + if ingress == nil { + return nil, fmt.Errorf("ingress provided to Apply must not be nil") + } + data, err := json.Marshal(ingress) + if err != nil { + return nil, err + } + name := ingress.Name + if name == nil { + return nil, fmt.Errorf("ingress.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(ingressesResource, c.ns, *name, types.ApplyPatchType, data, "status"), &networkingv1.Ingress{}) + + if obj == nil { + return nil, err + } + return obj.(*networkingv1.Ingress), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/networking/v1/fake/fake_ingressclass.go b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1/fake/fake_ingressclass.go new file mode 100644 index 000000000..fe320c4b7 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1/fake/fake_ingressclass.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + networkingv1 "k8s.io/api/networking/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsnetworkingv1 "k8s.io/client-go/applyconfigurations/networking/v1" + testing "k8s.io/client-go/testing" +) + +// FakeIngressClasses implements IngressClassInterface +type FakeIngressClasses struct { + Fake *FakeNetworkingV1 +} + +var ingressclassesResource = schema.GroupVersionResource{Group: "networking.k8s.io", Version: "v1", Resource: "ingressclasses"} + +var ingressclassesKind = schema.GroupVersionKind{Group: "networking.k8s.io", Version: "v1", Kind: "IngressClass"} + +// Get takes name of the ingressClass, and returns the corresponding ingressClass object, and an error if there is any. +func (c *FakeIngressClasses) Get(ctx context.Context, name string, options v1.GetOptions) (result *networkingv1.IngressClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(ingressclassesResource, name), &networkingv1.IngressClass{}) + if obj == nil { + return nil, err + } + return obj.(*networkingv1.IngressClass), err +} + +// List takes label and field selectors, and returns the list of IngressClasses that match those selectors. +func (c *FakeIngressClasses) List(ctx context.Context, opts v1.ListOptions) (result *networkingv1.IngressClassList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(ingressclassesResource, ingressclassesKind, opts), &networkingv1.IngressClassList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &networkingv1.IngressClassList{ListMeta: obj.(*networkingv1.IngressClassList).ListMeta} + for _, item := range obj.(*networkingv1.IngressClassList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested ingressClasses. +func (c *FakeIngressClasses) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(ingressclassesResource, opts)) +} + +// Create takes the representation of a ingressClass and creates it. Returns the server's representation of the ingressClass, and an error, if there is any. +func (c *FakeIngressClasses) Create(ctx context.Context, ingressClass *networkingv1.IngressClass, opts v1.CreateOptions) (result *networkingv1.IngressClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(ingressclassesResource, ingressClass), &networkingv1.IngressClass{}) + if obj == nil { + return nil, err + } + return obj.(*networkingv1.IngressClass), err +} + +// Update takes the representation of a ingressClass and updates it. Returns the server's representation of the ingressClass, and an error, if there is any. +func (c *FakeIngressClasses) Update(ctx context.Context, ingressClass *networkingv1.IngressClass, opts v1.UpdateOptions) (result *networkingv1.IngressClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(ingressclassesResource, ingressClass), &networkingv1.IngressClass{}) + if obj == nil { + return nil, err + } + return obj.(*networkingv1.IngressClass), err +} + +// Delete takes name of the ingressClass and deletes it. Returns an error if one occurs. +func (c *FakeIngressClasses) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(ingressclassesResource, name, opts), &networkingv1.IngressClass{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeIngressClasses) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(ingressclassesResource, listOpts) + + _, err := c.Fake.Invokes(action, &networkingv1.IngressClassList{}) + return err +} + +// Patch applies the patch and returns the patched ingressClass. +func (c *FakeIngressClasses) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *networkingv1.IngressClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(ingressclassesResource, name, pt, data, subresources...), &networkingv1.IngressClass{}) + if obj == nil { + return nil, err + } + return obj.(*networkingv1.IngressClass), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied ingressClass. +func (c *FakeIngressClasses) Apply(ctx context.Context, ingressClass *applyconfigurationsnetworkingv1.IngressClassApplyConfiguration, opts v1.ApplyOptions) (result *networkingv1.IngressClass, err error) { + if ingressClass == nil { + return nil, fmt.Errorf("ingressClass provided to Apply must not be nil") + } + data, err := json.Marshal(ingressClass) + if err != nil { + return nil, err + } + name := ingressClass.Name + if name == nil { + return nil, fmt.Errorf("ingressClass.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(ingressclassesResource, *name, types.ApplyPatchType, data), &networkingv1.IngressClass{}) + if obj == nil { + return nil, err + } + return obj.(*networkingv1.IngressClass), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/networking/v1/fake/fake_networking_client.go b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1/fake/fake_networking_client.go new file mode 100644 index 000000000..ed1639e2f --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1/fake/fake_networking_client.go @@ -0,0 +1,48 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/client-go/kubernetes/typed/networking/v1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeNetworkingV1 struct { + *testing.Fake +} + +func (c *FakeNetworkingV1) Ingresses(namespace string) v1.IngressInterface { + return &FakeIngresses{c, namespace} +} + +func (c *FakeNetworkingV1) IngressClasses() v1.IngressClassInterface { + return &FakeIngressClasses{c} +} + +func (c *FakeNetworkingV1) NetworkPolicies(namespace string) v1.NetworkPolicyInterface { + return &FakeNetworkPolicies{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeNetworkingV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/networking/v1/fake/fake_networkpolicy.go b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1/fake/fake_networkpolicy.go new file mode 100644 index 000000000..16c10cac0 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1/fake/fake_networkpolicy.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + networkingv1 "k8s.io/api/networking/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsnetworkingv1 "k8s.io/client-go/applyconfigurations/networking/v1" + testing "k8s.io/client-go/testing" +) + +// FakeNetworkPolicies implements NetworkPolicyInterface +type FakeNetworkPolicies struct { + Fake *FakeNetworkingV1 + ns string +} + +var networkpoliciesResource = schema.GroupVersionResource{Group: "networking.k8s.io", Version: "v1", Resource: "networkpolicies"} + +var networkpoliciesKind = schema.GroupVersionKind{Group: "networking.k8s.io", Version: "v1", Kind: "NetworkPolicy"} + +// Get takes name of the networkPolicy, and returns the corresponding networkPolicy object, and an error if there is any. +func (c *FakeNetworkPolicies) Get(ctx context.Context, name string, options v1.GetOptions) (result *networkingv1.NetworkPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(networkpoliciesResource, c.ns, name), &networkingv1.NetworkPolicy{}) + + if obj == nil { + return nil, err + } + return obj.(*networkingv1.NetworkPolicy), err +} + +// List takes label and field selectors, and returns the list of NetworkPolicies that match those selectors. +func (c *FakeNetworkPolicies) List(ctx context.Context, opts v1.ListOptions) (result *networkingv1.NetworkPolicyList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(networkpoliciesResource, networkpoliciesKind, c.ns, opts), &networkingv1.NetworkPolicyList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &networkingv1.NetworkPolicyList{ListMeta: obj.(*networkingv1.NetworkPolicyList).ListMeta} + for _, item := range obj.(*networkingv1.NetworkPolicyList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested networkPolicies. +func (c *FakeNetworkPolicies) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(networkpoliciesResource, c.ns, opts)) + +} + +// Create takes the representation of a networkPolicy and creates it. Returns the server's representation of the networkPolicy, and an error, if there is any. +func (c *FakeNetworkPolicies) Create(ctx context.Context, networkPolicy *networkingv1.NetworkPolicy, opts v1.CreateOptions) (result *networkingv1.NetworkPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(networkpoliciesResource, c.ns, networkPolicy), &networkingv1.NetworkPolicy{}) + + if obj == nil { + return nil, err + } + return obj.(*networkingv1.NetworkPolicy), err +} + +// Update takes the representation of a networkPolicy and updates it. Returns the server's representation of the networkPolicy, and an error, if there is any. +func (c *FakeNetworkPolicies) Update(ctx context.Context, networkPolicy *networkingv1.NetworkPolicy, opts v1.UpdateOptions) (result *networkingv1.NetworkPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(networkpoliciesResource, c.ns, networkPolicy), &networkingv1.NetworkPolicy{}) + + if obj == nil { + return nil, err + } + return obj.(*networkingv1.NetworkPolicy), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeNetworkPolicies) UpdateStatus(ctx context.Context, networkPolicy *networkingv1.NetworkPolicy, opts v1.UpdateOptions) (*networkingv1.NetworkPolicy, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(networkpoliciesResource, "status", c.ns, networkPolicy), &networkingv1.NetworkPolicy{}) + + if obj == nil { + return nil, err + } + return obj.(*networkingv1.NetworkPolicy), err +} + +// Delete takes name of the networkPolicy and deletes it. Returns an error if one occurs. +func (c *FakeNetworkPolicies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(networkpoliciesResource, c.ns, name, opts), &networkingv1.NetworkPolicy{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeNetworkPolicies) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(networkpoliciesResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &networkingv1.NetworkPolicyList{}) + return err +} + +// Patch applies the patch and returns the patched networkPolicy. +func (c *FakeNetworkPolicies) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *networkingv1.NetworkPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(networkpoliciesResource, c.ns, name, pt, data, subresources...), &networkingv1.NetworkPolicy{}) + + if obj == nil { + return nil, err + } + return obj.(*networkingv1.NetworkPolicy), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied networkPolicy. +func (c *FakeNetworkPolicies) Apply(ctx context.Context, networkPolicy *applyconfigurationsnetworkingv1.NetworkPolicyApplyConfiguration, opts v1.ApplyOptions) (result *networkingv1.NetworkPolicy, err error) { + if networkPolicy == nil { + return nil, fmt.Errorf("networkPolicy provided to Apply must not be nil") + } + data, err := json.Marshal(networkPolicy) + if err != nil { + return nil, err + } + name := networkPolicy.Name + if name == nil { + return nil, fmt.Errorf("networkPolicy.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(networkpoliciesResource, c.ns, *name, types.ApplyPatchType, data), &networkingv1.NetworkPolicy{}) + + if obj == nil { + return nil, err + } + return obj.(*networkingv1.NetworkPolicy), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeNetworkPolicies) ApplyStatus(ctx context.Context, networkPolicy *applyconfigurationsnetworkingv1.NetworkPolicyApplyConfiguration, opts v1.ApplyOptions) (result *networkingv1.NetworkPolicy, err error) { + if networkPolicy == nil { + return nil, fmt.Errorf("networkPolicy provided to Apply must not be nil") + } + data, err := json.Marshal(networkPolicy) + if err != nil { + return nil, err + } + name := networkPolicy.Name + if name == nil { + return nil, fmt.Errorf("networkPolicy.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(networkpoliciesResource, c.ns, *name, types.ApplyPatchType, data, "status"), &networkingv1.NetworkPolicy{}) + + if obj == nil { + return nil, err + } + return obj.(*networkingv1.NetworkPolicy), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/networking/v1alpha1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1alpha1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1alpha1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/networking/v1alpha1/fake/fake_clustercidr.go b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1alpha1/fake/fake_clustercidr.go new file mode 100644 index 000000000..ca0352d39 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1alpha1/fake/fake_clustercidr.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1alpha1 "k8s.io/api/networking/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + networkingv1alpha1 "k8s.io/client-go/applyconfigurations/networking/v1alpha1" + testing "k8s.io/client-go/testing" +) + +// FakeClusterCIDRs implements ClusterCIDRInterface +type FakeClusterCIDRs struct { + Fake *FakeNetworkingV1alpha1 +} + +var clustercidrsResource = schema.GroupVersionResource{Group: "networking.k8s.io", Version: "v1alpha1", Resource: "clustercidrs"} + +var clustercidrsKind = schema.GroupVersionKind{Group: "networking.k8s.io", Version: "v1alpha1", Kind: "ClusterCIDR"} + +// Get takes name of the clusterCIDR, and returns the corresponding clusterCIDR object, and an error if there is any. +func (c *FakeClusterCIDRs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ClusterCIDR, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(clustercidrsResource, name), &v1alpha1.ClusterCIDR{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterCIDR), err +} + +// List takes label and field selectors, and returns the list of ClusterCIDRs that match those selectors. +func (c *FakeClusterCIDRs) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ClusterCIDRList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(clustercidrsResource, clustercidrsKind, opts), &v1alpha1.ClusterCIDRList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.ClusterCIDRList{ListMeta: obj.(*v1alpha1.ClusterCIDRList).ListMeta} + for _, item := range obj.(*v1alpha1.ClusterCIDRList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested clusterCIDRs. +func (c *FakeClusterCIDRs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(clustercidrsResource, opts)) +} + +// Create takes the representation of a clusterCIDR and creates it. Returns the server's representation of the clusterCIDR, and an error, if there is any. +func (c *FakeClusterCIDRs) Create(ctx context.Context, clusterCIDR *v1alpha1.ClusterCIDR, opts v1.CreateOptions) (result *v1alpha1.ClusterCIDR, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(clustercidrsResource, clusterCIDR), &v1alpha1.ClusterCIDR{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterCIDR), err +} + +// Update takes the representation of a clusterCIDR and updates it. Returns the server's representation of the clusterCIDR, and an error, if there is any. +func (c *FakeClusterCIDRs) Update(ctx context.Context, clusterCIDR *v1alpha1.ClusterCIDR, opts v1.UpdateOptions) (result *v1alpha1.ClusterCIDR, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(clustercidrsResource, clusterCIDR), &v1alpha1.ClusterCIDR{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterCIDR), err +} + +// Delete takes name of the clusterCIDR and deletes it. Returns an error if one occurs. +func (c *FakeClusterCIDRs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(clustercidrsResource, name, opts), &v1alpha1.ClusterCIDR{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeClusterCIDRs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(clustercidrsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.ClusterCIDRList{}) + return err +} + +// Patch applies the patch and returns the patched clusterCIDR. +func (c *FakeClusterCIDRs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ClusterCIDR, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(clustercidrsResource, name, pt, data, subresources...), &v1alpha1.ClusterCIDR{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterCIDR), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied clusterCIDR. +func (c *FakeClusterCIDRs) Apply(ctx context.Context, clusterCIDR *networkingv1alpha1.ClusterCIDRApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.ClusterCIDR, err error) { + if clusterCIDR == nil { + return nil, fmt.Errorf("clusterCIDR provided to Apply must not be nil") + } + data, err := json.Marshal(clusterCIDR) + if err != nil { + return nil, err + } + name := clusterCIDR.Name + if name == nil { + return nil, fmt.Errorf("clusterCIDR.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(clustercidrsResource, *name, types.ApplyPatchType, data), &v1alpha1.ClusterCIDR{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterCIDR), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/networking/v1alpha1/fake/fake_networking_client.go b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1alpha1/fake/fake_networking_client.go new file mode 100644 index 000000000..96979aa88 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1alpha1/fake/fake_networking_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "k8s.io/client-go/kubernetes/typed/networking/v1alpha1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeNetworkingV1alpha1 struct { + *testing.Fake +} + +func (c *FakeNetworkingV1alpha1) ClusterCIDRs() v1alpha1.ClusterCIDRInterface { + return &FakeClusterCIDRs{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeNetworkingV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/fake/fake_ingress.go b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/fake/fake_ingress.go new file mode 100644 index 000000000..349196c53 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/fake/fake_ingress.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/networking/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + networkingv1beta1 "k8s.io/client-go/applyconfigurations/networking/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeIngresses implements IngressInterface +type FakeIngresses struct { + Fake *FakeNetworkingV1beta1 + ns string +} + +var ingressesResource = schema.GroupVersionResource{Group: "networking.k8s.io", Version: "v1beta1", Resource: "ingresses"} + +var ingressesKind = schema.GroupVersionKind{Group: "networking.k8s.io", Version: "v1beta1", Kind: "Ingress"} + +// Get takes name of the ingress, and returns the corresponding ingress object, and an error if there is any. +func (c *FakeIngresses) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.Ingress, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(ingressesResource, c.ns, name), &v1beta1.Ingress{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Ingress), err +} + +// List takes label and field selectors, and returns the list of Ingresses that match those selectors. +func (c *FakeIngresses) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.IngressList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(ingressesResource, ingressesKind, c.ns, opts), &v1beta1.IngressList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.IngressList{ListMeta: obj.(*v1beta1.IngressList).ListMeta} + for _, item := range obj.(*v1beta1.IngressList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested ingresses. +func (c *FakeIngresses) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(ingressesResource, c.ns, opts)) + +} + +// Create takes the representation of a ingress and creates it. Returns the server's representation of the ingress, and an error, if there is any. +func (c *FakeIngresses) Create(ctx context.Context, ingress *v1beta1.Ingress, opts v1.CreateOptions) (result *v1beta1.Ingress, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(ingressesResource, c.ns, ingress), &v1beta1.Ingress{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Ingress), err +} + +// Update takes the representation of a ingress and updates it. Returns the server's representation of the ingress, and an error, if there is any. +func (c *FakeIngresses) Update(ctx context.Context, ingress *v1beta1.Ingress, opts v1.UpdateOptions) (result *v1beta1.Ingress, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(ingressesResource, c.ns, ingress), &v1beta1.Ingress{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Ingress), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeIngresses) UpdateStatus(ctx context.Context, ingress *v1beta1.Ingress, opts v1.UpdateOptions) (*v1beta1.Ingress, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(ingressesResource, "status", c.ns, ingress), &v1beta1.Ingress{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Ingress), err +} + +// Delete takes name of the ingress and deletes it. Returns an error if one occurs. +func (c *FakeIngresses) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(ingressesResource, c.ns, name, opts), &v1beta1.Ingress{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeIngresses) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(ingressesResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.IngressList{}) + return err +} + +// Patch applies the patch and returns the patched ingress. +func (c *FakeIngresses) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Ingress, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(ingressesResource, c.ns, name, pt, data, subresources...), &v1beta1.Ingress{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Ingress), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied ingress. +func (c *FakeIngresses) Apply(ctx context.Context, ingress *networkingv1beta1.IngressApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.Ingress, err error) { + if ingress == nil { + return nil, fmt.Errorf("ingress provided to Apply must not be nil") + } + data, err := json.Marshal(ingress) + if err != nil { + return nil, err + } + name := ingress.Name + if name == nil { + return nil, fmt.Errorf("ingress.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(ingressesResource, c.ns, *name, types.ApplyPatchType, data), &v1beta1.Ingress{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Ingress), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeIngresses) ApplyStatus(ctx context.Context, ingress *networkingv1beta1.IngressApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.Ingress, err error) { + if ingress == nil { + return nil, fmt.Errorf("ingress provided to Apply must not be nil") + } + data, err := json.Marshal(ingress) + if err != nil { + return nil, err + } + name := ingress.Name + if name == nil { + return nil, fmt.Errorf("ingress.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(ingressesResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v1beta1.Ingress{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Ingress), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/fake/fake_ingressclass.go b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/fake/fake_ingressclass.go new file mode 100644 index 000000000..6ef8d1edd --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/fake/fake_ingressclass.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/networking/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + networkingv1beta1 "k8s.io/client-go/applyconfigurations/networking/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeIngressClasses implements IngressClassInterface +type FakeIngressClasses struct { + Fake *FakeNetworkingV1beta1 +} + +var ingressclassesResource = schema.GroupVersionResource{Group: "networking.k8s.io", Version: "v1beta1", Resource: "ingressclasses"} + +var ingressclassesKind = schema.GroupVersionKind{Group: "networking.k8s.io", Version: "v1beta1", Kind: "IngressClass"} + +// Get takes name of the ingressClass, and returns the corresponding ingressClass object, and an error if there is any. +func (c *FakeIngressClasses) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.IngressClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(ingressclassesResource, name), &v1beta1.IngressClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.IngressClass), err +} + +// List takes label and field selectors, and returns the list of IngressClasses that match those selectors. +func (c *FakeIngressClasses) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.IngressClassList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(ingressclassesResource, ingressclassesKind, opts), &v1beta1.IngressClassList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.IngressClassList{ListMeta: obj.(*v1beta1.IngressClassList).ListMeta} + for _, item := range obj.(*v1beta1.IngressClassList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested ingressClasses. +func (c *FakeIngressClasses) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(ingressclassesResource, opts)) +} + +// Create takes the representation of a ingressClass and creates it. Returns the server's representation of the ingressClass, and an error, if there is any. +func (c *FakeIngressClasses) Create(ctx context.Context, ingressClass *v1beta1.IngressClass, opts v1.CreateOptions) (result *v1beta1.IngressClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(ingressclassesResource, ingressClass), &v1beta1.IngressClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.IngressClass), err +} + +// Update takes the representation of a ingressClass and updates it. Returns the server's representation of the ingressClass, and an error, if there is any. +func (c *FakeIngressClasses) Update(ctx context.Context, ingressClass *v1beta1.IngressClass, opts v1.UpdateOptions) (result *v1beta1.IngressClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(ingressclassesResource, ingressClass), &v1beta1.IngressClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.IngressClass), err +} + +// Delete takes name of the ingressClass and deletes it. Returns an error if one occurs. +func (c *FakeIngressClasses) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(ingressclassesResource, name, opts), &v1beta1.IngressClass{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeIngressClasses) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(ingressclassesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.IngressClassList{}) + return err +} + +// Patch applies the patch and returns the patched ingressClass. +func (c *FakeIngressClasses) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.IngressClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(ingressclassesResource, name, pt, data, subresources...), &v1beta1.IngressClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.IngressClass), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied ingressClass. +func (c *FakeIngressClasses) Apply(ctx context.Context, ingressClass *networkingv1beta1.IngressClassApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.IngressClass, err error) { + if ingressClass == nil { + return nil, fmt.Errorf("ingressClass provided to Apply must not be nil") + } + data, err := json.Marshal(ingressClass) + if err != nil { + return nil, err + } + name := ingressClass.Name + if name == nil { + return nil, fmt.Errorf("ingressClass.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(ingressclassesResource, *name, types.ApplyPatchType, data), &v1beta1.IngressClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.IngressClass), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/fake/fake_networking_client.go b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/fake/fake_networking_client.go new file mode 100644 index 000000000..b8792a306 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/fake/fake_networking_client.go @@ -0,0 +1,44 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1beta1 "k8s.io/client-go/kubernetes/typed/networking/v1beta1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeNetworkingV1beta1 struct { + *testing.Fake +} + +func (c *FakeNetworkingV1beta1) Ingresses(namespace string) v1beta1.IngressInterface { + return &FakeIngresses{c, namespace} +} + +func (c *FakeNetworkingV1beta1) IngressClasses() v1beta1.IngressClassInterface { + return &FakeIngressClasses{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeNetworkingV1beta1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/node/v1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/node/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/node/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/node/v1/fake/fake_node_client.go b/vendor/k8s.io/client-go/kubernetes/typed/node/v1/fake/fake_node_client.go new file mode 100644 index 000000000..dea10cbad --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/node/v1/fake/fake_node_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/client-go/kubernetes/typed/node/v1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeNodeV1 struct { + *testing.Fake +} + +func (c *FakeNodeV1) RuntimeClasses() v1.RuntimeClassInterface { + return &FakeRuntimeClasses{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeNodeV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/node/v1/fake/fake_runtimeclass.go b/vendor/k8s.io/client-go/kubernetes/typed/node/v1/fake/fake_runtimeclass.go new file mode 100644 index 000000000..3a1aaf1b6 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/node/v1/fake/fake_runtimeclass.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + nodev1 "k8s.io/api/node/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsnodev1 "k8s.io/client-go/applyconfigurations/node/v1" + testing "k8s.io/client-go/testing" +) + +// FakeRuntimeClasses implements RuntimeClassInterface +type FakeRuntimeClasses struct { + Fake *FakeNodeV1 +} + +var runtimeclassesResource = schema.GroupVersionResource{Group: "node.k8s.io", Version: "v1", Resource: "runtimeclasses"} + +var runtimeclassesKind = schema.GroupVersionKind{Group: "node.k8s.io", Version: "v1", Kind: "RuntimeClass"} + +// Get takes name of the runtimeClass, and returns the corresponding runtimeClass object, and an error if there is any. +func (c *FakeRuntimeClasses) Get(ctx context.Context, name string, options v1.GetOptions) (result *nodev1.RuntimeClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(runtimeclassesResource, name), &nodev1.RuntimeClass{}) + if obj == nil { + return nil, err + } + return obj.(*nodev1.RuntimeClass), err +} + +// List takes label and field selectors, and returns the list of RuntimeClasses that match those selectors. +func (c *FakeRuntimeClasses) List(ctx context.Context, opts v1.ListOptions) (result *nodev1.RuntimeClassList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(runtimeclassesResource, runtimeclassesKind, opts), &nodev1.RuntimeClassList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &nodev1.RuntimeClassList{ListMeta: obj.(*nodev1.RuntimeClassList).ListMeta} + for _, item := range obj.(*nodev1.RuntimeClassList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested runtimeClasses. +func (c *FakeRuntimeClasses) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(runtimeclassesResource, opts)) +} + +// Create takes the representation of a runtimeClass and creates it. Returns the server's representation of the runtimeClass, and an error, if there is any. +func (c *FakeRuntimeClasses) Create(ctx context.Context, runtimeClass *nodev1.RuntimeClass, opts v1.CreateOptions) (result *nodev1.RuntimeClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(runtimeclassesResource, runtimeClass), &nodev1.RuntimeClass{}) + if obj == nil { + return nil, err + } + return obj.(*nodev1.RuntimeClass), err +} + +// Update takes the representation of a runtimeClass and updates it. Returns the server's representation of the runtimeClass, and an error, if there is any. +func (c *FakeRuntimeClasses) Update(ctx context.Context, runtimeClass *nodev1.RuntimeClass, opts v1.UpdateOptions) (result *nodev1.RuntimeClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(runtimeclassesResource, runtimeClass), &nodev1.RuntimeClass{}) + if obj == nil { + return nil, err + } + return obj.(*nodev1.RuntimeClass), err +} + +// Delete takes name of the runtimeClass and deletes it. Returns an error if one occurs. +func (c *FakeRuntimeClasses) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(runtimeclassesResource, name, opts), &nodev1.RuntimeClass{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeRuntimeClasses) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(runtimeclassesResource, listOpts) + + _, err := c.Fake.Invokes(action, &nodev1.RuntimeClassList{}) + return err +} + +// Patch applies the patch and returns the patched runtimeClass. +func (c *FakeRuntimeClasses) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *nodev1.RuntimeClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(runtimeclassesResource, name, pt, data, subresources...), &nodev1.RuntimeClass{}) + if obj == nil { + return nil, err + } + return obj.(*nodev1.RuntimeClass), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied runtimeClass. +func (c *FakeRuntimeClasses) Apply(ctx context.Context, runtimeClass *applyconfigurationsnodev1.RuntimeClassApplyConfiguration, opts v1.ApplyOptions) (result *nodev1.RuntimeClass, err error) { + if runtimeClass == nil { + return nil, fmt.Errorf("runtimeClass provided to Apply must not be nil") + } + data, err := json.Marshal(runtimeClass) + if err != nil { + return nil, err + } + name := runtimeClass.Name + if name == nil { + return nil, fmt.Errorf("runtimeClass.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(runtimeclassesResource, *name, types.ApplyPatchType, data), &nodev1.RuntimeClass{}) + if obj == nil { + return nil, err + } + return obj.(*nodev1.RuntimeClass), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/node/v1alpha1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/node/v1alpha1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/node/v1alpha1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/node/v1alpha1/fake/fake_node_client.go b/vendor/k8s.io/client-go/kubernetes/typed/node/v1alpha1/fake/fake_node_client.go new file mode 100644 index 000000000..21ab9de33 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/node/v1alpha1/fake/fake_node_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "k8s.io/client-go/kubernetes/typed/node/v1alpha1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeNodeV1alpha1 struct { + *testing.Fake +} + +func (c *FakeNodeV1alpha1) RuntimeClasses() v1alpha1.RuntimeClassInterface { + return &FakeRuntimeClasses{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeNodeV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/node/v1alpha1/fake/fake_runtimeclass.go b/vendor/k8s.io/client-go/kubernetes/typed/node/v1alpha1/fake/fake_runtimeclass.go new file mode 100644 index 000000000..4b6387943 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/node/v1alpha1/fake/fake_runtimeclass.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1alpha1 "k8s.io/api/node/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + nodev1alpha1 "k8s.io/client-go/applyconfigurations/node/v1alpha1" + testing "k8s.io/client-go/testing" +) + +// FakeRuntimeClasses implements RuntimeClassInterface +type FakeRuntimeClasses struct { + Fake *FakeNodeV1alpha1 +} + +var runtimeclassesResource = schema.GroupVersionResource{Group: "node.k8s.io", Version: "v1alpha1", Resource: "runtimeclasses"} + +var runtimeclassesKind = schema.GroupVersionKind{Group: "node.k8s.io", Version: "v1alpha1", Kind: "RuntimeClass"} + +// Get takes name of the runtimeClass, and returns the corresponding runtimeClass object, and an error if there is any. +func (c *FakeRuntimeClasses) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.RuntimeClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(runtimeclassesResource, name), &v1alpha1.RuntimeClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.RuntimeClass), err +} + +// List takes label and field selectors, and returns the list of RuntimeClasses that match those selectors. +func (c *FakeRuntimeClasses) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.RuntimeClassList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(runtimeclassesResource, runtimeclassesKind, opts), &v1alpha1.RuntimeClassList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.RuntimeClassList{ListMeta: obj.(*v1alpha1.RuntimeClassList).ListMeta} + for _, item := range obj.(*v1alpha1.RuntimeClassList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested runtimeClasses. +func (c *FakeRuntimeClasses) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(runtimeclassesResource, opts)) +} + +// Create takes the representation of a runtimeClass and creates it. Returns the server's representation of the runtimeClass, and an error, if there is any. +func (c *FakeRuntimeClasses) Create(ctx context.Context, runtimeClass *v1alpha1.RuntimeClass, opts v1.CreateOptions) (result *v1alpha1.RuntimeClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(runtimeclassesResource, runtimeClass), &v1alpha1.RuntimeClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.RuntimeClass), err +} + +// Update takes the representation of a runtimeClass and updates it. Returns the server's representation of the runtimeClass, and an error, if there is any. +func (c *FakeRuntimeClasses) Update(ctx context.Context, runtimeClass *v1alpha1.RuntimeClass, opts v1.UpdateOptions) (result *v1alpha1.RuntimeClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(runtimeclassesResource, runtimeClass), &v1alpha1.RuntimeClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.RuntimeClass), err +} + +// Delete takes name of the runtimeClass and deletes it. Returns an error if one occurs. +func (c *FakeRuntimeClasses) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(runtimeclassesResource, name, opts), &v1alpha1.RuntimeClass{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeRuntimeClasses) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(runtimeclassesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.RuntimeClassList{}) + return err +} + +// Patch applies the patch and returns the patched runtimeClass. +func (c *FakeRuntimeClasses) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.RuntimeClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(runtimeclassesResource, name, pt, data, subresources...), &v1alpha1.RuntimeClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.RuntimeClass), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied runtimeClass. +func (c *FakeRuntimeClasses) Apply(ctx context.Context, runtimeClass *nodev1alpha1.RuntimeClassApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.RuntimeClass, err error) { + if runtimeClass == nil { + return nil, fmt.Errorf("runtimeClass provided to Apply must not be nil") + } + data, err := json.Marshal(runtimeClass) + if err != nil { + return nil, err + } + name := runtimeClass.Name + if name == nil { + return nil, fmt.Errorf("runtimeClass.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(runtimeclassesResource, *name, types.ApplyPatchType, data), &v1alpha1.RuntimeClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.RuntimeClass), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/node/v1beta1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/node/v1beta1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/node/v1beta1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/node/v1beta1/fake/fake_node_client.go b/vendor/k8s.io/client-go/kubernetes/typed/node/v1beta1/fake/fake_node_client.go new file mode 100644 index 000000000..36976ce54 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/node/v1beta1/fake/fake_node_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1beta1 "k8s.io/client-go/kubernetes/typed/node/v1beta1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeNodeV1beta1 struct { + *testing.Fake +} + +func (c *FakeNodeV1beta1) RuntimeClasses() v1beta1.RuntimeClassInterface { + return &FakeRuntimeClasses{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeNodeV1beta1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/node/v1beta1/fake/fake_runtimeclass.go b/vendor/k8s.io/client-go/kubernetes/typed/node/v1beta1/fake/fake_runtimeclass.go new file mode 100644 index 000000000..191162114 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/node/v1beta1/fake/fake_runtimeclass.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/node/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + nodev1beta1 "k8s.io/client-go/applyconfigurations/node/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeRuntimeClasses implements RuntimeClassInterface +type FakeRuntimeClasses struct { + Fake *FakeNodeV1beta1 +} + +var runtimeclassesResource = schema.GroupVersionResource{Group: "node.k8s.io", Version: "v1beta1", Resource: "runtimeclasses"} + +var runtimeclassesKind = schema.GroupVersionKind{Group: "node.k8s.io", Version: "v1beta1", Kind: "RuntimeClass"} + +// Get takes name of the runtimeClass, and returns the corresponding runtimeClass object, and an error if there is any. +func (c *FakeRuntimeClasses) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.RuntimeClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(runtimeclassesResource, name), &v1beta1.RuntimeClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.RuntimeClass), err +} + +// List takes label and field selectors, and returns the list of RuntimeClasses that match those selectors. +func (c *FakeRuntimeClasses) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.RuntimeClassList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(runtimeclassesResource, runtimeclassesKind, opts), &v1beta1.RuntimeClassList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.RuntimeClassList{ListMeta: obj.(*v1beta1.RuntimeClassList).ListMeta} + for _, item := range obj.(*v1beta1.RuntimeClassList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested runtimeClasses. +func (c *FakeRuntimeClasses) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(runtimeclassesResource, opts)) +} + +// Create takes the representation of a runtimeClass and creates it. Returns the server's representation of the runtimeClass, and an error, if there is any. +func (c *FakeRuntimeClasses) Create(ctx context.Context, runtimeClass *v1beta1.RuntimeClass, opts v1.CreateOptions) (result *v1beta1.RuntimeClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(runtimeclassesResource, runtimeClass), &v1beta1.RuntimeClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.RuntimeClass), err +} + +// Update takes the representation of a runtimeClass and updates it. Returns the server's representation of the runtimeClass, and an error, if there is any. +func (c *FakeRuntimeClasses) Update(ctx context.Context, runtimeClass *v1beta1.RuntimeClass, opts v1.UpdateOptions) (result *v1beta1.RuntimeClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(runtimeclassesResource, runtimeClass), &v1beta1.RuntimeClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.RuntimeClass), err +} + +// Delete takes name of the runtimeClass and deletes it. Returns an error if one occurs. +func (c *FakeRuntimeClasses) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(runtimeclassesResource, name, opts), &v1beta1.RuntimeClass{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeRuntimeClasses) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(runtimeclassesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.RuntimeClassList{}) + return err +} + +// Patch applies the patch and returns the patched runtimeClass. +func (c *FakeRuntimeClasses) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.RuntimeClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(runtimeclassesResource, name, pt, data, subresources...), &v1beta1.RuntimeClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.RuntimeClass), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied runtimeClass. +func (c *FakeRuntimeClasses) Apply(ctx context.Context, runtimeClass *nodev1beta1.RuntimeClassApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.RuntimeClass, err error) { + if runtimeClass == nil { + return nil, fmt.Errorf("runtimeClass provided to Apply must not be nil") + } + data, err := json.Marshal(runtimeClass) + if err != nil { + return nil, err + } + name := runtimeClass.Name + if name == nil { + return nil, fmt.Errorf("runtimeClass.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(runtimeclassesResource, *name, types.ApplyPatchType, data), &v1beta1.RuntimeClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.RuntimeClass), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/policy/v1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/policy/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/policy/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_eviction.go b/vendor/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_eviction.go new file mode 100644 index 000000000..a579067ce --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_eviction.go @@ -0,0 +1,25 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +// FakeEvictions implements EvictionInterface +type FakeEvictions struct { + Fake *FakePolicyV1 + ns string +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_eviction_expansion.go b/vendor/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_eviction_expansion.go new file mode 100644 index 000000000..1b6b4ade1 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_eviction_expansion.go @@ -0,0 +1,37 @@ +/* +Copyright 2021 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 fake + +import ( + "context" + + policy "k8s.io/api/policy/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + core "k8s.io/client-go/testing" +) + +func (c *FakeEvictions) Evict(ctx context.Context, eviction *policy.Eviction) error { + action := core.CreateActionImpl{} + action.Verb = "create" + action.Namespace = c.ns + action.Resource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"} + action.Subresource = "eviction" + action.Object = eviction + + _, err := c.Fake.Invokes(action, eviction) + return err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_poddisruptionbudget.go b/vendor/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_poddisruptionbudget.go new file mode 100644 index 000000000..8023e2cd6 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_poddisruptionbudget.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + policyv1 "k8s.io/api/policy/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationspolicyv1 "k8s.io/client-go/applyconfigurations/policy/v1" + testing "k8s.io/client-go/testing" +) + +// FakePodDisruptionBudgets implements PodDisruptionBudgetInterface +type FakePodDisruptionBudgets struct { + Fake *FakePolicyV1 + ns string +} + +var poddisruptionbudgetsResource = schema.GroupVersionResource{Group: "policy", Version: "v1", Resource: "poddisruptionbudgets"} + +var poddisruptionbudgetsKind = schema.GroupVersionKind{Group: "policy", Version: "v1", Kind: "PodDisruptionBudget"} + +// Get takes name of the podDisruptionBudget, and returns the corresponding podDisruptionBudget object, and an error if there is any. +func (c *FakePodDisruptionBudgets) Get(ctx context.Context, name string, options v1.GetOptions) (result *policyv1.PodDisruptionBudget, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(poddisruptionbudgetsResource, c.ns, name), &policyv1.PodDisruptionBudget{}) + + if obj == nil { + return nil, err + } + return obj.(*policyv1.PodDisruptionBudget), err +} + +// List takes label and field selectors, and returns the list of PodDisruptionBudgets that match those selectors. +func (c *FakePodDisruptionBudgets) List(ctx context.Context, opts v1.ListOptions) (result *policyv1.PodDisruptionBudgetList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(poddisruptionbudgetsResource, poddisruptionbudgetsKind, c.ns, opts), &policyv1.PodDisruptionBudgetList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &policyv1.PodDisruptionBudgetList{ListMeta: obj.(*policyv1.PodDisruptionBudgetList).ListMeta} + for _, item := range obj.(*policyv1.PodDisruptionBudgetList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested podDisruptionBudgets. +func (c *FakePodDisruptionBudgets) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(poddisruptionbudgetsResource, c.ns, opts)) + +} + +// Create takes the representation of a podDisruptionBudget and creates it. Returns the server's representation of the podDisruptionBudget, and an error, if there is any. +func (c *FakePodDisruptionBudgets) Create(ctx context.Context, podDisruptionBudget *policyv1.PodDisruptionBudget, opts v1.CreateOptions) (result *policyv1.PodDisruptionBudget, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(poddisruptionbudgetsResource, c.ns, podDisruptionBudget), &policyv1.PodDisruptionBudget{}) + + if obj == nil { + return nil, err + } + return obj.(*policyv1.PodDisruptionBudget), err +} + +// Update takes the representation of a podDisruptionBudget and updates it. Returns the server's representation of the podDisruptionBudget, and an error, if there is any. +func (c *FakePodDisruptionBudgets) Update(ctx context.Context, podDisruptionBudget *policyv1.PodDisruptionBudget, opts v1.UpdateOptions) (result *policyv1.PodDisruptionBudget, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(poddisruptionbudgetsResource, c.ns, podDisruptionBudget), &policyv1.PodDisruptionBudget{}) + + if obj == nil { + return nil, err + } + return obj.(*policyv1.PodDisruptionBudget), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakePodDisruptionBudgets) UpdateStatus(ctx context.Context, podDisruptionBudget *policyv1.PodDisruptionBudget, opts v1.UpdateOptions) (*policyv1.PodDisruptionBudget, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(poddisruptionbudgetsResource, "status", c.ns, podDisruptionBudget), &policyv1.PodDisruptionBudget{}) + + if obj == nil { + return nil, err + } + return obj.(*policyv1.PodDisruptionBudget), err +} + +// Delete takes name of the podDisruptionBudget and deletes it. Returns an error if one occurs. +func (c *FakePodDisruptionBudgets) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(poddisruptionbudgetsResource, c.ns, name, opts), &policyv1.PodDisruptionBudget{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakePodDisruptionBudgets) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(poddisruptionbudgetsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &policyv1.PodDisruptionBudgetList{}) + return err +} + +// Patch applies the patch and returns the patched podDisruptionBudget. +func (c *FakePodDisruptionBudgets) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *policyv1.PodDisruptionBudget, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(poddisruptionbudgetsResource, c.ns, name, pt, data, subresources...), &policyv1.PodDisruptionBudget{}) + + if obj == nil { + return nil, err + } + return obj.(*policyv1.PodDisruptionBudget), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied podDisruptionBudget. +func (c *FakePodDisruptionBudgets) Apply(ctx context.Context, podDisruptionBudget *applyconfigurationspolicyv1.PodDisruptionBudgetApplyConfiguration, opts v1.ApplyOptions) (result *policyv1.PodDisruptionBudget, err error) { + if podDisruptionBudget == nil { + return nil, fmt.Errorf("podDisruptionBudget provided to Apply must not be nil") + } + data, err := json.Marshal(podDisruptionBudget) + if err != nil { + return nil, err + } + name := podDisruptionBudget.Name + if name == nil { + return nil, fmt.Errorf("podDisruptionBudget.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(poddisruptionbudgetsResource, c.ns, *name, types.ApplyPatchType, data), &policyv1.PodDisruptionBudget{}) + + if obj == nil { + return nil, err + } + return obj.(*policyv1.PodDisruptionBudget), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakePodDisruptionBudgets) ApplyStatus(ctx context.Context, podDisruptionBudget *applyconfigurationspolicyv1.PodDisruptionBudgetApplyConfiguration, opts v1.ApplyOptions) (result *policyv1.PodDisruptionBudget, err error) { + if podDisruptionBudget == nil { + return nil, fmt.Errorf("podDisruptionBudget provided to Apply must not be nil") + } + data, err := json.Marshal(podDisruptionBudget) + if err != nil { + return nil, err + } + name := podDisruptionBudget.Name + if name == nil { + return nil, fmt.Errorf("podDisruptionBudget.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(poddisruptionbudgetsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &policyv1.PodDisruptionBudget{}) + + if obj == nil { + return nil, err + } + return obj.(*policyv1.PodDisruptionBudget), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_policy_client.go b/vendor/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_policy_client.go new file mode 100644 index 000000000..d5bb3d549 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_policy_client.go @@ -0,0 +1,44 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/client-go/kubernetes/typed/policy/v1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakePolicyV1 struct { + *testing.Fake +} + +func (c *FakePolicyV1) Evictions(namespace string) v1.EvictionInterface { + return &FakeEvictions{c, namespace} +} + +func (c *FakePolicyV1) PodDisruptionBudgets(namespace string) v1.PodDisruptionBudgetInterface { + return &FakePodDisruptionBudgets{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakePolicyV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/fake_eviction.go b/vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/fake_eviction.go new file mode 100644 index 000000000..b8f6f3eae --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/fake_eviction.go @@ -0,0 +1,25 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +// FakeEvictions implements EvictionInterface +type FakeEvictions struct { + Fake *FakePolicyV1beta1 + ns string +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/fake_eviction_expansion.go b/vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/fake_eviction_expansion.go new file mode 100644 index 000000000..f97522bb3 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/fake_eviction_expansion.go @@ -0,0 +1,37 @@ +/* +Copyright 2016 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 fake + +import ( + "context" + + policy "k8s.io/api/policy/v1beta1" + "k8s.io/apimachinery/pkg/runtime/schema" + core "k8s.io/client-go/testing" +) + +func (c *FakeEvictions) Evict(ctx context.Context, eviction *policy.Eviction) error { + action := core.CreateActionImpl{} + action.Verb = "create" + action.Namespace = c.ns + action.Resource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"} + action.Subresource = "eviction" + action.Object = eviction + + _, err := c.Fake.Invokes(action, eviction) + return err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/fake_poddisruptionbudget.go b/vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/fake_poddisruptionbudget.go new file mode 100644 index 000000000..d1c856754 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/fake_poddisruptionbudget.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/policy/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + policyv1beta1 "k8s.io/client-go/applyconfigurations/policy/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakePodDisruptionBudgets implements PodDisruptionBudgetInterface +type FakePodDisruptionBudgets struct { + Fake *FakePolicyV1beta1 + ns string +} + +var poddisruptionbudgetsResource = schema.GroupVersionResource{Group: "policy", Version: "v1beta1", Resource: "poddisruptionbudgets"} + +var poddisruptionbudgetsKind = schema.GroupVersionKind{Group: "policy", Version: "v1beta1", Kind: "PodDisruptionBudget"} + +// Get takes name of the podDisruptionBudget, and returns the corresponding podDisruptionBudget object, and an error if there is any. +func (c *FakePodDisruptionBudgets) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.PodDisruptionBudget, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(poddisruptionbudgetsResource, c.ns, name), &v1beta1.PodDisruptionBudget{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PodDisruptionBudget), err +} + +// List takes label and field selectors, and returns the list of PodDisruptionBudgets that match those selectors. +func (c *FakePodDisruptionBudgets) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.PodDisruptionBudgetList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(poddisruptionbudgetsResource, poddisruptionbudgetsKind, c.ns, opts), &v1beta1.PodDisruptionBudgetList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.PodDisruptionBudgetList{ListMeta: obj.(*v1beta1.PodDisruptionBudgetList).ListMeta} + for _, item := range obj.(*v1beta1.PodDisruptionBudgetList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested podDisruptionBudgets. +func (c *FakePodDisruptionBudgets) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(poddisruptionbudgetsResource, c.ns, opts)) + +} + +// Create takes the representation of a podDisruptionBudget and creates it. Returns the server's representation of the podDisruptionBudget, and an error, if there is any. +func (c *FakePodDisruptionBudgets) Create(ctx context.Context, podDisruptionBudget *v1beta1.PodDisruptionBudget, opts v1.CreateOptions) (result *v1beta1.PodDisruptionBudget, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(poddisruptionbudgetsResource, c.ns, podDisruptionBudget), &v1beta1.PodDisruptionBudget{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PodDisruptionBudget), err +} + +// Update takes the representation of a podDisruptionBudget and updates it. Returns the server's representation of the podDisruptionBudget, and an error, if there is any. +func (c *FakePodDisruptionBudgets) Update(ctx context.Context, podDisruptionBudget *v1beta1.PodDisruptionBudget, opts v1.UpdateOptions) (result *v1beta1.PodDisruptionBudget, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(poddisruptionbudgetsResource, c.ns, podDisruptionBudget), &v1beta1.PodDisruptionBudget{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PodDisruptionBudget), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakePodDisruptionBudgets) UpdateStatus(ctx context.Context, podDisruptionBudget *v1beta1.PodDisruptionBudget, opts v1.UpdateOptions) (*v1beta1.PodDisruptionBudget, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(poddisruptionbudgetsResource, "status", c.ns, podDisruptionBudget), &v1beta1.PodDisruptionBudget{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PodDisruptionBudget), err +} + +// Delete takes name of the podDisruptionBudget and deletes it. Returns an error if one occurs. +func (c *FakePodDisruptionBudgets) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(poddisruptionbudgetsResource, c.ns, name, opts), &v1beta1.PodDisruptionBudget{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakePodDisruptionBudgets) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(poddisruptionbudgetsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.PodDisruptionBudgetList{}) + return err +} + +// Patch applies the patch and returns the patched podDisruptionBudget. +func (c *FakePodDisruptionBudgets) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.PodDisruptionBudget, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(poddisruptionbudgetsResource, c.ns, name, pt, data, subresources...), &v1beta1.PodDisruptionBudget{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PodDisruptionBudget), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied podDisruptionBudget. +func (c *FakePodDisruptionBudgets) Apply(ctx context.Context, podDisruptionBudget *policyv1beta1.PodDisruptionBudgetApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.PodDisruptionBudget, err error) { + if podDisruptionBudget == nil { + return nil, fmt.Errorf("podDisruptionBudget provided to Apply must not be nil") + } + data, err := json.Marshal(podDisruptionBudget) + if err != nil { + return nil, err + } + name := podDisruptionBudget.Name + if name == nil { + return nil, fmt.Errorf("podDisruptionBudget.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(poddisruptionbudgetsResource, c.ns, *name, types.ApplyPatchType, data), &v1beta1.PodDisruptionBudget{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PodDisruptionBudget), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakePodDisruptionBudgets) ApplyStatus(ctx context.Context, podDisruptionBudget *policyv1beta1.PodDisruptionBudgetApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.PodDisruptionBudget, err error) { + if podDisruptionBudget == nil { + return nil, fmt.Errorf("podDisruptionBudget provided to Apply must not be nil") + } + data, err := json.Marshal(podDisruptionBudget) + if err != nil { + return nil, err + } + name := podDisruptionBudget.Name + if name == nil { + return nil, fmt.Errorf("podDisruptionBudget.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(poddisruptionbudgetsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v1beta1.PodDisruptionBudget{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PodDisruptionBudget), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/fake_podsecuritypolicy.go b/vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/fake_podsecuritypolicy.go new file mode 100644 index 000000000..614d4e799 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/fake_podsecuritypolicy.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/policy/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + policyv1beta1 "k8s.io/client-go/applyconfigurations/policy/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakePodSecurityPolicies implements PodSecurityPolicyInterface +type FakePodSecurityPolicies struct { + Fake *FakePolicyV1beta1 +} + +var podsecuritypoliciesResource = schema.GroupVersionResource{Group: "policy", Version: "v1beta1", Resource: "podsecuritypolicies"} + +var podsecuritypoliciesKind = schema.GroupVersionKind{Group: "policy", Version: "v1beta1", Kind: "PodSecurityPolicy"} + +// Get takes name of the podSecurityPolicy, and returns the corresponding podSecurityPolicy object, and an error if there is any. +func (c *FakePodSecurityPolicies) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.PodSecurityPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(podsecuritypoliciesResource, name), &v1beta1.PodSecurityPolicy{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PodSecurityPolicy), err +} + +// List takes label and field selectors, and returns the list of PodSecurityPolicies that match those selectors. +func (c *FakePodSecurityPolicies) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.PodSecurityPolicyList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(podsecuritypoliciesResource, podsecuritypoliciesKind, opts), &v1beta1.PodSecurityPolicyList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.PodSecurityPolicyList{ListMeta: obj.(*v1beta1.PodSecurityPolicyList).ListMeta} + for _, item := range obj.(*v1beta1.PodSecurityPolicyList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested podSecurityPolicies. +func (c *FakePodSecurityPolicies) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(podsecuritypoliciesResource, opts)) +} + +// Create takes the representation of a podSecurityPolicy and creates it. Returns the server's representation of the podSecurityPolicy, and an error, if there is any. +func (c *FakePodSecurityPolicies) Create(ctx context.Context, podSecurityPolicy *v1beta1.PodSecurityPolicy, opts v1.CreateOptions) (result *v1beta1.PodSecurityPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(podsecuritypoliciesResource, podSecurityPolicy), &v1beta1.PodSecurityPolicy{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PodSecurityPolicy), err +} + +// Update takes the representation of a podSecurityPolicy and updates it. Returns the server's representation of the podSecurityPolicy, and an error, if there is any. +func (c *FakePodSecurityPolicies) Update(ctx context.Context, podSecurityPolicy *v1beta1.PodSecurityPolicy, opts v1.UpdateOptions) (result *v1beta1.PodSecurityPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(podsecuritypoliciesResource, podSecurityPolicy), &v1beta1.PodSecurityPolicy{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PodSecurityPolicy), err +} + +// Delete takes name of the podSecurityPolicy and deletes it. Returns an error if one occurs. +func (c *FakePodSecurityPolicies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(podsecuritypoliciesResource, name, opts), &v1beta1.PodSecurityPolicy{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakePodSecurityPolicies) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(podsecuritypoliciesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.PodSecurityPolicyList{}) + return err +} + +// Patch applies the patch and returns the patched podSecurityPolicy. +func (c *FakePodSecurityPolicies) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.PodSecurityPolicy, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(podsecuritypoliciesResource, name, pt, data, subresources...), &v1beta1.PodSecurityPolicy{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PodSecurityPolicy), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied podSecurityPolicy. +func (c *FakePodSecurityPolicies) Apply(ctx context.Context, podSecurityPolicy *policyv1beta1.PodSecurityPolicyApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.PodSecurityPolicy, err error) { + if podSecurityPolicy == nil { + return nil, fmt.Errorf("podSecurityPolicy provided to Apply must not be nil") + } + data, err := json.Marshal(podSecurityPolicy) + if err != nil { + return nil, err + } + name := podSecurityPolicy.Name + if name == nil { + return nil, fmt.Errorf("podSecurityPolicy.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(podsecuritypoliciesResource, *name, types.ApplyPatchType, data), &v1beta1.PodSecurityPolicy{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PodSecurityPolicy), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/fake_policy_client.go b/vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/fake_policy_client.go new file mode 100644 index 000000000..9c780bf1f --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake/fake_policy_client.go @@ -0,0 +1,48 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1beta1 "k8s.io/client-go/kubernetes/typed/policy/v1beta1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakePolicyV1beta1 struct { + *testing.Fake +} + +func (c *FakePolicyV1beta1) Evictions(namespace string) v1beta1.EvictionInterface { + return &FakeEvictions{c, namespace} +} + +func (c *FakePolicyV1beta1) PodDisruptionBudgets(namespace string) v1beta1.PodDisruptionBudgetInterface { + return &FakePodDisruptionBudgets{c, namespace} +} + +func (c *FakePolicyV1beta1) PodSecurityPolicies() v1beta1.PodSecurityPolicyInterface { + return &FakePodSecurityPolicies{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakePolicyV1beta1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/fake_clusterrole.go b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/fake_clusterrole.go new file mode 100644 index 000000000..21a32ca04 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/fake_clusterrole.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + rbacv1 "k8s.io/api/rbac/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsrbacv1 "k8s.io/client-go/applyconfigurations/rbac/v1" + testing "k8s.io/client-go/testing" +) + +// FakeClusterRoles implements ClusterRoleInterface +type FakeClusterRoles struct { + Fake *FakeRbacV1 +} + +var clusterrolesResource = schema.GroupVersionResource{Group: "rbac.authorization.k8s.io", Version: "v1", Resource: "clusterroles"} + +var clusterrolesKind = schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRole"} + +// Get takes name of the clusterRole, and returns the corresponding clusterRole object, and an error if there is any. +func (c *FakeClusterRoles) Get(ctx context.Context, name string, options v1.GetOptions) (result *rbacv1.ClusterRole, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(clusterrolesResource, name), &rbacv1.ClusterRole{}) + if obj == nil { + return nil, err + } + return obj.(*rbacv1.ClusterRole), err +} + +// List takes label and field selectors, and returns the list of ClusterRoles that match those selectors. +func (c *FakeClusterRoles) List(ctx context.Context, opts v1.ListOptions) (result *rbacv1.ClusterRoleList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(clusterrolesResource, clusterrolesKind, opts), &rbacv1.ClusterRoleList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &rbacv1.ClusterRoleList{ListMeta: obj.(*rbacv1.ClusterRoleList).ListMeta} + for _, item := range obj.(*rbacv1.ClusterRoleList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested clusterRoles. +func (c *FakeClusterRoles) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(clusterrolesResource, opts)) +} + +// Create takes the representation of a clusterRole and creates it. Returns the server's representation of the clusterRole, and an error, if there is any. +func (c *FakeClusterRoles) Create(ctx context.Context, clusterRole *rbacv1.ClusterRole, opts v1.CreateOptions) (result *rbacv1.ClusterRole, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(clusterrolesResource, clusterRole), &rbacv1.ClusterRole{}) + if obj == nil { + return nil, err + } + return obj.(*rbacv1.ClusterRole), err +} + +// Update takes the representation of a clusterRole and updates it. Returns the server's representation of the clusterRole, and an error, if there is any. +func (c *FakeClusterRoles) Update(ctx context.Context, clusterRole *rbacv1.ClusterRole, opts v1.UpdateOptions) (result *rbacv1.ClusterRole, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(clusterrolesResource, clusterRole), &rbacv1.ClusterRole{}) + if obj == nil { + return nil, err + } + return obj.(*rbacv1.ClusterRole), err +} + +// Delete takes name of the clusterRole and deletes it. Returns an error if one occurs. +func (c *FakeClusterRoles) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(clusterrolesResource, name, opts), &rbacv1.ClusterRole{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeClusterRoles) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(clusterrolesResource, listOpts) + + _, err := c.Fake.Invokes(action, &rbacv1.ClusterRoleList{}) + return err +} + +// Patch applies the patch and returns the patched clusterRole. +func (c *FakeClusterRoles) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *rbacv1.ClusterRole, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(clusterrolesResource, name, pt, data, subresources...), &rbacv1.ClusterRole{}) + if obj == nil { + return nil, err + } + return obj.(*rbacv1.ClusterRole), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied clusterRole. +func (c *FakeClusterRoles) Apply(ctx context.Context, clusterRole *applyconfigurationsrbacv1.ClusterRoleApplyConfiguration, opts v1.ApplyOptions) (result *rbacv1.ClusterRole, err error) { + if clusterRole == nil { + return nil, fmt.Errorf("clusterRole provided to Apply must not be nil") + } + data, err := json.Marshal(clusterRole) + if err != nil { + return nil, err + } + name := clusterRole.Name + if name == nil { + return nil, fmt.Errorf("clusterRole.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(clusterrolesResource, *name, types.ApplyPatchType, data), &rbacv1.ClusterRole{}) + if obj == nil { + return nil, err + } + return obj.(*rbacv1.ClusterRole), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/fake_clusterrolebinding.go b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/fake_clusterrolebinding.go new file mode 100644 index 000000000..c65399598 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/fake_clusterrolebinding.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + rbacv1 "k8s.io/api/rbac/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsrbacv1 "k8s.io/client-go/applyconfigurations/rbac/v1" + testing "k8s.io/client-go/testing" +) + +// FakeClusterRoleBindings implements ClusterRoleBindingInterface +type FakeClusterRoleBindings struct { + Fake *FakeRbacV1 +} + +var clusterrolebindingsResource = schema.GroupVersionResource{Group: "rbac.authorization.k8s.io", Version: "v1", Resource: "clusterrolebindings"} + +var clusterrolebindingsKind = schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRoleBinding"} + +// Get takes name of the clusterRoleBinding, and returns the corresponding clusterRoleBinding object, and an error if there is any. +func (c *FakeClusterRoleBindings) Get(ctx context.Context, name string, options v1.GetOptions) (result *rbacv1.ClusterRoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(clusterrolebindingsResource, name), &rbacv1.ClusterRoleBinding{}) + if obj == nil { + return nil, err + } + return obj.(*rbacv1.ClusterRoleBinding), err +} + +// List takes label and field selectors, and returns the list of ClusterRoleBindings that match those selectors. +func (c *FakeClusterRoleBindings) List(ctx context.Context, opts v1.ListOptions) (result *rbacv1.ClusterRoleBindingList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(clusterrolebindingsResource, clusterrolebindingsKind, opts), &rbacv1.ClusterRoleBindingList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &rbacv1.ClusterRoleBindingList{ListMeta: obj.(*rbacv1.ClusterRoleBindingList).ListMeta} + for _, item := range obj.(*rbacv1.ClusterRoleBindingList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested clusterRoleBindings. +func (c *FakeClusterRoleBindings) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(clusterrolebindingsResource, opts)) +} + +// Create takes the representation of a clusterRoleBinding and creates it. Returns the server's representation of the clusterRoleBinding, and an error, if there is any. +func (c *FakeClusterRoleBindings) Create(ctx context.Context, clusterRoleBinding *rbacv1.ClusterRoleBinding, opts v1.CreateOptions) (result *rbacv1.ClusterRoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(clusterrolebindingsResource, clusterRoleBinding), &rbacv1.ClusterRoleBinding{}) + if obj == nil { + return nil, err + } + return obj.(*rbacv1.ClusterRoleBinding), err +} + +// Update takes the representation of a clusterRoleBinding and updates it. Returns the server's representation of the clusterRoleBinding, and an error, if there is any. +func (c *FakeClusterRoleBindings) Update(ctx context.Context, clusterRoleBinding *rbacv1.ClusterRoleBinding, opts v1.UpdateOptions) (result *rbacv1.ClusterRoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(clusterrolebindingsResource, clusterRoleBinding), &rbacv1.ClusterRoleBinding{}) + if obj == nil { + return nil, err + } + return obj.(*rbacv1.ClusterRoleBinding), err +} + +// Delete takes name of the clusterRoleBinding and deletes it. Returns an error if one occurs. +func (c *FakeClusterRoleBindings) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(clusterrolebindingsResource, name, opts), &rbacv1.ClusterRoleBinding{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeClusterRoleBindings) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(clusterrolebindingsResource, listOpts) + + _, err := c.Fake.Invokes(action, &rbacv1.ClusterRoleBindingList{}) + return err +} + +// Patch applies the patch and returns the patched clusterRoleBinding. +func (c *FakeClusterRoleBindings) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *rbacv1.ClusterRoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(clusterrolebindingsResource, name, pt, data, subresources...), &rbacv1.ClusterRoleBinding{}) + if obj == nil { + return nil, err + } + return obj.(*rbacv1.ClusterRoleBinding), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied clusterRoleBinding. +func (c *FakeClusterRoleBindings) Apply(ctx context.Context, clusterRoleBinding *applyconfigurationsrbacv1.ClusterRoleBindingApplyConfiguration, opts v1.ApplyOptions) (result *rbacv1.ClusterRoleBinding, err error) { + if clusterRoleBinding == nil { + return nil, fmt.Errorf("clusterRoleBinding provided to Apply must not be nil") + } + data, err := json.Marshal(clusterRoleBinding) + if err != nil { + return nil, err + } + name := clusterRoleBinding.Name + if name == nil { + return nil, fmt.Errorf("clusterRoleBinding.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(clusterrolebindingsResource, *name, types.ApplyPatchType, data), &rbacv1.ClusterRoleBinding{}) + if obj == nil { + return nil, err + } + return obj.(*rbacv1.ClusterRoleBinding), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/fake_rbac_client.go b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/fake_rbac_client.go new file mode 100644 index 000000000..426fd70d6 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/fake_rbac_client.go @@ -0,0 +1,52 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/client-go/kubernetes/typed/rbac/v1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeRbacV1 struct { + *testing.Fake +} + +func (c *FakeRbacV1) ClusterRoles() v1.ClusterRoleInterface { + return &FakeClusterRoles{c} +} + +func (c *FakeRbacV1) ClusterRoleBindings() v1.ClusterRoleBindingInterface { + return &FakeClusterRoleBindings{c} +} + +func (c *FakeRbacV1) Roles(namespace string) v1.RoleInterface { + return &FakeRoles{c, namespace} +} + +func (c *FakeRbacV1) RoleBindings(namespace string) v1.RoleBindingInterface { + return &FakeRoleBindings{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeRbacV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/fake_role.go b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/fake_role.go new file mode 100644 index 000000000..4a70d0c35 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/fake_role.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + rbacv1 "k8s.io/api/rbac/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsrbacv1 "k8s.io/client-go/applyconfigurations/rbac/v1" + testing "k8s.io/client-go/testing" +) + +// FakeRoles implements RoleInterface +type FakeRoles struct { + Fake *FakeRbacV1 + ns string +} + +var rolesResource = schema.GroupVersionResource{Group: "rbac.authorization.k8s.io", Version: "v1", Resource: "roles"} + +var rolesKind = schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "Role"} + +// Get takes name of the role, and returns the corresponding role object, and an error if there is any. +func (c *FakeRoles) Get(ctx context.Context, name string, options v1.GetOptions) (result *rbacv1.Role, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(rolesResource, c.ns, name), &rbacv1.Role{}) + + if obj == nil { + return nil, err + } + return obj.(*rbacv1.Role), err +} + +// List takes label and field selectors, and returns the list of Roles that match those selectors. +func (c *FakeRoles) List(ctx context.Context, opts v1.ListOptions) (result *rbacv1.RoleList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(rolesResource, rolesKind, c.ns, opts), &rbacv1.RoleList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &rbacv1.RoleList{ListMeta: obj.(*rbacv1.RoleList).ListMeta} + for _, item := range obj.(*rbacv1.RoleList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested roles. +func (c *FakeRoles) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(rolesResource, c.ns, opts)) + +} + +// Create takes the representation of a role and creates it. Returns the server's representation of the role, and an error, if there is any. +func (c *FakeRoles) Create(ctx context.Context, role *rbacv1.Role, opts v1.CreateOptions) (result *rbacv1.Role, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(rolesResource, c.ns, role), &rbacv1.Role{}) + + if obj == nil { + return nil, err + } + return obj.(*rbacv1.Role), err +} + +// Update takes the representation of a role and updates it. Returns the server's representation of the role, and an error, if there is any. +func (c *FakeRoles) Update(ctx context.Context, role *rbacv1.Role, opts v1.UpdateOptions) (result *rbacv1.Role, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(rolesResource, c.ns, role), &rbacv1.Role{}) + + if obj == nil { + return nil, err + } + return obj.(*rbacv1.Role), err +} + +// Delete takes name of the role and deletes it. Returns an error if one occurs. +func (c *FakeRoles) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(rolesResource, c.ns, name, opts), &rbacv1.Role{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeRoles) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(rolesResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &rbacv1.RoleList{}) + return err +} + +// Patch applies the patch and returns the patched role. +func (c *FakeRoles) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *rbacv1.Role, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(rolesResource, c.ns, name, pt, data, subresources...), &rbacv1.Role{}) + + if obj == nil { + return nil, err + } + return obj.(*rbacv1.Role), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied role. +func (c *FakeRoles) Apply(ctx context.Context, role *applyconfigurationsrbacv1.RoleApplyConfiguration, opts v1.ApplyOptions) (result *rbacv1.Role, err error) { + if role == nil { + return nil, fmt.Errorf("role provided to Apply must not be nil") + } + data, err := json.Marshal(role) + if err != nil { + return nil, err + } + name := role.Name + if name == nil { + return nil, fmt.Errorf("role.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(rolesResource, c.ns, *name, types.ApplyPatchType, data), &rbacv1.Role{}) + + if obj == nil { + return nil, err + } + return obj.(*rbacv1.Role), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/fake_rolebinding.go b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/fake_rolebinding.go new file mode 100644 index 000000000..0db37dd57 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1/fake/fake_rolebinding.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + rbacv1 "k8s.io/api/rbac/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsrbacv1 "k8s.io/client-go/applyconfigurations/rbac/v1" + testing "k8s.io/client-go/testing" +) + +// FakeRoleBindings implements RoleBindingInterface +type FakeRoleBindings struct { + Fake *FakeRbacV1 + ns string +} + +var rolebindingsResource = schema.GroupVersionResource{Group: "rbac.authorization.k8s.io", Version: "v1", Resource: "rolebindings"} + +var rolebindingsKind = schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "RoleBinding"} + +// Get takes name of the roleBinding, and returns the corresponding roleBinding object, and an error if there is any. +func (c *FakeRoleBindings) Get(ctx context.Context, name string, options v1.GetOptions) (result *rbacv1.RoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(rolebindingsResource, c.ns, name), &rbacv1.RoleBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*rbacv1.RoleBinding), err +} + +// List takes label and field selectors, and returns the list of RoleBindings that match those selectors. +func (c *FakeRoleBindings) List(ctx context.Context, opts v1.ListOptions) (result *rbacv1.RoleBindingList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(rolebindingsResource, rolebindingsKind, c.ns, opts), &rbacv1.RoleBindingList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &rbacv1.RoleBindingList{ListMeta: obj.(*rbacv1.RoleBindingList).ListMeta} + for _, item := range obj.(*rbacv1.RoleBindingList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested roleBindings. +func (c *FakeRoleBindings) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(rolebindingsResource, c.ns, opts)) + +} + +// Create takes the representation of a roleBinding and creates it. Returns the server's representation of the roleBinding, and an error, if there is any. +func (c *FakeRoleBindings) Create(ctx context.Context, roleBinding *rbacv1.RoleBinding, opts v1.CreateOptions) (result *rbacv1.RoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(rolebindingsResource, c.ns, roleBinding), &rbacv1.RoleBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*rbacv1.RoleBinding), err +} + +// Update takes the representation of a roleBinding and updates it. Returns the server's representation of the roleBinding, and an error, if there is any. +func (c *FakeRoleBindings) Update(ctx context.Context, roleBinding *rbacv1.RoleBinding, opts v1.UpdateOptions) (result *rbacv1.RoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(rolebindingsResource, c.ns, roleBinding), &rbacv1.RoleBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*rbacv1.RoleBinding), err +} + +// Delete takes name of the roleBinding and deletes it. Returns an error if one occurs. +func (c *FakeRoleBindings) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(rolebindingsResource, c.ns, name, opts), &rbacv1.RoleBinding{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeRoleBindings) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(rolebindingsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &rbacv1.RoleBindingList{}) + return err +} + +// Patch applies the patch and returns the patched roleBinding. +func (c *FakeRoleBindings) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *rbacv1.RoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(rolebindingsResource, c.ns, name, pt, data, subresources...), &rbacv1.RoleBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*rbacv1.RoleBinding), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied roleBinding. +func (c *FakeRoleBindings) Apply(ctx context.Context, roleBinding *applyconfigurationsrbacv1.RoleBindingApplyConfiguration, opts v1.ApplyOptions) (result *rbacv1.RoleBinding, err error) { + if roleBinding == nil { + return nil, fmt.Errorf("roleBinding provided to Apply must not be nil") + } + data, err := json.Marshal(roleBinding) + if err != nil { + return nil, err + } + name := roleBinding.Name + if name == nil { + return nil, fmt.Errorf("roleBinding.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(rolebindingsResource, c.ns, *name, types.ApplyPatchType, data), &rbacv1.RoleBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*rbacv1.RoleBinding), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/fake_clusterrole.go b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/fake_clusterrole.go new file mode 100644 index 000000000..7e8e3a9b8 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/fake_clusterrole.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1alpha1 "k8s.io/api/rbac/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rbacv1alpha1 "k8s.io/client-go/applyconfigurations/rbac/v1alpha1" + testing "k8s.io/client-go/testing" +) + +// FakeClusterRoles implements ClusterRoleInterface +type FakeClusterRoles struct { + Fake *FakeRbacV1alpha1 +} + +var clusterrolesResource = schema.GroupVersionResource{Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Resource: "clusterroles"} + +var clusterrolesKind = schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Kind: "ClusterRole"} + +// Get takes name of the clusterRole, and returns the corresponding clusterRole object, and an error if there is any. +func (c *FakeClusterRoles) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ClusterRole, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(clusterrolesResource, name), &v1alpha1.ClusterRole{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterRole), err +} + +// List takes label and field selectors, and returns the list of ClusterRoles that match those selectors. +func (c *FakeClusterRoles) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ClusterRoleList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(clusterrolesResource, clusterrolesKind, opts), &v1alpha1.ClusterRoleList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.ClusterRoleList{ListMeta: obj.(*v1alpha1.ClusterRoleList).ListMeta} + for _, item := range obj.(*v1alpha1.ClusterRoleList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested clusterRoles. +func (c *FakeClusterRoles) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(clusterrolesResource, opts)) +} + +// Create takes the representation of a clusterRole and creates it. Returns the server's representation of the clusterRole, and an error, if there is any. +func (c *FakeClusterRoles) Create(ctx context.Context, clusterRole *v1alpha1.ClusterRole, opts v1.CreateOptions) (result *v1alpha1.ClusterRole, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(clusterrolesResource, clusterRole), &v1alpha1.ClusterRole{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterRole), err +} + +// Update takes the representation of a clusterRole and updates it. Returns the server's representation of the clusterRole, and an error, if there is any. +func (c *FakeClusterRoles) Update(ctx context.Context, clusterRole *v1alpha1.ClusterRole, opts v1.UpdateOptions) (result *v1alpha1.ClusterRole, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(clusterrolesResource, clusterRole), &v1alpha1.ClusterRole{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterRole), err +} + +// Delete takes name of the clusterRole and deletes it. Returns an error if one occurs. +func (c *FakeClusterRoles) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(clusterrolesResource, name, opts), &v1alpha1.ClusterRole{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeClusterRoles) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(clusterrolesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.ClusterRoleList{}) + return err +} + +// Patch applies the patch and returns the patched clusterRole. +func (c *FakeClusterRoles) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ClusterRole, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(clusterrolesResource, name, pt, data, subresources...), &v1alpha1.ClusterRole{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterRole), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied clusterRole. +func (c *FakeClusterRoles) Apply(ctx context.Context, clusterRole *rbacv1alpha1.ClusterRoleApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.ClusterRole, err error) { + if clusterRole == nil { + return nil, fmt.Errorf("clusterRole provided to Apply must not be nil") + } + data, err := json.Marshal(clusterRole) + if err != nil { + return nil, err + } + name := clusterRole.Name + if name == nil { + return nil, fmt.Errorf("clusterRole.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(clusterrolesResource, *name, types.ApplyPatchType, data), &v1alpha1.ClusterRole{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterRole), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/fake_clusterrolebinding.go b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/fake_clusterrolebinding.go new file mode 100644 index 000000000..5c5e63278 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/fake_clusterrolebinding.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1alpha1 "k8s.io/api/rbac/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rbacv1alpha1 "k8s.io/client-go/applyconfigurations/rbac/v1alpha1" + testing "k8s.io/client-go/testing" +) + +// FakeClusterRoleBindings implements ClusterRoleBindingInterface +type FakeClusterRoleBindings struct { + Fake *FakeRbacV1alpha1 +} + +var clusterrolebindingsResource = schema.GroupVersionResource{Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Resource: "clusterrolebindings"} + +var clusterrolebindingsKind = schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Kind: "ClusterRoleBinding"} + +// Get takes name of the clusterRoleBinding, and returns the corresponding clusterRoleBinding object, and an error if there is any. +func (c *FakeClusterRoleBindings) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ClusterRoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(clusterrolebindingsResource, name), &v1alpha1.ClusterRoleBinding{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterRoleBinding), err +} + +// List takes label and field selectors, and returns the list of ClusterRoleBindings that match those selectors. +func (c *FakeClusterRoleBindings) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ClusterRoleBindingList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(clusterrolebindingsResource, clusterrolebindingsKind, opts), &v1alpha1.ClusterRoleBindingList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.ClusterRoleBindingList{ListMeta: obj.(*v1alpha1.ClusterRoleBindingList).ListMeta} + for _, item := range obj.(*v1alpha1.ClusterRoleBindingList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested clusterRoleBindings. +func (c *FakeClusterRoleBindings) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(clusterrolebindingsResource, opts)) +} + +// Create takes the representation of a clusterRoleBinding and creates it. Returns the server's representation of the clusterRoleBinding, and an error, if there is any. +func (c *FakeClusterRoleBindings) Create(ctx context.Context, clusterRoleBinding *v1alpha1.ClusterRoleBinding, opts v1.CreateOptions) (result *v1alpha1.ClusterRoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(clusterrolebindingsResource, clusterRoleBinding), &v1alpha1.ClusterRoleBinding{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterRoleBinding), err +} + +// Update takes the representation of a clusterRoleBinding and updates it. Returns the server's representation of the clusterRoleBinding, and an error, if there is any. +func (c *FakeClusterRoleBindings) Update(ctx context.Context, clusterRoleBinding *v1alpha1.ClusterRoleBinding, opts v1.UpdateOptions) (result *v1alpha1.ClusterRoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(clusterrolebindingsResource, clusterRoleBinding), &v1alpha1.ClusterRoleBinding{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterRoleBinding), err +} + +// Delete takes name of the clusterRoleBinding and deletes it. Returns an error if one occurs. +func (c *FakeClusterRoleBindings) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(clusterrolebindingsResource, name, opts), &v1alpha1.ClusterRoleBinding{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeClusterRoleBindings) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(clusterrolebindingsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.ClusterRoleBindingList{}) + return err +} + +// Patch applies the patch and returns the patched clusterRoleBinding. +func (c *FakeClusterRoleBindings) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ClusterRoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(clusterrolebindingsResource, name, pt, data, subresources...), &v1alpha1.ClusterRoleBinding{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterRoleBinding), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied clusterRoleBinding. +func (c *FakeClusterRoleBindings) Apply(ctx context.Context, clusterRoleBinding *rbacv1alpha1.ClusterRoleBindingApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.ClusterRoleBinding, err error) { + if clusterRoleBinding == nil { + return nil, fmt.Errorf("clusterRoleBinding provided to Apply must not be nil") + } + data, err := json.Marshal(clusterRoleBinding) + if err != nil { + return nil, err + } + name := clusterRoleBinding.Name + if name == nil { + return nil, fmt.Errorf("clusterRoleBinding.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(clusterrolebindingsResource, *name, types.ApplyPatchType, data), &v1alpha1.ClusterRoleBinding{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterRoleBinding), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/fake_rbac_client.go b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/fake_rbac_client.go new file mode 100644 index 000000000..3447e9be8 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/fake_rbac_client.go @@ -0,0 +1,52 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "k8s.io/client-go/kubernetes/typed/rbac/v1alpha1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeRbacV1alpha1 struct { + *testing.Fake +} + +func (c *FakeRbacV1alpha1) ClusterRoles() v1alpha1.ClusterRoleInterface { + return &FakeClusterRoles{c} +} + +func (c *FakeRbacV1alpha1) ClusterRoleBindings() v1alpha1.ClusterRoleBindingInterface { + return &FakeClusterRoleBindings{c} +} + +func (c *FakeRbacV1alpha1) Roles(namespace string) v1alpha1.RoleInterface { + return &FakeRoles{c, namespace} +} + +func (c *FakeRbacV1alpha1) RoleBindings(namespace string) v1alpha1.RoleBindingInterface { + return &FakeRoleBindings{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeRbacV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/fake_role.go b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/fake_role.go new file mode 100644 index 000000000..cec3f099d --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/fake_role.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1alpha1 "k8s.io/api/rbac/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rbacv1alpha1 "k8s.io/client-go/applyconfigurations/rbac/v1alpha1" + testing "k8s.io/client-go/testing" +) + +// FakeRoles implements RoleInterface +type FakeRoles struct { + Fake *FakeRbacV1alpha1 + ns string +} + +var rolesResource = schema.GroupVersionResource{Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Resource: "roles"} + +var rolesKind = schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Kind: "Role"} + +// Get takes name of the role, and returns the corresponding role object, and an error if there is any. +func (c *FakeRoles) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.Role, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(rolesResource, c.ns, name), &v1alpha1.Role{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Role), err +} + +// List takes label and field selectors, and returns the list of Roles that match those selectors. +func (c *FakeRoles) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.RoleList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(rolesResource, rolesKind, c.ns, opts), &v1alpha1.RoleList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.RoleList{ListMeta: obj.(*v1alpha1.RoleList).ListMeta} + for _, item := range obj.(*v1alpha1.RoleList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested roles. +func (c *FakeRoles) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(rolesResource, c.ns, opts)) + +} + +// Create takes the representation of a role and creates it. Returns the server's representation of the role, and an error, if there is any. +func (c *FakeRoles) Create(ctx context.Context, role *v1alpha1.Role, opts v1.CreateOptions) (result *v1alpha1.Role, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(rolesResource, c.ns, role), &v1alpha1.Role{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Role), err +} + +// Update takes the representation of a role and updates it. Returns the server's representation of the role, and an error, if there is any. +func (c *FakeRoles) Update(ctx context.Context, role *v1alpha1.Role, opts v1.UpdateOptions) (result *v1alpha1.Role, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(rolesResource, c.ns, role), &v1alpha1.Role{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Role), err +} + +// Delete takes name of the role and deletes it. Returns an error if one occurs. +func (c *FakeRoles) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(rolesResource, c.ns, name, opts), &v1alpha1.Role{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeRoles) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(rolesResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.RoleList{}) + return err +} + +// Patch applies the patch and returns the patched role. +func (c *FakeRoles) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Role, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(rolesResource, c.ns, name, pt, data, subresources...), &v1alpha1.Role{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Role), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied role. +func (c *FakeRoles) Apply(ctx context.Context, role *rbacv1alpha1.RoleApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.Role, err error) { + if role == nil { + return nil, fmt.Errorf("role provided to Apply must not be nil") + } + data, err := json.Marshal(role) + if err != nil { + return nil, err + } + name := role.Name + if name == nil { + return nil, fmt.Errorf("role.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(rolesResource, c.ns, *name, types.ApplyPatchType, data), &v1alpha1.Role{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Role), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/fake_rolebinding.go b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/fake_rolebinding.go new file mode 100644 index 000000000..2d66494fd --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake/fake_rolebinding.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1alpha1 "k8s.io/api/rbac/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rbacv1alpha1 "k8s.io/client-go/applyconfigurations/rbac/v1alpha1" + testing "k8s.io/client-go/testing" +) + +// FakeRoleBindings implements RoleBindingInterface +type FakeRoleBindings struct { + Fake *FakeRbacV1alpha1 + ns string +} + +var rolebindingsResource = schema.GroupVersionResource{Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Resource: "rolebindings"} + +var rolebindingsKind = schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Kind: "RoleBinding"} + +// Get takes name of the roleBinding, and returns the corresponding roleBinding object, and an error if there is any. +func (c *FakeRoleBindings) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.RoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(rolebindingsResource, c.ns, name), &v1alpha1.RoleBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.RoleBinding), err +} + +// List takes label and field selectors, and returns the list of RoleBindings that match those selectors. +func (c *FakeRoleBindings) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.RoleBindingList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(rolebindingsResource, rolebindingsKind, c.ns, opts), &v1alpha1.RoleBindingList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.RoleBindingList{ListMeta: obj.(*v1alpha1.RoleBindingList).ListMeta} + for _, item := range obj.(*v1alpha1.RoleBindingList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested roleBindings. +func (c *FakeRoleBindings) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(rolebindingsResource, c.ns, opts)) + +} + +// Create takes the representation of a roleBinding and creates it. Returns the server's representation of the roleBinding, and an error, if there is any. +func (c *FakeRoleBindings) Create(ctx context.Context, roleBinding *v1alpha1.RoleBinding, opts v1.CreateOptions) (result *v1alpha1.RoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(rolebindingsResource, c.ns, roleBinding), &v1alpha1.RoleBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.RoleBinding), err +} + +// Update takes the representation of a roleBinding and updates it. Returns the server's representation of the roleBinding, and an error, if there is any. +func (c *FakeRoleBindings) Update(ctx context.Context, roleBinding *v1alpha1.RoleBinding, opts v1.UpdateOptions) (result *v1alpha1.RoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(rolebindingsResource, c.ns, roleBinding), &v1alpha1.RoleBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.RoleBinding), err +} + +// Delete takes name of the roleBinding and deletes it. Returns an error if one occurs. +func (c *FakeRoleBindings) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(rolebindingsResource, c.ns, name, opts), &v1alpha1.RoleBinding{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeRoleBindings) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(rolebindingsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.RoleBindingList{}) + return err +} + +// Patch applies the patch and returns the patched roleBinding. +func (c *FakeRoleBindings) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.RoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(rolebindingsResource, c.ns, name, pt, data, subresources...), &v1alpha1.RoleBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.RoleBinding), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied roleBinding. +func (c *FakeRoleBindings) Apply(ctx context.Context, roleBinding *rbacv1alpha1.RoleBindingApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.RoleBinding, err error) { + if roleBinding == nil { + return nil, fmt.Errorf("roleBinding provided to Apply must not be nil") + } + data, err := json.Marshal(roleBinding) + if err != nil { + return nil, err + } + name := roleBinding.Name + if name == nil { + return nil, fmt.Errorf("roleBinding.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(rolebindingsResource, c.ns, *name, types.ApplyPatchType, data), &v1alpha1.RoleBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.RoleBinding), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/fake_clusterrole.go b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/fake_clusterrole.go new file mode 100644 index 000000000..2b4f60054 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/fake_clusterrole.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/rbac/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rbacv1beta1 "k8s.io/client-go/applyconfigurations/rbac/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeClusterRoles implements ClusterRoleInterface +type FakeClusterRoles struct { + Fake *FakeRbacV1beta1 +} + +var clusterrolesResource = schema.GroupVersionResource{Group: "rbac.authorization.k8s.io", Version: "v1beta1", Resource: "clusterroles"} + +var clusterrolesKind = schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1beta1", Kind: "ClusterRole"} + +// Get takes name of the clusterRole, and returns the corresponding clusterRole object, and an error if there is any. +func (c *FakeClusterRoles) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.ClusterRole, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(clusterrolesResource, name), &v1beta1.ClusterRole{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ClusterRole), err +} + +// List takes label and field selectors, and returns the list of ClusterRoles that match those selectors. +func (c *FakeClusterRoles) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.ClusterRoleList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(clusterrolesResource, clusterrolesKind, opts), &v1beta1.ClusterRoleList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.ClusterRoleList{ListMeta: obj.(*v1beta1.ClusterRoleList).ListMeta} + for _, item := range obj.(*v1beta1.ClusterRoleList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested clusterRoles. +func (c *FakeClusterRoles) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(clusterrolesResource, opts)) +} + +// Create takes the representation of a clusterRole and creates it. Returns the server's representation of the clusterRole, and an error, if there is any. +func (c *FakeClusterRoles) Create(ctx context.Context, clusterRole *v1beta1.ClusterRole, opts v1.CreateOptions) (result *v1beta1.ClusterRole, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(clusterrolesResource, clusterRole), &v1beta1.ClusterRole{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ClusterRole), err +} + +// Update takes the representation of a clusterRole and updates it. Returns the server's representation of the clusterRole, and an error, if there is any. +func (c *FakeClusterRoles) Update(ctx context.Context, clusterRole *v1beta1.ClusterRole, opts v1.UpdateOptions) (result *v1beta1.ClusterRole, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(clusterrolesResource, clusterRole), &v1beta1.ClusterRole{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ClusterRole), err +} + +// Delete takes name of the clusterRole and deletes it. Returns an error if one occurs. +func (c *FakeClusterRoles) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(clusterrolesResource, name, opts), &v1beta1.ClusterRole{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeClusterRoles) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(clusterrolesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.ClusterRoleList{}) + return err +} + +// Patch applies the patch and returns the patched clusterRole. +func (c *FakeClusterRoles) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.ClusterRole, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(clusterrolesResource, name, pt, data, subresources...), &v1beta1.ClusterRole{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ClusterRole), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied clusterRole. +func (c *FakeClusterRoles) Apply(ctx context.Context, clusterRole *rbacv1beta1.ClusterRoleApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.ClusterRole, err error) { + if clusterRole == nil { + return nil, fmt.Errorf("clusterRole provided to Apply must not be nil") + } + data, err := json.Marshal(clusterRole) + if err != nil { + return nil, err + } + name := clusterRole.Name + if name == nil { + return nil, fmt.Errorf("clusterRole.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(clusterrolesResource, *name, types.ApplyPatchType, data), &v1beta1.ClusterRole{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ClusterRole), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/fake_clusterrolebinding.go b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/fake_clusterrolebinding.go new file mode 100644 index 000000000..379261ec8 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/fake_clusterrolebinding.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/rbac/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rbacv1beta1 "k8s.io/client-go/applyconfigurations/rbac/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeClusterRoleBindings implements ClusterRoleBindingInterface +type FakeClusterRoleBindings struct { + Fake *FakeRbacV1beta1 +} + +var clusterrolebindingsResource = schema.GroupVersionResource{Group: "rbac.authorization.k8s.io", Version: "v1beta1", Resource: "clusterrolebindings"} + +var clusterrolebindingsKind = schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1beta1", Kind: "ClusterRoleBinding"} + +// Get takes name of the clusterRoleBinding, and returns the corresponding clusterRoleBinding object, and an error if there is any. +func (c *FakeClusterRoleBindings) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.ClusterRoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(clusterrolebindingsResource, name), &v1beta1.ClusterRoleBinding{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ClusterRoleBinding), err +} + +// List takes label and field selectors, and returns the list of ClusterRoleBindings that match those selectors. +func (c *FakeClusterRoleBindings) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.ClusterRoleBindingList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(clusterrolebindingsResource, clusterrolebindingsKind, opts), &v1beta1.ClusterRoleBindingList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.ClusterRoleBindingList{ListMeta: obj.(*v1beta1.ClusterRoleBindingList).ListMeta} + for _, item := range obj.(*v1beta1.ClusterRoleBindingList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested clusterRoleBindings. +func (c *FakeClusterRoleBindings) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(clusterrolebindingsResource, opts)) +} + +// Create takes the representation of a clusterRoleBinding and creates it. Returns the server's representation of the clusterRoleBinding, and an error, if there is any. +func (c *FakeClusterRoleBindings) Create(ctx context.Context, clusterRoleBinding *v1beta1.ClusterRoleBinding, opts v1.CreateOptions) (result *v1beta1.ClusterRoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(clusterrolebindingsResource, clusterRoleBinding), &v1beta1.ClusterRoleBinding{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ClusterRoleBinding), err +} + +// Update takes the representation of a clusterRoleBinding and updates it. Returns the server's representation of the clusterRoleBinding, and an error, if there is any. +func (c *FakeClusterRoleBindings) Update(ctx context.Context, clusterRoleBinding *v1beta1.ClusterRoleBinding, opts v1.UpdateOptions) (result *v1beta1.ClusterRoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(clusterrolebindingsResource, clusterRoleBinding), &v1beta1.ClusterRoleBinding{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ClusterRoleBinding), err +} + +// Delete takes name of the clusterRoleBinding and deletes it. Returns an error if one occurs. +func (c *FakeClusterRoleBindings) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(clusterrolebindingsResource, name, opts), &v1beta1.ClusterRoleBinding{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeClusterRoleBindings) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(clusterrolebindingsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.ClusterRoleBindingList{}) + return err +} + +// Patch applies the patch and returns the patched clusterRoleBinding. +func (c *FakeClusterRoleBindings) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.ClusterRoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(clusterrolebindingsResource, name, pt, data, subresources...), &v1beta1.ClusterRoleBinding{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ClusterRoleBinding), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied clusterRoleBinding. +func (c *FakeClusterRoleBindings) Apply(ctx context.Context, clusterRoleBinding *rbacv1beta1.ClusterRoleBindingApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.ClusterRoleBinding, err error) { + if clusterRoleBinding == nil { + return nil, fmt.Errorf("clusterRoleBinding provided to Apply must not be nil") + } + data, err := json.Marshal(clusterRoleBinding) + if err != nil { + return nil, err + } + name := clusterRoleBinding.Name + if name == nil { + return nil, fmt.Errorf("clusterRoleBinding.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(clusterrolebindingsResource, *name, types.ApplyPatchType, data), &v1beta1.ClusterRoleBinding{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ClusterRoleBinding), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/fake_rbac_client.go b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/fake_rbac_client.go new file mode 100644 index 000000000..bdbc246b7 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/fake_rbac_client.go @@ -0,0 +1,52 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1beta1 "k8s.io/client-go/kubernetes/typed/rbac/v1beta1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeRbacV1beta1 struct { + *testing.Fake +} + +func (c *FakeRbacV1beta1) ClusterRoles() v1beta1.ClusterRoleInterface { + return &FakeClusterRoles{c} +} + +func (c *FakeRbacV1beta1) ClusterRoleBindings() v1beta1.ClusterRoleBindingInterface { + return &FakeClusterRoleBindings{c} +} + +func (c *FakeRbacV1beta1) Roles(namespace string) v1beta1.RoleInterface { + return &FakeRoles{c, namespace} +} + +func (c *FakeRbacV1beta1) RoleBindings(namespace string) v1beta1.RoleBindingInterface { + return &FakeRoleBindings{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeRbacV1beta1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/fake_role.go b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/fake_role.go new file mode 100644 index 000000000..44df9128a --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/fake_role.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/rbac/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rbacv1beta1 "k8s.io/client-go/applyconfigurations/rbac/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeRoles implements RoleInterface +type FakeRoles struct { + Fake *FakeRbacV1beta1 + ns string +} + +var rolesResource = schema.GroupVersionResource{Group: "rbac.authorization.k8s.io", Version: "v1beta1", Resource: "roles"} + +var rolesKind = schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1beta1", Kind: "Role"} + +// Get takes name of the role, and returns the corresponding role object, and an error if there is any. +func (c *FakeRoles) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.Role, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(rolesResource, c.ns, name), &v1beta1.Role{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Role), err +} + +// List takes label and field selectors, and returns the list of Roles that match those selectors. +func (c *FakeRoles) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.RoleList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(rolesResource, rolesKind, c.ns, opts), &v1beta1.RoleList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.RoleList{ListMeta: obj.(*v1beta1.RoleList).ListMeta} + for _, item := range obj.(*v1beta1.RoleList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested roles. +func (c *FakeRoles) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(rolesResource, c.ns, opts)) + +} + +// Create takes the representation of a role and creates it. Returns the server's representation of the role, and an error, if there is any. +func (c *FakeRoles) Create(ctx context.Context, role *v1beta1.Role, opts v1.CreateOptions) (result *v1beta1.Role, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(rolesResource, c.ns, role), &v1beta1.Role{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Role), err +} + +// Update takes the representation of a role and updates it. Returns the server's representation of the role, and an error, if there is any. +func (c *FakeRoles) Update(ctx context.Context, role *v1beta1.Role, opts v1.UpdateOptions) (result *v1beta1.Role, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(rolesResource, c.ns, role), &v1beta1.Role{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Role), err +} + +// Delete takes name of the role and deletes it. Returns an error if one occurs. +func (c *FakeRoles) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(rolesResource, c.ns, name, opts), &v1beta1.Role{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeRoles) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(rolesResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.RoleList{}) + return err +} + +// Patch applies the patch and returns the patched role. +func (c *FakeRoles) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Role, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(rolesResource, c.ns, name, pt, data, subresources...), &v1beta1.Role{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Role), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied role. +func (c *FakeRoles) Apply(ctx context.Context, role *rbacv1beta1.RoleApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.Role, err error) { + if role == nil { + return nil, fmt.Errorf("role provided to Apply must not be nil") + } + data, err := json.Marshal(role) + if err != nil { + return nil, err + } + name := role.Name + if name == nil { + return nil, fmt.Errorf("role.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(rolesResource, c.ns, *name, types.ApplyPatchType, data), &v1beta1.Role{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Role), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/fake_rolebinding.go b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/fake_rolebinding.go new file mode 100644 index 000000000..5e90e6dbd --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake/fake_rolebinding.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/rbac/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rbacv1beta1 "k8s.io/client-go/applyconfigurations/rbac/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeRoleBindings implements RoleBindingInterface +type FakeRoleBindings struct { + Fake *FakeRbacV1beta1 + ns string +} + +var rolebindingsResource = schema.GroupVersionResource{Group: "rbac.authorization.k8s.io", Version: "v1beta1", Resource: "rolebindings"} + +var rolebindingsKind = schema.GroupVersionKind{Group: "rbac.authorization.k8s.io", Version: "v1beta1", Kind: "RoleBinding"} + +// Get takes name of the roleBinding, and returns the corresponding roleBinding object, and an error if there is any. +func (c *FakeRoleBindings) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.RoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(rolebindingsResource, c.ns, name), &v1beta1.RoleBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.RoleBinding), err +} + +// List takes label and field selectors, and returns the list of RoleBindings that match those selectors. +func (c *FakeRoleBindings) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.RoleBindingList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(rolebindingsResource, rolebindingsKind, c.ns, opts), &v1beta1.RoleBindingList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.RoleBindingList{ListMeta: obj.(*v1beta1.RoleBindingList).ListMeta} + for _, item := range obj.(*v1beta1.RoleBindingList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested roleBindings. +func (c *FakeRoleBindings) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(rolebindingsResource, c.ns, opts)) + +} + +// Create takes the representation of a roleBinding and creates it. Returns the server's representation of the roleBinding, and an error, if there is any. +func (c *FakeRoleBindings) Create(ctx context.Context, roleBinding *v1beta1.RoleBinding, opts v1.CreateOptions) (result *v1beta1.RoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(rolebindingsResource, c.ns, roleBinding), &v1beta1.RoleBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.RoleBinding), err +} + +// Update takes the representation of a roleBinding and updates it. Returns the server's representation of the roleBinding, and an error, if there is any. +func (c *FakeRoleBindings) Update(ctx context.Context, roleBinding *v1beta1.RoleBinding, opts v1.UpdateOptions) (result *v1beta1.RoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(rolebindingsResource, c.ns, roleBinding), &v1beta1.RoleBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.RoleBinding), err +} + +// Delete takes name of the roleBinding and deletes it. Returns an error if one occurs. +func (c *FakeRoleBindings) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(rolebindingsResource, c.ns, name, opts), &v1beta1.RoleBinding{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeRoleBindings) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(rolebindingsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.RoleBindingList{}) + return err +} + +// Patch applies the patch and returns the patched roleBinding. +func (c *FakeRoleBindings) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.RoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(rolebindingsResource, c.ns, name, pt, data, subresources...), &v1beta1.RoleBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.RoleBinding), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied roleBinding. +func (c *FakeRoleBindings) Apply(ctx context.Context, roleBinding *rbacv1beta1.RoleBindingApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.RoleBinding, err error) { + if roleBinding == nil { + return nil, fmt.Errorf("roleBinding provided to Apply must not be nil") + } + data, err := json.Marshal(roleBinding) + if err != nil { + return nil, err + } + name := roleBinding.Name + if name == nil { + return nil, fmt.Errorf("roleBinding.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(rolebindingsResource, c.ns, *name, types.ApplyPatchType, data), &v1beta1.RoleBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.RoleBinding), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/fake_podscheduling.go b/vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/fake_podscheduling.go new file mode 100644 index 000000000..7b4e2a5d5 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/fake_podscheduling.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1alpha1 "k8s.io/api/resource/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + resourcev1alpha1 "k8s.io/client-go/applyconfigurations/resource/v1alpha1" + testing "k8s.io/client-go/testing" +) + +// FakePodSchedulings implements PodSchedulingInterface +type FakePodSchedulings struct { + Fake *FakeResourceV1alpha1 + ns string +} + +var podschedulingsResource = schema.GroupVersionResource{Group: "resource.k8s.io", Version: "v1alpha1", Resource: "podschedulings"} + +var podschedulingsKind = schema.GroupVersionKind{Group: "resource.k8s.io", Version: "v1alpha1", Kind: "PodScheduling"} + +// Get takes name of the podScheduling, and returns the corresponding podScheduling object, and an error if there is any. +func (c *FakePodSchedulings) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.PodScheduling, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(podschedulingsResource, c.ns, name), &v1alpha1.PodScheduling{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.PodScheduling), err +} + +// List takes label and field selectors, and returns the list of PodSchedulings that match those selectors. +func (c *FakePodSchedulings) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.PodSchedulingList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(podschedulingsResource, podschedulingsKind, c.ns, opts), &v1alpha1.PodSchedulingList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.PodSchedulingList{ListMeta: obj.(*v1alpha1.PodSchedulingList).ListMeta} + for _, item := range obj.(*v1alpha1.PodSchedulingList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested podSchedulings. +func (c *FakePodSchedulings) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(podschedulingsResource, c.ns, opts)) + +} + +// Create takes the representation of a podScheduling and creates it. Returns the server's representation of the podScheduling, and an error, if there is any. +func (c *FakePodSchedulings) Create(ctx context.Context, podScheduling *v1alpha1.PodScheduling, opts v1.CreateOptions) (result *v1alpha1.PodScheduling, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(podschedulingsResource, c.ns, podScheduling), &v1alpha1.PodScheduling{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.PodScheduling), err +} + +// Update takes the representation of a podScheduling and updates it. Returns the server's representation of the podScheduling, and an error, if there is any. +func (c *FakePodSchedulings) Update(ctx context.Context, podScheduling *v1alpha1.PodScheduling, opts v1.UpdateOptions) (result *v1alpha1.PodScheduling, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(podschedulingsResource, c.ns, podScheduling), &v1alpha1.PodScheduling{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.PodScheduling), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakePodSchedulings) UpdateStatus(ctx context.Context, podScheduling *v1alpha1.PodScheduling, opts v1.UpdateOptions) (*v1alpha1.PodScheduling, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(podschedulingsResource, "status", c.ns, podScheduling), &v1alpha1.PodScheduling{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.PodScheduling), err +} + +// Delete takes name of the podScheduling and deletes it. Returns an error if one occurs. +func (c *FakePodSchedulings) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(podschedulingsResource, c.ns, name, opts), &v1alpha1.PodScheduling{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakePodSchedulings) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(podschedulingsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.PodSchedulingList{}) + return err +} + +// Patch applies the patch and returns the patched podScheduling. +func (c *FakePodSchedulings) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.PodScheduling, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(podschedulingsResource, c.ns, name, pt, data, subresources...), &v1alpha1.PodScheduling{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.PodScheduling), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied podScheduling. +func (c *FakePodSchedulings) Apply(ctx context.Context, podScheduling *resourcev1alpha1.PodSchedulingApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.PodScheduling, err error) { + if podScheduling == nil { + return nil, fmt.Errorf("podScheduling provided to Apply must not be nil") + } + data, err := json.Marshal(podScheduling) + if err != nil { + return nil, err + } + name := podScheduling.Name + if name == nil { + return nil, fmt.Errorf("podScheduling.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(podschedulingsResource, c.ns, *name, types.ApplyPatchType, data), &v1alpha1.PodScheduling{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.PodScheduling), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakePodSchedulings) ApplyStatus(ctx context.Context, podScheduling *resourcev1alpha1.PodSchedulingApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.PodScheduling, err error) { + if podScheduling == nil { + return nil, fmt.Errorf("podScheduling provided to Apply must not be nil") + } + data, err := json.Marshal(podScheduling) + if err != nil { + return nil, err + } + name := podScheduling.Name + if name == nil { + return nil, fmt.Errorf("podScheduling.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(podschedulingsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v1alpha1.PodScheduling{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.PodScheduling), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/fake_resource_client.go b/vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/fake_resource_client.go new file mode 100644 index 000000000..c4776ee54 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/fake_resource_client.go @@ -0,0 +1,52 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "k8s.io/client-go/kubernetes/typed/resource/v1alpha1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeResourceV1alpha1 struct { + *testing.Fake +} + +func (c *FakeResourceV1alpha1) PodSchedulings(namespace string) v1alpha1.PodSchedulingInterface { + return &FakePodSchedulings{c, namespace} +} + +func (c *FakeResourceV1alpha1) ResourceClaims(namespace string) v1alpha1.ResourceClaimInterface { + return &FakeResourceClaims{c, namespace} +} + +func (c *FakeResourceV1alpha1) ResourceClaimTemplates(namespace string) v1alpha1.ResourceClaimTemplateInterface { + return &FakeResourceClaimTemplates{c, namespace} +} + +func (c *FakeResourceV1alpha1) ResourceClasses() v1alpha1.ResourceClassInterface { + return &FakeResourceClasses{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeResourceV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/fake_resourceclaim.go b/vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/fake_resourceclaim.go new file mode 100644 index 000000000..a458459f8 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/fake_resourceclaim.go @@ -0,0 +1,190 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1alpha1 "k8s.io/api/resource/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + resourcev1alpha1 "k8s.io/client-go/applyconfigurations/resource/v1alpha1" + testing "k8s.io/client-go/testing" +) + +// FakeResourceClaims implements ResourceClaimInterface +type FakeResourceClaims struct { + Fake *FakeResourceV1alpha1 + ns string +} + +var resourceclaimsResource = schema.GroupVersionResource{Group: "resource.k8s.io", Version: "v1alpha1", Resource: "resourceclaims"} + +var resourceclaimsKind = schema.GroupVersionKind{Group: "resource.k8s.io", Version: "v1alpha1", Kind: "ResourceClaim"} + +// Get takes name of the resourceClaim, and returns the corresponding resourceClaim object, and an error if there is any. +func (c *FakeResourceClaims) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ResourceClaim, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(resourceclaimsResource, c.ns, name), &v1alpha1.ResourceClaim{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ResourceClaim), err +} + +// List takes label and field selectors, and returns the list of ResourceClaims that match those selectors. +func (c *FakeResourceClaims) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ResourceClaimList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(resourceclaimsResource, resourceclaimsKind, c.ns, opts), &v1alpha1.ResourceClaimList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.ResourceClaimList{ListMeta: obj.(*v1alpha1.ResourceClaimList).ListMeta} + for _, item := range obj.(*v1alpha1.ResourceClaimList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested resourceClaims. +func (c *FakeResourceClaims) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(resourceclaimsResource, c.ns, opts)) + +} + +// Create takes the representation of a resourceClaim and creates it. Returns the server's representation of the resourceClaim, and an error, if there is any. +func (c *FakeResourceClaims) Create(ctx context.Context, resourceClaim *v1alpha1.ResourceClaim, opts v1.CreateOptions) (result *v1alpha1.ResourceClaim, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(resourceclaimsResource, c.ns, resourceClaim), &v1alpha1.ResourceClaim{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ResourceClaim), err +} + +// Update takes the representation of a resourceClaim and updates it. Returns the server's representation of the resourceClaim, and an error, if there is any. +func (c *FakeResourceClaims) Update(ctx context.Context, resourceClaim *v1alpha1.ResourceClaim, opts v1.UpdateOptions) (result *v1alpha1.ResourceClaim, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(resourceclaimsResource, c.ns, resourceClaim), &v1alpha1.ResourceClaim{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ResourceClaim), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeResourceClaims) UpdateStatus(ctx context.Context, resourceClaim *v1alpha1.ResourceClaim, opts v1.UpdateOptions) (*v1alpha1.ResourceClaim, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(resourceclaimsResource, "status", c.ns, resourceClaim), &v1alpha1.ResourceClaim{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ResourceClaim), err +} + +// Delete takes name of the resourceClaim and deletes it. Returns an error if one occurs. +func (c *FakeResourceClaims) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(resourceclaimsResource, c.ns, name, opts), &v1alpha1.ResourceClaim{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeResourceClaims) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(resourceclaimsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.ResourceClaimList{}) + return err +} + +// Patch applies the patch and returns the patched resourceClaim. +func (c *FakeResourceClaims) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ResourceClaim, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(resourceclaimsResource, c.ns, name, pt, data, subresources...), &v1alpha1.ResourceClaim{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ResourceClaim), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied resourceClaim. +func (c *FakeResourceClaims) Apply(ctx context.Context, resourceClaim *resourcev1alpha1.ResourceClaimApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.ResourceClaim, err error) { + if resourceClaim == nil { + return nil, fmt.Errorf("resourceClaim provided to Apply must not be nil") + } + data, err := json.Marshal(resourceClaim) + if err != nil { + return nil, err + } + name := resourceClaim.Name + if name == nil { + return nil, fmt.Errorf("resourceClaim.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(resourceclaimsResource, c.ns, *name, types.ApplyPatchType, data), &v1alpha1.ResourceClaim{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ResourceClaim), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeResourceClaims) ApplyStatus(ctx context.Context, resourceClaim *resourcev1alpha1.ResourceClaimApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.ResourceClaim, err error) { + if resourceClaim == nil { + return nil, fmt.Errorf("resourceClaim provided to Apply must not be nil") + } + data, err := json.Marshal(resourceClaim) + if err != nil { + return nil, err + } + name := resourceClaim.Name + if name == nil { + return nil, fmt.Errorf("resourceClaim.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(resourceclaimsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v1alpha1.ResourceClaim{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ResourceClaim), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/fake_resourceclaimtemplate.go b/vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/fake_resourceclaimtemplate.go new file mode 100644 index 000000000..be22ab6d3 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/fake_resourceclaimtemplate.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1alpha1 "k8s.io/api/resource/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + resourcev1alpha1 "k8s.io/client-go/applyconfigurations/resource/v1alpha1" + testing "k8s.io/client-go/testing" +) + +// FakeResourceClaimTemplates implements ResourceClaimTemplateInterface +type FakeResourceClaimTemplates struct { + Fake *FakeResourceV1alpha1 + ns string +} + +var resourceclaimtemplatesResource = schema.GroupVersionResource{Group: "resource.k8s.io", Version: "v1alpha1", Resource: "resourceclaimtemplates"} + +var resourceclaimtemplatesKind = schema.GroupVersionKind{Group: "resource.k8s.io", Version: "v1alpha1", Kind: "ResourceClaimTemplate"} + +// Get takes name of the resourceClaimTemplate, and returns the corresponding resourceClaimTemplate object, and an error if there is any. +func (c *FakeResourceClaimTemplates) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ResourceClaimTemplate, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(resourceclaimtemplatesResource, c.ns, name), &v1alpha1.ResourceClaimTemplate{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ResourceClaimTemplate), err +} + +// List takes label and field selectors, and returns the list of ResourceClaimTemplates that match those selectors. +func (c *FakeResourceClaimTemplates) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ResourceClaimTemplateList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(resourceclaimtemplatesResource, resourceclaimtemplatesKind, c.ns, opts), &v1alpha1.ResourceClaimTemplateList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.ResourceClaimTemplateList{ListMeta: obj.(*v1alpha1.ResourceClaimTemplateList).ListMeta} + for _, item := range obj.(*v1alpha1.ResourceClaimTemplateList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested resourceClaimTemplates. +func (c *FakeResourceClaimTemplates) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(resourceclaimtemplatesResource, c.ns, opts)) + +} + +// Create takes the representation of a resourceClaimTemplate and creates it. Returns the server's representation of the resourceClaimTemplate, and an error, if there is any. +func (c *FakeResourceClaimTemplates) Create(ctx context.Context, resourceClaimTemplate *v1alpha1.ResourceClaimTemplate, opts v1.CreateOptions) (result *v1alpha1.ResourceClaimTemplate, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(resourceclaimtemplatesResource, c.ns, resourceClaimTemplate), &v1alpha1.ResourceClaimTemplate{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ResourceClaimTemplate), err +} + +// Update takes the representation of a resourceClaimTemplate and updates it. Returns the server's representation of the resourceClaimTemplate, and an error, if there is any. +func (c *FakeResourceClaimTemplates) Update(ctx context.Context, resourceClaimTemplate *v1alpha1.ResourceClaimTemplate, opts v1.UpdateOptions) (result *v1alpha1.ResourceClaimTemplate, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(resourceclaimtemplatesResource, c.ns, resourceClaimTemplate), &v1alpha1.ResourceClaimTemplate{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ResourceClaimTemplate), err +} + +// Delete takes name of the resourceClaimTemplate and deletes it. Returns an error if one occurs. +func (c *FakeResourceClaimTemplates) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(resourceclaimtemplatesResource, c.ns, name, opts), &v1alpha1.ResourceClaimTemplate{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeResourceClaimTemplates) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(resourceclaimtemplatesResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.ResourceClaimTemplateList{}) + return err +} + +// Patch applies the patch and returns the patched resourceClaimTemplate. +func (c *FakeResourceClaimTemplates) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ResourceClaimTemplate, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(resourceclaimtemplatesResource, c.ns, name, pt, data, subresources...), &v1alpha1.ResourceClaimTemplate{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ResourceClaimTemplate), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied resourceClaimTemplate. +func (c *FakeResourceClaimTemplates) Apply(ctx context.Context, resourceClaimTemplate *resourcev1alpha1.ResourceClaimTemplateApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.ResourceClaimTemplate, err error) { + if resourceClaimTemplate == nil { + return nil, fmt.Errorf("resourceClaimTemplate provided to Apply must not be nil") + } + data, err := json.Marshal(resourceClaimTemplate) + if err != nil { + return nil, err + } + name := resourceClaimTemplate.Name + if name == nil { + return nil, fmt.Errorf("resourceClaimTemplate.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(resourceclaimtemplatesResource, c.ns, *name, types.ApplyPatchType, data), &v1alpha1.ResourceClaimTemplate{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ResourceClaimTemplate), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/fake_resourceclass.go b/vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/fake_resourceclass.go new file mode 100644 index 000000000..80fb7ec03 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake/fake_resourceclass.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1alpha1 "k8s.io/api/resource/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + resourcev1alpha1 "k8s.io/client-go/applyconfigurations/resource/v1alpha1" + testing "k8s.io/client-go/testing" +) + +// FakeResourceClasses implements ResourceClassInterface +type FakeResourceClasses struct { + Fake *FakeResourceV1alpha1 +} + +var resourceclassesResource = schema.GroupVersionResource{Group: "resource.k8s.io", Version: "v1alpha1", Resource: "resourceclasses"} + +var resourceclassesKind = schema.GroupVersionKind{Group: "resource.k8s.io", Version: "v1alpha1", Kind: "ResourceClass"} + +// Get takes name of the resourceClass, and returns the corresponding resourceClass object, and an error if there is any. +func (c *FakeResourceClasses) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ResourceClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(resourceclassesResource, name), &v1alpha1.ResourceClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ResourceClass), err +} + +// List takes label and field selectors, and returns the list of ResourceClasses that match those selectors. +func (c *FakeResourceClasses) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ResourceClassList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(resourceclassesResource, resourceclassesKind, opts), &v1alpha1.ResourceClassList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.ResourceClassList{ListMeta: obj.(*v1alpha1.ResourceClassList).ListMeta} + for _, item := range obj.(*v1alpha1.ResourceClassList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested resourceClasses. +func (c *FakeResourceClasses) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(resourceclassesResource, opts)) +} + +// Create takes the representation of a resourceClass and creates it. Returns the server's representation of the resourceClass, and an error, if there is any. +func (c *FakeResourceClasses) Create(ctx context.Context, resourceClass *v1alpha1.ResourceClass, opts v1.CreateOptions) (result *v1alpha1.ResourceClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(resourceclassesResource, resourceClass), &v1alpha1.ResourceClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ResourceClass), err +} + +// Update takes the representation of a resourceClass and updates it. Returns the server's representation of the resourceClass, and an error, if there is any. +func (c *FakeResourceClasses) Update(ctx context.Context, resourceClass *v1alpha1.ResourceClass, opts v1.UpdateOptions) (result *v1alpha1.ResourceClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(resourceclassesResource, resourceClass), &v1alpha1.ResourceClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ResourceClass), err +} + +// Delete takes name of the resourceClass and deletes it. Returns an error if one occurs. +func (c *FakeResourceClasses) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(resourceclassesResource, name, opts), &v1alpha1.ResourceClass{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeResourceClasses) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(resourceclassesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.ResourceClassList{}) + return err +} + +// Patch applies the patch and returns the patched resourceClass. +func (c *FakeResourceClasses) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ResourceClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(resourceclassesResource, name, pt, data, subresources...), &v1alpha1.ResourceClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ResourceClass), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied resourceClass. +func (c *FakeResourceClasses) Apply(ctx context.Context, resourceClass *resourcev1alpha1.ResourceClassApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.ResourceClass, err error) { + if resourceClass == nil { + return nil, fmt.Errorf("resourceClass provided to Apply must not be nil") + } + data, err := json.Marshal(resourceClass) + if err != nil { + return nil, err + } + name := resourceClass.Name + if name == nil { + return nil, fmt.Errorf("resourceClass.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(resourceclassesResource, *name, types.ApplyPatchType, data), &v1alpha1.ResourceClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ResourceClass), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1/fake/fake_priorityclass.go b/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1/fake/fake_priorityclass.go new file mode 100644 index 000000000..30f82270e --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1/fake/fake_priorityclass.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + schedulingv1 "k8s.io/api/scheduling/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsschedulingv1 "k8s.io/client-go/applyconfigurations/scheduling/v1" + testing "k8s.io/client-go/testing" +) + +// FakePriorityClasses implements PriorityClassInterface +type FakePriorityClasses struct { + Fake *FakeSchedulingV1 +} + +var priorityclassesResource = schema.GroupVersionResource{Group: "scheduling.k8s.io", Version: "v1", Resource: "priorityclasses"} + +var priorityclassesKind = schema.GroupVersionKind{Group: "scheduling.k8s.io", Version: "v1", Kind: "PriorityClass"} + +// Get takes name of the priorityClass, and returns the corresponding priorityClass object, and an error if there is any. +func (c *FakePriorityClasses) Get(ctx context.Context, name string, options v1.GetOptions) (result *schedulingv1.PriorityClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(priorityclassesResource, name), &schedulingv1.PriorityClass{}) + if obj == nil { + return nil, err + } + return obj.(*schedulingv1.PriorityClass), err +} + +// List takes label and field selectors, and returns the list of PriorityClasses that match those selectors. +func (c *FakePriorityClasses) List(ctx context.Context, opts v1.ListOptions) (result *schedulingv1.PriorityClassList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(priorityclassesResource, priorityclassesKind, opts), &schedulingv1.PriorityClassList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &schedulingv1.PriorityClassList{ListMeta: obj.(*schedulingv1.PriorityClassList).ListMeta} + for _, item := range obj.(*schedulingv1.PriorityClassList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested priorityClasses. +func (c *FakePriorityClasses) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(priorityclassesResource, opts)) +} + +// Create takes the representation of a priorityClass and creates it. Returns the server's representation of the priorityClass, and an error, if there is any. +func (c *FakePriorityClasses) Create(ctx context.Context, priorityClass *schedulingv1.PriorityClass, opts v1.CreateOptions) (result *schedulingv1.PriorityClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(priorityclassesResource, priorityClass), &schedulingv1.PriorityClass{}) + if obj == nil { + return nil, err + } + return obj.(*schedulingv1.PriorityClass), err +} + +// Update takes the representation of a priorityClass and updates it. Returns the server's representation of the priorityClass, and an error, if there is any. +func (c *FakePriorityClasses) Update(ctx context.Context, priorityClass *schedulingv1.PriorityClass, opts v1.UpdateOptions) (result *schedulingv1.PriorityClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(priorityclassesResource, priorityClass), &schedulingv1.PriorityClass{}) + if obj == nil { + return nil, err + } + return obj.(*schedulingv1.PriorityClass), err +} + +// Delete takes name of the priorityClass and deletes it. Returns an error if one occurs. +func (c *FakePriorityClasses) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(priorityclassesResource, name, opts), &schedulingv1.PriorityClass{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakePriorityClasses) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(priorityclassesResource, listOpts) + + _, err := c.Fake.Invokes(action, &schedulingv1.PriorityClassList{}) + return err +} + +// Patch applies the patch and returns the patched priorityClass. +func (c *FakePriorityClasses) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *schedulingv1.PriorityClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(priorityclassesResource, name, pt, data, subresources...), &schedulingv1.PriorityClass{}) + if obj == nil { + return nil, err + } + return obj.(*schedulingv1.PriorityClass), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied priorityClass. +func (c *FakePriorityClasses) Apply(ctx context.Context, priorityClass *applyconfigurationsschedulingv1.PriorityClassApplyConfiguration, opts v1.ApplyOptions) (result *schedulingv1.PriorityClass, err error) { + if priorityClass == nil { + return nil, fmt.Errorf("priorityClass provided to Apply must not be nil") + } + data, err := json.Marshal(priorityClass) + if err != nil { + return nil, err + } + name := priorityClass.Name + if name == nil { + return nil, fmt.Errorf("priorityClass.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(priorityclassesResource, *name, types.ApplyPatchType, data), &schedulingv1.PriorityClass{}) + if obj == nil { + return nil, err + } + return obj.(*schedulingv1.PriorityClass), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1/fake/fake_scheduling_client.go b/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1/fake/fake_scheduling_client.go new file mode 100644 index 000000000..a64ac945b --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1/fake/fake_scheduling_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/client-go/kubernetes/typed/scheduling/v1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeSchedulingV1 struct { + *testing.Fake +} + +func (c *FakeSchedulingV1) PriorityClasses() v1.PriorityClassInterface { + return &FakePriorityClasses{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeSchedulingV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1/fake/fake_priorityclass.go b/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1/fake/fake_priorityclass.go new file mode 100644 index 000000000..32b6a11cb --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1/fake/fake_priorityclass.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1alpha1 "k8s.io/api/scheduling/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + schedulingv1alpha1 "k8s.io/client-go/applyconfigurations/scheduling/v1alpha1" + testing "k8s.io/client-go/testing" +) + +// FakePriorityClasses implements PriorityClassInterface +type FakePriorityClasses struct { + Fake *FakeSchedulingV1alpha1 +} + +var priorityclassesResource = schema.GroupVersionResource{Group: "scheduling.k8s.io", Version: "v1alpha1", Resource: "priorityclasses"} + +var priorityclassesKind = schema.GroupVersionKind{Group: "scheduling.k8s.io", Version: "v1alpha1", Kind: "PriorityClass"} + +// Get takes name of the priorityClass, and returns the corresponding priorityClass object, and an error if there is any. +func (c *FakePriorityClasses) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.PriorityClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(priorityclassesResource, name), &v1alpha1.PriorityClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.PriorityClass), err +} + +// List takes label and field selectors, and returns the list of PriorityClasses that match those selectors. +func (c *FakePriorityClasses) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.PriorityClassList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(priorityclassesResource, priorityclassesKind, opts), &v1alpha1.PriorityClassList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.PriorityClassList{ListMeta: obj.(*v1alpha1.PriorityClassList).ListMeta} + for _, item := range obj.(*v1alpha1.PriorityClassList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested priorityClasses. +func (c *FakePriorityClasses) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(priorityclassesResource, opts)) +} + +// Create takes the representation of a priorityClass and creates it. Returns the server's representation of the priorityClass, and an error, if there is any. +func (c *FakePriorityClasses) Create(ctx context.Context, priorityClass *v1alpha1.PriorityClass, opts v1.CreateOptions) (result *v1alpha1.PriorityClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(priorityclassesResource, priorityClass), &v1alpha1.PriorityClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.PriorityClass), err +} + +// Update takes the representation of a priorityClass and updates it. Returns the server's representation of the priorityClass, and an error, if there is any. +func (c *FakePriorityClasses) Update(ctx context.Context, priorityClass *v1alpha1.PriorityClass, opts v1.UpdateOptions) (result *v1alpha1.PriorityClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(priorityclassesResource, priorityClass), &v1alpha1.PriorityClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.PriorityClass), err +} + +// Delete takes name of the priorityClass and deletes it. Returns an error if one occurs. +func (c *FakePriorityClasses) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(priorityclassesResource, name, opts), &v1alpha1.PriorityClass{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakePriorityClasses) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(priorityclassesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.PriorityClassList{}) + return err +} + +// Patch applies the patch and returns the patched priorityClass. +func (c *FakePriorityClasses) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.PriorityClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(priorityclassesResource, name, pt, data, subresources...), &v1alpha1.PriorityClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.PriorityClass), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied priorityClass. +func (c *FakePriorityClasses) Apply(ctx context.Context, priorityClass *schedulingv1alpha1.PriorityClassApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.PriorityClass, err error) { + if priorityClass == nil { + return nil, fmt.Errorf("priorityClass provided to Apply must not be nil") + } + data, err := json.Marshal(priorityClass) + if err != nil { + return nil, err + } + name := priorityClass.Name + if name == nil { + return nil, fmt.Errorf("priorityClass.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(priorityclassesResource, *name, types.ApplyPatchType, data), &v1alpha1.PriorityClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.PriorityClass), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1/fake/fake_scheduling_client.go b/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1/fake/fake_scheduling_client.go new file mode 100644 index 000000000..974ba193f --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1/fake/fake_scheduling_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeSchedulingV1alpha1 struct { + *testing.Fake +} + +func (c *FakeSchedulingV1alpha1) PriorityClasses() v1alpha1.PriorityClassInterface { + return &FakePriorityClasses{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeSchedulingV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1beta1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1beta1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1beta1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1beta1/fake/fake_priorityclass.go b/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1beta1/fake/fake_priorityclass.go new file mode 100644 index 000000000..8ff5a1bd6 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1beta1/fake/fake_priorityclass.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/scheduling/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + schedulingv1beta1 "k8s.io/client-go/applyconfigurations/scheduling/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakePriorityClasses implements PriorityClassInterface +type FakePriorityClasses struct { + Fake *FakeSchedulingV1beta1 +} + +var priorityclassesResource = schema.GroupVersionResource{Group: "scheduling.k8s.io", Version: "v1beta1", Resource: "priorityclasses"} + +var priorityclassesKind = schema.GroupVersionKind{Group: "scheduling.k8s.io", Version: "v1beta1", Kind: "PriorityClass"} + +// Get takes name of the priorityClass, and returns the corresponding priorityClass object, and an error if there is any. +func (c *FakePriorityClasses) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.PriorityClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(priorityclassesResource, name), &v1beta1.PriorityClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PriorityClass), err +} + +// List takes label and field selectors, and returns the list of PriorityClasses that match those selectors. +func (c *FakePriorityClasses) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.PriorityClassList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(priorityclassesResource, priorityclassesKind, opts), &v1beta1.PriorityClassList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.PriorityClassList{ListMeta: obj.(*v1beta1.PriorityClassList).ListMeta} + for _, item := range obj.(*v1beta1.PriorityClassList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested priorityClasses. +func (c *FakePriorityClasses) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(priorityclassesResource, opts)) +} + +// Create takes the representation of a priorityClass and creates it. Returns the server's representation of the priorityClass, and an error, if there is any. +func (c *FakePriorityClasses) Create(ctx context.Context, priorityClass *v1beta1.PriorityClass, opts v1.CreateOptions) (result *v1beta1.PriorityClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(priorityclassesResource, priorityClass), &v1beta1.PriorityClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PriorityClass), err +} + +// Update takes the representation of a priorityClass and updates it. Returns the server's representation of the priorityClass, and an error, if there is any. +func (c *FakePriorityClasses) Update(ctx context.Context, priorityClass *v1beta1.PriorityClass, opts v1.UpdateOptions) (result *v1beta1.PriorityClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(priorityclassesResource, priorityClass), &v1beta1.PriorityClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PriorityClass), err +} + +// Delete takes name of the priorityClass and deletes it. Returns an error if one occurs. +func (c *FakePriorityClasses) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(priorityclassesResource, name, opts), &v1beta1.PriorityClass{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakePriorityClasses) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(priorityclassesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.PriorityClassList{}) + return err +} + +// Patch applies the patch and returns the patched priorityClass. +func (c *FakePriorityClasses) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.PriorityClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(priorityclassesResource, name, pt, data, subresources...), &v1beta1.PriorityClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PriorityClass), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied priorityClass. +func (c *FakePriorityClasses) Apply(ctx context.Context, priorityClass *schedulingv1beta1.PriorityClassApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.PriorityClass, err error) { + if priorityClass == nil { + return nil, fmt.Errorf("priorityClass provided to Apply must not be nil") + } + data, err := json.Marshal(priorityClass) + if err != nil { + return nil, err + } + name := priorityClass.Name + if name == nil { + return nil, fmt.Errorf("priorityClass.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(priorityclassesResource, *name, types.ApplyPatchType, data), &v1beta1.PriorityClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.PriorityClass), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1beta1/fake/fake_scheduling_client.go b/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1beta1/fake/fake_scheduling_client.go new file mode 100644 index 000000000..4a6878a45 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1beta1/fake/fake_scheduling_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1beta1 "k8s.io/client-go/kubernetes/typed/scheduling/v1beta1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeSchedulingV1beta1 struct { + *testing.Fake +} + +func (c *FakeSchedulingV1beta1) PriorityClasses() v1beta1.PriorityClassInterface { + return &FakePriorityClasses{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeSchedulingV1beta1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_csidriver.go b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_csidriver.go new file mode 100644 index 000000000..42df475dc --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_csidriver.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + storagev1 "k8s.io/api/storage/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsstoragev1 "k8s.io/client-go/applyconfigurations/storage/v1" + testing "k8s.io/client-go/testing" +) + +// FakeCSIDrivers implements CSIDriverInterface +type FakeCSIDrivers struct { + Fake *FakeStorageV1 +} + +var csidriversResource = schema.GroupVersionResource{Group: "storage.k8s.io", Version: "v1", Resource: "csidrivers"} + +var csidriversKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1", Kind: "CSIDriver"} + +// Get takes name of the cSIDriver, and returns the corresponding cSIDriver object, and an error if there is any. +func (c *FakeCSIDrivers) Get(ctx context.Context, name string, options v1.GetOptions) (result *storagev1.CSIDriver, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(csidriversResource, name), &storagev1.CSIDriver{}) + if obj == nil { + return nil, err + } + return obj.(*storagev1.CSIDriver), err +} + +// List takes label and field selectors, and returns the list of CSIDrivers that match those selectors. +func (c *FakeCSIDrivers) List(ctx context.Context, opts v1.ListOptions) (result *storagev1.CSIDriverList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(csidriversResource, csidriversKind, opts), &storagev1.CSIDriverList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &storagev1.CSIDriverList{ListMeta: obj.(*storagev1.CSIDriverList).ListMeta} + for _, item := range obj.(*storagev1.CSIDriverList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested cSIDrivers. +func (c *FakeCSIDrivers) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(csidriversResource, opts)) +} + +// Create takes the representation of a cSIDriver and creates it. Returns the server's representation of the cSIDriver, and an error, if there is any. +func (c *FakeCSIDrivers) Create(ctx context.Context, cSIDriver *storagev1.CSIDriver, opts v1.CreateOptions) (result *storagev1.CSIDriver, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(csidriversResource, cSIDriver), &storagev1.CSIDriver{}) + if obj == nil { + return nil, err + } + return obj.(*storagev1.CSIDriver), err +} + +// Update takes the representation of a cSIDriver and updates it. Returns the server's representation of the cSIDriver, and an error, if there is any. +func (c *FakeCSIDrivers) Update(ctx context.Context, cSIDriver *storagev1.CSIDriver, opts v1.UpdateOptions) (result *storagev1.CSIDriver, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(csidriversResource, cSIDriver), &storagev1.CSIDriver{}) + if obj == nil { + return nil, err + } + return obj.(*storagev1.CSIDriver), err +} + +// Delete takes name of the cSIDriver and deletes it. Returns an error if one occurs. +func (c *FakeCSIDrivers) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(csidriversResource, name, opts), &storagev1.CSIDriver{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeCSIDrivers) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(csidriversResource, listOpts) + + _, err := c.Fake.Invokes(action, &storagev1.CSIDriverList{}) + return err +} + +// Patch applies the patch and returns the patched cSIDriver. +func (c *FakeCSIDrivers) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *storagev1.CSIDriver, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(csidriversResource, name, pt, data, subresources...), &storagev1.CSIDriver{}) + if obj == nil { + return nil, err + } + return obj.(*storagev1.CSIDriver), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied cSIDriver. +func (c *FakeCSIDrivers) Apply(ctx context.Context, cSIDriver *applyconfigurationsstoragev1.CSIDriverApplyConfiguration, opts v1.ApplyOptions) (result *storagev1.CSIDriver, err error) { + if cSIDriver == nil { + return nil, fmt.Errorf("cSIDriver provided to Apply must not be nil") + } + data, err := json.Marshal(cSIDriver) + if err != nil { + return nil, err + } + name := cSIDriver.Name + if name == nil { + return nil, fmt.Errorf("cSIDriver.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(csidriversResource, *name, types.ApplyPatchType, data), &storagev1.CSIDriver{}) + if obj == nil { + return nil, err + } + return obj.(*storagev1.CSIDriver), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_csinode.go b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_csinode.go new file mode 100644 index 000000000..4041d5e63 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_csinode.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + storagev1 "k8s.io/api/storage/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsstoragev1 "k8s.io/client-go/applyconfigurations/storage/v1" + testing "k8s.io/client-go/testing" +) + +// FakeCSINodes implements CSINodeInterface +type FakeCSINodes struct { + Fake *FakeStorageV1 +} + +var csinodesResource = schema.GroupVersionResource{Group: "storage.k8s.io", Version: "v1", Resource: "csinodes"} + +var csinodesKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1", Kind: "CSINode"} + +// Get takes name of the cSINode, and returns the corresponding cSINode object, and an error if there is any. +func (c *FakeCSINodes) Get(ctx context.Context, name string, options v1.GetOptions) (result *storagev1.CSINode, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(csinodesResource, name), &storagev1.CSINode{}) + if obj == nil { + return nil, err + } + return obj.(*storagev1.CSINode), err +} + +// List takes label and field selectors, and returns the list of CSINodes that match those selectors. +func (c *FakeCSINodes) List(ctx context.Context, opts v1.ListOptions) (result *storagev1.CSINodeList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(csinodesResource, csinodesKind, opts), &storagev1.CSINodeList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &storagev1.CSINodeList{ListMeta: obj.(*storagev1.CSINodeList).ListMeta} + for _, item := range obj.(*storagev1.CSINodeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested cSINodes. +func (c *FakeCSINodes) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(csinodesResource, opts)) +} + +// Create takes the representation of a cSINode and creates it. Returns the server's representation of the cSINode, and an error, if there is any. +func (c *FakeCSINodes) Create(ctx context.Context, cSINode *storagev1.CSINode, opts v1.CreateOptions) (result *storagev1.CSINode, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(csinodesResource, cSINode), &storagev1.CSINode{}) + if obj == nil { + return nil, err + } + return obj.(*storagev1.CSINode), err +} + +// Update takes the representation of a cSINode and updates it. Returns the server's representation of the cSINode, and an error, if there is any. +func (c *FakeCSINodes) Update(ctx context.Context, cSINode *storagev1.CSINode, opts v1.UpdateOptions) (result *storagev1.CSINode, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(csinodesResource, cSINode), &storagev1.CSINode{}) + if obj == nil { + return nil, err + } + return obj.(*storagev1.CSINode), err +} + +// Delete takes name of the cSINode and deletes it. Returns an error if one occurs. +func (c *FakeCSINodes) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(csinodesResource, name, opts), &storagev1.CSINode{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeCSINodes) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(csinodesResource, listOpts) + + _, err := c.Fake.Invokes(action, &storagev1.CSINodeList{}) + return err +} + +// Patch applies the patch and returns the patched cSINode. +func (c *FakeCSINodes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *storagev1.CSINode, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(csinodesResource, name, pt, data, subresources...), &storagev1.CSINode{}) + if obj == nil { + return nil, err + } + return obj.(*storagev1.CSINode), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied cSINode. +func (c *FakeCSINodes) Apply(ctx context.Context, cSINode *applyconfigurationsstoragev1.CSINodeApplyConfiguration, opts v1.ApplyOptions) (result *storagev1.CSINode, err error) { + if cSINode == nil { + return nil, fmt.Errorf("cSINode provided to Apply must not be nil") + } + data, err := json.Marshal(cSINode) + if err != nil { + return nil, err + } + name := cSINode.Name + if name == nil { + return nil, fmt.Errorf("cSINode.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(csinodesResource, *name, types.ApplyPatchType, data), &storagev1.CSINode{}) + if obj == nil { + return nil, err + } + return obj.(*storagev1.CSINode), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_csistoragecapacity.go b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_csistoragecapacity.go new file mode 100644 index 000000000..40c4171c8 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_csistoragecapacity.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + storagev1 "k8s.io/api/storage/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsstoragev1 "k8s.io/client-go/applyconfigurations/storage/v1" + testing "k8s.io/client-go/testing" +) + +// FakeCSIStorageCapacities implements CSIStorageCapacityInterface +type FakeCSIStorageCapacities struct { + Fake *FakeStorageV1 + ns string +} + +var csistoragecapacitiesResource = schema.GroupVersionResource{Group: "storage.k8s.io", Version: "v1", Resource: "csistoragecapacities"} + +var csistoragecapacitiesKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1", Kind: "CSIStorageCapacity"} + +// Get takes name of the cSIStorageCapacity, and returns the corresponding cSIStorageCapacity object, and an error if there is any. +func (c *FakeCSIStorageCapacities) Get(ctx context.Context, name string, options v1.GetOptions) (result *storagev1.CSIStorageCapacity, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(csistoragecapacitiesResource, c.ns, name), &storagev1.CSIStorageCapacity{}) + + if obj == nil { + return nil, err + } + return obj.(*storagev1.CSIStorageCapacity), err +} + +// List takes label and field selectors, and returns the list of CSIStorageCapacities that match those selectors. +func (c *FakeCSIStorageCapacities) List(ctx context.Context, opts v1.ListOptions) (result *storagev1.CSIStorageCapacityList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(csistoragecapacitiesResource, csistoragecapacitiesKind, c.ns, opts), &storagev1.CSIStorageCapacityList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &storagev1.CSIStorageCapacityList{ListMeta: obj.(*storagev1.CSIStorageCapacityList).ListMeta} + for _, item := range obj.(*storagev1.CSIStorageCapacityList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested cSIStorageCapacities. +func (c *FakeCSIStorageCapacities) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(csistoragecapacitiesResource, c.ns, opts)) + +} + +// Create takes the representation of a cSIStorageCapacity and creates it. Returns the server's representation of the cSIStorageCapacity, and an error, if there is any. +func (c *FakeCSIStorageCapacities) Create(ctx context.Context, cSIStorageCapacity *storagev1.CSIStorageCapacity, opts v1.CreateOptions) (result *storagev1.CSIStorageCapacity, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(csistoragecapacitiesResource, c.ns, cSIStorageCapacity), &storagev1.CSIStorageCapacity{}) + + if obj == nil { + return nil, err + } + return obj.(*storagev1.CSIStorageCapacity), err +} + +// Update takes the representation of a cSIStorageCapacity and updates it. Returns the server's representation of the cSIStorageCapacity, and an error, if there is any. +func (c *FakeCSIStorageCapacities) Update(ctx context.Context, cSIStorageCapacity *storagev1.CSIStorageCapacity, opts v1.UpdateOptions) (result *storagev1.CSIStorageCapacity, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(csistoragecapacitiesResource, c.ns, cSIStorageCapacity), &storagev1.CSIStorageCapacity{}) + + if obj == nil { + return nil, err + } + return obj.(*storagev1.CSIStorageCapacity), err +} + +// Delete takes name of the cSIStorageCapacity and deletes it. Returns an error if one occurs. +func (c *FakeCSIStorageCapacities) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(csistoragecapacitiesResource, c.ns, name, opts), &storagev1.CSIStorageCapacity{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeCSIStorageCapacities) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(csistoragecapacitiesResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &storagev1.CSIStorageCapacityList{}) + return err +} + +// Patch applies the patch and returns the patched cSIStorageCapacity. +func (c *FakeCSIStorageCapacities) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *storagev1.CSIStorageCapacity, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(csistoragecapacitiesResource, c.ns, name, pt, data, subresources...), &storagev1.CSIStorageCapacity{}) + + if obj == nil { + return nil, err + } + return obj.(*storagev1.CSIStorageCapacity), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied cSIStorageCapacity. +func (c *FakeCSIStorageCapacities) Apply(ctx context.Context, cSIStorageCapacity *applyconfigurationsstoragev1.CSIStorageCapacityApplyConfiguration, opts v1.ApplyOptions) (result *storagev1.CSIStorageCapacity, err error) { + if cSIStorageCapacity == nil { + return nil, fmt.Errorf("cSIStorageCapacity provided to Apply must not be nil") + } + data, err := json.Marshal(cSIStorageCapacity) + if err != nil { + return nil, err + } + name := cSIStorageCapacity.Name + if name == nil { + return nil, fmt.Errorf("cSIStorageCapacity.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(csistoragecapacitiesResource, c.ns, *name, types.ApplyPatchType, data), &storagev1.CSIStorageCapacity{}) + + if obj == nil { + return nil, err + } + return obj.(*storagev1.CSIStorageCapacity), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_storage_client.go b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_storage_client.go new file mode 100644 index 000000000..5cb91b516 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_storage_client.go @@ -0,0 +1,56 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/client-go/kubernetes/typed/storage/v1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeStorageV1 struct { + *testing.Fake +} + +func (c *FakeStorageV1) CSIDrivers() v1.CSIDriverInterface { + return &FakeCSIDrivers{c} +} + +func (c *FakeStorageV1) CSINodes() v1.CSINodeInterface { + return &FakeCSINodes{c} +} + +func (c *FakeStorageV1) CSIStorageCapacities(namespace string) v1.CSIStorageCapacityInterface { + return &FakeCSIStorageCapacities{c, namespace} +} + +func (c *FakeStorageV1) StorageClasses() v1.StorageClassInterface { + return &FakeStorageClasses{c} +} + +func (c *FakeStorageV1) VolumeAttachments() v1.VolumeAttachmentInterface { + return &FakeVolumeAttachments{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeStorageV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_storageclass.go b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_storageclass.go new file mode 100644 index 000000000..60895be5b --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_storageclass.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + storagev1 "k8s.io/api/storage/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsstoragev1 "k8s.io/client-go/applyconfigurations/storage/v1" + testing "k8s.io/client-go/testing" +) + +// FakeStorageClasses implements StorageClassInterface +type FakeStorageClasses struct { + Fake *FakeStorageV1 +} + +var storageclassesResource = schema.GroupVersionResource{Group: "storage.k8s.io", Version: "v1", Resource: "storageclasses"} + +var storageclassesKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1", Kind: "StorageClass"} + +// Get takes name of the storageClass, and returns the corresponding storageClass object, and an error if there is any. +func (c *FakeStorageClasses) Get(ctx context.Context, name string, options v1.GetOptions) (result *storagev1.StorageClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(storageclassesResource, name), &storagev1.StorageClass{}) + if obj == nil { + return nil, err + } + return obj.(*storagev1.StorageClass), err +} + +// List takes label and field selectors, and returns the list of StorageClasses that match those selectors. +func (c *FakeStorageClasses) List(ctx context.Context, opts v1.ListOptions) (result *storagev1.StorageClassList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(storageclassesResource, storageclassesKind, opts), &storagev1.StorageClassList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &storagev1.StorageClassList{ListMeta: obj.(*storagev1.StorageClassList).ListMeta} + for _, item := range obj.(*storagev1.StorageClassList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested storageClasses. +func (c *FakeStorageClasses) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(storageclassesResource, opts)) +} + +// Create takes the representation of a storageClass and creates it. Returns the server's representation of the storageClass, and an error, if there is any. +func (c *FakeStorageClasses) Create(ctx context.Context, storageClass *storagev1.StorageClass, opts v1.CreateOptions) (result *storagev1.StorageClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(storageclassesResource, storageClass), &storagev1.StorageClass{}) + if obj == nil { + return nil, err + } + return obj.(*storagev1.StorageClass), err +} + +// Update takes the representation of a storageClass and updates it. Returns the server's representation of the storageClass, and an error, if there is any. +func (c *FakeStorageClasses) Update(ctx context.Context, storageClass *storagev1.StorageClass, opts v1.UpdateOptions) (result *storagev1.StorageClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(storageclassesResource, storageClass), &storagev1.StorageClass{}) + if obj == nil { + return nil, err + } + return obj.(*storagev1.StorageClass), err +} + +// Delete takes name of the storageClass and deletes it. Returns an error if one occurs. +func (c *FakeStorageClasses) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(storageclassesResource, name, opts), &storagev1.StorageClass{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeStorageClasses) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(storageclassesResource, listOpts) + + _, err := c.Fake.Invokes(action, &storagev1.StorageClassList{}) + return err +} + +// Patch applies the patch and returns the patched storageClass. +func (c *FakeStorageClasses) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *storagev1.StorageClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(storageclassesResource, name, pt, data, subresources...), &storagev1.StorageClass{}) + if obj == nil { + return nil, err + } + return obj.(*storagev1.StorageClass), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied storageClass. +func (c *FakeStorageClasses) Apply(ctx context.Context, storageClass *applyconfigurationsstoragev1.StorageClassApplyConfiguration, opts v1.ApplyOptions) (result *storagev1.StorageClass, err error) { + if storageClass == nil { + return nil, fmt.Errorf("storageClass provided to Apply must not be nil") + } + data, err := json.Marshal(storageClass) + if err != nil { + return nil, err + } + name := storageClass.Name + if name == nil { + return nil, fmt.Errorf("storageClass.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(storageclassesResource, *name, types.ApplyPatchType, data), &storagev1.StorageClass{}) + if obj == nil { + return nil, err + } + return obj.(*storagev1.StorageClass), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_volumeattachment.go b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_volumeattachment.go new file mode 100644 index 000000000..e48943f8e --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1/fake/fake_volumeattachment.go @@ -0,0 +1,179 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + storagev1 "k8s.io/api/storage/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + applyconfigurationsstoragev1 "k8s.io/client-go/applyconfigurations/storage/v1" + testing "k8s.io/client-go/testing" +) + +// FakeVolumeAttachments implements VolumeAttachmentInterface +type FakeVolumeAttachments struct { + Fake *FakeStorageV1 +} + +var volumeattachmentsResource = schema.GroupVersionResource{Group: "storage.k8s.io", Version: "v1", Resource: "volumeattachments"} + +var volumeattachmentsKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1", Kind: "VolumeAttachment"} + +// Get takes name of the volumeAttachment, and returns the corresponding volumeAttachment object, and an error if there is any. +func (c *FakeVolumeAttachments) Get(ctx context.Context, name string, options v1.GetOptions) (result *storagev1.VolumeAttachment, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(volumeattachmentsResource, name), &storagev1.VolumeAttachment{}) + if obj == nil { + return nil, err + } + return obj.(*storagev1.VolumeAttachment), err +} + +// List takes label and field selectors, and returns the list of VolumeAttachments that match those selectors. +func (c *FakeVolumeAttachments) List(ctx context.Context, opts v1.ListOptions) (result *storagev1.VolumeAttachmentList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(volumeattachmentsResource, volumeattachmentsKind, opts), &storagev1.VolumeAttachmentList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &storagev1.VolumeAttachmentList{ListMeta: obj.(*storagev1.VolumeAttachmentList).ListMeta} + for _, item := range obj.(*storagev1.VolumeAttachmentList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested volumeAttachments. +func (c *FakeVolumeAttachments) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(volumeattachmentsResource, opts)) +} + +// Create takes the representation of a volumeAttachment and creates it. Returns the server's representation of the volumeAttachment, and an error, if there is any. +func (c *FakeVolumeAttachments) Create(ctx context.Context, volumeAttachment *storagev1.VolumeAttachment, opts v1.CreateOptions) (result *storagev1.VolumeAttachment, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(volumeattachmentsResource, volumeAttachment), &storagev1.VolumeAttachment{}) + if obj == nil { + return nil, err + } + return obj.(*storagev1.VolumeAttachment), err +} + +// Update takes the representation of a volumeAttachment and updates it. Returns the server's representation of the volumeAttachment, and an error, if there is any. +func (c *FakeVolumeAttachments) Update(ctx context.Context, volumeAttachment *storagev1.VolumeAttachment, opts v1.UpdateOptions) (result *storagev1.VolumeAttachment, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(volumeattachmentsResource, volumeAttachment), &storagev1.VolumeAttachment{}) + if obj == nil { + return nil, err + } + return obj.(*storagev1.VolumeAttachment), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeVolumeAttachments) UpdateStatus(ctx context.Context, volumeAttachment *storagev1.VolumeAttachment, opts v1.UpdateOptions) (*storagev1.VolumeAttachment, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(volumeattachmentsResource, "status", volumeAttachment), &storagev1.VolumeAttachment{}) + if obj == nil { + return nil, err + } + return obj.(*storagev1.VolumeAttachment), err +} + +// Delete takes name of the volumeAttachment and deletes it. Returns an error if one occurs. +func (c *FakeVolumeAttachments) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(volumeattachmentsResource, name, opts), &storagev1.VolumeAttachment{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeVolumeAttachments) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(volumeattachmentsResource, listOpts) + + _, err := c.Fake.Invokes(action, &storagev1.VolumeAttachmentList{}) + return err +} + +// Patch applies the patch and returns the patched volumeAttachment. +func (c *FakeVolumeAttachments) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *storagev1.VolumeAttachment, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(volumeattachmentsResource, name, pt, data, subresources...), &storagev1.VolumeAttachment{}) + if obj == nil { + return nil, err + } + return obj.(*storagev1.VolumeAttachment), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied volumeAttachment. +func (c *FakeVolumeAttachments) Apply(ctx context.Context, volumeAttachment *applyconfigurationsstoragev1.VolumeAttachmentApplyConfiguration, opts v1.ApplyOptions) (result *storagev1.VolumeAttachment, err error) { + if volumeAttachment == nil { + return nil, fmt.Errorf("volumeAttachment provided to Apply must not be nil") + } + data, err := json.Marshal(volumeAttachment) + if err != nil { + return nil, err + } + name := volumeAttachment.Name + if name == nil { + return nil, fmt.Errorf("volumeAttachment.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(volumeattachmentsResource, *name, types.ApplyPatchType, data), &storagev1.VolumeAttachment{}) + if obj == nil { + return nil, err + } + return obj.(*storagev1.VolumeAttachment), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeVolumeAttachments) ApplyStatus(ctx context.Context, volumeAttachment *applyconfigurationsstoragev1.VolumeAttachmentApplyConfiguration, opts v1.ApplyOptions) (result *storagev1.VolumeAttachment, err error) { + if volumeAttachment == nil { + return nil, fmt.Errorf("volumeAttachment provided to Apply must not be nil") + } + data, err := json.Marshal(volumeAttachment) + if err != nil { + return nil, err + } + name := volumeAttachment.Name + if name == nil { + return nil, fmt.Errorf("volumeAttachment.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(volumeattachmentsResource, *name, types.ApplyPatchType, data, "status"), &storagev1.VolumeAttachment{}) + if obj == nil { + return nil, err + } + return obj.(*storagev1.VolumeAttachment), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/storage/v1alpha1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1alpha1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1alpha1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/storage/v1alpha1/fake/fake_csistoragecapacity.go b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1alpha1/fake/fake_csistoragecapacity.go new file mode 100644 index 000000000..f56ed7895 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1alpha1/fake/fake_csistoragecapacity.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1alpha1 "k8s.io/api/storage/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + storagev1alpha1 "k8s.io/client-go/applyconfigurations/storage/v1alpha1" + testing "k8s.io/client-go/testing" +) + +// FakeCSIStorageCapacities implements CSIStorageCapacityInterface +type FakeCSIStorageCapacities struct { + Fake *FakeStorageV1alpha1 + ns string +} + +var csistoragecapacitiesResource = schema.GroupVersionResource{Group: "storage.k8s.io", Version: "v1alpha1", Resource: "csistoragecapacities"} + +var csistoragecapacitiesKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1alpha1", Kind: "CSIStorageCapacity"} + +// Get takes name of the cSIStorageCapacity, and returns the corresponding cSIStorageCapacity object, and an error if there is any. +func (c *FakeCSIStorageCapacities) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.CSIStorageCapacity, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(csistoragecapacitiesResource, c.ns, name), &v1alpha1.CSIStorageCapacity{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.CSIStorageCapacity), err +} + +// List takes label and field selectors, and returns the list of CSIStorageCapacities that match those selectors. +func (c *FakeCSIStorageCapacities) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.CSIStorageCapacityList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(csistoragecapacitiesResource, csistoragecapacitiesKind, c.ns, opts), &v1alpha1.CSIStorageCapacityList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.CSIStorageCapacityList{ListMeta: obj.(*v1alpha1.CSIStorageCapacityList).ListMeta} + for _, item := range obj.(*v1alpha1.CSIStorageCapacityList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested cSIStorageCapacities. +func (c *FakeCSIStorageCapacities) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(csistoragecapacitiesResource, c.ns, opts)) + +} + +// Create takes the representation of a cSIStorageCapacity and creates it. Returns the server's representation of the cSIStorageCapacity, and an error, if there is any. +func (c *FakeCSIStorageCapacities) Create(ctx context.Context, cSIStorageCapacity *v1alpha1.CSIStorageCapacity, opts v1.CreateOptions) (result *v1alpha1.CSIStorageCapacity, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(csistoragecapacitiesResource, c.ns, cSIStorageCapacity), &v1alpha1.CSIStorageCapacity{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.CSIStorageCapacity), err +} + +// Update takes the representation of a cSIStorageCapacity and updates it. Returns the server's representation of the cSIStorageCapacity, and an error, if there is any. +func (c *FakeCSIStorageCapacities) Update(ctx context.Context, cSIStorageCapacity *v1alpha1.CSIStorageCapacity, opts v1.UpdateOptions) (result *v1alpha1.CSIStorageCapacity, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(csistoragecapacitiesResource, c.ns, cSIStorageCapacity), &v1alpha1.CSIStorageCapacity{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.CSIStorageCapacity), err +} + +// Delete takes name of the cSIStorageCapacity and deletes it. Returns an error if one occurs. +func (c *FakeCSIStorageCapacities) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(csistoragecapacitiesResource, c.ns, name, opts), &v1alpha1.CSIStorageCapacity{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeCSIStorageCapacities) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(csistoragecapacitiesResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.CSIStorageCapacityList{}) + return err +} + +// Patch applies the patch and returns the patched cSIStorageCapacity. +func (c *FakeCSIStorageCapacities) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.CSIStorageCapacity, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(csistoragecapacitiesResource, c.ns, name, pt, data, subresources...), &v1alpha1.CSIStorageCapacity{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.CSIStorageCapacity), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied cSIStorageCapacity. +func (c *FakeCSIStorageCapacities) Apply(ctx context.Context, cSIStorageCapacity *storagev1alpha1.CSIStorageCapacityApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.CSIStorageCapacity, err error) { + if cSIStorageCapacity == nil { + return nil, fmt.Errorf("cSIStorageCapacity provided to Apply must not be nil") + } + data, err := json.Marshal(cSIStorageCapacity) + if err != nil { + return nil, err + } + name := cSIStorageCapacity.Name + if name == nil { + return nil, fmt.Errorf("cSIStorageCapacity.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(csistoragecapacitiesResource, c.ns, *name, types.ApplyPatchType, data), &v1alpha1.CSIStorageCapacity{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.CSIStorageCapacity), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/storage/v1alpha1/fake/fake_storage_client.go b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1alpha1/fake/fake_storage_client.go new file mode 100644 index 000000000..c26190aa0 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1alpha1/fake/fake_storage_client.go @@ -0,0 +1,44 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "k8s.io/client-go/kubernetes/typed/storage/v1alpha1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeStorageV1alpha1 struct { + *testing.Fake +} + +func (c *FakeStorageV1alpha1) CSIStorageCapacities(namespace string) v1alpha1.CSIStorageCapacityInterface { + return &FakeCSIStorageCapacities{c, namespace} +} + +func (c *FakeStorageV1alpha1) VolumeAttachments() v1alpha1.VolumeAttachmentInterface { + return &FakeVolumeAttachments{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeStorageV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/storage/v1alpha1/fake/fake_volumeattachment.go b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1alpha1/fake/fake_volumeattachment.go new file mode 100644 index 000000000..eb6ec7983 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1alpha1/fake/fake_volumeattachment.go @@ -0,0 +1,179 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1alpha1 "k8s.io/api/storage/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + storagev1alpha1 "k8s.io/client-go/applyconfigurations/storage/v1alpha1" + testing "k8s.io/client-go/testing" +) + +// FakeVolumeAttachments implements VolumeAttachmentInterface +type FakeVolumeAttachments struct { + Fake *FakeStorageV1alpha1 +} + +var volumeattachmentsResource = schema.GroupVersionResource{Group: "storage.k8s.io", Version: "v1alpha1", Resource: "volumeattachments"} + +var volumeattachmentsKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1alpha1", Kind: "VolumeAttachment"} + +// Get takes name of the volumeAttachment, and returns the corresponding volumeAttachment object, and an error if there is any. +func (c *FakeVolumeAttachments) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.VolumeAttachment, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(volumeattachmentsResource, name), &v1alpha1.VolumeAttachment{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.VolumeAttachment), err +} + +// List takes label and field selectors, and returns the list of VolumeAttachments that match those selectors. +func (c *FakeVolumeAttachments) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.VolumeAttachmentList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(volumeattachmentsResource, volumeattachmentsKind, opts), &v1alpha1.VolumeAttachmentList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.VolumeAttachmentList{ListMeta: obj.(*v1alpha1.VolumeAttachmentList).ListMeta} + for _, item := range obj.(*v1alpha1.VolumeAttachmentList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested volumeAttachments. +func (c *FakeVolumeAttachments) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(volumeattachmentsResource, opts)) +} + +// Create takes the representation of a volumeAttachment and creates it. Returns the server's representation of the volumeAttachment, and an error, if there is any. +func (c *FakeVolumeAttachments) Create(ctx context.Context, volumeAttachment *v1alpha1.VolumeAttachment, opts v1.CreateOptions) (result *v1alpha1.VolumeAttachment, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(volumeattachmentsResource, volumeAttachment), &v1alpha1.VolumeAttachment{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.VolumeAttachment), err +} + +// Update takes the representation of a volumeAttachment and updates it. Returns the server's representation of the volumeAttachment, and an error, if there is any. +func (c *FakeVolumeAttachments) Update(ctx context.Context, volumeAttachment *v1alpha1.VolumeAttachment, opts v1.UpdateOptions) (result *v1alpha1.VolumeAttachment, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(volumeattachmentsResource, volumeAttachment), &v1alpha1.VolumeAttachment{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.VolumeAttachment), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeVolumeAttachments) UpdateStatus(ctx context.Context, volumeAttachment *v1alpha1.VolumeAttachment, opts v1.UpdateOptions) (*v1alpha1.VolumeAttachment, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(volumeattachmentsResource, "status", volumeAttachment), &v1alpha1.VolumeAttachment{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.VolumeAttachment), err +} + +// Delete takes name of the volumeAttachment and deletes it. Returns an error if one occurs. +func (c *FakeVolumeAttachments) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(volumeattachmentsResource, name, opts), &v1alpha1.VolumeAttachment{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeVolumeAttachments) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(volumeattachmentsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.VolumeAttachmentList{}) + return err +} + +// Patch applies the patch and returns the patched volumeAttachment. +func (c *FakeVolumeAttachments) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.VolumeAttachment, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(volumeattachmentsResource, name, pt, data, subresources...), &v1alpha1.VolumeAttachment{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.VolumeAttachment), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied volumeAttachment. +func (c *FakeVolumeAttachments) Apply(ctx context.Context, volumeAttachment *storagev1alpha1.VolumeAttachmentApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.VolumeAttachment, err error) { + if volumeAttachment == nil { + return nil, fmt.Errorf("volumeAttachment provided to Apply must not be nil") + } + data, err := json.Marshal(volumeAttachment) + if err != nil { + return nil, err + } + name := volumeAttachment.Name + if name == nil { + return nil, fmt.Errorf("volumeAttachment.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(volumeattachmentsResource, *name, types.ApplyPatchType, data), &v1alpha1.VolumeAttachment{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.VolumeAttachment), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeVolumeAttachments) ApplyStatus(ctx context.Context, volumeAttachment *storagev1alpha1.VolumeAttachmentApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.VolumeAttachment, err error) { + if volumeAttachment == nil { + return nil, fmt.Errorf("volumeAttachment provided to Apply must not be nil") + } + data, err := json.Marshal(volumeAttachment) + if err != nil { + return nil, err + } + name := volumeAttachment.Name + if name == nil { + return nil, fmt.Errorf("volumeAttachment.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(volumeattachmentsResource, *name, types.ApplyPatchType, data, "status"), &v1alpha1.VolumeAttachment{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.VolumeAttachment), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/doc.go b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_csidriver.go b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_csidriver.go new file mode 100644 index 000000000..c65fa7422 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_csidriver.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/storage/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + storagev1beta1 "k8s.io/client-go/applyconfigurations/storage/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeCSIDrivers implements CSIDriverInterface +type FakeCSIDrivers struct { + Fake *FakeStorageV1beta1 +} + +var csidriversResource = schema.GroupVersionResource{Group: "storage.k8s.io", Version: "v1beta1", Resource: "csidrivers"} + +var csidriversKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1beta1", Kind: "CSIDriver"} + +// Get takes name of the cSIDriver, and returns the corresponding cSIDriver object, and an error if there is any. +func (c *FakeCSIDrivers) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.CSIDriver, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(csidriversResource, name), &v1beta1.CSIDriver{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSIDriver), err +} + +// List takes label and field selectors, and returns the list of CSIDrivers that match those selectors. +func (c *FakeCSIDrivers) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.CSIDriverList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(csidriversResource, csidriversKind, opts), &v1beta1.CSIDriverList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.CSIDriverList{ListMeta: obj.(*v1beta1.CSIDriverList).ListMeta} + for _, item := range obj.(*v1beta1.CSIDriverList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested cSIDrivers. +func (c *FakeCSIDrivers) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(csidriversResource, opts)) +} + +// Create takes the representation of a cSIDriver and creates it. Returns the server's representation of the cSIDriver, and an error, if there is any. +func (c *FakeCSIDrivers) Create(ctx context.Context, cSIDriver *v1beta1.CSIDriver, opts v1.CreateOptions) (result *v1beta1.CSIDriver, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(csidriversResource, cSIDriver), &v1beta1.CSIDriver{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSIDriver), err +} + +// Update takes the representation of a cSIDriver and updates it. Returns the server's representation of the cSIDriver, and an error, if there is any. +func (c *FakeCSIDrivers) Update(ctx context.Context, cSIDriver *v1beta1.CSIDriver, opts v1.UpdateOptions) (result *v1beta1.CSIDriver, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(csidriversResource, cSIDriver), &v1beta1.CSIDriver{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSIDriver), err +} + +// Delete takes name of the cSIDriver and deletes it. Returns an error if one occurs. +func (c *FakeCSIDrivers) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(csidriversResource, name, opts), &v1beta1.CSIDriver{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeCSIDrivers) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(csidriversResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.CSIDriverList{}) + return err +} + +// Patch applies the patch and returns the patched cSIDriver. +func (c *FakeCSIDrivers) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.CSIDriver, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(csidriversResource, name, pt, data, subresources...), &v1beta1.CSIDriver{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSIDriver), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied cSIDriver. +func (c *FakeCSIDrivers) Apply(ctx context.Context, cSIDriver *storagev1beta1.CSIDriverApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.CSIDriver, err error) { + if cSIDriver == nil { + return nil, fmt.Errorf("cSIDriver provided to Apply must not be nil") + } + data, err := json.Marshal(cSIDriver) + if err != nil { + return nil, err + } + name := cSIDriver.Name + if name == nil { + return nil, fmt.Errorf("cSIDriver.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(csidriversResource, *name, types.ApplyPatchType, data), &v1beta1.CSIDriver{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSIDriver), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_csinode.go b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_csinode.go new file mode 100644 index 000000000..1ffd49b3a --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_csinode.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/storage/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + storagev1beta1 "k8s.io/client-go/applyconfigurations/storage/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeCSINodes implements CSINodeInterface +type FakeCSINodes struct { + Fake *FakeStorageV1beta1 +} + +var csinodesResource = schema.GroupVersionResource{Group: "storage.k8s.io", Version: "v1beta1", Resource: "csinodes"} + +var csinodesKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1beta1", Kind: "CSINode"} + +// Get takes name of the cSINode, and returns the corresponding cSINode object, and an error if there is any. +func (c *FakeCSINodes) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.CSINode, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(csinodesResource, name), &v1beta1.CSINode{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSINode), err +} + +// List takes label and field selectors, and returns the list of CSINodes that match those selectors. +func (c *FakeCSINodes) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.CSINodeList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(csinodesResource, csinodesKind, opts), &v1beta1.CSINodeList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.CSINodeList{ListMeta: obj.(*v1beta1.CSINodeList).ListMeta} + for _, item := range obj.(*v1beta1.CSINodeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested cSINodes. +func (c *FakeCSINodes) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(csinodesResource, opts)) +} + +// Create takes the representation of a cSINode and creates it. Returns the server's representation of the cSINode, and an error, if there is any. +func (c *FakeCSINodes) Create(ctx context.Context, cSINode *v1beta1.CSINode, opts v1.CreateOptions) (result *v1beta1.CSINode, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(csinodesResource, cSINode), &v1beta1.CSINode{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSINode), err +} + +// Update takes the representation of a cSINode and updates it. Returns the server's representation of the cSINode, and an error, if there is any. +func (c *FakeCSINodes) Update(ctx context.Context, cSINode *v1beta1.CSINode, opts v1.UpdateOptions) (result *v1beta1.CSINode, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(csinodesResource, cSINode), &v1beta1.CSINode{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSINode), err +} + +// Delete takes name of the cSINode and deletes it. Returns an error if one occurs. +func (c *FakeCSINodes) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(csinodesResource, name, opts), &v1beta1.CSINode{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeCSINodes) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(csinodesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.CSINodeList{}) + return err +} + +// Patch applies the patch and returns the patched cSINode. +func (c *FakeCSINodes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.CSINode, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(csinodesResource, name, pt, data, subresources...), &v1beta1.CSINode{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSINode), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied cSINode. +func (c *FakeCSINodes) Apply(ctx context.Context, cSINode *storagev1beta1.CSINodeApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.CSINode, err error) { + if cSINode == nil { + return nil, fmt.Errorf("cSINode provided to Apply must not be nil") + } + data, err := json.Marshal(cSINode) + if err != nil { + return nil, err + } + name := cSINode.Name + if name == nil { + return nil, fmt.Errorf("cSINode.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(csinodesResource, *name, types.ApplyPatchType, data), &v1beta1.CSINode{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSINode), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_csistoragecapacity.go b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_csistoragecapacity.go new file mode 100644 index 000000000..1715884d1 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_csistoragecapacity.go @@ -0,0 +1,155 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/storage/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + storagev1beta1 "k8s.io/client-go/applyconfigurations/storage/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeCSIStorageCapacities implements CSIStorageCapacityInterface +type FakeCSIStorageCapacities struct { + Fake *FakeStorageV1beta1 + ns string +} + +var csistoragecapacitiesResource = schema.GroupVersionResource{Group: "storage.k8s.io", Version: "v1beta1", Resource: "csistoragecapacities"} + +var csistoragecapacitiesKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1beta1", Kind: "CSIStorageCapacity"} + +// Get takes name of the cSIStorageCapacity, and returns the corresponding cSIStorageCapacity object, and an error if there is any. +func (c *FakeCSIStorageCapacities) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.CSIStorageCapacity, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(csistoragecapacitiesResource, c.ns, name), &v1beta1.CSIStorageCapacity{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSIStorageCapacity), err +} + +// List takes label and field selectors, and returns the list of CSIStorageCapacities that match those selectors. +func (c *FakeCSIStorageCapacities) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.CSIStorageCapacityList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(csistoragecapacitiesResource, csistoragecapacitiesKind, c.ns, opts), &v1beta1.CSIStorageCapacityList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.CSIStorageCapacityList{ListMeta: obj.(*v1beta1.CSIStorageCapacityList).ListMeta} + for _, item := range obj.(*v1beta1.CSIStorageCapacityList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested cSIStorageCapacities. +func (c *FakeCSIStorageCapacities) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(csistoragecapacitiesResource, c.ns, opts)) + +} + +// Create takes the representation of a cSIStorageCapacity and creates it. Returns the server's representation of the cSIStorageCapacity, and an error, if there is any. +func (c *FakeCSIStorageCapacities) Create(ctx context.Context, cSIStorageCapacity *v1beta1.CSIStorageCapacity, opts v1.CreateOptions) (result *v1beta1.CSIStorageCapacity, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(csistoragecapacitiesResource, c.ns, cSIStorageCapacity), &v1beta1.CSIStorageCapacity{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSIStorageCapacity), err +} + +// Update takes the representation of a cSIStorageCapacity and updates it. Returns the server's representation of the cSIStorageCapacity, and an error, if there is any. +func (c *FakeCSIStorageCapacities) Update(ctx context.Context, cSIStorageCapacity *v1beta1.CSIStorageCapacity, opts v1.UpdateOptions) (result *v1beta1.CSIStorageCapacity, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(csistoragecapacitiesResource, c.ns, cSIStorageCapacity), &v1beta1.CSIStorageCapacity{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSIStorageCapacity), err +} + +// Delete takes name of the cSIStorageCapacity and deletes it. Returns an error if one occurs. +func (c *FakeCSIStorageCapacities) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(csistoragecapacitiesResource, c.ns, name, opts), &v1beta1.CSIStorageCapacity{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeCSIStorageCapacities) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(csistoragecapacitiesResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.CSIStorageCapacityList{}) + return err +} + +// Patch applies the patch and returns the patched cSIStorageCapacity. +func (c *FakeCSIStorageCapacities) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.CSIStorageCapacity, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(csistoragecapacitiesResource, c.ns, name, pt, data, subresources...), &v1beta1.CSIStorageCapacity{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSIStorageCapacity), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied cSIStorageCapacity. +func (c *FakeCSIStorageCapacities) Apply(ctx context.Context, cSIStorageCapacity *storagev1beta1.CSIStorageCapacityApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.CSIStorageCapacity, err error) { + if cSIStorageCapacity == nil { + return nil, fmt.Errorf("cSIStorageCapacity provided to Apply must not be nil") + } + data, err := json.Marshal(cSIStorageCapacity) + if err != nil { + return nil, err + } + name := cSIStorageCapacity.Name + if name == nil { + return nil, fmt.Errorf("cSIStorageCapacity.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(csistoragecapacitiesResource, c.ns, *name, types.ApplyPatchType, data), &v1beta1.CSIStorageCapacity{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSIStorageCapacity), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_storage_client.go b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_storage_client.go new file mode 100644 index 000000000..6b5bb02fd --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_storage_client.go @@ -0,0 +1,56 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1beta1 "k8s.io/client-go/kubernetes/typed/storage/v1beta1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeStorageV1beta1 struct { + *testing.Fake +} + +func (c *FakeStorageV1beta1) CSIDrivers() v1beta1.CSIDriverInterface { + return &FakeCSIDrivers{c} +} + +func (c *FakeStorageV1beta1) CSINodes() v1beta1.CSINodeInterface { + return &FakeCSINodes{c} +} + +func (c *FakeStorageV1beta1) CSIStorageCapacities(namespace string) v1beta1.CSIStorageCapacityInterface { + return &FakeCSIStorageCapacities{c, namespace} +} + +func (c *FakeStorageV1beta1) StorageClasses() v1beta1.StorageClassInterface { + return &FakeStorageClasses{c} +} + +func (c *FakeStorageV1beta1) VolumeAttachments() v1beta1.VolumeAttachmentInterface { + return &FakeVolumeAttachments{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeStorageV1beta1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_storageclass.go b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_storageclass.go new file mode 100644 index 000000000..f929c55f8 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_storageclass.go @@ -0,0 +1,146 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/storage/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + storagev1beta1 "k8s.io/client-go/applyconfigurations/storage/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeStorageClasses implements StorageClassInterface +type FakeStorageClasses struct { + Fake *FakeStorageV1beta1 +} + +var storageclassesResource = schema.GroupVersionResource{Group: "storage.k8s.io", Version: "v1beta1", Resource: "storageclasses"} + +var storageclassesKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1beta1", Kind: "StorageClass"} + +// Get takes name of the storageClass, and returns the corresponding storageClass object, and an error if there is any. +func (c *FakeStorageClasses) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.StorageClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(storageclassesResource, name), &v1beta1.StorageClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.StorageClass), err +} + +// List takes label and field selectors, and returns the list of StorageClasses that match those selectors. +func (c *FakeStorageClasses) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.StorageClassList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(storageclassesResource, storageclassesKind, opts), &v1beta1.StorageClassList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.StorageClassList{ListMeta: obj.(*v1beta1.StorageClassList).ListMeta} + for _, item := range obj.(*v1beta1.StorageClassList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested storageClasses. +func (c *FakeStorageClasses) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(storageclassesResource, opts)) +} + +// Create takes the representation of a storageClass and creates it. Returns the server's representation of the storageClass, and an error, if there is any. +func (c *FakeStorageClasses) Create(ctx context.Context, storageClass *v1beta1.StorageClass, opts v1.CreateOptions) (result *v1beta1.StorageClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(storageclassesResource, storageClass), &v1beta1.StorageClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.StorageClass), err +} + +// Update takes the representation of a storageClass and updates it. Returns the server's representation of the storageClass, and an error, if there is any. +func (c *FakeStorageClasses) Update(ctx context.Context, storageClass *v1beta1.StorageClass, opts v1.UpdateOptions) (result *v1beta1.StorageClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(storageclassesResource, storageClass), &v1beta1.StorageClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.StorageClass), err +} + +// Delete takes name of the storageClass and deletes it. Returns an error if one occurs. +func (c *FakeStorageClasses) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(storageclassesResource, name, opts), &v1beta1.StorageClass{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeStorageClasses) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(storageclassesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.StorageClassList{}) + return err +} + +// Patch applies the patch and returns the patched storageClass. +func (c *FakeStorageClasses) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.StorageClass, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(storageclassesResource, name, pt, data, subresources...), &v1beta1.StorageClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.StorageClass), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied storageClass. +func (c *FakeStorageClasses) Apply(ctx context.Context, storageClass *storagev1beta1.StorageClassApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.StorageClass, err error) { + if storageClass == nil { + return nil, fmt.Errorf("storageClass provided to Apply must not be nil") + } + data, err := json.Marshal(storageClass) + if err != nil { + return nil, err + } + name := storageClass.Name + if name == nil { + return nil, fmt.Errorf("storageClass.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(storageclassesResource, *name, types.ApplyPatchType, data), &v1beta1.StorageClass{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.StorageClass), err +} diff --git a/vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_volumeattachment.go b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_volumeattachment.go new file mode 100644 index 000000000..81df87769 --- /dev/null +++ b/vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_volumeattachment.go @@ -0,0 +1,179 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1beta1 "k8s.io/api/storage/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + storagev1beta1 "k8s.io/client-go/applyconfigurations/storage/v1beta1" + testing "k8s.io/client-go/testing" +) + +// FakeVolumeAttachments implements VolumeAttachmentInterface +type FakeVolumeAttachments struct { + Fake *FakeStorageV1beta1 +} + +var volumeattachmentsResource = schema.GroupVersionResource{Group: "storage.k8s.io", Version: "v1beta1", Resource: "volumeattachments"} + +var volumeattachmentsKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1beta1", Kind: "VolumeAttachment"} + +// Get takes name of the volumeAttachment, and returns the corresponding volumeAttachment object, and an error if there is any. +func (c *FakeVolumeAttachments) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.VolumeAttachment, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(volumeattachmentsResource, name), &v1beta1.VolumeAttachment{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.VolumeAttachment), err +} + +// List takes label and field selectors, and returns the list of VolumeAttachments that match those selectors. +func (c *FakeVolumeAttachments) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.VolumeAttachmentList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(volumeattachmentsResource, volumeattachmentsKind, opts), &v1beta1.VolumeAttachmentList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.VolumeAttachmentList{ListMeta: obj.(*v1beta1.VolumeAttachmentList).ListMeta} + for _, item := range obj.(*v1beta1.VolumeAttachmentList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested volumeAttachments. +func (c *FakeVolumeAttachments) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(volumeattachmentsResource, opts)) +} + +// Create takes the representation of a volumeAttachment and creates it. Returns the server's representation of the volumeAttachment, and an error, if there is any. +func (c *FakeVolumeAttachments) Create(ctx context.Context, volumeAttachment *v1beta1.VolumeAttachment, opts v1.CreateOptions) (result *v1beta1.VolumeAttachment, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(volumeattachmentsResource, volumeAttachment), &v1beta1.VolumeAttachment{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.VolumeAttachment), err +} + +// Update takes the representation of a volumeAttachment and updates it. Returns the server's representation of the volumeAttachment, and an error, if there is any. +func (c *FakeVolumeAttachments) Update(ctx context.Context, volumeAttachment *v1beta1.VolumeAttachment, opts v1.UpdateOptions) (result *v1beta1.VolumeAttachment, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(volumeattachmentsResource, volumeAttachment), &v1beta1.VolumeAttachment{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.VolumeAttachment), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeVolumeAttachments) UpdateStatus(ctx context.Context, volumeAttachment *v1beta1.VolumeAttachment, opts v1.UpdateOptions) (*v1beta1.VolumeAttachment, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(volumeattachmentsResource, "status", volumeAttachment), &v1beta1.VolumeAttachment{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.VolumeAttachment), err +} + +// Delete takes name of the volumeAttachment and deletes it. Returns an error if one occurs. +func (c *FakeVolumeAttachments) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(volumeattachmentsResource, name, opts), &v1beta1.VolumeAttachment{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeVolumeAttachments) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(volumeattachmentsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.VolumeAttachmentList{}) + return err +} + +// Patch applies the patch and returns the patched volumeAttachment. +func (c *FakeVolumeAttachments) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.VolumeAttachment, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(volumeattachmentsResource, name, pt, data, subresources...), &v1beta1.VolumeAttachment{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.VolumeAttachment), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied volumeAttachment. +func (c *FakeVolumeAttachments) Apply(ctx context.Context, volumeAttachment *storagev1beta1.VolumeAttachmentApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.VolumeAttachment, err error) { + if volumeAttachment == nil { + return nil, fmt.Errorf("volumeAttachment provided to Apply must not be nil") + } + data, err := json.Marshal(volumeAttachment) + if err != nil { + return nil, err + } + name := volumeAttachment.Name + if name == nil { + return nil, fmt.Errorf("volumeAttachment.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(volumeattachmentsResource, *name, types.ApplyPatchType, data), &v1beta1.VolumeAttachment{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.VolumeAttachment), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeVolumeAttachments) ApplyStatus(ctx context.Context, volumeAttachment *storagev1beta1.VolumeAttachmentApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.VolumeAttachment, err error) { + if volumeAttachment == nil { + return nil, fmt.Errorf("volumeAttachment provided to Apply must not be nil") + } + data, err := json.Marshal(volumeAttachment) + if err != nil { + return nil, err + } + name := volumeAttachment.Name + if name == nil { + return nil, fmt.Errorf("volumeAttachment.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(volumeattachmentsResource, *name, types.ApplyPatchType, data, "status"), &v1beta1.VolumeAttachment{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.VolumeAttachment), err +} diff --git a/vendor/k8s.io/client-go/rest/fake/fake.go b/vendor/k8s.io/client-go/rest/fake/fake.go new file mode 100644 index 000000000..293e09694 --- /dev/null +++ b/vendor/k8s.io/client-go/rest/fake/fake.go @@ -0,0 +1,118 @@ +/* +Copyright 2014 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. +*/ + +// This is made a separate package and should only be imported by tests, because +// it imports testapi +package fake + +import ( + "net/http" + "net/url" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + restclient "k8s.io/client-go/rest" + "k8s.io/client-go/util/flowcontrol" +) + +// CreateHTTPClient creates an http.Client that will invoke the provided roundTripper func +// when a request is made. +func CreateHTTPClient(roundTripper func(*http.Request) (*http.Response, error)) *http.Client { + return &http.Client{ + Transport: roundTripperFunc(roundTripper), + } +} + +type roundTripperFunc func(*http.Request) (*http.Response, error) + +func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) { + return f(req) +} + +// RESTClient provides a fake RESTClient interface. It is used to mock network +// interactions via a rest.Request, or to make them via the provided Client to +// a specific server. +type RESTClient struct { + NegotiatedSerializer runtime.NegotiatedSerializer + GroupVersion schema.GroupVersion + VersionedAPIPath string + + // Err is returned when any request would be made to the server. If Err is set, + // Req will not be recorded, Resp will not be returned, and Client will not be + // invoked. + Err error + // Req is set to the last request that was executed (had the methods Do/DoRaw) invoked. + Req *http.Request + // If Client is specified, the client will be invoked instead of returning Resp if + // Err is not set. + Client *http.Client + // Resp is returned to the caller after Req is recorded, unless Err or Client are set. + Resp *http.Response +} + +func (c *RESTClient) Get() *restclient.Request { + return c.Verb("GET") +} + +func (c *RESTClient) Put() *restclient.Request { + return c.Verb("PUT") +} + +func (c *RESTClient) Patch(pt types.PatchType) *restclient.Request { + return c.Verb("PATCH").SetHeader("Content-Type", string(pt)) +} + +func (c *RESTClient) Post() *restclient.Request { + return c.Verb("POST") +} + +func (c *RESTClient) Delete() *restclient.Request { + return c.Verb("DELETE") +} + +func (c *RESTClient) Verb(verb string) *restclient.Request { + return c.Request().Verb(verb) +} + +func (c *RESTClient) APIVersion() schema.GroupVersion { + return c.GroupVersion +} + +func (c *RESTClient) GetRateLimiter() flowcontrol.RateLimiter { + return nil +} + +func (c *RESTClient) Request() *restclient.Request { + config := restclient.ClientContentConfig{ + ContentType: runtime.ContentTypeJSON, + GroupVersion: c.GroupVersion, + Negotiator: runtime.NewClientNegotiator(c.NegotiatedSerializer, c.GroupVersion), + } + return restclient.NewRequestWithClient(&url.URL{Scheme: "https", Host: "localhost"}, c.VersionedAPIPath, config, CreateHTTPClient(c.do)) +} + +// do is invoked when a Request() created by this client is executed. +func (c *RESTClient) do(req *http.Request) (*http.Response, error) { + if c.Err != nil { + return nil, c.Err + } + c.Req = req + if c.Client != nil { + return c.Client.Do(req) + } + return c.Resp, nil +} diff --git a/vendor/k8s.io/cloud-provider/CONTRIBUTING.md b/vendor/k8s.io/cloud-provider/CONTRIBUTING.md new file mode 100644 index 000000000..fe4643fdb --- /dev/null +++ b/vendor/k8s.io/cloud-provider/CONTRIBUTING.md @@ -0,0 +1,9 @@ +# Contributing guidelines + +Welcome to Kubernetes. We are excited about the prospect of you joining our [community](https://github.com/kubernetes/community)! The Kubernetes community abides by the CNCF [code of conduct](code-of-conduct.md). + +Do not open pull requests directly against this repository, they will be ignored. Instead, please open pull requests against [kubernetes/kubernetes](https://git.k8s.io/kubernetes/). Please follow the same [contributing guide](https://git.k8s.io/kubernetes/CONTRIBUTING.md) you would follow for any other pull request made to kubernetes/kubernetes. Changes to this repo should be discussed with [sig cloud-provider](https://github.com/kubernetes/community/tree/master/sig-cloud-provider). + +This repository is published from [kubernetes/kubernetes/staging/src/k8s.io/cloud-provider](https://git.k8s.io/kubernetes/staging/src/k8s.io/cloud-provider) by the [kubernetes publishing-bot](https://git.k8s.io/publishing-bot). + +Please see [Staging Directory and Publishing](https://git.k8s.io/community/contributors/devel/sig-architecture/staging.md) for more information diff --git a/vendor/k8s.io/cloud-provider/LICENSE b/vendor/k8s.io/cloud-provider/LICENSE new file mode 100644 index 000000000..8dada3eda --- /dev/null +++ b/vendor/k8s.io/cloud-provider/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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. diff --git a/vendor/k8s.io/cloud-provider/OWNERS b/vendor/k8s.io/cloud-provider/OWNERS new file mode 100644 index 000000000..19a29715a --- /dev/null +++ b/vendor/k8s.io/cloud-provider/OWNERS @@ -0,0 +1,29 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +approvers: + - mikedanese + - dims + - wlan0 + - andrewsykim + - cheftako +reviewers: + - wojtek-t + - deads2k + - derekwaynecarr + - mikedanese + - liggitt + - sttts + - dchen1107 + - saad-ali + - luxas + - justinsb + - jsafrane + - dims + - freehan + - jingxu97 + - wlan0 + - cheftako + - andrewsykim +labels: + - sig/cloud-provider + - area/cloudprovider diff --git a/vendor/k8s.io/cloud-provider/README.md b/vendor/k8s.io/cloud-provider/README.md new file mode 100644 index 000000000..542a9a7a8 --- /dev/null +++ b/vendor/k8s.io/cloud-provider/README.md @@ -0,0 +1,33 @@ +# cloud-provider + +This repository defines the cloud-provider interface and mechanism to initialize +a cloud-provider implementation into Kubernetes. Currently multiple processes +use this code although the intent is that it will eventually only be cloud +controller manager. + +**Note:** go-get or vendor this package as `k8s.io/cloud-provider`. + +## Purpose + +This library is a shared dependency for processes which need to be able to +integrate with cloud-provider specific functionality. + +## Compatibility + +Cloud Providers are expected to keep the HEAD of their implementations in sync +with the HEAD of this repository. + +## Where does it come from? + +`cloud-provider` is synced from +https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/cloud-provider. +Code changes are made in that location, merged into k8s.io/kubernetes and +later synced here. + +## Things you should NOT do + + 1. Add an cloud provider specific code to this repo. + 2. Directly modify anything under vendor/k8s.io/cloud-provider in this repo. Those are driven from `k8s.io/kubernetes/staging/src/k8s.io/cloud-provider`. + 3. Make interface changes without first discussing them with + sig-cloudprovider. + diff --git a/vendor/k8s.io/cloud-provider/SECURITY_CONTACTS b/vendor/k8s.io/cloud-provider/SECURITY_CONTACTS new file mode 100644 index 000000000..68e73edaf --- /dev/null +++ b/vendor/k8s.io/cloud-provider/SECURITY_CONTACTS @@ -0,0 +1,20 @@ +# Defined below are the security contacts for this repo. +# +# They are the contact point for the Product Security Committee to reach out +# to for triaging and handling of incoming issues. +# +# The below names agree to abide by the +# [Embargo Policy](https://git.k8s.io/security/private-distributors-list.md#embargo-policy) +# and will be removed and replaced if they violate that agreement. +# +# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE +# INSTRUCTIONS AT https://kubernetes.io/security/ + +cheftako +andrewsykim +dims +cjcullen +joelsmith +liggitt +philips +tallclair diff --git a/vendor/k8s.io/cloud-provider/cloud.go b/vendor/k8s.io/cloud-provider/cloud.go new file mode 100644 index 000000000..44c62ccc0 --- /dev/null +++ b/vendor/k8s.io/cloud-provider/cloud.go @@ -0,0 +1,313 @@ +/* +Copyright 2014 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 cloudprovider + +import ( + "context" + "errors" + "fmt" + "strings" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/informers" + clientset "k8s.io/client-go/kubernetes" + restclient "k8s.io/client-go/rest" +) + +// ControllerClientBuilder allows you to get clients and configs for controllers +// Please note a copy also exists in pkg/controller/client_builder.go +// TODO: Make this depend on the separate controller utilities repo (issues/68947) +type ControllerClientBuilder interface { + Config(name string) (*restclient.Config, error) + ConfigOrDie(name string) *restclient.Config + Client(name string) (clientset.Interface, error) + ClientOrDie(name string) clientset.Interface +} + +// Interface is an abstract, pluggable interface for cloud providers. +type Interface interface { + // Initialize provides the cloud with a kubernetes client builder and may spawn goroutines + // to perform housekeeping or run custom controllers specific to the cloud provider. + // Any tasks started here should be cleaned up when the stop channel closes. + Initialize(clientBuilder ControllerClientBuilder, stop <-chan struct{}) + // LoadBalancer returns a balancer interface. Also returns true if the interface is supported, false otherwise. + LoadBalancer() (LoadBalancer, bool) + // Instances returns an instances interface. Also returns true if the interface is supported, false otherwise. + Instances() (Instances, bool) + // InstancesV2 is an implementation for instances and should only be implemented by external cloud providers. + // Implementing InstancesV2 is behaviorally identical to Instances but is optimized to significantly reduce + // API calls to the cloud provider when registering and syncing nodes. Implementation of this interface will + // disable calls to the Zones interface. Also returns true if the interface is supported, false otherwise. + InstancesV2() (InstancesV2, bool) + // Zones returns a zones interface. Also returns true if the interface is supported, false otherwise. + // DEPRECATED: Zones is deprecated in favor of retrieving zone/region information from InstancesV2. + // This interface will not be called if InstancesV2 is enabled. + Zones() (Zones, bool) + // Clusters returns a clusters interface. Also returns true if the interface is supported, false otherwise. + Clusters() (Clusters, bool) + // Routes returns a routes interface along with whether the interface is supported. + Routes() (Routes, bool) + // ProviderName returns the cloud provider ID. + ProviderName() string + // HasClusterID returns true if a ClusterID is required and set + HasClusterID() bool +} + +type InformerUser interface { + // SetInformers sets the informer on the cloud object. + SetInformers(informerFactory informers.SharedInformerFactory) +} + +// Clusters is an abstract, pluggable interface for clusters of containers. +type Clusters interface { + // ListClusters lists the names of the available clusters. + ListClusters(ctx context.Context) ([]string, error) + // Master gets back the address (either DNS name or IP address) of the master node for the cluster. + Master(ctx context.Context, clusterName string) (string, error) +} + +// (DEPRECATED) DefaultLoadBalancerName is the default load balancer name that is called from +// LoadBalancer.GetLoadBalancerName. Use this method to maintain backward compatible names for +// LoadBalancers that were created prior to Kubernetes v1.12. In the future, each provider should +// replace this method call in GetLoadBalancerName with a provider-specific implementation that +// is less cryptic than the Service's UUID. +func DefaultLoadBalancerName(service *v1.Service) string { + //GCE requires that the name of a load balancer starts with a lower case letter. + ret := "a" + string(service.UID) + ret = strings.Replace(ret, "-", "", -1) + //AWS requires that the name of a load balancer is shorter than 32 bytes. + if len(ret) > 32 { + ret = ret[:32] + } + return ret +} + +// GetInstanceProviderID builds a ProviderID for a node in a cloud. +func GetInstanceProviderID(ctx context.Context, cloud Interface, nodeName types.NodeName) (string, error) { + instances, ok := cloud.Instances() + if !ok { + return "", fmt.Errorf("failed to get instances from cloud provider") + } + instanceID, err := instances.InstanceID(ctx, nodeName) + if err != nil { + if err == NotImplemented { + return "", err + } + + return "", fmt.Errorf("failed to get instance ID from cloud provider: %v", err) + } + return cloud.ProviderName() + "://" + instanceID, nil +} + +// LoadBalancer is an abstract, pluggable interface for load balancers. +// +// Cloud provider may chose to implement the logic for +// constructing/destroying specific kinds of load balancers in a +// controller separate from the ServiceController. If this is the case, +// then {Ensure,Update}LoadBalancer must return the ImplementedElsewhere error. +// For the given LB service, the GetLoadBalancer must return "exists=True" if +// there exists a LoadBalancer instance created by ServiceController. +// In all other cases, GetLoadBalancer must return a NotFound error. +// EnsureLoadBalancerDeleted must not return ImplementedElsewhere to ensure +// proper teardown of resources that were allocated by the ServiceController. +// This can happen if a user changes the type of LB via an update to the resource +// or when migrating from ServiceController to alternate implementation. +// The finalizer on the service will be added and removed by ServiceController +// irrespective of the ImplementedElsewhere error. Additional finalizers for +// LB services must be managed in the alternate implementation. +type LoadBalancer interface { + // TODO: Break this up into different interfaces (LB, etc) when we have more than one type of service + // GetLoadBalancer returns whether the specified load balancer exists, and + // if so, what its status is. + // Implementations must treat the *v1.Service parameter as read-only and not modify it. + // Parameter 'clusterName' is the name of the cluster as presented to kube-controller-manager + GetLoadBalancer(ctx context.Context, clusterName string, service *v1.Service) (status *v1.LoadBalancerStatus, exists bool, err error) + // GetLoadBalancerName returns the name of the load balancer. Implementations must treat the + // *v1.Service parameter as read-only and not modify it. + GetLoadBalancerName(ctx context.Context, clusterName string, service *v1.Service) string + // EnsureLoadBalancer creates a new load balancer 'name', or updates the existing one. Returns the status of the balancer + // Implementations must treat the *v1.Service and *v1.Node + // parameters as read-only and not modify them. + // Parameter 'clusterName' is the name of the cluster as presented to kube-controller-manager + EnsureLoadBalancer(ctx context.Context, clusterName string, service *v1.Service, nodes []*v1.Node) (*v1.LoadBalancerStatus, error) + // UpdateLoadBalancer updates hosts under the specified load balancer. + // Implementations must treat the *v1.Service and *v1.Node + // parameters as read-only and not modify them. + // Parameter 'clusterName' is the name of the cluster as presented to kube-controller-manager + UpdateLoadBalancer(ctx context.Context, clusterName string, service *v1.Service, nodes []*v1.Node) error + // EnsureLoadBalancerDeleted deletes the specified load balancer if it + // exists, returning nil if the load balancer specified either didn't exist or + // was successfully deleted. + // This construction is useful because many cloud providers' load balancers + // have multiple underlying components, meaning a Get could say that the LB + // doesn't exist even if some part of it is still laying around. + // Implementations must treat the *v1.Service parameter as read-only and not modify it. + // Parameter 'clusterName' is the name of the cluster as presented to kube-controller-manager + EnsureLoadBalancerDeleted(ctx context.Context, clusterName string, service *v1.Service) error +} + +// Instances is an abstract, pluggable interface for sets of instances. +type Instances interface { + // NodeAddresses returns the addresses of the specified instance. + NodeAddresses(ctx context.Context, name types.NodeName) ([]v1.NodeAddress, error) + // NodeAddressesByProviderID returns the addresses of the specified instance. + // The instance is specified using the providerID of the node. The + // ProviderID is a unique identifier of the node. This will not be called + // from the node whose nodeaddresses are being queried. i.e. local metadata + // services cannot be used in this method to obtain nodeaddresses + NodeAddressesByProviderID(ctx context.Context, providerID string) ([]v1.NodeAddress, error) + // InstanceID returns the cloud provider ID of the node with the specified NodeName. + // Note that if the instance does not exist, we must return ("", cloudprovider.InstanceNotFound) + // cloudprovider.InstanceNotFound should NOT be returned for instances that exist but are stopped/sleeping + InstanceID(ctx context.Context, nodeName types.NodeName) (string, error) + // InstanceType returns the type of the specified instance. + InstanceType(ctx context.Context, name types.NodeName) (string, error) + // InstanceTypeByProviderID returns the type of the specified instance. + InstanceTypeByProviderID(ctx context.Context, providerID string) (string, error) + // AddSSHKeyToAllInstances adds an SSH public key as a legal identity for all instances + // expected format for the key is standard ssh-keygen format: + AddSSHKeyToAllInstances(ctx context.Context, user string, keyData []byte) error + // CurrentNodeName returns the name of the node we are currently running on + // On most clouds (e.g. GCE) this is the hostname, so we provide the hostname + CurrentNodeName(ctx context.Context, hostname string) (types.NodeName, error) + // InstanceExistsByProviderID returns true if the instance for the given provider exists. + // If false is returned with no error, the instance will be immediately deleted by the cloud controller manager. + // This method should still return true for instances that exist but are stopped/sleeping. + InstanceExistsByProviderID(ctx context.Context, providerID string) (bool, error) + // InstanceShutdownByProviderID returns true if the instance is shutdown in cloudprovider + InstanceShutdownByProviderID(ctx context.Context, providerID string) (bool, error) +} + +// InstancesV2 is an abstract, pluggable interface for cloud provider instances. +// Unlike the Instances interface, it is designed for external cloud providers and should only be used by them. +// Implementation of this interface will disable calls to the Zones interface. +type InstancesV2 interface { + // InstanceExists returns true if the instance for the given node exists according to the cloud provider. + // Use the node.name or node.spec.providerID field to find the node in the cloud provider. + InstanceExists(ctx context.Context, node *v1.Node) (bool, error) + // InstanceShutdown returns true if the instance is shutdown according to the cloud provider. + // Use the node.name or node.spec.providerID field to find the node in the cloud provider. + InstanceShutdown(ctx context.Context, node *v1.Node) (bool, error) + // InstanceMetadata returns the instance's metadata. The values returned in InstanceMetadata are + // translated into specific fields and labels in the Node object on registration. + // Implementations should always check node.spec.providerID first when trying to discover the instance + // for a given node. In cases where node.spec.providerID is empty, implementations can use other + // properties of the node like its name, labels and annotations. + InstanceMetadata(ctx context.Context, node *v1.Node) (*InstanceMetadata, error) +} + +// Route is a representation of an advanced routing rule. +type Route struct { + // Name is the name of the routing rule in the cloud-provider. + // It will be ignored in a Create (although nameHint may influence it) + Name string + // TargetNode is the NodeName of the target instance. + TargetNode types.NodeName + // DestinationCIDR is the CIDR format IP range that this routing rule + // applies to. + DestinationCIDR string + // Blackhole is set to true if this is a blackhole route + // The node controller will delete the route if it is in the managed range. + Blackhole bool +} + +// Routes is an abstract, pluggable interface for advanced routing rules. +type Routes interface { + // ListRoutes lists all managed routes that belong to the specified clusterName + ListRoutes(ctx context.Context, clusterName string) ([]*Route, error) + // CreateRoute creates the described managed route + // route.Name will be ignored, although the cloud-provider may use nameHint + // to create a more user-meaningful name. + CreateRoute(ctx context.Context, clusterName string, nameHint string, route *Route) error + // DeleteRoute deletes the specified managed route + // Route should be as returned by ListRoutes + DeleteRoute(ctx context.Context, clusterName string, route *Route) error +} + +var ( + DiskNotFound = errors.New("disk is not found") + ImplementedElsewhere = errors.New("implemented by alternate to cloud provider") + InstanceNotFound = errors.New("instance not found") + NotImplemented = errors.New("unimplemented") +) + +// Zone represents the location of a particular machine. +type Zone struct { + FailureDomain string + Region string +} + +// Zones is an abstract, pluggable interface for zone enumeration. +// DEPRECATED: Zones is deprecated in favor of retrieving zone/region information from InstancesV2. +// This interface will not be called if InstancesV2 is enabled. +type Zones interface { + // GetZone returns the Zone containing the current failure zone and locality region that the program is running in + // In most cases, this method is called from the kubelet querying a local metadata service to acquire its zone. + // For the case of external cloud providers, use GetZoneByProviderID or GetZoneByNodeName since GetZone + // can no longer be called from the kubelets. + GetZone(ctx context.Context) (Zone, error) + + // GetZoneByProviderID returns the Zone containing the current zone and locality region of the node specified by providerID + // This method is particularly used in the context of external cloud providers where node initialization must be done + // outside the kubelets. + GetZoneByProviderID(ctx context.Context, providerID string) (Zone, error) + + // GetZoneByNodeName returns the Zone containing the current zone and locality region of the node specified by node name + // This method is particularly used in the context of external cloud providers where node initialization must be done + // outside the kubelets. + GetZoneByNodeName(ctx context.Context, nodeName types.NodeName) (Zone, error) +} + +// PVLabeler is an abstract, pluggable interface for fetching labels for volumes +type PVLabeler interface { + GetLabelsForVolume(ctx context.Context, pv *v1.PersistentVolume) (map[string]string, error) +} + +// InstanceMetadata contains metadata about a specific instance. +// Values returned in InstanceMetadata are translated into specific fields and labels for Node. +type InstanceMetadata struct { + // ProviderID is a unique ID used to identify an instance on the cloud provider. + // The ProviderID set here will be set on the node's spec.providerID field. + // The provider ID format can be set by the cloud provider but providers should + // ensure the format does not change in any incompatible way. + // + // The provider ID format used by existing cloud provider has been: + // :// + // Existing providers setting this field should preserve the existing format + // currently being set in node.spec.providerID. + ProviderID string + // InstanceType is the instance's type. + // The InstanceType set here will be set using the following labels on the node object: + // * node.kubernetes.io/instance-type= + // * beta.kubernetes.io/instance-type= (DEPRECATED) + InstanceType string + // NodeAddress contains information for the instance's address. + // The node addresses returned here will be set on the node's status.addresses field. + NodeAddresses []v1.NodeAddress + + // Zone is the zone that the instance is in. + // The value set here is applied as the following labels on the node: + // * topology.kubernetes.io/zone= + // * failure-domain.beta.kubernetes.io/zone= (DEPRECATED) + Zone string + // Region is the region that the instance is in. + // The value set here is applied as the following labels on the node: + // * topology.kubernetes.io/region= + // * failure-domain.beta.kubernetes.io/region= (DEPRECATED) + Region string +} diff --git a/vendor/k8s.io/cloud-provider/code-of-conduct.md b/vendor/k8s.io/cloud-provider/code-of-conduct.md new file mode 100644 index 000000000..0d15c00cf --- /dev/null +++ b/vendor/k8s.io/cloud-provider/code-of-conduct.md @@ -0,0 +1,3 @@ +# Kubernetes Community Code of Conduct + +Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md) diff --git a/vendor/k8s.io/cloud-provider/doc.go b/vendor/k8s.io/cloud-provider/doc.go new file mode 100644 index 000000000..6b401e456 --- /dev/null +++ b/vendor/k8s.io/cloud-provider/doc.go @@ -0,0 +1,18 @@ +/* +Copyright 2014 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 cloudprovider supplies interfaces and implementations for cloud service providers. +package cloudprovider // import "k8s.io/cloud-provider" diff --git a/vendor/k8s.io/cloud-provider/plugins.go b/vendor/k8s.io/cloud-provider/plugins.go new file mode 100644 index 000000000..5300abdb4 --- /dev/null +++ b/vendor/k8s.io/cloud-provider/plugins.go @@ -0,0 +1,174 @@ +/* +Copyright 2014 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 cloudprovider + +import ( + "fmt" + "io" + "os" + "sync" + + "k8s.io/klog/v2" +) + +// Factory is a function that returns a cloudprovider.Interface. +// The config parameter provides an io.Reader handler to the factory in +// order to load specific configurations. If no configuration is provided +// the parameter is nil. +type Factory func(config io.Reader) (Interface, error) + +// All registered cloud providers. +var ( + providersMutex sync.Mutex + providers = make(map[string]Factory) + deprecatedCloudProviders = []struct { + name string + external bool + detail string + }{ + {"aws", false, "The AWS provider is deprecated and will be removed in a future release. Please use https://github.com/kubernetes/cloud-provider-aws"}, + {"azure", false, "The Azure provider is deprecated and will be removed in a future release. Please use https://github.com/kubernetes-sigs/cloud-provider-azure"}, + {"gce", false, "The GCE provider is deprecated and will be removed in a future release. Please use https://github.com/kubernetes/cloud-provider-gcp"}, + {"vsphere", false, "The vSphere provider is deprecated and will be removed in a future release. Please use https://github.com/kubernetes/cloud-provider-vsphere"}, + } +) + +const externalCloudProvider = "external" + +// RegisterCloudProvider registers a cloudprovider.Factory by name. This +// is expected to happen during app startup. +func RegisterCloudProvider(name string, cloud Factory) { + providersMutex.Lock() + defer providersMutex.Unlock() + if _, found := providers[name]; found { + klog.Fatalf("Cloud provider %q was registered twice", name) + } + klog.V(1).Infof("Registered cloud provider %q", name) + providers[name] = cloud +} + +// IsCloudProvider returns true if name corresponds to an already registered +// cloud provider. +func IsCloudProvider(name string) bool { + providersMutex.Lock() + defer providersMutex.Unlock() + _, found := providers[name] + return found +} + +// GetCloudProvider creates an instance of the named cloud provider, or nil if +// the name is unknown. The error return is only used if the named provider +// was known but failed to initialize. The config parameter specifies the +// io.Reader handler of the configuration file for the cloud provider, or nil +// for no configuration. +func GetCloudProvider(name string, config io.Reader) (Interface, error) { + providersMutex.Lock() + defer providersMutex.Unlock() + f, found := providers[name] + if !found { + return nil, nil + } + return f(config) +} + +// Detects if the string is an external cloud provider +func IsExternal(name string) bool { + return name == externalCloudProvider +} + +// IsDeprecatedInternal is responsible for preventing cloud.Interface +// from being initialized in kubelet, kube-controller-manager or kube-api-server +func IsDeprecatedInternal(name string) bool { + for _, provider := range deprecatedCloudProviders { + if provider.name == name { + return true + } + } + + return false +} + +// DisableWarningForProvider logs information about disabled cloud provider state +func DisableWarningForProvider(providerName string) { + for _, provider := range deprecatedCloudProviders { + if provider.name == providerName { + klog.Infof("INFO: Please make sure you are running external cloud controller manager binary for provider %q."+ + "In-tree cloud providers are currently disabled. Refer to https://github.com/kubernetes/kubernetes/tree/master/staging/src/k8s.io/cloud-provider/sample"+ + "for example implementation.", providerName) + detail := fmt.Sprintf("Please reach to sig-cloud-provider and use 'external' cloud provider for %q: %s", providerName, provider.detail) + klog.Warningf("WARNING: %q built-in cloud provider is now disabled. %s", providerName, detail) + break + } + } +} + +// DeprecationWarningForProvider logs information about deprecated cloud provider state +func DeprecationWarningForProvider(providerName string) { + for _, provider := range deprecatedCloudProviders { + if provider.name != providerName { + continue + } + + detail := provider.detail + if provider.external { + detail = fmt.Sprintf("Please use 'external' cloud provider for %s: %s", providerName, provider.detail) + } + + klog.Warningf("WARNING: %s built-in cloud provider is now deprecated. %s", providerName, detail) + break + } +} + +// InitCloudProvider creates an instance of the named cloud provider. +func InitCloudProvider(name string, configFilePath string) (Interface, error) { + var cloud Interface + var err error + + if name == "" { + return nil, nil + } + + if IsExternal(name) { + klog.Info("External cloud provider specified") + return nil, nil + } + + if configFilePath != "" { + var config *os.File + config, err = os.Open(configFilePath) + if err != nil { + klog.Fatalf("Couldn't open cloud provider configuration %s: %#v", + configFilePath, err) + } + + defer config.Close() + cloud, err = GetCloudProvider(name, config) + } else { + // Pass explicit nil so plugins can actually check for nil. See + // "Why is my nil error value not equal to nil?" in golang.org/doc/faq. + cloud, err = GetCloudProvider(name, nil) + } + + if err != nil { + return nil, fmt.Errorf("could not init cloud provider %q: %v", name, err) + } + if cloud == nil { + return nil, fmt.Errorf("unknown cloud provider %q", name) + } + + return cloud, nil +} diff --git a/vendor/k8s.io/cloud-provider/ports.go b/vendor/k8s.io/cloud-provider/ports.go new file mode 100644 index 000000000..797de6d92 --- /dev/null +++ b/vendor/k8s.io/cloud-provider/ports.go @@ -0,0 +1,23 @@ +/* +Copyright 2014 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 cloudprovider + +const ( + // CloudControllerManagerPort is the default port for the cloud controller manager server. + // This value may be overridden by a flag at startup. + CloudControllerManagerPort = 10258 +) diff --git a/vendor/k8s.io/cloud-provider/volume/constants.go b/vendor/k8s.io/cloud-provider/volume/constants.go new file mode 100644 index 000000000..d05f64ae2 --- /dev/null +++ b/vendor/k8s.io/cloud-provider/volume/constants.go @@ -0,0 +1,26 @@ +/* +Copyright 2019 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 volume + +const ( + // ProvisionedVolumeName is the name of a volume in an external cloud + // that is being provisioned and thus should be ignored by rest of Kubernetes. + ProvisionedVolumeName = "placeholder-for-provisioning" + + // LabelMultiZoneDelimiter separates zones for volumes + LabelMultiZoneDelimiter = "__" +) diff --git a/vendor/k8s.io/cloud-provider/volume/helpers/rounding.go b/vendor/k8s.io/cloud-provider/volume/helpers/rounding.go new file mode 100644 index 000000000..101815738 --- /dev/null +++ b/vendor/k8s.io/cloud-provider/volume/helpers/rounding.go @@ -0,0 +1,165 @@ +/* +Copyright 2019 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 helpers + +import ( + "fmt" + "math" + "math/bits" + + "k8s.io/apimachinery/pkg/api/resource" +) + +/* +The Cloud Provider's volume plugins provision disks for corresponding +PersistentVolumeClaims. Cloud Providers use different allocation unit for their +disk sizes. AWS allows you to specify the size as an integer amount of GiB, +while Portworx expects bytes for example. On AWS, if you want a volume of +1500MiB, the actual call to the AWS API should therefore be for a 2GiB disk. +This file contains functions that help rounding a storage request based on a +Cloud Provider's allocation unit. +*/ + +const ( + // GB - GigaByte size + GB = 1000 * 1000 * 1000 + // GiB - GibiByte size + GiB = 1024 * 1024 * 1024 + + // MB - MegaByte size + MB = 1000 * 1000 + // MiB - MebiByte size + MiB = 1024 * 1024 + + // KB - KiloByte size + KB = 1000 + // KiB - KibiByte size + KiB = 1024 +) + +// RoundUpToGiB rounds up given quantity upto chunks of GiB +func RoundUpToGiB(size resource.Quantity) (int64, error) { + return roundUpSizeInt64(size, GiB) +} + +// RoundUpToMB rounds up given quantity to chunks of MB +func RoundUpToMB(size resource.Quantity) (int64, error) { + return roundUpSizeInt64(size, MB) +} + +// RoundUpToMiB rounds up given quantity upto chunks of MiB +func RoundUpToMiB(size resource.Quantity) (int64, error) { + return roundUpSizeInt64(size, MiB) +} + +// RoundUpToKB rounds up given quantity to chunks of KB +func RoundUpToKB(size resource.Quantity) (int64, error) { + return roundUpSizeInt64(size, KB) +} + +// RoundUpToKiB rounds up given quantity to chunks of KiB +func RoundUpToKiB(size resource.Quantity) (int64, error) { + return roundUpSizeInt64(size, KiB) +} + +// RoundUpToB rounds up given quantity to chunks of bytes +func RoundUpToB(size resource.Quantity) (int64, error) { + return roundUpSizeInt64(size, 1) +} + +// RoundUpToGiBInt rounds up given quantity upto chunks of GiB. It returns an +// int instead of an int64 and an error if there's overflow +func RoundUpToGiBInt(size resource.Quantity) (int, error) { + return roundUpSizeInt(size, GiB) +} + +// RoundUpToMBInt rounds up given quantity to chunks of MB. It returns an +// int instead of an int64 and an error if there's overflow +func RoundUpToMBInt(size resource.Quantity) (int, error) { + return roundUpSizeInt(size, MB) +} + +// RoundUpToMiBInt rounds up given quantity upto chunks of MiB. It returns an +// int instead of an int64 and an error if there's overflow +func RoundUpToMiBInt(size resource.Quantity) (int, error) { + return roundUpSizeInt(size, MiB) +} + +// RoundUpToKBInt rounds up given quantity to chunks of KB. It returns an +// int instead of an int64 and an error if there's overflow +func RoundUpToKBInt(size resource.Quantity) (int, error) { + return roundUpSizeInt(size, KB) +} + +// RoundUpToKiBInt rounds up given quantity upto chunks of KiB. It returns an +// int instead of an int64 and an error if there's overflow +func RoundUpToKiBInt(size resource.Quantity) (int, error) { + return roundUpSizeInt(size, KiB) +} + +// RoundUpToGiBInt32 rounds up given quantity up to chunks of GiB. It returns an +// int32 instead of an int64 and an error if there's overflow +func RoundUpToGiBInt32(size resource.Quantity) (int32, error) { + return roundUpSizeInt32(size, GiB) +} + +// roundUpSizeInt calculates how many allocation units are needed to accommodate +// a volume of a given size. It returns an int and an error if there's overflow +func roundUpSizeInt(size resource.Quantity, allocationUnitBytes int64) (int, error) { + if bits.UintSize == 32 { + res, err := roundUpSizeInt32(size, allocationUnitBytes) + return int(res), err + } + res, err := roundUpSizeInt64(size, allocationUnitBytes) + return int(res), err +} + +// roundUpSizeInt32 calculates how many allocation units are needed to accommodate +// a volume of a given size. It returns an int32 and an error if there's overflow +func roundUpSizeInt32(size resource.Quantity, allocationUnitBytes int64) (int32, error) { + roundedUpInt32, err := roundUpSizeInt64(size, allocationUnitBytes) + if err != nil { + return 0, err + } + if roundedUpInt32 > math.MaxInt32 { + return 0, fmt.Errorf("quantity %s is too great, overflows int32", size.String()) + } + return int32(roundedUpInt32), nil +} + +// roundUpSizeInt64 calculates how many allocation units are needed to accommodate +// a volume of a given size. It returns an int64 and an error if there's overflow +func roundUpSizeInt64(size resource.Quantity, allocationUnitBytes int64) (int64, error) { + // Use CmpInt64() to find out if the value of "size" would overflow an + // int64 and therefore have Value() return a wrong result. Then, retrieve + // the value as int64 and perform the rounding. + // It's not convenient to use AsScale() and related functions as they don't + // support BinarySI format, nor can we use AsInt64() directly since it's + // only implemented for int64 scaled numbers (int64Amount). + + // CmpInt64() actually returns 0 when comparing an amount bigger than MaxInt64. + if size.CmpInt64(math.MaxInt64) >= 0 { + return 0, fmt.Errorf("quantity %s is too great, overflows int64", size.String()) + } + volumeSizeBytes := size.Value() + + roundedUp := volumeSizeBytes / allocationUnitBytes + if volumeSizeBytes%allocationUnitBytes > 0 { + roundedUp++ + } + return roundedUp, nil +} diff --git a/vendor/k8s.io/cloud-provider/volume/helpers/zones.go b/vendor/k8s.io/cloud-provider/volume/helpers/zones.go new file mode 100644 index 000000000..ff3a39284 --- /dev/null +++ b/vendor/k8s.io/cloud-provider/volume/helpers/zones.go @@ -0,0 +1,313 @@ +/* +Copyright 2019 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 helpers + +import ( + "fmt" + "hash/fnv" + "math/rand" + "strconv" + "strings" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/util/sets" + cloudvolume "k8s.io/cloud-provider/volume" + "k8s.io/klog/v2" +) + +// LabelZonesToSet converts a PV label value from string containing a delimited list of zones to set +func LabelZonesToSet(labelZonesValue string) (sets.String, error) { + return stringToSet(labelZonesValue, cloudvolume.LabelMultiZoneDelimiter) +} + +// ZonesSetToLabelValue converts zones set to label value +func ZonesSetToLabelValue(strSet sets.String) string { + return strings.Join(strSet.UnsortedList(), cloudvolume.LabelMultiZoneDelimiter) +} + +// ZonesToSet converts a string containing a comma separated list of zones to set +func ZonesToSet(zonesString string) (sets.String, error) { + zones, err := stringToSet(zonesString, ",") + if err != nil { + return nil, fmt.Errorf("error parsing zones %s, must be strings separated by commas: %v", zonesString, err) + } + return zones, nil +} + +// StringToSet converts a string containing list separated by specified delimiter to a set +func stringToSet(str, delimiter string) (sets.String, error) { + zonesSlice := strings.Split(str, delimiter) + zonesSet := make(sets.String) + for _, zone := range zonesSlice { + trimmedZone := strings.TrimSpace(zone) + if trimmedZone == "" { + return make(sets.String), fmt.Errorf( + "%q separated list (%q) must not contain an empty string", + delimiter, + str) + } + zonesSet.Insert(trimmedZone) + } + return zonesSet, nil +} + +// LabelZonesToList converts a PV label value from string containing a delimited list of zones to list +func LabelZonesToList(labelZonesValue string) ([]string, error) { + return stringToList(labelZonesValue, cloudvolume.LabelMultiZoneDelimiter) +} + +// StringToList converts a string containing list separated by specified delimiter to a list +func stringToList(str, delimiter string) ([]string, error) { + zonesSlice := make([]string, 0) + for _, zone := range strings.Split(str, delimiter) { + trimmedZone := strings.TrimSpace(zone) + if trimmedZone == "" { + return nil, fmt.Errorf( + "%q separated list (%q) must not contain an empty string", + delimiter, + str) + } + zonesSlice = append(zonesSlice, trimmedZone) + } + return zonesSlice, nil +} + +// SelectZoneForVolume is a wrapper around SelectZonesForVolume +// to select a single zone for a volume based on parameters +func SelectZoneForVolume(zoneParameterPresent, zonesParameterPresent bool, zoneParameter string, zonesParameter, zonesWithNodes sets.String, node *v1.Node, allowedTopologies []v1.TopologySelectorTerm, pvcName string) (string, error) { + zones, err := SelectZonesForVolume(zoneParameterPresent, zonesParameterPresent, zoneParameter, zonesParameter, zonesWithNodes, node, allowedTopologies, pvcName, 1) + if err != nil { + return "", err + } + zone, ok := zones.PopAny() + if !ok { + return "", fmt.Errorf("could not determine a zone to provision volume in") + } + return zone, nil +} + +// SelectZonesForVolume selects zones for a volume based on several factors: +// node.zone, allowedTopologies, zone/zones parameters from storageclass, +// zones with active nodes from the cluster. The number of zones = replicas. +func SelectZonesForVolume(zoneParameterPresent, zonesParameterPresent bool, zoneParameter string, zonesParameter, zonesWithNodes sets.String, node *v1.Node, allowedTopologies []v1.TopologySelectorTerm, pvcName string, numReplicas uint32) (sets.String, error) { + if zoneParameterPresent && zonesParameterPresent { + return nil, fmt.Errorf("both zone and zones StorageClass parameters must not be used at the same time") + } + + var zoneFromNode string + // pick one zone from node if present + if node != nil { + // VolumeScheduling implicit since node is not nil + if zoneParameterPresent || zonesParameterPresent { + return nil, fmt.Errorf("zone[s] cannot be specified in StorageClass if VolumeBindingMode is set to WaitForFirstConsumer. Please specify allowedTopologies in StorageClass for constraining zones") + } + + // pick node's zone for one of the replicas + var ok bool + zoneFromNode, ok = node.ObjectMeta.Labels[v1.LabelTopologyZone] + if !ok { + zoneFromNode, ok = node.ObjectMeta.Labels[v1.LabelFailureDomainBetaZone] + if !ok { + return nil, fmt.Errorf("Either %s or %s Label for node missing", v1.LabelTopologyZone, v1.LabelFailureDomainBetaZone) + } + } + // if single replica volume and node with zone found, return immediately + if numReplicas == 1 { + return sets.NewString(zoneFromNode), nil + } + } + + // pick zone from allowedZones if specified + allowedZones, err := ZonesFromAllowedTopologies(allowedTopologies) + if err != nil { + return nil, err + } + + if (len(allowedTopologies) > 0) && (allowedZones.Len() == 0) { + return nil, fmt.Errorf("no matchLabelExpressions with %s key found in allowedTopologies. Please specify matchLabelExpressions with %s key", v1.LabelTopologyZone, v1.LabelTopologyZone) + } + + if allowedZones.Len() > 0 { + // VolumeScheduling implicit since allowedZones present + if zoneParameterPresent || zonesParameterPresent { + return nil, fmt.Errorf("zone[s] cannot be specified in StorageClass if allowedTopologies specified") + } + // scheduler will guarantee if node != null above, zoneFromNode is member of allowedZones. + // so if zoneFromNode != "", we can safely assume it is part of allowedZones. + zones, err := chooseZonesForVolumeIncludingZone(allowedZones, pvcName, zoneFromNode, numReplicas) + if err != nil { + return nil, fmt.Errorf("cannot process zones in allowedTopologies: %v", err) + } + return zones, nil + } + + // pick zone from parameters if present + if zoneParameterPresent { + if numReplicas > 1 { + return nil, fmt.Errorf("zone cannot be specified if desired number of replicas for pv is greather than 1. Please specify zones or allowedTopologies to specify desired zones") + } + return sets.NewString(zoneParameter), nil + } + + if zonesParameterPresent { + if uint32(zonesParameter.Len()) < numReplicas { + return nil, fmt.Errorf("not enough zones found in zones parameter to provision a volume with %d replicas. Found %d zones, need %d zones", numReplicas, zonesParameter.Len(), numReplicas) + } + // directly choose from zones parameter; no zone from node need to be considered + return ChooseZonesForVolume(zonesParameter, pvcName, numReplicas), nil + } + + // pick zone from zones with nodes + if zonesWithNodes.Len() > 0 { + // If node != null (and thus zoneFromNode != ""), zoneFromNode will be member of zonesWithNodes + zones, err := chooseZonesForVolumeIncludingZone(zonesWithNodes, pvcName, zoneFromNode, numReplicas) + if err != nil { + return nil, fmt.Errorf("cannot process zones where nodes exist in the cluster: %v", err) + } + return zones, nil + } + return nil, fmt.Errorf("cannot determine zones to provision volume in") +} + +// ZonesFromAllowedTopologies returns a list of zones specified in allowedTopologies +func ZonesFromAllowedTopologies(allowedTopologies []v1.TopologySelectorTerm) (sets.String, error) { + zones := make(sets.String) + for _, term := range allowedTopologies { + for _, exp := range term.MatchLabelExpressions { + if exp.Key == v1.LabelTopologyZone || exp.Key == v1.LabelFailureDomainBetaZone { + for _, value := range exp.Values { + zones.Insert(value) + } + } else { + return nil, fmt.Errorf("unsupported key found in matchLabelExpressions: %s", exp.Key) + } + } + } + return zones, nil +} + +// chooseZonesForVolumeIncludingZone is a wrapper around ChooseZonesForVolume that ensures zoneToInclude is chosen +// zoneToInclude can either be empty in which case it is ignored. If non-empty, zoneToInclude is expected to be member of zones. +// numReplicas is expected to be > 0 and <= zones.Len() +func chooseZonesForVolumeIncludingZone(zones sets.String, pvcName, zoneToInclude string, numReplicas uint32) (sets.String, error) { + if numReplicas == 0 { + return nil, fmt.Errorf("invalid number of replicas passed") + } + if uint32(zones.Len()) < numReplicas { + return nil, fmt.Errorf("not enough zones found to provision a volume with %d replicas. Need at least %d distinct zones for a volume with %d replicas", numReplicas, numReplicas, numReplicas) + } + if zoneToInclude != "" && !zones.Has(zoneToInclude) { + return nil, fmt.Errorf("zone to be included: %s needs to be member of set: %v", zoneToInclude, zones) + } + if uint32(zones.Len()) == numReplicas { + return zones, nil + } + if zoneToInclude != "" { + zones.Delete(zoneToInclude) + numReplicas = numReplicas - 1 + } + zonesChosen := ChooseZonesForVolume(zones, pvcName, numReplicas) + if zoneToInclude != "" { + zonesChosen.Insert(zoneToInclude) + } + return zonesChosen, nil +} + +// ChooseZonesForVolume is identical to ChooseZoneForVolume, but selects a multiple zones, for multi-zone disks. +func ChooseZonesForVolume(zones sets.String, pvcName string, numZones uint32) sets.String { + // No zones available, return empty set. + replicaZones := sets.NewString() + if zones.Len() == 0 { + return replicaZones + } + + // We create the volume in a zone determined by the name + // Eventually the scheduler will coordinate placement into an available zone + hash, index := getPVCNameHashAndIndexOffset(pvcName) + + // Zones.List returns zones in a consistent order (sorted) + // We do have a potential failure case where volumes will not be properly spread, + // if the set of zones changes during StatefulSet volume creation. However, this is + // probably relatively unlikely because we expect the set of zones to be essentially + // static for clusters. + // Hopefully we can address this problem if/when we do full scheduler integration of + // PVC placement (which could also e.g. avoid putting volumes in overloaded or + // unhealthy zones) + zoneSlice := zones.List() + + startingIndex := index * numZones + for index = startingIndex; index < startingIndex+numZones; index++ { + zone := zoneSlice[(hash+index)%uint32(len(zoneSlice))] + replicaZones.Insert(zone) + } + + klog.V(2).Infof("Creating volume for replicated PVC %q; chosen zones=%q from zones=%q", + pvcName, replicaZones.UnsortedList(), zoneSlice) + return replicaZones +} + +func getPVCNameHashAndIndexOffset(pvcName string) (hash uint32, index uint32) { + if pvcName == "" { + // We should always be called with a name; this shouldn't happen + klog.Warningf("No name defined during volume create; choosing random zone") + + hash = rand.Uint32() + } else { + hashString := pvcName + + // Heuristic to make sure that volumes in a StatefulSet are spread across zones + // StatefulSet PVCs are (currently) named ClaimName-StatefulSetName-Id, + // where Id is an integer index. + // Note though that if a StatefulSet pod has multiple claims, we need them to be + // in the same zone, because otherwise the pod will be unable to mount both volumes, + // and will be unschedulable. So we hash _only_ the "StatefulSetName" portion when + // it looks like `ClaimName-StatefulSetName-Id`. + // We continue to round-robin volume names that look like `Name-Id` also; this is a useful + // feature for users that are creating statefulset-like functionality without using statefulsets. + lastDash := strings.LastIndexByte(pvcName, '-') + if lastDash != -1 { + statefulsetIDString := pvcName[lastDash+1:] + statefulsetID, err := strconv.ParseUint(statefulsetIDString, 10, 32) + if err == nil { + // Offset by the statefulsetID, so we round-robin across zones + index = uint32(statefulsetID) + // We still hash the volume name, but only the prefix + hashString = pvcName[:lastDash] + + // In the special case where it looks like `ClaimName-StatefulSetName-Id`, + // hash only the StatefulSetName, so that different claims on the same StatefulSet + // member end up in the same zone. + // Note that StatefulSetName (and ClaimName) might themselves both have dashes. + // We actually just take the portion after the final - of ClaimName-StatefulSetName. + // For our purposes it doesn't much matter (just suboptimal spreading). + lastDash := strings.LastIndexByte(hashString, '-') + if lastDash != -1 { + hashString = hashString[lastDash+1:] + } + + klog.V(2).Infof("Detected StatefulSet-style volume name %q; index=%d", pvcName, index) + } + } + + // We hash the (base) volume name, so we don't bias towards the first N zones + h := fnv.New32() + h.Write([]byte(hashString)) + hash = h.Sum32() + } + + return hash, index +} diff --git a/vendor/k8s.io/component-base/cli/globalflag/globalflags.go b/vendor/k8s.io/component-base/cli/globalflag/globalflags.go new file mode 100644 index 000000000..8f89fd391 --- /dev/null +++ b/vendor/k8s.io/component-base/cli/globalflag/globalflags.go @@ -0,0 +1,50 @@ +/* +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 globalflag + +import ( + "flag" + "fmt" + + "github.com/spf13/pflag" + "k8s.io/component-base/logs" +) + +// AddGlobalFlags explicitly registers flags that libraries (klog, verflag, etc.) register +// against the global flagsets from "flag" and "k8s.io/klog/v2". +// We do this in order to prevent unwanted flags from leaking into the component's flagset. +// +// k8s.io/component-base/logs.SkipLoggingConfigurationFlags must be used as +// option when the program also uses a LoggingConfiguration struct for +// configuring logging. Then only flags not covered by that get added. +func AddGlobalFlags(fs *pflag.FlagSet, name string, opts ...logs.Option) { + logs.AddFlags(fs, opts...) + + fs.BoolP("help", "h", false, fmt.Sprintf("help for %s", name)) +} + +// Register adds a flag to local that targets the Value associated with the Flag named globalName in flag.CommandLine. +func Register(local *pflag.FlagSet, globalName string) { + if f := flag.CommandLine.Lookup(globalName); f != nil { + pflagFlag := pflag.PFlagFromGoFlag(f) + normalizeFunc := local.GetNormalizeFunc() + pflagFlag.Name = string(normalizeFunc(local, pflagFlag.Name)) + local.AddFlag(pflagFlag) + } else { + panic(fmt.Sprintf("failed to find flag in global flagset (flag): %s", globalName)) + } +} diff --git a/vendor/k8s.io/component-base/config/options/leaderelectionconfig.go b/vendor/k8s.io/component-base/config/options/leaderelectionconfig.go new file mode 100644 index 000000000..bf2a44a0a --- /dev/null +++ b/vendor/k8s.io/component-base/config/options/leaderelectionconfig.go @@ -0,0 +1,53 @@ +/* +Copyright 2017 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 options + +import ( + "github.com/spf13/pflag" + "k8s.io/component-base/config" +) + +// BindLeaderElectionFlags binds the LeaderElectionConfiguration struct fields to a flagset +func BindLeaderElectionFlags(l *config.LeaderElectionConfiguration, fs *pflag.FlagSet) { + fs.BoolVar(&l.LeaderElect, "leader-elect", l.LeaderElect, ""+ + "Start a leader election client and gain leadership before "+ + "executing the main loop. Enable this when running replicated "+ + "components for high availability.") + fs.DurationVar(&l.LeaseDuration.Duration, "leader-elect-lease-duration", l.LeaseDuration.Duration, ""+ + "The duration that non-leader candidates will wait after observing a leadership "+ + "renewal until attempting to acquire leadership of a led but unrenewed leader "+ + "slot. This is effectively the maximum duration that a leader can be stopped "+ + "before it is replaced by another candidate. This is only applicable if leader "+ + "election is enabled.") + fs.DurationVar(&l.RenewDeadline.Duration, "leader-elect-renew-deadline", l.RenewDeadline.Duration, ""+ + "The interval between attempts by the acting master to renew a leadership slot "+ + "before it stops leading. This must be less than the lease duration. "+ + "This is only applicable if leader election is enabled.") + fs.DurationVar(&l.RetryPeriod.Duration, "leader-elect-retry-period", l.RetryPeriod.Duration, ""+ + "The duration the clients should wait between attempting acquisition and renewal "+ + "of a leadership. This is only applicable if leader election is enabled.") + fs.StringVar(&l.ResourceLock, "leader-elect-resource-lock", l.ResourceLock, ""+ + "The type of resource object that is used for locking during "+ + "leader election. Supported options are 'leases', 'endpointsleases' "+ + "and 'configmapsleases'.") + fs.StringVar(&l.ResourceName, "leader-elect-resource-name", l.ResourceName, ""+ + "The name of resource object that is used for locking during "+ + "leader election.") + fs.StringVar(&l.ResourceNamespace, "leader-elect-resource-namespace", l.ResourceNamespace, ""+ + "The namespace of resource object that is used for locking during "+ + "leader election.") +} diff --git a/vendor/k8s.io/component-base/config/validation/validation.go b/vendor/k8s.io/component-base/config/validation/validation.go new file mode 100644 index 000000000..1bee0a01f --- /dev/null +++ b/vendor/k8s.io/component-base/config/validation/validation.go @@ -0,0 +1,61 @@ +/* +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 validation + +import ( + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/component-base/config" +) + +// ValidateClientConnectionConfiguration ensures validation of the ClientConnectionConfiguration struct +func ValidateClientConnectionConfiguration(cc *config.ClientConnectionConfiguration, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if cc.Burst < 0 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("burst"), cc.Burst, "must be non-negative")) + } + return allErrs +} + +// ValidateLeaderElectionConfiguration ensures validation of the LeaderElectionConfiguration struct +func ValidateLeaderElectionConfiguration(cc *config.LeaderElectionConfiguration, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if !cc.LeaderElect { + return allErrs + } + if cc.LeaseDuration.Duration <= 0 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("leaseDuration"), cc.LeaseDuration, "must be greater than zero")) + } + if cc.RenewDeadline.Duration <= 0 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("renewDeadline"), cc.RenewDeadline, "must be greater than zero")) + } + if cc.RetryPeriod.Duration <= 0 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("retryPeriod"), cc.RetryPeriod, "must be greater than zero")) + } + if cc.LeaseDuration.Duration <= cc.RenewDeadline.Duration { + allErrs = append(allErrs, field.Invalid(fldPath.Child("leaseDuration"), cc.RenewDeadline, "LeaseDuration must be greater than RenewDeadline")) + } + if len(cc.ResourceLock) == 0 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("resourceLock"), cc.ResourceLock, "resourceLock is required")) + } + if len(cc.ResourceNamespace) == 0 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("resourceNamespace"), cc.ResourceNamespace, "resourceNamespace is required")) + } + if len(cc.ResourceName) == 0 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("resourceName"), cc.ResourceName, "resourceName is required")) + } + return allErrs +} diff --git a/vendor/k8s.io/component-base/configz/OWNERS b/vendor/k8s.io/component-base/configz/OWNERS new file mode 100644 index 000000000..3c2009a85 --- /dev/null +++ b/vendor/k8s.io/component-base/configz/OWNERS @@ -0,0 +1,16 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +# For lack of a better idea, assigned configz to api-approvers because +# configz is an API that has been around for a long time, even if we don't +# guarantee its stability. + +# Disable inheritance as this is an api owners file +options: + no_parent_owners: true +approvers: + - api-approvers +reviewers: + - api-reviewers +labels: + - kind/api-change + - sig/cluster-lifecycle diff --git a/vendor/k8s.io/component-base/configz/configz.go b/vendor/k8s.io/component-base/configz/configz.go new file mode 100644 index 000000000..60e4f938a --- /dev/null +++ b/vendor/k8s.io/component-base/configz/configz.go @@ -0,0 +1,125 @@ +/* +Copyright 2015 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 configz serves ComponentConfig objects from running components. +// +// Each component that wants to serve its ComponentConfig creates a Config +// object, and the program should call InstallHandler once. e.g., +// +// func main() { +// boatConfig := getBoatConfig() +// planeConfig := getPlaneConfig() +// +// bcz, err := configz.New("boat") +// if err != nil { +// panic(err) +// } +// bcz.Set(boatConfig) +// +// pcz, err := configz.New("plane") +// if err != nil { +// panic(err) +// } +// pcz.Set(planeConfig) +// +// configz.InstallHandler(http.DefaultServeMux) +// http.ListenAndServe(":8080", http.DefaultServeMux) +// } +package configz + +import ( + "encoding/json" + "fmt" + "net/http" + "sync" +) + +var ( + configsGuard sync.RWMutex + configs = map[string]*Config{} +) + +// Config is a handle to a ComponentConfig object. Don't create these directly; +// use New() instead. +type Config struct { + val interface{} +} + +// InstallHandler adds an HTTP handler on the given mux for the "/configz" +// endpoint which serves all registered ComponentConfigs in JSON format. +func InstallHandler(m mux) { + m.Handle("/configz", http.HandlerFunc(handle)) +} + +type mux interface { + Handle(string, http.Handler) +} + +// New creates a Config object with the given name. Each Config is registered +// with this package's "/configz" handler. +func New(name string) (*Config, error) { + configsGuard.Lock() + defer configsGuard.Unlock() + if _, found := configs[name]; found { + return nil, fmt.Errorf("register config %q twice", name) + } + newConfig := Config{} + configs[name] = &newConfig + return &newConfig, nil +} + +// Delete removes the named ComponentConfig from this package's "/configz" +// handler. +func Delete(name string) { + configsGuard.Lock() + defer configsGuard.Unlock() + delete(configs, name) +} + +// Set sets the ComponentConfig for this Config. +func (v *Config) Set(val interface{}) { + configsGuard.Lock() + defer configsGuard.Unlock() + v.val = val +} + +// MarshalJSON marshals the ComponentConfig as JSON data. +func (v *Config) MarshalJSON() ([]byte, error) { + return json.Marshal(v.val) +} + +func handle(w http.ResponseWriter, r *http.Request) { + if err := write(w); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } +} + +func write(w http.ResponseWriter) error { + var b []byte + var err error + func() { + configsGuard.RLock() + defer configsGuard.RUnlock() + b, err = json.Marshal(configs) + }() + if err != nil { + return fmt.Errorf("error marshaling json: %v", err) + } + w.Header().Set("Content-Type", "application/json") + w.Header().Set("X-Content-Type-Options", "nosniff") + _, err = w.Write(b) + return err +} diff --git a/vendor/k8s.io/component-base/version/verflag/verflag.go b/vendor/k8s.io/component-base/version/verflag/verflag.go new file mode 100644 index 000000000..106e3450f --- /dev/null +++ b/vendor/k8s.io/component-base/version/verflag/verflag.go @@ -0,0 +1,111 @@ +/* +Copyright 2014 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 verflag defines utility functions to handle command line flags +// related to version of Kubernetes. +package verflag + +import ( + "fmt" + "os" + "strconv" + + flag "github.com/spf13/pflag" + + "k8s.io/component-base/version" +) + +type versionValue int + +const ( + VersionFalse versionValue = 0 + VersionTrue versionValue = 1 + VersionRaw versionValue = 2 +) + +const strRawVersion string = "raw" + +func (v *versionValue) IsBoolFlag() bool { + return true +} + +func (v *versionValue) Get() interface{} { + return versionValue(*v) +} + +func (v *versionValue) Set(s string) error { + if s == strRawVersion { + *v = VersionRaw + return nil + } + boolVal, err := strconv.ParseBool(s) + if boolVal { + *v = VersionTrue + } else { + *v = VersionFalse + } + return err +} + +func (v *versionValue) String() string { + if *v == VersionRaw { + return strRawVersion + } + return fmt.Sprintf("%v", bool(*v == VersionTrue)) +} + +// The type of the flag as required by the pflag.Value interface +func (v *versionValue) Type() string { + return "version" +} + +func VersionVar(p *versionValue, name string, value versionValue, usage string) { + *p = value + flag.Var(p, name, usage) + // "--version" will be treated as "--version=true" + flag.Lookup(name).NoOptDefVal = "true" +} + +func Version(name string, value versionValue, usage string) *versionValue { + p := new(versionValue) + VersionVar(p, name, value, usage) + return p +} + +const versionFlagName = "version" + +var ( + versionFlag = Version(versionFlagName, VersionFalse, "Print version information and quit") + programName = "Kubernetes" +) + +// AddFlags registers this package's flags on arbitrary FlagSets, such that they point to the +// same value as the global flags. +func AddFlags(fs *flag.FlagSet) { + fs.AddFlag(flag.Lookup(versionFlagName)) +} + +// PrintAndExitIfRequested will check if the -version flag was passed +// and, if so, print the version and exit. +func PrintAndExitIfRequested() { + if *versionFlag == VersionRaw { + fmt.Printf("%#v\n", version.Get()) + os.Exit(0) + } else if *versionFlag == VersionTrue { + fmt.Printf("%s %s\n", programName, version.Get()) + os.Exit(0) + } +} diff --git a/vendor/k8s.io/component-helpers/LICENSE b/vendor/k8s.io/component-helpers/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/k8s.io/component-helpers/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/vendor/k8s.io/component-helpers/node/topology/helpers.go b/vendor/k8s.io/component-helpers/node/topology/helpers.go new file mode 100644 index 000000000..8eaff674a --- /dev/null +++ b/vendor/k8s.io/component-helpers/node/topology/helpers.go @@ -0,0 +1,58 @@ +/* +Copyright 2020 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 topology + +import ( + "k8s.io/api/core/v1" +) + +// GetZoneKey is a helper function that builds a string identifier that is unique per failure-zone; +// it returns empty-string for no zone. +// Since there are currently two separate zone keys: +// - "failure-domain.beta.kubernetes.io/zone" +// - "topology.kubernetes.io/zone" +// +// GetZoneKey will first check failure-domain.beta.kubernetes.io/zone and if not exists, will then check +// topology.kubernetes.io/zone +func GetZoneKey(node *v1.Node) string { + labels := node.Labels + if labels == nil { + return "" + } + + // TODO: "failure-domain.beta..." names are deprecated, but will + // stick around a long time due to existing on old extant objects like PVs. + // Maybe one day we can stop considering them (see #88493). + zone, ok := labels[v1.LabelFailureDomainBetaZone] + if !ok { + zone, _ = labels[v1.LabelTopologyZone] + } + + region, ok := labels[v1.LabelFailureDomainBetaRegion] + if !ok { + region, _ = labels[v1.LabelTopologyRegion] + } + + if region == "" && zone == "" { + return "" + } + + // We include the null character just in case region or failureDomain has a colon + // (We do assume there's no null characters in a region or failureDomain) + // As a nice side-benefit, the null character is not printed by fmt.Print or glog + return region + ":\x00:" + zone +} diff --git a/vendor/k8s.io/component-helpers/node/util/sysctl/sysctl.go b/vendor/k8s.io/component-helpers/node/util/sysctl/sysctl.go new file mode 100644 index 000000000..4910aa22d --- /dev/null +++ b/vendor/k8s.io/component-helpers/node/util/sysctl/sysctl.go @@ -0,0 +1,100 @@ +/* +Copyright 2015 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 sysctl + +import ( + "os" + "path" + "strconv" + "strings" +) + +const ( + sysctlBase = "/proc/sys" + // VMOvercommitMemory refers to the sysctl variable responsible for defining + // the memory over-commit policy used by kernel. + VMOvercommitMemory = "vm/overcommit_memory" + // VMPanicOnOOM refers to the sysctl variable responsible for defining + // the OOM behavior used by kernel. + VMPanicOnOOM = "vm/panic_on_oom" + // KernelPanic refers to the sysctl variable responsible for defining + // the timeout after a panic for the kernel to reboot. + KernelPanic = "kernel/panic" + // KernelPanicOnOops refers to the sysctl variable responsible for defining + // the kernel behavior when an oops or BUG is encountered. + KernelPanicOnOops = "kernel/panic_on_oops" + // RootMaxKeys refers to the sysctl variable responsible for defining + // the maximum number of keys that the root user (UID 0 in the root user namespace) may own. + RootMaxKeys = "kernel/keys/root_maxkeys" + // RootMaxBytes refers to the sysctl variable responsible for defining + // the maximum number of bytes of data that the root user (UID 0 in the root user namespace) + // can hold in the payloads of the keys owned by root. + RootMaxBytes = "kernel/keys/root_maxbytes" + + // VMOvercommitMemoryAlways represents that kernel performs no memory over-commit handling. + VMOvercommitMemoryAlways = 1 + // VMPanicOnOOMInvokeOOMKiller represents that kernel calls the oom_killer function when OOM occurs. + VMPanicOnOOMInvokeOOMKiller = 0 + + // KernelPanicOnOopsAlways represents that kernel panics on kernel oops. + KernelPanicOnOopsAlways = 1 + // KernelPanicRebootTimeout is the timeout seconds after a panic for the kernel to reboot. + KernelPanicRebootTimeout = 10 + + // RootMaxKeysSetting is the maximum number of keys that the root user (UID 0 in the root user namespace) may own. + // Needed since docker creates a new key per container. + RootMaxKeysSetting = 1000000 + // RootMaxBytesSetting is the maximum number of bytes of data that the root user (UID 0 in the root user namespace) + // can hold in the payloads of the keys owned by root. + // Allocate 25 bytes per key * number of MaxKeys. + RootMaxBytesSetting = RootMaxKeysSetting * 25 +) + +// Interface is an injectable interface for running sysctl commands. +type Interface interface { + // GetSysctl returns the value for the specified sysctl setting + GetSysctl(sysctl string) (int, error) + // SetSysctl modifies the specified sysctl flag to the new value + SetSysctl(sysctl string, newVal int) error +} + +// New returns a new Interface for accessing sysctl +func New() Interface { + return &procSysctl{} +} + +// procSysctl implements Interface by reading and writing files under /proc/sys +type procSysctl struct { +} + +// GetSysctl returns the value for the specified sysctl setting +func (*procSysctl) GetSysctl(sysctl string) (int, error) { + data, err := os.ReadFile(path.Join(sysctlBase, sysctl)) + if err != nil { + return -1, err + } + val, err := strconv.Atoi(strings.Trim(string(data), " \n")) + if err != nil { + return -1, err + } + return val, nil +} + +// SetSysctl modifies the specified sysctl flag to the new value +func (*procSysctl) SetSysctl(sysctl string, newVal int) error { + return os.WriteFile(path.Join(sysctlBase, sysctl), []byte(strconv.Itoa(newVal)), 0640) +} diff --git a/vendor/k8s.io/component-helpers/scheduling/corev1/doc.go b/vendor/k8s.io/component-helpers/scheduling/corev1/doc.go new file mode 100644 index 000000000..c6cf8132a --- /dev/null +++ b/vendor/k8s.io/component-helpers/scheduling/corev1/doc.go @@ -0,0 +1,23 @@ +/* +Copyright 2020 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 corev1 defines functions which should satisfy one of the following: +// +// - Be used by more than one core component (kube-scheduler, kubelet, kube-apiserver, etc.) +// - Be used by a core component and another kubernetes project (cluster-autoscaler, descheduler) +// +// And be a scheduling feature. +package corev1 // import "k8s.io/component-helpers/scheduling/corev1" diff --git a/vendor/k8s.io/component-helpers/scheduling/corev1/helpers.go b/vendor/k8s.io/component-helpers/scheduling/corev1/helpers.go new file mode 100644 index 000000000..23a94bd7b --- /dev/null +++ b/vendor/k8s.io/component-helpers/scheduling/corev1/helpers.go @@ -0,0 +1,101 @@ +/* +Copyright 2020 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 corev1 + +import ( + "encoding/json" + + v1 "k8s.io/api/core/v1" + "k8s.io/component-helpers/scheduling/corev1/nodeaffinity" +) + +// PodPriority returns priority of the given pod. +func PodPriority(pod *v1.Pod) int32 { + if pod.Spec.Priority != nil { + return *pod.Spec.Priority + } + // When priority of a running pod is nil, it means it was created at a time + // that there was no global default priority class and the priority class + // name of the pod was empty. So, we resolve to the static default priority. + return 0 +} + +// MatchNodeSelectorTerms checks whether the node labels and fields match node selector terms in ORed; +// nil or empty term matches no objects. +func MatchNodeSelectorTerms( + node *v1.Node, + nodeSelector *v1.NodeSelector, +) (bool, error) { + if node == nil { + return false, nil + } + return nodeaffinity.NewLazyErrorNodeSelector(nodeSelector).Match(node) +} + +// GetAvoidPodsFromNodeAnnotations scans the list of annotations and +// returns the pods that needs to be avoided for this node from scheduling +func GetAvoidPodsFromNodeAnnotations(annotations map[string]string) (v1.AvoidPods, error) { + var avoidPods v1.AvoidPods + if len(annotations) > 0 && annotations[v1.PreferAvoidPodsAnnotationKey] != "" { + err := json.Unmarshal([]byte(annotations[v1.PreferAvoidPodsAnnotationKey]), &avoidPods) + if err != nil { + return avoidPods, err + } + } + return avoidPods, nil +} + +// TolerationsTolerateTaint checks if taint is tolerated by any of the tolerations. +func TolerationsTolerateTaint(tolerations []v1.Toleration, taint *v1.Taint) bool { + for i := range tolerations { + if tolerations[i].ToleratesTaint(taint) { + return true + } + } + return false +} + +type taintsFilterFunc func(*v1.Taint) bool + +// FindMatchingUntoleratedTaint checks if the given tolerations tolerates +// all the filtered taints, and returns the first taint without a toleration +// Returns true if there is an untolerated taint +// Returns false if all taints are tolerated +func FindMatchingUntoleratedTaint(taints []v1.Taint, tolerations []v1.Toleration, inclusionFilter taintsFilterFunc) (v1.Taint, bool) { + filteredTaints := getFilteredTaints(taints, inclusionFilter) + for _, taint := range filteredTaints { + if !TolerationsTolerateTaint(tolerations, &taint) { + return taint, true + } + } + return v1.Taint{}, false +} + +// getFilteredTaints returns a list of taints satisfying the filter predicate +func getFilteredTaints(taints []v1.Taint, inclusionFilter taintsFilterFunc) []v1.Taint { + if inclusionFilter == nil { + return taints + } + filteredTaints := []v1.Taint{} + for _, taint := range taints { + if !inclusionFilter(&taint) { + continue + } + filteredTaints = append(filteredTaints, taint) + } + return filteredTaints +} diff --git a/vendor/k8s.io/component-helpers/scheduling/corev1/nodeaffinity/nodeaffinity.go b/vendor/k8s.io/component-helpers/scheduling/corev1/nodeaffinity/nodeaffinity.go new file mode 100644 index 000000000..27caf69b9 --- /dev/null +++ b/vendor/k8s.io/component-helpers/scheduling/corev1/nodeaffinity/nodeaffinity.go @@ -0,0 +1,324 @@ +/* +Copyright 2020 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 nodeaffinity + +import ( + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/selection" + "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apimachinery/pkg/util/validation/field" +) + +// NodeSelector is a runtime representation of v1.NodeSelector. +type NodeSelector struct { + lazy LazyErrorNodeSelector +} + +// LazyErrorNodeSelector is a runtime representation of v1.NodeSelector that +// only reports parse errors when no terms match. +type LazyErrorNodeSelector struct { + terms []nodeSelectorTerm +} + +// NewNodeSelector returns a NodeSelector or aggregate parsing errors found. +func NewNodeSelector(ns *v1.NodeSelector, opts ...field.PathOption) (*NodeSelector, error) { + lazy := NewLazyErrorNodeSelector(ns, opts...) + var errs []error + for _, term := range lazy.terms { + if len(term.parseErrs) > 0 { + errs = append(errs, term.parseErrs...) + } + } + if len(errs) != 0 { + return nil, errors.Flatten(errors.NewAggregate(errs)) + } + return &NodeSelector{lazy: *lazy}, nil +} + +// NewLazyErrorNodeSelector creates a NodeSelector that only reports parse +// errors when no terms match. +func NewLazyErrorNodeSelector(ns *v1.NodeSelector, opts ...field.PathOption) *LazyErrorNodeSelector { + p := field.ToPath(opts...) + parsedTerms := make([]nodeSelectorTerm, 0, len(ns.NodeSelectorTerms)) + path := p.Child("nodeSelectorTerms") + for i, term := range ns.NodeSelectorTerms { + // nil or empty term selects no objects + if isEmptyNodeSelectorTerm(&term) { + continue + } + p := path.Index(i) + parsedTerms = append(parsedTerms, newNodeSelectorTerm(&term, p)) + } + return &LazyErrorNodeSelector{ + terms: parsedTerms, + } +} + +// Match checks whether the node labels and fields match the selector terms, ORed; +// nil or empty term matches no objects. +func (ns *NodeSelector) Match(node *v1.Node) bool { + // parse errors are reported in NewNodeSelector. + match, _ := ns.lazy.Match(node) + return match +} + +// Match checks whether the node labels and fields match the selector terms, ORed; +// nil or empty term matches no objects. +// Parse errors are only returned if no terms matched. +func (ns *LazyErrorNodeSelector) Match(node *v1.Node) (bool, error) { + if node == nil { + return false, nil + } + nodeLabels := labels.Set(node.Labels) + nodeFields := extractNodeFields(node) + + var errs []error + for _, term := range ns.terms { + match, tErrs := term.match(nodeLabels, nodeFields) + if len(tErrs) > 0 { + errs = append(errs, tErrs...) + continue + } + if match { + return true, nil + } + } + return false, errors.Flatten(errors.NewAggregate(errs)) +} + +// PreferredSchedulingTerms is a runtime representation of []v1.PreferredSchedulingTerms. +type PreferredSchedulingTerms struct { + terms []preferredSchedulingTerm +} + +// NewPreferredSchedulingTerms returns a PreferredSchedulingTerms or all the parsing errors found. +// If a v1.PreferredSchedulingTerm has a 0 weight, its parsing is skipped. +func NewPreferredSchedulingTerms(terms []v1.PreferredSchedulingTerm, opts ...field.PathOption) (*PreferredSchedulingTerms, error) { + p := field.ToPath(opts...) + var errs []error + parsedTerms := make([]preferredSchedulingTerm, 0, len(terms)) + for i, term := range terms { + path := p.Index(i) + if term.Weight == 0 || isEmptyNodeSelectorTerm(&term.Preference) { + continue + } + parsedTerm := preferredSchedulingTerm{ + nodeSelectorTerm: newNodeSelectorTerm(&term.Preference, path), + weight: int(term.Weight), + } + if len(parsedTerm.parseErrs) > 0 { + errs = append(errs, parsedTerm.parseErrs...) + } else { + parsedTerms = append(parsedTerms, parsedTerm) + } + } + if len(errs) != 0 { + return nil, errors.Flatten(errors.NewAggregate(errs)) + } + return &PreferredSchedulingTerms{terms: parsedTerms}, nil +} + +// Score returns a score for a Node: the sum of the weights of the terms that +// match the Node. +func (t *PreferredSchedulingTerms) Score(node *v1.Node) int64 { + var score int64 + nodeLabels := labels.Set(node.Labels) + nodeFields := extractNodeFields(node) + for _, term := range t.terms { + // parse errors are reported in NewPreferredSchedulingTerms. + if ok, _ := term.match(nodeLabels, nodeFields); ok { + score += int64(term.weight) + } + } + return score +} + +func isEmptyNodeSelectorTerm(term *v1.NodeSelectorTerm) bool { + return len(term.MatchExpressions) == 0 && len(term.MatchFields) == 0 +} + +func extractNodeFields(n *v1.Node) fields.Set { + f := make(fields.Set) + if len(n.Name) > 0 { + f["metadata.name"] = n.Name + } + return f +} + +type nodeSelectorTerm struct { + matchLabels labels.Selector + matchFields fields.Selector + parseErrs []error +} + +func newNodeSelectorTerm(term *v1.NodeSelectorTerm, path *field.Path) nodeSelectorTerm { + var parsedTerm nodeSelectorTerm + var errs []error + if len(term.MatchExpressions) != 0 { + p := path.Child("matchExpressions") + parsedTerm.matchLabels, errs = nodeSelectorRequirementsAsSelector(term.MatchExpressions, p) + if errs != nil { + parsedTerm.parseErrs = append(parsedTerm.parseErrs, errs...) + } + } + if len(term.MatchFields) != 0 { + p := path.Child("matchFields") + parsedTerm.matchFields, errs = nodeSelectorRequirementsAsFieldSelector(term.MatchFields, p) + if errs != nil { + parsedTerm.parseErrs = append(parsedTerm.parseErrs, errs...) + } + } + return parsedTerm +} + +func (t *nodeSelectorTerm) match(nodeLabels labels.Set, nodeFields fields.Set) (bool, []error) { + if t.parseErrs != nil { + return false, t.parseErrs + } + if t.matchLabels != nil && !t.matchLabels.Matches(nodeLabels) { + return false, nil + } + if t.matchFields != nil && len(nodeFields) > 0 && !t.matchFields.Matches(nodeFields) { + return false, nil + } + return true, nil +} + +// nodeSelectorRequirementsAsSelector converts the []NodeSelectorRequirement api type into a struct that implements +// labels.Selector. +func nodeSelectorRequirementsAsSelector(nsm []v1.NodeSelectorRequirement, path *field.Path) (labels.Selector, []error) { + if len(nsm) == 0 { + return labels.Nothing(), nil + } + var errs []error + selector := labels.NewSelector() + for i, expr := range nsm { + p := path.Index(i) + var op selection.Operator + switch expr.Operator { + case v1.NodeSelectorOpIn: + op = selection.In + case v1.NodeSelectorOpNotIn: + op = selection.NotIn + case v1.NodeSelectorOpExists: + op = selection.Exists + case v1.NodeSelectorOpDoesNotExist: + op = selection.DoesNotExist + case v1.NodeSelectorOpGt: + op = selection.GreaterThan + case v1.NodeSelectorOpLt: + op = selection.LessThan + default: + errs = append(errs, field.NotSupported(p.Child("operator"), expr.Operator, nil)) + continue + } + r, err := labels.NewRequirement(expr.Key, op, expr.Values, field.WithPath(p)) + if err != nil { + errs = append(errs, err) + } else { + selector = selector.Add(*r) + } + } + if len(errs) != 0 { + return nil, errs + } + return selector, nil +} + +var validFieldSelectorOperators = []string{ + string(v1.NodeSelectorOpIn), + string(v1.NodeSelectorOpNotIn), +} + +// nodeSelectorRequirementsAsFieldSelector converts the []NodeSelectorRequirement core type into a struct that implements +// fields.Selector. +func nodeSelectorRequirementsAsFieldSelector(nsr []v1.NodeSelectorRequirement, path *field.Path) (fields.Selector, []error) { + if len(nsr) == 0 { + return fields.Nothing(), nil + } + var errs []error + + var selectors []fields.Selector + for i, expr := range nsr { + p := path.Index(i) + switch expr.Operator { + case v1.NodeSelectorOpIn: + if len(expr.Values) != 1 { + errs = append(errs, field.Invalid(p.Child("values"), expr.Values, "must have one element")) + } else { + selectors = append(selectors, fields.OneTermEqualSelector(expr.Key, expr.Values[0])) + } + + case v1.NodeSelectorOpNotIn: + if len(expr.Values) != 1 { + errs = append(errs, field.Invalid(p.Child("values"), expr.Values, "must have one element")) + } else { + selectors = append(selectors, fields.OneTermNotEqualSelector(expr.Key, expr.Values[0])) + } + + default: + errs = append(errs, field.NotSupported(p.Child("operator"), expr.Operator, validFieldSelectorOperators)) + } + } + + if len(errs) != 0 { + return nil, errs + } + return fields.AndSelectors(selectors...), nil +} + +type preferredSchedulingTerm struct { + nodeSelectorTerm + weight int +} + +type RequiredNodeAffinity struct { + labelSelector labels.Selector + nodeSelector *LazyErrorNodeSelector +} + +// GetRequiredNodeAffinity returns the parsing result of pod's nodeSelector and nodeAffinity. +func GetRequiredNodeAffinity(pod *v1.Pod) RequiredNodeAffinity { + var selector labels.Selector + if len(pod.Spec.NodeSelector) > 0 { + selector = labels.SelectorFromSet(pod.Spec.NodeSelector) + } + // Use LazyErrorNodeSelector for backwards compatibility of parsing errors. + var affinity *LazyErrorNodeSelector + if pod.Spec.Affinity != nil && + pod.Spec.Affinity.NodeAffinity != nil && + pod.Spec.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution != nil { + affinity = NewLazyErrorNodeSelector(pod.Spec.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution) + } + return RequiredNodeAffinity{labelSelector: selector, nodeSelector: affinity} +} + +// Match checks whether the pod is schedulable onto nodes according to +// the requirements in both nodeSelector and nodeAffinity. +func (s RequiredNodeAffinity) Match(node *v1.Node) (bool, error) { + if s.labelSelector != nil { + if !s.labelSelector.Matches(labels.Set(node.Labels)) { + return false, nil + } + } + if s.nodeSelector != nil { + return s.nodeSelector.Match(node) + } + return true, nil +} diff --git a/vendor/k8s.io/component-helpers/storage/ephemeral/ephemeral.go b/vendor/k8s.io/component-helpers/storage/ephemeral/ephemeral.go new file mode 100644 index 000000000..67dddaf5c --- /dev/null +++ b/vendor/k8s.io/component-helpers/storage/ephemeral/ephemeral.go @@ -0,0 +1,57 @@ +/* +Copyright 2021 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 ephemeral provides code that supports the usual pattern +// for accessing the PVC that provides a generic ephemeral inline volume: +// +// - determine the PVC name that corresponds to the inline volume source +// - retrieve the PVC +// - verify that the PVC is owned by the pod +// - use the PVC +package ephemeral + +import ( + "fmt" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// VolumeClaimName returns the name of the PersistentVolumeClaim +// object that gets created for the generic ephemeral inline volume. The +// name is deterministic and therefore this function does not need any +// additional information besides the Pod name and volume name and it +// will never fail. +// +// Before using the PVC for the Pod, the caller must check that it is +// indeed the PVC that was created for the Pod by calling IsUsable. +func VolumeClaimName(pod *v1.Pod, volume *v1.Volume) string { + return pod.Name + "-" + volume.Name +} + +// VolumeIsForPod checks that the PVC is the ephemeral volume that +// was created for the Pod. It returns an error that is informative +// enough to be returned by the caller without adding further details +// about the Pod or PVC. +func VolumeIsForPod(pod *v1.Pod, pvc *v1.PersistentVolumeClaim) error { + // Checking the namespaces is just a precaution. The caller should + // never pass in a PVC that isn't from the same namespace as the + // Pod. + if pvc.Namespace != pod.Namespace || !metav1.IsControlledBy(pvc, pod) { + return fmt.Errorf("PVC %s/%s was not created for pod %s/%s (pod is not owner)", pvc.Namespace, pvc.Name, pod.Namespace, pod.Name) + } + return nil +} diff --git a/vendor/k8s.io/component-helpers/storage/volume/helpers.go b/vendor/k8s.io/component-helpers/storage/volume/helpers.go new file mode 100644 index 000000000..7ec376f34 --- /dev/null +++ b/vendor/k8s.io/component-helpers/storage/volume/helpers.go @@ -0,0 +1,70 @@ +/* +Copyright 2020 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 volume + +import ( + "fmt" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/component-helpers/scheduling/corev1" +) + +// GetPersistentVolumeClaimClass returns StorageClassName. If no storage class was +// requested, it returns "". +func GetPersistentVolumeClaimClass(claim *v1.PersistentVolumeClaim) string { + // Use beta annotation first + if class, found := claim.Annotations[v1.BetaStorageClassAnnotation]; found { + return class + } + + if claim.Spec.StorageClassName != nil { + return *claim.Spec.StorageClassName + } + + return "" +} + +// GetPersistentVolumeClass returns StorageClassName. +func GetPersistentVolumeClass(volume *v1.PersistentVolume) string { + // Use beta annotation first + if class, found := volume.Annotations[v1.BetaStorageClassAnnotation]; found { + return class + } + + return volume.Spec.StorageClassName +} + +// CheckNodeAffinity looks at the PV node affinity, and checks if the node has the same corresponding labels +// This ensures that we don't mount a volume that doesn't belong to this node +func CheckNodeAffinity(pv *v1.PersistentVolume, nodeLabels map[string]string) error { + if pv.Spec.NodeAffinity == nil { + return nil + } + + if pv.Spec.NodeAffinity.Required != nil { + node := &v1.Node{ObjectMeta: metav1.ObjectMeta{Labels: nodeLabels}} + terms := pv.Spec.NodeAffinity.Required + if matches, err := corev1.MatchNodeSelectorTerms(node, terms); err != nil { + return err + } else if !matches { + return fmt.Errorf("no matching NodeSelectorTerms") + } + } + + return nil +} diff --git a/vendor/k8s.io/component-helpers/storage/volume/pv_helpers.go b/vendor/k8s.io/component-helpers/storage/volume/pv_helpers.go new file mode 100644 index 000000000..f927b7231 --- /dev/null +++ b/vendor/k8s.io/component-helpers/storage/volume/pv_helpers.go @@ -0,0 +1,342 @@ +/* +Copyright 2019 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 volume + +import ( + "fmt" + + v1 "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/kubernetes/scheme" + storagelisters "k8s.io/client-go/listers/storage/v1" + "k8s.io/client-go/tools/reference" +) + +const ( + // AnnBindCompleted Annotation applies to PVCs. It indicates that the lifecycle + // of the PVC has passed through the initial setup. This information changes how + // we interpret some observations of the state of the objects. Value of this + // Annotation does not matter. + AnnBindCompleted = "pv.kubernetes.io/bind-completed" + + // AnnBoundByController annotation applies to PVs and PVCs. It indicates that + // the binding (PV->PVC or PVC->PV) was installed by the controller. The + // absence of this annotation means the binding was done by the user (i.e. + // pre-bound). Value of this annotation does not matter. + // External PV binders must bind PV the same way as PV controller, otherwise PV + // controller may not handle it correctly. + AnnBoundByController = "pv.kubernetes.io/bound-by-controller" + + // AnnSelectedNode annotation is added to a PVC that has been triggered by scheduler to + // be dynamically provisioned. Its value is the name of the selected node. + AnnSelectedNode = "volume.kubernetes.io/selected-node" + + // NotSupportedProvisioner is a special provisioner name which can be set + // in storage class to indicate dynamic provisioning is not supported by + // the storage. + NotSupportedProvisioner = "kubernetes.io/no-provisioner" + + // AnnDynamicallyProvisioned annotation is added to a PV that has been dynamically provisioned by + // Kubernetes. Its value is name of volume plugin that created the volume. + // It serves both user (to show where a PV comes from) and Kubernetes (to + // recognize dynamically provisioned PVs in its decisions). + AnnDynamicallyProvisioned = "pv.kubernetes.io/provisioned-by" + + // AnnMigratedTo annotation is added to a PVC and PV that is supposed to be + // dynamically provisioned/deleted by by its corresponding CSI driver + // through the CSIMigration feature flags. When this annotation is set the + // Kubernetes components will "stand-down" and the external-provisioner will + // act on the objects + AnnMigratedTo = "pv.kubernetes.io/migrated-to" + + // AnnStorageProvisioner annotation is added to a PVC that is supposed to be dynamically + // provisioned. Its value is name of volume plugin that is supposed to provision + // a volume for this PVC. + // TODO: remove beta anno once deprecation period ends + AnnStorageProvisioner = "volume.kubernetes.io/storage-provisioner" + AnnBetaStorageProvisioner = "volume.beta.kubernetes.io/storage-provisioner" + + //PVDeletionProtectionFinalizer is the finalizer added by the external-provisioner on the PV + PVDeletionProtectionFinalizer = "external-provisioner.volume.kubernetes.io/finalizer" + + // PVDeletionInTreeProtectionFinalizer is the finalizer added to protect PV deletion for in-tree volumes. + PVDeletionInTreeProtectionFinalizer = "kubernetes.io/pv-controller" +) + +// IsDelayBindingProvisioning checks if claim provisioning with selected-node annotation +func IsDelayBindingProvisioning(claim *v1.PersistentVolumeClaim) bool { + // When feature VolumeScheduling enabled, + // Scheduler signal to the PV controller to start dynamic + // provisioning by setting the "AnnSelectedNode" annotation + // in the PVC + _, ok := claim.Annotations[AnnSelectedNode] + return ok +} + +// IsDelayBindingMode checks if claim is in delay binding mode. +func IsDelayBindingMode(claim *v1.PersistentVolumeClaim, classLister storagelisters.StorageClassLister) (bool, error) { + className := GetPersistentVolumeClaimClass(claim) + if className == "" { + return false, nil + } + + class, err := classLister.Get(className) + if err != nil { + if apierrors.IsNotFound(err) { + return false, nil + } + return false, err + } + + if class.VolumeBindingMode == nil { + return false, fmt.Errorf("VolumeBindingMode not set for StorageClass %q", className) + } + + return *class.VolumeBindingMode == storage.VolumeBindingWaitForFirstConsumer, nil +} + +// GetBindVolumeToClaim returns a new volume which is bound to given claim. In +// addition, it returns a bool which indicates whether we made modification on +// original volume. +func GetBindVolumeToClaim(volume *v1.PersistentVolume, claim *v1.PersistentVolumeClaim) (*v1.PersistentVolume, bool, error) { + dirty := false + + // Check if the volume was already bound (either by user or by controller) + shouldSetBoundByController := false + if !IsVolumeBoundToClaim(volume, claim) { + shouldSetBoundByController = true + } + + // The volume from method args can be pointing to watcher cache. We must not + // modify these, therefore create a copy. + volumeClone := volume.DeepCopy() + + // Bind the volume to the claim if it is not bound yet + if volume.Spec.ClaimRef == nil || + volume.Spec.ClaimRef.Name != claim.Name || + volume.Spec.ClaimRef.Namespace != claim.Namespace || + volume.Spec.ClaimRef.UID != claim.UID { + + claimRef, err := reference.GetReference(scheme.Scheme, claim) + if err != nil { + return nil, false, fmt.Errorf("unexpected error getting claim reference: %w", err) + } + volumeClone.Spec.ClaimRef = claimRef + dirty = true + } + + // Set AnnBoundByController if it is not set yet + if shouldSetBoundByController && !metav1.HasAnnotation(volumeClone.ObjectMeta, AnnBoundByController) { + metav1.SetMetaDataAnnotation(&volumeClone.ObjectMeta, AnnBoundByController, "yes") + dirty = true + } + + return volumeClone, dirty, nil +} + +// IsVolumeBoundToClaim returns true, if given volume is pre-bound or bound +// to specific claim. Both claim.Name and claim.Namespace must be equal. +// If claim.UID is present in volume.Spec.ClaimRef, it must be equal too. +func IsVolumeBoundToClaim(volume *v1.PersistentVolume, claim *v1.PersistentVolumeClaim) bool { + if volume.Spec.ClaimRef == nil { + return false + } + if claim.Name != volume.Spec.ClaimRef.Name || claim.Namespace != volume.Spec.ClaimRef.Namespace { + return false + } + if volume.Spec.ClaimRef.UID != "" && claim.UID != volume.Spec.ClaimRef.UID { + return false + } + return true +} + +// FindMatchingVolume goes through the list of volumes to find the best matching volume +// for the claim. +// +// This function is used by both the PV controller and scheduler. +// +// delayBinding is true only in the PV controller path. When set, prebound PVs are still returned +// as a match for the claim, but unbound PVs are skipped. +// +// node is set only in the scheduler path. When set, the PV node affinity is checked against +// the node's labels. +// +// excludedVolumes is only used in the scheduler path, and is needed for evaluating multiple +// unbound PVCs for a single Pod at one time. As each PVC finds a matching PV, the chosen +// PV needs to be excluded from future matching. +func FindMatchingVolume( + claim *v1.PersistentVolumeClaim, + volumes []*v1.PersistentVolume, + node *v1.Node, + excludedVolumes map[string]*v1.PersistentVolume, + delayBinding bool) (*v1.PersistentVolume, error) { + + var smallestVolume *v1.PersistentVolume + var smallestVolumeQty resource.Quantity + requestedQty := claim.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)] + requestedClass := GetPersistentVolumeClaimClass(claim) + + var selector labels.Selector + if claim.Spec.Selector != nil { + internalSelector, err := metav1.LabelSelectorAsSelector(claim.Spec.Selector) + if err != nil { + return nil, fmt.Errorf("error creating internal label selector for claim: %v: %v", claimToClaimKey(claim), err) + } + selector = internalSelector + } + + // Go through all available volumes with two goals: + // - find a volume that is either pre-bound by user or dynamically + // provisioned for this claim. Because of this we need to loop through + // all volumes. + // - find the smallest matching one if there is no volume pre-bound to + // the claim. + for _, volume := range volumes { + if _, ok := excludedVolumes[volume.Name]; ok { + // Skip volumes in the excluded list + continue + } + if volume.Spec.ClaimRef != nil && !IsVolumeBoundToClaim(volume, claim) { + continue + } + + volumeQty := volume.Spec.Capacity[v1.ResourceStorage] + if volumeQty.Cmp(requestedQty) < 0 { + continue + } + // filter out mismatching volumeModes + if CheckVolumeModeMismatches(&claim.Spec, &volume.Spec) { + continue + } + + // check if PV's DeletionTimeStamp is set, if so, skip this volume. + if volume.ObjectMeta.DeletionTimestamp != nil { + continue + } + + nodeAffinityValid := true + if node != nil { + // Scheduler path, check that the PV NodeAffinity + // is satisfied by the node + // CheckNodeAffinity is the most expensive call in this loop. + // We should check cheaper conditions first or consider optimizing this function. + err := CheckNodeAffinity(volume, node.Labels) + if err != nil { + nodeAffinityValid = false + } + } + + if IsVolumeBoundToClaim(volume, claim) { + // If PV node affinity is invalid, return no match. + // This means the prebound PV (and therefore PVC) + // is not suitable for this node. + if !nodeAffinityValid { + return nil, nil + } + + return volume, nil + } + + if node == nil && delayBinding { + // PV controller does not bind this claim. + // Scheduler will handle binding unbound volumes + // Scheduler path will have node != nil + continue + } + + // filter out: + // - volumes in non-available phase + // - volumes whose labels don't match the claim's selector, if specified + // - volumes in Class that is not requested + // - volumes whose NodeAffinity does not match the node + if volume.Status.Phase != v1.VolumeAvailable { + // We ignore volumes in non-available phase, because volumes that + // satisfies matching criteria will be updated to available, binding + // them now has high chance of encountering unnecessary failures + // due to API conflicts. + continue + } else if selector != nil && !selector.Matches(labels.Set(volume.Labels)) { + continue + } + if GetPersistentVolumeClass(volume) != requestedClass { + continue + } + if !nodeAffinityValid { + continue + } + + if node != nil { + // Scheduler path + // Check that the access modes match + if !CheckAccessModes(claim, volume) { + continue + } + } + + if smallestVolume == nil || smallestVolumeQty.Cmp(volumeQty) > 0 { + smallestVolume = volume + smallestVolumeQty = volumeQty + } + } + + if smallestVolume != nil { + // Found a matching volume + return smallestVolume, nil + } + + return nil, nil +} + +// CheckVolumeModeMismatches is a convenience method that checks volumeMode for PersistentVolume +// and PersistentVolumeClaims +func CheckVolumeModeMismatches(pvcSpec *v1.PersistentVolumeClaimSpec, pvSpec *v1.PersistentVolumeSpec) bool { + // In HA upgrades, we cannot guarantee that the apiserver is on a version >= controller-manager. + // So we default a nil volumeMode to filesystem + requestedVolumeMode := v1.PersistentVolumeFilesystem + if pvcSpec.VolumeMode != nil { + requestedVolumeMode = *pvcSpec.VolumeMode + } + pvVolumeMode := v1.PersistentVolumeFilesystem + if pvSpec.VolumeMode != nil { + pvVolumeMode = *pvSpec.VolumeMode + } + return requestedVolumeMode != pvVolumeMode +} + +// CheckAccessModes returns true if PV satisfies all the PVC's requested AccessModes +func CheckAccessModes(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) bool { + pvModesMap := map[v1.PersistentVolumeAccessMode]bool{} + for _, mode := range volume.Spec.AccessModes { + pvModesMap[mode] = true + } + + for _, mode := range claim.Spec.AccessModes { + _, ok := pvModesMap[mode] + if !ok { + return false + } + } + return true +} + +func claimToClaimKey(claim *v1.PersistentVolumeClaim) string { + return fmt.Sprintf("%s/%s", claim.Namespace, claim.Name) +} diff --git a/vendor/k8s.io/csi-translation-lib/CONTRIBUTING.md b/vendor/k8s.io/csi-translation-lib/CONTRIBUTING.md new file mode 100644 index 000000000..ecdb5f952 --- /dev/null +++ b/vendor/k8s.io/csi-translation-lib/CONTRIBUTING.md @@ -0,0 +1,7 @@ +# Contributing guidelines + +Do not open pull requests directly against this repository, they will be ignored. Instead, please open pull requests against [kubernetes/kubernetes](https://git.k8s.io/kubernetes/). Please follow the same [contributing guide](https://git.k8s.io/kubernetes/CONTRIBUTING.md) you would follow for any other pull request made to kubernetes/kubernetes. + +This repository is published from [kubernetes/kubernetes/staging/src/k8s.io/csi-translation-lib](https://git.k8s.io/kubernetes/staging/src/k8s.io/csi-translation-lib) by the [kubernetes publishing-bot](https://git.k8s.io/publishing-bot). + +Please see [Staging Directory and Publishing](https://git.k8s.io/community/contributors/devel/sig-architecture/staging.md) for more information. diff --git a/vendor/k8s.io/csi-translation-lib/LICENSE b/vendor/k8s.io/csi-translation-lib/LICENSE new file mode 100644 index 000000000..8dada3eda --- /dev/null +++ b/vendor/k8s.io/csi-translation-lib/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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. diff --git a/vendor/k8s.io/csi-translation-lib/OWNERS b/vendor/k8s.io/csi-translation-lib/OWNERS new file mode 100644 index 000000000..3000ec1d5 --- /dev/null +++ b/vendor/k8s.io/csi-translation-lib/OWNERS @@ -0,0 +1,11 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +reviewers: + - sig-storage-reviewers + - andyzhangx +approvers: + - sig-storage-approvers +labels: + - sig/storage +emeritus_approvers: + - davidz627 diff --git a/vendor/k8s.io/csi-translation-lib/README.md b/vendor/k8s.io/csi-translation-lib/README.md new file mode 100644 index 000000000..8c1b5663a --- /dev/null +++ b/vendor/k8s.io/csi-translation-lib/README.md @@ -0,0 +1,30 @@ +## Purpose + +This repository contains functions to be consumed by various Kubernetes and +out-of-tree CSI components like external provisioner to facilitate migration of +code from Kubernetes In-tree plugin code to CSI plugin repositories. + +Consumers of this repository can make use of functions like `TranslateToCSI` and +`TranslateToInTree` functions to translate PV sources. + +## Community, discussion, contribution, and support + +Learn how to engage with the Kubernetes community on the [community +page](http://kubernetes.io/community/). + +You can reach the maintainers of this repository at: + +- Slack: #sig-storage (on https://kubernetes.slack.com -- get an + invite at slack.kubernetes.io) +- Mailing List: + https://groups.google.com/forum/#!forum/kubernetes-sig-storage + +### Code of Conduct + +Participation in the Kubernetes community is governed by the [Kubernetes +Code of Conduct](code-of-conduct.md). + +### Contibution Guidelines + +See [CONTRIBUTING.md](CONTRIBUTING.md) for more information. + diff --git a/vendor/k8s.io/csi-translation-lib/SECURITY_CONTACTS b/vendor/k8s.io/csi-translation-lib/SECURITY_CONTACTS new file mode 100644 index 000000000..14fe23e18 --- /dev/null +++ b/vendor/k8s.io/csi-translation-lib/SECURITY_CONTACTS @@ -0,0 +1,18 @@ +# Defined below are the security contacts for this repo. +# +# They are the contact point for the Product Security Committee to reach out +# to for triaging and handling of incoming issues. +# +# The below names agree to abide by the +# [Embargo Policy](https://git.k8s.io/security/private-distributors-list.md#embargo-policy) +# and will be removed and replaced if they violate that agreement. +# +# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE +# INSTRUCTIONS AT https://kubernetes.io/security/ + +saad-ali +cjcullen +joelsmith +liggitt +philips +tallclair diff --git a/vendor/k8s.io/csi-translation-lib/code-of-conduct.md b/vendor/k8s.io/csi-translation-lib/code-of-conduct.md new file mode 100644 index 000000000..0d15c00cf --- /dev/null +++ b/vendor/k8s.io/csi-translation-lib/code-of-conduct.md @@ -0,0 +1,3 @@ +# Kubernetes Community Code of Conduct + +Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md) diff --git a/vendor/k8s.io/csi-translation-lib/plugins/aws_ebs.go b/vendor/k8s.io/csi-translation-lib/plugins/aws_ebs.go new file mode 100644 index 000000000..cf1ba1124 --- /dev/null +++ b/vendor/k8s.io/csi-translation-lib/plugins/aws_ebs.go @@ -0,0 +1,304 @@ +/* +Copyright 2019 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 plugins + +import ( + "fmt" + "net/url" + "regexp" + "strconv" + "strings" + + v1 "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/sets" +) + +const ( + // AWSEBSDriverName is the name of the CSI driver for EBS + AWSEBSDriverName = "ebs.csi.aws.com" + // AWSEBSInTreePluginName is the name of the intree plugin for EBS + AWSEBSInTreePluginName = "kubernetes.io/aws-ebs" + // AWSEBSTopologyKey is the zonal topology key for AWS EBS CSI driver + AWSEBSTopologyKey = "topology." + AWSEBSDriverName + "/zone" + // iopsPerGBKey is StorageClass parameter name that specifies IOPS + // Per GB. + iopsPerGBKey = "iopspergb" + // allowIncreaseIOPSKey is parameter name that allows the CSI driver + // to increase IOPS to the minimum value supported by AWS when IOPS + // Per GB is too low for a given volume size. This preserves current + // in-tree volume plugin behavior. + allowIncreaseIOPSKey = "allowautoiopspergbincrease" +) + +var _ InTreePlugin = &awsElasticBlockStoreCSITranslator{} + +// awsElasticBlockStoreTranslator handles translation of PV spec from In-tree EBS to CSI EBS and vice versa +type awsElasticBlockStoreCSITranslator struct{} + +// NewAWSElasticBlockStoreCSITranslator returns a new instance of awsElasticBlockStoreTranslator +func NewAWSElasticBlockStoreCSITranslator() InTreePlugin { + return &awsElasticBlockStoreCSITranslator{} +} + +// TranslateInTreeStorageClassToCSI translates InTree EBS storage class parameters to CSI storage class +func (t *awsElasticBlockStoreCSITranslator) TranslateInTreeStorageClassToCSI(sc *storage.StorageClass) (*storage.StorageClass, error) { + var ( + generatedTopologies []v1.TopologySelectorTerm + params = map[string]string{} + ) + for k, v := range sc.Parameters { + switch strings.ToLower(k) { + case fsTypeKey: + params[csiFsTypeKey] = v + case zoneKey: + generatedTopologies = generateToplogySelectors(AWSEBSTopologyKey, []string{v}) + case zonesKey: + generatedTopologies = generateToplogySelectors(AWSEBSTopologyKey, strings.Split(v, ",")) + case iopsPerGBKey: + // Keep iopsPerGBKey + params[k] = v + // Preserve current in-tree volume plugin behavior and allow the CSI + // driver to bump volume IOPS when volume size * iopsPerGB is too low. + params[allowIncreaseIOPSKey] = "true" + default: + params[k] = v + } + } + + if len(generatedTopologies) > 0 && len(sc.AllowedTopologies) > 0 { + return nil, fmt.Errorf("cannot simultaneously set allowed topologies and zone/zones parameters") + } else if len(generatedTopologies) > 0 { + sc.AllowedTopologies = generatedTopologies + } else if len(sc.AllowedTopologies) > 0 { + newTopologies, err := translateAllowedTopologies(sc.AllowedTopologies, AWSEBSTopologyKey) + if err != nil { + return nil, fmt.Errorf("failed translating allowed topologies: %v", err) + } + sc.AllowedTopologies = newTopologies + } + + sc.Parameters = params + + return sc, nil +} + +// TranslateInTreeInlineVolumeToCSI takes a Volume with AWSElasticBlockStore set from in-tree +// and converts the AWSElasticBlockStore source to a CSIPersistentVolumeSource +func (t *awsElasticBlockStoreCSITranslator) TranslateInTreeInlineVolumeToCSI(volume *v1.Volume, podNamespace string) (*v1.PersistentVolume, error) { + if volume == nil || volume.AWSElasticBlockStore == nil { + return nil, fmt.Errorf("volume is nil or AWS EBS not defined on volume") + } + ebsSource := volume.AWSElasticBlockStore + volumeHandle, err := KubernetesVolumeIDToEBSVolumeID(ebsSource.VolumeID) + if err != nil { + return nil, fmt.Errorf("failed to translate Kubernetes ID to EBS Volume ID %v", err) + } + pv := &v1.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + // Must be unique per disk as it is used as the unique part of the + // staging path + Name: fmt.Sprintf("%s-%s", AWSEBSDriverName, volumeHandle), + }, + Spec: v1.PersistentVolumeSpec{ + PersistentVolumeSource: v1.PersistentVolumeSource{ + CSI: &v1.CSIPersistentVolumeSource{ + Driver: AWSEBSDriverName, + VolumeHandle: volumeHandle, + ReadOnly: ebsSource.ReadOnly, + FSType: ebsSource.FSType, + VolumeAttributes: map[string]string{ + "partition": strconv.FormatInt(int64(ebsSource.Partition), 10), + }, + }, + }, + AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, + }, + } + return pv, nil +} + +// TranslateInTreePVToCSI takes a PV with AWSElasticBlockStore set from in-tree +// and converts the AWSElasticBlockStore source to a CSIPersistentVolumeSource +func (t *awsElasticBlockStoreCSITranslator) TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + if pv == nil || pv.Spec.AWSElasticBlockStore == nil { + return nil, fmt.Errorf("pv is nil or AWS EBS not defined on pv") + } + + ebsSource := pv.Spec.AWSElasticBlockStore + + volumeHandle, err := KubernetesVolumeIDToEBSVolumeID(ebsSource.VolumeID) + if err != nil { + return nil, fmt.Errorf("failed to translate Kubernetes ID to EBS Volume ID %v", err) + } + + csiSource := &v1.CSIPersistentVolumeSource{ + Driver: AWSEBSDriverName, + VolumeHandle: volumeHandle, + ReadOnly: ebsSource.ReadOnly, + FSType: ebsSource.FSType, + VolumeAttributes: map[string]string{ + "partition": strconv.FormatInt(int64(ebsSource.Partition), 10), + }, + } + + if err := translateTopologyFromInTreeToCSI(pv, AWSEBSTopologyKey); err != nil { + return nil, fmt.Errorf("failed to translate topology: %v", err) + } + + pv.Spec.AWSElasticBlockStore = nil + pv.Spec.CSI = csiSource + return pv, nil +} + +// TranslateCSIPVToInTree takes a PV with CSIPersistentVolumeSource set and +// translates the EBS CSI source to a AWSElasticBlockStore source. +func (t *awsElasticBlockStoreCSITranslator) TranslateCSIPVToInTree(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + if pv == nil || pv.Spec.CSI == nil { + return nil, fmt.Errorf("pv is nil or CSI source not defined on pv") + } + + csiSource := pv.Spec.CSI + + ebsSource := &v1.AWSElasticBlockStoreVolumeSource{ + VolumeID: csiSource.VolumeHandle, + FSType: csiSource.FSType, + ReadOnly: csiSource.ReadOnly, + } + + if partition, ok := csiSource.VolumeAttributes["partition"]; ok { + partValue, err := strconv.Atoi(partition) + if err != nil { + return nil, fmt.Errorf("failed to convert partition %v to integer: %v", partition, err) + } + ebsSource.Partition = int32(partValue) + } + + // translate CSI topology to In-tree topology for rollback compatibility + if err := translateTopologyFromCSIToInTree(pv, AWSEBSTopologyKey, getAwsRegionFromZones); err != nil { + return nil, fmt.Errorf("failed to translate topology. PV:%+v. Error:%v", *pv, err) + } + + pv.Spec.CSI = nil + pv.Spec.AWSElasticBlockStore = ebsSource + return pv, nil +} + +// CanSupport tests whether the plugin supports a given persistent volume +// specification from the API. The spec pointer should be considered +// const. +func (t *awsElasticBlockStoreCSITranslator) CanSupport(pv *v1.PersistentVolume) bool { + return pv != nil && pv.Spec.AWSElasticBlockStore != nil +} + +// CanSupportInline tests whether the plugin supports a given inline volume +// specification from the API. The spec pointer should be considered +// const. +func (t *awsElasticBlockStoreCSITranslator) CanSupportInline(volume *v1.Volume) bool { + return volume != nil && volume.AWSElasticBlockStore != nil +} + +// GetInTreePluginName returns the name of the intree plugin driver +func (t *awsElasticBlockStoreCSITranslator) GetInTreePluginName() string { + return AWSEBSInTreePluginName +} + +// GetCSIPluginName returns the name of the CSI plugin +func (t *awsElasticBlockStoreCSITranslator) GetCSIPluginName() string { + return AWSEBSDriverName +} + +func (t *awsElasticBlockStoreCSITranslator) RepairVolumeHandle(volumeHandle, nodeID string) (string, error) { + return volumeHandle, nil +} + +// awsVolumeRegMatch represents Regex Match for AWS volume. +var awsVolumeRegMatch = regexp.MustCompile("^vol-[^/]*$") + +// KubernetesVolumeIDToEBSVolumeID translates Kubernetes volume ID to EBS volume ID +// KubernetesVolumeID forms: +// - aws:/// +// - aws:/// +// - +// +// EBS Volume ID form: +// - vol- +// +// This translation shouldn't be needed and should be fixed in long run +// See https://github.com/kubernetes/kubernetes/issues/73730 +func KubernetesVolumeIDToEBSVolumeID(kubernetesID string) (string, error) { + // name looks like aws://availability-zone/awsVolumeId + + // The original idea of the URL-style name was to put the AZ into the + // host, so we could find the AZ immediately from the name without + // querying the API. But it turns out we don't actually need it for + // multi-AZ clusters, as we put the AZ into the labels on the PV instead. + // However, if in future we want to support multi-AZ cluster + // volume-awareness without using PersistentVolumes, we likely will + // want the AZ in the host. + if !strings.HasPrefix(kubernetesID, "aws://") { + // Assume a bare aws volume id (vol-1234...) + return kubernetesID, nil + } + url, err := url.Parse(kubernetesID) + if err != nil { + // TODO: Maybe we should pass a URL into the Volume functions + return "", fmt.Errorf("Invalid disk name (%s): %v", kubernetesID, err) + } + if url.Scheme != "aws" { + return "", fmt.Errorf("Invalid scheme for AWS volume (%s)", kubernetesID) + } + + awsID := url.Path + awsID = strings.Trim(awsID, "/") + + // We sanity check the resulting volume; the two known formats are + // vol-12345678 and vol-12345678abcdef01 + if !awsVolumeRegMatch.MatchString(awsID) { + return "", fmt.Errorf("Invalid format for AWS volume (%s)", kubernetesID) + } + + return awsID, nil +} + +func getAwsRegionFromZones(zones []string) (string, error) { + regions := sets.String{} + if len(zones) < 1 { + return "", fmt.Errorf("no zones specified") + } + + // AWS zones can be in four forms: + // us-west-2a, us-gov-east-1a, us-west-2-lax-1a (local zone) and us-east-1-wl1-bos-wlz-1 (wavelength). + for _, zone := range zones { + splitZone := strings.Split(zone, "-") + if (len(splitZone) == 3 || len(splitZone) == 4) && len(splitZone[len(splitZone)-1]) == 2 { + // this would break if we ever have a location with more than 9 regions, ie us-west-10. + splitZone[len(splitZone)-1] = splitZone[len(splitZone)-1][:1] + regions.Insert(strings.Join(splitZone, "-")) + } else if len(splitZone) == 5 || len(splitZone) == 7 { + // local zone or wavelength + regions.Insert(strings.Join(splitZone[:3], "-")) + } else { + return "", fmt.Errorf("Unexpected zone format: %v is not a valid AWS zone", zone) + } + } + if regions.Len() != 1 { + return "", fmt.Errorf("multiple or no regions gotten from zones, got: %v", regions) + } + return regions.UnsortedList()[0], nil +} diff --git a/vendor/k8s.io/csi-translation-lib/plugins/azure_disk.go b/vendor/k8s.io/csi-translation-lib/plugins/azure_disk.go new file mode 100644 index 000000000..73f7736e5 --- /dev/null +++ b/vendor/k8s.io/csi-translation-lib/plugins/azure_disk.go @@ -0,0 +1,308 @@ +/* +Copyright 2019 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 plugins + +import ( + "fmt" + "regexp" + "strings" + + v1 "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + // AzureDiskDriverName is the name of the CSI driver for Azure Disk + AzureDiskDriverName = "disk.csi.azure.com" + // AzureDiskTopologyKey is the topology key of Azure Disk CSI driver + AzureDiskTopologyKey = "topology.disk.csi.azure.com/zone" + // AzureDiskInTreePluginName is the name of the intree plugin for Azure Disk + AzureDiskInTreePluginName = "kubernetes.io/azure-disk" + + // Parameter names defined in azure disk CSI driver, refer to + // https://github.com/kubernetes-sigs/azuredisk-csi-driver/blob/master/docs/driver-parameters.md + azureDiskKind = "kind" + azureDiskCachingMode = "cachingmode" + azureDiskFSType = "fstype" +) + +var ( + managedDiskPathRE = regexp.MustCompile(`.*/subscriptions/(?:.*)/resourceGroups/(?:.*)/providers/Microsoft.Compute/disks/(.+)`) + unmanagedDiskPathRE = regexp.MustCompile(`http(?:.*)://(?:.*)/vhds/(.+)`) + managed = string(v1.AzureManagedDisk) + unzonedCSIRegionRE = regexp.MustCompile(`^[0-9]+$`) +) + +var _ InTreePlugin = &azureDiskCSITranslator{} + +// azureDiskCSITranslator handles translation of PV spec from In-tree +// Azure Disk to CSI Azure Disk and vice versa +type azureDiskCSITranslator struct{} + +// NewAzureDiskCSITranslator returns a new instance of azureDiskTranslator +func NewAzureDiskCSITranslator() InTreePlugin { + return &azureDiskCSITranslator{} +} + +// TranslateInTreeStorageClassToCSI translates InTree Azure Disk storage class parameters to CSI storage class +func (t *azureDiskCSITranslator) TranslateInTreeStorageClassToCSI(sc *storage.StorageClass) (*storage.StorageClass, error) { + var ( + generatedTopologies []v1.TopologySelectorTerm + params = map[string]string{} + ) + for k, v := range sc.Parameters { + switch strings.ToLower(k) { + case zoneKey: + generatedTopologies = generateToplogySelectors(AzureDiskTopologyKey, []string{v}) + case zonesKey: + generatedTopologies = generateToplogySelectors(AzureDiskTopologyKey, strings.Split(v, ",")) + default: + params[k] = v + } + } + + if len(generatedTopologies) > 0 && len(sc.AllowedTopologies) > 0 { + return nil, fmt.Errorf("cannot simultaneously set allowed topologies and zone/zones parameters") + } else if len(generatedTopologies) > 0 { + sc.AllowedTopologies = generatedTopologies + } else if len(sc.AllowedTopologies) > 0 { + newTopologies, err := translateAllowedTopologies(sc.AllowedTopologies, AzureDiskTopologyKey) + if err != nil { + return nil, fmt.Errorf("failed translating allowed topologies: %v", err) + } + sc.AllowedTopologies = newTopologies + } + sc.AllowedTopologies = t.replaceFailureDomainsToCSI(sc.AllowedTopologies) + + sc.Parameters = params + + return sc, nil +} + +// TranslateInTreeInlineVolumeToCSI takes a Volume with AzureDisk set from in-tree +// and converts the AzureDisk source to a CSIPersistentVolumeSource +func (t *azureDiskCSITranslator) TranslateInTreeInlineVolumeToCSI(volume *v1.Volume, podNamespace string) (*v1.PersistentVolume, error) { + if volume == nil || volume.AzureDisk == nil { + return nil, fmt.Errorf("volume is nil or Azure Disk not defined on volume") + } + + azureSource := volume.AzureDisk + if azureSource.Kind != nil && !strings.EqualFold(string(*azureSource.Kind), managed) { + return nil, fmt.Errorf("kind(%v) is not supported in csi migration", *azureSource.Kind) + } + pv := &v1.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + // Must be unique per disk as it is used as the unique part of the + // staging path + Name: azureSource.DataDiskURI, + }, + Spec: v1.PersistentVolumeSpec{ + PersistentVolumeSource: v1.PersistentVolumeSource{ + CSI: &v1.CSIPersistentVolumeSource{ + Driver: AzureDiskDriverName, + VolumeHandle: azureSource.DataDiskURI, + VolumeAttributes: map[string]string{azureDiskKind: managed}, + }, + }, + AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, + }, + } + if azureSource.ReadOnly != nil { + pv.Spec.PersistentVolumeSource.CSI.ReadOnly = *azureSource.ReadOnly + } + + if azureSource.CachingMode != nil && *azureSource.CachingMode != "" { + pv.Spec.PersistentVolumeSource.CSI.VolumeAttributes[azureDiskCachingMode] = string(*azureSource.CachingMode) + } + if azureSource.FSType != nil { + pv.Spec.PersistentVolumeSource.CSI.FSType = *azureSource.FSType + pv.Spec.PersistentVolumeSource.CSI.VolumeAttributes[azureDiskFSType] = *azureSource.FSType + } + pv.Spec.PersistentVolumeSource.CSI.VolumeAttributes[azureDiskKind] = managed + + return pv, nil +} + +// TranslateInTreePVToCSI takes a PV with AzureDisk set from in-tree +// and converts the AzureDisk source to a CSIPersistentVolumeSource +func (t *azureDiskCSITranslator) TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + if pv == nil || pv.Spec.AzureDisk == nil { + return nil, fmt.Errorf("pv is nil or Azure Disk source not defined on pv") + } + + var ( + azureSource = pv.Spec.PersistentVolumeSource.AzureDisk + + // refer to https://github.com/kubernetes-sigs/azuredisk-csi-driver/blob/master/docs/driver-parameters.md + csiSource = &v1.CSIPersistentVolumeSource{ + Driver: AzureDiskDriverName, + VolumeAttributes: map[string]string{azureDiskKind: managed}, + VolumeHandle: azureSource.DataDiskURI, + } + ) + + if azureSource.Kind != nil && !strings.EqualFold(string(*azureSource.Kind), managed) { + return nil, fmt.Errorf("kind(%v) is not supported in csi migration", *azureSource.Kind) + } + + if azureSource.CachingMode != nil { + csiSource.VolumeAttributes[azureDiskCachingMode] = string(*azureSource.CachingMode) + } + + if azureSource.FSType != nil { + csiSource.FSType = *azureSource.FSType + csiSource.VolumeAttributes[azureDiskFSType] = *azureSource.FSType + } + csiSource.VolumeAttributes[azureDiskKind] = managed + + if azureSource.ReadOnly != nil { + csiSource.ReadOnly = *azureSource.ReadOnly + } + + pv.Spec.PersistentVolumeSource.AzureDisk = nil + pv.Spec.PersistentVolumeSource.CSI = csiSource + + return pv, nil +} + +// TranslateCSIPVToInTree takes a PV with CSIPersistentVolumeSource set and +// translates the Azure Disk CSI source to a AzureDisk source. +func (t *azureDiskCSITranslator) TranslateCSIPVToInTree(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + if pv == nil || pv.Spec.CSI == nil { + return nil, fmt.Errorf("pv is nil or CSI source not defined on pv") + } + csiSource := pv.Spec.CSI + + diskURI := csiSource.VolumeHandle + diskName, err := getDiskName(diskURI) + if err != nil { + return nil, err + } + + // refer to https://github.com/kubernetes-sigs/azuredisk-csi-driver/blob/master/docs/driver-parameters.md + managed := v1.AzureManagedDisk + azureSource := &v1.AzureDiskVolumeSource{ + DiskName: diskName, + DataDiskURI: diskURI, + FSType: &csiSource.FSType, + ReadOnly: &csiSource.ReadOnly, + Kind: &managed, + } + + if csiSource.VolumeAttributes != nil { + for k, v := range csiSource.VolumeAttributes { + switch strings.ToLower(k) { + case azureDiskCachingMode: + if v != "" { + mode := v1.AzureDataDiskCachingMode(v) + azureSource.CachingMode = &mode + } + case azureDiskFSType: + if v != "" { + fsType := v + azureSource.FSType = &fsType + } + } + } + azureSource.Kind = &managed + } + + pv.Spec.CSI = nil + pv.Spec.AzureDisk = azureSource + + return pv, nil +} + +// CanSupport tests whether the plugin supports a given volume +// specification from the API. The spec pointer should be considered +// const. +func (t *azureDiskCSITranslator) CanSupport(pv *v1.PersistentVolume) bool { + return pv != nil && pv.Spec.AzureDisk != nil +} + +// CanSupportInline tests whether the plugin supports a given inline volume +// specification from the API. The spec pointer should be considered +// const. +func (t *azureDiskCSITranslator) CanSupportInline(volume *v1.Volume) bool { + return volume != nil && volume.AzureDisk != nil +} + +// GetInTreePluginName returns the name of the intree plugin driver +func (t *azureDiskCSITranslator) GetInTreePluginName() string { + return AzureDiskInTreePluginName +} + +// GetCSIPluginName returns the name of the CSI plugin +func (t *azureDiskCSITranslator) GetCSIPluginName() string { + return AzureDiskDriverName +} + +func (t *azureDiskCSITranslator) RepairVolumeHandle(volumeHandle, nodeID string) (string, error) { + return volumeHandle, nil +} + +func isManagedDisk(diskURI string) bool { + if len(diskURI) > 4 && strings.ToLower(diskURI[:4]) == "http" { + return false + } + return true +} + +func getDiskName(diskURI string) (string, error) { + diskPathRE := managedDiskPathRE + if !isManagedDisk(diskURI) { + diskPathRE = unmanagedDiskPathRE + } + + matches := diskPathRE.FindStringSubmatch(diskURI) + if len(matches) != 2 { + return "", fmt.Errorf("could not get disk name from %s, correct format: %s", diskURI, diskPathRE) + } + return matches[1], nil +} + +// Replace topology values for failure domains ("") to "", +// as it's the value that the CSI driver expects. +func (t *azureDiskCSITranslator) replaceFailureDomainsToCSI(terms []v1.TopologySelectorTerm) []v1.TopologySelectorTerm { + if terms == nil { + return nil + } + + newTopologies := []v1.TopologySelectorTerm{} + for _, term := range terms { + newTerm := term.DeepCopy() + for i := range newTerm.MatchLabelExpressions { + exp := &newTerm.MatchLabelExpressions[i] + if exp.Key == AzureDiskTopologyKey { + for j := range exp.Values { + if unzonedCSIRegionRE.Match([]byte(exp.Values[j])) { + // Topologies "0", "1" etc are used when in-tree topology is translated to CSI in Azure + // regions that don't have availability zones. E.g.: + // topology.kubernetes.io/region: westus + // topology.kubernetes.io/zone: "0" + // The CSI driver uses zone "" instead of "0" in this case. + // topology.disk.csi.azure.com/zone": "" + exp.Values[j] = "" + } + } + } + } + newTopologies = append(newTopologies, *newTerm) + } + return newTopologies +} diff --git a/vendor/k8s.io/csi-translation-lib/plugins/azure_file.go b/vendor/k8s.io/csi-translation-lib/plugins/azure_file.go new file mode 100644 index 000000000..6a688d709 --- /dev/null +++ b/vendor/k8s.io/csi-translation-lib/plugins/azure_file.go @@ -0,0 +1,282 @@ +/* +Copyright 2019 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 plugins + +import ( + "fmt" + "regexp" + "strings" + + v1 "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/klog/v2" +) + +const ( + // AzureFileDriverName is the name of the CSI driver for Azure File + AzureFileDriverName = "file.csi.azure.com" + // AzureFileInTreePluginName is the name of the intree plugin for Azure file + AzureFileInTreePluginName = "kubernetes.io/azure-file" + + separator = "#" + volumeIDTemplate = "%s#%s#%s#%s#%s" + // Parameter names defined in azure file CSI driver, refer to + // https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/driver-parameters.md + shareNameField = "sharename" + secretNameField = "secretname" + secretNamespaceField = "secretnamespace" + secretNameTemplate = "azure-storage-account-%s-secret" + defaultSecretNamespace = "default" + resourceGroupAnnotation = "kubernetes.io/azure-file-resource-group" +) + +var _ InTreePlugin = &azureFileCSITranslator{} + +var secretNameFormatRE = regexp.MustCompile(`azure-storage-account-(.+)-secret`) + +// azureFileCSITranslator handles translation of PV spec from In-tree +// Azure File to CSI Azure File and vice versa +type azureFileCSITranslator struct{} + +// NewAzureFileCSITranslator returns a new instance of azureFileTranslator +func NewAzureFileCSITranslator() InTreePlugin { + return &azureFileCSITranslator{} +} + +// TranslateInTreeStorageClassToCSI translates InTree Azure File storage class parameters to CSI storage class +func (t *azureFileCSITranslator) TranslateInTreeStorageClassToCSI(sc *storage.StorageClass) (*storage.StorageClass, error) { + return sc, nil +} + +// TranslateInTreeInlineVolumeToCSI takes a Volume with AzureFile set from in-tree +// and converts the AzureFile source to a CSIPersistentVolumeSource +func (t *azureFileCSITranslator) TranslateInTreeInlineVolumeToCSI(volume *v1.Volume, podNamespace string) (*v1.PersistentVolume, error) { + if volume == nil || volume.AzureFile == nil { + return nil, fmt.Errorf("volume is nil or Azure File not defined on volume") + } + + azureSource := volume.AzureFile + accountName, err := getStorageAccountName(azureSource.SecretName) + if err != nil { + klog.Warningf("getStorageAccountName(%s) returned with error: %v", azureSource.SecretName, err) + accountName = azureSource.SecretName + } + + secretNamespace := defaultSecretNamespace + if podNamespace != "" { + secretNamespace = podNamespace + } + volumeID := fmt.Sprintf(volumeIDTemplate, "", accountName, azureSource.ShareName, volume.Name, secretNamespace) + + var ( + pv = &v1.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + // Must be unique as it is used as the unique part of the staging path + Name: volumeID, + }, + Spec: v1.PersistentVolumeSpec{ + PersistentVolumeSource: v1.PersistentVolumeSource{ + CSI: &v1.CSIPersistentVolumeSource{ + Driver: AzureFileDriverName, + VolumeHandle: volumeID, + ReadOnly: azureSource.ReadOnly, + VolumeAttributes: map[string]string{shareNameField: azureSource.ShareName}, + NodeStageSecretRef: &v1.SecretReference{ + Name: azureSource.SecretName, + Namespace: secretNamespace, + }, + }, + }, + AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteMany}, + }, + } + ) + + return pv, nil +} + +// TranslateInTreePVToCSI takes a PV with AzureFile set from in-tree +// and converts the AzureFile source to a CSIPersistentVolumeSource +func (t *azureFileCSITranslator) TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + if pv == nil || pv.Spec.AzureFile == nil { + return nil, fmt.Errorf("pv is nil or Azure File source not defined on pv") + } + + azureSource := pv.Spec.PersistentVolumeSource.AzureFile + accountName, err := getStorageAccountName(azureSource.SecretName) + if err != nil { + klog.Warningf("getStorageAccountName(%s) returned with error: %v", azureSource.SecretName, err) + accountName = azureSource.SecretName + } + resourceGroup := "" + if pv.ObjectMeta.Annotations != nil { + if v, ok := pv.ObjectMeta.Annotations[resourceGroupAnnotation]; ok { + resourceGroup = v + } + } + + // Secret is required when mounting a volume but pod presence cannot be assumed - we should not try to read pod now. + namespace := "" + // Try to read SecretNamespace from source pv. + if azureSource.SecretNamespace != nil { + namespace = *azureSource.SecretNamespace + } else { + // Try to read namespace from ClaimRef which should be always present. + if pv.Spec.ClaimRef != nil { + namespace = pv.Spec.ClaimRef.Namespace + } + } + + if len(namespace) == 0 { + return nil, fmt.Errorf("could not find a secret namespace in PersistentVolumeSource or ClaimRef") + } + + volumeID := fmt.Sprintf(volumeIDTemplate, resourceGroup, accountName, azureSource.ShareName, pv.ObjectMeta.Name, namespace) + + var ( + // refer to https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/driver-parameters.md + csiSource = &v1.CSIPersistentVolumeSource{ + Driver: AzureFileDriverName, + NodeStageSecretRef: &v1.SecretReference{ + Name: azureSource.SecretName, + Namespace: namespace, + }, + ReadOnly: azureSource.ReadOnly, + VolumeAttributes: map[string]string{shareNameField: azureSource.ShareName}, + VolumeHandle: volumeID, + } + ) + + pv.Spec.PersistentVolumeSource.AzureFile = nil + pv.Spec.PersistentVolumeSource.CSI = csiSource + + return pv, nil +} + +// TranslateCSIPVToInTree takes a PV with CSIPersistentVolumeSource set and +// translates the Azure File CSI source to a AzureFile source. +func (t *azureFileCSITranslator) TranslateCSIPVToInTree(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + if pv == nil || pv.Spec.CSI == nil { + return nil, fmt.Errorf("pv is nil or CSI source not defined on pv") + } + csiSource := pv.Spec.CSI + + // refer to https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/driver-parameters.md + azureSource := &v1.AzureFilePersistentVolumeSource{ + ReadOnly: csiSource.ReadOnly, + } + + for k, v := range csiSource.VolumeAttributes { + switch strings.ToLower(k) { + case shareNameField: + azureSource.ShareName = v + case secretNameField: + azureSource.SecretName = v + case secretNamespaceField: + ns := v + azureSource.SecretNamespace = &ns + } + } + + resourceGroup := "" + if csiSource.NodeStageSecretRef != nil && csiSource.NodeStageSecretRef.Name != "" { + azureSource.SecretName = csiSource.NodeStageSecretRef.Name + azureSource.SecretNamespace = &csiSource.NodeStageSecretRef.Namespace + } + if azureSource.ShareName == "" || azureSource.SecretName == "" { + rg, storageAccount, fileShareName, _, err := getFileShareInfo(csiSource.VolumeHandle) + if err != nil { + return nil, err + } + if azureSource.ShareName == "" { + azureSource.ShareName = fileShareName + } + if azureSource.SecretName == "" { + azureSource.SecretName = fmt.Sprintf(secretNameTemplate, storageAccount) + } + resourceGroup = rg + } + + if azureSource.SecretNamespace == nil { + ns := defaultSecretNamespace + azureSource.SecretNamespace = &ns + } + + pv.Spec.CSI = nil + pv.Spec.AzureFile = azureSource + if pv.ObjectMeta.Annotations == nil { + pv.ObjectMeta.Annotations = map[string]string{} + } + if resourceGroup != "" { + pv.ObjectMeta.Annotations[resourceGroupAnnotation] = resourceGroup + } + + return pv, nil +} + +// CanSupport tests whether the plugin supports a given volume +// specification from the API. The spec pointer should be considered +// const. +func (t *azureFileCSITranslator) CanSupport(pv *v1.PersistentVolume) bool { + return pv != nil && pv.Spec.AzureFile != nil +} + +// CanSupportInline tests whether the plugin supports a given inline volume +// specification from the API. The spec pointer should be considered +// const. +func (t *azureFileCSITranslator) CanSupportInline(volume *v1.Volume) bool { + return volume != nil && volume.AzureFile != nil +} + +// GetInTreePluginName returns the name of the intree plugin driver +func (t *azureFileCSITranslator) GetInTreePluginName() string { + return AzureFileInTreePluginName +} + +// GetCSIPluginName returns the name of the CSI plugin +func (t *azureFileCSITranslator) GetCSIPluginName() string { + return AzureFileDriverName +} + +func (t *azureFileCSITranslator) RepairVolumeHandle(volumeHandle, nodeID string) (string, error) { + return volumeHandle, nil +} + +// get file share info according to volume id, e.g. +// input: "rg#f5713de20cde511e8ba4900#pvc-file-dynamic-17e43f84-f474-11e8-acd0-000d3a00df41#diskname.vhd" +// output: rg, f5713de20cde511e8ba4900, pvc-file-dynamic-17e43f84-f474-11e8-acd0-000d3a00df41, diskname.vhd +func getFileShareInfo(id string) (string, string, string, string, error) { + segments := strings.Split(id, separator) + if len(segments) < 3 { + return "", "", "", "", fmt.Errorf("error parsing volume id: %q, should at least contain two #", id) + } + var diskName string + if len(segments) > 3 { + diskName = segments[3] + } + return segments[0], segments[1], segments[2], diskName, nil +} + +// get storage account name from secret name +func getStorageAccountName(secretName string) (string, error) { + matches := secretNameFormatRE.FindStringSubmatch(secretName) + if len(matches) != 2 { + return "", fmt.Errorf("could not get account name from %s, correct format: %s", secretName, secretNameFormatRE) + } + return matches[1], nil +} diff --git a/vendor/k8s.io/csi-translation-lib/plugins/const.go b/vendor/k8s.io/csi-translation-lib/plugins/const.go new file mode 100644 index 000000000..fe3a5289b --- /dev/null +++ b/vendor/k8s.io/csi-translation-lib/plugins/const.go @@ -0,0 +1,21 @@ +/* +Copyright 2020 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 plugins + +// Matches the delimiter LabelMultiZoneDelimiter used by k8s.io/cloud-provider/volume and is mirrored here to avoid a large dependency +// labelMultiZoneDelimiter separates zones for volumes +const labelMultiZoneDelimiter = "__" diff --git a/vendor/k8s.io/csi-translation-lib/plugins/gce_pd.go b/vendor/k8s.io/csi-translation-lib/plugins/gce_pd.go new file mode 100644 index 000000000..52efea05e --- /dev/null +++ b/vendor/k8s.io/csi-translation-lib/plugins/gce_pd.go @@ -0,0 +1,399 @@ +/* +Copyright 2019 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 plugins + +import ( + "fmt" + "strconv" + "strings" + + v1 "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/sets" +) + +const ( + // GCEPDDriverName is the name of the CSI driver for GCE PD + GCEPDDriverName = "pd.csi.storage.gke.io" + // GCEPDInTreePluginName is the name of the intree plugin for GCE PD + GCEPDInTreePluginName = "kubernetes.io/gce-pd" + + // GCEPDTopologyKey is the zonal topology key for GCE PD CSI Driver + GCEPDTopologyKey = "topology.gke.io/zone" + + // Volume ID Expected Format + // "projects/{projectName}/zones/{zoneName}/disks/{diskName}" + volIDZonalFmt = "projects/%s/zones/%s/disks/%s" + // "projects/{projectName}/regions/{regionName}/disks/{diskName}" + volIDRegionalFmt = "projects/%s/regions/%s/disks/%s" + volIDProjectValue = 1 + volIDRegionalityValue = 2 + volIDZoneValue = 3 + volIDDiskNameValue = 5 + volIDTotalElements = 6 + + nodeIDFmt = "projects/%s/zones/%s/instances/%s" + + // UnspecifiedValue is used for an unknown zone string + UnspecifiedValue = "UNSPECIFIED" +) + +var _ InTreePlugin = &gcePersistentDiskCSITranslator{} + +// gcePersistentDiskCSITranslator handles translation of PV spec from In-tree +// GCE PD to CSI GCE PD and vice versa +type gcePersistentDiskCSITranslator struct{} + +// NewGCEPersistentDiskCSITranslator returns a new instance of gcePersistentDiskTranslator +func NewGCEPersistentDiskCSITranslator() InTreePlugin { + return &gcePersistentDiskCSITranslator{} +} + +func generateToplogySelectors(key string, values []string) []v1.TopologySelectorTerm { + return []v1.TopologySelectorTerm{ + { + MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{ + { + Key: key, + Values: values, + }, + }, + }, + } +} + +// TranslateInTreeStorageClassToCSI translates InTree GCE storage class parameters to CSI storage class +func (g *gcePersistentDiskCSITranslator) TranslateInTreeStorageClassToCSI(sc *storage.StorageClass) (*storage.StorageClass, error) { + var generatedTopologies []v1.TopologySelectorTerm + + np := map[string]string{} + for k, v := range sc.Parameters { + switch strings.ToLower(k) { + case fsTypeKey: + // prefixed fstype parameter is stripped out by external provisioner + np[csiFsTypeKey] = v + // Strip out zone and zones parameters and translate them into topologies instead + case zoneKey: + generatedTopologies = generateToplogySelectors(GCEPDTopologyKey, []string{v}) + case zonesKey: + generatedTopologies = generateToplogySelectors(GCEPDTopologyKey, strings.Split(v, ",")) + default: + np[k] = v + } + } + + if len(generatedTopologies) > 0 && len(sc.AllowedTopologies) > 0 { + return nil, fmt.Errorf("cannot simultaneously set allowed topologies and zone/zones parameters") + } else if len(generatedTopologies) > 0 { + sc.AllowedTopologies = generatedTopologies + } else if len(sc.AllowedTopologies) > 0 { + newTopologies, err := translateAllowedTopologies(sc.AllowedTopologies, GCEPDTopologyKey) + if err != nil { + return nil, fmt.Errorf("failed translating allowed topologies: %v", err) + } + sc.AllowedTopologies = newTopologies + } + + sc.Parameters = np + + return sc, nil +} + +// backwardCompatibleAccessModes translates all instances of ReadWriteMany +// access mode from the in-tree plugin to ReadWriteOnce. This is because in-tree +// plugin never supported ReadWriteMany but also did not validate or enforce +// this access mode for pre-provisioned volumes. The GCE PD CSI Driver validates +// and enforces (fails) ReadWriteMany. Therefore we treat all in-tree +// ReadWriteMany as ReadWriteOnce volumes to not break legacy volumes. It also +// takes [ReadWriteOnce, ReadOnlyMany] and makes it ReadWriteOnce. This is +// because the in-tree plugin does not enforce access modes and just attaches +// the disk in ReadWriteOnce mode; however, the CSI external-attacher will fail +// this combination because technically [ReadWriteOnce, ReadOnlyMany] is not +// supportable on an attached volume +// See: https://github.com/kubernetes-csi/external-attacher/issues/153 +func backwardCompatibleAccessModes(ams []v1.PersistentVolumeAccessMode) []v1.PersistentVolumeAccessMode { + if ams == nil { + return nil + } + + s := map[v1.PersistentVolumeAccessMode]bool{} + var newAM []v1.PersistentVolumeAccessMode + + for _, am := range ams { + if am == v1.ReadWriteMany { + // ReadWriteMany is unsupported in CSI, but in-tree did no + // validation and treated it as ReadWriteOnce + s[v1.ReadWriteOnce] = true + } else { + s[am] = true + } + } + + switch { + case s[v1.ReadOnlyMany] && s[v1.ReadWriteOnce]: + // ROX,RWO is unsupported in CSI, but in-tree did not validation and + // treated it as ReadWriteOnce + newAM = []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce} + case s[v1.ReadWriteOnce]: + newAM = []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce} + case s[v1.ReadOnlyMany]: + newAM = []v1.PersistentVolumeAccessMode{v1.ReadOnlyMany} + default: + newAM = []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce} + } + + return newAM +} + +// TranslateInTreeInlineVolumeToCSI takes a Volume with GCEPersistentDisk set from in-tree +// and converts the GCEPersistentDisk source to a CSIPersistentVolumeSource +func (g *gcePersistentDiskCSITranslator) TranslateInTreeInlineVolumeToCSI(volume *v1.Volume, podNamespace string) (*v1.PersistentVolume, error) { + if volume == nil || volume.GCEPersistentDisk == nil { + return nil, fmt.Errorf("volume is nil or GCE PD not defined on volume") + } + + pdSource := volume.GCEPersistentDisk + + partition := "" + if pdSource.Partition != 0 { + partition = strconv.Itoa(int(pdSource.Partition)) + } + + var am v1.PersistentVolumeAccessMode + if pdSource.ReadOnly { + am = v1.ReadOnlyMany + } else { + am = v1.ReadWriteOnce + } + + fsMode := v1.PersistentVolumeFilesystem + return &v1.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + // Must be unique per disk as it is used as the unique part of the + // staging path + Name: fmt.Sprintf("%s-%s", GCEPDDriverName, pdSource.PDName), + }, + Spec: v1.PersistentVolumeSpec{ + PersistentVolumeSource: v1.PersistentVolumeSource{ + CSI: &v1.CSIPersistentVolumeSource{ + Driver: GCEPDDriverName, + VolumeHandle: fmt.Sprintf(volIDZonalFmt, UnspecifiedValue, UnspecifiedValue, pdSource.PDName), + ReadOnly: pdSource.ReadOnly, + FSType: pdSource.FSType, + VolumeAttributes: map[string]string{ + "partition": partition, + }, + }, + }, + AccessModes: []v1.PersistentVolumeAccessMode{am}, + VolumeMode: &fsMode, + }, + }, nil +} + +// TranslateInTreePVToCSI takes a PV with GCEPersistentDisk set from in-tree +// and converts the GCEPersistentDisk source to a CSIPersistentVolumeSource +func (g *gcePersistentDiskCSITranslator) TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + var volID string + + if pv == nil || pv.Spec.GCEPersistentDisk == nil { + return nil, fmt.Errorf("pv is nil or GCE Persistent Disk source not defined on pv") + } + + // depend on which version it migrates from, the label could be failuredomain beta or topology GA version + zonesLabel := pv.Labels[v1.LabelFailureDomainBetaZone] + if zonesLabel == "" { + zonesLabel = pv.Labels[v1.LabelTopologyZone] + } + + zones := strings.Split(zonesLabel, labelMultiZoneDelimiter) + if len(zones) == 1 && len(zones[0]) != 0 { + // Zonal + volID = fmt.Sprintf(volIDZonalFmt, UnspecifiedValue, zones[0], pv.Spec.GCEPersistentDisk.PDName) + } else if len(zones) > 1 { + // Regional + region, err := gceGetRegionFromZones(zones) + if err != nil { + return nil, fmt.Errorf("failed to get region from zones: %v", err) + } + volID = fmt.Sprintf(volIDRegionalFmt, UnspecifiedValue, region, pv.Spec.GCEPersistentDisk.PDName) + } else { + // Unspecified + volID = fmt.Sprintf(volIDZonalFmt, UnspecifiedValue, UnspecifiedValue, pv.Spec.GCEPersistentDisk.PDName) + } + + gceSource := pv.Spec.PersistentVolumeSource.GCEPersistentDisk + + partition := "" + if gceSource.Partition != 0 { + partition = strconv.Itoa(int(gceSource.Partition)) + } + + csiSource := &v1.CSIPersistentVolumeSource{ + Driver: GCEPDDriverName, + VolumeHandle: volID, + ReadOnly: gceSource.ReadOnly, + FSType: gceSource.FSType, + VolumeAttributes: map[string]string{ + "partition": partition, + }, + } + + if err := translateTopologyFromInTreeToCSI(pv, GCEPDTopologyKey); err != nil { + return nil, fmt.Errorf("failed to translate topology: %v", err) + } + + pv.Spec.PersistentVolumeSource.GCEPersistentDisk = nil + pv.Spec.PersistentVolumeSource.CSI = csiSource + pv.Spec.AccessModes = backwardCompatibleAccessModes(pv.Spec.AccessModes) + + return pv, nil +} + +// TranslateCSIPVToInTree takes a PV with CSIPersistentVolumeSource set and +// translates the GCE PD CSI source to a GCEPersistentDisk source. +func (g *gcePersistentDiskCSITranslator) TranslateCSIPVToInTree(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + if pv == nil || pv.Spec.CSI == nil { + return nil, fmt.Errorf("pv is nil or CSI source not defined on pv") + } + csiSource := pv.Spec.CSI + + pdName, err := pdNameFromVolumeID(csiSource.VolumeHandle) + if err != nil { + return nil, err + } + + gceSource := &v1.GCEPersistentDiskVolumeSource{ + PDName: pdName, + FSType: csiSource.FSType, + ReadOnly: csiSource.ReadOnly, + } + if partition, ok := csiSource.VolumeAttributes["partition"]; ok && partition != "" { + partInt, err := strconv.Atoi(partition) + if err != nil { + return nil, fmt.Errorf("Failed to convert partition %v to integer: %v", partition, err) + } + gceSource.Partition = int32(partInt) + } + + // translate CSI topology to In-tree topology for rollback compatibility + if err := translateTopologyFromCSIToInTree(pv, GCEPDTopologyKey, gceGetRegionFromZones); err != nil { + return nil, fmt.Errorf("failed to translate topology. PV:%+v. Error:%v", *pv, err) + } + + pv.Spec.CSI = nil + pv.Spec.GCEPersistentDisk = gceSource + + return pv, nil +} + +// CanSupport tests whether the plugin supports a given persistent volume +// specification from the API. The spec pointer should be considered +// const. +func (g *gcePersistentDiskCSITranslator) CanSupport(pv *v1.PersistentVolume) bool { + return pv != nil && pv.Spec.GCEPersistentDisk != nil +} + +// CanSupportInline tests whether the plugin supports a given inline volume +// specification from the API. The spec pointer should be considered +// const. +func (g *gcePersistentDiskCSITranslator) CanSupportInline(volume *v1.Volume) bool { + return volume != nil && volume.GCEPersistentDisk != nil +} + +// GetInTreePluginName returns the name of the intree plugin driver +func (g *gcePersistentDiskCSITranslator) GetInTreePluginName() string { + return GCEPDInTreePluginName +} + +// GetCSIPluginName returns the name of the CSI plugin +func (g *gcePersistentDiskCSITranslator) GetCSIPluginName() string { + return GCEPDDriverName +} + +// RepairVolumeHandle returns a fully specified volume handle by inferring +// project, zone/region from the node ID if the volume handle has UNSPECIFIED +// sections +func (g *gcePersistentDiskCSITranslator) RepairVolumeHandle(volumeHandle, nodeID string) (string, error) { + var err error + tok := strings.Split(volumeHandle, "/") + if len(tok) < volIDTotalElements { + return "", fmt.Errorf("volume handle has wrong number of elements; got %v, wanted %v or more", len(tok), volIDTotalElements) + } + if tok[volIDProjectValue] != UnspecifiedValue { + return volumeHandle, nil + } + + nodeTok := strings.Split(nodeID, "/") + if len(nodeTok) < volIDTotalElements { + return "", fmt.Errorf("node handle has wrong number of elements; got %v, wanted %v or more", len(nodeTok), volIDTotalElements) + } + + switch tok[volIDRegionalityValue] { + case "zones": + zone := "" + if tok[volIDZoneValue] == UnspecifiedValue { + zone = nodeTok[volIDZoneValue] + } else { + zone = tok[volIDZoneValue] + } + return fmt.Sprintf(volIDZonalFmt, nodeTok[volIDProjectValue], zone, tok[volIDDiskNameValue]), nil + case "regions": + region := "" + if tok[volIDZoneValue] == UnspecifiedValue { + region, err = gceGetRegionFromZones([]string{nodeTok[volIDZoneValue]}) + if err != nil { + return "", fmt.Errorf("failed to get region from zone %s: %v", nodeTok[volIDZoneValue], err) + } + } else { + region = tok[volIDZoneValue] + } + return fmt.Sprintf(volIDRegionalFmt, nodeTok[volIDProjectValue], region, tok[volIDDiskNameValue]), nil + default: + return "", fmt.Errorf("expected volume handle to have zones or regions regionality value, got: %s", tok[volIDRegionalityValue]) + } +} + +func pdNameFromVolumeID(id string) (string, error) { + splitID := strings.Split(id, "/") + if len(splitID) < volIDTotalElements { + return "", fmt.Errorf("failed to get id components.Got: %v, wanted %v components or more. ", len(splitID), volIDTotalElements) + } + return splitID[volIDDiskNameValue], nil +} + +// TODO: Replace this with the imported one from GCE PD CSI Driver when +// the driver removes all k8s/k8s dependencies +func gceGetRegionFromZones(zones []string) (string, error) { + regions := sets.String{} + if len(zones) < 1 { + return "", fmt.Errorf("no zones specified") + } + for _, zone := range zones { + // Zone expected format {locale}-{region}-{zone} + splitZone := strings.Split(zone, "-") + if len(splitZone) != 3 { + return "", fmt.Errorf("zone in unexpected format, expected: {locale}-{region}-{zone}, got: %v", zone) + } + regions.Insert(strings.Join(splitZone[0:2], "-")) + } + if regions.Len() != 1 { + return "", fmt.Errorf("multiple or no regions gotten from zones, got: %v", regions) + } + return regions.UnsortedList()[0], nil +} diff --git a/vendor/k8s.io/csi-translation-lib/plugins/in_tree_volume.go b/vendor/k8s.io/csi-translation-lib/plugins/in_tree_volume.go new file mode 100644 index 000000000..2ce4c271d --- /dev/null +++ b/vendor/k8s.io/csi-translation-lib/plugins/in_tree_volume.go @@ -0,0 +1,397 @@ +/* +Copyright 2019 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 plugins + +import ( + "errors" + "fmt" + "sort" + "strings" + + v1 "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1" + "k8s.io/apimachinery/pkg/util/sets" +) + +// InTreePlugin handles translations between CSI and in-tree sources in a PV +type InTreePlugin interface { + + // TranslateInTreeStorageClassToCSI takes in-tree volume options + // and translates them to a volume options consumable by CSI plugin + TranslateInTreeStorageClassToCSI(sc *storage.StorageClass) (*storage.StorageClass, error) + + // TranslateInTreeInlineVolumeToCSI takes a inline volume and will translate + // the in-tree inline volume source to a CSIPersistentVolumeSource + // A PV object containing the CSIPersistentVolumeSource in it's spec is returned + // podNamespace is only needed for azurefile to fetch secret namespace, no need to be set for other plugins. + TranslateInTreeInlineVolumeToCSI(volume *v1.Volume, podNamespace string) (*v1.PersistentVolume, error) + + // TranslateInTreePVToCSI takes a persistent volume and will translate + // the in-tree pv source to a CSI Source. The input persistent volume can be modified + TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) + + // TranslateCSIPVToInTree takes a PV with a CSI PersistentVolume Source and will translate + // it to a in-tree Persistent Volume Source for the in-tree volume + // by the `Driver` field in the CSI Source. The input PV object can be modified + TranslateCSIPVToInTree(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) + + // CanSupport tests whether the plugin supports a given persistent volume + // specification from the API. + CanSupport(pv *v1.PersistentVolume) bool + + // CanSupportInline tests whether the plugin supports a given inline volume + // specification from the API. + CanSupportInline(vol *v1.Volume) bool + + // GetInTreePluginName returns the in-tree plugin name this migrates + GetInTreePluginName() string + + // GetCSIPluginName returns the name of the CSI plugin that supersedes the in-tree plugin + GetCSIPluginName() string + + // RepairVolumeHandle generates a correct volume handle based on node ID information. + RepairVolumeHandle(volumeHandle, nodeID string) (string, error) +} + +const ( + // fsTypeKey is the deprecated storage class parameter key for fstype + fsTypeKey = "fstype" + // csiFsTypeKey is the storage class parameter key for CSI fstype + csiFsTypeKey = "csi.storage.k8s.io/fstype" + // zoneKey is the deprecated storage class parameter key for zone + zoneKey = "zone" + // zonesKey is the deprecated storage class parameter key for zones + zonesKey = "zones" +) + +// replaceTopology overwrites an existing key in NodeAffinity by a new one. +// If there are any newKey already exist in an expression of a term, we will +// not combine the replaced key Values with the existing ones. +// So there might be duplication if there is any newKey expression +// already in the terms. +func replaceTopology(pv *v1.PersistentVolume, oldKey, newKey string) error { + // Make sure the necessary fields exist + if pv == nil || pv.Spec.NodeAffinity == nil || pv.Spec.NodeAffinity.Required == nil || + pv.Spec.NodeAffinity.Required.NodeSelectorTerms == nil || len(pv.Spec.NodeAffinity.Required.NodeSelectorTerms) == 0 { + return nil + } + for i := range pv.Spec.NodeAffinity.Required.NodeSelectorTerms { + for j, r := range pv.Spec.NodeAffinity.Required.NodeSelectorTerms[i].MatchExpressions { + if r.Key == oldKey { + pv.Spec.NodeAffinity.Required.NodeSelectorTerms[i].MatchExpressions[j].Key = newKey + } + } + } + + return nil +} + +// getTopologyValues returns all unique topology values with the given key found in +// the PV NodeAffinity. Sort by alphabetical order. +// This function collapses multiple zones into a list that is ORed. This assumes that +// the plugin does not support a constraint like key in "zone1" AND "zone2" +func getTopologyValues(pv *v1.PersistentVolume, key string) []string { + if pv.Spec.NodeAffinity == nil || + pv.Spec.NodeAffinity.Required == nil || + len(pv.Spec.NodeAffinity.Required.NodeSelectorTerms) < 1 { + return nil + } + + values := make(map[string]bool) + for i := range pv.Spec.NodeAffinity.Required.NodeSelectorTerms { + for _, r := range pv.Spec.NodeAffinity.Required.NodeSelectorTerms[i].MatchExpressions { + if r.Key == key { + for _, v := range r.Values { + values[v] = true + } + } + } + } + // remove duplication and sort them in order for better usage + var re []string + for k := range values { + re = append(re, k) + } + sort.Strings(re) + return re +} + +// addTopology appends the topology to the given PV to all Terms. +func addTopology(pv *v1.PersistentVolume, topologyKey string, zones []string) error { + // Make sure there are no duplicate or empty strings + filteredZones := sets.String{} + for i := range zones { + zone := strings.TrimSpace(zones[i]) + if len(zone) > 0 { + filteredZones.Insert(zone) + } + } + + zones = filteredZones.List() + if len(zones) < 1 { + return errors.New("there are no valid zones to add to pv") + } + + // Make sure the necessary fields exist + if pv.Spec.NodeAffinity == nil { + pv.Spec.NodeAffinity = new(v1.VolumeNodeAffinity) + } + + if pv.Spec.NodeAffinity.Required == nil { + pv.Spec.NodeAffinity.Required = new(v1.NodeSelector) + } + + if len(pv.Spec.NodeAffinity.Required.NodeSelectorTerms) == 0 { + pv.Spec.NodeAffinity.Required.NodeSelectorTerms = make([]v1.NodeSelectorTerm, 1) + } + + topology := v1.NodeSelectorRequirement{ + Key: topologyKey, + Operator: v1.NodeSelectorOpIn, + Values: zones, + } + + // add the CSI topology to each term + for i := range pv.Spec.NodeAffinity.Required.NodeSelectorTerms { + pv.Spec.NodeAffinity.Required.NodeSelectorTerms[i].MatchExpressions = append( + pv.Spec.NodeAffinity.Required.NodeSelectorTerms[i].MatchExpressions, + topology, + ) + } + + return nil +} + +// translateTopologyFromInTreeToCSI converts existing zone labels or in-tree topology to CSI topology. +// In-tree topology has precedence over zone labels. When both in-tree topology and zone labels exist +// for a particular CSI topology, in-tree topology will be used. +// This function will remove the Beta version Kubernetes topology label in case the node upgrade to a +// newer version where it does not have any Beta topology label anymore +func translateTopologyFromInTreeToCSI(pv *v1.PersistentVolume, csiTopologyKey string) error { + + zoneLabel, regionLabel := getTopologyLabel(pv) + + // If Zone kubernetes topology exist, replace it to use csiTopologyKey + zones := getTopologyValues(pv, zoneLabel) + if len(zones) > 0 { + replaceTopology(pv, zoneLabel, csiTopologyKey) + } else { + // if nothing is in the NodeAffinity, try to fetch the topology from PV labels + if label, ok := pv.Labels[zoneLabel]; ok { + zones = strings.Split(label, labelMultiZoneDelimiter) + if len(zones) > 0 { + addTopology(pv, csiTopologyKey, zones) + } + } + } + + // if the in-tree PV has beta region label, replace it with GA label to ensure + // the scheduler is able to schedule it on new nodes with only GA kubernetes label + // No need to check it for zone label because it has already been replaced if exist + if regionLabel == v1.LabelFailureDomainBetaRegion { + regions := getTopologyValues(pv, regionLabel) + if len(regions) > 0 { + replaceTopology(pv, regionLabel, v1.LabelTopologyRegion) + } + } + + return nil +} + +// getTopologyLabel checks if the kubernetes topology label used in this +// PV is GA and return the zone/region label used. +// The version checking follows the following orders +// 1. Check NodeAffinity +// 1.1 Check if zoneGA exists, if yes return GA labels +// 1.2 Check if zoneBeta exists, if yes return Beta labels +// 2. Check PV labels +// 2.1 Check if zoneGA exists, if yes return GA labels +// 2.2 Check if zoneBeta exists, if yes return Beta labels +func getTopologyLabel(pv *v1.PersistentVolume) (zoneLabel string, regionLabel string) { + + if zoneGA := TopologyKeyExist(v1.LabelTopologyZone, pv.Spec.NodeAffinity); zoneGA { + return v1.LabelTopologyZone, v1.LabelTopologyRegion + } + if zoneBeta := TopologyKeyExist(v1.LabelFailureDomainBetaZone, pv.Spec.NodeAffinity); zoneBeta { + return v1.LabelFailureDomainBetaZone, v1.LabelFailureDomainBetaRegion + } + if _, zoneGA := pv.Labels[v1.LabelTopologyZone]; zoneGA { + return v1.LabelTopologyZone, v1.LabelTopologyRegion + } + if _, zoneBeta := pv.Labels[v1.LabelFailureDomainBetaZone]; zoneBeta { + return v1.LabelFailureDomainBetaZone, v1.LabelFailureDomainBetaRegion + } + // No labels or NodeAffinity exist, default to GA version + return v1.LabelTopologyZone, v1.LabelTopologyRegion +} + +// TopologyKeyExist checks if a certain key exists in a VolumeNodeAffinity +func TopologyKeyExist(key string, vna *v1.VolumeNodeAffinity) bool { + if vna == nil || vna.Required == nil || vna.Required.NodeSelectorTerms == nil || len(vna.Required.NodeSelectorTerms) == 0 { + return false + } + + for _, nodeSelectorTerms := range vna.Required.NodeSelectorTerms { + nsrequirements := nodeSelectorTerms.MatchExpressions + for _, nodeSelectorRequirement := range nsrequirements { + if nodeSelectorRequirement.Key == key { + return true + } + } + } + return false +} + +type regionParserFn func([]string) (string, error) + +// translateTopologyFromCSIToInTree translate a CSI topology to +// Kubernetes topology and add topology labels to it. Note that this function +// will only work for plugin with a single topologyKey that translates to +// Kubernetes zone(and region if regionParser is passed in). +// If a plugin has more than one topologyKey, it will need to be processed +// separately by the plugin. +// If regionParser is nil, no region NodeAffinity will be added. If not nil, +// it'll be passed to regionTopologyHandler, which will add region topology NodeAffinity +// and labels for the given PV. It assumes the Zone NodeAffinity already exists. +// In short this function will, +// 1. Replace all CSI topology to Kubernetes Zone topology label +// 2. Process and generate region topology if a regionParser is passed +// 3. Add Kubernetes Topology labels(zone) if they do not exist +func translateTopologyFromCSIToInTree(pv *v1.PersistentVolume, csiTopologyKey string, regionParser regionParserFn) error { + + zoneLabel, _ := getTopologyLabel(pv) + + // 1. Replace all CSI topology to Kubernetes Zone label + err := replaceTopology(pv, csiTopologyKey, zoneLabel) + if err != nil { + return fmt.Errorf("Failed to replace CSI topology to Kubernetes topology, error: %v", err) + } + + // 2. Take care of region topology if a regionParser is passed + if regionParser != nil { + // let's make less strict on this one. Even if there is an error in the region processing, just ignore it + err = regionTopologyHandler(pv, regionParser) + if err != nil { + return fmt.Errorf("Failed to handle region topology. error: %v", err) + } + } + + // 3. Add labels about Kubernetes Topology + zoneVals := getTopologyValues(pv, zoneLabel) + if len(zoneVals) > 0 { + if pv.Labels == nil { + pv.Labels = make(map[string]string) + } + _, zoneOK := pv.Labels[zoneLabel] + if !zoneOK { + zoneValStr := strings.Join(zoneVals, labelMultiZoneDelimiter) + pv.Labels[zoneLabel] = zoneValStr + } + } + + return nil +} + +// translateAllowedTopologies translates allowed topologies within storage class or PV +// from legacy failure domain to given CSI topology key +func translateAllowedTopologies(terms []v1.TopologySelectorTerm, key string) ([]v1.TopologySelectorTerm, error) { + if terms == nil { + return nil, nil + } + + newTopologies := []v1.TopologySelectorTerm{} + for _, term := range terms { + newTerm := v1.TopologySelectorTerm{} + for _, exp := range term.MatchLabelExpressions { + var newExp v1.TopologySelectorLabelRequirement + if exp.Key == v1.LabelFailureDomainBetaZone || exp.Key == v1.LabelTopologyZone { + newExp = v1.TopologySelectorLabelRequirement{ + Key: key, + Values: exp.Values, + } + } else { + // Other topologies are passed through unchanged. + newExp = exp + } + newTerm.MatchLabelExpressions = append(newTerm.MatchLabelExpressions, newExp) + } + newTopologies = append(newTopologies, newTerm) + } + return newTopologies, nil +} + +// regionTopologyHandler will process the PV and add region +// kubernetes topology label to its NodeAffinity and labels +// It assumes the Zone NodeAffinity already exists +// Each provider is responsible for providing their own regionParser +func regionTopologyHandler(pv *v1.PersistentVolume, regionParser regionParserFn) error { + + // Make sure the necessary fields exist + if pv == nil || pv.Spec.NodeAffinity == nil || pv.Spec.NodeAffinity.Required == nil || + pv.Spec.NodeAffinity.Required.NodeSelectorTerms == nil || len(pv.Spec.NodeAffinity.Required.NodeSelectorTerms) == 0 { + return nil + } + + zoneLabel, regionLabel := getTopologyLabel(pv) + + // process each term + for index, nodeSelectorTerm := range pv.Spec.NodeAffinity.Required.NodeSelectorTerms { + // In the first loop, see if regionLabel already exist + regionExist := false + var zoneVals []string + for _, nsRequirement := range nodeSelectorTerm.MatchExpressions { + if nsRequirement.Key == regionLabel { + regionExist = true + break + } else if nsRequirement.Key == zoneLabel { + zoneVals = append(zoneVals, nsRequirement.Values...) + } + } + if regionExist { + // Regionlabel already exist in this term, skip it + continue + } + // If no regionLabel found, generate region label from the zoneLabel we collect from this term + regionVal, err := regionParser(zoneVals) + if err != nil { + return err + } + // Add the regionVal to this term + pv.Spec.NodeAffinity.Required.NodeSelectorTerms[index].MatchExpressions = + append(pv.Spec.NodeAffinity.Required.NodeSelectorTerms[index].MatchExpressions, v1.NodeSelectorRequirement{ + Key: regionLabel, + Operator: v1.NodeSelectorOpIn, + Values: []string{regionVal}, + }) + + } + + // Add region label + regionVals := getTopologyValues(pv, regionLabel) + if len(regionVals) == 1 { + // We should only have exactly 1 region value + if pv.Labels == nil { + pv.Labels = make(map[string]string) + } + _, regionOK := pv.Labels[regionLabel] + if !regionOK { + pv.Labels[regionLabel] = regionVals[0] + } + } + + return nil +} diff --git a/vendor/k8s.io/csi-translation-lib/plugins/openstack_cinder.go b/vendor/k8s.io/csi-translation-lib/plugins/openstack_cinder.go new file mode 100644 index 000000000..92c5a1338 --- /dev/null +++ b/vendor/k8s.io/csi-translation-lib/plugins/openstack_cinder.go @@ -0,0 +1,184 @@ +/* +Copyright 2019 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 plugins + +import ( + "fmt" + "strings" + + v1 "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + // CinderDriverName is the name of the CSI driver for Cinder + CinderDriverName = "cinder.csi.openstack.org" + // CinderTopologyKey is the zonal topology key for Cinder CSI Driver + CinderTopologyKey = "topology.cinder.csi.openstack.org/zone" + // CinderInTreePluginName is the name of the intree plugin for Cinder + CinderInTreePluginName = "kubernetes.io/cinder" +) + +var _ InTreePlugin = (*osCinderCSITranslator)(nil) + +// osCinderCSITranslator handles translation of PV spec from In-tree Cinder to CSI Cinder and vice versa +type osCinderCSITranslator struct{} + +// NewOpenStackCinderCSITranslator returns a new instance of osCinderCSITranslator +func NewOpenStackCinderCSITranslator() InTreePlugin { + return &osCinderCSITranslator{} +} + +// TranslateInTreeStorageClassToCSI translates InTree Cinder storage class parameters to CSI storage class +func (t *osCinderCSITranslator) TranslateInTreeStorageClassToCSI(sc *storage.StorageClass) (*storage.StorageClass, error) { + var ( + params = map[string]string{} + ) + for k, v := range sc.Parameters { + switch strings.ToLower(k) { + case fsTypeKey: + params[csiFsTypeKey] = v + default: + // All other parameters are supported by the CSI driver. + // This includes also "availability", therefore do not translate it to sc.AllowedTopologies + params[k] = v + } + } + + if len(sc.AllowedTopologies) > 0 { + newTopologies, err := translateAllowedTopologies(sc.AllowedTopologies, CinderTopologyKey) + if err != nil { + return nil, fmt.Errorf("failed translating allowed topologies: %v", err) + } + sc.AllowedTopologies = newTopologies + } + + sc.Parameters = params + + return sc, nil +} + +// TranslateInTreeInlineVolumeToCSI takes a Volume with Cinder set from in-tree +// and converts the Cinder source to a CSIPersistentVolumeSource +func (t *osCinderCSITranslator) TranslateInTreeInlineVolumeToCSI(volume *v1.Volume, podNamespace string) (*v1.PersistentVolume, error) { + if volume == nil || volume.Cinder == nil { + return nil, fmt.Errorf("volume is nil or Cinder not defined on volume") + } + + cinderSource := volume.Cinder + pv := &v1.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + // Must be unique per disk as it is used as the unique part of the + // staging path + Name: fmt.Sprintf("%s-%s", CinderDriverName, cinderSource.VolumeID), + }, + Spec: v1.PersistentVolumeSpec{ + PersistentVolumeSource: v1.PersistentVolumeSource{ + CSI: &v1.CSIPersistentVolumeSource{ + Driver: CinderDriverName, + VolumeHandle: cinderSource.VolumeID, + ReadOnly: cinderSource.ReadOnly, + FSType: cinderSource.FSType, + VolumeAttributes: map[string]string{}, + }, + }, + AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, + }, + } + return pv, nil +} + +// TranslateInTreePVToCSI takes a PV with Cinder set from in-tree +// and converts the Cinder source to a CSIPersistentVolumeSource +func (t *osCinderCSITranslator) TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + if pv == nil || pv.Spec.Cinder == nil { + return nil, fmt.Errorf("pv is nil or Cinder not defined on pv") + } + + cinderSource := pv.Spec.Cinder + + csiSource := &v1.CSIPersistentVolumeSource{ + Driver: CinderDriverName, + VolumeHandle: cinderSource.VolumeID, + ReadOnly: cinderSource.ReadOnly, + FSType: cinderSource.FSType, + VolumeAttributes: map[string]string{}, + } + + if err := translateTopologyFromInTreeToCSI(pv, CinderTopologyKey); err != nil { + return nil, fmt.Errorf("failed to translate topology: %v", err) + } + + pv.Spec.Cinder = nil + pv.Spec.CSI = csiSource + return pv, nil +} + +// TranslateCSIPVToInTree takes a PV with CSIPersistentVolumeSource set and +// translates the Cinder CSI source to a Cinder In-tree source. +func (t *osCinderCSITranslator) TranslateCSIPVToInTree(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + if pv == nil || pv.Spec.CSI == nil { + return nil, fmt.Errorf("pv is nil or CSI source not defined on pv") + } + + csiSource := pv.Spec.CSI + + cinderSource := &v1.CinderPersistentVolumeSource{ + VolumeID: csiSource.VolumeHandle, + FSType: csiSource.FSType, + ReadOnly: csiSource.ReadOnly, + } + + // translate CSI topology to In-tree topology for rollback compatibility. + // It is not possible to guess Cinder Region from the Zone, therefore leave it empty. + if err := translateTopologyFromCSIToInTree(pv, CinderTopologyKey, nil); err != nil { + return nil, fmt.Errorf("failed to translate topology. PV:%+v. Error:%v", *pv, err) + } + + pv.Spec.CSI = nil + pv.Spec.Cinder = cinderSource + return pv, nil +} + +// CanSupport tests whether the plugin supports a given persistent volume +// specification from the API. The spec pointer should be considered +// const. +func (t *osCinderCSITranslator) CanSupport(pv *v1.PersistentVolume) bool { + return pv != nil && pv.Spec.Cinder != nil +} + +// CanSupportInline tests whether the plugin supports a given inline volume +// specification from the API. The spec pointer should be considered +// const. +func (t *osCinderCSITranslator) CanSupportInline(volume *v1.Volume) bool { + return volume != nil && volume.Cinder != nil +} + +// GetInTreePluginName returns the name of the intree plugin driver +func (t *osCinderCSITranslator) GetInTreePluginName() string { + return CinderInTreePluginName +} + +// GetCSIPluginName returns the name of the CSI plugin +func (t *osCinderCSITranslator) GetCSIPluginName() string { + return CinderDriverName +} + +func (t *osCinderCSITranslator) RepairVolumeHandle(volumeHandle, nodeID string) (string, error) { + return volumeHandle, nil +} diff --git a/vendor/k8s.io/csi-translation-lib/plugins/portworx.go b/vendor/k8s.io/csi-translation-lib/plugins/portworx.go new file mode 100644 index 000000000..1dcf9a255 --- /dev/null +++ b/vendor/k8s.io/csi-translation-lib/plugins/portworx.go @@ -0,0 +1,145 @@ +/* +Copyright 2021 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 plugins + +import ( + "fmt" + + "k8s.io/api/core/v1" + storagev1 "k8s.io/api/storage/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + PortworxVolumePluginName = "kubernetes.io/portworx-volume" + PortworxDriverName = "pxd.portworx.com" +) + +var _ InTreePlugin = &portworxCSITranslator{} + +type portworxCSITranslator struct{} + +func NewPortworxCSITranslator() InTreePlugin { + return &portworxCSITranslator{} +} + +// TranslateInTreeStorageClassToCSI takes in-tree storage class used by in-tree plugin +// and translates them to a storageclass consumable by CSI plugin +func (p portworxCSITranslator) TranslateInTreeStorageClassToCSI(sc *storagev1.StorageClass) (*storagev1.StorageClass, error) { + if sc == nil { + return nil, fmt.Errorf("sc is nil") + } + sc.Provisioner = PortworxDriverName + return sc, nil +} + +// TranslateInTreeInlineVolumeToCSI takes a inline volume and will translate +// the in-tree inline volume source to a CSIPersistentVolumeSource +func (p portworxCSITranslator) TranslateInTreeInlineVolumeToCSI(volume *v1.Volume, podNamespace string) (*v1.PersistentVolume, error) { + if volume == nil || volume.PortworxVolume == nil { + return nil, fmt.Errorf("volume is nil or PortworxVolume not defined on volume") + } + + var am v1.PersistentVolumeAccessMode + if volume.PortworxVolume.ReadOnly { + am = v1.ReadOnlyMany + } else { + am = v1.ReadWriteOnce + } + + pv := &v1.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-%s", PortworxDriverName, volume.PortworxVolume.VolumeID), + }, + Spec: v1.PersistentVolumeSpec{ + PersistentVolumeSource: v1.PersistentVolumeSource{ + CSI: &v1.CSIPersistentVolumeSource{ + Driver: PortworxDriverName, + VolumeHandle: volume.PortworxVolume.VolumeID, + FSType: volume.PortworxVolume.FSType, + VolumeAttributes: make(map[string]string), + }, + }, + AccessModes: []v1.PersistentVolumeAccessMode{am}, + }, + } + return pv, nil +} + +// TranslateInTreePVToCSI takes a Portworx persistent volume and will translate +// the in-tree pv source to a CSI Source +func (p portworxCSITranslator) TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + if pv == nil || pv.Spec.PortworxVolume == nil { + return nil, fmt.Errorf("pv is nil or PortworxVolume not defined on pv") + } + csiSource := &v1.CSIPersistentVolumeSource{ + Driver: PortworxDriverName, + VolumeHandle: pv.Spec.PortworxVolume.VolumeID, + FSType: pv.Spec.PortworxVolume.FSType, + VolumeAttributes: make(map[string]string), // copy access mode + } + pv.Spec.PortworxVolume = nil + pv.Spec.CSI = csiSource + + return pv, nil +} + +// TranslateCSIPVToInTree takes a PV with a CSI PersistentVolume Source and will translate +// it to a in-tree Persistent Volume Source for the in-tree volume +func (p portworxCSITranslator) TranslateCSIPVToInTree(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + if pv == nil || pv.Spec.CSI == nil { + return nil, fmt.Errorf("pv is nil or CSI source not defined on pv") + } + csiSource := pv.Spec.CSI + + portworxSource := &v1.PortworxVolumeSource{ + VolumeID: csiSource.VolumeHandle, + FSType: csiSource.FSType, + ReadOnly: csiSource.ReadOnly, + } + pv.Spec.CSI = nil + pv.Spec.PortworxVolume = portworxSource + + return pv, nil +} + +// CanSupport tests whether the plugin supports a given persistent volume +// specification from the API. +func (p portworxCSITranslator) CanSupport(pv *v1.PersistentVolume) bool { + return pv != nil && pv.Spec.PortworxVolume != nil +} + +// CanSupportInline tests whether the plugin supports a given inline volume +// specification from the API. +func (p portworxCSITranslator) CanSupportInline(volume *v1.Volume) bool { + return volume != nil && volume.PortworxVolume != nil +} + +// GetInTreePluginName returns the in-tree plugin name this migrates +func (p portworxCSITranslator) GetInTreePluginName() string { + return PortworxVolumePluginName +} + +// GetCSIPluginName returns the name of the CSI plugin that supersedes the in-tree plugin +func (p portworxCSITranslator) GetCSIPluginName() string { + return PortworxDriverName +} + +// RepairVolumeHandle generates a correct volume handle based on node ID information. +func (p portworxCSITranslator) RepairVolumeHandle(volumeHandle, nodeID string) (string, error) { + return volumeHandle, nil +} diff --git a/vendor/k8s.io/csi-translation-lib/plugins/rbd.go b/vendor/k8s.io/csi-translation-lib/plugins/rbd.go new file mode 100644 index 000000000..b0f49fdb7 --- /dev/null +++ b/vendor/k8s.io/csi-translation-lib/plugins/rbd.go @@ -0,0 +1,325 @@ +/* +Copyright 2021 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 plugins + +import ( + "crypto/md5" + "encoding/hex" + "fmt" + "strings" + + "k8s.io/api/core/v1" + storagev1 "k8s.io/api/storage/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + RBDVolumePluginName = "kubernetes.io/rbd" + RBDDriverName = "rbd.csi.ceph.com" + defaultAdminSecretNamespace = "default" + defaultImgFeatureVal = "layering" + defaultAdminUser = "admin" + defaultPoolVal = "rbd" + defaultIntreeImagePfx = "kubernetes-dynamic-pvc-" + defaultMigKey = "migration" + defaultMigStaticVal = "true" + CSIRBDVolHandleAnnKey = "rbd.csi.ceph.com/volume-handle" + imgFeatureKey = "imageFeatures" + imgFmtKey = "imageFormat" + imgNameKey = "imageName" + clusterIDKey = "clusterID" + journalPoolKey = "journalPool" + poolKey = "pool" + monsKey = "monitors" + adminIDKey = "adminId" + staticVolKey = "staticVolume" + monsPfx = "mons-" + imgPfx = "image-" + migVolPfx = "mig" + provSecretNameKey = "csi.storage.k8s.io/provisioner-secret-name" + nodeStageSecretNameKey = "csi.storage.k8s.io/node-stage-secret-name" + cntrlExpandSecretNameKey = "csi.storage.k8s.io/controller-expand-secret-name" + provSecretNamespaceKey = "csi.storage.k8s.io/provisioner-secret-namespace" + nodeStageSecretNamespaceKey = "csi.storage.k8s.io/node-stage-secret-namespace" + cntrlExpandSecretNamespaceKey = "csi.storage.k8s.io/controller-expand-secret-namespace" +) + +var _ InTreePlugin = &rbdCSITranslator{} + +type rbdCSITranslator struct{} + +func NewRBDCSITranslator() InTreePlugin { + return &rbdCSITranslator{} +} + +// TranslateInTreeStorageClassToCSI takes in-tree storage class used by in-tree plugin +// and translates them to a storage class consumable by CSI plugin +func (p rbdCSITranslator) TranslateInTreeStorageClassToCSI(sc *storagev1.StorageClass) (*storagev1.StorageClass, error) { + if sc == nil { + return nil, fmt.Errorf("sc is nil") + } + + var params = map[string]string{} + + fillDefaultSCParams(params) + for k, v := range sc.Parameters { + switch strings.ToLower(k) { + case fsTypeKey: + params[csiFsTypeKey] = v + case "imagefeatures": + params[imgFeatureKey] = v + case poolKey: + params[poolKey] = v + case "imageformat": + params[imgFmtKey] = v + case "adminid": + params[adminIDKey] = v + case "adminsecretname": + params[provSecretNameKey] = v + params[nodeStageSecretNameKey] = v + params[cntrlExpandSecretNameKey] = v + case "adminsecretnamespace": + params[provSecretNamespaceKey] = v + params[nodeStageSecretNamespaceKey] = v + params[cntrlExpandSecretNamespaceKey] = v + case monsKey: + arr := strings.Split(v, ",") + if len(arr) < 1 { + return nil, fmt.Errorf("missing Ceph monitors") + } + params[monsKey] = v + params[clusterIDKey] = fmt.Sprintf("%x", md5.Sum([]byte(v))) + } + } + + if params[provSecretNameKey] == "" { + return nil, fmt.Errorf("missing Ceph admin secret name") + } + if params[monsKey] == "" { + return nil, fmt.Errorf("missing Ceph monitors") + } + sc.Provisioner = RBDDriverName + sc.Parameters = params + return sc, nil +} + +// TranslateInTreeInlineVolumeToCSI takes an inline volume and will translate +// the in-tree inline volume source to a CSIPersistentVolumeSource +func (p rbdCSITranslator) TranslateInTreeInlineVolumeToCSI(volume *v1.Volume, podNamespace string) (*v1.PersistentVolume, error) { + if volume == nil || volume.RBD == nil { + return nil, fmt.Errorf("volume is nil or RBDVolume not defined on volume") + } + + var am v1.PersistentVolumeAccessMode + if volume.RBD.ReadOnly { + am = v1.ReadOnlyMany + } else { + am = v1.ReadWriteOnce + } + secRef := &v1.SecretReference{} + if volume.RBD.SecretRef != nil { + secRef.Name = volume.RBD.SecretRef.Name + secRef.Namespace = podNamespace + } + volumeAttr := make(map[string]string) + volumeAttr[clusterIDKey] = fmt.Sprintf("%x", md5.Sum([]byte(strings.Join(volume.RBD.CephMonitors, ",")))) + volumeAttr[poolKey] = defaultPoolVal + if volume.RBD.RBDPool != "" { + volumeAttr[poolKey] = volume.RBD.RBDPool + } + volumeAttr[staticVolKey] = defaultMigStaticVal + volumeAttr[imgFeatureKey] = defaultImgFeatureVal + pv := &v1.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-%s", RBDDriverName, volume.RBD.RBDImage), + }, + Spec: v1.PersistentVolumeSpec{ + PersistentVolumeSource: v1.PersistentVolumeSource{ + CSI: &v1.CSIPersistentVolumeSource{ + Driver: RBDDriverName, + VolumeHandle: volume.RBD.RBDImage, + FSType: volume.RBD.FSType, + VolumeAttributes: volumeAttr, + NodeStageSecretRef: secRef, + ControllerExpandSecretRef: secRef, + }, + }, + AccessModes: []v1.PersistentVolumeAccessMode{am}, + }, + } + return pv, nil +} + +// TranslateInTreePVToCSI takes a RBD persistent volume and will translate +// the in-tree pv source to a CSI Source +func (p rbdCSITranslator) TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + if pv == nil || pv.Spec.RBD == nil { + return nil, fmt.Errorf("pv is nil or RBD Volume not defined on pv") + } + var volID string + volumeAttributes := make(map[string]string) + + if pv.Annotations[CSIRBDVolHandleAnnKey] != "" { + volID = pv.Annotations[CSIRBDVolHandleAnnKey] + volumeAttributes[clusterIDKey] = pv.Annotations[clusterIDKey] + } else { + mons := strings.Join(pv.Spec.RBD.CephMonitors, ",") + pool := pv.Spec.RBD.RBDPool + image := pv.Spec.RBD.RBDImage + volumeAttributes[staticVolKey] = defaultMigStaticVal + volumeAttributes[clusterIDKey] = fmt.Sprintf("%x", md5.Sum([]byte(mons))) + volID = composeMigVolID(mons, pool, image) + } + + err := fillVolAttrsForRequest(pv, volumeAttributes) + if err != nil { + return nil, err + } + if volumeAttributes[imgFeatureKey] == "" { + volumeAttributes[imgFeatureKey] = defaultImgFeatureVal + } + var am v1.PersistentVolumeAccessMode + if pv.Spec.RBD.ReadOnly { + am = v1.ReadOnlyMany + } else { + am = v1.ReadWriteOnce + } + pv.Spec.AccessModes = []v1.PersistentVolumeAccessMode{am} + csiSource := &v1.CSIPersistentVolumeSource{ + Driver: RBDDriverName, + FSType: pv.Spec.RBD.FSType, + VolumeHandle: volID, + VolumeAttributes: volumeAttributes, + NodeStageSecretRef: pv.Spec.RBD.SecretRef, + ControllerExpandSecretRef: pv.Spec.RBD.SecretRef, + } + pv.Spec.RBD = nil + pv.Spec.CSI = csiSource + return pv, nil +} + +// TranslateCSIPVToInTree takes a PV with a CSI PersistentVolume Source and will translate +// it to an in-tree Persistent Volume Source for the in-tree volume +func (p rbdCSITranslator) TranslateCSIPVToInTree(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + if pv == nil || pv.Spec.CSI == nil { + return nil, fmt.Errorf("pv is nil or CSI source not defined on pv") + } + var rbdImageName string + monSlice := []string{""} + csiSource := pv.Spec.CSI + + rbdImageName = csiSource.VolumeAttributes[imgNameKey] + rbdPool := csiSource.VolumeAttributes[poolKey] + radosUser := csiSource.VolumeAttributes[adminIDKey] + if radosUser == "" { + radosUser = defaultAdminUser + } + + RBDSource := &v1.RBDPersistentVolumeSource{ + CephMonitors: monSlice, + RBDImage: rbdImageName, + FSType: csiSource.FSType, + RBDPool: rbdPool, + RadosUser: radosUser, + ReadOnly: csiSource.ReadOnly, + } + + if pv.Annotations == nil { + pv.Annotations = make(map[string]string) + } + fillAnnotationsFromCSISource(pv, csiSource) + nodeSecret := csiSource.NodeStageSecretRef + if nodeSecret != nil { + RBDSource.SecretRef = &v1.SecretReference{Name: nodeSecret.Name, Namespace: nodeSecret.Namespace} + } + pv.Spec.CSI = nil + pv.Spec.RBD = RBDSource + + return pv, nil +} + +// CanSupport tests whether the plugin supports a given persistent volume +// specification from the API. +func (p rbdCSITranslator) CanSupport(pv *v1.PersistentVolume) bool { + return pv != nil && pv.Spec.RBD != nil +} + +// CanSupportInline tests whether the plugin supports a given inline volume +// specification from the API. +func (p rbdCSITranslator) CanSupportInline(volume *v1.Volume) bool { + return volume != nil && volume.RBD != nil +} + +// GetInTreePluginName returns the in-tree plugin name this migrates +func (p rbdCSITranslator) GetInTreePluginName() string { + return RBDVolumePluginName +} + +// GetCSIPluginName returns the name of the CSI plugin that supersedes the in-tree plugin +func (p rbdCSITranslator) GetCSIPluginName() string { + return RBDDriverName +} + +// RepairVolumeHandle generates a correct volume handle based on node ID information. +func (p rbdCSITranslator) RepairVolumeHandle(volumeHandle, nodeID string) (string, error) { + return volumeHandle, nil +} + +// fillDefaultSCParams fills some sc parameters with default values +func fillDefaultSCParams(params map[string]string) { + params[defaultMigKey] = defaultMigStaticVal + params[poolKey] = defaultPoolVal + params[provSecretNamespaceKey] = defaultAdminSecretNamespace + params[cntrlExpandSecretNamespaceKey] = defaultAdminSecretNamespace + params[nodeStageSecretNamespaceKey] = defaultAdminSecretNamespace +} + +// composeMigVolID composes migration handle for RBD PV +// mig_mons-afcca55bc1bdd3f479be1e8281c13ab1_image-e0b45b52-7e09-47d3-8f1b-806995fa4412_7265706c696361706f6f6c +func composeMigVolID(mons string, pool string, image string) string { + clusterIDInHandle := md5.Sum([]byte(mons)) + clusterField := monsPfx + fmt.Sprintf("%x", clusterIDInHandle) + poolHashInHandle := hex.EncodeToString([]byte(pool)) + imageHashInHandle := strings.TrimPrefix(image, defaultIntreeImagePfx) + imageField := imgPfx + imageHashInHandle + volHash := strings.Join([]string{migVolPfx, clusterField, imageField, poolHashInHandle}, "_") + return volHash +} + +// fillVolAttrsForRequest fill the volume attributes for node operations +func fillVolAttrsForRequest(pv *v1.PersistentVolume, volumeAttributes map[string]string) error { + if pv == nil || pv.Spec.RBD == nil { + return fmt.Errorf("pv is nil or RBD Volume not defined on pv") + } + volumeAttributes[imgNameKey] = pv.Spec.RBD.RBDImage + volumeAttributes[poolKey] = pv.Spec.RBD.RBDPool + volumeAttributes[imgFeatureKey] = pv.Annotations[imgFeatureKey] + volumeAttributes[imgFmtKey] = pv.Annotations[imgFmtKey] + volumeAttributes[journalPoolKey] = pv.Annotations[journalPoolKey] + volumeAttributes[defaultMigKey] = defaultMigStaticVal + volumeAttributes["tryOtherMounters"] = defaultMigStaticVal + return nil +} + +// fillAnnotationsFromCSISource capture required information from csi source +func fillAnnotationsFromCSISource(pv *v1.PersistentVolume, csiSource *v1.CSIPersistentVolumeSource) { + pv.Annotations[CSIRBDVolHandleAnnKey] = csiSource.VolumeHandle + pv.Annotations[clusterIDKey] = csiSource.VolumeAttributes[clusterIDKey] + pv.Annotations[journalPoolKey] = csiSource.VolumeAttributes[journalPoolKey] + pv.Annotations[imgFeatureKey] = csiSource.VolumeAttributes[imgFeatureKey] + pv.Annotations[imgFmtKey] = csiSource.VolumeAttributes[imgFmtKey] +} diff --git a/vendor/k8s.io/csi-translation-lib/plugins/vsphere_volume.go b/vendor/k8s.io/csi-translation-lib/plugins/vsphere_volume.go new file mode 100644 index 000000000..13c37486c --- /dev/null +++ b/vendor/k8s.io/csi-translation-lib/plugins/vsphere_volume.go @@ -0,0 +1,302 @@ +/* +Copyright 2020 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 plugins + +import ( + "fmt" + "strings" + + v1 "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/klog/v2" +) + +const ( + // VSphereDriverName is the name of the CSI driver for vSphere Volume + VSphereDriverName = "csi.vsphere.vmware.com" + // VSphereInTreePluginName is the name of the in-tree plugin for vSphere Volume + VSphereInTreePluginName = "kubernetes.io/vsphere-volume" + + // vSphereCSITopologyZoneKey is the zonal topology key for vSphere CSI Driver + vSphereCSITopologyZoneKey = "topology.csi.vmware.com/zone" + + // vSphereCSITopologyRegionKey is the region topology key for vSphere CSI Driver + vSphereCSITopologyRegionKey = "topology.csi.vmware.com/region" + + // paramStoragePolicyName used to supply SPBM Policy name for Volume provisioning + paramStoragePolicyName = "storagepolicyname" + + // This param is used to tell Driver to return volumePath and not VolumeID + // in-tree vSphere plugin does not understand volume id, it uses volumePath + paramcsiMigration = "csimigration" + + // This param is used to supply datastore name for Volume provisioning + paramDatastore = "datastore-migrationparam" + + // This param supplies disk foramt (thin, thick, zeoredthick) for Volume provisioning + paramDiskFormat = "diskformat-migrationparam" + + // vSAN Policy Parameters + paramHostFailuresToTolerate = "hostfailurestotolerate-migrationparam" + paramForceProvisioning = "forceprovisioning-migrationparam" + paramCacheReservation = "cachereservation-migrationparam" + paramDiskstripes = "diskstripes-migrationparam" + paramObjectspacereservation = "objectspacereservation-migrationparam" + paramIopslimit = "iopslimit-migrationparam" + + // AttributeInitialVolumeFilepath represents the path of volume where volume is created + AttributeInitialVolumeFilepath = "initialvolumefilepath" +) + +var _ InTreePlugin = &vSphereCSITranslator{} + +// vSphereCSITranslator handles translation of PV spec from In-tree vSphere Volume to vSphere CSI +type vSphereCSITranslator struct{} + +// NewvSphereCSITranslator returns a new instance of vSphereCSITranslator +func NewvSphereCSITranslator() InTreePlugin { + return &vSphereCSITranslator{} +} + +// TranslateInTreeStorageClassToCSI translates InTree vSphere storage class parameters to CSI storage class +func (t *vSphereCSITranslator) TranslateInTreeStorageClassToCSI(sc *storage.StorageClass) (*storage.StorageClass, error) { + if sc == nil { + return nil, fmt.Errorf("sc is nil") + } + var params = map[string]string{} + for k, v := range sc.Parameters { + switch strings.ToLower(k) { + case fsTypeKey: + params[csiFsTypeKey] = v + case paramStoragePolicyName: + params[paramStoragePolicyName] = v + case "datastore": + params[paramDatastore] = v + case "diskformat": + params[paramDiskFormat] = v + case "hostfailurestotolerate": + params[paramHostFailuresToTolerate] = v + case "forceprovisioning": + params[paramForceProvisioning] = v + case "cachereservation": + params[paramCacheReservation] = v + case "diskstripes": + params[paramDiskstripes] = v + case "objectspacereservation": + params[paramObjectspacereservation] = v + case "iopslimit": + params[paramIopslimit] = v + default: + klog.V(2).Infof("StorageClass parameter [name:%q, value:%q] is not supported", k, v) + } + } + + // This helps vSphere CSI driver to identify in-tree provisioner request vs CSI provisioner request + // When this is true, Driver returns initialvolumefilepath in the VolumeContext, which is + // used in TranslateCSIPVToInTree + params[paramcsiMigration] = "true" + // translate AllowedTopologies to vSphere CSI Driver topology + if len(sc.AllowedTopologies) > 0 { + newTopologies, err := translateAllowedTopologies(sc.AllowedTopologies, vSphereCSITopologyZoneKey) + if err != nil { + return nil, fmt.Errorf("failed translating allowed topologies: %v", err) + } + sc.AllowedTopologies = newTopologies + } + sc.Parameters = params + return sc, nil +} + +// TranslateInTreeInlineVolumeToCSI takes a Volume with VsphereVolume set from in-tree +// and converts the VsphereVolume source to a CSIPersistentVolumeSource +func (t *vSphereCSITranslator) TranslateInTreeInlineVolumeToCSI(volume *v1.Volume, podNamespace string) (*v1.PersistentVolume, error) { + if volume == nil || volume.VsphereVolume == nil { + return nil, fmt.Errorf("volume is nil or VsphereVolume not defined on volume") + } + pv := &v1.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + // Must be unique per disk as it is used as the unique part of the + // staging path + Name: fmt.Sprintf("%s-%s", VSphereDriverName, volume.VsphereVolume.VolumePath), + }, + Spec: v1.PersistentVolumeSpec{ + PersistentVolumeSource: v1.PersistentVolumeSource{ + CSI: &v1.CSIPersistentVolumeSource{ + Driver: VSphereDriverName, + VolumeHandle: volume.VsphereVolume.VolumePath, + FSType: volume.VsphereVolume.FSType, + VolumeAttributes: make(map[string]string), + }, + }, + AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, + }, + } + if volume.VsphereVolume.StoragePolicyName != "" { + pv.Spec.CSI.VolumeAttributes[paramStoragePolicyName] = pv.Spec.VsphereVolume.StoragePolicyName + } + return pv, nil +} + +// TranslateInTreePVToCSI takes a PV with VsphereVolume set from in-tree +// and converts the VsphereVolume source to a CSIPersistentVolumeSource +func (t *vSphereCSITranslator) TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + if pv == nil || pv.Spec.VsphereVolume == nil { + return nil, fmt.Errorf("pv is nil or VsphereVolume not defined on pv") + } + csiSource := &v1.CSIPersistentVolumeSource{ + Driver: VSphereDriverName, + VolumeHandle: pv.Spec.VsphereVolume.VolumePath, + FSType: pv.Spec.VsphereVolume.FSType, + VolumeAttributes: make(map[string]string), + } + if pv.Spec.VsphereVolume.StoragePolicyName != "" { + csiSource.VolumeAttributes[paramStoragePolicyName] = pv.Spec.VsphereVolume.StoragePolicyName + } + // translate in-tree topology to CSI topology for migration + if err := translateTopologyFromInTreevSphereToCSI(pv, vSphereCSITopologyZoneKey, vSphereCSITopologyRegionKey); err != nil { + return nil, fmt.Errorf("failed to translate topology: %v", err) + } + pv.Spec.VsphereVolume = nil + pv.Spec.CSI = csiSource + return pv, nil +} + +// TranslateCSIPVToInTree takes a PV with CSIPersistentVolumeSource set and +// translates the vSphere CSI source to a vSphereVolume source. +func (t *vSphereCSITranslator) TranslateCSIPVToInTree(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + if pv == nil || pv.Spec.CSI == nil { + return nil, fmt.Errorf("pv is nil or CSI source not defined on pv") + } + csiSource := pv.Spec.CSI + vsphereVirtualDiskVolumeSource := &v1.VsphereVirtualDiskVolumeSource{ + FSType: csiSource.FSType, + } + volumeFilePath, ok := csiSource.VolumeAttributes[AttributeInitialVolumeFilepath] + if ok { + vsphereVirtualDiskVolumeSource.VolumePath = volumeFilePath + } + // translate CSI topology to In-tree topology for rollback compatibility. + if err := translateTopologyFromCSIToInTreevSphere(pv, vSphereCSITopologyZoneKey, vSphereCSITopologyRegionKey); err != nil { + return nil, fmt.Errorf("failed to translate topology. PV:%+v. Error:%v", *pv, err) + } + pv.Spec.CSI = nil + pv.Spec.VsphereVolume = vsphereVirtualDiskVolumeSource + return pv, nil +} + +// CanSupport tests whether the plugin supports a given persistent volume +// specification from the API. +func (t *vSphereCSITranslator) CanSupport(pv *v1.PersistentVolume) bool { + return pv != nil && pv.Spec.VsphereVolume != nil +} + +// CanSupportInline tests whether the plugin supports a given inline volume +// specification from the API. +func (t *vSphereCSITranslator) CanSupportInline(volume *v1.Volume) bool { + return volume != nil && volume.VsphereVolume != nil +} + +// GetInTreePluginName returns the name of the in-tree plugin driver +func (t *vSphereCSITranslator) GetInTreePluginName() string { + return VSphereInTreePluginName +} + +// GetCSIPluginName returns the name of the CSI plugin +func (t *vSphereCSITranslator) GetCSIPluginName() string { + return VSphereDriverName +} + +// RepairVolumeHandle is needed in VerifyVolumesAttached on the external attacher when we need to do strict volume +// handle matching to check VolumeAttachment attached status. +// vSphere volume does not need patch to help verify whether that volume is attached. +func (t *vSphereCSITranslator) RepairVolumeHandle(volumeHandle, nodeID string) (string, error) { + return volumeHandle, nil +} + +// translateTopologyFromInTreevSphereToCSI converts existing zone labels or in-tree vsphere topology to +// vSphere CSI topology. +func translateTopologyFromInTreevSphereToCSI(pv *v1.PersistentVolume, csiTopologyKeyZone string, csiTopologyKeyRegion string) error { + zoneLabel, regionLabel := getTopologyLabel(pv) + + // If Zone kubernetes topology exist, replace it to use csiTopologyKeyZone + zones := getTopologyValues(pv, zoneLabel) + if len(zones) > 0 { + replaceTopology(pv, zoneLabel, csiTopologyKeyZone) + } else { + // if nothing is in the NodeAffinity, try to fetch the topology from PV labels + if label, ok := pv.Labels[zoneLabel]; ok { + if len(label) > 0 { + addTopology(pv, csiTopologyKeyZone, []string{label}) + } + } + } + + // If region kubernetes topology exist, replace it to use csiTopologyKeyRegion + regions := getTopologyValues(pv, regionLabel) + if len(regions) > 0 { + replaceTopology(pv, regionLabel, csiTopologyKeyRegion) + } else { + // if nothing is in the NodeAffinity, try to fetch the topology from PV labels + if label, ok := pv.Labels[regionLabel]; ok { + if len(label) > 0 { + addTopology(pv, csiTopologyKeyRegion, []string{label}) + } + } + } + return nil +} + +// translateTopologyFromCSIToInTreevSphere converts CSI zone/region affinity rules to in-tree vSphere zone/region labels +func translateTopologyFromCSIToInTreevSphere(pv *v1.PersistentVolume, + csiTopologyKeyZone string, csiTopologyKeyRegion string) error { + zoneLabel, regionLabel := getTopologyLabel(pv) + + // Replace all CSI topology to Kubernetes Zone label + err := replaceTopology(pv, csiTopologyKeyZone, zoneLabel) + if err != nil { + return fmt.Errorf("failed to replace CSI topology to Kubernetes topology, error: %v", err) + } + + // Replace all CSI topology to Kubernetes Region label + err = replaceTopology(pv, csiTopologyKeyRegion, regionLabel) + if err != nil { + return fmt.Errorf("failed to replace CSI topology to Kubernetes topology, error: %v", err) + } + + zoneVals := getTopologyValues(pv, zoneLabel) + if len(zoneVals) > 0 { + if pv.Labels == nil { + pv.Labels = make(map[string]string) + } + _, zoneOK := pv.Labels[zoneLabel] + if !zoneOK { + pv.Labels[zoneLabel] = zoneVals[0] + } + } + regionVals := getTopologyValues(pv, regionLabel) + if len(regionVals) > 0 { + if pv.Labels == nil { + pv.Labels = make(map[string]string) + } + _, regionOK := pv.Labels[regionLabel] + if !regionOK { + pv.Labels[regionLabel] = regionVals[0] + } + } + return nil +} diff --git a/vendor/k8s.io/csi-translation-lib/translate.go b/vendor/k8s.io/csi-translation-lib/translate.go new file mode 100644 index 000000000..9dde21629 --- /dev/null +++ b/vendor/k8s.io/csi-translation-lib/translate.go @@ -0,0 +1,212 @@ +/* +Copyright 2019 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 csitranslation + +import ( + "errors" + "fmt" + + v1 "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1" + "k8s.io/csi-translation-lib/plugins" +) + +var ( + inTreePlugins = map[string]plugins.InTreePlugin{ + plugins.GCEPDDriverName: plugins.NewGCEPersistentDiskCSITranslator(), + plugins.AWSEBSDriverName: plugins.NewAWSElasticBlockStoreCSITranslator(), + plugins.CinderDriverName: plugins.NewOpenStackCinderCSITranslator(), + plugins.AzureDiskDriverName: plugins.NewAzureDiskCSITranslator(), + plugins.AzureFileDriverName: plugins.NewAzureFileCSITranslator(), + plugins.VSphereDriverName: plugins.NewvSphereCSITranslator(), + plugins.PortworxDriverName: plugins.NewPortworxCSITranslator(), + plugins.RBDDriverName: plugins.NewRBDCSITranslator(), + } +) + +// CSITranslator translates in-tree storage API objects to their equivalent CSI +// API objects. It also provides many helper functions to determine whether +// translation logic exists and the mappings between "in-tree plugin <-> csi driver" +type CSITranslator struct{} + +// New creates a new CSITranslator which does real translation +// for "in-tree plugins <-> csi drivers" +func New() CSITranslator { + return CSITranslator{} +} + +// TranslateInTreeStorageClassToCSI takes in-tree Storage Class +// and translates it to a set of parameters consumable by CSI plugin +func (CSITranslator) TranslateInTreeStorageClassToCSI(inTreePluginName string, sc *storage.StorageClass) (*storage.StorageClass, error) { + newSC := sc.DeepCopy() + for _, curPlugin := range inTreePlugins { + if inTreePluginName == curPlugin.GetInTreePluginName() { + return curPlugin.TranslateInTreeStorageClassToCSI(newSC) + } + } + return nil, fmt.Errorf("could not find in-tree storage class parameter translation logic for %#v", inTreePluginName) +} + +// TranslateInTreeInlineVolumeToCSI takes a inline volume and will translate +// the in-tree volume source to a CSIPersistentVolumeSource (wrapped in a PV) +// if the translation logic has been implemented. +func (CSITranslator) TranslateInTreeInlineVolumeToCSI(volume *v1.Volume, podNamespace string) (*v1.PersistentVolume, error) { + if volume == nil { + return nil, fmt.Errorf("persistent volume was nil") + } + for _, curPlugin := range inTreePlugins { + if curPlugin.CanSupportInline(volume) { + pv, err := curPlugin.TranslateInTreeInlineVolumeToCSI(volume, podNamespace) + if err != nil { + return nil, err + } + // Inline volumes only support PersistentVolumeFilesystem (and not block). + // If VolumeMode has not been set explicitly by plugin-specific + // translator, set it to Filesystem here. + // This is only necessary for inline volumes as the default PV + // initialization that populates VolumeMode does not apply to inline volumes. + if pv.Spec.VolumeMode == nil { + volumeMode := v1.PersistentVolumeFilesystem + pv.Spec.VolumeMode = &volumeMode + } + return pv, nil + } + } + return nil, fmt.Errorf("could not find in-tree plugin translation logic for %#v", volume.Name) +} + +// TranslateInTreePVToCSI takes a persistent volume and will translate +// the in-tree source to a CSI Source if the translation logic +// has been implemented. The input persistent volume will not +// be modified +func (CSITranslator) TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + if pv == nil { + return nil, errors.New("persistent volume was nil") + } + copiedPV := pv.DeepCopy() + for _, curPlugin := range inTreePlugins { + if curPlugin.CanSupport(copiedPV) { + return curPlugin.TranslateInTreePVToCSI(copiedPV) + } + } + return nil, fmt.Errorf("could not find in-tree plugin translation logic for %#v", copiedPV.Name) +} + +// TranslateCSIPVToInTree takes a PV with a CSI PersistentVolume Source and will translate +// it to a in-tree Persistent Volume Source for the specific in-tree volume specified +// by the `Driver` field in the CSI Source. The input PV object will not be modified. +func (CSITranslator) TranslateCSIPVToInTree(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + if pv == nil || pv.Spec.CSI == nil { + return nil, errors.New("CSI persistent volume was nil") + } + copiedPV := pv.DeepCopy() + for driverName, curPlugin := range inTreePlugins { + if copiedPV.Spec.CSI.Driver == driverName { + return curPlugin.TranslateCSIPVToInTree(copiedPV) + } + } + return nil, fmt.Errorf("could not find in-tree plugin translation logic for %s", copiedPV.Spec.CSI.Driver) +} + +// IsMigratableIntreePluginByName tests whether there is migration logic for the in-tree plugin +// whose name matches the given name +func (CSITranslator) IsMigratableIntreePluginByName(inTreePluginName string) bool { + for _, curPlugin := range inTreePlugins { + if curPlugin.GetInTreePluginName() == inTreePluginName { + return true + } + } + return false +} + +// IsMigratedCSIDriverByName tests whether there exists an in-tree plugin with logic +// to migrate to the CSI driver with given name +func (CSITranslator) IsMigratedCSIDriverByName(csiPluginName string) bool { + if _, ok := inTreePlugins[csiPluginName]; ok { + return true + } + return false +} + +// GetInTreePluginNameFromSpec returns the plugin name +func (CSITranslator) GetInTreePluginNameFromSpec(pv *v1.PersistentVolume, vol *v1.Volume) (string, error) { + if pv != nil { + for _, curPlugin := range inTreePlugins { + if curPlugin.CanSupport(pv) { + return curPlugin.GetInTreePluginName(), nil + } + } + return "", fmt.Errorf("could not find in-tree plugin name from persistent volume %v", pv) + } else if vol != nil { + for _, curPlugin := range inTreePlugins { + if curPlugin.CanSupportInline(vol) { + return curPlugin.GetInTreePluginName(), nil + } + } + return "", fmt.Errorf("could not find in-tree plugin name from volume %v", vol) + } else { + return "", errors.New("both persistent volume and volume are nil") + } +} + +// GetCSINameFromInTreeName returns the name of a CSI driver that supersedes the +// in-tree plugin with the given name +func (CSITranslator) GetCSINameFromInTreeName(pluginName string) (string, error) { + for csiDriverName, curPlugin := range inTreePlugins { + if curPlugin.GetInTreePluginName() == pluginName { + return csiDriverName, nil + } + } + return "", fmt.Errorf("could not find CSI Driver name for plugin %v", pluginName) +} + +// GetInTreeNameFromCSIName returns the name of the in-tree plugin superseded by +// a CSI driver with the given name +func (CSITranslator) GetInTreeNameFromCSIName(pluginName string) (string, error) { + if plugin, ok := inTreePlugins[pluginName]; ok { + return plugin.GetInTreePluginName(), nil + } + return "", fmt.Errorf("could not find In-Tree driver name for CSI plugin %v", pluginName) +} + +// IsPVMigratable tests whether there is migration logic for the given Persistent Volume +func (CSITranslator) IsPVMigratable(pv *v1.PersistentVolume) bool { + for _, curPlugin := range inTreePlugins { + if curPlugin.CanSupport(pv) { + return true + } + } + return false +} + +// IsInlineMigratable tests whether there is Migration logic for the given Inline Volume +func (CSITranslator) IsInlineMigratable(vol *v1.Volume) bool { + for _, curPlugin := range inTreePlugins { + if curPlugin.CanSupportInline(vol) { + return true + } + } + return false +} + +// RepairVolumeHandle generates a correct volume handle based on node ID information. +func (CSITranslator) RepairVolumeHandle(driverName, volumeHandle, nodeID string) (string, error) { + if plugin, ok := inTreePlugins[driverName]; ok { + return plugin.RepairVolumeHandle(volumeHandle, nodeID) + } + return "", fmt.Errorf("could not find In-Tree driver name for CSI plugin %v", driverName) +} diff --git a/vendor/k8s.io/dynamic-resource-allocation/LICENSE b/vendor/k8s.io/dynamic-resource-allocation/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/k8s.io/dynamic-resource-allocation/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/vendor/k8s.io/dynamic-resource-allocation/resourceclaim/resourceclaim.go b/vendor/k8s.io/dynamic-resource-allocation/resourceclaim/resourceclaim.go new file mode 100644 index 000000000..5d5eb94c5 --- /dev/null +++ b/vendor/k8s.io/dynamic-resource-allocation/resourceclaim/resourceclaim.go @@ -0,0 +1,81 @@ +/* +Copyright 2022 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 resourceclaim provides code that supports the usual pattern +// for accessing the ResourceClaim that is referenced by a PodResourceClaim: +// +// - determine the ResourceClaim name that corresponds to the PodResourceClaim +// - retrieve the ResourceClaim +// - verify that the ResourceClaim is owned by the pod if generated from a template +// - use the ResourceClaim +package resourceclaim + +import ( + "fmt" + + v1 "k8s.io/api/core/v1" + resourcev1alpha1 "k8s.io/api/resource/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// Name returns the name of the ResourceClaim object that gets referenced by or +// created for the PodResourceClaim. The name is deterministic and therefore +// this function does not need any additional information and it will never +// fail. +// +// Either podClaim.ResourceClaimName or podClaim.Template must be non-nil, but not +// both. This is enforced by API validation. +// +// If podClaim.Template is not nil, the caller must check that the +// ResourceClaim is indeed the one that was created for the Pod by calling +// IsUsable. +func Name(pod *v1.Pod, podClaim *v1.PodResourceClaim) string { + if podClaim.Source.ResourceClaimName != nil { + return *podClaim.Source.ResourceClaimName + } + return pod.Name + "-" + podClaim.Name +} + +// IsForPod checks that the ResourceClaim is the ephemeral volume that +// was created for the Pod. It returns an error that is informative +// enough to be returned by the caller without adding further details +// about the Pod or ResourceClaim. +func IsForPod(pod *v1.Pod, claim *resourcev1alpha1.ResourceClaim) error { + // Checking the namespaces is just a precaution. The caller should + // never pass in a ResourceClaim that isn't from the same namespace as the + // Pod. + if claim.Namespace != pod.Namespace || !metav1.IsControlledBy(claim, pod) { + return fmt.Errorf("ResourceClaim %s/%s was not created for pod %s/%s (pod is not owner)", claim.Namespace, claim.Name, pod.Namespace, pod.Name) + } + return nil +} + +// IsReservedForPod checks whether a claim lists the pod as one of the objects +// that the claim was reserved for. +func IsReservedForPod(pod *v1.Pod, claim *resourcev1alpha1.ResourceClaim) bool { + for _, reserved := range claim.Status.ReservedFor { + if reserved.UID == pod.UID { + return true + } + } + return false +} + +// CanBeReserved checks whether the claim could be reserved for another object. +func CanBeReserved(claim *resourcev1alpha1.ResourceClaim) bool { + return claim.Status.Allocation.Shareable || + len(claim.Status.ReservedFor) == 0 +} diff --git a/vendor/k8s.io/kube-scheduler/LICENSE b/vendor/k8s.io/kube-scheduler/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/vendor/k8s.io/kube-scheduler/config/v1/doc.go b/vendor/k8s.io/kube-scheduler/config/v1/doc.go new file mode 100644 index 000000000..bbc4641e7 --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/config/v1/doc.go @@ -0,0 +1,21 @@ +/* +Copyright 2022 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. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:openapi-gen=true +// +groupName=kubescheduler.config.k8s.io + +package v1 // import "k8s.io/kube-scheduler/config/v1" diff --git a/vendor/k8s.io/kube-scheduler/config/v1/register.go b/vendor/k8s.io/kube-scheduler/config/v1/register.go new file mode 100644 index 000000000..58adac5dc --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/config/v1/register.go @@ -0,0 +1,50 @@ +/* +Copyright 2022 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 v1 + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// GroupName is the group name used in this package +const GroupName = "kubescheduler.config.k8s.io" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} + +var ( + // SchemeBuilder is the scheme builder with scheme init functions to run for this API package + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + // AddToScheme is a global function that registers this API group & version to a scheme + AddToScheme = SchemeBuilder.AddToScheme +) + +// addKnownTypes registers known types to the given scheme +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &KubeSchedulerConfiguration{}, + &DefaultPreemptionArgs{}, + &InterPodAffinityArgs{}, + &NodeResourcesBalancedAllocationArgs{}, + &NodeResourcesFitArgs{}, + &PodTopologySpreadArgs{}, + &VolumeBindingArgs{}, + &NodeAffinityArgs{}, + ) + return nil +} diff --git a/vendor/k8s.io/kube-scheduler/config/v1/types.go b/vendor/k8s.io/kube-scheduler/config/v1/types.go new file mode 100644 index 000000000..703516fb7 --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/config/v1/types.go @@ -0,0 +1,391 @@ +/* +Copyright 2022 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 v1 + +import ( + "bytes" + "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + componentbaseconfigv1alpha1 "k8s.io/component-base/config/v1alpha1" + "sigs.k8s.io/yaml" +) + +const ( + // SchedulerDefaultLockObjectNamespace defines default scheduler lock object namespace ("kube-system") + SchedulerDefaultLockObjectNamespace string = metav1.NamespaceSystem + + // SchedulerDefaultLockObjectName defines default scheduler lock object name ("kube-scheduler") + SchedulerDefaultLockObjectName = "kube-scheduler" + + // SchedulerDefaultProviderName defines the default provider names + SchedulerDefaultProviderName = "DefaultProvider" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// KubeSchedulerConfiguration configures a scheduler +type KubeSchedulerConfiguration struct { + metav1.TypeMeta `json:",inline"` + + // Parallelism defines the amount of parallelism in algorithms for scheduling a Pods. Must be greater than 0. Defaults to 16 + Parallelism *int32 `json:"parallelism,omitempty"` + + // LeaderElection defines the configuration of leader election client. + LeaderElection componentbaseconfigv1alpha1.LeaderElectionConfiguration `json:"leaderElection"` + + // ClientConnection specifies the kubeconfig file and client connection + // settings for the proxy server to use when communicating with the apiserver. + ClientConnection componentbaseconfigv1alpha1.ClientConnectionConfiguration `json:"clientConnection"` + + // DebuggingConfiguration holds configuration for Debugging related features + // TODO: We might wanna make this a substruct like Debugging componentbaseconfigv1alpha1.DebuggingConfiguration + componentbaseconfigv1alpha1.DebuggingConfiguration `json:",inline"` + + // PercentageOfNodesToScore is the percentage of all nodes that once found feasible + // for running a pod, the scheduler stops its search for more feasible nodes in + // the cluster. This helps improve scheduler's performance. Scheduler always tries to find + // at least "minFeasibleNodesToFind" feasible nodes no matter what the value of this flag is. + // Example: if the cluster size is 500 nodes and the value of this flag is 30, + // then scheduler stops finding further feasible nodes once it finds 150 feasible ones. + // When the value is 0, default percentage (5%--50% based on the size of the cluster) of the + // nodes will be scored. It is overridden by profile level PercentageofNodesToScore. + PercentageOfNodesToScore *int32 `json:"percentageOfNodesToScore,omitempty"` + + // PodInitialBackoffSeconds is the initial backoff for unschedulable pods. + // If specified, it must be greater than 0. If this value is null, the default value (1s) + // will be used. + PodInitialBackoffSeconds *int64 `json:"podInitialBackoffSeconds,omitempty"` + + // PodMaxBackoffSeconds is the max backoff for unschedulable pods. + // If specified, it must be greater than podInitialBackoffSeconds. If this value is null, + // the default value (10s) will be used. + PodMaxBackoffSeconds *int64 `json:"podMaxBackoffSeconds,omitempty"` + + // Profiles are scheduling profiles that kube-scheduler supports. Pods can + // choose to be scheduled under a particular profile by setting its associated + // scheduler name. Pods that don't specify any scheduler name are scheduled + // with the "default-scheduler" profile, if present here. + // +listType=map + // +listMapKey=schedulerName + Profiles []KubeSchedulerProfile `json:"profiles,omitempty"` + + // Extenders are the list of scheduler extenders, each holding the values of how to communicate + // with the extender. These extenders are shared by all scheduler profiles. + // +listType=set + Extenders []Extender `json:"extenders,omitempty"` +} + +// DecodeNestedObjects decodes plugin args for known types. +func (c *KubeSchedulerConfiguration) DecodeNestedObjects(d runtime.Decoder) error { + var strictDecodingErrs []error + for i := range c.Profiles { + prof := &c.Profiles[i] + for j := range prof.PluginConfig { + err := prof.PluginConfig[j].decodeNestedObjects(d) + if err != nil { + decodingErr := fmt.Errorf("decoding .profiles[%d].pluginConfig[%d]: %w", i, j, err) + if runtime.IsStrictDecodingError(err) { + strictDecodingErrs = append(strictDecodingErrs, decodingErr) + } else { + return decodingErr + } + } + } + } + if len(strictDecodingErrs) > 0 { + return runtime.NewStrictDecodingError(strictDecodingErrs) + } + return nil +} + +// EncodeNestedObjects encodes plugin args. +func (c *KubeSchedulerConfiguration) EncodeNestedObjects(e runtime.Encoder) error { + for i := range c.Profiles { + prof := &c.Profiles[i] + for j := range prof.PluginConfig { + err := prof.PluginConfig[j].encodeNestedObjects(e) + if err != nil { + return fmt.Errorf("encoding .profiles[%d].pluginConfig[%d]: %w", i, j, err) + } + } + } + return nil +} + +// KubeSchedulerProfile is a scheduling profile. +type KubeSchedulerProfile struct { + // SchedulerName is the name of the scheduler associated to this profile. + // If SchedulerName matches with the pod's "spec.schedulerName", then the pod + // is scheduled with this profile. + SchedulerName *string `json:"schedulerName,omitempty"` + + // PercentageOfNodesToScore is the percentage of all nodes that once found feasible + // for running a pod, the scheduler stops its search for more feasible nodes in + // the cluster. This helps improve scheduler's performance. Scheduler always tries to find + // at least "minFeasibleNodesToFind" feasible nodes no matter what the value of this flag is. + // Example: if the cluster size is 500 nodes and the value of this flag is 30, + // then scheduler stops finding further feasible nodes once it finds 150 feasible ones. + // When the value is 0, default percentage (5%--50% based on the size of the cluster) of the + // nodes will be scored. It will override global PercentageOfNodesToScore. If it is empty, + // global PercentageOfNodesToScore will be used. + PercentageOfNodesToScore *int32 `json:"percentageOfNodesToScore,omitempty"` + + // Plugins specify the set of plugins that should be enabled or disabled. + // Enabled plugins are the ones that should be enabled in addition to the + // default plugins. Disabled plugins are any of the default plugins that + // should be disabled. + // When no enabled or disabled plugin is specified for an extension point, + // default plugins for that extension point will be used if there is any. + // If a QueueSort plugin is specified, the same QueueSort Plugin and + // PluginConfig must be specified for all profiles. + Plugins *Plugins `json:"plugins,omitempty"` + + // PluginConfig is an optional set of custom plugin arguments for each plugin. + // Omitting config args for a plugin is equivalent to using the default config + // for that plugin. + // +listType=map + // +listMapKey=name + PluginConfig []PluginConfig `json:"pluginConfig,omitempty"` +} + +// Plugins include multiple extension points. When specified, the list of plugins for +// a particular extension point are the only ones enabled. If an extension point is +// omitted from the config, then the default set of plugins is used for that extension point. +// Enabled plugins are called in the order specified here, after default plugins. If they need to +// be invoked before default plugins, default plugins must be disabled and re-enabled here in desired order. +type Plugins struct { + // PreEnqueue is a list of plugins that should be invoked before adding pods to the scheduling queue. + PreEnqueue PluginSet `json:"preEnqueue,omitempty"` + + // QueueSort is a list of plugins that should be invoked when sorting pods in the scheduling queue. + QueueSort PluginSet `json:"queueSort,omitempty"` + + // PreFilter is a list of plugins that should be invoked at "PreFilter" extension point of the scheduling framework. + PreFilter PluginSet `json:"preFilter,omitempty"` + + // Filter is a list of plugins that should be invoked when filtering out nodes that cannot run the Pod. + Filter PluginSet `json:"filter,omitempty"` + + // PostFilter is a list of plugins that are invoked after filtering phase, but only when no feasible nodes were found for the pod. + PostFilter PluginSet `json:"postFilter,omitempty"` + + // PreScore is a list of plugins that are invoked before scoring. + PreScore PluginSet `json:"preScore,omitempty"` + + // Score is a list of plugins that should be invoked when ranking nodes that have passed the filtering phase. + Score PluginSet `json:"score,omitempty"` + + // Reserve is a list of plugins invoked when reserving/unreserving resources + // after a node is assigned to run the pod. + Reserve PluginSet `json:"reserve,omitempty"` + + // Permit is a list of plugins that control binding of a Pod. These plugins can prevent or delay binding of a Pod. + Permit PluginSet `json:"permit,omitempty"` + + // PreBind is a list of plugins that should be invoked before a pod is bound. + PreBind PluginSet `json:"preBind,omitempty"` + + // Bind is a list of plugins that should be invoked at "Bind" extension point of the scheduling framework. + // The scheduler call these plugins in order. Scheduler skips the rest of these plugins as soon as one returns success. + Bind PluginSet `json:"bind,omitempty"` + + // PostBind is a list of plugins that should be invoked after a pod is successfully bound. + PostBind PluginSet `json:"postBind,omitempty"` + + // MultiPoint is a simplified config section to enable plugins for all valid extension points. + // Plugins enabled through MultiPoint will automatically register for every individual extension + // point the plugin has implemented. Disabling a plugin through MultiPoint disables that behavior. + // The same is true for disabling "*" through MultiPoint (no default plugins will be automatically registered). + // Plugins can still be disabled through their individual extension points. + // + // In terms of precedence, plugin config follows this basic hierarchy + // 1. Specific extension points + // 2. Explicitly configured MultiPoint plugins + // 3. The set of default plugins, as MultiPoint plugins + // This implies that a higher precedence plugin will run first and overwrite any settings within MultiPoint. + // Explicitly user-configured plugins also take a higher precedence over default plugins. + // Within this hierarchy, an Enabled setting takes precedence over Disabled. For example, if a plugin is + // set in both `multiPoint.Enabled` and `multiPoint.Disabled`, the plugin will be enabled. Similarly, + // including `multiPoint.Disabled = '*'` and `multiPoint.Enabled = pluginA` will still register that specific + // plugin through MultiPoint. This follows the same behavior as all other extension point configurations. + MultiPoint PluginSet `json:"multiPoint,omitempty"` +} + +// PluginSet specifies enabled and disabled plugins for an extension point. +// If an array is empty, missing, or nil, default plugins at that extension point will be used. +type PluginSet struct { + // Enabled specifies plugins that should be enabled in addition to default plugins. + // If the default plugin is also configured in the scheduler config file, the weight of plugin will + // be overridden accordingly. + // These are called after default plugins and in the same order specified here. + // +listType=atomic + Enabled []Plugin `json:"enabled,omitempty"` + // Disabled specifies default plugins that should be disabled. + // When all default plugins need to be disabled, an array containing only one "*" should be provided. + // +listType=map + // +listMapKey=name + Disabled []Plugin `json:"disabled,omitempty"` +} + +// Plugin specifies a plugin name and its weight when applicable. Weight is used only for Score plugins. +type Plugin struct { + // Name defines the name of plugin + Name string `json:"name"` + // Weight defines the weight of plugin, only used for Score plugins. + Weight *int32 `json:"weight,omitempty"` +} + +// PluginConfig specifies arguments that should be passed to a plugin at the time of initialization. +// A plugin that is invoked at multiple extension points is initialized once. Args can have arbitrary structure. +// It is up to the plugin to process these Args. +type PluginConfig struct { + // Name defines the name of plugin being configured + Name string `json:"name"` + // Args defines the arguments passed to the plugins at the time of initialization. Args can have arbitrary structure. + Args runtime.RawExtension `json:"args,omitempty"` +} + +func (c *PluginConfig) decodeNestedObjects(d runtime.Decoder) error { + gvk := SchemeGroupVersion.WithKind(c.Name + "Args") + // dry-run to detect and skip out-of-tree plugin args. + if _, _, err := d.Decode(nil, &gvk, nil); runtime.IsNotRegisteredError(err) { + return nil + } + + var strictDecodingErr error + obj, parsedGvk, err := d.Decode(c.Args.Raw, &gvk, nil) + if err != nil { + decodingArgsErr := fmt.Errorf("decoding args for plugin %s: %w", c.Name, err) + if obj != nil && runtime.IsStrictDecodingError(err) { + strictDecodingErr = runtime.NewStrictDecodingError([]error{decodingArgsErr}) + } else { + return decodingArgsErr + } + } + if parsedGvk.GroupKind() != gvk.GroupKind() { + return fmt.Errorf("args for plugin %s were not of type %s, got %s", c.Name, gvk.GroupKind(), parsedGvk.GroupKind()) + } + c.Args.Object = obj + return strictDecodingErr +} + +func (c *PluginConfig) encodeNestedObjects(e runtime.Encoder) error { + if c.Args.Object == nil { + return nil + } + var buf bytes.Buffer + err := e.Encode(c.Args.Object, &buf) + if err != nil { + return err + } + // The encoder might be a YAML encoder, but the parent encoder expects + // JSON output, so we convert YAML back to JSON. + // This is a no-op if produces JSON. + json, err := yaml.YAMLToJSON(buf.Bytes()) + if err != nil { + return err + } + c.Args.Raw = json + return nil +} + +// Extender holds the parameters used to communicate with the extender. If a verb is unspecified/empty, +// it is assumed that the extender chose not to provide that extension. +type Extender struct { + // URLPrefix at which the extender is available + URLPrefix string `json:"urlPrefix"` + // Verb for the filter call, empty if not supported. This verb is appended to the URLPrefix when issuing the filter call to extender. + FilterVerb string `json:"filterVerb,omitempty"` + // Verb for the preempt call, empty if not supported. This verb is appended to the URLPrefix when issuing the preempt call to extender. + PreemptVerb string `json:"preemptVerb,omitempty"` + // Verb for the prioritize call, empty if not supported. This verb is appended to the URLPrefix when issuing the prioritize call to extender. + PrioritizeVerb string `json:"prioritizeVerb,omitempty"` + // The numeric multiplier for the node scores that the prioritize call generates. + // The weight should be a positive integer + Weight int64 `json:"weight,omitempty"` + // Verb for the bind call, empty if not supported. This verb is appended to the URLPrefix when issuing the bind call to extender. + // If this method is implemented by the extender, it is the extender's responsibility to bind the pod to apiserver. Only one extender + // can implement this function. + BindVerb string `json:"bindVerb,omitempty"` + // EnableHTTPS specifies whether https should be used to communicate with the extender + EnableHTTPS bool `json:"enableHTTPS,omitempty"` + // TLSConfig specifies the transport layer security config + TLSConfig *ExtenderTLSConfig `json:"tlsConfig,omitempty"` + // HTTPTimeout specifies the timeout duration for a call to the extender. Filter timeout fails the scheduling of the pod. Prioritize + // timeout is ignored, k8s/other extenders priorities are used to select the node. + HTTPTimeout metav1.Duration `json:"httpTimeout,omitempty"` + // NodeCacheCapable specifies that the extender is capable of caching node information, + // so the scheduler should only send minimal information about the eligible nodes + // assuming that the extender already cached full details of all nodes in the cluster + NodeCacheCapable bool `json:"nodeCacheCapable,omitempty"` + // ManagedResources is a list of extended resources that are managed by + // this extender. + // - A pod will be sent to the extender on the Filter, Prioritize and Bind + // (if the extender is the binder) phases iff the pod requests at least + // one of the extended resources in this list. If empty or unspecified, + // all pods will be sent to this extender. + // - If IgnoredByScheduler is set to true for a resource, kube-scheduler + // will skip checking the resource in predicates. + // +optional + // +listType=atomic + ManagedResources []ExtenderManagedResource `json:"managedResources,omitempty"` + // Ignorable specifies if the extender is ignorable, i.e. scheduling should not + // fail when the extender returns an error or is not reachable. + Ignorable bool `json:"ignorable,omitempty"` +} + +// ExtenderManagedResource describes the arguments of extended resources +// managed by an extender. +type ExtenderManagedResource struct { + // Name is the extended resource name. + Name string `json:"name"` + // IgnoredByScheduler indicates whether kube-scheduler should ignore this + // resource when applying predicates. + IgnoredByScheduler bool `json:"ignoredByScheduler,omitempty"` +} + +// ExtenderTLSConfig contains settings to enable TLS with extender +type ExtenderTLSConfig struct { + // Server should be accessed without verifying the TLS certificate. For testing only. + Insecure bool `json:"insecure,omitempty"` + // ServerName is passed to the server for SNI and is used in the client to check server + // certificates against. If ServerName is empty, the hostname used to contact the + // server is used. + ServerName string `json:"serverName,omitempty"` + + // Server requires TLS client certificate authentication + CertFile string `json:"certFile,omitempty"` + // Server requires TLS client certificate authentication + KeyFile string `json:"keyFile,omitempty"` + // Trusted root certificates for server + CAFile string `json:"caFile,omitempty"` + + // CertData holds PEM-encoded bytes (typically read from a client certificate file). + // CertData takes precedence over CertFile + // +listType=atomic + CertData []byte `json:"certData,omitempty"` + // KeyData holds PEM-encoded bytes (typically read from a client certificate key file). + // KeyData takes precedence over KeyFile + // +listType=atomic + KeyData []byte `json:"keyData,omitempty"` + // CAData holds PEM-encoded bytes (typically read from a root certificates bundle). + // CAData takes precedence over CAFile + // +listType=atomic + CAData []byte `json:"caData,omitempty"` +} diff --git a/vendor/k8s.io/kube-scheduler/config/v1/types_pluginargs.go b/vendor/k8s.io/kube-scheduler/config/v1/types_pluginargs.go new file mode 100644 index 000000000..2698a4769 --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/config/v1/types_pluginargs.go @@ -0,0 +1,225 @@ +/* +Copyright 2022 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 v1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// DefaultPreemptionArgs holds arguments used to configure the +// DefaultPreemption plugin. +type DefaultPreemptionArgs struct { + metav1.TypeMeta `json:",inline"` + + // MinCandidateNodesPercentage is the minimum number of candidates to + // shortlist when dry running preemption as a percentage of number of nodes. + // Must be in the range [0, 100]. Defaults to 10% of the cluster size if + // unspecified. + MinCandidateNodesPercentage *int32 `json:"minCandidateNodesPercentage,omitempty"` + // MinCandidateNodesAbsolute is the absolute minimum number of candidates to + // shortlist. The likely number of candidates enumerated for dry running + // preemption is given by the formula: + // numCandidates = max(numNodes * minCandidateNodesPercentage, minCandidateNodesAbsolute) + // We say "likely" because there are other factors such as PDB violations + // that play a role in the number of candidates shortlisted. Must be at least + // 0 nodes. Defaults to 100 nodes if unspecified. + MinCandidateNodesAbsolute *int32 `json:"minCandidateNodesAbsolute,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// InterPodAffinityArgs holds arguments used to configure the InterPodAffinity plugin. +type InterPodAffinityArgs struct { + metav1.TypeMeta `json:",inline"` + + // HardPodAffinityWeight is the scoring weight for existing pods with a + // matching hard affinity to the incoming pod. + HardPodAffinityWeight *int32 `json:"hardPodAffinityWeight,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// NodeResourcesFitArgs holds arguments used to configure the NodeResourcesFit plugin. +type NodeResourcesFitArgs struct { + metav1.TypeMeta `json:",inline"` + + // IgnoredResources is the list of resources that NodeResources fit filter + // should ignore. This doesn't apply to scoring. + // +listType=atomic + IgnoredResources []string `json:"ignoredResources,omitempty"` + // IgnoredResourceGroups defines the list of resource groups that NodeResources fit filter should ignore. + // e.g. if group is ["example.com"], it will ignore all resource names that begin + // with "example.com", such as "example.com/aaa" and "example.com/bbb". + // A resource group name can't contain '/'. This doesn't apply to scoring. + // +listType=atomic + IgnoredResourceGroups []string `json:"ignoredResourceGroups,omitempty"` + + // ScoringStrategy selects the node resource scoring strategy. + // The default strategy is LeastAllocated with an equal "cpu" and "memory" weight. + ScoringStrategy *ScoringStrategy `json:"scoringStrategy,omitempty"` +} + +// PodTopologySpreadConstraintsDefaulting defines how to set default constraints +// for the PodTopologySpread plugin. +type PodTopologySpreadConstraintsDefaulting string + +const ( + // SystemDefaulting instructs to use the kubernetes defined default. + SystemDefaulting PodTopologySpreadConstraintsDefaulting = "System" + // ListDefaulting instructs to use the config provided default. + ListDefaulting PodTopologySpreadConstraintsDefaulting = "List" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// PodTopologySpreadArgs holds arguments used to configure the PodTopologySpread plugin. +type PodTopologySpreadArgs struct { + metav1.TypeMeta `json:",inline"` + + // DefaultConstraints defines topology spread constraints to be applied to + // Pods that don't define any in `pod.spec.topologySpreadConstraints`. + // `.defaultConstraints[*].labelSelectors` must be empty, as they are + // deduced from the Pod's membership to Services, ReplicationControllers, + // ReplicaSets or StatefulSets. + // When not empty, .defaultingType must be "List". + // +optional + // +listType=atomic + DefaultConstraints []corev1.TopologySpreadConstraint `json:"defaultConstraints,omitempty"` + + // DefaultingType determines how .defaultConstraints are deduced. Can be one + // of "System" or "List". + // + // - "System": Use kubernetes defined constraints that spread Pods among + // Nodes and Zones. + // - "List": Use constraints defined in .defaultConstraints. + // + // Defaults to "System". + // +optional + DefaultingType PodTopologySpreadConstraintsDefaulting `json:"defaultingType,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// NodeResourcesBalancedAllocationArgs holds arguments used to configure NodeResourcesBalancedAllocation plugin. +type NodeResourcesBalancedAllocationArgs struct { + metav1.TypeMeta `json:",inline"` + + // Resources to be managed, the default is "cpu" and "memory" if not specified. + // +listType=map + // +listMapKey=name + Resources []ResourceSpec `json:"resources,omitempty"` +} + +// UtilizationShapePoint represents single point of priority function shape. +type UtilizationShapePoint struct { + // Utilization (x axis). Valid values are 0 to 100. Fully utilized node maps to 100. + Utilization int32 `json:"utilization"` + // Score assigned to given utilization (y axis). Valid values are 0 to 10. + Score int32 `json:"score"` +} + +// ResourceSpec represents a single resource. +type ResourceSpec struct { + // Name of the resource. + Name string `json:"name"` + // Weight of the resource. + Weight int64 `json:"weight,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// VolumeBindingArgs holds arguments used to configure the VolumeBinding plugin. +type VolumeBindingArgs struct { + metav1.TypeMeta `json:",inline"` + + // BindTimeoutSeconds is the timeout in seconds in volume binding operation. + // Value must be non-negative integer. The value zero indicates no waiting. + // If this value is nil, the default value (600) will be used. + BindTimeoutSeconds *int64 `json:"bindTimeoutSeconds,omitempty"` + + // Shape specifies the points defining the score function shape, which is + // used to score nodes based on the utilization of statically provisioned + // PVs. The utilization is calculated by dividing the total requested + // storage of the pod by the total capacity of feasible PVs on each node. + // Each point contains utilization (ranges from 0 to 100) and its + // associated score (ranges from 0 to 10). You can turn the priority by + // specifying different scores for different utilization numbers. + // The default shape points are: + // 1) 0 for 0 utilization + // 2) 10 for 100 utilization + // All points must be sorted in increasing order by utilization. + // +featureGate=VolumeCapacityPriority + // +optional + // +listType=atomic + Shape []UtilizationShapePoint `json:"shape,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// NodeAffinityArgs holds arguments to configure the NodeAffinity plugin. +type NodeAffinityArgs struct { + metav1.TypeMeta `json:",inline"` + + // AddedAffinity is applied to all Pods additionally to the NodeAffinity + // specified in the PodSpec. That is, Nodes need to satisfy AddedAffinity + // AND .spec.NodeAffinity. AddedAffinity is empty by default (all Nodes + // match). + // When AddedAffinity is used, some Pods with affinity requirements that match + // a specific Node (such as Daemonset Pods) might remain unschedulable. + // +optional + AddedAffinity *corev1.NodeAffinity `json:"addedAffinity,omitempty"` +} + +// ScoringStrategyType the type of scoring strategy used in NodeResourcesFit plugin. +type ScoringStrategyType string + +const ( + // LeastAllocated strategy prioritizes nodes with least allocated resources. + LeastAllocated ScoringStrategyType = "LeastAllocated" + // MostAllocated strategy prioritizes nodes with most allocated resources. + MostAllocated ScoringStrategyType = "MostAllocated" + // RequestedToCapacityRatio strategy allows specifying a custom shape function + // to score nodes based on the request to capacity ratio. + RequestedToCapacityRatio ScoringStrategyType = "RequestedToCapacityRatio" +) + +// ScoringStrategy define ScoringStrategyType for node resource plugin +type ScoringStrategy struct { + // Type selects which strategy to run. + Type ScoringStrategyType `json:"type,omitempty"` + + // Resources to consider when scoring. + // The default resource set includes "cpu" and "memory" with an equal weight. + // Allowed weights go from 1 to 100. + // Weight defaults to 1 if not specified or explicitly set to 0. + // +listType=map + // +listMapKey=topologyKey + Resources []ResourceSpec `json:"resources,omitempty"` + + // Arguments specific to RequestedToCapacityRatio strategy. + RequestedToCapacityRatio *RequestedToCapacityRatioParam `json:"requestedToCapacityRatio,omitempty"` +} + +// RequestedToCapacityRatioParam define RequestedToCapacityRatio parameters +type RequestedToCapacityRatioParam struct { + // Shape is a list of points defining the scoring function shape. + // +listType=atomic + Shape []UtilizationShapePoint `json:"shape,omitempty"` +} diff --git a/vendor/k8s.io/kube-scheduler/config/v1/zz_generated.deepcopy.go b/vendor/k8s.io/kube-scheduler/config/v1/zz_generated.deepcopy.go new file mode 100644 index 000000000..1203cdd3b --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/config/v1/zz_generated.deepcopy.go @@ -0,0 +1,609 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + corev1 "k8s.io/api/core/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DefaultPreemptionArgs) DeepCopyInto(out *DefaultPreemptionArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.MinCandidateNodesPercentage != nil { + in, out := &in.MinCandidateNodesPercentage, &out.MinCandidateNodesPercentage + *out = new(int32) + **out = **in + } + if in.MinCandidateNodesAbsolute != nil { + in, out := &in.MinCandidateNodesAbsolute, &out.MinCandidateNodesAbsolute + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DefaultPreemptionArgs. +func (in *DefaultPreemptionArgs) DeepCopy() *DefaultPreemptionArgs { + if in == nil { + return nil + } + out := new(DefaultPreemptionArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DefaultPreemptionArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Extender) DeepCopyInto(out *Extender) { + *out = *in + if in.TLSConfig != nil { + in, out := &in.TLSConfig, &out.TLSConfig + *out = new(ExtenderTLSConfig) + (*in).DeepCopyInto(*out) + } + out.HTTPTimeout = in.HTTPTimeout + if in.ManagedResources != nil { + in, out := &in.ManagedResources, &out.ManagedResources + *out = make([]ExtenderManagedResource, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Extender. +func (in *Extender) DeepCopy() *Extender { + if in == nil { + return nil + } + out := new(Extender) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExtenderManagedResource) DeepCopyInto(out *ExtenderManagedResource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderManagedResource. +func (in *ExtenderManagedResource) DeepCopy() *ExtenderManagedResource { + if in == nil { + return nil + } + out := new(ExtenderManagedResource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExtenderTLSConfig) DeepCopyInto(out *ExtenderTLSConfig) { + *out = *in + if in.CertData != nil { + in, out := &in.CertData, &out.CertData + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.KeyData != nil { + in, out := &in.KeyData, &out.KeyData + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.CAData != nil { + in, out := &in.CAData, &out.CAData + *out = make([]byte, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderTLSConfig. +func (in *ExtenderTLSConfig) DeepCopy() *ExtenderTLSConfig { + if in == nil { + return nil + } + out := new(ExtenderTLSConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InterPodAffinityArgs) DeepCopyInto(out *InterPodAffinityArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.HardPodAffinityWeight != nil { + in, out := &in.HardPodAffinityWeight, &out.HardPodAffinityWeight + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InterPodAffinityArgs. +func (in *InterPodAffinityArgs) DeepCopy() *InterPodAffinityArgs { + if in == nil { + return nil + } + out := new(InterPodAffinityArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *InterPodAffinityArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubeSchedulerConfiguration) DeepCopyInto(out *KubeSchedulerConfiguration) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.Parallelism != nil { + in, out := &in.Parallelism, &out.Parallelism + *out = new(int32) + **out = **in + } + in.LeaderElection.DeepCopyInto(&out.LeaderElection) + out.ClientConnection = in.ClientConnection + in.DebuggingConfiguration.DeepCopyInto(&out.DebuggingConfiguration) + if in.PercentageOfNodesToScore != nil { + in, out := &in.PercentageOfNodesToScore, &out.PercentageOfNodesToScore + *out = new(int32) + **out = **in + } + if in.PodInitialBackoffSeconds != nil { + in, out := &in.PodInitialBackoffSeconds, &out.PodInitialBackoffSeconds + *out = new(int64) + **out = **in + } + if in.PodMaxBackoffSeconds != nil { + in, out := &in.PodMaxBackoffSeconds, &out.PodMaxBackoffSeconds + *out = new(int64) + **out = **in + } + if in.Profiles != nil { + in, out := &in.Profiles, &out.Profiles + *out = make([]KubeSchedulerProfile, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Extenders != nil { + in, out := &in.Extenders, &out.Extenders + *out = make([]Extender, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeSchedulerConfiguration. +func (in *KubeSchedulerConfiguration) DeepCopy() *KubeSchedulerConfiguration { + if in == nil { + return nil + } + out := new(KubeSchedulerConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KubeSchedulerConfiguration) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubeSchedulerProfile) DeepCopyInto(out *KubeSchedulerProfile) { + *out = *in + if in.SchedulerName != nil { + in, out := &in.SchedulerName, &out.SchedulerName + *out = new(string) + **out = **in + } + if in.PercentageOfNodesToScore != nil { + in, out := &in.PercentageOfNodesToScore, &out.PercentageOfNodesToScore + *out = new(int32) + **out = **in + } + if in.Plugins != nil { + in, out := &in.Plugins, &out.Plugins + *out = new(Plugins) + (*in).DeepCopyInto(*out) + } + if in.PluginConfig != nil { + in, out := &in.PluginConfig, &out.PluginConfig + *out = make([]PluginConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeSchedulerProfile. +func (in *KubeSchedulerProfile) DeepCopy() *KubeSchedulerProfile { + if in == nil { + return nil + } + out := new(KubeSchedulerProfile) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeAffinityArgs) DeepCopyInto(out *NodeAffinityArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.AddedAffinity != nil { + in, out := &in.AddedAffinity, &out.AddedAffinity + *out = new(corev1.NodeAffinity) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeAffinityArgs. +func (in *NodeAffinityArgs) DeepCopy() *NodeAffinityArgs { + if in == nil { + return nil + } + out := new(NodeAffinityArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodeAffinityArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeResourcesBalancedAllocationArgs) DeepCopyInto(out *NodeResourcesBalancedAllocationArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make([]ResourceSpec, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeResourcesBalancedAllocationArgs. +func (in *NodeResourcesBalancedAllocationArgs) DeepCopy() *NodeResourcesBalancedAllocationArgs { + if in == nil { + return nil + } + out := new(NodeResourcesBalancedAllocationArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodeResourcesBalancedAllocationArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeResourcesFitArgs) DeepCopyInto(out *NodeResourcesFitArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.IgnoredResources != nil { + in, out := &in.IgnoredResources, &out.IgnoredResources + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.IgnoredResourceGroups != nil { + in, out := &in.IgnoredResourceGroups, &out.IgnoredResourceGroups + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.ScoringStrategy != nil { + in, out := &in.ScoringStrategy, &out.ScoringStrategy + *out = new(ScoringStrategy) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeResourcesFitArgs. +func (in *NodeResourcesFitArgs) DeepCopy() *NodeResourcesFitArgs { + if in == nil { + return nil + } + out := new(NodeResourcesFitArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodeResourcesFitArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Plugin) DeepCopyInto(out *Plugin) { + *out = *in + if in.Weight != nil { + in, out := &in.Weight, &out.Weight + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Plugin. +func (in *Plugin) DeepCopy() *Plugin { + if in == nil { + return nil + } + out := new(Plugin) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginConfig) DeepCopyInto(out *PluginConfig) { + *out = *in + in.Args.DeepCopyInto(&out.Args) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginConfig. +func (in *PluginConfig) DeepCopy() *PluginConfig { + if in == nil { + return nil + } + out := new(PluginConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginSet) DeepCopyInto(out *PluginSet) { + *out = *in + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = make([]Plugin, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Disabled != nil { + in, out := &in.Disabled, &out.Disabled + *out = make([]Plugin, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginSet. +func (in *PluginSet) DeepCopy() *PluginSet { + if in == nil { + return nil + } + out := new(PluginSet) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Plugins) DeepCopyInto(out *Plugins) { + *out = *in + in.PreEnqueue.DeepCopyInto(&out.PreEnqueue) + in.QueueSort.DeepCopyInto(&out.QueueSort) + in.PreFilter.DeepCopyInto(&out.PreFilter) + in.Filter.DeepCopyInto(&out.Filter) + in.PostFilter.DeepCopyInto(&out.PostFilter) + in.PreScore.DeepCopyInto(&out.PreScore) + in.Score.DeepCopyInto(&out.Score) + in.Reserve.DeepCopyInto(&out.Reserve) + in.Permit.DeepCopyInto(&out.Permit) + in.PreBind.DeepCopyInto(&out.PreBind) + in.Bind.DeepCopyInto(&out.Bind) + in.PostBind.DeepCopyInto(&out.PostBind) + in.MultiPoint.DeepCopyInto(&out.MultiPoint) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Plugins. +func (in *Plugins) DeepCopy() *Plugins { + if in == nil { + return nil + } + out := new(Plugins) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodTopologySpreadArgs) DeepCopyInto(out *PodTopologySpreadArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.DefaultConstraints != nil { + in, out := &in.DefaultConstraints, &out.DefaultConstraints + *out = make([]corev1.TopologySpreadConstraint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodTopologySpreadArgs. +func (in *PodTopologySpreadArgs) DeepCopy() *PodTopologySpreadArgs { + if in == nil { + return nil + } + out := new(PodTopologySpreadArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PodTopologySpreadArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RequestedToCapacityRatioParam) DeepCopyInto(out *RequestedToCapacityRatioParam) { + *out = *in + if in.Shape != nil { + in, out := &in.Shape, &out.Shape + *out = make([]UtilizationShapePoint, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RequestedToCapacityRatioParam. +func (in *RequestedToCapacityRatioParam) DeepCopy() *RequestedToCapacityRatioParam { + if in == nil { + return nil + } + out := new(RequestedToCapacityRatioParam) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceSpec) DeepCopyInto(out *ResourceSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceSpec. +func (in *ResourceSpec) DeepCopy() *ResourceSpec { + if in == nil { + return nil + } + out := new(ResourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ScoringStrategy) DeepCopyInto(out *ScoringStrategy) { + *out = *in + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make([]ResourceSpec, len(*in)) + copy(*out, *in) + } + if in.RequestedToCapacityRatio != nil { + in, out := &in.RequestedToCapacityRatio, &out.RequestedToCapacityRatio + *out = new(RequestedToCapacityRatioParam) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScoringStrategy. +func (in *ScoringStrategy) DeepCopy() *ScoringStrategy { + if in == nil { + return nil + } + out := new(ScoringStrategy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UtilizationShapePoint) DeepCopyInto(out *UtilizationShapePoint) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UtilizationShapePoint. +func (in *UtilizationShapePoint) DeepCopy() *UtilizationShapePoint { + if in == nil { + return nil + } + out := new(UtilizationShapePoint) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeBindingArgs) DeepCopyInto(out *VolumeBindingArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.BindTimeoutSeconds != nil { + in, out := &in.BindTimeoutSeconds, &out.BindTimeoutSeconds + *out = new(int64) + **out = **in + } + if in.Shape != nil { + in, out := &in.Shape, &out.Shape + *out = make([]UtilizationShapePoint, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeBindingArgs. +func (in *VolumeBindingArgs) DeepCopy() *VolumeBindingArgs { + if in == nil { + return nil + } + out := new(VolumeBindingArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VolumeBindingArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} diff --git a/vendor/k8s.io/kube-scheduler/config/v1beta2/doc.go b/vendor/k8s.io/kube-scheduler/config/v1beta2/doc.go new file mode 100644 index 000000000..c9f5f62ed --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/config/v1beta2/doc.go @@ -0,0 +1,21 @@ +/* +Copyright 2021 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. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:openapi-gen=true +// +groupName=kubescheduler.config.k8s.io + +package v1beta2 // import "k8s.io/kube-scheduler/config/v1beta2" diff --git a/vendor/k8s.io/kube-scheduler/config/v1beta2/register.go b/vendor/k8s.io/kube-scheduler/config/v1beta2/register.go new file mode 100644 index 000000000..59fc014a9 --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/config/v1beta2/register.go @@ -0,0 +1,50 @@ +/* +Copyright 2021 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 v1beta2 + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// GroupName is the group name used in this package +const GroupName = "kubescheduler.config.k8s.io" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1beta2"} + +var ( + // SchemeBuilder is the scheme builder with scheme init functions to run for this API package + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + // AddToScheme is a global function that registers this API group & version to a scheme + AddToScheme = SchemeBuilder.AddToScheme +) + +// addKnownTypes registers known types to the given scheme +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &KubeSchedulerConfiguration{}, + &DefaultPreemptionArgs{}, + &InterPodAffinityArgs{}, + &NodeResourcesBalancedAllocationArgs{}, + &NodeResourcesFitArgs{}, + &PodTopologySpreadArgs{}, + &VolumeBindingArgs{}, + &NodeAffinityArgs{}, + ) + return nil +} diff --git a/vendor/k8s.io/kube-scheduler/config/v1beta2/types.go b/vendor/k8s.io/kube-scheduler/config/v1beta2/types.go new file mode 100644 index 000000000..0e47967ad --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/config/v1beta2/types.go @@ -0,0 +1,369 @@ +/* +Copyright 2021 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 v1beta2 + +import ( + "bytes" + "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + componentbaseconfigv1alpha1 "k8s.io/component-base/config/v1alpha1" + "sigs.k8s.io/yaml" +) + +const ( + // SchedulerDefaultLockObjectNamespace defines default scheduler lock object namespace ("kube-system") + SchedulerDefaultLockObjectNamespace string = metav1.NamespaceSystem + + // SchedulerDefaultLockObjectName defines default scheduler lock object name ("kube-scheduler") + SchedulerDefaultLockObjectName = "kube-scheduler" + + // SchedulerDefaultProviderName defines the default provider names + SchedulerDefaultProviderName = "DefaultProvider" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// KubeSchedulerConfiguration configures a scheduler +type KubeSchedulerConfiguration struct { + metav1.TypeMeta `json:",inline"` + + // Parallelism defines the amount of parallelism in algorithms for scheduling a Pods. Must be greater than 0. Defaults to 16 + Parallelism *int32 `json:"parallelism,omitempty"` + + // LeaderElection defines the configuration of leader election client. + LeaderElection componentbaseconfigv1alpha1.LeaderElectionConfiguration `json:"leaderElection"` + + // ClientConnection specifies the kubeconfig file and client connection + // settings for the proxy server to use when communicating with the apiserver. + ClientConnection componentbaseconfigv1alpha1.ClientConnectionConfiguration `json:"clientConnection"` + + // Note: Both HealthzBindAddress and MetricsBindAddress fields are deprecated. + // Only empty address or port 0 is allowed. Anything else will fail validation. + // HealthzBindAddress is the IP address and port for the health check server to serve on. + HealthzBindAddress *string `json:"healthzBindAddress,omitempty"` + // MetricsBindAddress is the IP address and port for the metrics server to serve on. + MetricsBindAddress *string `json:"metricsBindAddress,omitempty"` + + // DebuggingConfiguration holds configuration for Debugging related features + // TODO: We might wanna make this a substruct like Debugging componentbaseconfigv1alpha1.DebuggingConfiguration + componentbaseconfigv1alpha1.DebuggingConfiguration `json:",inline"` + + // PercentageOfNodesToScore is the percentage of all nodes that once found feasible + // for running a pod, the scheduler stops its search for more feasible nodes in + // the cluster. This helps improve scheduler's performance. Scheduler always tries to find + // at least "minFeasibleNodesToFind" feasible nodes no matter what the value of this flag is. + // Example: if the cluster size is 500 nodes and the value of this flag is 30, + // then scheduler stops finding further feasible nodes once it finds 150 feasible ones. + // When the value is 0, default percentage (5%--50% based on the size of the cluster) of the + // nodes will be scored. + PercentageOfNodesToScore *int32 `json:"percentageOfNodesToScore,omitempty"` + + // PodInitialBackoffSeconds is the initial backoff for unschedulable pods. + // If specified, it must be greater than 0. If this value is null, the default value (1s) + // will be used. + PodInitialBackoffSeconds *int64 `json:"podInitialBackoffSeconds,omitempty"` + + // PodMaxBackoffSeconds is the max backoff for unschedulable pods. + // If specified, it must be greater than podInitialBackoffSeconds. If this value is null, + // the default value (10s) will be used. + PodMaxBackoffSeconds *int64 `json:"podMaxBackoffSeconds,omitempty"` + + // Profiles are scheduling profiles that kube-scheduler supports. Pods can + // choose to be scheduled under a particular profile by setting its associated + // scheduler name. Pods that don't specify any scheduler name are scheduled + // with the "default-scheduler" profile, if present here. + // +listType=map + // +listMapKey=schedulerName + Profiles []KubeSchedulerProfile `json:"profiles,omitempty"` + + // Extenders are the list of scheduler extenders, each holding the values of how to communicate + // with the extender. These extenders are shared by all scheduler profiles. + // +listType=set + Extenders []Extender `json:"extenders,omitempty"` +} + +// DecodeNestedObjects decodes plugin args for known types. +func (c *KubeSchedulerConfiguration) DecodeNestedObjects(d runtime.Decoder) error { + var strictDecodingErrs []error + for i := range c.Profiles { + prof := &c.Profiles[i] + for j := range prof.PluginConfig { + err := prof.PluginConfig[j].decodeNestedObjects(d) + if err != nil { + decodingErr := fmt.Errorf("decoding .profiles[%d].pluginConfig[%d]: %w", i, j, err) + if runtime.IsStrictDecodingError(err) { + strictDecodingErrs = append(strictDecodingErrs, decodingErr) + } else { + return decodingErr + } + } + } + } + if len(strictDecodingErrs) > 0 { + return runtime.NewStrictDecodingError(strictDecodingErrs) + } + return nil +} + +// EncodeNestedObjects encodes plugin args. +func (c *KubeSchedulerConfiguration) EncodeNestedObjects(e runtime.Encoder) error { + for i := range c.Profiles { + prof := &c.Profiles[i] + for j := range prof.PluginConfig { + err := prof.PluginConfig[j].encodeNestedObjects(e) + if err != nil { + return fmt.Errorf("encoding .profiles[%d].pluginConfig[%d]: %w", i, j, err) + } + } + } + return nil +} + +// KubeSchedulerProfile is a scheduling profile. +type KubeSchedulerProfile struct { + // SchedulerName is the name of the scheduler associated to this profile. + // If SchedulerName matches with the pod's "spec.schedulerName", then the pod + // is scheduled with this profile. + SchedulerName *string `json:"schedulerName,omitempty"` + + // Plugins specify the set of plugins that should be enabled or disabled. + // Enabled plugins are the ones that should be enabled in addition to the + // default plugins. Disabled plugins are any of the default plugins that + // should be disabled. + // When no enabled or disabled plugin is specified for an extension point, + // default plugins for that extension point will be used if there is any. + // If a QueueSort plugin is specified, the same QueueSort Plugin and + // PluginConfig must be specified for all profiles. + Plugins *Plugins `json:"plugins,omitempty"` + + // PluginConfig is an optional set of custom plugin arguments for each plugin. + // Omitting config args for a plugin is equivalent to using the default config + // for that plugin. + // +listType=map + // +listMapKey=name + PluginConfig []PluginConfig `json:"pluginConfig,omitempty"` +} + +// Plugins include multiple extension points. When specified, the list of plugins for +// a particular extension point are the only ones enabled. If an extension point is +// omitted from the config, then the default set of plugins is used for that extension point. +// Enabled plugins are called in the order specified here, after default plugins. If they need to +// be invoked before default plugins, default plugins must be disabled and re-enabled here in desired order. +type Plugins struct { + // PreEnqueue is a list of plugins that should be invoked before adding pods to the scheduling queue. + PreEnqueue PluginSet `json:"preEnqueue,omitempty"` + + // QueueSort is a list of plugins that should be invoked when sorting pods in the scheduling queue. + QueueSort PluginSet `json:"queueSort,omitempty"` + + // PreFilter is a list of plugins that should be invoked at "PreFilter" extension point of the scheduling framework. + PreFilter PluginSet `json:"preFilter,omitempty"` + + // Filter is a list of plugins that should be invoked when filtering out nodes that cannot run the Pod. + Filter PluginSet `json:"filter,omitempty"` + + // PostFilter is a list of plugins that are invoked after filtering phase, but only when no feasible nodes were found for the pod. + PostFilter PluginSet `json:"postFilter,omitempty"` + + // PreScore is a list of plugins that are invoked before scoring. + PreScore PluginSet `json:"preScore,omitempty"` + + // Score is a list of plugins that should be invoked when ranking nodes that have passed the filtering phase. + Score PluginSet `json:"score,omitempty"` + + // Reserve is a list of plugins invoked when reserving/unreserving resources + // after a node is assigned to run the pod. + Reserve PluginSet `json:"reserve,omitempty"` + + // Permit is a list of plugins that control binding of a Pod. These plugins can prevent or delay binding of a Pod. + Permit PluginSet `json:"permit,omitempty"` + + // PreBind is a list of plugins that should be invoked before a pod is bound. + PreBind PluginSet `json:"preBind,omitempty"` + + // Bind is a list of plugins that should be invoked at "Bind" extension point of the scheduling framework. + // The scheduler call these plugins in order. Scheduler skips the rest of these plugins as soon as one returns success. + Bind PluginSet `json:"bind,omitempty"` + + // PostBind is a list of plugins that should be invoked after a pod is successfully bound. + PostBind PluginSet `json:"postBind,omitempty"` + + // MultiPoint is a simplified config section to enable plugins for all valid extension points. + MultiPoint PluginSet `json:"multiPoint,omitempty"` +} + +// PluginSet specifies enabled and disabled plugins for an extension point. +// If an array is empty, missing, or nil, default plugins at that extension point will be used. +type PluginSet struct { + // Enabled specifies plugins that should be enabled in addition to default plugins. + // If the default plugin is also configured in the scheduler config file, the weight of plugin will + // be overridden accordingly. + // These are called after default plugins and in the same order specified here. + // +listType=atomic + Enabled []Plugin `json:"enabled,omitempty"` + // Disabled specifies default plugins that should be disabled. + // When all default plugins need to be disabled, an array containing only one "*" should be provided. + // +listType=map + // +listMapKey=name + Disabled []Plugin `json:"disabled,omitempty"` +} + +// Plugin specifies a plugin name and its weight when applicable. Weight is used only for Score plugins. +type Plugin struct { + // Name defines the name of plugin + Name string `json:"name"` + // Weight defines the weight of plugin, only used for Score plugins. + Weight *int32 `json:"weight,omitempty"` +} + +// PluginConfig specifies arguments that should be passed to a plugin at the time of initialization. +// A plugin that is invoked at multiple extension points is initialized once. Args can have arbitrary structure. +// It is up to the plugin to process these Args. +type PluginConfig struct { + // Name defines the name of plugin being configured + Name string `json:"name"` + // Args defines the arguments passed to the plugins at the time of initialization. Args can have arbitrary structure. + Args runtime.RawExtension `json:"args,omitempty"` +} + +func (c *PluginConfig) decodeNestedObjects(d runtime.Decoder) error { + gvk := SchemeGroupVersion.WithKind(c.Name + "Args") + // dry-run to detect and skip out-of-tree plugin args. + if _, _, err := d.Decode(nil, &gvk, nil); runtime.IsNotRegisteredError(err) { + return nil + } + + var strictDecodingErr error + obj, parsedGvk, err := d.Decode(c.Args.Raw, &gvk, nil) + if err != nil { + decodingArgsErr := fmt.Errorf("decoding args for plugin %s: %w", c.Name, err) + if obj != nil && runtime.IsStrictDecodingError(err) { + strictDecodingErr = runtime.NewStrictDecodingError([]error{decodingArgsErr}) + } else { + return decodingArgsErr + } + } + if parsedGvk.GroupKind() != gvk.GroupKind() { + return fmt.Errorf("args for plugin %s were not of type %s, got %s", c.Name, gvk.GroupKind(), parsedGvk.GroupKind()) + } + c.Args.Object = obj + return strictDecodingErr +} + +func (c *PluginConfig) encodeNestedObjects(e runtime.Encoder) error { + if c.Args.Object == nil { + return nil + } + var buf bytes.Buffer + err := e.Encode(c.Args.Object, &buf) + if err != nil { + return err + } + // The encoder might be a YAML encoder, but the parent encoder expects + // JSON output, so we convert YAML back to JSON. + // This is a no-op if produces JSON. + json, err := yaml.YAMLToJSON(buf.Bytes()) + if err != nil { + return err + } + c.Args.Raw = json + return nil +} + +// Extender holds the parameters used to communicate with the extender. If a verb is unspecified/empty, +// it is assumed that the extender chose not to provide that extension. +type Extender struct { + // URLPrefix at which the extender is available + URLPrefix string `json:"urlPrefix"` + // Verb for the filter call, empty if not supported. This verb is appended to the URLPrefix when issuing the filter call to extender. + FilterVerb string `json:"filterVerb,omitempty"` + // Verb for the preempt call, empty if not supported. This verb is appended to the URLPrefix when issuing the preempt call to extender. + PreemptVerb string `json:"preemptVerb,omitempty"` + // Verb for the prioritize call, empty if not supported. This verb is appended to the URLPrefix when issuing the prioritize call to extender. + PrioritizeVerb string `json:"prioritizeVerb,omitempty"` + // The numeric multiplier for the node scores that the prioritize call generates. + // The weight should be a positive integer + Weight int64 `json:"weight,omitempty"` + // Verb for the bind call, empty if not supported. This verb is appended to the URLPrefix when issuing the bind call to extender. + // If this method is implemented by the extender, it is the extender's responsibility to bind the pod to apiserver. Only one extender + // can implement this function. + BindVerb string `json:"bindVerb,omitempty"` + // EnableHTTPS specifies whether https should be used to communicate with the extender + EnableHTTPS bool `json:"enableHTTPS,omitempty"` + // TLSConfig specifies the transport layer security config + TLSConfig *ExtenderTLSConfig `json:"tlsConfig,omitempty"` + // HTTPTimeout specifies the timeout duration for a call to the extender. Filter timeout fails the scheduling of the pod. Prioritize + // timeout is ignored, k8s/other extenders priorities are used to select the node. + HTTPTimeout metav1.Duration `json:"httpTimeout,omitempty"` + // NodeCacheCapable specifies that the extender is capable of caching node information, + // so the scheduler should only send minimal information about the eligible nodes + // assuming that the extender already cached full details of all nodes in the cluster + NodeCacheCapable bool `json:"nodeCacheCapable,omitempty"` + // ManagedResources is a list of extended resources that are managed by + // this extender. + // - A pod will be sent to the extender on the Filter, Prioritize and Bind + // (if the extender is the binder) phases iff the pod requests at least + // one of the extended resources in this list. If empty or unspecified, + // all pods will be sent to this extender. + // - If IgnoredByScheduler is set to true for a resource, kube-scheduler + // will skip checking the resource in predicates. + // +optional + // +listType=atomic + ManagedResources []ExtenderManagedResource `json:"managedResources,omitempty"` + // Ignorable specifies if the extender is ignorable, i.e. scheduling should not + // fail when the extender returns an error or is not reachable. + Ignorable bool `json:"ignorable,omitempty"` +} + +// ExtenderManagedResource describes the arguments of extended resources +// managed by an extender. +type ExtenderManagedResource struct { + // Name is the extended resource name. + Name string `json:"name"` + // IgnoredByScheduler indicates whether kube-scheduler should ignore this + // resource when applying predicates. + IgnoredByScheduler bool `json:"ignoredByScheduler,omitempty"` +} + +// ExtenderTLSConfig contains settings to enable TLS with extender +type ExtenderTLSConfig struct { + // Server should be accessed without verifying the TLS certificate. For testing only. + Insecure bool `json:"insecure,omitempty"` + // ServerName is passed to the server for SNI and is used in the client to check server + // certificates against. If ServerName is empty, the hostname used to contact the + // server is used. + ServerName string `json:"serverName,omitempty"` + + // Server requires TLS client certificate authentication + CertFile string `json:"certFile,omitempty"` + // Server requires TLS client certificate authentication + KeyFile string `json:"keyFile,omitempty"` + // Trusted root certificates for server + CAFile string `json:"caFile,omitempty"` + + // CertData holds PEM-encoded bytes (typically read from a client certificate file). + // CertData takes precedence over CertFile + CertData []byte `json:"certData,omitempty"` + // KeyData holds PEM-encoded bytes (typically read from a client certificate key file). + // KeyData takes precedence over KeyFile + KeyData []byte `json:"keyData,omitempty"` + // CAData holds PEM-encoded bytes (typically read from a root certificates bundle). + // CAData takes precedence over CAFile + CAData []byte `json:"caData,omitempty"` +} diff --git a/vendor/k8s.io/kube-scheduler/config/v1beta2/types_pluginargs.go b/vendor/k8s.io/kube-scheduler/config/v1beta2/types_pluginargs.go new file mode 100644 index 000000000..3ab964f42 --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/config/v1beta2/types_pluginargs.go @@ -0,0 +1,225 @@ +/* +Copyright 2021 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 v1beta2 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// DefaultPreemptionArgs holds arguments used to configure the +// DefaultPreemption plugin. +type DefaultPreemptionArgs struct { + metav1.TypeMeta `json:",inline"` + + // MinCandidateNodesPercentage is the minimum number of candidates to + // shortlist when dry running preemption as a percentage of number of nodes. + // Must be in the range [0, 100]. Defaults to 10% of the cluster size if + // unspecified. + MinCandidateNodesPercentage *int32 `json:"minCandidateNodesPercentage,omitempty"` + // MinCandidateNodesAbsolute is the absolute minimum number of candidates to + // shortlist. The likely number of candidates enumerated for dry running + // preemption is given by the formula: + // numCandidates = max(numNodes * minCandidateNodesPercentage, minCandidateNodesAbsolute) + // We say "likely" because there are other factors such as PDB violations + // that play a role in the number of candidates shortlisted. Must be at least + // 0 nodes. Defaults to 100 nodes if unspecified. + MinCandidateNodesAbsolute *int32 `json:"minCandidateNodesAbsolute,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// InterPodAffinityArgs holds arguments used to configure the InterPodAffinity plugin. +type InterPodAffinityArgs struct { + metav1.TypeMeta `json:",inline"` + + // HardPodAffinityWeight is the scoring weight for existing pods with a + // matching hard affinity to the incoming pod. + HardPodAffinityWeight *int32 `json:"hardPodAffinityWeight,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// NodeResourcesFitArgs holds arguments used to configure the NodeResourcesFit plugin. +type NodeResourcesFitArgs struct { + metav1.TypeMeta `json:",inline"` + + // IgnoredResources is the list of resources that NodeResources fit filter + // should ignore. This doesn't apply to scoring. + // +listType=atomic + IgnoredResources []string `json:"ignoredResources,omitempty"` + // IgnoredResourceGroups defines the list of resource groups that NodeResources fit filter should ignore. + // e.g. if group is ["example.com"], it will ignore all resource names that begin + // with "example.com", such as "example.com/aaa" and "example.com/bbb". + // A resource group name can't contain '/'. This doesn't apply to scoring. + // +listType=atomic + IgnoredResourceGroups []string `json:"ignoredResourceGroups,omitempty"` + + // ScoringStrategy selects the node resource scoring strategy. + // The default strategy is LeastAllocated with an equal "cpu" and "memory" weight. + ScoringStrategy *ScoringStrategy `json:"scoringStrategy,omitempty"` +} + +// PodTopologySpreadConstraintsDefaulting defines how to set default constraints +// for the PodTopologySpread plugin. +type PodTopologySpreadConstraintsDefaulting string + +const ( + // SystemDefaulting instructs to use the kubernetes defined default. + SystemDefaulting PodTopologySpreadConstraintsDefaulting = "System" + // ListDefaulting instructs to use the config provided default. + ListDefaulting PodTopologySpreadConstraintsDefaulting = "List" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// PodTopologySpreadArgs holds arguments used to configure the PodTopologySpread plugin. +type PodTopologySpreadArgs struct { + metav1.TypeMeta `json:",inline"` + + // DefaultConstraints defines topology spread constraints to be applied to + // Pods that don't define any in `pod.spec.topologySpreadConstraints`. + // `.defaultConstraints[*].labelSelectors` must be empty, as they are + // deduced from the Pod's membership to Services, ReplicationControllers, + // ReplicaSets or StatefulSets. + // When not empty, .defaultingType must be "List". + // +optional + // +listType=atomic + DefaultConstraints []corev1.TopologySpreadConstraint `json:"defaultConstraints,omitempty"` + + // DefaultingType determines how .defaultConstraints are deduced. Can be one + // of "System" or "List". + // + // - "System": Use kubernetes defined constraints that spread Pods among + // Nodes and Zones. + // - "List": Use constraints defined in .defaultConstraints. + // + // Defaults to "System". + // +optional + DefaultingType PodTopologySpreadConstraintsDefaulting `json:"defaultingType,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// NodeResourcesBalancedAllocationArgs holds arguments used to configure NodeResourcesBalancedAllocation plugin. +type NodeResourcesBalancedAllocationArgs struct { + metav1.TypeMeta `json:",inline"` + + // Resources to be managed, the default is "cpu" and "memory" if not specified. + // +listType=map + // +listMapKey=name + Resources []ResourceSpec `json:"resources,omitempty"` +} + +// UtilizationShapePoint represents single point of priority function shape. +type UtilizationShapePoint struct { + // Utilization (x axis). Valid values are 0 to 100. Fully utilized node maps to 100. + Utilization int32 `json:"utilization"` + // Score assigned to given utilization (y axis). Valid values are 0 to 10. + Score int32 `json:"score"` +} + +// ResourceSpec represents a single resource. +type ResourceSpec struct { + // Name of the resource. + Name string `json:"name"` + // Weight of the resource. + Weight int64 `json:"weight,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// VolumeBindingArgs holds arguments used to configure the VolumeBinding plugin. +type VolumeBindingArgs struct { + metav1.TypeMeta `json:",inline"` + + // BindTimeoutSeconds is the timeout in seconds in volume binding operation. + // Value must be non-negative integer. The value zero indicates no waiting. + // If this value is nil, the default value (600) will be used. + BindTimeoutSeconds *int64 `json:"bindTimeoutSeconds,omitempty"` + + // Shape specifies the points defining the score function shape, which is + // used to score nodes based on the utilization of statically provisioned + // PVs. The utilization is calculated by dividing the total requested + // storage of the pod by the total capacity of feasible PVs on each node. + // Each point contains utilization (ranges from 0 to 100) and its + // associated score (ranges from 0 to 10). You can turn the priority by + // specifying different scores for different utilization numbers. + // The default shape points are: + // 1) 0 for 0 utilization + // 2) 10 for 100 utilization + // All points must be sorted in increasing order by utilization. + // +featureGate=VolumeCapacityPriority + // +optional + // +listType=atomic + Shape []UtilizationShapePoint `json:"shape,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// NodeAffinityArgs holds arguments to configure the NodeAffinity plugin. +type NodeAffinityArgs struct { + metav1.TypeMeta `json:",inline"` + + // AddedAffinity is applied to all Pods additionally to the NodeAffinity + // specified in the PodSpec. That is, Nodes need to satisfy AddedAffinity + // AND .spec.NodeAffinity. AddedAffinity is empty by default (all Nodes + // match). + // When AddedAffinity is used, some Pods with affinity requirements that match + // a specific Node (such as Daemonset Pods) might remain unschedulable. + // +optional + AddedAffinity *corev1.NodeAffinity `json:"addedAffinity,omitempty"` +} + +// ScoringStrategyType the type of scoring strategy used in NodeResourcesFit plugin. +type ScoringStrategyType string + +const ( + // LeastAllocated strategy prioritizes nodes with least allocated resources. + LeastAllocated ScoringStrategyType = "LeastAllocated" + // MostAllocated strategy prioritizes nodes with most allocated resources. + MostAllocated ScoringStrategyType = "MostAllocated" + // RequestedToCapacityRatio strategy allows specifying a custom shape function + // to score nodes based on the request to capacity ratio. + RequestedToCapacityRatio ScoringStrategyType = "RequestedToCapacityRatio" +) + +// ScoringStrategy define ScoringStrategyType for node resource plugin +type ScoringStrategy struct { + // Type selects which strategy to run. + Type ScoringStrategyType `json:"type,omitempty"` + + // Resources to consider when scoring. + // The default resource set includes "cpu" and "memory" with an equal weight. + // Allowed weights go from 1 to 100. + // Weight defaults to 1 if not specified or explicitly set to 0. + // +listType=map + // +listMapKey=topologyKey + Resources []ResourceSpec `json:"resources,omitempty"` + + // Arguments specific to RequestedToCapacityRatio strategy. + RequestedToCapacityRatio *RequestedToCapacityRatioParam `json:"requestedToCapacityRatio,omitempty"` +} + +// RequestedToCapacityRatioParam define RequestedToCapacityRatio parameters +type RequestedToCapacityRatioParam struct { + // Shape is a list of points defining the scoring function shape. + // +listType=atomic + Shape []UtilizationShapePoint `json:"shape,omitempty"` +} diff --git a/vendor/k8s.io/kube-scheduler/config/v1beta2/zz_generated.deepcopy.go b/vendor/k8s.io/kube-scheduler/config/v1beta2/zz_generated.deepcopy.go new file mode 100644 index 000000000..7ffacf0f3 --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/config/v1beta2/zz_generated.deepcopy.go @@ -0,0 +1,614 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1beta2 + +import ( + v1 "k8s.io/api/core/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DefaultPreemptionArgs) DeepCopyInto(out *DefaultPreemptionArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.MinCandidateNodesPercentage != nil { + in, out := &in.MinCandidateNodesPercentage, &out.MinCandidateNodesPercentage + *out = new(int32) + **out = **in + } + if in.MinCandidateNodesAbsolute != nil { + in, out := &in.MinCandidateNodesAbsolute, &out.MinCandidateNodesAbsolute + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DefaultPreemptionArgs. +func (in *DefaultPreemptionArgs) DeepCopy() *DefaultPreemptionArgs { + if in == nil { + return nil + } + out := new(DefaultPreemptionArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DefaultPreemptionArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Extender) DeepCopyInto(out *Extender) { + *out = *in + if in.TLSConfig != nil { + in, out := &in.TLSConfig, &out.TLSConfig + *out = new(ExtenderTLSConfig) + (*in).DeepCopyInto(*out) + } + out.HTTPTimeout = in.HTTPTimeout + if in.ManagedResources != nil { + in, out := &in.ManagedResources, &out.ManagedResources + *out = make([]ExtenderManagedResource, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Extender. +func (in *Extender) DeepCopy() *Extender { + if in == nil { + return nil + } + out := new(Extender) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExtenderManagedResource) DeepCopyInto(out *ExtenderManagedResource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderManagedResource. +func (in *ExtenderManagedResource) DeepCopy() *ExtenderManagedResource { + if in == nil { + return nil + } + out := new(ExtenderManagedResource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExtenderTLSConfig) DeepCopyInto(out *ExtenderTLSConfig) { + *out = *in + if in.CertData != nil { + in, out := &in.CertData, &out.CertData + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.KeyData != nil { + in, out := &in.KeyData, &out.KeyData + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.CAData != nil { + in, out := &in.CAData, &out.CAData + *out = make([]byte, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderTLSConfig. +func (in *ExtenderTLSConfig) DeepCopy() *ExtenderTLSConfig { + if in == nil { + return nil + } + out := new(ExtenderTLSConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InterPodAffinityArgs) DeepCopyInto(out *InterPodAffinityArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.HardPodAffinityWeight != nil { + in, out := &in.HardPodAffinityWeight, &out.HardPodAffinityWeight + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InterPodAffinityArgs. +func (in *InterPodAffinityArgs) DeepCopy() *InterPodAffinityArgs { + if in == nil { + return nil + } + out := new(InterPodAffinityArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *InterPodAffinityArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubeSchedulerConfiguration) DeepCopyInto(out *KubeSchedulerConfiguration) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.Parallelism != nil { + in, out := &in.Parallelism, &out.Parallelism + *out = new(int32) + **out = **in + } + in.LeaderElection.DeepCopyInto(&out.LeaderElection) + out.ClientConnection = in.ClientConnection + if in.HealthzBindAddress != nil { + in, out := &in.HealthzBindAddress, &out.HealthzBindAddress + *out = new(string) + **out = **in + } + if in.MetricsBindAddress != nil { + in, out := &in.MetricsBindAddress, &out.MetricsBindAddress + *out = new(string) + **out = **in + } + in.DebuggingConfiguration.DeepCopyInto(&out.DebuggingConfiguration) + if in.PercentageOfNodesToScore != nil { + in, out := &in.PercentageOfNodesToScore, &out.PercentageOfNodesToScore + *out = new(int32) + **out = **in + } + if in.PodInitialBackoffSeconds != nil { + in, out := &in.PodInitialBackoffSeconds, &out.PodInitialBackoffSeconds + *out = new(int64) + **out = **in + } + if in.PodMaxBackoffSeconds != nil { + in, out := &in.PodMaxBackoffSeconds, &out.PodMaxBackoffSeconds + *out = new(int64) + **out = **in + } + if in.Profiles != nil { + in, out := &in.Profiles, &out.Profiles + *out = make([]KubeSchedulerProfile, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Extenders != nil { + in, out := &in.Extenders, &out.Extenders + *out = make([]Extender, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeSchedulerConfiguration. +func (in *KubeSchedulerConfiguration) DeepCopy() *KubeSchedulerConfiguration { + if in == nil { + return nil + } + out := new(KubeSchedulerConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KubeSchedulerConfiguration) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubeSchedulerProfile) DeepCopyInto(out *KubeSchedulerProfile) { + *out = *in + if in.SchedulerName != nil { + in, out := &in.SchedulerName, &out.SchedulerName + *out = new(string) + **out = **in + } + if in.Plugins != nil { + in, out := &in.Plugins, &out.Plugins + *out = new(Plugins) + (*in).DeepCopyInto(*out) + } + if in.PluginConfig != nil { + in, out := &in.PluginConfig, &out.PluginConfig + *out = make([]PluginConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeSchedulerProfile. +func (in *KubeSchedulerProfile) DeepCopy() *KubeSchedulerProfile { + if in == nil { + return nil + } + out := new(KubeSchedulerProfile) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeAffinityArgs) DeepCopyInto(out *NodeAffinityArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.AddedAffinity != nil { + in, out := &in.AddedAffinity, &out.AddedAffinity + *out = new(v1.NodeAffinity) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeAffinityArgs. +func (in *NodeAffinityArgs) DeepCopy() *NodeAffinityArgs { + if in == nil { + return nil + } + out := new(NodeAffinityArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodeAffinityArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeResourcesBalancedAllocationArgs) DeepCopyInto(out *NodeResourcesBalancedAllocationArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make([]ResourceSpec, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeResourcesBalancedAllocationArgs. +func (in *NodeResourcesBalancedAllocationArgs) DeepCopy() *NodeResourcesBalancedAllocationArgs { + if in == nil { + return nil + } + out := new(NodeResourcesBalancedAllocationArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodeResourcesBalancedAllocationArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeResourcesFitArgs) DeepCopyInto(out *NodeResourcesFitArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.IgnoredResources != nil { + in, out := &in.IgnoredResources, &out.IgnoredResources + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.IgnoredResourceGroups != nil { + in, out := &in.IgnoredResourceGroups, &out.IgnoredResourceGroups + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.ScoringStrategy != nil { + in, out := &in.ScoringStrategy, &out.ScoringStrategy + *out = new(ScoringStrategy) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeResourcesFitArgs. +func (in *NodeResourcesFitArgs) DeepCopy() *NodeResourcesFitArgs { + if in == nil { + return nil + } + out := new(NodeResourcesFitArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodeResourcesFitArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Plugin) DeepCopyInto(out *Plugin) { + *out = *in + if in.Weight != nil { + in, out := &in.Weight, &out.Weight + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Plugin. +func (in *Plugin) DeepCopy() *Plugin { + if in == nil { + return nil + } + out := new(Plugin) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginConfig) DeepCopyInto(out *PluginConfig) { + *out = *in + in.Args.DeepCopyInto(&out.Args) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginConfig. +func (in *PluginConfig) DeepCopy() *PluginConfig { + if in == nil { + return nil + } + out := new(PluginConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginSet) DeepCopyInto(out *PluginSet) { + *out = *in + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = make([]Plugin, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Disabled != nil { + in, out := &in.Disabled, &out.Disabled + *out = make([]Plugin, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginSet. +func (in *PluginSet) DeepCopy() *PluginSet { + if in == nil { + return nil + } + out := new(PluginSet) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Plugins) DeepCopyInto(out *Plugins) { + *out = *in + in.PreEnqueue.DeepCopyInto(&out.PreEnqueue) + in.QueueSort.DeepCopyInto(&out.QueueSort) + in.PreFilter.DeepCopyInto(&out.PreFilter) + in.Filter.DeepCopyInto(&out.Filter) + in.PostFilter.DeepCopyInto(&out.PostFilter) + in.PreScore.DeepCopyInto(&out.PreScore) + in.Score.DeepCopyInto(&out.Score) + in.Reserve.DeepCopyInto(&out.Reserve) + in.Permit.DeepCopyInto(&out.Permit) + in.PreBind.DeepCopyInto(&out.PreBind) + in.Bind.DeepCopyInto(&out.Bind) + in.PostBind.DeepCopyInto(&out.PostBind) + in.MultiPoint.DeepCopyInto(&out.MultiPoint) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Plugins. +func (in *Plugins) DeepCopy() *Plugins { + if in == nil { + return nil + } + out := new(Plugins) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodTopologySpreadArgs) DeepCopyInto(out *PodTopologySpreadArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.DefaultConstraints != nil { + in, out := &in.DefaultConstraints, &out.DefaultConstraints + *out = make([]v1.TopologySpreadConstraint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodTopologySpreadArgs. +func (in *PodTopologySpreadArgs) DeepCopy() *PodTopologySpreadArgs { + if in == nil { + return nil + } + out := new(PodTopologySpreadArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PodTopologySpreadArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RequestedToCapacityRatioParam) DeepCopyInto(out *RequestedToCapacityRatioParam) { + *out = *in + if in.Shape != nil { + in, out := &in.Shape, &out.Shape + *out = make([]UtilizationShapePoint, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RequestedToCapacityRatioParam. +func (in *RequestedToCapacityRatioParam) DeepCopy() *RequestedToCapacityRatioParam { + if in == nil { + return nil + } + out := new(RequestedToCapacityRatioParam) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceSpec) DeepCopyInto(out *ResourceSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceSpec. +func (in *ResourceSpec) DeepCopy() *ResourceSpec { + if in == nil { + return nil + } + out := new(ResourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ScoringStrategy) DeepCopyInto(out *ScoringStrategy) { + *out = *in + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make([]ResourceSpec, len(*in)) + copy(*out, *in) + } + if in.RequestedToCapacityRatio != nil { + in, out := &in.RequestedToCapacityRatio, &out.RequestedToCapacityRatio + *out = new(RequestedToCapacityRatioParam) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScoringStrategy. +func (in *ScoringStrategy) DeepCopy() *ScoringStrategy { + if in == nil { + return nil + } + out := new(ScoringStrategy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UtilizationShapePoint) DeepCopyInto(out *UtilizationShapePoint) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UtilizationShapePoint. +func (in *UtilizationShapePoint) DeepCopy() *UtilizationShapePoint { + if in == nil { + return nil + } + out := new(UtilizationShapePoint) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeBindingArgs) DeepCopyInto(out *VolumeBindingArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.BindTimeoutSeconds != nil { + in, out := &in.BindTimeoutSeconds, &out.BindTimeoutSeconds + *out = new(int64) + **out = **in + } + if in.Shape != nil { + in, out := &in.Shape, &out.Shape + *out = make([]UtilizationShapePoint, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeBindingArgs. +func (in *VolumeBindingArgs) DeepCopy() *VolumeBindingArgs { + if in == nil { + return nil + } + out := new(VolumeBindingArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VolumeBindingArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} diff --git a/vendor/k8s.io/kube-scheduler/config/v1beta3/doc.go b/vendor/k8s.io/kube-scheduler/config/v1beta3/doc.go new file mode 100644 index 000000000..c791874d6 --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/config/v1beta3/doc.go @@ -0,0 +1,21 @@ +/* +Copyright 2021 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. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:openapi-gen=true +// +groupName=kubescheduler.config.k8s.io + +package v1beta3 // import "k8s.io/kube-scheduler/config/v1beta3" diff --git a/vendor/k8s.io/kube-scheduler/config/v1beta3/register.go b/vendor/k8s.io/kube-scheduler/config/v1beta3/register.go new file mode 100644 index 000000000..768f107b4 --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/config/v1beta3/register.go @@ -0,0 +1,50 @@ +/* +Copyright 2021 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 v1beta3 + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// GroupName is the group name used in this package +const GroupName = "kubescheduler.config.k8s.io" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1beta3"} + +var ( + // SchemeBuilder is the scheme builder with scheme init functions to run for this API package + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + // AddToScheme is a global function that registers this API group & version to a scheme + AddToScheme = SchemeBuilder.AddToScheme +) + +// addKnownTypes registers known types to the given scheme +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &KubeSchedulerConfiguration{}, + &DefaultPreemptionArgs{}, + &InterPodAffinityArgs{}, + &NodeResourcesBalancedAllocationArgs{}, + &NodeResourcesFitArgs{}, + &PodTopologySpreadArgs{}, + &VolumeBindingArgs{}, + &NodeAffinityArgs{}, + ) + return nil +} diff --git a/vendor/k8s.io/kube-scheduler/config/v1beta3/types.go b/vendor/k8s.io/kube-scheduler/config/v1beta3/types.go new file mode 100644 index 000000000..45371c9d9 --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/config/v1beta3/types.go @@ -0,0 +1,377 @@ +/* +Copyright 2021 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 v1beta3 + +import ( + "bytes" + "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + componentbaseconfigv1alpha1 "k8s.io/component-base/config/v1alpha1" + "sigs.k8s.io/yaml" +) + +const ( + // SchedulerDefaultLockObjectNamespace defines default scheduler lock object namespace ("kube-system") + SchedulerDefaultLockObjectNamespace string = metav1.NamespaceSystem + + // SchedulerDefaultLockObjectName defines default scheduler lock object name ("kube-scheduler") + SchedulerDefaultLockObjectName = "kube-scheduler" + + // SchedulerDefaultProviderName defines the default provider names + SchedulerDefaultProviderName = "DefaultProvider" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// KubeSchedulerConfiguration configures a scheduler +type KubeSchedulerConfiguration struct { + metav1.TypeMeta `json:",inline"` + + // Parallelism defines the amount of parallelism in algorithms for scheduling a Pods. Must be greater than 0. Defaults to 16 + Parallelism *int32 `json:"parallelism,omitempty"` + + // LeaderElection defines the configuration of leader election client. + LeaderElection componentbaseconfigv1alpha1.LeaderElectionConfiguration `json:"leaderElection"` + + // ClientConnection specifies the kubeconfig file and client connection + // settings for the proxy server to use when communicating with the apiserver. + ClientConnection componentbaseconfigv1alpha1.ClientConnectionConfiguration `json:"clientConnection"` + + // DebuggingConfiguration holds configuration for Debugging related features + // TODO: We might wanna make this a substruct like Debugging componentbaseconfigv1alpha1.DebuggingConfiguration + componentbaseconfigv1alpha1.DebuggingConfiguration `json:",inline"` + + // PercentageOfNodesToScore is the percentage of all nodes that once found feasible + // for running a pod, the scheduler stops its search for more feasible nodes in + // the cluster. This helps improve scheduler's performance. Scheduler always tries to find + // at least "minFeasibleNodesToFind" feasible nodes no matter what the value of this flag is. + // Example: if the cluster size is 500 nodes and the value of this flag is 30, + // then scheduler stops finding further feasible nodes once it finds 150 feasible ones. + // When the value is 0, default percentage (5%--50% based on the size of the cluster) of the + // nodes will be scored. + PercentageOfNodesToScore *int32 `json:"percentageOfNodesToScore,omitempty"` + + // PodInitialBackoffSeconds is the initial backoff for unschedulable pods. + // If specified, it must be greater than 0. If this value is null, the default value (1s) + // will be used. + PodInitialBackoffSeconds *int64 `json:"podInitialBackoffSeconds,omitempty"` + + // PodMaxBackoffSeconds is the max backoff for unschedulable pods. + // If specified, it must be greater than podInitialBackoffSeconds. If this value is null, + // the default value (10s) will be used. + PodMaxBackoffSeconds *int64 `json:"podMaxBackoffSeconds,omitempty"` + + // Profiles are scheduling profiles that kube-scheduler supports. Pods can + // choose to be scheduled under a particular profile by setting its associated + // scheduler name. Pods that don't specify any scheduler name are scheduled + // with the "default-scheduler" profile, if present here. + // +listType=map + // +listMapKey=schedulerName + Profiles []KubeSchedulerProfile `json:"profiles,omitempty"` + + // Extenders are the list of scheduler extenders, each holding the values of how to communicate + // with the extender. These extenders are shared by all scheduler profiles. + // +listType=set + Extenders []Extender `json:"extenders,omitempty"` +} + +// DecodeNestedObjects decodes plugin args for known types. +func (c *KubeSchedulerConfiguration) DecodeNestedObjects(d runtime.Decoder) error { + var strictDecodingErrs []error + for i := range c.Profiles { + prof := &c.Profiles[i] + for j := range prof.PluginConfig { + err := prof.PluginConfig[j].decodeNestedObjects(d) + if err != nil { + decodingErr := fmt.Errorf("decoding .profiles[%d].pluginConfig[%d]: %w", i, j, err) + if runtime.IsStrictDecodingError(err) { + strictDecodingErrs = append(strictDecodingErrs, decodingErr) + } else { + return decodingErr + } + } + } + } + if len(strictDecodingErrs) > 0 { + return runtime.NewStrictDecodingError(strictDecodingErrs) + } + return nil +} + +// EncodeNestedObjects encodes plugin args. +func (c *KubeSchedulerConfiguration) EncodeNestedObjects(e runtime.Encoder) error { + for i := range c.Profiles { + prof := &c.Profiles[i] + for j := range prof.PluginConfig { + err := prof.PluginConfig[j].encodeNestedObjects(e) + if err != nil { + return fmt.Errorf("encoding .profiles[%d].pluginConfig[%d]: %w", i, j, err) + } + } + } + return nil +} + +// KubeSchedulerProfile is a scheduling profile. +type KubeSchedulerProfile struct { + // SchedulerName is the name of the scheduler associated to this profile. + // If SchedulerName matches with the pod's "spec.schedulerName", then the pod + // is scheduled with this profile. + SchedulerName *string `json:"schedulerName,omitempty"` + + // Plugins specify the set of plugins that should be enabled or disabled. + // Enabled plugins are the ones that should be enabled in addition to the + // default plugins. Disabled plugins are any of the default plugins that + // should be disabled. + // When no enabled or disabled plugin is specified for an extension point, + // default plugins for that extension point will be used if there is any. + // If a QueueSort plugin is specified, the same QueueSort Plugin and + // PluginConfig must be specified for all profiles. + Plugins *Plugins `json:"plugins,omitempty"` + + // PluginConfig is an optional set of custom plugin arguments for each plugin. + // Omitting config args for a plugin is equivalent to using the default config + // for that plugin. + // +listType=map + // +listMapKey=name + PluginConfig []PluginConfig `json:"pluginConfig,omitempty"` +} + +// Plugins include multiple extension points. When specified, the list of plugins for +// a particular extension point are the only ones enabled. If an extension point is +// omitted from the config, then the default set of plugins is used for that extension point. +// Enabled plugins are called in the order specified here, after default plugins. If they need to +// be invoked before default plugins, default plugins must be disabled and re-enabled here in desired order. +type Plugins struct { + // PreEnqueue is a list of plugins that should be invoked before adding pods to the scheduling queue. + PreEnqueue PluginSet `json:"preEnqueue,omitempty"` + + // QueueSort is a list of plugins that should be invoked when sorting pods in the scheduling queue. + QueueSort PluginSet `json:"queueSort,omitempty"` + + // PreFilter is a list of plugins that should be invoked at "PreFilter" extension point of the scheduling framework. + PreFilter PluginSet `json:"preFilter,omitempty"` + + // Filter is a list of plugins that should be invoked when filtering out nodes that cannot run the Pod. + Filter PluginSet `json:"filter,omitempty"` + + // PostFilter is a list of plugins that are invoked after filtering phase, but only when no feasible nodes were found for the pod. + PostFilter PluginSet `json:"postFilter,omitempty"` + + // PreScore is a list of plugins that are invoked before scoring. + PreScore PluginSet `json:"preScore,omitempty"` + + // Score is a list of plugins that should be invoked when ranking nodes that have passed the filtering phase. + Score PluginSet `json:"score,omitempty"` + + // Reserve is a list of plugins invoked when reserving/unreserving resources + // after a node is assigned to run the pod. + Reserve PluginSet `json:"reserve,omitempty"` + + // Permit is a list of plugins that control binding of a Pod. These plugins can prevent or delay binding of a Pod. + Permit PluginSet `json:"permit,omitempty"` + + // PreBind is a list of plugins that should be invoked before a pod is bound. + PreBind PluginSet `json:"preBind,omitempty"` + + // Bind is a list of plugins that should be invoked at "Bind" extension point of the scheduling framework. + // The scheduler call these plugins in order. Scheduler skips the rest of these plugins as soon as one returns success. + Bind PluginSet `json:"bind,omitempty"` + + // PostBind is a list of plugins that should be invoked after a pod is successfully bound. + PostBind PluginSet `json:"postBind,omitempty"` + + // MultiPoint is a simplified config section to enable plugins for all valid extension points. + // Plugins enabled through MultiPoint will automatically register for every individual extension + // point the plugin has implemented. Disabling a plugin through MultiPoint disables that behavior. + // The same is true for disabling "*" through MultiPoint (no default plugins will be automatically registered). + // Plugins can still be disabled through their individual extension points. + // + // In terms of precedence, plugin config follows this basic hierarchy + // 1. Specific extension points + // 2. Explicitly configured MultiPoint plugins + // 3. The set of default plugins, as MultiPoint plugins + // This implies that a higher precedence plugin will run first and overwrite any settings within MultiPoint. + // Explicitly user-configured plugins also take a higher precedence over default plugins. + // Within this hierarchy, an Enabled setting takes precedence over Disabled. For example, if a plugin is + // set in both `multiPoint.Enabled` and `multiPoint.Disabled`, the plugin will be enabled. Similarly, + // including `multiPoint.Disabled = '*'` and `multiPoint.Enabled = pluginA` will still register that specific + // plugin through MultiPoint. This follows the same behavior as all other extension point configurations. + MultiPoint PluginSet `json:"multiPoint,omitempty"` +} + +// PluginSet specifies enabled and disabled plugins for an extension point. +// If an array is empty, missing, or nil, default plugins at that extension point will be used. +type PluginSet struct { + // Enabled specifies plugins that should be enabled in addition to default plugins. + // If the default plugin is also configured in the scheduler config file, the weight of plugin will + // be overridden accordingly. + // These are called after default plugins and in the same order specified here. + // +listType=atomic + Enabled []Plugin `json:"enabled,omitempty"` + // Disabled specifies default plugins that should be disabled. + // When all default plugins need to be disabled, an array containing only one "*" should be provided. + // +listType=map + // +listMapKey=name + Disabled []Plugin `json:"disabled,omitempty"` +} + +// Plugin specifies a plugin name and its weight when applicable. Weight is used only for Score plugins. +type Plugin struct { + // Name defines the name of plugin + Name string `json:"name"` + // Weight defines the weight of plugin, only used for Score plugins. + Weight *int32 `json:"weight,omitempty"` +} + +// PluginConfig specifies arguments that should be passed to a plugin at the time of initialization. +// A plugin that is invoked at multiple extension points is initialized once. Args can have arbitrary structure. +// It is up to the plugin to process these Args. +type PluginConfig struct { + // Name defines the name of plugin being configured + Name string `json:"name"` + // Args defines the arguments passed to the plugins at the time of initialization. Args can have arbitrary structure. + Args runtime.RawExtension `json:"args,omitempty"` +} + +func (c *PluginConfig) decodeNestedObjects(d runtime.Decoder) error { + gvk := SchemeGroupVersion.WithKind(c.Name + "Args") + // dry-run to detect and skip out-of-tree plugin args. + if _, _, err := d.Decode(nil, &gvk, nil); runtime.IsNotRegisteredError(err) { + return nil + } + + var strictDecodingErr error + obj, parsedGvk, err := d.Decode(c.Args.Raw, &gvk, nil) + if err != nil { + decodingArgsErr := fmt.Errorf("decoding args for plugin %s: %w", c.Name, err) + if obj != nil && runtime.IsStrictDecodingError(err) { + strictDecodingErr = runtime.NewStrictDecodingError([]error{decodingArgsErr}) + } else { + return decodingArgsErr + } + } + if parsedGvk.GroupKind() != gvk.GroupKind() { + return fmt.Errorf("args for plugin %s were not of type %s, got %s", c.Name, gvk.GroupKind(), parsedGvk.GroupKind()) + } + c.Args.Object = obj + return strictDecodingErr +} + +func (c *PluginConfig) encodeNestedObjects(e runtime.Encoder) error { + if c.Args.Object == nil { + return nil + } + var buf bytes.Buffer + err := e.Encode(c.Args.Object, &buf) + if err != nil { + return err + } + // The encoder might be a YAML encoder, but the parent encoder expects + // JSON output, so we convert YAML back to JSON. + // This is a no-op if produces JSON. + json, err := yaml.YAMLToJSON(buf.Bytes()) + if err != nil { + return err + } + c.Args.Raw = json + return nil +} + +// Extender holds the parameters used to communicate with the extender. If a verb is unspecified/empty, +// it is assumed that the extender chose not to provide that extension. +type Extender struct { + // URLPrefix at which the extender is available + URLPrefix string `json:"urlPrefix"` + // Verb for the filter call, empty if not supported. This verb is appended to the URLPrefix when issuing the filter call to extender. + FilterVerb string `json:"filterVerb,omitempty"` + // Verb for the preempt call, empty if not supported. This verb is appended to the URLPrefix when issuing the preempt call to extender. + PreemptVerb string `json:"preemptVerb,omitempty"` + // Verb for the prioritize call, empty if not supported. This verb is appended to the URLPrefix when issuing the prioritize call to extender. + PrioritizeVerb string `json:"prioritizeVerb,omitempty"` + // The numeric multiplier for the node scores that the prioritize call generates. + // The weight should be a positive integer + Weight int64 `json:"weight,omitempty"` + // Verb for the bind call, empty if not supported. This verb is appended to the URLPrefix when issuing the bind call to extender. + // If this method is implemented by the extender, it is the extender's responsibility to bind the pod to apiserver. Only one extender + // can implement this function. + BindVerb string `json:"bindVerb,omitempty"` + // EnableHTTPS specifies whether https should be used to communicate with the extender + EnableHTTPS bool `json:"enableHTTPS,omitempty"` + // TLSConfig specifies the transport layer security config + TLSConfig *ExtenderTLSConfig `json:"tlsConfig,omitempty"` + // HTTPTimeout specifies the timeout duration for a call to the extender. Filter timeout fails the scheduling of the pod. Prioritize + // timeout is ignored, k8s/other extenders priorities are used to select the node. + HTTPTimeout metav1.Duration `json:"httpTimeout,omitempty"` + // NodeCacheCapable specifies that the extender is capable of caching node information, + // so the scheduler should only send minimal information about the eligible nodes + // assuming that the extender already cached full details of all nodes in the cluster + NodeCacheCapable bool `json:"nodeCacheCapable,omitempty"` + // ManagedResources is a list of extended resources that are managed by + // this extender. + // - A pod will be sent to the extender on the Filter, Prioritize and Bind + // (if the extender is the binder) phases iff the pod requests at least + // one of the extended resources in this list. If empty or unspecified, + // all pods will be sent to this extender. + // - If IgnoredByScheduler is set to true for a resource, kube-scheduler + // will skip checking the resource in predicates. + // +optional + // +listType=atomic + ManagedResources []ExtenderManagedResource `json:"managedResources,omitempty"` + // Ignorable specifies if the extender is ignorable, i.e. scheduling should not + // fail when the extender returns an error or is not reachable. + Ignorable bool `json:"ignorable,omitempty"` +} + +// ExtenderManagedResource describes the arguments of extended resources +// managed by an extender. +type ExtenderManagedResource struct { + // Name is the extended resource name. + Name string `json:"name"` + // IgnoredByScheduler indicates whether kube-scheduler should ignore this + // resource when applying predicates. + IgnoredByScheduler bool `json:"ignoredByScheduler,omitempty"` +} + +// ExtenderTLSConfig contains settings to enable TLS with extender +type ExtenderTLSConfig struct { + // Server should be accessed without verifying the TLS certificate. For testing only. + Insecure bool `json:"insecure,omitempty"` + // ServerName is passed to the server for SNI and is used in the client to check server + // certificates against. If ServerName is empty, the hostname used to contact the + // server is used. + ServerName string `json:"serverName,omitempty"` + + // Server requires TLS client certificate authentication + CertFile string `json:"certFile,omitempty"` + // Server requires TLS client certificate authentication + KeyFile string `json:"keyFile,omitempty"` + // Trusted root certificates for server + CAFile string `json:"caFile,omitempty"` + + // CertData holds PEM-encoded bytes (typically read from a client certificate file). + // CertData takes precedence over CertFile + CertData []byte `json:"certData,omitempty"` + // KeyData holds PEM-encoded bytes (typically read from a client certificate key file). + // KeyData takes precedence over KeyFile + KeyData []byte `json:"keyData,omitempty"` + // CAData holds PEM-encoded bytes (typically read from a root certificates bundle). + // CAData takes precedence over CAFile + CAData []byte `json:"caData,omitempty"` +} diff --git a/vendor/k8s.io/kube-scheduler/config/v1beta3/types_pluginargs.go b/vendor/k8s.io/kube-scheduler/config/v1beta3/types_pluginargs.go new file mode 100644 index 000000000..725cd1b92 --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/config/v1beta3/types_pluginargs.go @@ -0,0 +1,225 @@ +/* +Copyright 2021 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 v1beta3 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// DefaultPreemptionArgs holds arguments used to configure the +// DefaultPreemption plugin. +type DefaultPreemptionArgs struct { + metav1.TypeMeta `json:",inline"` + + // MinCandidateNodesPercentage is the minimum number of candidates to + // shortlist when dry running preemption as a percentage of number of nodes. + // Must be in the range [0, 100]. Defaults to 10% of the cluster size if + // unspecified. + MinCandidateNodesPercentage *int32 `json:"minCandidateNodesPercentage,omitempty"` + // MinCandidateNodesAbsolute is the absolute minimum number of candidates to + // shortlist. The likely number of candidates enumerated for dry running + // preemption is given by the formula: + // numCandidates = max(numNodes * minCandidateNodesPercentage, minCandidateNodesAbsolute) + // We say "likely" because there are other factors such as PDB violations + // that play a role in the number of candidates shortlisted. Must be at least + // 0 nodes. Defaults to 100 nodes if unspecified. + MinCandidateNodesAbsolute *int32 `json:"minCandidateNodesAbsolute,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// InterPodAffinityArgs holds arguments used to configure the InterPodAffinity plugin. +type InterPodAffinityArgs struct { + metav1.TypeMeta `json:",inline"` + + // HardPodAffinityWeight is the scoring weight for existing pods with a + // matching hard affinity to the incoming pod. + HardPodAffinityWeight *int32 `json:"hardPodAffinityWeight,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// NodeResourcesFitArgs holds arguments used to configure the NodeResourcesFit plugin. +type NodeResourcesFitArgs struct { + metav1.TypeMeta `json:",inline"` + + // IgnoredResources is the list of resources that NodeResources fit filter + // should ignore. This doesn't apply to scoring. + // +listType=atomic + IgnoredResources []string `json:"ignoredResources,omitempty"` + // IgnoredResourceGroups defines the list of resource groups that NodeResources fit filter should ignore. + // e.g. if group is ["example.com"], it will ignore all resource names that begin + // with "example.com", such as "example.com/aaa" and "example.com/bbb". + // A resource group name can't contain '/'. This doesn't apply to scoring. + // +listType=atomic + IgnoredResourceGroups []string `json:"ignoredResourceGroups,omitempty"` + + // ScoringStrategy selects the node resource scoring strategy. + // The default strategy is LeastAllocated with an equal "cpu" and "memory" weight. + ScoringStrategy *ScoringStrategy `json:"scoringStrategy,omitempty"` +} + +// PodTopologySpreadConstraintsDefaulting defines how to set default constraints +// for the PodTopologySpread plugin. +type PodTopologySpreadConstraintsDefaulting string + +const ( + // SystemDefaulting instructs to use the kubernetes defined default. + SystemDefaulting PodTopologySpreadConstraintsDefaulting = "System" + // ListDefaulting instructs to use the config provided default. + ListDefaulting PodTopologySpreadConstraintsDefaulting = "List" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// PodTopologySpreadArgs holds arguments used to configure the PodTopologySpread plugin. +type PodTopologySpreadArgs struct { + metav1.TypeMeta `json:",inline"` + + // DefaultConstraints defines topology spread constraints to be applied to + // Pods that don't define any in `pod.spec.topologySpreadConstraints`. + // `.defaultConstraints[*].labelSelectors` must be empty, as they are + // deduced from the Pod's membership to Services, ReplicationControllers, + // ReplicaSets or StatefulSets. + // When not empty, .defaultingType must be "List". + // +optional + // +listType=atomic + DefaultConstraints []corev1.TopologySpreadConstraint `json:"defaultConstraints,omitempty"` + + // DefaultingType determines how .defaultConstraints are deduced. Can be one + // of "System" or "List". + // + // - "System": Use kubernetes defined constraints that spread Pods among + // Nodes and Zones. + // - "List": Use constraints defined in .defaultConstraints. + // + // Defaults to "System". + // +optional + DefaultingType PodTopologySpreadConstraintsDefaulting `json:"defaultingType,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// NodeResourcesBalancedAllocationArgs holds arguments used to configure NodeResourcesBalancedAllocation plugin. +type NodeResourcesBalancedAllocationArgs struct { + metav1.TypeMeta `json:",inline"` + + // Resources to be managed, the default is "cpu" and "memory" if not specified. + // +listType=map + // +listMapKey=name + Resources []ResourceSpec `json:"resources,omitempty"` +} + +// UtilizationShapePoint represents single point of priority function shape. +type UtilizationShapePoint struct { + // Utilization (x axis). Valid values are 0 to 100. Fully utilized node maps to 100. + Utilization int32 `json:"utilization"` + // Score assigned to given utilization (y axis). Valid values are 0 to 10. + Score int32 `json:"score"` +} + +// ResourceSpec represents a single resource. +type ResourceSpec struct { + // Name of the resource. + Name string `json:"name"` + // Weight of the resource. + Weight int64 `json:"weight,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// VolumeBindingArgs holds arguments used to configure the VolumeBinding plugin. +type VolumeBindingArgs struct { + metav1.TypeMeta `json:",inline"` + + // BindTimeoutSeconds is the timeout in seconds in volume binding operation. + // Value must be non-negative integer. The value zero indicates no waiting. + // If this value is nil, the default value (600) will be used. + BindTimeoutSeconds *int64 `json:"bindTimeoutSeconds,omitempty"` + + // Shape specifies the points defining the score function shape, which is + // used to score nodes based on the utilization of statically provisioned + // PVs. The utilization is calculated by dividing the total requested + // storage of the pod by the total capacity of feasible PVs on each node. + // Each point contains utilization (ranges from 0 to 100) and its + // associated score (ranges from 0 to 10). You can turn the priority by + // specifying different scores for different utilization numbers. + // The default shape points are: + // 1) 0 for 0 utilization + // 2) 10 for 100 utilization + // All points must be sorted in increasing order by utilization. + // +featureGate=VolumeCapacityPriority + // +optional + // +listType=atomic + Shape []UtilizationShapePoint `json:"shape,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// NodeAffinityArgs holds arguments to configure the NodeAffinity plugin. +type NodeAffinityArgs struct { + metav1.TypeMeta `json:",inline"` + + // AddedAffinity is applied to all Pods additionally to the NodeAffinity + // specified in the PodSpec. That is, Nodes need to satisfy AddedAffinity + // AND .spec.NodeAffinity. AddedAffinity is empty by default (all Nodes + // match). + // When AddedAffinity is used, some Pods with affinity requirements that match + // a specific Node (such as Daemonset Pods) might remain unschedulable. + // +optional + AddedAffinity *corev1.NodeAffinity `json:"addedAffinity,omitempty"` +} + +// ScoringStrategyType the type of scoring strategy used in NodeResourcesFit plugin. +type ScoringStrategyType string + +const ( + // LeastAllocated strategy prioritizes nodes with least allocated resources. + LeastAllocated ScoringStrategyType = "LeastAllocated" + // MostAllocated strategy prioritizes nodes with most allocated resources. + MostAllocated ScoringStrategyType = "MostAllocated" + // RequestedToCapacityRatio strategy allows specifying a custom shape function + // to score nodes based on the request to capacity ratio. + RequestedToCapacityRatio ScoringStrategyType = "RequestedToCapacityRatio" +) + +// ScoringStrategy define ScoringStrategyType for node resource plugin +type ScoringStrategy struct { + // Type selects which strategy to run. + Type ScoringStrategyType `json:"type,omitempty"` + + // Resources to consider when scoring. + // The default resource set includes "cpu" and "memory" with an equal weight. + // Allowed weights go from 1 to 100. + // Weight defaults to 1 if not specified or explicitly set to 0. + // +listType=map + // +listMapKey=topologyKey + Resources []ResourceSpec `json:"resources,omitempty"` + + // Arguments specific to RequestedToCapacityRatio strategy. + RequestedToCapacityRatio *RequestedToCapacityRatioParam `json:"requestedToCapacityRatio,omitempty"` +} + +// RequestedToCapacityRatioParam define RequestedToCapacityRatio parameters +type RequestedToCapacityRatioParam struct { + // Shape is a list of points defining the scoring function shape. + // +listType=atomic + Shape []UtilizationShapePoint `json:"shape,omitempty"` +} diff --git a/vendor/k8s.io/kube-scheduler/config/v1beta3/zz_generated.deepcopy.go b/vendor/k8s.io/kube-scheduler/config/v1beta3/zz_generated.deepcopy.go new file mode 100644 index 000000000..2b549d499 --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/config/v1beta3/zz_generated.deepcopy.go @@ -0,0 +1,604 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1beta3 + +import ( + v1 "k8s.io/api/core/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DefaultPreemptionArgs) DeepCopyInto(out *DefaultPreemptionArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.MinCandidateNodesPercentage != nil { + in, out := &in.MinCandidateNodesPercentage, &out.MinCandidateNodesPercentage + *out = new(int32) + **out = **in + } + if in.MinCandidateNodesAbsolute != nil { + in, out := &in.MinCandidateNodesAbsolute, &out.MinCandidateNodesAbsolute + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DefaultPreemptionArgs. +func (in *DefaultPreemptionArgs) DeepCopy() *DefaultPreemptionArgs { + if in == nil { + return nil + } + out := new(DefaultPreemptionArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DefaultPreemptionArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Extender) DeepCopyInto(out *Extender) { + *out = *in + if in.TLSConfig != nil { + in, out := &in.TLSConfig, &out.TLSConfig + *out = new(ExtenderTLSConfig) + (*in).DeepCopyInto(*out) + } + out.HTTPTimeout = in.HTTPTimeout + if in.ManagedResources != nil { + in, out := &in.ManagedResources, &out.ManagedResources + *out = make([]ExtenderManagedResource, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Extender. +func (in *Extender) DeepCopy() *Extender { + if in == nil { + return nil + } + out := new(Extender) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExtenderManagedResource) DeepCopyInto(out *ExtenderManagedResource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderManagedResource. +func (in *ExtenderManagedResource) DeepCopy() *ExtenderManagedResource { + if in == nil { + return nil + } + out := new(ExtenderManagedResource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExtenderTLSConfig) DeepCopyInto(out *ExtenderTLSConfig) { + *out = *in + if in.CertData != nil { + in, out := &in.CertData, &out.CertData + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.KeyData != nil { + in, out := &in.KeyData, &out.KeyData + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.CAData != nil { + in, out := &in.CAData, &out.CAData + *out = make([]byte, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderTLSConfig. +func (in *ExtenderTLSConfig) DeepCopy() *ExtenderTLSConfig { + if in == nil { + return nil + } + out := new(ExtenderTLSConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InterPodAffinityArgs) DeepCopyInto(out *InterPodAffinityArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.HardPodAffinityWeight != nil { + in, out := &in.HardPodAffinityWeight, &out.HardPodAffinityWeight + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InterPodAffinityArgs. +func (in *InterPodAffinityArgs) DeepCopy() *InterPodAffinityArgs { + if in == nil { + return nil + } + out := new(InterPodAffinityArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *InterPodAffinityArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubeSchedulerConfiguration) DeepCopyInto(out *KubeSchedulerConfiguration) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.Parallelism != nil { + in, out := &in.Parallelism, &out.Parallelism + *out = new(int32) + **out = **in + } + in.LeaderElection.DeepCopyInto(&out.LeaderElection) + out.ClientConnection = in.ClientConnection + in.DebuggingConfiguration.DeepCopyInto(&out.DebuggingConfiguration) + if in.PercentageOfNodesToScore != nil { + in, out := &in.PercentageOfNodesToScore, &out.PercentageOfNodesToScore + *out = new(int32) + **out = **in + } + if in.PodInitialBackoffSeconds != nil { + in, out := &in.PodInitialBackoffSeconds, &out.PodInitialBackoffSeconds + *out = new(int64) + **out = **in + } + if in.PodMaxBackoffSeconds != nil { + in, out := &in.PodMaxBackoffSeconds, &out.PodMaxBackoffSeconds + *out = new(int64) + **out = **in + } + if in.Profiles != nil { + in, out := &in.Profiles, &out.Profiles + *out = make([]KubeSchedulerProfile, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Extenders != nil { + in, out := &in.Extenders, &out.Extenders + *out = make([]Extender, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeSchedulerConfiguration. +func (in *KubeSchedulerConfiguration) DeepCopy() *KubeSchedulerConfiguration { + if in == nil { + return nil + } + out := new(KubeSchedulerConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KubeSchedulerConfiguration) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubeSchedulerProfile) DeepCopyInto(out *KubeSchedulerProfile) { + *out = *in + if in.SchedulerName != nil { + in, out := &in.SchedulerName, &out.SchedulerName + *out = new(string) + **out = **in + } + if in.Plugins != nil { + in, out := &in.Plugins, &out.Plugins + *out = new(Plugins) + (*in).DeepCopyInto(*out) + } + if in.PluginConfig != nil { + in, out := &in.PluginConfig, &out.PluginConfig + *out = make([]PluginConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeSchedulerProfile. +func (in *KubeSchedulerProfile) DeepCopy() *KubeSchedulerProfile { + if in == nil { + return nil + } + out := new(KubeSchedulerProfile) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeAffinityArgs) DeepCopyInto(out *NodeAffinityArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.AddedAffinity != nil { + in, out := &in.AddedAffinity, &out.AddedAffinity + *out = new(v1.NodeAffinity) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeAffinityArgs. +func (in *NodeAffinityArgs) DeepCopy() *NodeAffinityArgs { + if in == nil { + return nil + } + out := new(NodeAffinityArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodeAffinityArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeResourcesBalancedAllocationArgs) DeepCopyInto(out *NodeResourcesBalancedAllocationArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make([]ResourceSpec, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeResourcesBalancedAllocationArgs. +func (in *NodeResourcesBalancedAllocationArgs) DeepCopy() *NodeResourcesBalancedAllocationArgs { + if in == nil { + return nil + } + out := new(NodeResourcesBalancedAllocationArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodeResourcesBalancedAllocationArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeResourcesFitArgs) DeepCopyInto(out *NodeResourcesFitArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.IgnoredResources != nil { + in, out := &in.IgnoredResources, &out.IgnoredResources + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.IgnoredResourceGroups != nil { + in, out := &in.IgnoredResourceGroups, &out.IgnoredResourceGroups + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.ScoringStrategy != nil { + in, out := &in.ScoringStrategy, &out.ScoringStrategy + *out = new(ScoringStrategy) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeResourcesFitArgs. +func (in *NodeResourcesFitArgs) DeepCopy() *NodeResourcesFitArgs { + if in == nil { + return nil + } + out := new(NodeResourcesFitArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodeResourcesFitArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Plugin) DeepCopyInto(out *Plugin) { + *out = *in + if in.Weight != nil { + in, out := &in.Weight, &out.Weight + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Plugin. +func (in *Plugin) DeepCopy() *Plugin { + if in == nil { + return nil + } + out := new(Plugin) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginConfig) DeepCopyInto(out *PluginConfig) { + *out = *in + in.Args.DeepCopyInto(&out.Args) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginConfig. +func (in *PluginConfig) DeepCopy() *PluginConfig { + if in == nil { + return nil + } + out := new(PluginConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginSet) DeepCopyInto(out *PluginSet) { + *out = *in + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = make([]Plugin, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Disabled != nil { + in, out := &in.Disabled, &out.Disabled + *out = make([]Plugin, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginSet. +func (in *PluginSet) DeepCopy() *PluginSet { + if in == nil { + return nil + } + out := new(PluginSet) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Plugins) DeepCopyInto(out *Plugins) { + *out = *in + in.PreEnqueue.DeepCopyInto(&out.PreEnqueue) + in.QueueSort.DeepCopyInto(&out.QueueSort) + in.PreFilter.DeepCopyInto(&out.PreFilter) + in.Filter.DeepCopyInto(&out.Filter) + in.PostFilter.DeepCopyInto(&out.PostFilter) + in.PreScore.DeepCopyInto(&out.PreScore) + in.Score.DeepCopyInto(&out.Score) + in.Reserve.DeepCopyInto(&out.Reserve) + in.Permit.DeepCopyInto(&out.Permit) + in.PreBind.DeepCopyInto(&out.PreBind) + in.Bind.DeepCopyInto(&out.Bind) + in.PostBind.DeepCopyInto(&out.PostBind) + in.MultiPoint.DeepCopyInto(&out.MultiPoint) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Plugins. +func (in *Plugins) DeepCopy() *Plugins { + if in == nil { + return nil + } + out := new(Plugins) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodTopologySpreadArgs) DeepCopyInto(out *PodTopologySpreadArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.DefaultConstraints != nil { + in, out := &in.DefaultConstraints, &out.DefaultConstraints + *out = make([]v1.TopologySpreadConstraint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodTopologySpreadArgs. +func (in *PodTopologySpreadArgs) DeepCopy() *PodTopologySpreadArgs { + if in == nil { + return nil + } + out := new(PodTopologySpreadArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PodTopologySpreadArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RequestedToCapacityRatioParam) DeepCopyInto(out *RequestedToCapacityRatioParam) { + *out = *in + if in.Shape != nil { + in, out := &in.Shape, &out.Shape + *out = make([]UtilizationShapePoint, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RequestedToCapacityRatioParam. +func (in *RequestedToCapacityRatioParam) DeepCopy() *RequestedToCapacityRatioParam { + if in == nil { + return nil + } + out := new(RequestedToCapacityRatioParam) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceSpec) DeepCopyInto(out *ResourceSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceSpec. +func (in *ResourceSpec) DeepCopy() *ResourceSpec { + if in == nil { + return nil + } + out := new(ResourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ScoringStrategy) DeepCopyInto(out *ScoringStrategy) { + *out = *in + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make([]ResourceSpec, len(*in)) + copy(*out, *in) + } + if in.RequestedToCapacityRatio != nil { + in, out := &in.RequestedToCapacityRatio, &out.RequestedToCapacityRatio + *out = new(RequestedToCapacityRatioParam) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScoringStrategy. +func (in *ScoringStrategy) DeepCopy() *ScoringStrategy { + if in == nil { + return nil + } + out := new(ScoringStrategy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UtilizationShapePoint) DeepCopyInto(out *UtilizationShapePoint) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UtilizationShapePoint. +func (in *UtilizationShapePoint) DeepCopy() *UtilizationShapePoint { + if in == nil { + return nil + } + out := new(UtilizationShapePoint) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeBindingArgs) DeepCopyInto(out *VolumeBindingArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.BindTimeoutSeconds != nil { + in, out := &in.BindTimeoutSeconds, &out.BindTimeoutSeconds + *out = new(int64) + **out = **in + } + if in.Shape != nil { + in, out := &in.Shape, &out.Shape + *out = make([]UtilizationShapePoint, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeBindingArgs. +func (in *VolumeBindingArgs) DeepCopy() *VolumeBindingArgs { + if in == nil { + return nil + } + out := new(VolumeBindingArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VolumeBindingArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} diff --git a/vendor/k8s.io/kube-scheduler/extender/v1/doc.go b/vendor/k8s.io/kube-scheduler/extender/v1/doc.go new file mode 100644 index 000000000..202572083 --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/extender/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2019 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. +*/ + +// +k8s:deepcopy-gen=package + +// Package v1 contains scheduler API objects. +package v1 // import "k8s.io/kube-scheduler/extender/v1" diff --git a/vendor/k8s.io/kube-scheduler/extender/v1/types.go b/vendor/k8s.io/kube-scheduler/extender/v1/types.go new file mode 100644 index 000000000..ebb4fd7e5 --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/extender/v1/types.go @@ -0,0 +1,132 @@ +/* +Copyright 2019 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 v1 + +import ( + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" +) + +const ( + // MinExtenderPriority defines the min priority value for extender. + MinExtenderPriority int64 = 0 + + // MaxExtenderPriority defines the max priority value for extender. + MaxExtenderPriority int64 = 10 +) + +// ExtenderPreemptionResult represents the result returned by preemption phase of extender. +type ExtenderPreemptionResult struct { + NodeNameToMetaVictims map[string]*MetaVictims +} + +// ExtenderPreemptionArgs represents the arguments needed by the extender to preempt pods on nodes. +type ExtenderPreemptionArgs struct { + // Pod being scheduled + Pod *v1.Pod + // Victims map generated by scheduler preemption phase + // Only set NodeNameToMetaVictims if Extender.NodeCacheCapable == true. Otherwise, only set NodeNameToVictims. + NodeNameToVictims map[string]*Victims + NodeNameToMetaVictims map[string]*MetaVictims +} + +// Victims represents: +// +// pods: a group of pods expected to be preempted. +// numPDBViolations: the count of violations of PodDisruptionBudget +type Victims struct { + Pods []*v1.Pod + NumPDBViolations int64 +} + +// MetaPod represent identifier for a v1.Pod +type MetaPod struct { + UID string +} + +// MetaVictims represents: +// +// pods: a group of pods expected to be preempted. +// Only Pod identifiers will be sent and user are expect to get v1.Pod in their own way. +// numPDBViolations: the count of violations of PodDisruptionBudget +type MetaVictims struct { + Pods []*MetaPod + NumPDBViolations int64 +} + +// ExtenderArgs represents the arguments needed by the extender to filter/prioritize +// nodes for a pod. +type ExtenderArgs struct { + // Pod being scheduled + Pod *v1.Pod + // List of candidate nodes where the pod can be scheduled; to be populated + // only if Extender.NodeCacheCapable == false + Nodes *v1.NodeList + // List of candidate node names where the pod can be scheduled; to be + // populated only if Extender.NodeCacheCapable == true + NodeNames *[]string +} + +// FailedNodesMap represents the filtered out nodes, with node names and failure messages +type FailedNodesMap map[string]string + +// ExtenderFilterResult represents the results of a filter call to an extender +type ExtenderFilterResult struct { + // Filtered set of nodes where the pod can be scheduled; to be populated + // only if Extender.NodeCacheCapable == false + Nodes *v1.NodeList + // Filtered set of nodes where the pod can be scheduled; to be populated + // only if Extender.NodeCacheCapable == true + NodeNames *[]string + // Filtered out nodes where the pod can't be scheduled and the failure messages + FailedNodes FailedNodesMap + // Filtered out nodes where the pod can't be scheduled and preemption would + // not change anything. The value is the failure message same as FailedNodes. + // Nodes specified here takes precedence over FailedNodes. + FailedAndUnresolvableNodes FailedNodesMap + // Error message indicating failure + Error string +} + +// ExtenderBindingArgs represents the arguments to an extender for binding a pod to a node. +type ExtenderBindingArgs struct { + // PodName is the name of the pod being bound + PodName string + // PodNamespace is the namespace of the pod being bound + PodNamespace string + // PodUID is the UID of the pod being bound + PodUID types.UID + // Node selected by the scheduler + Node string +} + +// ExtenderBindingResult represents the result of binding of a pod to a node from an extender. +type ExtenderBindingResult struct { + // Error message indicating failure + Error string +} + +// HostPriority represents the priority of scheduling to a particular host, higher priority is better. +type HostPriority struct { + // Name of the host + Host string + // Score associated with the host + Score int64 +} + +// HostPriorityList declares a []HostPriority type. +type HostPriorityList []HostPriority diff --git a/vendor/k8s.io/kube-scheduler/extender/v1/zz_generated.deepcopy.go b/vendor/k8s.io/kube-scheduler/extender/v1/zz_generated.deepcopy.go new file mode 100644 index 000000000..99373a374 --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/extender/v1/zz_generated.deepcopy.go @@ -0,0 +1,347 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + corev1 "k8s.io/api/core/v1" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExtenderArgs) DeepCopyInto(out *ExtenderArgs) { + *out = *in + if in.Pod != nil { + in, out := &in.Pod, &out.Pod + *out = new(corev1.Pod) + (*in).DeepCopyInto(*out) + } + if in.Nodes != nil { + in, out := &in.Nodes, &out.Nodes + *out = new(corev1.NodeList) + (*in).DeepCopyInto(*out) + } + if in.NodeNames != nil { + in, out := &in.NodeNames, &out.NodeNames + *out = new([]string) + if **in != nil { + in, out := *in, *out + *out = make([]string, len(*in)) + copy(*out, *in) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderArgs. +func (in *ExtenderArgs) DeepCopy() *ExtenderArgs { + if in == nil { + return nil + } + out := new(ExtenderArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExtenderBindingArgs) DeepCopyInto(out *ExtenderBindingArgs) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderBindingArgs. +func (in *ExtenderBindingArgs) DeepCopy() *ExtenderBindingArgs { + if in == nil { + return nil + } + out := new(ExtenderBindingArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExtenderBindingResult) DeepCopyInto(out *ExtenderBindingResult) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderBindingResult. +func (in *ExtenderBindingResult) DeepCopy() *ExtenderBindingResult { + if in == nil { + return nil + } + out := new(ExtenderBindingResult) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExtenderFilterResult) DeepCopyInto(out *ExtenderFilterResult) { + *out = *in + if in.Nodes != nil { + in, out := &in.Nodes, &out.Nodes + *out = new(corev1.NodeList) + (*in).DeepCopyInto(*out) + } + if in.NodeNames != nil { + in, out := &in.NodeNames, &out.NodeNames + *out = new([]string) + if **in != nil { + in, out := *in, *out + *out = make([]string, len(*in)) + copy(*out, *in) + } + } + if in.FailedNodes != nil { + in, out := &in.FailedNodes, &out.FailedNodes + *out = make(FailedNodesMap, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.FailedAndUnresolvableNodes != nil { + in, out := &in.FailedAndUnresolvableNodes, &out.FailedAndUnresolvableNodes + *out = make(FailedNodesMap, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderFilterResult. +func (in *ExtenderFilterResult) DeepCopy() *ExtenderFilterResult { + if in == nil { + return nil + } + out := new(ExtenderFilterResult) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExtenderPreemptionArgs) DeepCopyInto(out *ExtenderPreemptionArgs) { + *out = *in + if in.Pod != nil { + in, out := &in.Pod, &out.Pod + *out = new(corev1.Pod) + (*in).DeepCopyInto(*out) + } + if in.NodeNameToVictims != nil { + in, out := &in.NodeNameToVictims, &out.NodeNameToVictims + *out = make(map[string]*Victims, len(*in)) + for key, val := range *in { + var outVal *Victims + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new(Victims) + (*in).DeepCopyInto(*out) + } + (*out)[key] = outVal + } + } + if in.NodeNameToMetaVictims != nil { + in, out := &in.NodeNameToMetaVictims, &out.NodeNameToMetaVictims + *out = make(map[string]*MetaVictims, len(*in)) + for key, val := range *in { + var outVal *MetaVictims + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new(MetaVictims) + (*in).DeepCopyInto(*out) + } + (*out)[key] = outVal + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderPreemptionArgs. +func (in *ExtenderPreemptionArgs) DeepCopy() *ExtenderPreemptionArgs { + if in == nil { + return nil + } + out := new(ExtenderPreemptionArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExtenderPreemptionResult) DeepCopyInto(out *ExtenderPreemptionResult) { + *out = *in + if in.NodeNameToMetaVictims != nil { + in, out := &in.NodeNameToMetaVictims, &out.NodeNameToMetaVictims + *out = make(map[string]*MetaVictims, len(*in)) + for key, val := range *in { + var outVal *MetaVictims + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new(MetaVictims) + (*in).DeepCopyInto(*out) + } + (*out)[key] = outVal + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderPreemptionResult. +func (in *ExtenderPreemptionResult) DeepCopy() *ExtenderPreemptionResult { + if in == nil { + return nil + } + out := new(ExtenderPreemptionResult) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in FailedNodesMap) DeepCopyInto(out *FailedNodesMap) { + { + in := &in + *out = make(FailedNodesMap, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FailedNodesMap. +func (in FailedNodesMap) DeepCopy() FailedNodesMap { + if in == nil { + return nil + } + out := new(FailedNodesMap) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HostPriority) DeepCopyInto(out *HostPriority) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostPriority. +func (in *HostPriority) DeepCopy() *HostPriority { + if in == nil { + return nil + } + out := new(HostPriority) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in HostPriorityList) DeepCopyInto(out *HostPriorityList) { + { + in := &in + *out = make(HostPriorityList, len(*in)) + copy(*out, *in) + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostPriorityList. +func (in HostPriorityList) DeepCopy() HostPriorityList { + if in == nil { + return nil + } + out := new(HostPriorityList) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetaPod) DeepCopyInto(out *MetaPod) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetaPod. +func (in *MetaPod) DeepCopy() *MetaPod { + if in == nil { + return nil + } + out := new(MetaPod) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetaVictims) DeepCopyInto(out *MetaVictims) { + *out = *in + if in.Pods != nil { + in, out := &in.Pods, &out.Pods + *out = make([]*MetaPod, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(MetaPod) + **out = **in + } + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetaVictims. +func (in *MetaVictims) DeepCopy() *MetaVictims { + if in == nil { + return nil + } + out := new(MetaVictims) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Victims) DeepCopyInto(out *Victims) { + *out = *in + if in.Pods != nil { + in, out := &in.Pods, &out.Pods + *out = make([]*corev1.Pod, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(corev1.Pod) + (*in).DeepCopyInto(*out) + } + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Victims. +func (in *Victims) DeepCopy() *Victims { + if in == nil { + return nil + } + out := new(Victims) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/k8s.io/kubernetes/LICENSE b/vendor/k8s.io/kubernetes/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/k8s.io/kubernetes/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/vendor/k8s.io/kubernetes/cmd/kube-scheduler/app/config/config.go b/vendor/k8s.io/kubernetes/cmd/kube-scheduler/app/config/config.go new file mode 100644 index 000000000..774cab62d --- /dev/null +++ b/vendor/k8s.io/kubernetes/cmd/kube-scheduler/app/config/config.go @@ -0,0 +1,79 @@ +/* +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 config + +import ( + "time" + + apiserver "k8s.io/apiserver/pkg/server" + "k8s.io/client-go/dynamic/dynamicinformer" + "k8s.io/client-go/informers" + clientset "k8s.io/client-go/kubernetes" + restclient "k8s.io/client-go/rest" + "k8s.io/client-go/tools/events" + "k8s.io/client-go/tools/leaderelection" + kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config" +) + +// Config has all the context to run a Scheduler +type Config struct { + // ComponentConfig is the scheduler server's configuration object. + ComponentConfig kubeschedulerconfig.KubeSchedulerConfiguration + + // LoopbackClientConfig is a config for a privileged loopback connection + LoopbackClientConfig *restclient.Config + + Authentication apiserver.AuthenticationInfo + Authorization apiserver.AuthorizationInfo + SecureServing *apiserver.SecureServingInfo + + Client clientset.Interface + KubeConfig *restclient.Config + InformerFactory informers.SharedInformerFactory + DynInformerFactory dynamicinformer.DynamicSharedInformerFactory + + //nolint:staticcheck // SA1019 this deprecated field still needs to be used for now. It will be removed once the migration is done. + EventBroadcaster events.EventBroadcasterAdapter + + // LeaderElection is optional. + LeaderElection *leaderelection.LeaderElectionConfig + + // PodMaxInUnschedulablePodsDuration is the maximum time a pod can stay in + // unschedulablePods. If a pod stays in unschedulablePods for longer than this + // value, the pod will be moved from unschedulablePods to backoffQ or activeQ. + // If this value is empty, the default value (5min) will be used. + PodMaxInUnschedulablePodsDuration time.Duration +} + +type completedConfig struct { + *Config +} + +// CompletedConfig same as Config, just to swap private object. +type CompletedConfig struct { + // Embed a private pointer that cannot be instantiated outside of this package. + *completedConfig +} + +// Complete fills in any fields not set that are required to have valid data. It's mutating the receiver. +func (c *Config) Complete() CompletedConfig { + cc := completedConfig{c} + + apiserver.AuthorizeClientBearerToken(c.LoopbackClientConfig, &c.Authentication, &c.Authorization) + + return CompletedConfig{&cc} +} diff --git a/vendor/k8s.io/kubernetes/cmd/kube-scheduler/app/options/configfile.go b/vendor/k8s.io/kubernetes/cmd/kube-scheduler/app/options/configfile.go new file mode 100644 index 000000000..8cc48328b --- /dev/null +++ b/vendor/k8s.io/kubernetes/cmd/kube-scheduler/app/options/configfile.go @@ -0,0 +1,121 @@ +/* +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 options + +import ( + "bytes" + "fmt" + "io" + "os" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog/v2" + "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/kubernetes/pkg/scheduler/apis/config/scheme" + configv1 "k8s.io/kubernetes/pkg/scheduler/apis/config/v1" + configv1beta2 "k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2" + configv1beta3 "k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3" +) + +func loadConfigFromFile(file string) (*config.KubeSchedulerConfiguration, error) { + data, err := os.ReadFile(file) + if err != nil { + return nil, err + } + + return loadConfig(data) +} + +func loadConfig(data []byte) (*config.KubeSchedulerConfiguration, error) { + // The UniversalDecoder runs defaulting and returns the internal type by default. + obj, gvk, err := scheme.Codecs.UniversalDecoder().Decode(data, nil, nil) + if err != nil { + return nil, err + } + if cfgObj, ok := obj.(*config.KubeSchedulerConfiguration); ok { + // We don't set this field in pkg/scheduler/apis/config/{version}/conversion.go + // because the field will be cleared later by API machinery during + // conversion. See KubeSchedulerConfiguration internal type definition for + // more details. + cfgObj.TypeMeta.APIVersion = gvk.GroupVersion().String() + switch cfgObj.TypeMeta.APIVersion { + case configv1beta2.SchemeGroupVersion.String(): + klog.InfoS("KubeSchedulerConfiguration v1beta2 is deprecated in v1.25, will be removed in v1.28") + case configv1beta3.SchemeGroupVersion.String(): + klog.InfoS("KubeSchedulerConfiguration v1beta3 is deprecated in v1.26, will be removed in v1.29") + } + return cfgObj, nil + } + return nil, fmt.Errorf("couldn't decode as KubeSchedulerConfiguration, got %s: ", gvk) +} + +func encodeConfig(cfg *config.KubeSchedulerConfiguration) (*bytes.Buffer, error) { + buf := new(bytes.Buffer) + const mediaType = runtime.ContentTypeYAML + info, ok := runtime.SerializerInfoForMediaType(scheme.Codecs.SupportedMediaTypes(), mediaType) + if !ok { + return buf, fmt.Errorf("unable to locate encoder -- %q is not a supported media type", mediaType) + } + + var encoder runtime.Encoder + switch cfg.TypeMeta.APIVersion { + case configv1beta2.SchemeGroupVersion.String(): + encoder = scheme.Codecs.EncoderForVersion(info.Serializer, configv1beta2.SchemeGroupVersion) + case configv1beta3.SchemeGroupVersion.String(): + encoder = scheme.Codecs.EncoderForVersion(info.Serializer, configv1beta3.SchemeGroupVersion) + case configv1.SchemeGroupVersion.String(): + encoder = scheme.Codecs.EncoderForVersion(info.Serializer, configv1.SchemeGroupVersion) + default: + encoder = scheme.Codecs.EncoderForVersion(info.Serializer, configv1.SchemeGroupVersion) + } + if err := encoder.Encode(cfg, buf); err != nil { + return buf, err + } + return buf, nil +} + +// LogOrWriteConfig logs the completed component config and writes it into the given file name as YAML, if either is enabled +func LogOrWriteConfig(fileName string, cfg *config.KubeSchedulerConfiguration, completedProfiles []config.KubeSchedulerProfile) error { + klogV := klog.V(2) + if !klogV.Enabled() && len(fileName) == 0 { + return nil + } + cfg.Profiles = completedProfiles + + buf, err := encodeConfig(cfg) + if err != nil { + return err + } + + if klogV.Enabled() { + klogV.InfoS("Using component config", "config", buf.String()) + } + + if len(fileName) > 0 { + configFile, err := os.Create(fileName) + if err != nil { + return err + } + defer configFile.Close() + if _, err := io.Copy(configFile, buf); err != nil { + return err + } + klog.InfoS("Wrote configuration", "file", fileName) + os.Exit(0) + } + return nil +} diff --git a/vendor/k8s.io/kubernetes/cmd/kube-scheduler/app/options/deprecated.go b/vendor/k8s.io/kubernetes/cmd/kube-scheduler/app/options/deprecated.go new file mode 100644 index 000000000..a465d69af --- /dev/null +++ b/vendor/k8s.io/kubernetes/cmd/kube-scheduler/app/options/deprecated.go @@ -0,0 +1,55 @@ +/* +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 options + +import ( + "time" + + "github.com/spf13/pflag" + componentbaseconfig "k8s.io/component-base/config" +) + +// DeprecatedOptions contains deprecated options and their flags. +// TODO remove these fields once the deprecated flags are removed. +type DeprecatedOptions struct { + componentbaseconfig.DebuggingConfiguration + componentbaseconfig.ClientConnectionConfiguration + // Note that only the deprecated options (lock-object-name and lock-object-namespace) are populated here. + componentbaseconfig.LeaderElectionConfiguration + // PodMaxInUnschedulablePodsDuration is the maximum time a pod can stay in + // unschedulablePods. If a pod stays in unschedulablePods for longer than this + // value, the pod will be moved from unschedulablePods to backoffQ or activeQ. + // If this value is empty, the default value (5min) will be used. + PodMaxInUnschedulablePodsDuration time.Duration +} + +// AddFlags adds flags for the deprecated options. +func (o *DeprecatedOptions) AddFlags(fs *pflag.FlagSet) { + if o == nil { + return + } + + fs.BoolVar(&o.EnableProfiling, "profiling", true, "DEPRECATED: enable profiling via web interface host:port/debug/pprof/. This parameter is ignored if a config file is specified in --config.") + fs.BoolVar(&o.EnableContentionProfiling, "contention-profiling", true, "DEPRECATED: enable lock contention profiling, if profiling is enabled. This parameter is ignored if a config file is specified in --config.") + fs.StringVar(&o.Kubeconfig, "kubeconfig", "", "DEPRECATED: path to kubeconfig file with authorization and master location information. This parameter is ignored if a config file is specified in --config.") + fs.StringVar(&o.ContentType, "kube-api-content-type", "application/vnd.kubernetes.protobuf", "DEPRECATED: content type of requests sent to apiserver. This parameter is ignored if a config file is specified in --config.") + fs.Float32Var(&o.QPS, "kube-api-qps", 50.0, "DEPRECATED: QPS to use while talking with kubernetes apiserver. This parameter is ignored if a config file is specified in --config.") + fs.Int32Var(&o.Burst, "kube-api-burst", 100, "DEPRECATED: burst to use while talking with kubernetes apiserver. This parameter is ignored if a config file is specified in --config.") + fs.StringVar(&o.ResourceNamespace, "lock-object-namespace", "kube-system", "DEPRECATED: define the namespace of the lock object. Will be removed in favor of leader-elect-resource-namespace. This parameter is ignored if a config file is specified in --config.") + fs.StringVar(&o.ResourceName, "lock-object-name", "kube-scheduler", "DEPRECATED: define the name of the lock object. Will be removed in favor of leader-elect-resource-name. This parameter is ignored if a config file is specified in --config.") + fs.DurationVar(&o.PodMaxInUnschedulablePodsDuration, "pod-max-in-unschedulable-pods-duration", 5*time.Minute, "DEPRECATED: the maximum time a pod can stay in unschedulablePods. If a pod stays in unschedulablePods for longer than this value, the pod will be moved from unschedulablePods to backoffQ or activeQ. This flag is deprecated and will be removed in 1.26") +} diff --git a/vendor/k8s.io/kubernetes/cmd/kube-scheduler/app/options/options.go b/vendor/k8s.io/kubernetes/cmd/kube-scheduler/app/options/options.go new file mode 100644 index 000000000..dfc7ce863 --- /dev/null +++ b/vendor/k8s.io/kubernetes/cmd/kube-scheduler/app/options/options.go @@ -0,0 +1,379 @@ +/* +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 options + +import ( + "fmt" + "net" + "os" + "time" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/uuid" + apiserveroptions "k8s.io/apiserver/pkg/server/options" + utilfeature "k8s.io/apiserver/pkg/util/feature" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/dynamic/dynamicinformer" + clientset "k8s.io/client-go/kubernetes" + restclient "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/client-go/tools/events" + "k8s.io/client-go/tools/leaderelection" + "k8s.io/client-go/tools/leaderelection/resourcelock" + "k8s.io/client-go/tools/record" + cliflag "k8s.io/component-base/cli/flag" + componentbaseconfig "k8s.io/component-base/config" + "k8s.io/component-base/config/options" + "k8s.io/component-base/logs" + logsapi "k8s.io/component-base/logs/api/v1" + "k8s.io/component-base/metrics" + schedulerappconfig "k8s.io/kubernetes/cmd/kube-scheduler/app/config" + "k8s.io/kubernetes/pkg/scheduler" + kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/kubernetes/pkg/scheduler/apis/config/validation" + netutils "k8s.io/utils/net" +) + +// Options has all the params needed to run a Scheduler +type Options struct { + // The default values. + ComponentConfig *kubeschedulerconfig.KubeSchedulerConfiguration + + SecureServing *apiserveroptions.SecureServingOptionsWithLoopback + Authentication *apiserveroptions.DelegatingAuthenticationOptions + Authorization *apiserveroptions.DelegatingAuthorizationOptions + Metrics *metrics.Options + Logs *logs.Options + Deprecated *DeprecatedOptions + LeaderElection *componentbaseconfig.LeaderElectionConfiguration + + // ConfigFile is the location of the scheduler server's configuration file. + ConfigFile string + + // WriteConfigTo is the path where the default configuration will be written. + WriteConfigTo string + + Master string + + // Flags hold the parsed CLI flags. + Flags *cliflag.NamedFlagSets +} + +// NewOptions returns default scheduler app options. +func NewOptions() *Options { + o := &Options{ + SecureServing: apiserveroptions.NewSecureServingOptions().WithLoopback(), + Authentication: apiserveroptions.NewDelegatingAuthenticationOptions(), + Authorization: apiserveroptions.NewDelegatingAuthorizationOptions(), + Deprecated: &DeprecatedOptions{ + PodMaxInUnschedulablePodsDuration: 5 * time.Minute, + }, + LeaderElection: &componentbaseconfig.LeaderElectionConfiguration{ + LeaderElect: true, + LeaseDuration: metav1.Duration{Duration: 15 * time.Second}, + RenewDeadline: metav1.Duration{Duration: 10 * time.Second}, + RetryPeriod: metav1.Duration{Duration: 2 * time.Second}, + ResourceLock: "leases", + ResourceName: "kube-scheduler", + ResourceNamespace: "kube-system", + }, + Metrics: metrics.NewOptions(), + Logs: logs.NewOptions(), + } + + o.Authentication.TolerateInClusterLookupFailure = true + o.Authentication.RemoteKubeConfigFileOptional = true + o.Authorization.RemoteKubeConfigFileOptional = true + + // Set the PairName but leave certificate directory blank to generate in-memory by default + o.SecureServing.ServerCert.CertDirectory = "" + o.SecureServing.ServerCert.PairName = "kube-scheduler" + o.SecureServing.BindPort = kubeschedulerconfig.DefaultKubeSchedulerPort + + o.initFlags() + + return o +} + +// ApplyDeprecated obtains the deprecated CLI args and set them to `o.ComponentConfig` if specified. +func (o *Options) ApplyDeprecated() { + if o.Flags == nil { + return + } + // Obtain deprecated CLI args. Set them to cfg if specified in command line. + deprecated := o.Flags.FlagSet("deprecated") + if deprecated.Changed("profiling") { + o.ComponentConfig.EnableProfiling = o.Deprecated.EnableProfiling + } + if deprecated.Changed("contention-profiling") { + o.ComponentConfig.EnableContentionProfiling = o.Deprecated.EnableContentionProfiling + } + if deprecated.Changed("kubeconfig") { + o.ComponentConfig.ClientConnection.Kubeconfig = o.Deprecated.Kubeconfig + } + if deprecated.Changed("kube-api-content-type") { + o.ComponentConfig.ClientConnection.ContentType = o.Deprecated.ContentType + } + if deprecated.Changed("kube-api-qps") { + o.ComponentConfig.ClientConnection.QPS = o.Deprecated.QPS + } + if deprecated.Changed("kube-api-burst") { + o.ComponentConfig.ClientConnection.Burst = o.Deprecated.Burst + } + if deprecated.Changed("lock-object-namespace") { + o.ComponentConfig.LeaderElection.ResourceNamespace = o.Deprecated.ResourceNamespace + } + if deprecated.Changed("lock-object-name") { + o.ComponentConfig.LeaderElection.ResourceName = o.Deprecated.ResourceName + } +} + +// ApplyLeaderElectionTo obtains the CLI args related with leaderelection, and override the values in `cfg`. +// Then the `cfg` object is injected into the `options` object. +func (o *Options) ApplyLeaderElectionTo(cfg *kubeschedulerconfig.KubeSchedulerConfiguration) { + if o.Flags == nil { + return + } + // Obtain CLI args related with leaderelection. Set them to `cfg` if specified in command line. + leaderelection := o.Flags.FlagSet("leader election") + if leaderelection.Changed("leader-elect") { + cfg.LeaderElection.LeaderElect = o.LeaderElection.LeaderElect + } + if leaderelection.Changed("leader-elect-lease-duration") { + cfg.LeaderElection.LeaseDuration = o.LeaderElection.LeaseDuration + } + if leaderelection.Changed("leader-elect-renew-deadline") { + cfg.LeaderElection.RenewDeadline = o.LeaderElection.RenewDeadline + } + if leaderelection.Changed("leader-elect-retry-period") { + cfg.LeaderElection.RetryPeriod = o.LeaderElection.RetryPeriod + } + if leaderelection.Changed("leader-elect-resource-lock") { + cfg.LeaderElection.ResourceLock = o.LeaderElection.ResourceLock + } + if leaderelection.Changed("leader-elect-resource-name") { + cfg.LeaderElection.ResourceName = o.LeaderElection.ResourceName + } + if leaderelection.Changed("leader-elect-resource-namespace") { + cfg.LeaderElection.ResourceNamespace = o.LeaderElection.ResourceNamespace + } + + o.ComponentConfig = cfg +} + +// initFlags initializes flags by section name. +func (o *Options) initFlags() { + if o.Flags != nil { + return + } + + nfs := cliflag.NamedFlagSets{} + fs := nfs.FlagSet("misc") + fs.StringVar(&o.ConfigFile, "config", o.ConfigFile, "The path to the configuration file.") + fs.StringVar(&o.WriteConfigTo, "write-config-to", o.WriteConfigTo, "If set, write the configuration values to this file and exit.") + fs.StringVar(&o.Master, "master", o.Master, "The address of the Kubernetes API server (overrides any value in kubeconfig)") + + o.SecureServing.AddFlags(nfs.FlagSet("secure serving")) + o.Authentication.AddFlags(nfs.FlagSet("authentication")) + o.Authorization.AddFlags(nfs.FlagSet("authorization")) + o.Deprecated.AddFlags(nfs.FlagSet("deprecated")) + options.BindLeaderElectionFlags(o.LeaderElection, nfs.FlagSet("leader election")) + utilfeature.DefaultMutableFeatureGate.AddFlag(nfs.FlagSet("feature gate")) + o.Metrics.AddFlags(nfs.FlagSet("metrics")) + logsapi.AddFlags(o.Logs, nfs.FlagSet("logs")) + + o.Flags = &nfs +} + +// ApplyTo applies the scheduler options to the given scheduler app configuration. +func (o *Options) ApplyTo(c *schedulerappconfig.Config) error { + if len(o.ConfigFile) == 0 { + // If the --config arg is not specified, honor the deprecated as well as leader election CLI args. + o.ApplyDeprecated() + o.ApplyLeaderElectionTo(o.ComponentConfig) + c.ComponentConfig = *o.ComponentConfig + } else { + cfg, err := loadConfigFromFile(o.ConfigFile) + if err != nil { + return err + } + // If the --config arg is specified, honor the leader election CLI args only. + o.ApplyLeaderElectionTo(cfg) + + if err := validation.ValidateKubeSchedulerConfiguration(cfg); err != nil { + return err + } + + c.ComponentConfig = *cfg + } + + // Build kubeconfig first to so that if it fails, it doesn't cause leaking + // goroutines (started from initializing secure serving - which underneath + // creates a queue which in its constructor starts a goroutine). + kubeConfig, err := createKubeConfig(c.ComponentConfig.ClientConnection, o.Master) + if err != nil { + return err + } + c.KubeConfig = kubeConfig + + if err := o.SecureServing.ApplyTo(&c.SecureServing, &c.LoopbackClientConfig); err != nil { + return err + } + if o.SecureServing != nil && (o.SecureServing.BindPort != 0 || o.SecureServing.Listener != nil) { + if err := o.Authentication.ApplyTo(&c.Authentication, c.SecureServing, nil); err != nil { + return err + } + if err := o.Authorization.ApplyTo(&c.Authorization); err != nil { + return err + } + } + o.Metrics.Apply() + + // Apply value independently instead of using ApplyDeprecated() because it can't be configured via ComponentConfig. + if o.Deprecated != nil { + c.PodMaxInUnschedulablePodsDuration = o.Deprecated.PodMaxInUnschedulablePodsDuration + } + + return nil +} + +// Validate validates all the required options. +func (o *Options) Validate() []error { + var errs []error + + if err := validation.ValidateKubeSchedulerConfiguration(o.ComponentConfig); err != nil { + errs = append(errs, err.Errors()...) + } + errs = append(errs, o.SecureServing.Validate()...) + errs = append(errs, o.Authentication.Validate()...) + errs = append(errs, o.Authorization.Validate()...) + errs = append(errs, o.Metrics.Validate()...) + + return errs +} + +// Config return a scheduler config object +func (o *Options) Config() (*schedulerappconfig.Config, error) { + if o.SecureServing != nil { + if err := o.SecureServing.MaybeDefaultWithSelfSignedCerts("localhost", nil, []net.IP{netutils.ParseIPSloppy("127.0.0.1")}); err != nil { + return nil, fmt.Errorf("error creating self-signed certificates: %v", err) + } + } + + c := &schedulerappconfig.Config{} + if err := o.ApplyTo(c); err != nil { + return nil, err + } + + // Prepare kube clients. + client, eventClient, err := createClients(c.KubeConfig) + if err != nil { + return nil, err + } + + c.EventBroadcaster = events.NewEventBroadcasterAdapter(eventClient) + + // Set up leader election if enabled. + var leaderElectionConfig *leaderelection.LeaderElectionConfig + if c.ComponentConfig.LeaderElection.LeaderElect { + // Use the scheduler name in the first profile to record leader election. + schedulerName := corev1.DefaultSchedulerName + if len(c.ComponentConfig.Profiles) != 0 { + schedulerName = c.ComponentConfig.Profiles[0].SchedulerName + } + coreRecorder := c.EventBroadcaster.DeprecatedNewLegacyRecorder(schedulerName) + leaderElectionConfig, err = makeLeaderElectionConfig(c.ComponentConfig.LeaderElection, c.KubeConfig, coreRecorder) + if err != nil { + return nil, err + } + } + + c.Client = client + c.InformerFactory = scheduler.NewInformerFactory(client, 0) + dynClient := dynamic.NewForConfigOrDie(c.KubeConfig) + c.DynInformerFactory = dynamicinformer.NewFilteredDynamicSharedInformerFactory(dynClient, 0, corev1.NamespaceAll, nil) + c.LeaderElection = leaderElectionConfig + + return c, nil +} + +// makeLeaderElectionConfig builds a leader election configuration. It will +// create a new resource lock associated with the configuration. +func makeLeaderElectionConfig(config componentbaseconfig.LeaderElectionConfiguration, kubeConfig *restclient.Config, recorder record.EventRecorder) (*leaderelection.LeaderElectionConfig, error) { + hostname, err := os.Hostname() + if err != nil { + return nil, fmt.Errorf("unable to get hostname: %v", err) + } + // add a uniquifier so that two processes on the same host don't accidentally both become active + id := hostname + "_" + string(uuid.NewUUID()) + + rl, err := resourcelock.NewFromKubeconfig(config.ResourceLock, + config.ResourceNamespace, + config.ResourceName, + resourcelock.ResourceLockConfig{ + Identity: id, + EventRecorder: recorder, + }, + kubeConfig, + config.RenewDeadline.Duration) + if err != nil { + return nil, fmt.Errorf("couldn't create resource lock: %v", err) + } + + return &leaderelection.LeaderElectionConfig{ + Lock: rl, + LeaseDuration: config.LeaseDuration.Duration, + RenewDeadline: config.RenewDeadline.Duration, + RetryPeriod: config.RetryPeriod.Duration, + WatchDog: leaderelection.NewLeaderHealthzAdaptor(time.Second * 20), + Name: "kube-scheduler", + ReleaseOnCancel: true, + }, nil +} + +// createKubeConfig creates a kubeConfig from the given config and masterOverride. +// TODO remove masterOverride when CLI flags are removed. +func createKubeConfig(config componentbaseconfig.ClientConnectionConfiguration, masterOverride string) (*restclient.Config, error) { + kubeConfig, err := clientcmd.BuildConfigFromFlags(masterOverride, config.Kubeconfig) + if err != nil { + return nil, err + } + + kubeConfig.DisableCompression = true + kubeConfig.AcceptContentTypes = config.AcceptContentTypes + kubeConfig.ContentType = config.ContentType + kubeConfig.QPS = config.QPS + kubeConfig.Burst = int(config.Burst) + + return kubeConfig, nil +} + +// createClients creates a kube client and an event client from the given kubeConfig +func createClients(kubeConfig *restclient.Config) (clientset.Interface, clientset.Interface, error) { + client, err := clientset.NewForConfig(restclient.AddUserAgent(kubeConfig, "scheduler")) + if err != nil { + return nil, nil, err + } + + eventClient, err := clientset.NewForConfig(kubeConfig) + if err != nil { + return nil, nil, err + } + + return client, eventClient, nil +} diff --git a/vendor/k8s.io/kubernetes/cmd/kube-scheduler/app/server.go b/vendor/k8s.io/kubernetes/cmd/kube-scheduler/app/server.go new file mode 100644 index 000000000..8d01f3b76 --- /dev/null +++ b/vendor/k8s.io/kubernetes/cmd/kube-scheduler/app/server.go @@ -0,0 +1,364 @@ +/* +Copyright 2014 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 app implements a Server object for running the scheduler. +package app + +import ( + "context" + "fmt" + "net/http" + "os" + goruntime "runtime" + + "github.com/spf13/cobra" + + utilerrors "k8s.io/apimachinery/pkg/util/errors" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apiserver/pkg/authentication/authenticator" + "k8s.io/apiserver/pkg/authorization/authorizer" + genericapifilters "k8s.io/apiserver/pkg/endpoints/filters" + apirequest "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/apiserver/pkg/server" + genericfilters "k8s.io/apiserver/pkg/server/filters" + "k8s.io/apiserver/pkg/server/healthz" + "k8s.io/apiserver/pkg/server/mux" + "k8s.io/apiserver/pkg/server/routes" + utilfeature "k8s.io/apiserver/pkg/util/feature" + "k8s.io/client-go/informers" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/tools/events" + "k8s.io/client-go/tools/leaderelection" + cliflag "k8s.io/component-base/cli/flag" + "k8s.io/component-base/cli/globalflag" + "k8s.io/component-base/configz" + "k8s.io/component-base/logs" + logsapi "k8s.io/component-base/logs/api/v1" + "k8s.io/component-base/metrics/features" + "k8s.io/component-base/metrics/legacyregistry" + "k8s.io/component-base/metrics/prometheus/slis" + "k8s.io/component-base/term" + "k8s.io/component-base/version" + "k8s.io/component-base/version/verflag" + "k8s.io/klog/v2" + schedulerserverconfig "k8s.io/kubernetes/cmd/kube-scheduler/app/config" + "k8s.io/kubernetes/cmd/kube-scheduler/app/options" + "k8s.io/kubernetes/pkg/scheduler" + kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/kubernetes/pkg/scheduler/apis/config/latest" + "k8s.io/kubernetes/pkg/scheduler/framework/runtime" + "k8s.io/kubernetes/pkg/scheduler/metrics/resources" + "k8s.io/kubernetes/pkg/scheduler/profile" +) + +func init() { + utilruntime.Must(logsapi.AddFeatureGates(utilfeature.DefaultMutableFeatureGate)) + utilruntime.Must(features.AddFeatureGates(utilfeature.DefaultMutableFeatureGate)) +} + +// Option configures a framework.Registry. +type Option func(runtime.Registry) error + +// NewSchedulerCommand creates a *cobra.Command object with default parameters and registryOptions +func NewSchedulerCommand(registryOptions ...Option) *cobra.Command { + opts := options.NewOptions() + + cmd := &cobra.Command{ + Use: "kube-scheduler", + Long: `The Kubernetes scheduler is a control plane process which assigns +Pods to Nodes. The scheduler determines which Nodes are valid placements for +each Pod in the scheduling queue according to constraints and available +resources. The scheduler then ranks each valid Node and binds the Pod to a +suitable Node. Multiple different schedulers may be used within a cluster; +kube-scheduler is the reference implementation. +See [scheduling](https://kubernetes.io/docs/concepts/scheduling-eviction/) +for more information about scheduling and the kube-scheduler component.`, + RunE: func(cmd *cobra.Command, args []string) error { + return runCommand(cmd, opts, registryOptions...) + }, + Args: func(cmd *cobra.Command, args []string) error { + for _, arg := range args { + if len(arg) > 0 { + return fmt.Errorf("%q does not take any arguments, got %q", cmd.CommandPath(), args) + } + } + return nil + }, + } + + nfs := opts.Flags + verflag.AddFlags(nfs.FlagSet("global")) + globalflag.AddGlobalFlags(nfs.FlagSet("global"), cmd.Name(), logs.SkipLoggingConfigurationFlags()) + fs := cmd.Flags() + for _, f := range nfs.FlagSets { + fs.AddFlagSet(f) + } + + cols, _, _ := term.TerminalSize(cmd.OutOrStdout()) + cliflag.SetUsageAndHelpFunc(cmd, *nfs, cols) + + if err := cmd.MarkFlagFilename("config", "yaml", "yml", "json"); err != nil { + klog.ErrorS(err, "Failed to mark flag filename") + } + + return cmd +} + +// runCommand runs the scheduler. +func runCommand(cmd *cobra.Command, opts *options.Options, registryOptions ...Option) error { + verflag.PrintAndExitIfRequested() + + // Activate logging as soon as possible, after that + // show flags with the final logging configuration. + if err := logsapi.ValidateAndApply(opts.Logs, utilfeature.DefaultFeatureGate); err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + os.Exit(1) + } + cliflag.PrintFlags(cmd.Flags()) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + go func() { + stopCh := server.SetupSignalHandler() + <-stopCh + cancel() + }() + + cc, sched, err := Setup(ctx, opts, registryOptions...) + if err != nil { + return err + } + // add feature enablement metrics + utilfeature.DefaultMutableFeatureGate.AddMetrics() + return Run(ctx, cc, sched) +} + +// Run executes the scheduler based on the given configuration. It only returns on error or when context is done. +func Run(ctx context.Context, cc *schedulerserverconfig.CompletedConfig, sched *scheduler.Scheduler) error { + // To help debugging, immediately log version + klog.InfoS("Starting Kubernetes Scheduler", "version", version.Get()) + + klog.InfoS("Golang settings", "GOGC", os.Getenv("GOGC"), "GOMAXPROCS", os.Getenv("GOMAXPROCS"), "GOTRACEBACK", os.Getenv("GOTRACEBACK")) + + // Configz registration. + if cz, err := configz.New("componentconfig"); err == nil { + cz.Set(cc.ComponentConfig) + } else { + return fmt.Errorf("unable to register configz: %s", err) + } + + // Start events processing pipeline. + cc.EventBroadcaster.StartRecordingToSink(ctx.Done()) + defer cc.EventBroadcaster.Shutdown() + + // Setup healthz checks. + var checks []healthz.HealthChecker + if cc.ComponentConfig.LeaderElection.LeaderElect { + checks = append(checks, cc.LeaderElection.WatchDog) + } + + waitingForLeader := make(chan struct{}) + isLeader := func() bool { + select { + case _, ok := <-waitingForLeader: + // if channel is closed, we are leading + return !ok + default: + // channel is open, we are waiting for a leader + return false + } + } + + // Start up the healthz server. + if cc.SecureServing != nil { + handler := buildHandlerChain(newHealthzAndMetricsHandler(&cc.ComponentConfig, cc.InformerFactory, isLeader, checks...), cc.Authentication.Authenticator, cc.Authorization.Authorizer) + // TODO: handle stoppedCh and listenerStoppedCh returned by c.SecureServing.Serve + if _, _, err := cc.SecureServing.Serve(handler, 0, ctx.Done()); err != nil { + // fail early for secure handlers, removing the old error loop from above + return fmt.Errorf("failed to start secure server: %v", err) + } + } + + // Start all informers. + cc.InformerFactory.Start(ctx.Done()) + // DynInformerFactory can be nil in tests. + if cc.DynInformerFactory != nil { + cc.DynInformerFactory.Start(ctx.Done()) + } + + // Wait for all caches to sync before scheduling. + cc.InformerFactory.WaitForCacheSync(ctx.Done()) + // DynInformerFactory can be nil in tests. + if cc.DynInformerFactory != nil { + cc.DynInformerFactory.WaitForCacheSync(ctx.Done()) + } + + // If leader election is enabled, runCommand via LeaderElector until done and exit. + if cc.LeaderElection != nil { + cc.LeaderElection.Callbacks = leaderelection.LeaderCallbacks{ + OnStartedLeading: func(ctx context.Context) { + close(waitingForLeader) + sched.Run(ctx) + }, + OnStoppedLeading: func() { + select { + case <-ctx.Done(): + // We were asked to terminate. Exit 0. + klog.InfoS("Requested to terminate, exiting") + os.Exit(0) + default: + // We lost the lock. + klog.ErrorS(nil, "Leaderelection lost") + klog.FlushAndExit(klog.ExitFlushTimeout, 1) + } + }, + } + leaderElector, err := leaderelection.NewLeaderElector(*cc.LeaderElection) + if err != nil { + return fmt.Errorf("couldn't create leader elector: %v", err) + } + + leaderElector.Run(ctx) + + return fmt.Errorf("lost lease") + } + + // Leader election is disabled, so runCommand inline until done. + close(waitingForLeader) + sched.Run(ctx) + return fmt.Errorf("finished without leader elect") +} + +// buildHandlerChain wraps the given handler with the standard filters. +func buildHandlerChain(handler http.Handler, authn authenticator.Request, authz authorizer.Authorizer) http.Handler { + requestInfoResolver := &apirequest.RequestInfoFactory{} + failedHandler := genericapifilters.Unauthorized(scheme.Codecs) + + handler = genericapifilters.WithAuthorization(handler, authz, scheme.Codecs) + handler = genericapifilters.WithAuthentication(handler, authn, failedHandler, nil) + handler = genericapifilters.WithRequestInfo(handler, requestInfoResolver) + handler = genericapifilters.WithCacheControl(handler) + handler = genericfilters.WithHTTPLogging(handler) + handler = genericfilters.WithPanicRecovery(handler, requestInfoResolver) + + return handler +} + +func installMetricHandler(pathRecorderMux *mux.PathRecorderMux, informers informers.SharedInformerFactory, isLeader func() bool) { + configz.InstallHandler(pathRecorderMux) + pathRecorderMux.Handle("/metrics", legacyregistry.HandlerWithReset()) + + resourceMetricsHandler := resources.Handler(informers.Core().V1().Pods().Lister()) + pathRecorderMux.HandleFunc("/metrics/resources", func(w http.ResponseWriter, req *http.Request) { + if !isLeader() { + return + } + resourceMetricsHandler.ServeHTTP(w, req) + }) +} + +// newHealthzAndMetricsHandler creates a healthz server from the config, and will also +// embed the metrics handler. +func newHealthzAndMetricsHandler(config *kubeschedulerconfig.KubeSchedulerConfiguration, informers informers.SharedInformerFactory, isLeader func() bool, checks ...healthz.HealthChecker) http.Handler { + pathRecorderMux := mux.NewPathRecorderMux("kube-scheduler") + healthz.InstallHandler(pathRecorderMux, checks...) + installMetricHandler(pathRecorderMux, informers, isLeader) + if utilfeature.DefaultFeatureGate.Enabled(features.ComponentSLIs) { + slis.SLIMetricsWithReset{}.Install(pathRecorderMux) + } + if config.EnableProfiling { + routes.Profiling{}.Install(pathRecorderMux) + if config.EnableContentionProfiling { + goruntime.SetBlockProfileRate(1) + } + routes.DebugFlags{}.Install(pathRecorderMux, "v", routes.StringFlagPutHandler(logs.GlogSetter)) + } + return pathRecorderMux +} + +func getRecorderFactory(cc *schedulerserverconfig.CompletedConfig) profile.RecorderFactory { + return func(name string) events.EventRecorder { + return cc.EventBroadcaster.NewRecorder(name) + } +} + +// WithPlugin creates an Option based on plugin name and factory. Please don't remove this function: it is used to register out-of-tree plugins, +// hence there are no references to it from the kubernetes scheduler code base. +func WithPlugin(name string, factory runtime.PluginFactory) Option { + return func(registry runtime.Registry) error { + return registry.Register(name, factory) + } +} + +// Setup creates a completed config and a scheduler based on the command args and options +func Setup(ctx context.Context, opts *options.Options, outOfTreeRegistryOptions ...Option) (*schedulerserverconfig.CompletedConfig, *scheduler.Scheduler, error) { + if cfg, err := latest.Default(); err != nil { + return nil, nil, err + } else { + opts.ComponentConfig = cfg + } + + if errs := opts.Validate(); len(errs) > 0 { + return nil, nil, utilerrors.NewAggregate(errs) + } + + c, err := opts.Config() + if err != nil { + return nil, nil, err + } + + // Get the completed config + cc := c.Complete() + + outOfTreeRegistry := make(runtime.Registry) + for _, option := range outOfTreeRegistryOptions { + if err := option(outOfTreeRegistry); err != nil { + return nil, nil, err + } + } + + recorderFactory := getRecorderFactory(&cc) + completedProfiles := make([]kubeschedulerconfig.KubeSchedulerProfile, 0) + // Create the scheduler. + sched, err := scheduler.New(cc.Client, + cc.InformerFactory, + cc.DynInformerFactory, + recorderFactory, + ctx.Done(), + scheduler.WithComponentConfigVersion(cc.ComponentConfig.TypeMeta.APIVersion), + scheduler.WithKubeConfig(cc.KubeConfig), + scheduler.WithProfiles(cc.ComponentConfig.Profiles...), + scheduler.WithPercentageOfNodesToScore(cc.ComponentConfig.PercentageOfNodesToScore), + scheduler.WithFrameworkOutOfTreeRegistry(outOfTreeRegistry), + scheduler.WithPodMaxBackoffSeconds(cc.ComponentConfig.PodMaxBackoffSeconds), + scheduler.WithPodInitialBackoffSeconds(cc.ComponentConfig.PodInitialBackoffSeconds), + scheduler.WithPodMaxInUnschedulablePodsDuration(cc.PodMaxInUnschedulablePodsDuration), + scheduler.WithExtenders(cc.ComponentConfig.Extenders...), + scheduler.WithParallelism(cc.ComponentConfig.Parallelism), + scheduler.WithBuildFrameworkCapturer(func(profile kubeschedulerconfig.KubeSchedulerProfile) { + // Profiles are processed during Framework instantiation to set default plugins and configurations. Capturing them for logging + completedProfiles = append(completedProfiles, profile) + }), + ) + if err != nil { + return nil, nil, err + } + if err := options.LogOrWriteConfig(opts.WriteConfigTo, &cc.ComponentConfig, completedProfiles); err != nil { + return nil, nil, err + } + + return &cc, sched, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/api/legacyscheme/scheme.go b/vendor/k8s.io/kubernetes/pkg/api/legacyscheme/scheme.go new file mode 100644 index 000000000..f9baf7a01 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/api/legacyscheme/scheme.go @@ -0,0 +1,37 @@ +/* +Copyright 2014 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 legacyscheme + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" +) + +var ( + // Scheme is the default instance of runtime.Scheme to which types in the Kubernetes API are already registered. + // NOTE: If you are copying this file to start a new api group, STOP! Copy the + // extensions group instead. This Scheme is special and should appear ONLY in + // the api group, unless you really know what you're doing. + // TODO(lavalamp): make the above error impossible. + Scheme = runtime.NewScheme() + + // Codecs provides access to encoding and decoding for the scheme + Codecs = serializer.NewCodecFactory(Scheme) + + // ParameterCodec handles versioning of objects that are converted to query parameters. + ParameterCodec = runtime.NewParameterCodec(Scheme) +) diff --git a/vendor/k8s.io/kubernetes/pkg/api/service/OWNERS b/vendor/k8s.io/kubernetes/pkg/api/service/OWNERS new file mode 100644 index 000000000..a1efa9b2a --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/api/service/OWNERS @@ -0,0 +1,5 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +reviewers: + - justinsb + - freehan diff --git a/vendor/k8s.io/kubernetes/pkg/api/service/util.go b/vendor/k8s.io/kubernetes/pkg/api/service/util.go new file mode 100644 index 000000000..a4262edad --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/api/service/util.go @@ -0,0 +1,86 @@ +/* +Copyright 2016 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 service + +import ( + "fmt" + "strings" + + api "k8s.io/kubernetes/pkg/apis/core" + utilnet "k8s.io/utils/net" +) + +const ( + defaultLoadBalancerSourceRanges = "0.0.0.0/0" +) + +// IsAllowAll checks whether the utilnet.IPNet allows traffic from 0.0.0.0/0 +func IsAllowAll(ipnets utilnet.IPNetSet) bool { + for _, s := range ipnets.StringSlice() { + if s == "0.0.0.0/0" { + return true + } + } + return false +} + +// GetLoadBalancerSourceRanges first try to parse and verify LoadBalancerSourceRanges field from a service. +// If the field is not specified, turn to parse and verify the AnnotationLoadBalancerSourceRangesKey annotation from a service, +// extracting the source ranges to allow, and if not present returns a default (allow-all) value. +func GetLoadBalancerSourceRanges(service *api.Service) (utilnet.IPNetSet, error) { + var ipnets utilnet.IPNetSet + var err error + // if SourceRange field is specified, ignore sourceRange annotation + if len(service.Spec.LoadBalancerSourceRanges) > 0 { + specs := service.Spec.LoadBalancerSourceRanges + ipnets, err = utilnet.ParseIPNets(specs...) + + if err != nil { + return nil, fmt.Errorf("service.Spec.LoadBalancerSourceRanges: %v is not valid. Expecting a list of IP ranges. For example, 10.0.0.0/24. Error msg: %v", specs, err) + } + } else { + val := service.Annotations[api.AnnotationLoadBalancerSourceRangesKey] + val = strings.TrimSpace(val) + if val == "" { + val = defaultLoadBalancerSourceRanges + } + specs := strings.Split(val, ",") + ipnets, err = utilnet.ParseIPNets(specs...) + if err != nil { + return nil, fmt.Errorf("%s: %s is not valid. Expecting a comma-separated list of source IP ranges. For example, 10.0.0.0/24,192.168.2.0/24", api.AnnotationLoadBalancerSourceRangesKey, val) + } + } + return ipnets, nil +} + +// RequestsOnlyLocalTraffic checks if service requests OnlyLocal traffic. +func RequestsOnlyLocalTraffic(service *api.Service) bool { + if service.Spec.Type != api.ServiceTypeLoadBalancer && + service.Spec.Type != api.ServiceTypeNodePort { + return false + } + + return service.Spec.ExternalTrafficPolicy == api.ServiceExternalTrafficPolicyTypeLocal +} + +// NeedsHealthCheck checks if service needs health check. +func NeedsHealthCheck(service *api.Service) bool { + if service.Spec.Type != api.ServiceTypeLoadBalancer { + return false + } + return RequestsOnlyLocalTraffic(service) +} diff --git a/vendor/k8s.io/kubernetes/pkg/api/v1/pod/util.go b/vendor/k8s.io/kubernetes/pkg/api/v1/pod/util.go new file mode 100644 index 000000000..dc526b62e --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/api/v1/pod/util.go @@ -0,0 +1,386 @@ +/* +Copyright 2015 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 pod + +import ( + "fmt" + "time" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" +) + +// FindPort locates the container port for the given pod and portName. If the +// targetPort is a number, use that. If the targetPort is a string, look that +// string up in all named ports in all containers in the target pod. If no +// match is found, fail. +func FindPort(pod *v1.Pod, svcPort *v1.ServicePort) (int, error) { + portName := svcPort.TargetPort + switch portName.Type { + case intstr.String: + name := portName.StrVal + for _, container := range pod.Spec.Containers { + for _, port := range container.Ports { + if port.Name == name && port.Protocol == svcPort.Protocol { + return int(port.ContainerPort), nil + } + } + } + case intstr.Int: + return portName.IntValue(), nil + } + + return 0, fmt.Errorf("no suitable port for manifest: %s", pod.UID) +} + +// ContainerType signifies container type +type ContainerType int + +const ( + // Containers is for normal containers + Containers ContainerType = 1 << iota + // InitContainers is for init containers + InitContainers + // EphemeralContainers is for ephemeral containers + EphemeralContainers +) + +// AllContainers specifies that all containers be visited +const AllContainers ContainerType = InitContainers | Containers | EphemeralContainers + +// AllFeatureEnabledContainers returns a ContainerType mask which includes all container +// types except for the ones guarded by feature gate. +func AllFeatureEnabledContainers() ContainerType { + return AllContainers +} + +// ContainerVisitor is called with each container spec, and returns true +// if visiting should continue. +type ContainerVisitor func(container *v1.Container, containerType ContainerType) (shouldContinue bool) + +// Visitor is called with each object name, and returns true if visiting should continue +type Visitor func(name string) (shouldContinue bool) + +func skipEmptyNames(visitor Visitor) Visitor { + return func(name string) bool { + if len(name) == 0 { + // continue visiting + return true + } + // delegate to visitor + return visitor(name) + } +} + +// VisitContainers invokes the visitor function with a pointer to every container +// spec in the given pod spec with type set in mask. If visitor returns false, +// visiting is short-circuited. VisitContainers returns true if visiting completes, +// false if visiting was short-circuited. +func VisitContainers(podSpec *v1.PodSpec, mask ContainerType, visitor ContainerVisitor) bool { + if mask&InitContainers != 0 { + for i := range podSpec.InitContainers { + if !visitor(&podSpec.InitContainers[i], InitContainers) { + return false + } + } + } + if mask&Containers != 0 { + for i := range podSpec.Containers { + if !visitor(&podSpec.Containers[i], Containers) { + return false + } + } + } + if mask&EphemeralContainers != 0 { + for i := range podSpec.EphemeralContainers { + if !visitor((*v1.Container)(&podSpec.EphemeralContainers[i].EphemeralContainerCommon), EphemeralContainers) { + return false + } + } + } + return true +} + +// VisitPodSecretNames invokes the visitor function with the name of every secret +// referenced by the pod spec. If visitor returns false, visiting is short-circuited. +// Transitive references (e.g. pod -> pvc -> pv -> secret) are not visited. +// Returns true if visiting completed, false if visiting was short-circuited. +func VisitPodSecretNames(pod *v1.Pod, visitor Visitor) bool { + visitor = skipEmptyNames(visitor) + for _, reference := range pod.Spec.ImagePullSecrets { + if !visitor(reference.Name) { + return false + } + } + VisitContainers(&pod.Spec, AllContainers, func(c *v1.Container, containerType ContainerType) bool { + return visitContainerSecretNames(c, visitor) + }) + var source *v1.VolumeSource + + for i := range pod.Spec.Volumes { + source = &pod.Spec.Volumes[i].VolumeSource + switch { + case source.AzureFile != nil: + if len(source.AzureFile.SecretName) > 0 && !visitor(source.AzureFile.SecretName) { + return false + } + case source.CephFS != nil: + if source.CephFS.SecretRef != nil && !visitor(source.CephFS.SecretRef.Name) { + return false + } + case source.Cinder != nil: + if source.Cinder.SecretRef != nil && !visitor(source.Cinder.SecretRef.Name) { + return false + } + case source.FlexVolume != nil: + if source.FlexVolume.SecretRef != nil && !visitor(source.FlexVolume.SecretRef.Name) { + return false + } + case source.Projected != nil: + for j := range source.Projected.Sources { + if source.Projected.Sources[j].Secret != nil { + if !visitor(source.Projected.Sources[j].Secret.Name) { + return false + } + } + } + case source.RBD != nil: + if source.RBD.SecretRef != nil && !visitor(source.RBD.SecretRef.Name) { + return false + } + case source.Secret != nil: + if !visitor(source.Secret.SecretName) { + return false + } + case source.ScaleIO != nil: + if source.ScaleIO.SecretRef != nil && !visitor(source.ScaleIO.SecretRef.Name) { + return false + } + case source.ISCSI != nil: + if source.ISCSI.SecretRef != nil && !visitor(source.ISCSI.SecretRef.Name) { + return false + } + case source.StorageOS != nil: + if source.StorageOS.SecretRef != nil && !visitor(source.StorageOS.SecretRef.Name) { + return false + } + case source.CSI != nil: + if source.CSI.NodePublishSecretRef != nil && !visitor(source.CSI.NodePublishSecretRef.Name) { + return false + } + } + } + return true +} + +// visitContainerSecretNames returns true unless the visitor returned false when invoked with a secret reference +func visitContainerSecretNames(container *v1.Container, visitor Visitor) bool { + for _, env := range container.EnvFrom { + if env.SecretRef != nil { + if !visitor(env.SecretRef.Name) { + return false + } + } + } + for _, envVar := range container.Env { + if envVar.ValueFrom != nil && envVar.ValueFrom.SecretKeyRef != nil { + if !visitor(envVar.ValueFrom.SecretKeyRef.Name) { + return false + } + } + } + return true +} + +// VisitPodConfigmapNames invokes the visitor function with the name of every configmap +// referenced by the pod spec. If visitor returns false, visiting is short-circuited. +// Transitive references (e.g. pod -> pvc -> pv -> secret) are not visited. +// Returns true if visiting completed, false if visiting was short-circuited. +func VisitPodConfigmapNames(pod *v1.Pod, visitor Visitor) bool { + visitor = skipEmptyNames(visitor) + VisitContainers(&pod.Spec, AllContainers, func(c *v1.Container, containerType ContainerType) bool { + return visitContainerConfigmapNames(c, visitor) + }) + var source *v1.VolumeSource + for i := range pod.Spec.Volumes { + source = &pod.Spec.Volumes[i].VolumeSource + switch { + case source.Projected != nil: + for j := range source.Projected.Sources { + if source.Projected.Sources[j].ConfigMap != nil { + if !visitor(source.Projected.Sources[j].ConfigMap.Name) { + return false + } + } + } + case source.ConfigMap != nil: + if !visitor(source.ConfigMap.Name) { + return false + } + } + } + return true +} + +// visitContainerConfigmapNames returns true unless the visitor returned false when invoked with a configmap reference +func visitContainerConfigmapNames(container *v1.Container, visitor Visitor) bool { + for _, env := range container.EnvFrom { + if env.ConfigMapRef != nil { + if !visitor(env.ConfigMapRef.Name) { + return false + } + } + } + for _, envVar := range container.Env { + if envVar.ValueFrom != nil && envVar.ValueFrom.ConfigMapKeyRef != nil { + if !visitor(envVar.ValueFrom.ConfigMapKeyRef.Name) { + return false + } + } + } + return true +} + +// GetContainerStatus extracts the status of container "name" from "statuses". +// It also returns if "name" exists. +func GetContainerStatus(statuses []v1.ContainerStatus, name string) (v1.ContainerStatus, bool) { + for i := range statuses { + if statuses[i].Name == name { + return statuses[i], true + } + } + return v1.ContainerStatus{}, false +} + +// GetExistingContainerStatus extracts the status of container "name" from "statuses", +// It also returns if "name" exists. +func GetExistingContainerStatus(statuses []v1.ContainerStatus, name string) v1.ContainerStatus { + status, _ := GetContainerStatus(statuses, name) + return status +} + +// IsPodAvailable returns true if a pod is available; false otherwise. +// Precondition for an available pod is that it must be ready. On top +// of that, there are two cases when a pod can be considered available: +// 1. minReadySeconds == 0, or +// 2. LastTransitionTime (is set) + minReadySeconds < current time +func IsPodAvailable(pod *v1.Pod, minReadySeconds int32, now metav1.Time) bool { + if !IsPodReady(pod) { + return false + } + + c := GetPodReadyCondition(pod.Status) + minReadySecondsDuration := time.Duration(minReadySeconds) * time.Second + if minReadySeconds == 0 || (!c.LastTransitionTime.IsZero() && c.LastTransitionTime.Add(minReadySecondsDuration).Before(now.Time)) { + return true + } + return false +} + +// IsPodReady returns true if a pod is ready; false otherwise. +func IsPodReady(pod *v1.Pod) bool { + return IsPodReadyConditionTrue(pod.Status) +} + +// IsPodTerminal returns true if a pod is terminal, all containers are stopped and cannot ever regress. +func IsPodTerminal(pod *v1.Pod) bool { + return IsPodPhaseTerminal(pod.Status.Phase) +} + +// IsPodPhaseTerminal returns true if the pod's phase is terminal. +func IsPodPhaseTerminal(phase v1.PodPhase) bool { + return phase == v1.PodFailed || phase == v1.PodSucceeded +} + +// IsPodReadyConditionTrue returns true if a pod is ready; false otherwise. +func IsPodReadyConditionTrue(status v1.PodStatus) bool { + condition := GetPodReadyCondition(status) + return condition != nil && condition.Status == v1.ConditionTrue +} + +// IsContainersReadyConditionTrue returns true if a pod is ready; false otherwise. +func IsContainersReadyConditionTrue(status v1.PodStatus) bool { + condition := GetContainersReadyCondition(status) + return condition != nil && condition.Status == v1.ConditionTrue +} + +// GetPodReadyCondition extracts the pod ready condition from the given status and returns that. +// Returns nil if the condition is not present. +func GetPodReadyCondition(status v1.PodStatus) *v1.PodCondition { + _, condition := GetPodCondition(&status, v1.PodReady) + return condition +} + +// GetContainersReadyCondition extracts the containers ready condition from the given status and returns that. +// Returns nil if the condition is not present. +func GetContainersReadyCondition(status v1.PodStatus) *v1.PodCondition { + _, condition := GetPodCondition(&status, v1.ContainersReady) + return condition +} + +// GetPodCondition extracts the provided condition from the given status and returns that. +// Returns nil and -1 if the condition is not present, and the index of the located condition. +func GetPodCondition(status *v1.PodStatus, conditionType v1.PodConditionType) (int, *v1.PodCondition) { + if status == nil { + return -1, nil + } + return GetPodConditionFromList(status.Conditions, conditionType) +} + +// GetPodConditionFromList extracts the provided condition from the given list of condition and +// returns the index of the condition and the condition. Returns -1 and nil if the condition is not present. +func GetPodConditionFromList(conditions []v1.PodCondition, conditionType v1.PodConditionType) (int, *v1.PodCondition) { + if conditions == nil { + return -1, nil + } + for i := range conditions { + if conditions[i].Type == conditionType { + return i, &conditions[i] + } + } + return -1, nil +} + +// UpdatePodCondition updates existing pod condition or creates a new one. Sets LastTransitionTime to now if the +// status has changed. +// Returns true if pod condition has changed or has been added. +func UpdatePodCondition(status *v1.PodStatus, condition *v1.PodCondition) bool { + condition.LastTransitionTime = metav1.Now() + // Try to find this pod condition. + conditionIndex, oldCondition := GetPodCondition(status, condition.Type) + + if oldCondition == nil { + // We are adding new pod condition. + status.Conditions = append(status.Conditions, *condition) + return true + } + // We are updating an existing condition, so we need to check if it has changed. + if condition.Status == oldCondition.Status { + condition.LastTransitionTime = oldCondition.LastTransitionTime + } + + isEqual := condition.Status == oldCondition.Status && + condition.Reason == oldCondition.Reason && + condition.Message == oldCondition.Message && + condition.LastProbeTime.Equal(&oldCondition.LastProbeTime) && + condition.LastTransitionTime.Equal(&oldCondition.LastTransitionTime) + + status.Conditions[conditionIndex] = *condition + // Return true if one of the fields have changed. + return !isEqual +} diff --git a/vendor/k8s.io/kubernetes/pkg/api/v1/resource/helpers.go b/vendor/k8s.io/kubernetes/pkg/api/v1/resource/helpers.go new file mode 100644 index 000000000..8f77c9a27 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/api/v1/resource/helpers.go @@ -0,0 +1,303 @@ +/* +Copyright 2014 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 resource + +import ( + "fmt" + "math" + "strconv" + "strings" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" +) + +// PodRequestsAndLimits returns a dictionary of all defined resources summed up for all +// containers of the pod. Pod overhead is added to the +// total container resource requests and to the total container limits which have a +// non-zero quantity. +func PodRequestsAndLimits(pod *v1.Pod) (reqs, limits v1.ResourceList) { + return PodRequestsAndLimitsReuse(pod, nil, nil) +} + +// PodRequestsAndLimitsWithoutOverhead will create a dictionary of all defined resources summed up for all +// containers of the pod. +func PodRequestsAndLimitsWithoutOverhead(pod *v1.Pod) (reqs, limits v1.ResourceList) { + reqs = make(v1.ResourceList, 4) + limits = make(v1.ResourceList, 4) + podRequestsAndLimitsWithoutOverhead(pod, reqs, limits) + + return reqs, limits +} + +func podRequestsAndLimitsWithoutOverhead(pod *v1.Pod, reqs, limits v1.ResourceList) { + for _, container := range pod.Spec.Containers { + addResourceList(reqs, container.Resources.Requests) + addResourceList(limits, container.Resources.Limits) + } + // init containers define the minimum of any resource + for _, container := range pod.Spec.InitContainers { + maxResourceList(reqs, container.Resources.Requests) + maxResourceList(limits, container.Resources.Limits) + } +} + +// PodRequestsAndLimitsReuse returns a dictionary of all defined resources summed up for all +// containers of the pod. Pod overhead is added to the +// total container resource requests and to the total container limits which have a +// non-zero quantity. The caller may avoid allocations of resource lists by passing +// a requests and limits list to the function, which will be cleared before use. +func PodRequestsAndLimitsReuse(pod *v1.Pod, reuseReqs, reuseLimits v1.ResourceList) (reqs, limits v1.ResourceList) { + // attempt to reuse the maps if passed, or allocate otherwise + reqs, limits = reuseOrClearResourceList(reuseReqs), reuseOrClearResourceList(reuseLimits) + + podRequestsAndLimitsWithoutOverhead(pod, reqs, limits) + + // Add overhead for running a pod + // to the sum of requests and to non-zero limits: + if pod.Spec.Overhead != nil { + addResourceList(reqs, pod.Spec.Overhead) + + for name, quantity := range pod.Spec.Overhead { + if value, ok := limits[name]; ok && !value.IsZero() { + value.Add(quantity) + limits[name] = value + } + } + } + + return +} + +// reuseOrClearResourceList is a helper for avoiding excessive allocations of +// resource lists within the inner loop of resource calculations. +func reuseOrClearResourceList(reuse v1.ResourceList) v1.ResourceList { + if reuse == nil { + return make(v1.ResourceList, 4) + } + for k := range reuse { + delete(reuse, k) + } + return reuse +} + +// addResourceList adds the resources in newList to list. +func addResourceList(list, newList v1.ResourceList) { + for name, quantity := range newList { + if value, ok := list[name]; !ok { + list[name] = quantity.DeepCopy() + } else { + value.Add(quantity) + list[name] = value + } + } +} + +// maxResourceList sets list to the greater of list/newList for every resource in newList +func maxResourceList(list, newList v1.ResourceList) { + for name, quantity := range newList { + if value, ok := list[name]; !ok || quantity.Cmp(value) > 0 { + list[name] = quantity.DeepCopy() + } + } +} + +// GetResourceRequestQuantity finds and returns the request quantity for a specific resource. +func GetResourceRequestQuantity(pod *v1.Pod, resourceName v1.ResourceName) resource.Quantity { + requestQuantity := resource.Quantity{} + + switch resourceName { + case v1.ResourceCPU: + requestQuantity = resource.Quantity{Format: resource.DecimalSI} + case v1.ResourceMemory, v1.ResourceStorage, v1.ResourceEphemeralStorage: + requestQuantity = resource.Quantity{Format: resource.BinarySI} + default: + requestQuantity = resource.Quantity{Format: resource.DecimalSI} + } + + for _, container := range pod.Spec.Containers { + if rQuantity, ok := container.Resources.Requests[resourceName]; ok { + requestQuantity.Add(rQuantity) + } + } + + for _, container := range pod.Spec.InitContainers { + if rQuantity, ok := container.Resources.Requests[resourceName]; ok { + if requestQuantity.Cmp(rQuantity) < 0 { + requestQuantity = rQuantity.DeepCopy() + } + } + } + + // Add overhead for running a pod + // to the total requests if the resource total is non-zero + if pod.Spec.Overhead != nil { + if podOverhead, ok := pod.Spec.Overhead[resourceName]; ok && !requestQuantity.IsZero() { + requestQuantity.Add(podOverhead) + } + } + + return requestQuantity +} + +// GetResourceRequest finds and returns the request value for a specific resource. +func GetResourceRequest(pod *v1.Pod, resource v1.ResourceName) int64 { + if resource == v1.ResourcePods { + return 1 + } + + requestQuantity := GetResourceRequestQuantity(pod, resource) + + if resource == v1.ResourceCPU { + return requestQuantity.MilliValue() + } + + return requestQuantity.Value() +} + +// ExtractResourceValueByContainerName extracts the value of a resource +// by providing container name +func ExtractResourceValueByContainerName(fs *v1.ResourceFieldSelector, pod *v1.Pod, containerName string) (string, error) { + container, err := findContainerInPod(pod, containerName) + if err != nil { + return "", err + } + return ExtractContainerResourceValue(fs, container) +} + +// ExtractResourceValueByContainerNameAndNodeAllocatable extracts the value of a resource +// by providing container name and node allocatable +func ExtractResourceValueByContainerNameAndNodeAllocatable(fs *v1.ResourceFieldSelector, pod *v1.Pod, containerName string, nodeAllocatable v1.ResourceList) (string, error) { + realContainer, err := findContainerInPod(pod, containerName) + if err != nil { + return "", err + } + + container := realContainer.DeepCopy() + + MergeContainerResourceLimits(container, nodeAllocatable) + + return ExtractContainerResourceValue(fs, container) +} + +// ExtractContainerResourceValue extracts the value of a resource +// in an already known container +func ExtractContainerResourceValue(fs *v1.ResourceFieldSelector, container *v1.Container) (string, error) { + divisor := resource.Quantity{} + if divisor.Cmp(fs.Divisor) == 0 { + divisor = resource.MustParse("1") + } else { + divisor = fs.Divisor + } + + switch fs.Resource { + case "limits.cpu": + return convertResourceCPUToString(container.Resources.Limits.Cpu(), divisor) + case "limits.memory": + return convertResourceMemoryToString(container.Resources.Limits.Memory(), divisor) + case "limits.ephemeral-storage": + return convertResourceEphemeralStorageToString(container.Resources.Limits.StorageEphemeral(), divisor) + case "requests.cpu": + return convertResourceCPUToString(container.Resources.Requests.Cpu(), divisor) + case "requests.memory": + return convertResourceMemoryToString(container.Resources.Requests.Memory(), divisor) + case "requests.ephemeral-storage": + return convertResourceEphemeralStorageToString(container.Resources.Requests.StorageEphemeral(), divisor) + } + // handle extended standard resources with dynamic names + // example: requests.hugepages- or limits.hugepages- + if strings.HasPrefix(fs.Resource, "requests.") { + resourceName := v1.ResourceName(strings.TrimPrefix(fs.Resource, "requests.")) + if IsHugePageResourceName(resourceName) { + return convertResourceHugePagesToString(container.Resources.Requests.Name(resourceName, resource.BinarySI), divisor) + } + } + if strings.HasPrefix(fs.Resource, "limits.") { + resourceName := v1.ResourceName(strings.TrimPrefix(fs.Resource, "limits.")) + if IsHugePageResourceName(resourceName) { + return convertResourceHugePagesToString(container.Resources.Limits.Name(resourceName, resource.BinarySI), divisor) + } + } + return "", fmt.Errorf("unsupported container resource : %v", fs.Resource) +} + +// convertResourceCPUToString converts cpu value to the format of divisor and returns +// ceiling of the value. +func convertResourceCPUToString(cpu *resource.Quantity, divisor resource.Quantity) (string, error) { + c := int64(math.Ceil(float64(cpu.MilliValue()) / float64(divisor.MilliValue()))) + return strconv.FormatInt(c, 10), nil +} + +// convertResourceMemoryToString converts memory value to the format of divisor and returns +// ceiling of the value. +func convertResourceMemoryToString(memory *resource.Quantity, divisor resource.Quantity) (string, error) { + m := int64(math.Ceil(float64(memory.Value()) / float64(divisor.Value()))) + return strconv.FormatInt(m, 10), nil +} + +// convertResourceHugePagesToString converts hugepages value to the format of divisor and returns +// ceiling of the value. +func convertResourceHugePagesToString(hugePages *resource.Quantity, divisor resource.Quantity) (string, error) { + m := int64(math.Ceil(float64(hugePages.Value()) / float64(divisor.Value()))) + return strconv.FormatInt(m, 10), nil +} + +// convertResourceEphemeralStorageToString converts ephemeral storage value to the format of divisor and returns +// ceiling of the value. +func convertResourceEphemeralStorageToString(ephemeralStorage *resource.Quantity, divisor resource.Quantity) (string, error) { + m := int64(math.Ceil(float64(ephemeralStorage.Value()) / float64(divisor.Value()))) + return strconv.FormatInt(m, 10), nil +} + +// findContainerInPod finds a container by its name in the provided pod +func findContainerInPod(pod *v1.Pod, containerName string) (*v1.Container, error) { + for _, container := range pod.Spec.Containers { + if container.Name == containerName { + return &container, nil + } + } + for _, container := range pod.Spec.InitContainers { + if container.Name == containerName { + return &container, nil + } + } + return nil, fmt.Errorf("container %s not found", containerName) +} + +// MergeContainerResourceLimits checks if a limit is applied for +// the container, and if not, it sets the limit to the passed resource list. +func MergeContainerResourceLimits(container *v1.Container, + allocatable v1.ResourceList) { + if container.Resources.Limits == nil { + container.Resources.Limits = make(v1.ResourceList) + } + // NOTE: we exclude hugepages-* resources because hugepages are never overcommitted. + // This means that the container always has a limit specified. + for _, resource := range []v1.ResourceName{v1.ResourceCPU, v1.ResourceMemory, v1.ResourceEphemeralStorage} { + if quantity, exists := container.Resources.Limits[resource]; !exists || quantity.IsZero() { + if cap, exists := allocatable[resource]; exists { + container.Resources.Limits[resource] = cap.DeepCopy() + } + } + } +} + +// IsHugePageResourceName returns true if the resource name has the huge page +// resource prefix. +func IsHugePageResourceName(name v1.ResourceName) bool { + return strings.HasPrefix(string(name), v1.ResourceHugePagesPrefix) +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/apps/OWNERS b/vendor/k8s.io/kubernetes/pkg/apis/apps/OWNERS new file mode 100644 index 000000000..885cc9f3e --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/apps/OWNERS @@ -0,0 +1,8 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +# approval on api packages bubbles to api-approvers +reviewers: + - sig-apps-api-reviewers + - sig-apps-api-approvers +labels: + - sig/apps diff --git a/vendor/k8s.io/kubernetes/pkg/apis/apps/doc.go b/vendor/k8s.io/kubernetes/pkg/apis/apps/doc.go new file mode 100644 index 000000000..1ff549998 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/apps/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2016 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. +*/ + +// +k8s:deepcopy-gen=package + +package apps // import "k8s.io/kubernetes/pkg/apis/apps" diff --git a/vendor/k8s.io/kubernetes/pkg/apis/apps/register.go b/vendor/k8s.io/kubernetes/pkg/apis/apps/register.go new file mode 100644 index 000000000..4f5f20a34 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/apps/register.go @@ -0,0 +1,66 @@ +/* +Copyright 2016 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 apps + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/kubernetes/pkg/apis/autoscaling" +) + +var ( + // SchemeBuilder stores functions to add things to a scheme. + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + // AddToScheme applies all stored functions t oa scheme. + AddToScheme = SchemeBuilder.AddToScheme +) + +// GroupName is the group name use in this package +const GroupName = "apps" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal} + +// Kind takes an unqualified kind and returns a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to the given scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + // TODO this will get cleaned up with the scheme types are fixed + scheme.AddKnownTypes(SchemeGroupVersion, + &DaemonSet{}, + &DaemonSetList{}, + &Deployment{}, + &DeploymentList{}, + &DeploymentRollback{}, + &autoscaling.Scale{}, + &StatefulSet{}, + &StatefulSetList{}, + &ControllerRevision{}, + &ControllerRevisionList{}, + &ReplicaSet{}, + &ReplicaSetList{}, + ) + return nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/apps/types.go b/vendor/k8s.io/kubernetes/pkg/apis/apps/types.go new file mode 100644 index 000000000..624deca9b --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/apps/types.go @@ -0,0 +1,916 @@ +/* +Copyright 2016 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 apps + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/intstr" + api "k8s.io/kubernetes/pkg/apis/core" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// StatefulSet represents a set of pods with consistent identities. +// Identities are defined as: +// - Network: A single stable DNS and hostname. +// - Storage: As many VolumeClaims as requested. +// +// The StatefulSet guarantees that a given network identity will always +// map to the same storage identity. +type StatefulSet struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + + // Spec defines the desired identities of pods in this set. + // +optional + Spec StatefulSetSpec + + // Status is the current status of Pods in this StatefulSet. This data + // may be out of date by some window of time. + // +optional + Status StatefulSetStatus +} + +// PodManagementPolicyType defines the policy for creating pods under a stateful set. +type PodManagementPolicyType string + +const ( + // OrderedReadyPodManagement will create pods in strictly increasing order on + // scale up and strictly decreasing order on scale down, progressing only when + // the previous pod is ready or terminated. At most one pod will be changed + // at any time. + OrderedReadyPodManagement PodManagementPolicyType = "OrderedReady" + // ParallelPodManagement will create and delete pods as soon as the stateful set + // replica count is changed, and will not wait for pods to be ready or complete + // termination. + ParallelPodManagement PodManagementPolicyType = "Parallel" +) + +// StatefulSetUpdateStrategy indicates the strategy that the StatefulSet +// controller will use to perform updates. It includes any additional parameters +// necessary to perform the update for the indicated strategy. +type StatefulSetUpdateStrategy struct { + // Type indicates the type of the StatefulSetUpdateStrategy. + Type StatefulSetUpdateStrategyType + // RollingUpdate is used to communicate parameters when Type is RollingUpdateStatefulSetStrategyType. + RollingUpdate *RollingUpdateStatefulSetStrategy +} + +// StatefulSetUpdateStrategyType is a string enumeration type that enumerates +// all possible update strategies for the StatefulSet controller. +type StatefulSetUpdateStrategyType string + +const ( + // RollingUpdateStatefulSetStrategyType indicates that update will be + // applied to all Pods in the StatefulSet with respect to the StatefulSet + // ordering constraints. When a scale operation is performed with this + // strategy, new Pods will be created from the specification version indicated + // by the StatefulSet's updateRevision. + RollingUpdateStatefulSetStrategyType StatefulSetUpdateStrategyType = "RollingUpdate" + // OnDeleteStatefulSetStrategyType triggers the legacy behavior. Version + // tracking and ordered rolling restarts are disabled. Pods are recreated + // from the StatefulSetSpec when they are manually deleted. When a scale + // operation is performed with this strategy,specification version indicated + // by the StatefulSet's currentRevision. + OnDeleteStatefulSetStrategyType StatefulSetUpdateStrategyType = "OnDelete" +) + +// RollingUpdateStatefulSetStrategy is used to communicate parameter for RollingUpdateStatefulSetStrategyType. +type RollingUpdateStatefulSetStrategy struct { + // Partition indicates the ordinal at which the StatefulSet should be partitioned + // for updates. During a rolling update, all pods from ordinal Replicas-1 to + // Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. + // This is helpful in being able to do a canary based deployment. The default value is 0. + Partition int32 + // The maximum number of pods that can be unavailable during the update. + // Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). + // Absolute number is calculated from percentage by rounding up. This can not be 0. + // Defaults to 1. This field is alpha-level and is only honored by servers that enable the + // MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to + // Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it + // will be counted towards MaxUnavailable. + // +optional + MaxUnavailable *intstr.IntOrString +} + +// PersistentVolumeClaimRetentionPolicyType is a string enumeration of the policies that will determine +// when volumes from the VolumeClaimTemplates will be deleted when the controlling StatefulSet is +// deleted or scaled down. +type PersistentVolumeClaimRetentionPolicyType string + +const ( + // RetainPersistentVolumeClaimRetentionPolicyType is the default + // PersistentVolumeClaimRetentionPolicy and specifies that + // PersistentVolumeClaims associated with StatefulSet VolumeClaimTemplates + // will not be deleted. + RetainPersistentVolumeClaimRetentionPolicyType PersistentVolumeClaimRetentionPolicyType = "Retain" + // DeletePersistentVolumeClaimRetentionPolicyType specifies that + // PersistentVolumeClaims associated with StatefulSet VolumeClaimTemplates + // will be deleted in the scenario specified in + // StatefulSetPersistentVolumeClaimPolicy. + DeletePersistentVolumeClaimRetentionPolicyType PersistentVolumeClaimRetentionPolicyType = "Delete" +) + +// StatefulSetPersistentVolumeClaimRetentionPolicy describes the policy used for PVCs +// created from the StatefulSet VolumeClaimTemplates. +type StatefulSetPersistentVolumeClaimRetentionPolicy struct { + // WhenDeleted specifies what happens to PVCs created from StatefulSet + // VolumeClaimTemplates when the StatefulSet is deleted. The default policy + // of `Retain` causes PVCs to not be affected by StatefulSet deletion. The + // `Delete` policy causes those PVCs to be deleted. + WhenDeleted PersistentVolumeClaimRetentionPolicyType + // WhenScaled specifies what happens to PVCs created from StatefulSet + // VolumeClaimTemplates when the StatefulSet is scaled down. The default + // policy of `Retain` causes PVCs to not be affected by a scaledown. The + // `Delete` policy causes the associated PVCs for any excess pods above + // the replica count to be deleted. + WhenScaled PersistentVolumeClaimRetentionPolicyType +} + +// StatefulSetOrdinals describes the policy used for replica ordinal assignment +// in this StatefulSet. +type StatefulSetOrdinals struct { + // start is the number representing the first replica's index. It may be used + // to number replicas from an alternate index (eg: 1-indexed) over the default + // 0-indexed names, or to orchestrate progressive movement of replicas from + // one StatefulSet to another. + // If set, replica indices will be in the range: + // [.spec.ordinals.start, .spec.ordinals.start + .spec.replicas). + // If unset, defaults to 0. Replica indices will be in the range: + // [0, .spec.replicas). + // +optional + Start int32 +} + +// A StatefulSetSpec is the specification of a StatefulSet. +type StatefulSetSpec struct { + // Replicas is the desired number of replicas of the given Template. + // These are replicas in the sense that they are instantiations of the + // same Template, but individual replicas also have a consistent identity. + // If unspecified, defaults to 1. + // TODO: Consider a rename of this field. + // +optional + Replicas int32 + + // Selector is a label query over pods that should match the replica count. + // If empty, defaulted to labels on the pod template. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + // +optional + Selector *metav1.LabelSelector + + // Template is the object that describes the pod that will be created if + // insufficient replicas are detected. Each pod stamped out by the StatefulSet + // will fulfill this Template, but have a unique identity from the rest + // of the StatefulSet. Each pod will be named with the format + // -. For example, a pod in a StatefulSet named + // "web" with index number "3" would be named "web-3". + Template api.PodTemplateSpec + + // VolumeClaimTemplates is a list of claims that pods are allowed to reference. + // The StatefulSet controller is responsible for mapping network identities to + // claims in a way that maintains the identity of a pod. Every claim in + // this list must have at least one matching (by name) volumeMount in one + // container in the template. A claim in this list takes precedence over + // any volumes in the template, with the same name. + // TODO: Define the behavior if a claim already exists with the same name. + // +optional + VolumeClaimTemplates []api.PersistentVolumeClaim + + // ServiceName is the name of the service that governs this StatefulSet. + // This service must exist before the StatefulSet, and is responsible for + // the network identity of the set. Pods get DNS/hostnames that follow the + // pattern: pod-specific-string.serviceName.default.svc.cluster.local + // where "pod-specific-string" is managed by the StatefulSet controller. + ServiceName string + + // PodManagementPolicy controls how pods are created during initial scale up, + // when replacing pods on nodes, or when scaling down. The default policy is + // `OrderedReady`, where pods are created in increasing order (pod-0, then + // pod-1, etc) and the controller will wait until each pod is ready before + // continuing. When scaling down, the pods are removed in the opposite order. + // The alternative policy is `Parallel` which will create pods in parallel + // to match the desired scale without waiting, and on scale down will delete + // all pods at once. + // +optional + PodManagementPolicy PodManagementPolicyType + + // updateStrategy indicates the StatefulSetUpdateStrategy that will be + // employed to update Pods in the StatefulSet when a revision is made to + // Template. + UpdateStrategy StatefulSetUpdateStrategy + + // revisionHistoryLimit is the maximum number of revisions that will + // be maintained in the StatefulSet's revision history. The revision history + // consists of all revisions not represented by a currently applied + // StatefulSetSpec version. The default value is 10. + RevisionHistoryLimit *int32 + + // Minimum number of seconds for which a newly created pod should be ready + // without any of its container crashing for it to be considered available. + // Defaults to 0 (pod will be considered available as soon as it is ready) + // +optional + MinReadySeconds int32 + + // PersistentVolumeClaimRetentionPolicy describes the policy used for PVCs created from + // the StatefulSet VolumeClaimTemplates. This requires the + // StatefulSetAutoDeletePVC feature gate to be enabled, which is alpha. + // +optional + PersistentVolumeClaimRetentionPolicy *StatefulSetPersistentVolumeClaimRetentionPolicy + + // ordinals controls the numbering of replica indices in a StatefulSet. The + // default ordinals behavior assigns a "0" index to the first replica and + // increments the index by one for each additional replica requested. Using + // the ordinals field requires the StatefulSetStartOrdinal feature gate to be + // enabled, which is alpha. + // +optional + Ordinals *StatefulSetOrdinals +} + +// StatefulSetStatus represents the current state of a StatefulSet. +type StatefulSetStatus struct { + // observedGeneration is the most recent generation observed for this StatefulSet. It corresponds to the + // StatefulSet's generation, which is updated on mutation by the API Server. + // +optional + ObservedGeneration *int64 + + // replicas is the number of Pods created by the StatefulSet controller. + Replicas int32 + + // readyReplicas is the number of Pods created by the StatefulSet controller that have a Ready Condition. + ReadyReplicas int32 + + // currentReplicas is the number of Pods created by the StatefulSet controller from the StatefulSet version + // indicated by currentRevision. + CurrentReplicas int32 + + // updatedReplicas is the number of Pods created by the StatefulSet controller from the StatefulSet version + // indicated by updateRevision. + UpdatedReplicas int32 + + // currentRevision, if not empty, indicates the version of the StatefulSet used to generate Pods in the + // sequence [0,currentReplicas). + CurrentRevision string + + // updateRevision, if not empty, indicates the version of the StatefulSet used to generate Pods in the sequence + // [replicas-updatedReplicas,replicas) + UpdateRevision string + + // collisionCount is the count of hash collisions for the StatefulSet. The StatefulSet controller + // uses this field as a collision avoidance mechanism when it needs to create the name for the + // newest ControllerRevision. + // +optional + CollisionCount *int32 + + // Represents the latest available observations of a statefulset's current state. + Conditions []StatefulSetCondition + + // Total number of available pods (ready for at least minReadySeconds) targeted by this statefulset. + // +optional + AvailableReplicas int32 +} + +// StatefulSetConditionType describes the condition types of StatefulSets. +type StatefulSetConditionType string + +// TODO: Add valid condition types for Statefulsets. + +// StatefulSetCondition describes the state of a statefulset at a certain point. +type StatefulSetCondition struct { + // Type of statefulset condition. + Type StatefulSetConditionType + // Status of the condition, one of True, False, Unknown. + Status api.ConditionStatus + // The last time this condition was updated. + LastTransitionTime metav1.Time + // The reason for the condition's last transition. + Reason string + // A human readable message indicating details about the transition. + Message string +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// StatefulSetList is a collection of StatefulSets. +type StatefulSetList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + Items []StatefulSet +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ControllerRevision implements an immutable snapshot of state data. Clients +// are responsible for serializing and deserializing the objects that contain +// their internal state. +// Once a ControllerRevision has been successfully created, it can not be updated. +// The API Server will fail validation of all requests that attempt to mutate +// the Data field. ControllerRevisions may, however, be deleted. +type ControllerRevision struct { + metav1.TypeMeta + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // +optional + metav1.ObjectMeta + + // Data is the Object representing the state. + Data runtime.Object + + // Revision indicates the revision of the state represented by Data. + Revision int64 +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ControllerRevisionList is a resource containing a list of ControllerRevision objects. +type ControllerRevisionList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + + // Items is the list of ControllerRevision objects. + Items []ControllerRevision +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Deployment provides declarative updates for Pods and ReplicaSets. +type Deployment struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + + // Specification of the desired behavior of the Deployment. + // +optional + Spec DeploymentSpec + + // Most recently observed status of the Deployment. + // +optional + Status DeploymentStatus +} + +// DeploymentSpec specifies the state of a Deployment. +type DeploymentSpec struct { + // Number of desired pods. + Replicas int32 + + // Label selector for pods. Existing ReplicaSets whose pods are + // selected by this will be the ones affected by this deployment. + // +optional + Selector *metav1.LabelSelector + + // Template describes the pods that will be created. + Template api.PodTemplateSpec + + // The deployment strategy to use to replace existing pods with new ones. + // +optional + Strategy DeploymentStrategy + + // Minimum number of seconds for which a newly created pod should be ready + // without any of its container crashing, for it to be considered available. + // Defaults to 0 (pod will be considered available as soon as it is ready) + // +optional + MinReadySeconds int32 + + // The number of old ReplicaSets to retain to allow rollback. + // This is a pointer to distinguish between explicit zero and not specified. + // This is set to the max value of int32 (i.e. 2147483647) by default, which means + // "retaining all old ReplicaSets". + // +optional + RevisionHistoryLimit *int32 + + // Indicates that the deployment is paused and will not be processed by the + // deployment controller. + // +optional + Paused bool + + // DEPRECATED. + // The config this deployment is rolling back to. Will be cleared after rollback is done. + // +optional + RollbackTo *RollbackConfig + + // The maximum time in seconds for a deployment to make progress before it + // is considered to be failed. The deployment controller will continue to + // process failed deployments and a condition with a ProgressDeadlineExceeded + // reason will be surfaced in the deployment status. Note that progress will + // not be estimated during the time a deployment is paused. This is set to + // the max value of int32 (i.e. 2147483647) by default, which means "no deadline". + // +optional + ProgressDeadlineSeconds *int32 +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// DeploymentRollback stores the information required to rollback a deployment. +// DEPRECATED. +type DeploymentRollback struct { + metav1.TypeMeta + // Required: This must match the Name of a deployment. + Name string + // The annotations to be updated to a deployment + // +optional + UpdatedAnnotations map[string]string + // The config of this deployment rollback. + RollbackTo RollbackConfig +} + +// RollbackConfig specifies the state of a revision to roll back to. +// DEPRECATED. +type RollbackConfig struct { + // The revision to rollback to. If set to 0, rollback to the last revision. + // +optional + Revision int64 +} + +const ( + // DefaultDeploymentUniqueLabelKey is the default key of the selector that is added + // to existing RCs (and label key that is added to its pods) to prevent the existing RCs + // to select new pods (and old pods being select by new RC). + DefaultDeploymentUniqueLabelKey string = "pod-template-hash" +) + +// DeploymentStrategy stores information about the strategy and rolling-update +// behavior of a deployment. +type DeploymentStrategy struct { + // Type of deployment. Can be "Recreate" or "RollingUpdate". Default is RollingUpdate. + // +optional + Type DeploymentStrategyType + + // Rolling update config params. Present only if DeploymentStrategyType = + // RollingUpdate. + //--- + // TODO: Update this to follow our convention for oneOf, whatever we decide it + // to be. + // +optional + RollingUpdate *RollingUpdateDeployment +} + +// DeploymentStrategyType defines strategies with a deployment. +type DeploymentStrategyType string + +const ( + // RecreateDeploymentStrategyType - kill all existing pods before creating new ones. + RecreateDeploymentStrategyType DeploymentStrategyType = "Recreate" + + // RollingUpdateDeploymentStrategyType - Replace the old RCs by new one using rolling update i.e gradually scale down the old RCs and scale up the new one. + RollingUpdateDeploymentStrategyType DeploymentStrategyType = "RollingUpdate" +) + +// RollingUpdateDeployment is the spec to control the desired behavior of rolling update. +type RollingUpdateDeployment struct { + // The maximum number of pods that can be unavailable during the update. + // Value can be an absolute number (ex: 5) or a percentage of total pods at the start of update (ex: 10%). + // Absolute number is calculated from percentage by rounding down. + // This can not be 0 if MaxSurge is 0. + // By default, a fixed value of 1 is used. + // Example: when this is set to 30%, the old RC can be scaled down by 30% + // immediately when the rolling update starts. Once new pods are ready, old RC + // can be scaled down further, followed by scaling up the new RC, ensuring + // that at least 70% of original number of pods are available at all times + // during the update. + // +optional + MaxUnavailable intstr.IntOrString + + // The maximum number of pods that can be scheduled above the original number of + // pods. + // Value can be an absolute number (ex: 5) or a percentage of total pods at + // the start of the update (ex: 10%). This can not be 0 if MaxUnavailable is 0. + // Absolute number is calculated from percentage by rounding up. + // By default, a value of 1 is used. + // Example: when this is set to 30%, the new RC can be scaled up by 30% + // immediately when the rolling update starts. Once old pods have been killed, + // new RC can be scaled up further, ensuring that total number of pods running + // at any time during the update is at most 130% of original pods. + // +optional + MaxSurge intstr.IntOrString +} + +// DeploymentStatus holds information about the observed status of a deployment. +type DeploymentStatus struct { + // The generation observed by the deployment controller. + // +optional + ObservedGeneration int64 + + // Total number of non-terminated pods targeted by this deployment (their labels match the selector). + // +optional + Replicas int32 + + // Total number of non-terminated pods targeted by this deployment that have the desired template spec. + // +optional + UpdatedReplicas int32 + + // Total number of ready pods targeted by this deployment. + // +optional + ReadyReplicas int32 + + // Total number of available pods (ready for at least minReadySeconds) targeted by this deployment. + // +optional + AvailableReplicas int32 + + // Total number of unavailable pods targeted by this deployment. This is the total number of + // pods that are still required for the deployment to have 100% available capacity. They may + // either be pods that are running but not yet available or pods that still have not been created. + // +optional + UnavailableReplicas int32 + + // Represents the latest available observations of a deployment's current state. + Conditions []DeploymentCondition + + // Count of hash collisions for the Deployment. The Deployment controller uses this + // field as a collision avoidance mechanism when it needs to create the name for the + // newest ReplicaSet. + // +optional + CollisionCount *int32 +} + +// DeploymentConditionType defines conditions of a deployment. +type DeploymentConditionType string + +// These are valid conditions of a deployment. +const ( + // Available means the deployment is available, ie. at least the minimum available + // replicas required are up and running for at least minReadySeconds. + DeploymentAvailable DeploymentConditionType = "Available" + // Progressing means the deployment is progressing. Progress for a deployment is + // considered when a new replica set is created or adopted, and when new pods scale + // up or old pods scale down. Progress is not estimated for paused deployments or + // when progressDeadlineSeconds is not specified. + DeploymentProgressing DeploymentConditionType = "Progressing" + // ReplicaFailure is added in a deployment when one of its pods fails to be created + // or deleted. + DeploymentReplicaFailure DeploymentConditionType = "ReplicaFailure" +) + +// DeploymentCondition describes the state of a deployment at a certain point. +type DeploymentCondition struct { + // Type of deployment condition. + Type DeploymentConditionType + // Status of the condition, one of True, False, Unknown. + Status api.ConditionStatus + // The last time this condition was updated. + LastUpdateTime metav1.Time + // Last time the condition transitioned from one status to another. + LastTransitionTime metav1.Time + // The reason for the condition's last transition. + Reason string + // A human readable message indicating details about the transition. + Message string +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// DeploymentList defines multiple deployments. +type DeploymentList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + + // Items is the list of deployments. + Items []Deployment +} + +// DaemonSetUpdateStrategy defines a strategy to update a daemon set. +type DaemonSetUpdateStrategy struct { + // Type of daemon set update. Can be "RollingUpdate" or "OnDelete". + // +optional + Type DaemonSetUpdateStrategyType + + // Rolling update config params. Present only if type = "RollingUpdate". + //--- + // TODO: Update this to follow our convention for oneOf, whatever we decide it + // to be. Same as Deployment `strategy.rollingUpdate`. + // See https://github.com/kubernetes/kubernetes/issues/35345 + // +optional + RollingUpdate *RollingUpdateDaemonSet +} + +// DaemonSetUpdateStrategyType is a strategy according to which a daemon set +// gets updated. +type DaemonSetUpdateStrategyType string + +const ( + // RollingUpdateDaemonSetStrategyType - Replace the old daemons by new ones using rolling update i.e replace them on each node one after the other. + RollingUpdateDaemonSetStrategyType DaemonSetUpdateStrategyType = "RollingUpdate" + + // OnDeleteDaemonSetStrategyType - Replace the old daemons only when it's killed + OnDeleteDaemonSetStrategyType DaemonSetUpdateStrategyType = "OnDelete" +) + +// RollingUpdateDaemonSet is the spec to control the desired behavior of daemon set rolling update. +type RollingUpdateDaemonSet struct { + // The maximum number of DaemonSet pods that can be unavailable during the + // update. Value can be an absolute number (ex: 5) or a percentage of total + // number of DaemonSet pods at the start of the update (ex: 10%). Absolute + // number is calculated from percentage by rounding up. + // This cannot be 0 if MaxSurge is 0 + // Default value is 1. + // Example: when this is set to 30%, at most 30% of the total number of nodes + // that should be running the daemon pod (i.e. status.desiredNumberScheduled) + // can have their pods stopped for an update at any given time. The update + // starts by stopping at most 30% of those DaemonSet pods and then brings + // up new DaemonSet pods in their place. Once the new pods are available, + // it then proceeds onto other DaemonSet pods, thus ensuring that at least + // 70% of original number of DaemonSet pods are available at all times during + // the update. + // +optional + MaxUnavailable intstr.IntOrString + + // The maximum number of nodes with an existing available DaemonSet pod that + // can have an updated DaemonSet pod during during an update. + // Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). + // This can not be 0 if MaxUnavailable is 0. + // Absolute number is calculated from percentage by rounding up to a minimum of 1. + // Default value is 0. + // Example: when this is set to 30%, at most 30% of the total number of nodes + // that should be running the daemon pod (i.e. status.desiredNumberScheduled) + // can have their a new pod created before the old pod is marked as deleted. + // The update starts by launching new pods on 30% of nodes. Once an updated + // pod is available (Ready for at least minReadySeconds) the old DaemonSet pod + // on that node is marked deleted. If the old pod becomes unavailable for any + // reason (Ready transitions to false, is evicted, or is drained) an updated + // pod is immediately created on that node without considering surge limits. + // Allowing surge implies the possibility that the resources consumed by the + // daemonset on any given node can double if the readiness check fails, and + // so resource intensive daemonsets should take into account that they may + // cause evictions during disruption. + // +optional + MaxSurge intstr.IntOrString +} + +// DaemonSetSpec is the specification of a daemon set. +type DaemonSetSpec struct { + // A label query over pods that are managed by the daemon set. + // Must match in order to be controlled. + // If empty, defaulted to labels on Pod template. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + // +optional + Selector *metav1.LabelSelector + + // An object that describes the pod that will be created. + // The DaemonSet will create exactly one copy of this pod on every node + // that matches the template's node selector (or on every node if no node + // selector is specified). + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#pod-template + Template api.PodTemplateSpec + + // An update strategy to replace existing DaemonSet pods with new pods. + // +optional + UpdateStrategy DaemonSetUpdateStrategy + + // The minimum number of seconds for which a newly created DaemonSet pod should + // be ready without any of its container crashing, for it to be considered + // available. Defaults to 0 (pod will be considered available as soon as it + // is ready). + // +optional + MinReadySeconds int32 + + // DEPRECATED. + // A sequence number representing a specific generation of the template. + // Populated by the system. It can be set only during the creation. + // +optional + TemplateGeneration int64 + + // The number of old history to retain to allow rollback. + // This is a pointer to distinguish between explicit zero and not specified. + // Defaults to 10. + // +optional + RevisionHistoryLimit *int32 +} + +// DaemonSetStatus represents the current status of a daemon set. +type DaemonSetStatus struct { + // The number of nodes that are running at least 1 + // daemon pod and are supposed to run the daemon pod. + CurrentNumberScheduled int32 + + // The number of nodes that are running the daemon pod, but are + // not supposed to run the daemon pod. + NumberMisscheduled int32 + + // The total number of nodes that should be running the daemon + // pod (including nodes correctly running the daemon pod). + DesiredNumberScheduled int32 + + // The number of nodes that should be running the daemon pod and have one + // or more of the daemon pod running and ready. + NumberReady int32 + + // The most recent generation observed by the daemon set controller. + // +optional + ObservedGeneration int64 + + // The total number of nodes that are running updated daemon pod + // +optional + UpdatedNumberScheduled int32 + + // The number of nodes that should be running the + // daemon pod and have one or more of the daemon pod running and + // available (ready for at least spec.minReadySeconds) + // +optional + NumberAvailable int32 + + // The number of nodes that should be running the + // daemon pod and have none of the daemon pod running and available + // (ready for at least spec.minReadySeconds) + // +optional + NumberUnavailable int32 + + // Count of hash collisions for the DaemonSet. The DaemonSet controller + // uses this field as a collision avoidance mechanism when it needs to + // create the name for the newest ControllerRevision. + // +optional + CollisionCount *int32 + + // Represents the latest available observations of a DaemonSet's current state. + Conditions []DaemonSetCondition +} + +// DaemonSetConditionType defines a daemon set condition. +type DaemonSetConditionType string + +// TODO: Add valid condition types of a DaemonSet. + +// DaemonSetCondition describes the state of a DaemonSet at a certain point. +type DaemonSetCondition struct { + // Type of DaemonSet condition. + Type DaemonSetConditionType + // Status of the condition, one of True, False, Unknown. + Status api.ConditionStatus + // Last time the condition transitioned from one status to another. + LastTransitionTime metav1.Time + // The reason for the condition's last transition. + Reason string + // A human readable message indicating details about the transition. + Message string +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// DaemonSet represents the configuration of a daemon set. +type DaemonSet struct { + metav1.TypeMeta + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // +optional + metav1.ObjectMeta + + // The desired behavior of this daemon set. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + // +optional + Spec DaemonSetSpec + + // The current status of this daemon set. This data may be + // out of date by some window of time. + // Populated by the system. + // Read-only. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + // +optional + Status DaemonSetStatus +} + +const ( + // DaemonSetTemplateGenerationKey is the key of the labels that is added + // to daemon set pods to distinguish between old and new pod templates + // during DaemonSet template update. + // DEPRECATED: DefaultDaemonSetUniqueLabelKey is used instead. + DaemonSetTemplateGenerationKey string = "pod-template-generation" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// DaemonSetList is a collection of daemon sets. +type DaemonSetList struct { + metav1.TypeMeta + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // +optional + metav1.ListMeta + + // A list of daemon sets. + Items []DaemonSet +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ReplicaSet ensures that a specified number of pod replicas are running at any given time. +type ReplicaSet struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + + // Spec defines the desired behavior of this ReplicaSet. + // +optional + Spec ReplicaSetSpec + + // Status is the current status of this ReplicaSet. This data may be + // out of date by some window of time. + // +optional + Status ReplicaSetStatus +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ReplicaSetList is a collection of ReplicaSets. +type ReplicaSetList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + + Items []ReplicaSet +} + +// ReplicaSetSpec is the specification of a ReplicaSet. +// As the internal representation of a ReplicaSet, it must have +// a Template set. +type ReplicaSetSpec struct { + // Replicas is the number of desired replicas. + Replicas int32 + + // Minimum number of seconds for which a newly created pod should be ready + // without any of its container crashing, for it to be considered available. + // Defaults to 0 (pod will be considered available as soon as it is ready) + // +optional + MinReadySeconds int32 + + // Selector is a label query over pods that should match the replica count. + // Must match in order to be controlled. + // If empty, defaulted to labels on pod template. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + // +optional + Selector *metav1.LabelSelector + + // Template is the object that describes the pod that will be created if + // insufficient replicas are detected. + // +optional + Template api.PodTemplateSpec +} + +// ReplicaSetStatus represents the current status of a ReplicaSet. +type ReplicaSetStatus struct { + // Replicas is the number of actual replicas. + Replicas int32 + + // The number of pods that have labels matching the labels of the pod template of the replicaset. + // +optional + FullyLabeledReplicas int32 + + // The number of ready replicas for this replica set. + // +optional + ReadyReplicas int32 + + // The number of available replicas (ready for at least minReadySeconds) for this replica set. + // +optional + AvailableReplicas int32 + + // ObservedGeneration is the most recent generation observed by the controller. + // +optional + ObservedGeneration int64 + + // Represents the latest available observations of a replica set's current state. + // +optional + Conditions []ReplicaSetCondition +} + +// ReplicaSetConditionType is a condition of a replica set. +type ReplicaSetConditionType string + +// These are valid conditions of a replica set. +const ( + // ReplicaSetReplicaFailure is added in a replica set when one of its pods fails to be created + // due to insufficient quota, limit ranges, pod security policy, node selectors, etc. or deleted + // due to kubelet being down or finalizers are failing. + ReplicaSetReplicaFailure ReplicaSetConditionType = "ReplicaFailure" +) + +// ReplicaSetCondition describes the state of a replica set at a certain point. +type ReplicaSetCondition struct { + // Type of replica set condition. + Type ReplicaSetConditionType + // Status of the condition, one of True, False, Unknown. + Status api.ConditionStatus + // The last time the condition transitioned from one status to another. + // +optional + LastTransitionTime metav1.Time + // The reason for the condition's last transition. + // +optional + Reason string + // A human readable message indicating details about the transition. + // +optional + Message string +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/apps/zz_generated.deepcopy.go b/vendor/k8s.io/kubernetes/pkg/apis/apps/zz_generated.deepcopy.go new file mode 100644 index 000000000..3353f1250 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/apps/zz_generated.deepcopy.go @@ -0,0 +1,850 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package apps + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + intstr "k8s.io/apimachinery/pkg/util/intstr" + core "k8s.io/kubernetes/pkg/apis/core" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControllerRevision) DeepCopyInto(out *ControllerRevision) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.Data != nil { + out.Data = in.Data.DeepCopyObject() + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerRevision. +func (in *ControllerRevision) DeepCopy() *ControllerRevision { + if in == nil { + return nil + } + out := new(ControllerRevision) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ControllerRevision) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControllerRevisionList) DeepCopyInto(out *ControllerRevisionList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ControllerRevision, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerRevisionList. +func (in *ControllerRevisionList) DeepCopy() *ControllerRevisionList { + if in == nil { + return nil + } + out := new(ControllerRevisionList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ControllerRevisionList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DaemonSet) DeepCopyInto(out *DaemonSet) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DaemonSet. +func (in *DaemonSet) DeepCopy() *DaemonSet { + if in == nil { + return nil + } + out := new(DaemonSet) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DaemonSet) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DaemonSetCondition) DeepCopyInto(out *DaemonSetCondition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DaemonSetCondition. +func (in *DaemonSetCondition) DeepCopy() *DaemonSetCondition { + if in == nil { + return nil + } + out := new(DaemonSetCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DaemonSetList) DeepCopyInto(out *DaemonSetList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]DaemonSet, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DaemonSetList. +func (in *DaemonSetList) DeepCopy() *DaemonSetList { + if in == nil { + return nil + } + out := new(DaemonSetList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DaemonSetList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DaemonSetSpec) DeepCopyInto(out *DaemonSetSpec) { + *out = *in + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + in.Template.DeepCopyInto(&out.Template) + in.UpdateStrategy.DeepCopyInto(&out.UpdateStrategy) + if in.RevisionHistoryLimit != nil { + in, out := &in.RevisionHistoryLimit, &out.RevisionHistoryLimit + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DaemonSetSpec. +func (in *DaemonSetSpec) DeepCopy() *DaemonSetSpec { + if in == nil { + return nil + } + out := new(DaemonSetSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DaemonSetStatus) DeepCopyInto(out *DaemonSetStatus) { + *out = *in + if in.CollisionCount != nil { + in, out := &in.CollisionCount, &out.CollisionCount + *out = new(int32) + **out = **in + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]DaemonSetCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DaemonSetStatus. +func (in *DaemonSetStatus) DeepCopy() *DaemonSetStatus { + if in == nil { + return nil + } + out := new(DaemonSetStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DaemonSetUpdateStrategy) DeepCopyInto(out *DaemonSetUpdateStrategy) { + *out = *in + if in.RollingUpdate != nil { + in, out := &in.RollingUpdate, &out.RollingUpdate + *out = new(RollingUpdateDaemonSet) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DaemonSetUpdateStrategy. +func (in *DaemonSetUpdateStrategy) DeepCopy() *DaemonSetUpdateStrategy { + if in == nil { + return nil + } + out := new(DaemonSetUpdateStrategy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Deployment) DeepCopyInto(out *Deployment) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Deployment. +func (in *Deployment) DeepCopy() *Deployment { + if in == nil { + return nil + } + out := new(Deployment) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Deployment) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeploymentCondition) DeepCopyInto(out *DeploymentCondition) { + *out = *in + in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentCondition. +func (in *DeploymentCondition) DeepCopy() *DeploymentCondition { + if in == nil { + return nil + } + out := new(DeploymentCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeploymentList) DeepCopyInto(out *DeploymentList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Deployment, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentList. +func (in *DeploymentList) DeepCopy() *DeploymentList { + if in == nil { + return nil + } + out := new(DeploymentList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DeploymentList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeploymentRollback) DeepCopyInto(out *DeploymentRollback) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.UpdatedAnnotations != nil { + in, out := &in.UpdatedAnnotations, &out.UpdatedAnnotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + out.RollbackTo = in.RollbackTo + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentRollback. +func (in *DeploymentRollback) DeepCopy() *DeploymentRollback { + if in == nil { + return nil + } + out := new(DeploymentRollback) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DeploymentRollback) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeploymentSpec) DeepCopyInto(out *DeploymentSpec) { + *out = *in + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + in.Template.DeepCopyInto(&out.Template) + in.Strategy.DeepCopyInto(&out.Strategy) + if in.RevisionHistoryLimit != nil { + in, out := &in.RevisionHistoryLimit, &out.RevisionHistoryLimit + *out = new(int32) + **out = **in + } + if in.RollbackTo != nil { + in, out := &in.RollbackTo, &out.RollbackTo + *out = new(RollbackConfig) + **out = **in + } + if in.ProgressDeadlineSeconds != nil { + in, out := &in.ProgressDeadlineSeconds, &out.ProgressDeadlineSeconds + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentSpec. +func (in *DeploymentSpec) DeepCopy() *DeploymentSpec { + if in == nil { + return nil + } + out := new(DeploymentSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeploymentStatus) DeepCopyInto(out *DeploymentStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]DeploymentCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.CollisionCount != nil { + in, out := &in.CollisionCount, &out.CollisionCount + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentStatus. +func (in *DeploymentStatus) DeepCopy() *DeploymentStatus { + if in == nil { + return nil + } + out := new(DeploymentStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeploymentStrategy) DeepCopyInto(out *DeploymentStrategy) { + *out = *in + if in.RollingUpdate != nil { + in, out := &in.RollingUpdate, &out.RollingUpdate + *out = new(RollingUpdateDeployment) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentStrategy. +func (in *DeploymentStrategy) DeepCopy() *DeploymentStrategy { + if in == nil { + return nil + } + out := new(DeploymentStrategy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReplicaSet) DeepCopyInto(out *ReplicaSet) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplicaSet. +func (in *ReplicaSet) DeepCopy() *ReplicaSet { + if in == nil { + return nil + } + out := new(ReplicaSet) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ReplicaSet) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReplicaSetCondition) DeepCopyInto(out *ReplicaSetCondition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplicaSetCondition. +func (in *ReplicaSetCondition) DeepCopy() *ReplicaSetCondition { + if in == nil { + return nil + } + out := new(ReplicaSetCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReplicaSetList) DeepCopyInto(out *ReplicaSetList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ReplicaSet, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplicaSetList. +func (in *ReplicaSetList) DeepCopy() *ReplicaSetList { + if in == nil { + return nil + } + out := new(ReplicaSetList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ReplicaSetList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReplicaSetSpec) DeepCopyInto(out *ReplicaSetSpec) { + *out = *in + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + in.Template.DeepCopyInto(&out.Template) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplicaSetSpec. +func (in *ReplicaSetSpec) DeepCopy() *ReplicaSetSpec { + if in == nil { + return nil + } + out := new(ReplicaSetSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReplicaSetStatus) DeepCopyInto(out *ReplicaSetStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]ReplicaSetCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplicaSetStatus. +func (in *ReplicaSetStatus) DeepCopy() *ReplicaSetStatus { + if in == nil { + return nil + } + out := new(ReplicaSetStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RollbackConfig) DeepCopyInto(out *RollbackConfig) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RollbackConfig. +func (in *RollbackConfig) DeepCopy() *RollbackConfig { + if in == nil { + return nil + } + out := new(RollbackConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RollingUpdateDaemonSet) DeepCopyInto(out *RollingUpdateDaemonSet) { + *out = *in + out.MaxUnavailable = in.MaxUnavailable + out.MaxSurge = in.MaxSurge + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RollingUpdateDaemonSet. +func (in *RollingUpdateDaemonSet) DeepCopy() *RollingUpdateDaemonSet { + if in == nil { + return nil + } + out := new(RollingUpdateDaemonSet) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RollingUpdateDeployment) DeepCopyInto(out *RollingUpdateDeployment) { + *out = *in + out.MaxUnavailable = in.MaxUnavailable + out.MaxSurge = in.MaxSurge + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RollingUpdateDeployment. +func (in *RollingUpdateDeployment) DeepCopy() *RollingUpdateDeployment { + if in == nil { + return nil + } + out := new(RollingUpdateDeployment) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RollingUpdateStatefulSetStrategy) DeepCopyInto(out *RollingUpdateStatefulSetStrategy) { + *out = *in + if in.MaxUnavailable != nil { + in, out := &in.MaxUnavailable, &out.MaxUnavailable + *out = new(intstr.IntOrString) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RollingUpdateStatefulSetStrategy. +func (in *RollingUpdateStatefulSetStrategy) DeepCopy() *RollingUpdateStatefulSetStrategy { + if in == nil { + return nil + } + out := new(RollingUpdateStatefulSetStrategy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StatefulSet) DeepCopyInto(out *StatefulSet) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StatefulSet. +func (in *StatefulSet) DeepCopy() *StatefulSet { + if in == nil { + return nil + } + out := new(StatefulSet) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *StatefulSet) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StatefulSetCondition) DeepCopyInto(out *StatefulSetCondition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StatefulSetCondition. +func (in *StatefulSetCondition) DeepCopy() *StatefulSetCondition { + if in == nil { + return nil + } + out := new(StatefulSetCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StatefulSetList) DeepCopyInto(out *StatefulSetList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]StatefulSet, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StatefulSetList. +func (in *StatefulSetList) DeepCopy() *StatefulSetList { + if in == nil { + return nil + } + out := new(StatefulSetList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *StatefulSetList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StatefulSetOrdinals) DeepCopyInto(out *StatefulSetOrdinals) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StatefulSetOrdinals. +func (in *StatefulSetOrdinals) DeepCopy() *StatefulSetOrdinals { + if in == nil { + return nil + } + out := new(StatefulSetOrdinals) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StatefulSetPersistentVolumeClaimRetentionPolicy) DeepCopyInto(out *StatefulSetPersistentVolumeClaimRetentionPolicy) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StatefulSetPersistentVolumeClaimRetentionPolicy. +func (in *StatefulSetPersistentVolumeClaimRetentionPolicy) DeepCopy() *StatefulSetPersistentVolumeClaimRetentionPolicy { + if in == nil { + return nil + } + out := new(StatefulSetPersistentVolumeClaimRetentionPolicy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StatefulSetSpec) DeepCopyInto(out *StatefulSetSpec) { + *out = *in + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + in.Template.DeepCopyInto(&out.Template) + if in.VolumeClaimTemplates != nil { + in, out := &in.VolumeClaimTemplates, &out.VolumeClaimTemplates + *out = make([]core.PersistentVolumeClaim, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.UpdateStrategy.DeepCopyInto(&out.UpdateStrategy) + if in.RevisionHistoryLimit != nil { + in, out := &in.RevisionHistoryLimit, &out.RevisionHistoryLimit + *out = new(int32) + **out = **in + } + if in.PersistentVolumeClaimRetentionPolicy != nil { + in, out := &in.PersistentVolumeClaimRetentionPolicy, &out.PersistentVolumeClaimRetentionPolicy + *out = new(StatefulSetPersistentVolumeClaimRetentionPolicy) + **out = **in + } + if in.Ordinals != nil { + in, out := &in.Ordinals, &out.Ordinals + *out = new(StatefulSetOrdinals) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StatefulSetSpec. +func (in *StatefulSetSpec) DeepCopy() *StatefulSetSpec { + if in == nil { + return nil + } + out := new(StatefulSetSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StatefulSetStatus) DeepCopyInto(out *StatefulSetStatus) { + *out = *in + if in.ObservedGeneration != nil { + in, out := &in.ObservedGeneration, &out.ObservedGeneration + *out = new(int64) + **out = **in + } + if in.CollisionCount != nil { + in, out := &in.CollisionCount, &out.CollisionCount + *out = new(int32) + **out = **in + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]StatefulSetCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StatefulSetStatus. +func (in *StatefulSetStatus) DeepCopy() *StatefulSetStatus { + if in == nil { + return nil + } + out := new(StatefulSetStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StatefulSetUpdateStrategy) DeepCopyInto(out *StatefulSetUpdateStrategy) { + *out = *in + if in.RollingUpdate != nil { + in, out := &in.RollingUpdate, &out.RollingUpdate + *out = new(RollingUpdateStatefulSetStrategy) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StatefulSetUpdateStrategy. +func (in *StatefulSetUpdateStrategy) DeepCopy() *StatefulSetUpdateStrategy { + if in == nil { + return nil + } + out := new(StatefulSetUpdateStrategy) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/OWNERS b/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/OWNERS new file mode 100644 index 000000000..ba7b77a5a --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/OWNERS @@ -0,0 +1,12 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +reviewers: + - thockin + - lavalamp + - smarterclayton + - wojtek-t + - deads2k + - caesarxuchao + - sttts + - ncdc + - dims diff --git a/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/annotations.go b/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/annotations.go new file mode 100644 index 000000000..e49aaab2e --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/annotations.go @@ -0,0 +1,38 @@ +/* +Copyright 2016 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 autoscaling + +// MetricSpecsAnnotation is the annotation which holds non-CPU-utilization HPA metric +// specs when converting the `Metrics` field from autoscaling/v2beta1 +const MetricSpecsAnnotation = "autoscaling.alpha.kubernetes.io/metrics" + +// MetricStatusesAnnotation is the annotation which holds non-CPU-utilization HPA metric +// statuses when converting the `CurrentMetrics` field from autoscaling/v2beta1 +const MetricStatusesAnnotation = "autoscaling.alpha.kubernetes.io/current-metrics" + +// HorizontalPodAutoscalerConditionsAnnotation is the annotation which holds the conditions +// of an HPA when converting the `Conditions` field from autoscaling/v2beta1 +const HorizontalPodAutoscalerConditionsAnnotation = "autoscaling.alpha.kubernetes.io/conditions" + +// DefaultCPUUtilization is the default value for CPU utilization, provided no other +// metrics are present. This is here because it's used by both the v2beta1 defaulting +// logic, and the pseudo-defaulting done in v1 conversion. +const DefaultCPUUtilization = 80 + +// BehaviorSpecsAnnotation is the annotation which holds the HPA constraints specs +// when converting the `Behavior` field from autoscaling/v2beta2 +const BehaviorSpecsAnnotation = "autoscaling.alpha.kubernetes.io/behavior" diff --git a/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/doc.go b/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/doc.go new file mode 100644 index 000000000..7c91aac8b --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2016 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. +*/ + +// +k8s:deepcopy-gen=package + +package autoscaling // import "k8s.io/kubernetes/pkg/apis/autoscaling" diff --git a/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/helpers.go b/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/helpers.go new file mode 100644 index 000000000..f66a12f4d --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/helpers.go @@ -0,0 +1,58 @@ +/* +Copyright 2020 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 autoscaling + +// DropRoundTripHorizontalPodAutoscalerAnnotations removes any annotations used to serialize round-tripped fields from later API versions, +// and returns false if no changes were made and the original input object was returned. +// It should always be called when converting internal -> external versions, prior +// to setting any of the custom annotations: +// +// annotations, copiedAnnotations := DropRoundTripHorizontalPodAutoscalerAnnotations(externalObj.Annotations) +// externalObj.Annotations = annotations +// +// if internal.SomeField != nil { +// if !copiedAnnotations { +// externalObj.Annotations = DeepCopyStringMap(externalObj.Annotations) +// copiedAnnotations = true +// } +// externalObj.Annotations[...] = json.Marshal(...) +// } +func DropRoundTripHorizontalPodAutoscalerAnnotations(in map[string]string) (out map[string]string, copied bool) { + _, hasMetricsSpecs := in[MetricSpecsAnnotation] + _, hasBehaviorSpecs := in[BehaviorSpecsAnnotation] + _, hasMetricsStatuses := in[MetricStatusesAnnotation] + _, hasConditions := in[HorizontalPodAutoscalerConditionsAnnotation] + if hasMetricsSpecs || hasBehaviorSpecs || hasMetricsStatuses || hasConditions { + out = DeepCopyStringMap(in) + delete(out, MetricSpecsAnnotation) + delete(out, BehaviorSpecsAnnotation) + delete(out, MetricStatusesAnnotation) + delete(out, HorizontalPodAutoscalerConditionsAnnotation) + return out, true + } + return in, false +} + +// DeepCopyStringMap returns a copy of the input map. +// If input is nil, an empty map is returned. +func DeepCopyStringMap(in map[string]string) map[string]string { + out := make(map[string]string, len(in)) + for k, v := range in { + out[k] = v + } + return out +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/register.go b/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/register.go new file mode 100644 index 000000000..871e5513a --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/register.go @@ -0,0 +1,55 @@ +/* +Copyright 2016 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 autoscaling + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// GroupName is the group name use in this package +const GroupName = "autoscaling" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal} + +// Kind takes an unqualified kind and returns a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + // SchemeBuilder points to a list of functions added to Scheme. + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + // AddToScheme applies all the stored functions to the scheme. + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to the given scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &Scale{}, + &HorizontalPodAutoscaler{}, + &HorizontalPodAutoscalerList{}, + ) + return nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/types.go b/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/types.go new file mode 100644 index 000000000..e0ed0dad1 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/types.go @@ -0,0 +1,554 @@ +/* +Copyright 2016 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 autoscaling + +import ( + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + api "k8s.io/kubernetes/pkg/apis/core" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Scale represents a scaling request for a resource. +type Scale struct { + metav1.TypeMeta + // Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. + // +optional + metav1.ObjectMeta + + // defines the behavior of the scale. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status. + // +optional + Spec ScaleSpec + + // current status of the scale. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status. Read-only. + // +optional + Status ScaleStatus +} + +// ScaleSpec describes the attributes of a scale subresource. +type ScaleSpec struct { + // desired number of instances for the scaled object. + // +optional + Replicas int32 +} + +// ScaleStatus represents the current status of a scale subresource. +type ScaleStatus struct { + // actual number of observed instances of the scaled object. + Replicas int32 + + // label query over pods that should match the replicas count. This is same + // as the label selector but in the string format to avoid introspection + // by clients. The string will be in the same format as the query-param syntax. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + // +optional + Selector string +} + +// CrossVersionObjectReference contains enough information to let you identify the referred resource. +type CrossVersionObjectReference struct { + // Kind of the referent; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds" + Kind string + // Name of the referent; More info: http://kubernetes.io/docs/user-guide/identifiers#names + Name string + // API version of the referent + // +optional + APIVersion string +} + +// HorizontalPodAutoscalerSpec describes the desired functionality of the HorizontalPodAutoscaler. +type HorizontalPodAutoscalerSpec struct { + // ScaleTargetRef points to the target resource to scale, and is used to the pods for which metrics + // should be collected, as well as to actually change the replica count. + ScaleTargetRef CrossVersionObjectReference + // minReplicas is the lower limit for the number of replicas to which the autoscaler + // can scale down. It defaults to 1 pod. minReplicas is allowed to be 0 if the + // alpha feature gate HPAScaleToZero is enabled and at least one Object or External + // metric is configured. Scaling is active as long as at least one metric value is + // available. + // +optional + MinReplicas *int32 + // MaxReplicas is the upper limit for the number of replicas to which the autoscaler can scale up. + // It cannot be less that minReplicas. + MaxReplicas int32 + // Metrics contains the specifications for which to use to calculate the + // desired replica count (the maximum replica count across all metrics will + // be used). The desired replica count is calculated multiplying the + // ratio between the target value and the current value by the current + // number of pods. Ergo, metrics used must decrease as the pod count is + // increased, and vice-versa. See the individual metric source types for + // more information about how each type of metric must respond. + // +optional + Metrics []MetricSpec + + // behavior configures the scaling behavior of the target + // in both Up and Down directions (scaleUp and scaleDown fields respectively). + // If not set, the default HPAScalingRules for scale up and scale down are used. + // +optional + Behavior *HorizontalPodAutoscalerBehavior +} + +// HorizontalPodAutoscalerBehavior configures a scaling behavior for Up and Down direction +// (scaleUp and scaleDown fields respectively). +type HorizontalPodAutoscalerBehavior struct { + // scaleUp is scaling policy for scaling Up. + // If not set, the default value is the higher of: + // * increase no more than 4 pods per 60 seconds + // * double the number of pods per 60 seconds + // No stabilization is used. + // +optional + ScaleUp *HPAScalingRules + // scaleDown is scaling policy for scaling Down. + // If not set, the default value is to allow to scale down to minReplicas pods, with a + // 300 second stabilization window (i.e., the highest recommendation for + // the last 300sec is used). + // +optional + ScaleDown *HPAScalingRules +} + +// ScalingPolicySelect is used to specify which policy should be used while scaling in a certain direction +type ScalingPolicySelect string + +const ( + // MaxPolicySelect selects the policy with the highest possible change. + MaxPolicySelect ScalingPolicySelect = "Max" + // MinPolicySelect selects the policy with the lowest possible change. + MinPolicySelect ScalingPolicySelect = "Min" + // DisabledPolicySelect disables the scaling in this direction. + DisabledPolicySelect ScalingPolicySelect = "Disabled" +) + +// HPAScalingRules configures the scaling behavior for one direction. +// These Rules are applied after calculating DesiredReplicas from metrics for the HPA. +// They can limit the scaling velocity by specifying scaling policies. +// They can prevent flapping by specifying the stabilization window, so that the +// number of replicas is not set instantly, instead, the safest value from the stabilization +// window is chosen. +type HPAScalingRules struct { + // StabilizationWindowSeconds is the number of seconds for which past recommendations should be + // considered while scaling up or scaling down. + // StabilizationWindowSeconds must be greater than or equal to zero and less than or equal to 3600 (one hour). + // If not set, use the default values: + // - For scale up: 0 (i.e. no stabilization is done). + // - For scale down: 300 (i.e. the stabilization window is 300 seconds long). + // +optional + StabilizationWindowSeconds *int32 + // selectPolicy is used to specify which policy should be used. + // If not set, the default value MaxPolicySelect is used. + // +optional + SelectPolicy *ScalingPolicySelect + // policies is a list of potential scaling polices which can used during scaling. + // At least one policy must be specified, otherwise the HPAScalingRules will be discarded as invalid + // +optional + Policies []HPAScalingPolicy +} + +// HPAScalingPolicyType is the type of the policy which could be used while making scaling decisions. +type HPAScalingPolicyType string + +const ( + // PodsScalingPolicy is a policy used to specify a change in absolute number of pods. + PodsScalingPolicy HPAScalingPolicyType = "Pods" + // PercentScalingPolicy is a policy used to specify a relative amount of change with respect to + // the current number of pods. + PercentScalingPolicy HPAScalingPolicyType = "Percent" +) + +// HPAScalingPolicy is a single policy which must hold true for a specified past interval. +type HPAScalingPolicy struct { + // Type is used to specify the scaling policy. + Type HPAScalingPolicyType + // Value contains the amount of change which is permitted by the policy. + // It must be greater than zero + Value int32 + // PeriodSeconds specifies the window of time for which the policy should hold true. + // PeriodSeconds must be greater than zero and less than or equal to 1800 (30 min). + PeriodSeconds int32 +} + +// MetricSourceType indicates the type of metric. +type MetricSourceType string + +const ( + // ObjectMetricSourceType is a metric describing a kubernetes object + // (for example, hits-per-second on an Ingress object). + ObjectMetricSourceType MetricSourceType = "Object" + // PodsMetricSourceType is a metric describing each pod in the current scale + // target (for example, transactions-processed-per-second). The values + // will be averaged together before being compared to the target value. + PodsMetricSourceType MetricSourceType = "Pods" + // ResourceMetricSourceType is a resource metric known to Kubernetes, as + // specified in requests and limits, describing each pod in the current + // scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics (the "pods" source). + ResourceMetricSourceType MetricSourceType = "Resource" + // ExternalMetricSourceType is a global metric that is not associated + // with any Kubernetes object. It allows autoscaling based on information + // coming from components running outside of cluster + // (for example length of queue in cloud messaging service, or + // QPS from loadbalancer running outside of cluster). + ExternalMetricSourceType MetricSourceType = "External" + // ContainerResourceMetricSourceType is a resource metric known to Kubernetes, as + // specified in requests and limits, describing a single container in each pod in the current + // scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics (the "pods" source). + ContainerResourceMetricSourceType MetricSourceType = "ContainerResource" +) + +// MetricSpec specifies how to scale based on a single metric +// (only `type` and one other matching field should be set at once). +type MetricSpec struct { + // Type is the type of metric source. It should be one of "Object", + // "Pods" or "Resource", each mapping to a matching field in the object. + Type MetricSourceType + + // Object refers to a metric describing a single kubernetes object + // (for example, hits-per-second on an Ingress object). + // +optional + Object *ObjectMetricSource + // Pods refers to a metric describing each pod in the current scale target + // (for example, transactions-processed-per-second). The values will be + // averaged together before being compared to the target value. + // +optional + Pods *PodsMetricSource + // Resource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing each pod in the + // current scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics using the "pods" source. + // +optional + Resource *ResourceMetricSource + // ContainerResource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing a single container in each pod of the + // current scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics using the "pods" source. + // +optional + ContainerResource *ContainerResourceMetricSource + // External refers to a global metric that is not associated + // with any Kubernetes object. It allows autoscaling based on information + // coming from components running outside of cluster + // (for example length of queue in cloud messaging service, or + // QPS from loadbalancer running outside of cluster). + // +optional + External *ExternalMetricSource +} + +// ObjectMetricSource indicates how to scale on a metric describing a +// kubernetes object (for example, hits-per-second on an Ingress object). +type ObjectMetricSource struct { + DescribedObject CrossVersionObjectReference + Target MetricTarget + Metric MetricIdentifier +} + +// PodsMetricSource indicates how to scale on a metric describing each pod in +// the current scale target (for example, transactions-processed-per-second). +// The values will be averaged together before being compared to the target +// value. +type PodsMetricSource struct { + // metric identifies the target metric by name and selector + Metric MetricIdentifier + // target specifies the target value for the given metric + Target MetricTarget +} + +// ResourceMetricSource indicates how to scale on a resource metric known to +// Kubernetes, as specified in requests and limits, describing each pod in the +// current scale target (e.g. CPU or memory). The values will be averaged +// together before being compared to the target. Such metrics are built in to +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. Only one "target" type +// should be set. +type ResourceMetricSource struct { + // Name is the name of the resource in question. + Name api.ResourceName + // Target specifies the target value for the given metric + Target MetricTarget +} + +// ContainerResourceMetricSource indicates how to scale on a resource metric known to +// Kubernetes, as specified in the requests and limits, describing a single container in +// each of the pods of the current scale target(e.g. CPU or memory). The values will be +// averaged together before being compared to the target. Such metrics are built into +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. Only one "target" type +// should be set. +type ContainerResourceMetricSource struct { + // name is the name of the of the resource + Name api.ResourceName + // container is the name of the container in the pods of the scaling target. + Container string + // target specifies the target value for the given metric + Target MetricTarget +} + +// ExternalMetricSource indicates how to scale on a metric not associated with +// any Kubernetes object (for example length of queue in cloud +// messaging service, or QPS from loadbalancer running outside of cluster). +type ExternalMetricSource struct { + // Metric identifies the target metric by name and selector + Metric MetricIdentifier + // Target specifies the target value for the given metric + Target MetricTarget +} + +// MetricIdentifier defines the name and optionally selector for a metric +type MetricIdentifier struct { + // Name is the name of the given metric + Name string + // Selector is the selector for the given metric + // it is the string-encoded form of a standard kubernetes label selector + // +optional + Selector *metav1.LabelSelector +} + +// MetricTarget defines the target value, average value, or average utilization of a specific metric +type MetricTarget struct { + // Type represents whether the metric type is Utilization, Value, or AverageValue + Type MetricTargetType + // Value is the target value of the metric (as a quantity). + Value *resource.Quantity + // TargetAverageValue is the target value of the average of the + // metric across all relevant pods (as a quantity) + AverageValue *resource.Quantity + + // AverageUtilization is the target value of the average of the + // resource metric across all relevant pods, represented as a percentage of + // the requested value of the resource for the pods. + // Currently only valid for Resource metric source type + AverageUtilization *int32 +} + +// MetricTargetType specifies the type of metric being targeted, and should be either +// "Value", "AverageValue", or "Utilization" +type MetricTargetType string + +const ( + // UtilizationMetricType is a possible value for MetricTarget.Type. + UtilizationMetricType MetricTargetType = "Utilization" + // ValueMetricType is a possible value for MetricTarget.Type. + ValueMetricType MetricTargetType = "Value" + // AverageValueMetricType is a possible value for MetricTarget.Type. + AverageValueMetricType MetricTargetType = "AverageValue" +) + +// HorizontalPodAutoscalerStatus describes the current status of a horizontal pod autoscaler. +type HorizontalPodAutoscalerStatus struct { + // ObservedGeneration is the most recent generation observed by this autoscaler. + // +optional + ObservedGeneration *int64 + + // LastScaleTime is the last time the HorizontalPodAutoscaler scaled the number of pods, + // used by the autoscaler to control how often the number of pods is changed. + // +optional + LastScaleTime *metav1.Time + + // CurrentReplicas is current number of replicas of pods managed by this autoscaler, + // as last seen by the autoscaler. + CurrentReplicas int32 + + // DesiredReplicas is the desired number of replicas of pods managed by this autoscaler, + // as last calculated by the autoscaler. + DesiredReplicas int32 + + // CurrentMetrics is the last read state of the metrics used by this autoscaler. + // +optional + CurrentMetrics []MetricStatus + + // Conditions is the set of conditions required for this autoscaler to scale its target, + // and indicates whether or not those conditions are met. + Conditions []HorizontalPodAutoscalerCondition +} + +// ConditionStatus indicates the status of a condition (true, false, or unknown). +type ConditionStatus string + +// These are valid condition statuses. "ConditionTrue" means a resource is in the condition; +// "ConditionFalse" means a resource is not in the condition; "ConditionUnknown" means kubernetes +// can't decide if a resource is in the condition or not. In the future, we could add other +// intermediate conditions, e.g. ConditionDegraded. +const ( + ConditionTrue ConditionStatus = "True" + ConditionFalse ConditionStatus = "False" + ConditionUnknown ConditionStatus = "Unknown" +) + +// HorizontalPodAutoscalerConditionType are the valid conditions of +// a HorizontalPodAutoscaler. +type HorizontalPodAutoscalerConditionType string + +const ( + // ScalingActive indicates that the HPA controller is able to scale if necessary: + // it's correctly configured, can fetch the desired metrics, and isn't disabled. + ScalingActive HorizontalPodAutoscalerConditionType = "ScalingActive" + // AbleToScale indicates a lack of transient issues which prevent scaling from occurring, + // such as being in a backoff window, or being unable to access/update the target scale. + AbleToScale HorizontalPodAutoscalerConditionType = "AbleToScale" + // ScalingLimited indicates that the calculated scale based on metrics would be above or + // below the range for the HPA, and has thus been capped. + ScalingLimited HorizontalPodAutoscalerConditionType = "ScalingLimited" +) + +// HorizontalPodAutoscalerCondition describes the state of +// a HorizontalPodAutoscaler at a certain point. +type HorizontalPodAutoscalerCondition struct { + // Type describes the current condition + Type HorizontalPodAutoscalerConditionType + // Status is the status of the condition (True, False, Unknown) + Status ConditionStatus + // LastTransitionTime is the last time the condition transitioned from + // one status to another + // +optional + LastTransitionTime metav1.Time + // Reason is the reason for the condition's last transition. + // +optional + Reason string + // Message is a human-readable explanation containing details about + // the transition + // +optional + Message string +} + +// MetricStatus describes the last-read state of a single metric. +type MetricStatus struct { + // Type is the type of metric source. It will be one of "Object", + // "Pods" or "Resource", each corresponds to a matching field in the object. + Type MetricSourceType + + // Object refers to a metric describing a single kubernetes object + // (for example, hits-per-second on an Ingress object). + // +optional + Object *ObjectMetricStatus + // Pods refers to a metric describing each pod in the current scale target + // (for example, transactions-processed-per-second). The values will be + // averaged together before being compared to the target value. + // +optional + Pods *PodsMetricStatus + // Resource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing each pod in the + // current scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics using the "pods" source. + // +optional + Resource *ResourceMetricStatus + // ContainerResource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing a single container in each pod in the + // current scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics using the "pods" source. + // +optional + ContainerResource *ContainerResourceMetricStatus + // External refers to a global metric that is not associated + // with any Kubernetes object. It allows autoscaling based on information + // coming from components running outside of cluster + // (for example length of queue in cloud messaging service, or + // QPS from loadbalancer running outside of cluster). + // +optional + External *ExternalMetricStatus +} + +// ObjectMetricStatus indicates the current value of a metric describing a +// kubernetes object (for example, hits-per-second on an Ingress object). +type ObjectMetricStatus struct { + Metric MetricIdentifier + Current MetricValueStatus + + DescribedObject CrossVersionObjectReference +} + +// PodsMetricStatus indicates the current value of a metric describing each pod in +// the current scale target (for example, transactions-processed-per-second). +type PodsMetricStatus struct { + Metric MetricIdentifier + Current MetricValueStatus +} + +// ResourceMetricStatus indicates the current value of a resource metric known to +// Kubernetes, as specified in requests and limits, describing each pod in the +// current scale target (e.g. CPU or memory). Such metrics are built in to +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. +type ResourceMetricStatus struct { + // Name is the name of the resource in question. + Name api.ResourceName + Current MetricValueStatus +} + +// ContainerResourceMetricStatus indicates the current value of a resource metric known to +// Kubernetes, as specified in requests and limits, describing each pod in the +// current scale target (e.g. CPU or memory). Such metrics are built in to +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. +type ContainerResourceMetricStatus struct { + // Name is the name of the resource in question. + Name api.ResourceName + Container string + Current MetricValueStatus +} + +// ExternalMetricStatus indicates the current value of a global metric +// not associated with any Kubernetes object. +type ExternalMetricStatus struct { + Metric MetricIdentifier + Current MetricValueStatus +} + +// MetricValueStatus indicates the current value of a metric. +type MetricValueStatus struct { + Value *resource.Quantity + AverageValue *resource.Quantity + AverageUtilization *int32 +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// HorizontalPodAutoscaler is the configuration for a horizontal pod +// autoscaler, which automatically manages the replica count of any resource +// implementing the scale subresource based on the metrics specified. +type HorizontalPodAutoscaler struct { + metav1.TypeMeta + // Metadata is the standard object metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // +optional + metav1.ObjectMeta + + // Spec is the specification for the behaviour of the autoscaler. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status. + // +optional + Spec HorizontalPodAutoscalerSpec + + // Status is the current information about the autoscaler. + // +optional + Status HorizontalPodAutoscalerStatus +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// HorizontalPodAutoscalerList is a list of horizontal pod autoscaler objects. +type HorizontalPodAutoscalerList struct { + metav1.TypeMeta + // Metadata is the standard list metadata. + // +optional + metav1.ListMeta + + // Items is the list of horizontal pod autoscaler objects. + Items []HorizontalPodAutoscaler +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/zz_generated.deepcopy.go b/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/zz_generated.deepcopy.go new file mode 100644 index 000000000..9f2d6c2e5 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/zz_generated.deepcopy.go @@ -0,0 +1,670 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package autoscaling + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerResourceMetricSource) DeepCopyInto(out *ContainerResourceMetricSource) { + *out = *in + in.Target.DeepCopyInto(&out.Target) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerResourceMetricSource. +func (in *ContainerResourceMetricSource) DeepCopy() *ContainerResourceMetricSource { + if in == nil { + return nil + } + out := new(ContainerResourceMetricSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerResourceMetricStatus) DeepCopyInto(out *ContainerResourceMetricStatus) { + *out = *in + in.Current.DeepCopyInto(&out.Current) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerResourceMetricStatus. +func (in *ContainerResourceMetricStatus) DeepCopy() *ContainerResourceMetricStatus { + if in == nil { + return nil + } + out := new(ContainerResourceMetricStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CrossVersionObjectReference) DeepCopyInto(out *CrossVersionObjectReference) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CrossVersionObjectReference. +func (in *CrossVersionObjectReference) DeepCopy() *CrossVersionObjectReference { + if in == nil { + return nil + } + out := new(CrossVersionObjectReference) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExternalMetricSource) DeepCopyInto(out *ExternalMetricSource) { + *out = *in + in.Metric.DeepCopyInto(&out.Metric) + in.Target.DeepCopyInto(&out.Target) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalMetricSource. +func (in *ExternalMetricSource) DeepCopy() *ExternalMetricSource { + if in == nil { + return nil + } + out := new(ExternalMetricSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExternalMetricStatus) DeepCopyInto(out *ExternalMetricStatus) { + *out = *in + in.Metric.DeepCopyInto(&out.Metric) + in.Current.DeepCopyInto(&out.Current) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalMetricStatus. +func (in *ExternalMetricStatus) DeepCopy() *ExternalMetricStatus { + if in == nil { + return nil + } + out := new(ExternalMetricStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HPAScalingPolicy) DeepCopyInto(out *HPAScalingPolicy) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HPAScalingPolicy. +func (in *HPAScalingPolicy) DeepCopy() *HPAScalingPolicy { + if in == nil { + return nil + } + out := new(HPAScalingPolicy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HPAScalingRules) DeepCopyInto(out *HPAScalingRules) { + *out = *in + if in.StabilizationWindowSeconds != nil { + in, out := &in.StabilizationWindowSeconds, &out.StabilizationWindowSeconds + *out = new(int32) + **out = **in + } + if in.SelectPolicy != nil { + in, out := &in.SelectPolicy, &out.SelectPolicy + *out = new(ScalingPolicySelect) + **out = **in + } + if in.Policies != nil { + in, out := &in.Policies, &out.Policies + *out = make([]HPAScalingPolicy, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HPAScalingRules. +func (in *HPAScalingRules) DeepCopy() *HPAScalingRules { + if in == nil { + return nil + } + out := new(HPAScalingRules) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HorizontalPodAutoscaler) DeepCopyInto(out *HorizontalPodAutoscaler) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HorizontalPodAutoscaler. +func (in *HorizontalPodAutoscaler) DeepCopy() *HorizontalPodAutoscaler { + if in == nil { + return nil + } + out := new(HorizontalPodAutoscaler) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HorizontalPodAutoscaler) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HorizontalPodAutoscalerBehavior) DeepCopyInto(out *HorizontalPodAutoscalerBehavior) { + *out = *in + if in.ScaleUp != nil { + in, out := &in.ScaleUp, &out.ScaleUp + *out = new(HPAScalingRules) + (*in).DeepCopyInto(*out) + } + if in.ScaleDown != nil { + in, out := &in.ScaleDown, &out.ScaleDown + *out = new(HPAScalingRules) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HorizontalPodAutoscalerBehavior. +func (in *HorizontalPodAutoscalerBehavior) DeepCopy() *HorizontalPodAutoscalerBehavior { + if in == nil { + return nil + } + out := new(HorizontalPodAutoscalerBehavior) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HorizontalPodAutoscalerCondition) DeepCopyInto(out *HorizontalPodAutoscalerCondition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HorizontalPodAutoscalerCondition. +func (in *HorizontalPodAutoscalerCondition) DeepCopy() *HorizontalPodAutoscalerCondition { + if in == nil { + return nil + } + out := new(HorizontalPodAutoscalerCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HorizontalPodAutoscalerList) DeepCopyInto(out *HorizontalPodAutoscalerList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]HorizontalPodAutoscaler, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HorizontalPodAutoscalerList. +func (in *HorizontalPodAutoscalerList) DeepCopy() *HorizontalPodAutoscalerList { + if in == nil { + return nil + } + out := new(HorizontalPodAutoscalerList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HorizontalPodAutoscalerList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HorizontalPodAutoscalerSpec) DeepCopyInto(out *HorizontalPodAutoscalerSpec) { + *out = *in + out.ScaleTargetRef = in.ScaleTargetRef + if in.MinReplicas != nil { + in, out := &in.MinReplicas, &out.MinReplicas + *out = new(int32) + **out = **in + } + if in.Metrics != nil { + in, out := &in.Metrics, &out.Metrics + *out = make([]MetricSpec, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Behavior != nil { + in, out := &in.Behavior, &out.Behavior + *out = new(HorizontalPodAutoscalerBehavior) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HorizontalPodAutoscalerSpec. +func (in *HorizontalPodAutoscalerSpec) DeepCopy() *HorizontalPodAutoscalerSpec { + if in == nil { + return nil + } + out := new(HorizontalPodAutoscalerSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HorizontalPodAutoscalerStatus) DeepCopyInto(out *HorizontalPodAutoscalerStatus) { + *out = *in + if in.ObservedGeneration != nil { + in, out := &in.ObservedGeneration, &out.ObservedGeneration + *out = new(int64) + **out = **in + } + if in.LastScaleTime != nil { + in, out := &in.LastScaleTime, &out.LastScaleTime + *out = (*in).DeepCopy() + } + if in.CurrentMetrics != nil { + in, out := &in.CurrentMetrics, &out.CurrentMetrics + *out = make([]MetricStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]HorizontalPodAutoscalerCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HorizontalPodAutoscalerStatus. +func (in *HorizontalPodAutoscalerStatus) DeepCopy() *HorizontalPodAutoscalerStatus { + if in == nil { + return nil + } + out := new(HorizontalPodAutoscalerStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricIdentifier) DeepCopyInto(out *MetricIdentifier) { + *out = *in + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricIdentifier. +func (in *MetricIdentifier) DeepCopy() *MetricIdentifier { + if in == nil { + return nil + } + out := new(MetricIdentifier) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricSpec) DeepCopyInto(out *MetricSpec) { + *out = *in + if in.Object != nil { + in, out := &in.Object, &out.Object + *out = new(ObjectMetricSource) + (*in).DeepCopyInto(*out) + } + if in.Pods != nil { + in, out := &in.Pods, &out.Pods + *out = new(PodsMetricSource) + (*in).DeepCopyInto(*out) + } + if in.Resource != nil { + in, out := &in.Resource, &out.Resource + *out = new(ResourceMetricSource) + (*in).DeepCopyInto(*out) + } + if in.ContainerResource != nil { + in, out := &in.ContainerResource, &out.ContainerResource + *out = new(ContainerResourceMetricSource) + (*in).DeepCopyInto(*out) + } + if in.External != nil { + in, out := &in.External, &out.External + *out = new(ExternalMetricSource) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricSpec. +func (in *MetricSpec) DeepCopy() *MetricSpec { + if in == nil { + return nil + } + out := new(MetricSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricStatus) DeepCopyInto(out *MetricStatus) { + *out = *in + if in.Object != nil { + in, out := &in.Object, &out.Object + *out = new(ObjectMetricStatus) + (*in).DeepCopyInto(*out) + } + if in.Pods != nil { + in, out := &in.Pods, &out.Pods + *out = new(PodsMetricStatus) + (*in).DeepCopyInto(*out) + } + if in.Resource != nil { + in, out := &in.Resource, &out.Resource + *out = new(ResourceMetricStatus) + (*in).DeepCopyInto(*out) + } + if in.ContainerResource != nil { + in, out := &in.ContainerResource, &out.ContainerResource + *out = new(ContainerResourceMetricStatus) + (*in).DeepCopyInto(*out) + } + if in.External != nil { + in, out := &in.External, &out.External + *out = new(ExternalMetricStatus) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricStatus. +func (in *MetricStatus) DeepCopy() *MetricStatus { + if in == nil { + return nil + } + out := new(MetricStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricTarget) DeepCopyInto(out *MetricTarget) { + *out = *in + if in.Value != nil { + in, out := &in.Value, &out.Value + x := (*in).DeepCopy() + *out = &x + } + if in.AverageValue != nil { + in, out := &in.AverageValue, &out.AverageValue + x := (*in).DeepCopy() + *out = &x + } + if in.AverageUtilization != nil { + in, out := &in.AverageUtilization, &out.AverageUtilization + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricTarget. +func (in *MetricTarget) DeepCopy() *MetricTarget { + if in == nil { + return nil + } + out := new(MetricTarget) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MetricValueStatus) DeepCopyInto(out *MetricValueStatus) { + *out = *in + if in.Value != nil { + in, out := &in.Value, &out.Value + x := (*in).DeepCopy() + *out = &x + } + if in.AverageValue != nil { + in, out := &in.AverageValue, &out.AverageValue + x := (*in).DeepCopy() + *out = &x + } + if in.AverageUtilization != nil { + in, out := &in.AverageUtilization, &out.AverageUtilization + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricValueStatus. +func (in *MetricValueStatus) DeepCopy() *MetricValueStatus { + if in == nil { + return nil + } + out := new(MetricValueStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ObjectMetricSource) DeepCopyInto(out *ObjectMetricSource) { + *out = *in + out.DescribedObject = in.DescribedObject + in.Target.DeepCopyInto(&out.Target) + in.Metric.DeepCopyInto(&out.Metric) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectMetricSource. +func (in *ObjectMetricSource) DeepCopy() *ObjectMetricSource { + if in == nil { + return nil + } + out := new(ObjectMetricSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ObjectMetricStatus) DeepCopyInto(out *ObjectMetricStatus) { + *out = *in + in.Metric.DeepCopyInto(&out.Metric) + in.Current.DeepCopyInto(&out.Current) + out.DescribedObject = in.DescribedObject + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectMetricStatus. +func (in *ObjectMetricStatus) DeepCopy() *ObjectMetricStatus { + if in == nil { + return nil + } + out := new(ObjectMetricStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodsMetricSource) DeepCopyInto(out *PodsMetricSource) { + *out = *in + in.Metric.DeepCopyInto(&out.Metric) + in.Target.DeepCopyInto(&out.Target) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodsMetricSource. +func (in *PodsMetricSource) DeepCopy() *PodsMetricSource { + if in == nil { + return nil + } + out := new(PodsMetricSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodsMetricStatus) DeepCopyInto(out *PodsMetricStatus) { + *out = *in + in.Metric.DeepCopyInto(&out.Metric) + in.Current.DeepCopyInto(&out.Current) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodsMetricStatus. +func (in *PodsMetricStatus) DeepCopy() *PodsMetricStatus { + if in == nil { + return nil + } + out := new(PodsMetricStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceMetricSource) DeepCopyInto(out *ResourceMetricSource) { + *out = *in + in.Target.DeepCopyInto(&out.Target) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceMetricSource. +func (in *ResourceMetricSource) DeepCopy() *ResourceMetricSource { + if in == nil { + return nil + } + out := new(ResourceMetricSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceMetricStatus) DeepCopyInto(out *ResourceMetricStatus) { + *out = *in + in.Current.DeepCopyInto(&out.Current) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceMetricStatus. +func (in *ResourceMetricStatus) DeepCopy() *ResourceMetricStatus { + if in == nil { + return nil + } + out := new(ResourceMetricStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Scale) DeepCopyInto(out *Scale) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Scale. +func (in *Scale) DeepCopy() *Scale { + if in == nil { + return nil + } + out := new(Scale) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Scale) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ScaleSpec) DeepCopyInto(out *ScaleSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScaleSpec. +func (in *ScaleSpec) DeepCopy() *ScaleSpec { + if in == nil { + return nil + } + out := new(ScaleSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ScaleStatus) DeepCopyInto(out *ScaleStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScaleStatus. +func (in *ScaleStatus) DeepCopy() *ScaleStatus { + if in == nil { + return nil + } + out := new(ScaleStatus) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/OWNERS b/vendor/k8s.io/kubernetes/pkg/apis/core/OWNERS new file mode 100644 index 000000000..688ea8bd0 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/OWNERS @@ -0,0 +1,4 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +labels: + - sig/apps diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/annotation_key_constants.go b/vendor/k8s.io/kubernetes/pkg/apis/core/annotation_key_constants.go new file mode 100644 index 000000000..3053200a2 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/annotation_key_constants.go @@ -0,0 +1,129 @@ +/* +Copyright 2017 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. +*/ + +// This file should be consistent with pkg/api/v1/annotation_key_constants.go. + +package core + +const ( + // ImagePolicyFailedOpenKey is added to pods created by failing open when the image policy + // webhook backend fails. + ImagePolicyFailedOpenKey string = "alpha.image-policy.k8s.io/failed-open" + + // MirrorPodAnnotationKey represents the annotation key set by kubelets when creating mirror pods + MirrorPodAnnotationKey string = "kubernetes.io/config.mirror" + + // TolerationsAnnotationKey represents the key of tolerations data (json serialized) + // in the Annotations of a Pod. + TolerationsAnnotationKey string = "scheduler.alpha.kubernetes.io/tolerations" + + // TaintsAnnotationKey represents the key of taints data (json serialized) + // in the Annotations of a Node. + TaintsAnnotationKey string = "scheduler.alpha.kubernetes.io/taints" + + // SeccompPodAnnotationKey represents the key of a seccomp profile applied + // to all containers of a pod. + // Deprecated: set a pod security context `seccompProfile` field. + SeccompPodAnnotationKey string = "seccomp.security.alpha.kubernetes.io/pod" + + // SeccompContainerAnnotationKeyPrefix represents the key of a seccomp profile applied + // to one container of a pod. + // Deprecated: set a container security context `seccompProfile` field. + SeccompContainerAnnotationKeyPrefix string = "container.seccomp.security.alpha.kubernetes.io/" + + // SeccompProfileRuntimeDefault represents the default seccomp profile used by container runtime. + // Deprecated: set a pod or container security context `seccompProfile` of type "RuntimeDefault" instead. + SeccompProfileRuntimeDefault string = "runtime/default" + + // DeprecatedSeccompProfileDockerDefault represents the default seccomp profile used by docker. + // Deprecated: set a pod or container security context `seccompProfile` of type "RuntimeDefault" instead. + DeprecatedSeccompProfileDockerDefault string = "docker/default" + + // PreferAvoidPodsAnnotationKey represents the key of preferAvoidPods data (json serialized) + // in the Annotations of a Node. + PreferAvoidPodsAnnotationKey string = "scheduler.alpha.kubernetes.io/preferAvoidPods" + + // ObjectTTLAnnotationKey represents a suggestion for kubelet for how long it can cache + // an object (e.g. secret, config map) before fetching it again from apiserver. + // This annotation can be attached to node. + ObjectTTLAnnotationKey string = "node.alpha.kubernetes.io/ttl" + + // NonConvertibleAnnotationPrefix annotation key prefix used to identify non-convertible json paths. + NonConvertibleAnnotationPrefix = "non-convertible.kubernetes.io" + + kubectlPrefix = "kubectl.kubernetes.io/" + + // LastAppliedConfigAnnotation is the annotation used to store the previous + // configuration of a resource for use in a three way diff by UpdateApplyAnnotation. + LastAppliedConfigAnnotation = kubectlPrefix + "last-applied-configuration" + + // AnnotationLoadBalancerSourceRangesKey is the key of the annotation on a service to set allowed ingress ranges on their LoadBalancers + // + // It should be a comma-separated list of CIDRs, e.g. `0.0.0.0/0` to + // allow full access (the default) or `18.0.0.0/8,56.0.0.0/8` to allow + // access only from the CIDRs currently allocated to MIT & the USPS. + // + // Not all cloud providers support this annotation, though AWS & GCE do. + AnnotationLoadBalancerSourceRangesKey = "service.beta.kubernetes.io/load-balancer-source-ranges" + + // EndpointsLastChangeTriggerTime is the annotation key, set for endpoints objects, that + // represents the timestamp (stored as RFC 3339 date-time string, e.g. '2018-10-22T19:32:52.1Z') + // of the last change, of some Pod or Service object, that triggered the endpoints object change. + // In other words, if a Pod / Service changed at time T0, that change was observed by endpoints + // controller at T1, and the Endpoints object was changed at T2, the + // EndpointsLastChangeTriggerTime would be set to T0. + // + // The "endpoints change trigger" here means any Pod or Service change that resulted in the + // Endpoints object change. + // + // Given the definition of the "endpoints change trigger", please note that this annotation will + // be set ONLY for endpoints object changes triggered by either Pod or Service change. If the + // Endpoints object changes due to other reasons, this annotation won't be set (or updated if it's + // already set). + // + // This annotation will be used to compute the in-cluster network programming latency SLI, see + // https://github.com/kubernetes/community/blob/master/sig-scalability/slos/network_programming_latency.md + EndpointsLastChangeTriggerTime = "endpoints.kubernetes.io/last-change-trigger-time" + + // EndpointsOverCapacity will be set on an Endpoints resource when it + // exceeds the maximum capacity of 1000 addresses. Initially the Endpoints + // controller will set this annotation with a value of "warning". In a + // future release, the controller may set this annotation with a value of + // "truncated" to indicate that any addresses exceeding the limit of 1000 + // have been truncated from the Endpoints resource. + EndpointsOverCapacity = "endpoints.kubernetes.io/over-capacity" + + // MigratedPluginsAnnotationKey is the annotation key, set for CSINode objects, that is a comma-separated + // list of in-tree plugins that will be serviced by the CSI backend on the Node represented by CSINode. + // This annotation is used by the Attach Detach Controller to determine whether to use the in-tree or + // CSI Backend for a volume plugin on a specific node. + MigratedPluginsAnnotationKey = "storage.alpha.kubernetes.io/migrated-plugins" + + // PodDeletionCost can be used to set to an int32 that represent the cost of deleting + // a pod compared to other pods belonging to the same ReplicaSet. Pods with lower + // deletion cost are preferred to be deleted before pods with higher deletion cost. + // Note that this is honored on a best-effort basis, and so it does not offer guarantees on + // pod deletion order. + // The implicit deletion cost for pods that don't set the annotation is 0, negative values are permitted. + // + // This annotation is beta-level and is only honored when PodDeletionCost feature is enabled. + PodDeletionCost = "controller.kubernetes.io/pod-deletion-cost" + + // AnnotationTopologyAwareHints can be used to enable or disable Topology + // Aware Hints for a Service. This may be set to "Auto" or "Disabled". Any + // other value is treated as "Disabled". + AnnotationTopologyAwareHints = "service.kubernetes.io/topology-aware-hints" +) diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/doc.go b/vendor/k8s.io/kubernetes/pkg/apis/core/doc.go new file mode 100644 index 000000000..6475fdab1 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/doc.go @@ -0,0 +1,24 @@ +/* +Copyright 2014 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. +*/ + +// +k8s:deepcopy-gen=package + +// Package core contains the latest (or "internal") version of the +// Kubernetes API objects. This is the API objects as represented in memory. +// The contract presented to clients is located in the versioned packages, +// which are sub-directories. The first one is "v1". Those packages +// describe how a particular version is serialized to storage/network. +package core // import "k8s.io/kubernetes/pkg/apis/core" diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/helper/helpers.go b/vendor/k8s.io/kubernetes/pkg/apis/core/helper/helpers.go new file mode 100644 index 000000000..4cdbae980 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/helper/helpers.go @@ -0,0 +1,515 @@ +/* +Copyright 2014 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 helper + +import ( + "encoding/json" + "fmt" + "strconv" + "strings" + + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/conversion" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/validation" + "k8s.io/kubernetes/pkg/apis/core" +) + +// IsHugePageResourceName returns true if the resource name has the huge page +// resource prefix. +func IsHugePageResourceName(name core.ResourceName) bool { + return strings.HasPrefix(string(name), core.ResourceHugePagesPrefix) +} + +// IsHugePageResourceValueDivisible returns true if the resource value of storage is +// integer multiple of page size. +func IsHugePageResourceValueDivisible(name core.ResourceName, quantity resource.Quantity) bool { + pageSize, err := HugePageSizeFromResourceName(name) + if err != nil { + return false + } + + if pageSize.Sign() <= 0 || pageSize.MilliValue()%int64(1000) != int64(0) { + return false + } + + return quantity.Value()%pageSize.Value() == 0 +} + +// IsQuotaHugePageResourceName returns true if the resource name has the quota +// related huge page resource prefix. +func IsQuotaHugePageResourceName(name core.ResourceName) bool { + return strings.HasPrefix(string(name), core.ResourceHugePagesPrefix) || strings.HasPrefix(string(name), core.ResourceRequestsHugePagesPrefix) +} + +// HugePageResourceName returns a ResourceName with the canonical hugepage +// prefix prepended for the specified page size. The page size is converted +// to its canonical representation. +func HugePageResourceName(pageSize resource.Quantity) core.ResourceName { + return core.ResourceName(fmt.Sprintf("%s%s", core.ResourceHugePagesPrefix, pageSize.String())) +} + +// HugePageSizeFromResourceName returns the page size for the specified huge page +// resource name. If the specified input is not a valid huge page resource name +// an error is returned. +func HugePageSizeFromResourceName(name core.ResourceName) (resource.Quantity, error) { + if !IsHugePageResourceName(name) { + return resource.Quantity{}, fmt.Errorf("resource name: %s is an invalid hugepage name", name) + } + pageSize := strings.TrimPrefix(string(name), core.ResourceHugePagesPrefix) + return resource.ParseQuantity(pageSize) +} + +// NonConvertibleFields iterates over the provided map and filters out all but +// any keys with the "non-convertible.kubernetes.io" prefix. +func NonConvertibleFields(annotations map[string]string) map[string]string { + nonConvertibleKeys := map[string]string{} + for key, value := range annotations { + if strings.HasPrefix(key, core.NonConvertibleAnnotationPrefix) { + nonConvertibleKeys[key] = value + } + } + return nonConvertibleKeys +} + +// Semantic can do semantic deep equality checks for core objects. +// Example: apiequality.Semantic.DeepEqual(aPod, aPodWithNonNilButEmptyMaps) == true +var Semantic = conversion.EqualitiesOrDie( + func(a, b resource.Quantity) bool { + // Ignore formatting, only care that numeric value stayed the same. + // TODO: if we decide it's important, it should be safe to start comparing the format. + // + // Uninitialized quantities are equivalent to 0 quantities. + return a.Cmp(b) == 0 + }, + func(a, b metav1.MicroTime) bool { + return a.UTC() == b.UTC() + }, + func(a, b metav1.Time) bool { + return a.UTC() == b.UTC() + }, + func(a, b labels.Selector) bool { + return a.String() == b.String() + }, + func(a, b fields.Selector) bool { + return a.String() == b.String() + }, +) + +var standardResourceQuotaScopes = sets.NewString( + string(core.ResourceQuotaScopeTerminating), + string(core.ResourceQuotaScopeNotTerminating), + string(core.ResourceQuotaScopeBestEffort), + string(core.ResourceQuotaScopeNotBestEffort), + string(core.ResourceQuotaScopePriorityClass), +) + +// IsStandardResourceQuotaScope returns true if the scope is a standard value +func IsStandardResourceQuotaScope(str string) bool { + return standardResourceQuotaScopes.Has(str) || str == string(core.ResourceQuotaScopeCrossNamespacePodAffinity) +} + +var podObjectCountQuotaResources = sets.NewString( + string(core.ResourcePods), +) + +var podComputeQuotaResources = sets.NewString( + string(core.ResourceCPU), + string(core.ResourceMemory), + string(core.ResourceLimitsCPU), + string(core.ResourceLimitsMemory), + string(core.ResourceRequestsCPU), + string(core.ResourceRequestsMemory), +) + +// IsResourceQuotaScopeValidForResource returns true if the resource applies to the specified scope +func IsResourceQuotaScopeValidForResource(scope core.ResourceQuotaScope, resource string) bool { + switch scope { + case core.ResourceQuotaScopeTerminating, core.ResourceQuotaScopeNotTerminating, core.ResourceQuotaScopeNotBestEffort, + core.ResourceQuotaScopePriorityClass, core.ResourceQuotaScopeCrossNamespacePodAffinity: + return podObjectCountQuotaResources.Has(resource) || podComputeQuotaResources.Has(resource) + case core.ResourceQuotaScopeBestEffort: + return podObjectCountQuotaResources.Has(resource) + default: + return true + } +} + +var standardContainerResources = sets.NewString( + string(core.ResourceCPU), + string(core.ResourceMemory), + string(core.ResourceEphemeralStorage), +) + +// IsStandardContainerResourceName returns true if the container can make a resource request +// for the specified resource +func IsStandardContainerResourceName(str string) bool { + return standardContainerResources.Has(str) || IsHugePageResourceName(core.ResourceName(str)) +} + +// IsExtendedResourceName returns true if: +// 1. the resource name is not in the default namespace; +// 2. resource name does not have "requests." prefix, +// to avoid confusion with the convention in quota +// 3. it satisfies the rules in IsQualifiedName() after converted into quota resource name +func IsExtendedResourceName(name core.ResourceName) bool { + if IsNativeResource(name) || strings.HasPrefix(string(name), core.DefaultResourceRequestsPrefix) { + return false + } + // Ensure it satisfies the rules in IsQualifiedName() after converted into quota resource name + nameForQuota := fmt.Sprintf("%s%s", core.DefaultResourceRequestsPrefix, string(name)) + if errs := validation.IsQualifiedName(nameForQuota); len(errs) != 0 { + return false + } + return true +} + +// IsNativeResource returns true if the resource name is in the +// *kubernetes.io/ namespace. Partially-qualified (unprefixed) names are +// implicitly in the kubernetes.io/ namespace. +func IsNativeResource(name core.ResourceName) bool { + return !strings.Contains(string(name), "/") || + strings.Contains(string(name), core.ResourceDefaultNamespacePrefix) +} + +// IsOvercommitAllowed returns true if the resource is in the default +// namespace and is not hugepages. +func IsOvercommitAllowed(name core.ResourceName) bool { + return IsNativeResource(name) && + !IsHugePageResourceName(name) +} + +var standardLimitRangeTypes = sets.NewString( + string(core.LimitTypePod), + string(core.LimitTypeContainer), + string(core.LimitTypePersistentVolumeClaim), +) + +// IsStandardLimitRangeType returns true if the type is Pod or Container +func IsStandardLimitRangeType(str string) bool { + return standardLimitRangeTypes.Has(str) +} + +var standardQuotaResources = sets.NewString( + string(core.ResourceCPU), + string(core.ResourceMemory), + string(core.ResourceEphemeralStorage), + string(core.ResourceRequestsCPU), + string(core.ResourceRequestsMemory), + string(core.ResourceRequestsStorage), + string(core.ResourceRequestsEphemeralStorage), + string(core.ResourceLimitsCPU), + string(core.ResourceLimitsMemory), + string(core.ResourceLimitsEphemeralStorage), + string(core.ResourcePods), + string(core.ResourceQuotas), + string(core.ResourceServices), + string(core.ResourceReplicationControllers), + string(core.ResourceSecrets), + string(core.ResourcePersistentVolumeClaims), + string(core.ResourceConfigMaps), + string(core.ResourceServicesNodePorts), + string(core.ResourceServicesLoadBalancers), +) + +// IsStandardQuotaResourceName returns true if the resource is known to +// the quota tracking system +func IsStandardQuotaResourceName(str string) bool { + return standardQuotaResources.Has(str) || IsQuotaHugePageResourceName(core.ResourceName(str)) +} + +var standardResources = sets.NewString( + string(core.ResourceCPU), + string(core.ResourceMemory), + string(core.ResourceEphemeralStorage), + string(core.ResourceRequestsCPU), + string(core.ResourceRequestsMemory), + string(core.ResourceRequestsEphemeralStorage), + string(core.ResourceLimitsCPU), + string(core.ResourceLimitsMemory), + string(core.ResourceLimitsEphemeralStorage), + string(core.ResourcePods), + string(core.ResourceQuotas), + string(core.ResourceServices), + string(core.ResourceReplicationControllers), + string(core.ResourceSecrets), + string(core.ResourceConfigMaps), + string(core.ResourcePersistentVolumeClaims), + string(core.ResourceStorage), + string(core.ResourceRequestsStorage), + string(core.ResourceServicesNodePorts), + string(core.ResourceServicesLoadBalancers), +) + +// IsStandardResourceName returns true if the resource is known to the system +func IsStandardResourceName(str string) bool { + return standardResources.Has(str) || IsQuotaHugePageResourceName(core.ResourceName(str)) +} + +var integerResources = sets.NewString( + string(core.ResourcePods), + string(core.ResourceQuotas), + string(core.ResourceServices), + string(core.ResourceReplicationControllers), + string(core.ResourceSecrets), + string(core.ResourceConfigMaps), + string(core.ResourcePersistentVolumeClaims), + string(core.ResourceServicesNodePorts), + string(core.ResourceServicesLoadBalancers), +) + +// IsIntegerResourceName returns true if the resource is measured in integer values +func IsIntegerResourceName(str string) bool { + return integerResources.Has(str) || IsExtendedResourceName(core.ResourceName(str)) +} + +// IsServiceIPSet aims to check if the service's ClusterIP is set or not +// the objective is not to perform validation here +func IsServiceIPSet(service *core.Service) bool { + // This function assumes that the service is semantically validated + // it does not test if the IP is valid, just makes sure that it is set. + return len(service.Spec.ClusterIP) > 0 && + service.Spec.ClusterIP != core.ClusterIPNone +} + +var standardFinalizers = sets.NewString( + string(core.FinalizerKubernetes), + metav1.FinalizerOrphanDependents, + metav1.FinalizerDeleteDependents, +) + +// IsStandardFinalizerName checks if the input string is a standard finalizer name +func IsStandardFinalizerName(str string) bool { + return standardFinalizers.Has(str) +} + +// GetAccessModesAsString returns a string representation of an array of access modes. +// modes, when present, are always in the same order: RWO,ROX,RWX,RWOP. +func GetAccessModesAsString(modes []core.PersistentVolumeAccessMode) string { + modes = removeDuplicateAccessModes(modes) + modesStr := []string{} + if ContainsAccessMode(modes, core.ReadWriteOnce) { + modesStr = append(modesStr, "RWO") + } + if ContainsAccessMode(modes, core.ReadOnlyMany) { + modesStr = append(modesStr, "ROX") + } + if ContainsAccessMode(modes, core.ReadWriteMany) { + modesStr = append(modesStr, "RWX") + } + if ContainsAccessMode(modes, core.ReadWriteOncePod) { + modesStr = append(modesStr, "RWOP") + } + return strings.Join(modesStr, ",") +} + +// GetAccessModesFromString returns an array of AccessModes from a string created by GetAccessModesAsString +func GetAccessModesFromString(modes string) []core.PersistentVolumeAccessMode { + strmodes := strings.Split(modes, ",") + accessModes := []core.PersistentVolumeAccessMode{} + for _, s := range strmodes { + s = strings.Trim(s, " ") + switch { + case s == "RWO": + accessModes = append(accessModes, core.ReadWriteOnce) + case s == "ROX": + accessModes = append(accessModes, core.ReadOnlyMany) + case s == "RWX": + accessModes = append(accessModes, core.ReadWriteMany) + case s == "RWOP": + accessModes = append(accessModes, core.ReadWriteOncePod) + } + } + return accessModes +} + +// removeDuplicateAccessModes returns an array of access modes without any duplicates +func removeDuplicateAccessModes(modes []core.PersistentVolumeAccessMode) []core.PersistentVolumeAccessMode { + accessModes := []core.PersistentVolumeAccessMode{} + for _, m := range modes { + if !ContainsAccessMode(accessModes, m) { + accessModes = append(accessModes, m) + } + } + return accessModes +} + +func ContainsAccessMode(modes []core.PersistentVolumeAccessMode, mode core.PersistentVolumeAccessMode) bool { + for _, m := range modes { + if m == mode { + return true + } + } + return false +} + +// GetTolerationsFromPodAnnotations gets the json serialized tolerations data from Pod.Annotations +// and converts it to the []Toleration type in core. +func GetTolerationsFromPodAnnotations(annotations map[string]string) ([]core.Toleration, error) { + var tolerations []core.Toleration + if len(annotations) > 0 && annotations[core.TolerationsAnnotationKey] != "" { + err := json.Unmarshal([]byte(annotations[core.TolerationsAnnotationKey]), &tolerations) + if err != nil { + return tolerations, err + } + } + return tolerations, nil +} + +// AddOrUpdateTolerationInPod tries to add a toleration to the pod's toleration list. +// Returns true if something was updated, false otherwise. +func AddOrUpdateTolerationInPod(pod *core.Pod, toleration *core.Toleration) bool { + podTolerations := pod.Spec.Tolerations + + var newTolerations []core.Toleration + updated := false + for i := range podTolerations { + if toleration.MatchToleration(&podTolerations[i]) { + if Semantic.DeepEqual(toleration, podTolerations[i]) { + return false + } + newTolerations = append(newTolerations, *toleration) + updated = true + continue + } + + newTolerations = append(newTolerations, podTolerations[i]) + } + + if !updated { + newTolerations = append(newTolerations, *toleration) + } + + pod.Spec.Tolerations = newTolerations + return true +} + +// GetTaintsFromNodeAnnotations gets the json serialized taints data from Pod.Annotations +// and converts it to the []Taint type in core. +func GetTaintsFromNodeAnnotations(annotations map[string]string) ([]core.Taint, error) { + var taints []core.Taint + if len(annotations) > 0 && annotations[core.TaintsAnnotationKey] != "" { + err := json.Unmarshal([]byte(annotations[core.TaintsAnnotationKey]), &taints) + if err != nil { + return []core.Taint{}, err + } + } + return taints, nil +} + +// GetPersistentVolumeClass returns StorageClassName. +func GetPersistentVolumeClass(volume *core.PersistentVolume) string { + // Use beta annotation first + if class, found := volume.Annotations[core.BetaStorageClassAnnotation]; found { + return class + } + + return volume.Spec.StorageClassName +} + +// GetPersistentVolumeClaimClass returns StorageClassName. If no storage class was +// requested, it returns "". +func GetPersistentVolumeClaimClass(claim *core.PersistentVolumeClaim) string { + // Use beta annotation first + if class, found := claim.Annotations[core.BetaStorageClassAnnotation]; found { + return class + } + + if claim.Spec.StorageClassName != nil { + return *claim.Spec.StorageClassName + } + + return "" +} + +// PersistentVolumeClaimHasClass returns true if given claim has set StorageClassName field. +func PersistentVolumeClaimHasClass(claim *core.PersistentVolumeClaim) bool { + // Use beta annotation first + if _, found := claim.Annotations[core.BetaStorageClassAnnotation]; found { + return true + } + + if claim.Spec.StorageClassName != nil { + return true + } + + return false +} + +func toResourceNames(resources core.ResourceList) []core.ResourceName { + result := []core.ResourceName{} + for resourceName := range resources { + result = append(result, resourceName) + } + return result +} + +func toSet(resourceNames []core.ResourceName) sets.String { + result := sets.NewString() + for _, resourceName := range resourceNames { + result.Insert(string(resourceName)) + } + return result +} + +// toContainerResourcesSet returns a set of resources names in container resource requirements +func toContainerResourcesSet(ctr *core.Container) sets.String { + resourceNames := toResourceNames(ctr.Resources.Requests) + resourceNames = append(resourceNames, toResourceNames(ctr.Resources.Limits)...) + return toSet(resourceNames) +} + +// ToPodResourcesSet returns a set of resource names in all containers in a pod. +func ToPodResourcesSet(podSpec *core.PodSpec) sets.String { + result := sets.NewString() + for i := range podSpec.InitContainers { + result = result.Union(toContainerResourcesSet(&podSpec.InitContainers[i])) + } + for i := range podSpec.Containers { + result = result.Union(toContainerResourcesSet(&podSpec.Containers[i])) + } + return result +} + +// GetDeletionCostFromPodAnnotations returns the integer value of pod-deletion-cost. Returns 0 +// if not set or the value is invalid. +func GetDeletionCostFromPodAnnotations(annotations map[string]string) (int32, error) { + if value, exist := annotations[core.PodDeletionCost]; exist { + // values that start with plus sign (e.g, "+10") or leading zeros (e.g., "008") are not valid. + if !validFirstDigit(value) { + return 0, fmt.Errorf("invalid value %q", value) + } + + i, err := strconv.ParseInt(value, 10, 32) + if err != nil { + // make sure we default to 0 on error. + return 0, err + } + return int32(i), nil + } + return 0, nil +} + +func validFirstDigit(str string) bool { + if len(str) == 0 { + return false + } + return str[0] == '-' || (str[0] == '0' && str == "0") || (str[0] >= '1' && str[0] <= '9') +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/json.go b/vendor/k8s.io/kubernetes/pkg/apis/core/json.go new file mode 100644 index 000000000..46702cb46 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/json.go @@ -0,0 +1,31 @@ +/* +Copyright 2017 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 core + +import "encoding/json" + +// This file implements json marshaling/unmarshaling interfaces on objects that are currently marshaled into annotations +// to prevent anyone from marshaling these internal structs. + +var _ = json.Marshaler(&AvoidPods{}) +var _ = json.Unmarshaler(&AvoidPods{}) + +// MarshalJSON panics to prevent marshalling of internal structs +func (AvoidPods) MarshalJSON() ([]byte, error) { panic("do not marshal internal struct") } + +// UnmarshalJSON panics to prevent unmarshalling of internal structs +func (*AvoidPods) UnmarshalJSON([]byte) error { panic("do not unmarshal to internal struct") } diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/objectreference.go b/vendor/k8s.io/kubernetes/pkg/apis/core/objectreference.go new file mode 100644 index 000000000..60f7e8a88 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/objectreference.go @@ -0,0 +1,37 @@ +/* +Copyright 2017 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. +*/ + +//TODO: consider making these methods functions, because we don't want helper +//functions in the k8s.io/api repo. + +package core + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// SetGroupVersionKind sets the API version and kind of the object reference +func (obj *ObjectReference) SetGroupVersionKind(gvk schema.GroupVersionKind) { + obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind() +} + +// GroupVersionKind returns the API version and kind of the object reference +func (obj *ObjectReference) GroupVersionKind() schema.GroupVersionKind { + return schema.FromAPIVersionAndKind(obj.APIVersion, obj.Kind) +} + +// GetObjectKind returns the kind of object reference +func (obj *ObjectReference) GetObjectKind() schema.ObjectKind { return obj } diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/pods/helpers.go b/vendor/k8s.io/kubernetes/pkg/apis/core/pods/helpers.go new file mode 100644 index 000000000..71810c500 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/pods/helpers.go @@ -0,0 +1,96 @@ +/* +Copyright 2017 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 pods + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/util/validation/field" + api "k8s.io/kubernetes/pkg/apis/core" + "k8s.io/kubernetes/pkg/fieldpath" +) + +// ContainerVisitorWithPath is called with each container and the field.Path to that container, +// and returns true if visiting should continue. +type ContainerVisitorWithPath func(container *api.Container, path *field.Path) bool + +// VisitContainersWithPath invokes the visitor function with a pointer to the spec +// of every container in the given pod spec and the field.Path to that container. +// If visitor returns false, visiting is short-circuited. VisitContainersWithPath returns true if visiting completes, +// false if visiting was short-circuited. +func VisitContainersWithPath(podSpec *api.PodSpec, specPath *field.Path, visitor ContainerVisitorWithPath) bool { + fldPath := specPath.Child("initContainers") + for i := range podSpec.InitContainers { + if !visitor(&podSpec.InitContainers[i], fldPath.Index(i)) { + return false + } + } + fldPath = specPath.Child("containers") + for i := range podSpec.Containers { + if !visitor(&podSpec.Containers[i], fldPath.Index(i)) { + return false + } + } + fldPath = specPath.Child("ephemeralContainers") + for i := range podSpec.EphemeralContainers { + if !visitor((*api.Container)(&podSpec.EphemeralContainers[i].EphemeralContainerCommon), fldPath.Index(i)) { + return false + } + } + return true +} + +// ConvertDownwardAPIFieldLabel converts the specified downward API field label +// and its value in the pod of the specified version to the internal version, +// and returns the converted label and value. This function returns an error if +// the conversion fails. +func ConvertDownwardAPIFieldLabel(version, label, value string) (string, string, error) { + if version != "v1" { + return "", "", fmt.Errorf("unsupported pod version: %s", version) + } + + if path, _, ok := fieldpath.SplitMaybeSubscriptedPath(label); ok { + switch path { + case "metadata.annotations", "metadata.labels": + return label, value, nil + default: + return "", "", fmt.Errorf("field label does not support subscript: %s", label) + } + } + + switch label { + case "metadata.annotations", + "metadata.labels", + "metadata.name", + "metadata.namespace", + "metadata.uid", + "spec.nodeName", + "spec.restartPolicy", + "spec.serviceAccountName", + "spec.schedulerName", + "status.phase", + "status.hostIP", + "status.podIP", + "status.podIPs": + return label, value, nil + // This is for backwards compatibility with old v1 clients which send spec.host + case "spec.host": + return "spec.nodeName", value, nil + default: + return "", "", fmt.Errorf("field label not supported: %s", label) + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/register.go b/vendor/k8s.io/kubernetes/pkg/apis/core/register.go new file mode 100644 index 000000000..882f31795 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/register.go @@ -0,0 +1,102 @@ +/* +Copyright 2014 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 core + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// GroupName is the group name use in this package +const GroupName = "" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal} + +// Kind takes an unqualified kind and returns a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + // SchemeBuilder object to register various known types + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + + // AddToScheme represents a func that can be used to apply all the registered + // funcs in a scheme + AddToScheme = SchemeBuilder.AddToScheme +) + +func addKnownTypes(scheme *runtime.Scheme) error { + if err := scheme.AddIgnoredConversionType(&metav1.TypeMeta{}, &metav1.TypeMeta{}); err != nil { + return err + } + scheme.AddKnownTypes(SchemeGroupVersion, + &Pod{}, + &PodList{}, + &PodStatusResult{}, + &PodTemplate{}, + &PodTemplateList{}, + &ReplicationControllerList{}, + &ReplicationController{}, + &ServiceList{}, + &Service{}, + &ServiceProxyOptions{}, + &NodeList{}, + &Node{}, + &NodeProxyOptions{}, + &Endpoints{}, + &EndpointsList{}, + &Binding{}, + &Event{}, + &EventList{}, + &List{}, + &LimitRange{}, + &LimitRangeList{}, + &ResourceQuota{}, + &ResourceQuotaList{}, + &Namespace{}, + &NamespaceList{}, + &ServiceAccount{}, + &ServiceAccountList{}, + &Secret{}, + &SecretList{}, + &PersistentVolume{}, + &PersistentVolumeList{}, + &PersistentVolumeClaim{}, + &PersistentVolumeClaimList{}, + &PodAttachOptions{}, + &PodLogOptions{}, + &PodExecOptions{}, + &PodPortForwardOptions{}, + &PodProxyOptions{}, + &ComponentStatus{}, + &ComponentStatusList{}, + &SerializedReference{}, + &RangeAllocation{}, + &ConfigMap{}, + &ConfigMapList{}, + ) + + return nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/resource.go b/vendor/k8s.io/kubernetes/pkg/apis/core/resource.go new file mode 100644 index 000000000..bde1e24ca --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/resource.go @@ -0,0 +1,58 @@ +/* +Copyright 2017 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 core + +import ( + "k8s.io/apimachinery/pkg/api/resource" +) + +func (rn ResourceName) String() string { + return string(rn) +} + +// CPU returns the CPU limit if specified. +func (rl *ResourceList) CPU() *resource.Quantity { + return rl.Name(ResourceCPU, resource.DecimalSI) +} + +// Memory returns the Memory limit if specified. +func (rl *ResourceList) Memory() *resource.Quantity { + return rl.Name(ResourceMemory, resource.BinarySI) +} + +// Storage returns the Storage limit if specified. +func (rl *ResourceList) Storage() *resource.Quantity { + return rl.Name(ResourceStorage, resource.BinarySI) +} + +// Pods returns the list of pods +func (rl *ResourceList) Pods() *resource.Quantity { + return rl.Name(ResourcePods, resource.DecimalSI) +} + +// StorageEphemeral returns the list of ephemeral storage volumes, if any +func (rl *ResourceList) StorageEphemeral() *resource.Quantity { + return rl.Name(ResourceEphemeralStorage, resource.BinarySI) +} + +// Name returns the resource with name if specified, otherwise it returns a nil quantity with default format. +func (rl *ResourceList) Name(name ResourceName, defaultFormat resource.Format) *resource.Quantity { + if val, ok := (*rl)[name]; ok { + return &val + } + return &resource.Quantity{Format: defaultFormat} +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/taint.go b/vendor/k8s.io/kubernetes/pkg/apis/core/taint.go new file mode 100644 index 000000000..2c800de9b --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/taint.go @@ -0,0 +1,42 @@ +/* +Copyright 2017 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. +*/ + +//TODO: consider making these methods functions, because we don't want helper +//functions in the k8s.io/api repo. + +package core + +import "fmt" + +// MatchTaint checks if the taint matches taintToMatch. Taints are unique by key:effect, +// if the two taints have same key:effect, regard as they match. +func (t *Taint) MatchTaint(taintToMatch Taint) bool { + return t.Key == taintToMatch.Key && t.Effect == taintToMatch.Effect +} + +// ToString converts taint struct to string in format '=:', '=:', ':', or ''. +func (t *Taint) ToString() string { + if len(t.Effect) == 0 { + if len(t.Value) == 0 { + return fmt.Sprintf("%v", t.Key) + } + return fmt.Sprintf("%v=%v:", t.Key, t.Value) + } + if len(t.Value) == 0 { + return fmt.Sprintf("%v:%v", t.Key, t.Effect) + } + return fmt.Sprintf("%v=%v:%v", t.Key, t.Value, t.Effect) +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/toleration.go b/vendor/k8s.io/kubernetes/pkg/apis/core/toleration.go new file mode 100644 index 000000000..1dfbc9f1b --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/toleration.go @@ -0,0 +1,30 @@ +/* +Copyright 2017 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. +*/ + +//TODO: consider making these methods functions, because we don't want helper +//functions in the k8s.io/api repo. + +package core + +// MatchToleration checks if the toleration matches tolerationToMatch. Tolerations are unique by , +// if the two tolerations have same combination, regard as they match. +// TODO: uniqueness check for tolerations in api validations. +func (t *Toleration) MatchToleration(tolerationToMatch *Toleration) bool { + return t.Key == tolerationToMatch.Key && + t.Effect == tolerationToMatch.Effect && + t.Operator == tolerationToMatch.Operator && + t.Value == tolerationToMatch.Value +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/types.go b/vendor/k8s.io/kubernetes/pkg/apis/core/types.go new file mode 100644 index 000000000..be71573e1 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/types.go @@ -0,0 +1,5907 @@ +/* +Copyright 2014 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 core + +import ( + "k8s.io/apimachinery/pkg/api/resource" + metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/intstr" +) + +const ( + // NamespaceDefault means the object is in the default namespace which is applied when not specified by clients + NamespaceDefault = "default" + // NamespaceAll is the default argument to specify on a context when you want to list or filter resources across all namespaces + NamespaceAll = "" + // NamespaceNone is the argument for a context when there is no namespace. + NamespaceNone = "" + // NamespaceSystem is the system namespace where we place system components. + NamespaceSystem = "kube-system" + // NamespacePublic is the namespace where we place public info (ConfigMaps) + NamespacePublic = "kube-public" + // NamespaceNodeLease is the namespace where we place node lease objects (used for node heartbeats) + NamespaceNodeLease = "kube-node-lease" + // TerminationMessagePathDefault means the default path to capture the application termination message running in a container + TerminationMessagePathDefault = "/dev/termination-log" +) + +// Volume represents a named volume in a pod that may be accessed by any containers in the pod. +type Volume struct { + // Required: This must be a DNS_LABEL. Each volume in a pod must have + // a unique name. + Name string + // The VolumeSource represents the location and type of a volume to mount. + // This is optional for now. If not specified, the Volume is implied to be an EmptyDir. + // This implied behavior is deprecated and will be removed in a future version. + // +optional + VolumeSource +} + +// VolumeSource represents the source location of a volume to mount. +// Only one of its members may be specified. +type VolumeSource struct { + // HostPath represents file or directory on the host machine that is + // directly exposed to the container. This is generally used for system + // agents or other privileged things that are allowed to see the host + // machine. Most containers will NOT need this. + // --- + // TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not + // mount host directories as read/write. + // +optional + HostPath *HostPathVolumeSource + // EmptyDir represents a temporary directory that shares a pod's lifetime. + // +optional + EmptyDir *EmptyDirVolumeSource + // GCEPersistentDisk represents a GCE Disk resource that is attached to a + // kubelet's host machine and then exposed to the pod. + // +optional + GCEPersistentDisk *GCEPersistentDiskVolumeSource + // AWSElasticBlockStore represents an AWS EBS disk that is attached to a + // kubelet's host machine and then exposed to the pod. + // +optional + AWSElasticBlockStore *AWSElasticBlockStoreVolumeSource + // GitRepo represents a git repository at a particular revision. + // DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an + // EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir + // into the Pod's container. + // +optional + GitRepo *GitRepoVolumeSource + // Secret represents a secret that should populate this volume. + // +optional + Secret *SecretVolumeSource + // NFS represents an NFS mount on the host that shares a pod's lifetime + // +optional + NFS *NFSVolumeSource + // ISCSIVolumeSource represents an ISCSI Disk resource that is attached to a + // kubelet's host machine and then exposed to the pod. + // +optional + ISCSI *ISCSIVolumeSource + // Glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime + // +optional + Glusterfs *GlusterfsVolumeSource + // PersistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace + // +optional + PersistentVolumeClaim *PersistentVolumeClaimVolumeSource + // RBD represents a Rados Block Device mount on the host that shares a pod's lifetime + // +optional + RBD *RBDVolumeSource + + // Quobyte represents a Quobyte mount on the host that shares a pod's lifetime + // +optional + Quobyte *QuobyteVolumeSource + + // FlexVolume represents a generic volume resource that is + // provisioned/attached using an exec based plugin. + // +optional + FlexVolume *FlexVolumeSource + + // Cinder represents a cinder volume attached and mounted on kubelet's host machine. + // +optional + Cinder *CinderVolumeSource + + // CephFS represents a Cephfs mount on the host that shares a pod's lifetime + // +optional + CephFS *CephFSVolumeSource + + // Flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running + // +optional + Flocker *FlockerVolumeSource + + // DownwardAPI represents metadata about the pod that should populate this volume + // +optional + DownwardAPI *DownwardAPIVolumeSource + // FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod. + // +optional + FC *FCVolumeSource + // AzureFile represents an Azure File Service mount on the host and bind mount to the pod. + // +optional + AzureFile *AzureFileVolumeSource + // ConfigMap represents a configMap that should populate this volume + // +optional + ConfigMap *ConfigMapVolumeSource + // VsphereVolume represents a vSphere volume attached and mounted on kubelet's host machine + // +optional + VsphereVolume *VsphereVirtualDiskVolumeSource + // AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. + // +optional + AzureDisk *AzureDiskVolumeSource + // PhotonPersistentDisk represents a Photon Controller persistent disk attached and mounted on kubelet's host machine + PhotonPersistentDisk *PhotonPersistentDiskVolumeSource + // Items for all in one resources secrets, configmaps, and downward API + Projected *ProjectedVolumeSource + // PortworxVolume represents a portworx volume attached and mounted on kubelet's host machine + // +optional + PortworxVolume *PortworxVolumeSource + // ScaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes. + // +optional + ScaleIO *ScaleIOVolumeSource + // StorageOS represents a StorageOS volume that is attached to the kubelet's host machine and mounted into the pod + // +optional + StorageOS *StorageOSVolumeSource + // CSI (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers. + // +optional + CSI *CSIVolumeSource + // Ephemeral represents a volume that is handled by a cluster storage driver. + // The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, + // and deleted when the pod is removed. + // + // Use this if: + // a) the volume is only needed while the pod runs, + // b) features of normal volumes like restoring from snapshot or capacity + // tracking are needed, + // c) the storage driver is specified through a storage class, and + // d) the storage driver supports dynamic volume provisioning through + // a PersistentVolumeClaim (see EphemeralVolumeSource for more + // information on the connection between this volume type + // and PersistentVolumeClaim). + // + // Use PersistentVolumeClaim or one of the vendor-specific + // APIs for volumes that persist for longer than the lifecycle + // of an individual pod. + // + // Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to + // be used that way - see the documentation of the driver for + // more information. + // + // A pod can use both types of ephemeral volumes and + // persistent volumes at the same time. + // + // +optional + Ephemeral *EphemeralVolumeSource +} + +// PersistentVolumeSource is similar to VolumeSource but meant for the administrator who creates PVs. +// Exactly one of its members must be set. +type PersistentVolumeSource struct { + // GCEPersistentDisk represents a GCE Disk resource that is attached to a + // kubelet's host machine and then exposed to the pod. + // +optional + GCEPersistentDisk *GCEPersistentDiskVolumeSource + // AWSElasticBlockStore represents an AWS EBS disk that is attached to a + // kubelet's host machine and then exposed to the pod. + // +optional + AWSElasticBlockStore *AWSElasticBlockStoreVolumeSource + // HostPath represents a directory on the host. + // Provisioned by a developer or tester. + // This is useful for single-node development and testing only! + // On-host storage is not supported in any way and WILL NOT WORK in a multi-node cluster. + // +optional + HostPath *HostPathVolumeSource + // Glusterfs represents a Glusterfs volume that is attached to a host and exposed to the pod + // +optional + Glusterfs *GlusterfsPersistentVolumeSource + // NFS represents an NFS mount on the host that shares a pod's lifetime + // +optional + NFS *NFSVolumeSource + // RBD represents a Rados Block Device mount on the host that shares a pod's lifetime + // +optional + RBD *RBDPersistentVolumeSource + // Quobyte represents a Quobyte mount on the host that shares a pod's lifetime + // +optional + Quobyte *QuobyteVolumeSource + // ISCSIPersistentVolumeSource represents an ISCSI resource that is attached to a + // kubelet's host machine and then exposed to the pod. + // +optional + ISCSI *ISCSIPersistentVolumeSource + // FlexVolume represents a generic volume resource that is + // provisioned/attached using an exec based plugin. + // +optional + FlexVolume *FlexPersistentVolumeSource + // Cinder represents a cinder volume attached and mounted on kubelet's host machine. + // +optional + Cinder *CinderPersistentVolumeSource + // CephFS represents a Ceph FS mount on the host that shares a pod's lifetime + // +optional + CephFS *CephFSPersistentVolumeSource + // FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod. + // +optional + FC *FCVolumeSource + // Flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running + // +optional + Flocker *FlockerVolumeSource + // AzureFile represents an Azure File Service mount on the host and bind mount to the pod. + // +optional + AzureFile *AzureFilePersistentVolumeSource + // VsphereVolume represents a vSphere volume attached and mounted on kubelet's host machine + // +optional + VsphereVolume *VsphereVirtualDiskVolumeSource + // AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. + // +optional + AzureDisk *AzureDiskVolumeSource + // PhotonPersistentDisk represents a Photon Controller persistent disk attached and mounted on kubelet's host machine + PhotonPersistentDisk *PhotonPersistentDiskVolumeSource + // PortworxVolume represents a portworx volume attached and mounted on kubelet's host machine + // +optional + PortworxVolume *PortworxVolumeSource + // ScaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes. + // +optional + ScaleIO *ScaleIOPersistentVolumeSource + // Local represents directly-attached storage with node affinity + // +optional + Local *LocalVolumeSource + // StorageOS represents a StorageOS volume that is attached to the kubelet's host machine and mounted into the pod + // More info: https://examples.k8s.io/volumes/storageos/README.md + // +optional + StorageOS *StorageOSPersistentVolumeSource + // CSI (Container Storage Interface) represents storage that is handled by an external CSI driver. + // +optional + CSI *CSIPersistentVolumeSource +} + +// PersistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace +type PersistentVolumeClaimVolumeSource struct { + // ClaimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume + ClaimName string + // Optional: Defaults to false (read/write). ReadOnly here + // will force the ReadOnly setting in VolumeMounts + // +optional + ReadOnly bool +} + +const ( + // BetaStorageClassAnnotation represents the beta/previous StorageClass annotation. + // It's deprecated and will be removed in a future release. (#51440) + BetaStorageClassAnnotation = "volume.beta.kubernetes.io/storage-class" + + // MountOptionAnnotation defines mount option annotation used in PVs + MountOptionAnnotation = "volume.beta.kubernetes.io/mount-options" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// PersistentVolume struct captures the details of the implementation of PV storage +type PersistentVolume struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + + // Spec defines a persistent volume owned by the cluster + // +optional + Spec PersistentVolumeSpec + + // Status represents the current information about persistent volume. + // +optional + Status PersistentVolumeStatus +} + +// PersistentVolumeSpec has most of the details required to define a persistent volume +type PersistentVolumeSpec struct { + // Resources represents the actual resources of the volume + Capacity ResourceList + // Source represents the location and type of a volume to mount. + PersistentVolumeSource + // AccessModes contains all ways the volume can be mounted + // +optional + AccessModes []PersistentVolumeAccessMode + // ClaimRef is part of a bi-directional binding between PersistentVolume and PersistentVolumeClaim. + // ClaimRef is expected to be non-nil when bound. + // claim.VolumeName is the authoritative bind between PV and PVC. + // When set to non-nil value, PVC.Spec.Selector of the referenced PVC is + // ignored, i.e. labels of this PV do not need to match PVC selector. + // +optional + ClaimRef *ObjectReference + // Optional: what happens to a persistent volume when released from its claim. + // +optional + PersistentVolumeReclaimPolicy PersistentVolumeReclaimPolicy + // Name of StorageClass to which this persistent volume belongs. Empty value + // means that this volume does not belong to any StorageClass. + // +optional + StorageClassName string + // A list of mount options, e.g. ["ro", "soft"]. Not validated - mount will + // simply fail if one is invalid. + // +optional + MountOptions []string + // volumeMode defines if a volume is intended to be used with a formatted filesystem + // or to remain in raw block state. Value of Filesystem is implied when not included in spec. + // +optional + VolumeMode *PersistentVolumeMode + // NodeAffinity defines constraints that limit what nodes this volume can be accessed from. + // This field influences the scheduling of pods that use this volume. + // +optional + NodeAffinity *VolumeNodeAffinity +} + +// VolumeNodeAffinity defines constraints that limit what nodes this volume can be accessed from. +type VolumeNodeAffinity struct { + // Required specifies hard node constraints that must be met. + Required *NodeSelector +} + +// PersistentVolumeReclaimPolicy describes a policy for end-of-life maintenance of persistent volumes +type PersistentVolumeReclaimPolicy string + +const ( + // PersistentVolumeReclaimRecycle means the volume will be recycled back into the pool of unbound persistent volumes on release from its claim. + // The volume plugin must support Recycling. + // DEPRECATED: The PersistentVolumeReclaimRecycle called Recycle is being deprecated. See announcement here: https://groups.google.com/forum/#!topic/kubernetes-dev/uexugCza84I + PersistentVolumeReclaimRecycle PersistentVolumeReclaimPolicy = "Recycle" + // PersistentVolumeReclaimDelete means the volume will be deleted from Kubernetes on release from its claim. + // The volume plugin must support Deletion. + PersistentVolumeReclaimDelete PersistentVolumeReclaimPolicy = "Delete" + // PersistentVolumeReclaimRetain means the volume will be left in its current phase (Released) for manual reclamation by the administrator. + // The default policy is Retain. + PersistentVolumeReclaimRetain PersistentVolumeReclaimPolicy = "Retain" +) + +// PersistentVolumeMode describes how a volume is intended to be consumed, either Block or Filesystem. +type PersistentVolumeMode string + +const ( + // PersistentVolumeBlock means the volume will not be formatted with a filesystem and will remain a raw block device. + PersistentVolumeBlock PersistentVolumeMode = "Block" + // PersistentVolumeFilesystem means the volume will be or is formatted with a filesystem. + PersistentVolumeFilesystem PersistentVolumeMode = "Filesystem" +) + +// PersistentVolumeStatus represents the status of PV storage +type PersistentVolumeStatus struct { + // Phase indicates if a volume is available, bound to a claim, or released by a claim + // +optional + Phase PersistentVolumePhase + // A human-readable message indicating details about why the volume is in this state. + // +optional + Message string + // Reason is a brief CamelCase string that describes any failure and is meant for machine parsing and tidy display in the CLI + // +optional + Reason string +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// PersistentVolumeList represents a list of PVs +type PersistentVolumeList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + Items []PersistentVolume +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// PersistentVolumeClaim is a user's request for and claim to a persistent volume +type PersistentVolumeClaim struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + + // Spec defines the volume requested by a pod author + // +optional + Spec PersistentVolumeClaimSpec + + // Status represents the current information about a claim + // +optional + Status PersistentVolumeClaimStatus +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// PersistentVolumeClaimList represents the list of PV claims +type PersistentVolumeClaimList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + Items []PersistentVolumeClaim +} + +// PersistentVolumeClaimSpec describes the common attributes of storage devices +// and allows a Source for provider-specific attributes +type PersistentVolumeClaimSpec struct { + // Contains the types of access modes required + // +optional + AccessModes []PersistentVolumeAccessMode + // A label query over volumes to consider for binding. This selector is + // ignored when VolumeName is set + // +optional + Selector *metav1.LabelSelector + // Resources represents the minimum resources required + // If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + // that are lower than previous value but must still be higher than capacity recorded in the + // status field of the claim. + // +optional + Resources ResourceRequirements + // VolumeName is the binding reference to the PersistentVolume backing this + // claim. When set to non-empty value Selector is not evaluated + // +optional + VolumeName string + // Name of the StorageClass required by the claim. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#class-1 + // +optional + StorageClassName *string + // volumeMode defines what type of volume is required by the claim. + // Value of Filesystem is implied when not included in claim spec. + // +optional + VolumeMode *PersistentVolumeMode + // This field can be used to specify either: + // * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + // * An existing PVC (PersistentVolumeClaim) + // If the provisioner or an external controller can support the specified data source, + // it will create a new volume based on the contents of the specified data source. + // When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, + // and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. + // If the namespace is specified, then dataSourceRef will not be copied to dataSource. + // +optional + DataSource *TypedLocalObjectReference + // Specifies the object from which to populate the volume with data, if a non-empty + // volume is desired. This may be any object from a non-empty API group (non + // core object) or a PersistentVolumeClaim object. + // When this field is specified, volume binding will only succeed if the type of + // the specified object matches some installed volume populator or dynamic + // provisioner. + // This field will replace the functionality of the dataSource field and as such + // if both fields are non-empty, they must have the same value. For backwards + // compatibility, when namespace isn't specified in dataSourceRef, + // both fields (dataSource and dataSourceRef) will be set to the same + // value automatically if one of them is empty and the other is non-empty. + // When namespace is specified in dataSourceRef, + // dataSource isn't set to the same value and must be empty. + // There are three important differences between dataSource and dataSourceRef: + // * While dataSource only allows two specific types of objects, dataSourceRef + // allows any non-core object, as well as PersistentVolumeClaim objects. + // * While dataSource ignores disallowed values (dropping them), dataSourceRef + // preserves all values, and generates an error if a disallowed value is + // specified. + // * While dataSource only allows local objects, dataSourceRef allows objects + // in any namespaces. + // (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + // (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + // +optional + DataSourceRef *TypedObjectReference +} + +type TypedObjectReference struct { + // APIGroup is the group for the resource being referenced. + // If APIGroup is not specified, the specified Kind must be in the core API group. + // For any other third-party types, APIGroup is required. + // +optional + APIGroup *string + // Kind is the type of resource being referenced + Kind string + // Name is the name of resource being referenced + Name string + // Namespace is the namespace of resource being referenced + // Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + // (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + // +featureGate=CrossNamespaceVolumeDataSource + // +optional + Namespace *string +} + +// PersistentVolumeClaimConditionType defines the condition of PV claim. +// Valid values are either "Resizing" or "FileSystemResizePending". +type PersistentVolumeClaimConditionType string + +// These are valid conditions of Pvc +const ( + // An user trigger resize of pvc has been started + PersistentVolumeClaimResizing PersistentVolumeClaimConditionType = "Resizing" + // PersistentVolumeClaimFileSystemResizePending - controller resize is finished and a file system resize is pending on node + PersistentVolumeClaimFileSystemResizePending PersistentVolumeClaimConditionType = "FileSystemResizePending" +) + +// +enum +type PersistentVolumeClaimResizeStatus string + +const ( + // When expansion is complete, the empty string is set by resize controller or kubelet. + PersistentVolumeClaimNoExpansionInProgress PersistentVolumeClaimResizeStatus = "" + // State set when resize controller starts expanding the volume in control-plane + PersistentVolumeClaimControllerExpansionInProgress PersistentVolumeClaimResizeStatus = "ControllerExpansionInProgress" + // State set when expansion has failed in resize controller with a terminal error. + // Transient errors such as timeout should not set this status and should leave ResizeStatus + // unmodified, so as resize controller can resume the volume expansion. + PersistentVolumeClaimControllerExpansionFailed PersistentVolumeClaimResizeStatus = "ControllerExpansionFailed" + // State set when resize controller has finished expanding the volume but further expansion is needed on the node. + PersistentVolumeClaimNodeExpansionPending PersistentVolumeClaimResizeStatus = "NodeExpansionPending" + // State set when kubelet starts expanding the volume. + PersistentVolumeClaimNodeExpansionInProgress PersistentVolumeClaimResizeStatus = "NodeExpansionInProgress" + // State set when expansion has failed in kubelet with a terminal error. Transient errors don't set NodeExpansionFailed. + PersistentVolumeClaimNodeExpansionFailed PersistentVolumeClaimResizeStatus = "NodeExpansionFailed" +) + +// PersistentVolumeClaimCondition represents the current condition of PV claim +type PersistentVolumeClaimCondition struct { + Type PersistentVolumeClaimConditionType + Status ConditionStatus + // +optional + LastProbeTime metav1.Time + // +optional + LastTransitionTime metav1.Time + // +optional + Reason string + // +optional + Message string +} + +// PersistentVolumeClaimStatus represents the status of PV claim +type PersistentVolumeClaimStatus struct { + // Phase represents the current phase of PersistentVolumeClaim + // +optional + Phase PersistentVolumeClaimPhase + // AccessModes contains all ways the volume backing the PVC can be mounted + // +optional + AccessModes []PersistentVolumeAccessMode + // Represents the actual resources of the underlying volume + // +optional + Capacity ResourceList + // +optional + Conditions []PersistentVolumeClaimCondition + // The storage resource within AllocatedResources tracks the capacity allocated to a PVC. It may + // be larger than the actual capacity when a volume expansion operation is requested. + // For storage quota, the larger value from allocatedResources and PVC.spec.resources is used. + // If allocatedResources is not set, PVC.spec.resources alone is used for quota calculation. + // If a volume expansion capacity request is lowered, allocatedResources is only + // lowered if there are no expansion operations in progress and if the actual volume capacity + // is equal or lower than the requested capacity. + // This is an alpha field and requires enabling RecoverVolumeExpansionFailure feature. + // +featureGate=RecoverVolumeExpansionFailure + // +optional + AllocatedResources ResourceList + // ResizeStatus stores status of resize operation. + // ResizeStatus is not set by default but when expansion is complete resizeStatus is set to empty + // string by resize controller or kubelet. + // This is an alpha field and requires enabling RecoverVolumeExpansionFailure feature. + // +featureGate=RecoverVolumeExpansionFailure + // +optional + ResizeStatus *PersistentVolumeClaimResizeStatus +} + +// PersistentVolumeAccessMode defines various access modes for PV. +type PersistentVolumeAccessMode string + +// These are the valid values for PersistentVolumeAccessMode +const ( + // can be mounted read/write mode to exactly 1 host + ReadWriteOnce PersistentVolumeAccessMode = "ReadWriteOnce" + // can be mounted in read-only mode to many hosts + ReadOnlyMany PersistentVolumeAccessMode = "ReadOnlyMany" + // can be mounted in read/write mode to many hosts + ReadWriteMany PersistentVolumeAccessMode = "ReadWriteMany" + // can be mounted read/write mode to exactly 1 pod + // cannot be used in combination with other access modes + ReadWriteOncePod PersistentVolumeAccessMode = "ReadWriteOncePod" +) + +// PersistentVolumePhase defines the phase in which a PV is +type PersistentVolumePhase string + +// These are the valid values for PersistentVolumePhase +const ( + // used for PersistentVolumes that are not available + VolumePending PersistentVolumePhase = "Pending" + // used for PersistentVolumes that are not yet bound + // Available volumes are held by the binder and matched to PersistentVolumeClaims + VolumeAvailable PersistentVolumePhase = "Available" + // used for PersistentVolumes that are bound + VolumeBound PersistentVolumePhase = "Bound" + // used for PersistentVolumes where the bound PersistentVolumeClaim was deleted + // released volumes must be recycled before becoming available again + // this phase is used by the persistent volume claim binder to signal to another process to reclaim the resource + VolumeReleased PersistentVolumePhase = "Released" + // used for PersistentVolumes that failed to be correctly recycled or deleted after being released from a claim + VolumeFailed PersistentVolumePhase = "Failed" +) + +// PersistentVolumeClaimPhase defines the phase of PV claim +type PersistentVolumeClaimPhase string + +// These are the valid value for PersistentVolumeClaimPhase +const ( + // used for PersistentVolumeClaims that are not yet bound + ClaimPending PersistentVolumeClaimPhase = "Pending" + // used for PersistentVolumeClaims that are bound + ClaimBound PersistentVolumeClaimPhase = "Bound" + // used for PersistentVolumeClaims that lost their underlying + // PersistentVolume. The claim was bound to a PersistentVolume and this + // volume does not exist any longer and all data on it was lost. + ClaimLost PersistentVolumeClaimPhase = "Lost" +) + +// HostPathType defines the type of host path for PV +type HostPathType string + +// These are the valid values for HostPathType +const ( + // For backwards compatible, leave it empty if unset + HostPathUnset HostPathType = "" + // If nothing exists at the given path, an empty directory will be created there + // as needed with file mode 0755, having the same group and ownership with Kubelet. + HostPathDirectoryOrCreate HostPathType = "DirectoryOrCreate" + // A directory must exist at the given path + HostPathDirectory HostPathType = "Directory" + // If nothing exists at the given path, an empty file will be created there + // as needed with file mode 0644, having the same group and ownership with Kubelet. + HostPathFileOrCreate HostPathType = "FileOrCreate" + // A file must exist at the given path + HostPathFile HostPathType = "File" + // A UNIX socket must exist at the given path + HostPathSocket HostPathType = "Socket" + // A character device must exist at the given path + HostPathCharDev HostPathType = "CharDevice" + // A block device must exist at the given path + HostPathBlockDev HostPathType = "BlockDevice" +) + +// HostPathVolumeSource represents a host path mapped into a pod. +// Host path volumes do not support ownership management or SELinux relabeling. +type HostPathVolumeSource struct { + // If the path is a symlink, it will follow the link to the real path. + Path string + // Defaults to "" + Type *HostPathType +} + +// EmptyDirVolumeSource represents an empty directory for a pod. +// Empty directory volumes support ownership management and SELinux relabeling. +type EmptyDirVolumeSource struct { + // TODO: Longer term we want to represent the selection of underlying + // media more like a scheduling problem - user says what traits they + // need, we give them a backing store that satisfies that. For now + // this will cover the most common needs. + // Optional: what type of storage medium should back this directory. + // The default is "" which means to use the node's default medium. + // +optional + Medium StorageMedium + // Total amount of local storage required for this EmptyDir volume. + // The size limit is also applicable for memory medium. + // The maximum usage on memory medium EmptyDir would be the minimum value between + // the SizeLimit specified here and the sum of memory limits of all containers in a pod. + // The default is nil which means that the limit is undefined. + // More info: http://kubernetes.io/docs/user-guide/volumes#emptydir + // +optional + SizeLimit *resource.Quantity +} + +// StorageMedium defines ways that storage can be allocated to a volume. +type StorageMedium string + +// These are the valid value for StorageMedium +const ( + StorageMediumDefault StorageMedium = "" // use whatever the default is for the node + StorageMediumMemory StorageMedium = "Memory" // use memory (tmpfs) + StorageMediumHugePages StorageMedium = "HugePages" // use hugepages + StorageMediumHugePagesPrefix StorageMedium = "HugePages-" // prefix for full medium notation HugePages- +) + +// Protocol defines network protocols supported for things like container ports. +type Protocol string + +const ( + // ProtocolTCP is the TCP protocol. + ProtocolTCP Protocol = "TCP" + // ProtocolUDP is the UDP protocol. + ProtocolUDP Protocol = "UDP" + // ProtocolSCTP is the SCTP protocol. + ProtocolSCTP Protocol = "SCTP" +) + +// GCEPersistentDiskVolumeSource represents a Persistent Disk resource in Google Compute Engine. +// +// A GCE PD must exist before mounting to a container. The disk must +// also be in the same GCE project and zone as the kubelet. A GCE PD +// can only be mounted as read/write once or read-only many times. GCE +// PDs support ownership management and SELinux relabeling. +type GCEPersistentDiskVolumeSource struct { + // Unique name of the PD resource. Used to identify the disk in GCE + PDName string + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // TODO: how do we prevent errors in the filesystem from compromising the machine + // +optional + FSType string + // Optional: Partition on the disk to mount. + // If omitted, kubelet will attempt to mount the device name. + // Ex. For /dev/sda1, this field is "1", for /dev/sda, this field is 0 or empty. + // +optional + Partition int32 + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool +} + +// ISCSIVolumeSource represents an ISCSI disk. +// ISCSI volumes can only be mounted as read/write once. +// ISCSI volumes support ownership management and SELinux relabeling. +type ISCSIVolumeSource struct { + // Required: iSCSI target portal + // the portal is either an IP or ip_addr:port if port is other than default (typically TCP ports 860 and 3260) + // +optional + TargetPortal string + // Required: target iSCSI Qualified Name + // +optional + IQN string + // Required: iSCSI target lun number + // +optional + Lun int32 + // Optional: Defaults to 'default' (tcp). iSCSI interface name that uses an iSCSI transport. + // +optional + ISCSIInterface string + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // TODO: how do we prevent errors in the filesystem from compromising the machine + // +optional + FSType string + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool + // Optional: list of iSCSI target portal ips for high availability. + // the portal is either an IP or ip_addr:port if port is other than default (typically TCP ports 860 and 3260) + // +optional + Portals []string + // Optional: whether support iSCSI Discovery CHAP authentication + // +optional + DiscoveryCHAPAuth bool + // Optional: whether support iSCSI Session CHAP authentication + // +optional + SessionCHAPAuth bool + // Optional: CHAP secret for iSCSI target and initiator authentication. + // The secret is used if either DiscoveryCHAPAuth or SessionCHAPAuth is true + // +optional + SecretRef *LocalObjectReference + // Optional: Custom initiator name per volume. + // If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface + // : will be created for the connection. + // +optional + InitiatorName *string +} + +// ISCSIPersistentVolumeSource represents an ISCSI disk. +// ISCSI volumes can only be mounted as read/write once. +// ISCSI volumes support ownership management and SELinux relabeling. +type ISCSIPersistentVolumeSource struct { + // Required: iSCSI target portal + // the portal is either an IP or ip_addr:port if port is other than default (typically TCP ports 860 and 3260) + // +optional + TargetPortal string + // Required: target iSCSI Qualified Name + // +optional + IQN string + // Required: iSCSI target lun number + // +optional + Lun int32 + // Optional: Defaults to 'default' (tcp). iSCSI interface name that uses an iSCSI transport. + // +optional + ISCSIInterface string + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // TODO: how do we prevent errors in the filesystem from compromising the machine + // +optional + FSType string + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool + // Optional: list of iSCSI target portal ips for high availability. + // the portal is either an IP or ip_addr:port if port is other than default (typically TCP ports 860 and 3260) + // +optional + Portals []string + // Optional: whether support iSCSI Discovery CHAP authentication + // +optional + DiscoveryCHAPAuth bool + // Optional: whether support iSCSI Session CHAP authentication + // +optional + SessionCHAPAuth bool + // Optional: CHAP secret for iSCSI target and initiator authentication. + // The secret is used if either DiscoveryCHAPAuth or SessionCHAPAuth is true + // +optional + SecretRef *SecretReference + // Optional: Custom initiator name per volume. + // If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface + // : will be created for the connection. + // +optional + InitiatorName *string +} + +// FCVolumeSource represents a Fibre Channel volume. +// Fibre Channel volumes can only be mounted as read/write once. +// Fibre Channel volumes support ownership management and SELinux relabeling. +type FCVolumeSource struct { + // Optional: FC target worldwide names (WWNs) + // +optional + TargetWWNs []string + // Optional: FC target lun number + // +optional + Lun *int32 + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // TODO: how do we prevent errors in the filesystem from compromising the machine + // +optional + FSType string + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool + // Optional: FC volume World Wide Identifiers (WWIDs) + // Either WWIDs or TargetWWNs and Lun must be set, but not both simultaneously. + // +optional + WWIDs []string +} + +// FlexPersistentVolumeSource represents a generic persistent volume resource that is +// provisioned/attached using an exec based plugin. +type FlexPersistentVolumeSource struct { + // Driver is the name of the driver to use for this volume. + Driver string + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. + // +optional + FSType string + // Optional: SecretRef is reference to the secret object containing + // sensitive information to pass to the plugin scripts. This may be + // empty if no secret object is specified. If the secret object + // contains more than one secret, all secrets are passed to the plugin + // scripts. + // +optional + SecretRef *SecretReference + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool + // Optional: Extra driver options if any. + // +optional + Options map[string]string +} + +// FlexVolumeSource represents a generic volume resource that is +// provisioned/attached using an exec based plugin. +type FlexVolumeSource struct { + // Driver is the name of the driver to use for this volume. + Driver string + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. + // +optional + FSType string + // Optional: SecretRef is reference to the secret object containing + // sensitive information to pass to the plugin scripts. This may be + // empty if no secret object is specified. If the secret object + // contains more than one secret, all secrets are passed to the plugin + // scripts. + // +optional + SecretRef *LocalObjectReference + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool + // Optional: Extra driver options if any. + // +optional + Options map[string]string +} + +// AWSElasticBlockStoreVolumeSource represents a Persistent Disk resource in AWS. +// +// An AWS EBS disk must exist before mounting to a container. The disk +// must also be in the same AWS zone as the kubelet. An AWS EBS disk +// can only be mounted as read/write once. AWS EBS volumes support +// ownership management and SELinux relabeling. +type AWSElasticBlockStoreVolumeSource struct { + // Unique id of the persistent disk resource. Used to identify the disk in AWS + VolumeID string + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // TODO: how do we prevent errors in the filesystem from compromising the machine + // +optional + FSType string + // Optional: Partition on the disk to mount. + // If omitted, kubelet will attempt to mount the device name. + // Ex. For /dev/sda1, this field is "1", for /dev/sda, this field is 0 or empty. + // +optional + Partition int32 + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool +} + +// GitRepoVolumeSource represents a volume that is populated with the contents of a git repository. +// Git repo volumes do not support ownership management. +// Git repo volumes support SELinux relabeling. +// +// DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an +// EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir +// into the Pod's container. +type GitRepoVolumeSource struct { + // Repository URL + Repository string + // Commit hash, this is optional + // +optional + Revision string + // Clone target, this is optional + // Must not contain or start with '..'. If '.' is supplied, the volume directory will be the + // git repository. Otherwise, if specified, the volume will contain the git repository in + // the subdirectory with the given name. + // +optional + Directory string + // TODO: Consider credentials here. +} + +// SecretVolumeSource adapts a Secret into a volume. +// +// The contents of the target Secret's Data field will be presented in a volume +// as files using the keys in the Data field as the file names. +// Secret volumes support ownership management and SELinux relabeling. +type SecretVolumeSource struct { + // Name of the secret in the pod's namespace to use. + // +optional + SecretName string + // If unspecified, each key-value pair in the Data field of the referenced + // Secret will be projected into the volume as a file whose name is the + // key and content is the value. If specified, the listed keys will be + // projected into the specified paths, and unlisted keys will not be + // present. If a key is specified which is not present in the Secret, + // the volume setup will error unless it is marked optional. Paths must be + // relative and may not contain the '..' path or start with '..'. + // +optional + Items []KeyToPath + // Mode bits to use on created files by default. Must be a value between + // 0 and 0777. + // Directories within the path are not affected by this setting. + // This might be in conflict with other options that affect the file + // mode, like fsGroup, and the result can be other mode bits set. + // +optional + DefaultMode *int32 + // Specify whether the Secret or its key must be defined + // +optional + Optional *bool +} + +// SecretProjection adapts a secret into a projected volume. +// +// The contents of the target Secret's Data field will be presented in a +// projected volume as files using the keys in the Data field as the file names. +// Note that this is identical to a secret volume source without the default +// mode. +type SecretProjection struct { + LocalObjectReference + // If unspecified, each key-value pair in the Data field of the referenced + // Secret will be projected into the volume as a file whose name is the + // key and content is the value. If specified, the listed keys will be + // projected into the specified paths, and unlisted keys will not be + // present. If a key is specified which is not present in the Secret, + // the volume setup will error unless it is marked optional. Paths must be + // relative and may not contain the '..' path or start with '..'. + // +optional + Items []KeyToPath + // Specify whether the Secret or its key must be defined + // +optional + Optional *bool +} + +// NFSVolumeSource represents an NFS mount that lasts the lifetime of a pod. +// NFS volumes do not support ownership management or SELinux relabeling. +type NFSVolumeSource struct { + // Server is the hostname or IP address of the NFS server + Server string + + // Path is the exported NFS share + Path string + + // Optional: Defaults to false (read/write). ReadOnly here will force + // the NFS export to be mounted with read-only permissions + // +optional + ReadOnly bool +} + +// QuobyteVolumeSource represents a Quobyte mount that lasts the lifetime of a pod. +// Quobyte volumes do not support ownership management or SELinux relabeling. +type QuobyteVolumeSource struct { + // Registry represents a single or multiple Quobyte Registry services + // specified as a string as host:port pair (multiple entries are separated with commas) + // which acts as the central registry for volumes + Registry string + + // Volume is a string that references an already created Quobyte volume by name. + Volume string + + // Defaults to false (read/write). ReadOnly here will force + // the Quobyte to be mounted with read-only permissions + // +optional + ReadOnly bool + + // User to map volume access to + // Defaults to the root user + // +optional + User string + + // Group to map volume access to + // Default is no group + // +optional + Group string + + // Tenant owning the given Quobyte volume in the Backend + // Used with dynamically provisioned Quobyte volumes, value is set by the plugin + // +optional + Tenant string +} + +// GlusterfsVolumeSource represents a Glusterfs mount that lasts the lifetime of a pod. +// Glusterfs volumes do not support ownership management or SELinux relabeling. +type GlusterfsVolumeSource struct { + // Required: EndpointsName is the endpoint name that details Glusterfs topology + EndpointsName string + + // Required: Path is the Glusterfs volume path + Path string + + // Optional: Defaults to false (read/write). ReadOnly here will force + // the Glusterfs to be mounted with read-only permissions + // +optional + ReadOnly bool +} + +// GlusterfsPersistentVolumeSource represents a Glusterfs mount that lasts the lifetime of a pod. +// Glusterfs volumes do not support ownership management or SELinux relabeling. +type GlusterfsPersistentVolumeSource struct { + // EndpointsName is the endpoint name that details Glusterfs topology. + // More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + EndpointsName string + + // Path is the Glusterfs volume path. + // More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + Path string + + // ReadOnly here will force the Glusterfs volume to be mounted with read-only permissions. + // Defaults to false. + // More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + // +optional + ReadOnly bool + + // EndpointsNamespace is the namespace that contains Glusterfs endpoint. + // If this field is empty, the EndpointNamespace defaults to the same namespace as the bound PVC. + // More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + // +optional + EndpointsNamespace *string +} + +// RBDVolumeSource represents a Rados Block Device mount that lasts the lifetime of a pod. +// RBD volumes support ownership management and SELinux relabeling. +type RBDVolumeSource struct { + // Required: CephMonitors is a collection of Ceph monitors + CephMonitors []string + // Required: RBDImage is the rados image name + RBDImage string + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // TODO: how do we prevent errors in the filesystem from compromising the machine + // +optional + FSType string + // Optional: RadosPool is the rados pool name,default is rbd + // +optional + RBDPool string + // Optional: RBDUser is the rados user name, default is admin + // +optional + RadosUser string + // Optional: Keyring is the path to key ring for RBDUser, default is /etc/ceph/keyring + // +optional + Keyring string + // Optional: SecretRef is name of the authentication secret for RBDUser, default is nil. + // +optional + SecretRef *LocalObjectReference + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool +} + +// RBDPersistentVolumeSource represents a Rados Block Device mount that lasts the lifetime of a pod. +// RBD volumes support ownership management and SELinux relabeling. +type RBDPersistentVolumeSource struct { + // Required: CephMonitors is a collection of Ceph monitors + CephMonitors []string + // Required: RBDImage is the rados image name + RBDImage string + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // TODO: how do we prevent errors in the filesystem from compromising the machine + // +optional + FSType string + // Optional: RadosPool is the rados pool name,default is rbd + // +optional + RBDPool string + // Optional: RBDUser is the rados user name, default is admin + // +optional + RadosUser string + // Optional: Keyring is the path to key ring for RBDUser, default is /etc/ceph/keyring + // +optional + Keyring string + // Optional: SecretRef is reference to the authentication secret for User, default is empty. + // +optional + SecretRef *SecretReference + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool +} + +// CinderVolumeSource represents a cinder volume resource in Openstack. A Cinder volume +// must exist before mounting to a container. The volume must also be +// in the same region as the kubelet. Cinder volumes support ownership +// management and SELinux relabeling. +type CinderVolumeSource struct { + // Unique id of the volume used to identify the cinder volume. + VolumeID string + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // +optional + FSType string + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool + // Optional: points to a secret object containing parameters used to connect + // to OpenStack. + // +optional + SecretRef *LocalObjectReference +} + +// CinderPersistentVolumeSource represents a cinder volume resource in Openstack. A Cinder volume +// must exist before mounting to a container. The volume must also be +// in the same region as the kubelet. Cinder volumes support ownership +// management and SELinux relabeling. +type CinderPersistentVolumeSource struct { + // Unique id of the volume used to identify the cinder volume. + VolumeID string + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // +optional + FSType string + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool + // Optional: points to a secret object containing parameters used to connect + // to OpenStack. + // +optional + SecretRef *SecretReference +} + +// CephFSVolumeSource represents a Ceph Filesystem mount that lasts the lifetime of a pod +// Cephfs volumes do not support ownership management or SELinux relabeling. +type CephFSVolumeSource struct { + // Required: Monitors is a collection of Ceph monitors + Monitors []string + // Optional: Used as the mounted root, rather than the full Ceph tree, default is / + // +optional + Path string + // Optional: User is the rados user name, default is admin + // +optional + User string + // Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret + // +optional + SecretFile string + // Optional: SecretRef is reference to the authentication secret for User, default is empty. + // +optional + SecretRef *LocalObjectReference + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool +} + +// SecretReference represents a Secret Reference. It has enough information to retrieve secret +// in any namespace +type SecretReference struct { + // Name is unique within a namespace to reference a secret resource. + // +optional + Name string + // Namespace defines the space within which the secret name must be unique. + // +optional + Namespace string +} + +// CephFSPersistentVolumeSource represents a Ceph Filesystem mount that lasts the lifetime of a pod +// Cephfs volumes do not support ownership management or SELinux relabeling. +type CephFSPersistentVolumeSource struct { + // Required: Monitors is a collection of Ceph monitors + Monitors []string + // Optional: Used as the mounted root, rather than the full Ceph tree, default is / + // +optional + Path string + // Optional: User is the rados user name, default is admin + // +optional + User string + // Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret + // +optional + SecretFile string + // Optional: SecretRef is reference to the authentication secret for User, default is empty. + // +optional + SecretRef *SecretReference + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool +} + +// FlockerVolumeSource represents a Flocker volume mounted by the Flocker agent. +// One and only one of datasetName and datasetUUID should be set. +// Flocker volumes do not support ownership management or SELinux relabeling. +type FlockerVolumeSource struct { + // Name of the dataset stored as metadata -> name on the dataset for Flocker + // should be considered as deprecated + // +optional + DatasetName string + // UUID of the dataset. This is unique identifier of a Flocker dataset + // +optional + DatasetUUID string +} + +// DownwardAPIVolumeSource represents a volume containing downward API info. +// Downward API volumes support ownership management and SELinux relabeling. +type DownwardAPIVolumeSource struct { + // Items is a list of DownwardAPIVolume file + // +optional + Items []DownwardAPIVolumeFile + // Mode bits to use on created files by default. Must be a value between + // 0 and 0777. + // Directories within the path are not affected by this setting. + // This might be in conflict with other options that affect the file + // mode, like fsGroup, and the result can be other mode bits set. + // +optional + DefaultMode *int32 +} + +// DownwardAPIVolumeFile represents a single file containing information from the downward API +type DownwardAPIVolumeFile struct { + // Required: Path is the relative path name of the file to be created. Must not be absolute or contain the '..' path. Must be utf-8 encoded. The first item of the relative path must not start with '..' + Path string + // Required: Selects a field of the pod: only annotations, labels, name, namespace and uid are supported. + // +optional + FieldRef *ObjectFieldSelector + // Selects a resource of the container: only resources limits and requests + // (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. + // +optional + ResourceFieldRef *ResourceFieldSelector + // Optional: mode bits to use on this file, must be a value between 0 + // and 0777. If not specified, the volume defaultMode will be used. + // This might be in conflict with other options that affect the file + // mode, like fsGroup, and the result can be other mode bits set. + // +optional + Mode *int32 +} + +// DownwardAPIProjection represents downward API info for projecting into a projected volume. +// Note that this is identical to a downwardAPI volume source without the default +// mode. +type DownwardAPIProjection struct { + // Items is a list of DownwardAPIVolume file + // +optional + Items []DownwardAPIVolumeFile +} + +// AzureFileVolumeSource azureFile represents an Azure File Service mount on the host and bind mount to the pod. +type AzureFileVolumeSource struct { + // the name of secret that contains Azure Storage Account Name and Key + SecretName string + // Share Name + ShareName string + // Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool +} + +// AzureFilePersistentVolumeSource represents an Azure File Service mount on the host and bind mount to the pod. +type AzureFilePersistentVolumeSource struct { + // the name of secret that contains Azure Storage Account Name and Key + SecretName string + // Share Name + ShareName string + // Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool + // the namespace of the secret that contains Azure Storage Account Name and Key + // default is the same as the Pod + // +optional + SecretNamespace *string +} + +// VsphereVirtualDiskVolumeSource represents a vSphere volume resource. +type VsphereVirtualDiskVolumeSource struct { + // Path that identifies vSphere volume vmdk + VolumePath string + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // +optional + FSType string + // Storage Policy Based Management (SPBM) profile name. + // +optional + StoragePolicyName string + // Storage Policy Based Management (SPBM) profile ID associated with the StoragePolicyName. + // +optional + StoragePolicyID string +} + +// PhotonPersistentDiskVolumeSource represents a Photon Controller persistent disk resource. +type PhotonPersistentDiskVolumeSource struct { + // ID that identifies Photon Controller persistent disk + PdID string + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + FSType string +} + +// PortworxVolumeSource represents a Portworx volume resource. +type PortworxVolumeSource struct { + // VolumeID uniquely identifies a Portworx volume + VolumeID string + // FSType represents the filesystem type to mount + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. + // +optional + FSType string + // Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool +} + +// AzureDataDiskCachingMode defines the caching mode for Azure data disk +type AzureDataDiskCachingMode string + +// AzureDataDiskKind defines the kind of Azure data disk +type AzureDataDiskKind string + +// Defines cache mode and kinds for Azure data disk +const ( + AzureDataDiskCachingNone AzureDataDiskCachingMode = "None" + AzureDataDiskCachingReadOnly AzureDataDiskCachingMode = "ReadOnly" + AzureDataDiskCachingReadWrite AzureDataDiskCachingMode = "ReadWrite" + + AzureSharedBlobDisk AzureDataDiskKind = "Shared" + AzureDedicatedBlobDisk AzureDataDiskKind = "Dedicated" + AzureManagedDisk AzureDataDiskKind = "Managed" +) + +// AzureDiskVolumeSource represents an Azure Data Disk mount on the host and bind mount to the pod. +type AzureDiskVolumeSource struct { + // The Name of the data disk in the blob storage + DiskName string + // The URI of the data disk in the blob storage + DataDiskURI string + // Host Caching mode: None, Read Only, Read Write. + // +optional + CachingMode *AzureDataDiskCachingMode + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // +optional + FSType *string + // Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly *bool + // Expected values Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared + Kind *AzureDataDiskKind +} + +// ScaleIOVolumeSource represents a persistent ScaleIO volume +type ScaleIOVolumeSource struct { + // The host address of the ScaleIO API Gateway. + Gateway string + // The name of the storage system as configured in ScaleIO. + System string + // SecretRef references to the secret for ScaleIO user and other + // sensitive information. If this is not provided, Login operation will fail. + SecretRef *LocalObjectReference + // Flag to enable/disable SSL communication with Gateway, default false + // +optional + SSLEnabled bool + // The name of the ScaleIO Protection Domain for the configured storage. + // +optional + ProtectionDomain string + // The ScaleIO Storage Pool associated with the protection domain. + // +optional + StoragePool string + // Indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. + // Default is ThinProvisioned. + // +optional + StorageMode string + // The name of a volume already created in the ScaleIO system + // that is associated with this volume source. + VolumeName string + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". + // Default is "xfs". + // +optional + FSType string + // Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool +} + +// ScaleIOPersistentVolumeSource represents a persistent ScaleIO volume that can be defined +// by a an admin via a storage class, for instance. +type ScaleIOPersistentVolumeSource struct { + // The host address of the ScaleIO API Gateway. + Gateway string + // The name of the storage system as configured in ScaleIO. + System string + // SecretRef references to the secret for ScaleIO user and other + // sensitive information. If this is not provided, Login operation will fail. + SecretRef *SecretReference + // Flag to enable/disable SSL communication with Gateway, default false + // +optional + SSLEnabled bool + // The name of the ScaleIO Protection Domain for the configured storage. + // +optional + ProtectionDomain string + // The ScaleIO Storage Pool associated with the protection domain. + // +optional + StoragePool string + // Indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. + // Default is ThinProvisioned. + // +optional + StorageMode string + // The name of a volume created in the ScaleIO system + // that is associated with this volume source. + VolumeName string + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". + // Default is "xfs". + // +optional + FSType string + // Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool +} + +// StorageOSVolumeSource represents a StorageOS persistent volume resource. +type StorageOSVolumeSource struct { + // VolumeName is the human-readable name of the StorageOS volume. Volume + // names are only unique within a namespace. + VolumeName string + // VolumeNamespace specifies the scope of the volume within StorageOS. If no + // namespace is specified then the Pod's namespace will be used. This allows the + // Kubernetes name scoping to be mirrored within StorageOS for tighter integration. + // Set VolumeName to any name to override the default behaviour. + // Set to "default" if you are not using namespaces within StorageOS. + // Namespaces that do not pre-exist within StorageOS will be created. + // +optional + VolumeNamespace string + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // +optional + FSType string + // Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool + // SecretRef specifies the secret to use for obtaining the StorageOS API + // credentials. If not specified, default values will be attempted. + // +optional + SecretRef *LocalObjectReference +} + +// StorageOSPersistentVolumeSource represents a StorageOS persistent volume resource. +type StorageOSPersistentVolumeSource struct { + // VolumeName is the human-readable name of the StorageOS volume. Volume + // names are only unique within a namespace. + VolumeName string + // VolumeNamespace specifies the scope of the volume within StorageOS. If no + // namespace is specified then the Pod's namespace will be used. This allows the + // Kubernetes name scoping to be mirrored within StorageOS for tighter integration. + // Set VolumeName to any name to override the default behaviour. + // Set to "default" if you are not using namespaces within StorageOS. + // Namespaces that do not pre-exist within StorageOS will be created. + // +optional + VolumeNamespace string + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // +optional + FSType string + // Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool + // SecretRef specifies the secret to use for obtaining the StorageOS API + // credentials. If not specified, default values will be attempted. + // +optional + SecretRef *ObjectReference +} + +// ConfigMapVolumeSource adapts a ConfigMap into a volume. +// +// The contents of the target ConfigMap's Data field will be presented in a +// volume as files using the keys in the Data field as the file names, unless +// the items element is populated with specific mappings of keys to paths. +// ConfigMap volumes support ownership management and SELinux relabeling. +type ConfigMapVolumeSource struct { + LocalObjectReference + // If unspecified, each key-value pair in the Data field of the referenced + // ConfigMap will be projected into the volume as a file whose name is the + // key and content is the value. If specified, the listed keys will be + // projected into the specified paths, and unlisted keys will not be + // present. If a key is specified which is not present in the ConfigMap, + // the volume setup will error unless it is marked optional. Paths must be + // relative and may not contain the '..' path or start with '..'. + // +optional + Items []KeyToPath + // Mode bits to use on created files by default. Must be a value between + // 0 and 0777. + // Directories within the path are not affected by this setting. + // This might be in conflict with other options that affect the file + // mode, like fsGroup, and the result can be other mode bits set. + // +optional + DefaultMode *int32 + // Specify whether the ConfigMap or its keys must be defined + // +optional + Optional *bool +} + +// ConfigMapProjection adapts a ConfigMap into a projected volume. +// +// The contents of the target ConfigMap's Data field will be presented in a +// projected volume as files using the keys in the Data field as the file names, +// unless the items element is populated with specific mappings of keys to paths. +// Note that this is identical to a configmap volume source without the default +// mode. +type ConfigMapProjection struct { + LocalObjectReference + // If unspecified, each key-value pair in the Data field of the referenced + // ConfigMap will be projected into the volume as a file whose name is the + // key and content is the value. If specified, the listed keys will be + // projected into the specified paths, and unlisted keys will not be + // present. If a key is specified which is not present in the ConfigMap, + // the volume setup will error unless it is marked optional. Paths must be + // relative and may not contain the '..' path or start with '..'. + // +optional + Items []KeyToPath + // Specify whether the ConfigMap or its keys must be defined + // +optional + Optional *bool +} + +// ServiceAccountTokenProjection represents a projected service account token +// volume. This projection can be used to insert a service account token into +// the pods runtime filesystem for use against APIs (Kubernetes API Server or +// otherwise). +type ServiceAccountTokenProjection struct { + // Audience is the intended audience of the token. A recipient of a token + // must identify itself with an identifier specified in the audience of the + // token, and otherwise should reject the token. The audience defaults to the + // identifier of the apiserver. + Audience string + // ExpirationSeconds is the requested duration of validity of the service + // account token. As the token approaches expiration, the kubelet volume + // plugin will proactively rotate the service account token. The kubelet will + // start trying to rotate the token if the token is older than 80 percent of + // its time to live or if the token is older than 24 hours.Defaults to 1 hour + // and must be at least 10 minutes. + ExpirationSeconds int64 + // Path is the path relative to the mount point of the file to project the + // token into. + Path string +} + +// ProjectedVolumeSource represents a projected volume source +type ProjectedVolumeSource struct { + // list of volume projections + Sources []VolumeProjection + // Mode bits to use on created files by default. Must be a value between + // 0 and 0777. + // Directories within the path are not affected by this setting. + // This might be in conflict with other options that affect the file + // mode, like fsGroup, and the result can be other mode bits set. + // +optional + DefaultMode *int32 +} + +// VolumeProjection that may be projected along with other supported volume types +type VolumeProjection struct { + // all types below are the supported types for projection into the same volume + + // information about the secret data to project + Secret *SecretProjection + // information about the downwardAPI data to project + DownwardAPI *DownwardAPIProjection + // information about the configMap data to project + ConfigMap *ConfigMapProjection + // information about the serviceAccountToken data to project + ServiceAccountToken *ServiceAccountTokenProjection +} + +// KeyToPath maps a string key to a path within a volume. +type KeyToPath struct { + // The key to project. + Key string + + // The relative path of the file to map the key to. + // May not be an absolute path. + // May not contain the path element '..'. + // May not start with the string '..'. + Path string + // Optional: mode bits to use on this file, should be a value between 0 + // and 0777. If not specified, the volume defaultMode will be used. + // This might be in conflict with other options that affect the file + // mode, like fsGroup, and the result can be other mode bits set. + // +optional + Mode *int32 +} + +// LocalVolumeSource represents directly-attached storage with node affinity (Beta feature) +type LocalVolumeSource struct { + // The full path to the volume on the node. + // It can be either a directory or block device (disk, partition, ...). + Path string + + // Filesystem type to mount. + // It applies only when the Path is a block device. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". The default value is to auto-select a filesystem if unspecified. + // +optional + FSType *string +} + +// CSIPersistentVolumeSource represents storage that is managed by an external CSI volume driver. +type CSIPersistentVolumeSource struct { + // Driver is the name of the driver to use for this volume. + // Required. + Driver string + + // VolumeHandle is the unique volume name returned by the CSI volume + // plugin’s CreateVolume to refer to the volume on all subsequent calls. + // Required. + VolumeHandle string + + // Optional: The value to pass to ControllerPublishVolumeRequest. + // Defaults to false (read/write). + // +optional + ReadOnly bool + + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". + // +optional + FSType string + + // Attributes of the volume to publish. + // +optional + VolumeAttributes map[string]string + + // ControllerPublishSecretRef is a reference to the secret object containing + // sensitive information to pass to the CSI driver to complete the CSI + // ControllerPublishVolume and ControllerUnpublishVolume calls. + // This field is optional, and may be empty if no secret is required. If the + // secret object contains more than one secret, all secrets are passed. + // +optional + ControllerPublishSecretRef *SecretReference + + // NodeStageSecretRef is a reference to the secret object containing sensitive + // information to pass to the CSI driver to complete the CSI NodeStageVolume + // and NodeStageVolume and NodeUnstageVolume calls. + // This field is optional, and may be empty if no secret is required. If the + // secret object contains more than one secret, all secrets are passed. + // +optional + NodeStageSecretRef *SecretReference + + // NodePublishSecretRef is a reference to the secret object containing + // sensitive information to pass to the CSI driver to complete the CSI + // NodePublishVolume and NodeUnpublishVolume calls. + // This field is optional, and may be empty if no secret is required. If the + // secret object contains more than one secret, all secrets are passed. + // +optional + NodePublishSecretRef *SecretReference + + // ControllerExpandSecretRef is a reference to the secret object containing + // sensitive information to pass to the CSI driver to complete the CSI + // ControllerExpandVolume call. + // This is an beta field and requires enabling ExpandCSIVolumes feature gate. + // This field is optional, and may be empty if no secret is required. If the + // secret object contains more than one secret, all secrets are passed. + // +optional + ControllerExpandSecretRef *SecretReference + + // NodeExpandSecretRef is a reference to the secret object containing + // sensitive information to pass to the CSI driver to complete the CSI + // NodeExpandVolume call. + // This is an alpha field and requires enabling CSINodeExpandSecret feature gate. + // This field is optional, may be omitted if no secret is required. If the + // secret object contains more than one secret, all secrets are passed. + // +optional + NodeExpandSecretRef *SecretReference +} + +// CSIVolumeSource represents a source location of a volume to mount, managed by an external CSI driver +type CSIVolumeSource struct { + // Driver is the name of the CSI driver that handles this volume. + // Consult with your admin for the correct name as registered in the cluster. + // Required. + Driver string + + // Specifies a read-only configuration for the volume. + // Defaults to false (read/write). + // +optional + ReadOnly *bool + + // Filesystem type to mount. Ex. "ext4", "xfs", "ntfs". + // If not provided, the empty value is passed to the associated CSI driver + // which will determine the default filesystem to apply. + // +optional + FSType *string + + // VolumeAttributes stores driver-specific properties that are passed to the CSI + // driver. Consult your driver's documentation for supported values. + // +optional + VolumeAttributes map[string]string + + // NodePublishSecretRef is a reference to the secret object containing + // sensitive information to pass to the CSI driver to complete the CSI + // NodePublishVolume and NodeUnpublishVolume calls. + // This field is optional, and may be empty if no secret is required. If the + // secret object contains more than one secret, all secret references are passed. + // +optional + NodePublishSecretRef *LocalObjectReference +} + +// EphemeralVolumeSource represents an ephemeral volume that is handled by a normal storage driver. +type EphemeralVolumeSource struct { + // VolumeClaimTemplate will be used to create a stand-alone PVC to provision the volume. + // The pod in which this EphemeralVolumeSource is embedded will be the + // owner of the PVC, i.e. the PVC will be deleted together with the + // pod. The name of the PVC will be `-` where + // `` is the name from the `PodSpec.Volumes` array + // entry. Pod validation will reject the pod if the concatenated name + // is not valid for a PVC (for example, too long). + // + // An existing PVC with that name that is not owned by the pod + // will *not* be used for the pod to avoid using an unrelated + // volume by mistake. Starting the pod is then blocked until + // the unrelated PVC is removed. If such a pre-created PVC is + // meant to be used by the pod, the PVC has to updated with an + // owner reference to the pod once the pod exists. Normally + // this should not be necessary, but it may be useful when + // manually reconstructing a broken cluster. + // + // This field is read-only and no changes will be made by Kubernetes + // to the PVC after it has been created. + // + // Required, must not be nil. + VolumeClaimTemplate *PersistentVolumeClaimTemplate +} + +// PersistentVolumeClaimTemplate is used to produce +// PersistentVolumeClaim objects as part of an EphemeralVolumeSource. +type PersistentVolumeClaimTemplate struct { + // ObjectMeta may contain labels and annotations that will be copied into the PVC + // when creating it. No other fields are allowed and will be rejected during + // validation. + // +optional + metav1.ObjectMeta + + // Spec for the PersistentVolumeClaim. The entire content is + // copied unchanged into the PVC that gets created from this + // template. The same fields as in a PersistentVolumeClaim + // are also valid here. + Spec PersistentVolumeClaimSpec +} + +// ContainerPort represents a network port in a single container +type ContainerPort struct { + // Optional: If specified, this must be an IANA_SVC_NAME Each named port + // in a pod must have a unique name. + // +optional + Name string + // Optional: If specified, this must be a valid port number, 0 < x < 65536. + // If HostNetwork is specified, this must match ContainerPort. + // +optional + HostPort int32 + // Required: This must be a valid port number, 0 < x < 65536. + ContainerPort int32 + // Required: Supports "TCP", "UDP" and "SCTP" + // +optional + Protocol Protocol + // Optional: What host IP to bind the external port to. + // +optional + HostIP string +} + +// VolumeMount describes a mounting of a Volume within a container. +type VolumeMount struct { + // Required: This must match the Name of a Volume [above]. + Name string + // Optional: Defaults to false (read-write). + // +optional + ReadOnly bool + // Required. If the path is not an absolute path (e.g. some/path) it + // will be prepended with the appropriate root prefix for the operating + // system. On Linux this is '/', on Windows this is 'C:\'. + MountPath string + // Path within the volume from which the container's volume should be mounted. + // Defaults to "" (volume's root). + // +optional + SubPath string + // mountPropagation determines how mounts are propagated from the host + // to container and the other way around. + // When not set, MountPropagationNone is used. + // This field is beta in 1.10. + // +optional + MountPropagation *MountPropagationMode + // Expanded path within the volume from which the container's volume should be mounted. + // Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. + // Defaults to "" (volume's root). + // SubPathExpr and SubPath are mutually exclusive. + // +optional + SubPathExpr string +} + +// MountPropagationMode describes mount propagation. +type MountPropagationMode string + +const ( + // MountPropagationNone means that the volume in a container will + // not receive new mounts from the host or other containers, and filesystems + // mounted inside the container won't be propagated to the host or other + // containers. + // Note that this mode corresponds to "private" in Linux terminology. + MountPropagationNone MountPropagationMode = "None" + // MountPropagationHostToContainer means that the volume in a container will + // receive new mounts from the host or other containers, but filesystems + // mounted inside the container won't be propagated to the host or other + // containers. + // Note that this mode is recursively applied to all mounts in the volume + // ("rslave" in Linux terminology). + MountPropagationHostToContainer MountPropagationMode = "HostToContainer" + // MountPropagationBidirectional means that the volume in a container will + // receive new mounts from the host or other containers, and its own mounts + // will be propagated from the container to the host or other containers. + // Note that this mode is recursively applied to all mounts in the volume + // ("rshared" in Linux terminology). + MountPropagationBidirectional MountPropagationMode = "Bidirectional" +) + +// VolumeDevice describes a mapping of a raw block device within a container. +type VolumeDevice struct { + // name must match the name of a persistentVolumeClaim in the pod + Name string + // devicePath is the path inside of the container that the device will be mapped to. + DevicePath string +} + +// EnvVar represents an environment variable present in a Container. +type EnvVar struct { + // Required: This must be a C_IDENTIFIER. + Name string + // Optional: no more than one of the following may be specified. + // Optional: Defaults to ""; variable references $(VAR_NAME) are expanded + // using the previously defined environment variables in the container and + // any service environment variables. If a variable cannot be resolved, + // the reference in the input string will be unchanged. Double $$ are + // reduced to a single $, which allows for escaping the $(VAR_NAME) + // syntax: i.e. "$$(VAR_NAME)" will produce the string literal + // "$(VAR_NAME)". Escaped references will never be expanded, + // regardless of whether the variable exists or not. + // +optional + Value string + // Optional: Specifies a source the value of this var should come from. + // +optional + ValueFrom *EnvVarSource +} + +// EnvVarSource represents a source for the value of an EnvVar. +// Only one of its fields may be set. +type EnvVarSource struct { + // Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + // metadata.uid, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + // +optional + FieldRef *ObjectFieldSelector + // Selects a resource of the container: only resources limits and requests + // (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + // +optional + ResourceFieldRef *ResourceFieldSelector + // Selects a key of a ConfigMap. + // +optional + ConfigMapKeyRef *ConfigMapKeySelector + // Selects a key of a secret in the pod's namespace. + // +optional + SecretKeyRef *SecretKeySelector +} + +// ObjectFieldSelector selects an APIVersioned field of an object. +type ObjectFieldSelector struct { + // Required: Version of the schema the FieldPath is written in terms of. + // If no value is specified, it will be defaulted to the APIVersion of the + // enclosing object. + APIVersion string + // Required: Path of the field to select in the specified API version + FieldPath string +} + +// ResourceFieldSelector represents container resources (cpu, memory) and their output format +type ResourceFieldSelector struct { + // Container name: required for volumes, optional for env vars + // +optional + ContainerName string + // Required: resource to select + Resource string + // Specifies the output format of the exposed resources, defaults to "1" + // +optional + Divisor resource.Quantity +} + +// ConfigMapKeySelector selects a key from a ConfigMap. +type ConfigMapKeySelector struct { + // The ConfigMap to select from. + LocalObjectReference + // The key to select. + Key string + // Specify whether the ConfigMap or its key must be defined + // +optional + Optional *bool +} + +// SecretKeySelector selects a key of a Secret. +type SecretKeySelector struct { + // The name of the secret in the pod's namespace to select from. + LocalObjectReference + // The key of the secret to select from. Must be a valid secret key. + Key string + // Specify whether the Secret or its key must be defined + // +optional + Optional *bool +} + +// EnvFromSource represents the source of a set of ConfigMaps +type EnvFromSource struct { + // An optional identifier to prepend to each key in the ConfigMap. + // +optional + Prefix string + // The ConfigMap to select from. + // +optional + ConfigMapRef *ConfigMapEnvSource + // The Secret to select from. + // +optional + SecretRef *SecretEnvSource +} + +// ConfigMapEnvSource selects a ConfigMap to populate the environment +// variables with. +// +// The contents of the target ConfigMap's Data field will represent the +// key-value pairs as environment variables. +type ConfigMapEnvSource struct { + // The ConfigMap to select from. + LocalObjectReference + // Specify whether the ConfigMap must be defined + // +optional + Optional *bool +} + +// SecretEnvSource selects a Secret to populate the environment +// variables with. +// +// The contents of the target Secret's Data field will represent the +// key-value pairs as environment variables. +type SecretEnvSource struct { + // The Secret to select from. + LocalObjectReference + // Specify whether the Secret must be defined + // +optional + Optional *bool +} + +// HTTPHeader describes a custom header to be used in HTTP probes +type HTTPHeader struct { + // The header field name + Name string + // The header field value + Value string +} + +// HTTPGetAction describes an action based on HTTP Get requests. +type HTTPGetAction struct { + // Optional: Path to access on the HTTP server. + // +optional + Path string + // Required: Name or number of the port to access on the container. + // +optional + Port intstr.IntOrString + // Optional: Host name to connect to, defaults to the pod IP. You + // probably want to set "Host" in httpHeaders instead. + // +optional + Host string + // Optional: Scheme to use for connecting to the host, defaults to HTTP. + // +optional + Scheme URIScheme + // Optional: Custom headers to set in the request. HTTP allows repeated headers. + // +optional + HTTPHeaders []HTTPHeader +} + +// URIScheme identifies the scheme used for connection to a host for Get actions +type URIScheme string + +const ( + // URISchemeHTTP means that the scheme used will be http:// + URISchemeHTTP URIScheme = "HTTP" + // URISchemeHTTPS means that the scheme used will be https:// + URISchemeHTTPS URIScheme = "HTTPS" +) + +// TCPSocketAction describes an action based on opening a socket +type TCPSocketAction struct { + // Required: Port to connect to. + // +optional + Port intstr.IntOrString + // Optional: Host name to connect to, defaults to the pod IP. + // +optional + Host string +} + +// ExecAction describes a "run in container" action. +type ExecAction struct { + // Command is the command line to execute inside the container, the working directory for the + // command is root ('/') in the container's filesystem. The command is simply exec'd, it is + // not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + // a shell, you need to explicitly call out to that shell. + // +optional + Command []string +} + +// Probe describes a health check to be performed against a container to determine whether it is +// alive or ready to receive traffic. +type Probe struct { + // The action taken to determine the health of a container + ProbeHandler + // Length of time before health checking is activated. In seconds. + // +optional + InitialDelaySeconds int32 + // Length of time before health checking times out. In seconds. + // +optional + TimeoutSeconds int32 + // How often (in seconds) to perform the probe. + // +optional + PeriodSeconds int32 + // Minimum consecutive successes for the probe to be considered successful after having failed. + // Must be 1 for liveness and startup. + // +optional + SuccessThreshold int32 + // Minimum consecutive failures for the probe to be considered failed after having succeeded. + // +optional + FailureThreshold int32 + // Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + // The grace period is the duration in seconds after the processes running in the pod are sent + // a termination signal and the time when the processes are forcibly halted with a kill signal. + // Set this value longer than the expected cleanup time for your process. + // If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + // value overrides the value provided by the pod spec. + // Value must be non-negative integer. The value zero indicates stop immediately via + // the kill signal (no opportunity to shut down). + // This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + // +optional + TerminationGracePeriodSeconds *int64 +} + +// PullPolicy describes a policy for if/when to pull a container image +type PullPolicy string + +const ( + // PullAlways means that kubelet always attempts to pull the latest image. Container will fail If the pull fails. + PullAlways PullPolicy = "Always" + // PullNever means that kubelet never pulls an image, but only uses a local image. Container will fail if the image isn't present + PullNever PullPolicy = "Never" + // PullIfNotPresent means that kubelet pulls if the image isn't present on disk. Container will fail if the image isn't present and the pull fails. + PullIfNotPresent PullPolicy = "IfNotPresent" +) + +// PreemptionPolicy describes a policy for if/when to preempt a pod. +type PreemptionPolicy string + +const ( + // PreemptLowerPriority means that pod can preempt other pods with lower priority. + PreemptLowerPriority PreemptionPolicy = "PreemptLowerPriority" + // PreemptNever means that pod never preempts other pods with lower priority. + PreemptNever PreemptionPolicy = "Never" +) + +// TerminationMessagePolicy describes how termination messages are retrieved from a container. +type TerminationMessagePolicy string + +const ( + // TerminationMessageReadFile is the default behavior and will set the container status message to + // the contents of the container's terminationMessagePath when the container exits. + TerminationMessageReadFile TerminationMessagePolicy = "File" + // TerminationMessageFallbackToLogsOnError will read the most recent contents of the container logs + // for the container status message when the container exits with an error and the + // terminationMessagePath has no contents. + TerminationMessageFallbackToLogsOnError TerminationMessagePolicy = "FallbackToLogsOnError" +) + +// Capability represent POSIX capabilities type +type Capability string + +// Capabilities represent POSIX capabilities that can be added or removed to a running container. +type Capabilities struct { + // Added capabilities + // +optional + Add []Capability + // Removed capabilities + // +optional + Drop []Capability +} + +// ResourceRequirements describes the compute resource requirements. +type ResourceRequirements struct { + // Limits describes the maximum amount of compute resources allowed. + // +optional + Limits ResourceList + // Requests describes the minimum amount of compute resources required. + // If Request is omitted for a container, it defaults to Limits if that is explicitly specified, + // otherwise to an implementation-defined value + // +optional + Requests ResourceList + // Claims lists the names of resources, defined in spec.resourceClaims, + // that are used by this container. + // + // This is an alpha field and requires enabling the + // DynamicResourceAllocation feature gate. + // + // This field is immutable. It can only be set for containers. + // + // +featureGate=DynamicResourceAllocation + // +optional + Claims []ResourceClaim +} + +// ResourceClaim references one entry in PodSpec.ResourceClaims. +type ResourceClaim struct { + // Name must match the name of one entry in pod.spec.resourceClaims of + // the Pod where this field is used. It makes that resource available + // inside a container. + Name string +} + +// Container represents a single container that is expected to be run on the host. +type Container struct { + // Required: This must be a DNS_LABEL. Each container in a pod must + // have a unique name. + Name string + // Required. + Image string + // Optional: The container image's entrypoint is used if this is not provided; cannot be updated. + // Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + // cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + // to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + // produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + // of whether the variable exists or not. + // +optional + Command []string + // Optional: The container image's cmd is used if this is not provided; cannot be updated. + // Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + // cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + // to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + // produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + // of whether the variable exists or not. + // +optional + Args []string + // Optional: Defaults to the container runtime's default working directory. + // +optional + WorkingDir string + // +optional + Ports []ContainerPort + // List of sources to populate environment variables in the container. + // The keys defined within a source must be a C_IDENTIFIER. All invalid keys + // will be reported as an event when the container is starting. When a key exists in multiple + // sources, the value associated with the last source will take precedence. + // Values defined by an Env with a duplicate key will take precedence. + // Cannot be updated. + // +optional + EnvFrom []EnvFromSource + // +optional + Env []EnvVar + // Compute resource requirements. + // +optional + Resources ResourceRequirements + // +optional + VolumeMounts []VolumeMount + // volumeDevices is the list of block devices to be used by the container. + // +optional + VolumeDevices []VolumeDevice + // +optional + LivenessProbe *Probe + // +optional + ReadinessProbe *Probe + // +optional + StartupProbe *Probe + // +optional + Lifecycle *Lifecycle + // Required. + // +optional + TerminationMessagePath string + // +optional + TerminationMessagePolicy TerminationMessagePolicy + // Required: Policy for pulling images for this container + ImagePullPolicy PullPolicy + // Optional: SecurityContext defines the security options the container should be run with. + // If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. + // +optional + SecurityContext *SecurityContext + + // Variables for interactive containers, these have very specialized use-cases (e.g. debugging) + // and shouldn't be used for general purpose containers. + // +optional + Stdin bool + // +optional + StdinOnce bool + // +optional + TTY bool +} + +// ProbeHandler defines a specific action that should be taken in a probe. +// One and only one of the fields must be specified. +type ProbeHandler struct { + // Exec specifies the action to take. + // +optional + Exec *ExecAction + // HTTPGet specifies the http request to perform. + // +optional + HTTPGet *HTTPGetAction + // TCPSocket specifies an action involving a TCP port. + // +optional + TCPSocket *TCPSocketAction + + // GRPC specifies an action involving a GRPC port. + // This is a beta field and requires enabling GRPCContainerProbe feature gate. + // +featureGate=GRPCContainerProbe + // +optional + GRPC *GRPCAction +} + +// LifecycleHandler defines a specific action that should be taken in a lifecycle +// hook. One and only one of the fields, except TCPSocket must be specified. +type LifecycleHandler struct { + // Exec specifies the action to take. + // +optional + Exec *ExecAction + // HTTPGet specifies the http request to perform. + // +optional + HTTPGet *HTTPGetAction + // Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept + // for the backward compatibility. There are no validation of this field and + // lifecycle hooks will fail in runtime when tcp handler is specified. + // +optional + TCPSocket *TCPSocketAction +} + +type GRPCAction struct { + // Port number of the gRPC service. + // Note: Number must be in the range 1 to 65535. + Port int32 + + // Service is the name of the service to place in the gRPC HealthCheckRequest + // (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + // + // If this is not specified, the default behavior is to probe the server's overall health status. + // +optional + Service *string +} + +// Lifecycle describes actions that the management system should take in response to container lifecycle +// events. For the PostStart and PreStop lifecycle handlers, management of the container blocks +// until the action is complete, unless the container process fails, in which case the handler is aborted. +type Lifecycle struct { + // PostStart is called immediately after a container is created. If the handler fails, the container + // is terminated and restarted. + // More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + // +optional + PostStart *LifecycleHandler + // PreStop is called immediately before a container is terminated due to an + // API request or management event such as liveness/startup probe failure, + // preemption, resource contention, etc. The handler is not called if the + // container crashes or exits. The Pod's termination grace period countdown begins before the + // PreStop hook is executed. Regardless of the outcome of the handler, the + // container will eventually terminate within the Pod's termination grace + // period (unless delayed by finalizers). Other management of the container blocks until the hook completes + // or until the termination grace period is reached. + // More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + // +optional + PreStop *LifecycleHandler +} + +// The below types are used by kube_client and api_server. + +// ConditionStatus defines conditions of resources +type ConditionStatus string + +// These are valid condition statuses. "ConditionTrue" means a resource is in the condition; +// "ConditionFalse" means a resource is not in the condition; "ConditionUnknown" means kubernetes +// can't decide if a resource is in the condition or not. In the future, we could add other +// intermediate conditions, e.g. ConditionDegraded. +const ( + ConditionTrue ConditionStatus = "True" + ConditionFalse ConditionStatus = "False" + ConditionUnknown ConditionStatus = "Unknown" +) + +// ContainerStateWaiting represents the waiting state of a container +type ContainerStateWaiting struct { + // A brief CamelCase string indicating details about why the container is in waiting state. + // +optional + Reason string + // A human-readable message indicating details about why the container is in waiting state. + // +optional + Message string +} + +// ContainerStateRunning represents the running state of a container +type ContainerStateRunning struct { + // +optional + StartedAt metav1.Time +} + +// ContainerStateTerminated represents the terminated state of a container +type ContainerStateTerminated struct { + ExitCode int32 + // +optional + Signal int32 + // +optional + Reason string + // +optional + Message string + // +optional + StartedAt metav1.Time + // +optional + FinishedAt metav1.Time + // +optional + ContainerID string +} + +// ContainerState holds a possible state of container. +// Only one of its members may be specified. +// If none of them is specified, the default one is ContainerStateWaiting. +type ContainerState struct { + // +optional + Waiting *ContainerStateWaiting + // +optional + Running *ContainerStateRunning + // +optional + Terminated *ContainerStateTerminated +} + +// ContainerStatus represents the status of a container +type ContainerStatus struct { + // Each container in a pod must have a unique name. + Name string + // +optional + State ContainerState + // +optional + LastTerminationState ContainerState + // Ready specifies whether the container has passed its readiness check. + Ready bool + // Note that this is calculated from dead containers. But those containers are subject to + // garbage collection. This value will get capped at 5 by GC. + RestartCount int32 + Image string + ImageID string + // +optional + ContainerID string + Started *bool +} + +// PodPhase is a label for the condition of a pod at the current time. +type PodPhase string + +// These are the valid statuses of pods. +const ( + // PodPending means the pod has been accepted by the system, but one or more of the containers + // has not been started. This includes time before being bound to a node, as well as time spent + // pulling images onto the host. + PodPending PodPhase = "Pending" + // PodRunning means the pod has been bound to a node and all of the containers have been started. + // At least one container is still running or is in the process of being restarted. + PodRunning PodPhase = "Running" + // PodSucceeded means that all containers in the pod have voluntarily terminated + // with a container exit code of 0, and the system is not going to restart any of these containers. + PodSucceeded PodPhase = "Succeeded" + // PodFailed means that all containers in the pod have terminated, and at least one container has + // terminated in a failure (exited with a non-zero exit code or was stopped by the system). + PodFailed PodPhase = "Failed" + // PodUnknown means that for some reason the state of the pod could not be obtained, typically due + // to an error in communicating with the host of the pod. + // Deprecated in v1.21: It isn't being set since 2015 (74da3b14b0c0f658b3bb8d2def5094686d0e9095) + PodUnknown PodPhase = "Unknown" +) + +// PodConditionType defines the condition of pod +type PodConditionType string + +// These are valid conditions of pod. +const ( + // PodScheduled represents status of the scheduling process for this pod. + PodScheduled PodConditionType = "PodScheduled" + // PodReady means the pod is able to service requests and should be added to the + // load balancing pools of all matching services. + PodReady PodConditionType = "Ready" + // PodInitialized means that all init containers in the pod have started successfully. + PodInitialized PodConditionType = "Initialized" + // PodReasonUnschedulable reason in PodScheduled PodCondition means that the scheduler + // can't schedule the pod right now, for example due to insufficient resources in the cluster. + PodReasonUnschedulable = "Unschedulable" + // PodReasonSchedulingGated reason in PodScheduled PodCondition means that the scheduler + // skips scheduling the pod because one or more scheduling gates are still present. + PodReasonSchedulingGated = "SchedulingGated" + // ContainersReady indicates whether all containers in the pod are ready. + ContainersReady PodConditionType = "ContainersReady" + // DisruptionTarget indicates the pod is about to be terminated due to a + // disruption (such as preemption, eviction API or garbage-collection). + DisruptionTarget PodConditionType = "DisruptionTarget" +) + +// PodCondition represents pod's condition +type PodCondition struct { + Type PodConditionType + Status ConditionStatus + // +optional + LastProbeTime metav1.Time + // +optional + LastTransitionTime metav1.Time + // +optional + Reason string + // +optional + Message string +} + +// RestartPolicy describes how the container should be restarted. +// Only one of the following restart policies may be specified. +// If none of the following policies is specified, the default one +// is RestartPolicyAlways. +type RestartPolicy string + +// These are valid restart policies +const ( + RestartPolicyAlways RestartPolicy = "Always" + RestartPolicyOnFailure RestartPolicy = "OnFailure" + RestartPolicyNever RestartPolicy = "Never" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// PodList is a list of Pods. +type PodList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + + Items []Pod +} + +// DNSPolicy defines how a pod's DNS will be configured. +type DNSPolicy string + +const ( + // DNSClusterFirstWithHostNet indicates that the pod should use cluster DNS + // first, if it is available, then fall back on the default + // (as determined by kubelet) DNS settings. + DNSClusterFirstWithHostNet DNSPolicy = "ClusterFirstWithHostNet" + + // DNSClusterFirst indicates that the pod should use cluster DNS + // first unless hostNetwork is true, if it is available, then + // fall back on the default (as determined by kubelet) DNS settings. + DNSClusterFirst DNSPolicy = "ClusterFirst" + + // DNSDefault indicates that the pod should use the default (as + // determined by kubelet) DNS settings. + DNSDefault DNSPolicy = "Default" + + // DNSNone indicates that the pod should use empty DNS settings. DNS + // parameters such as nameservers and search paths should be defined via + // DNSConfig. + DNSNone DNSPolicy = "None" +) + +// NodeSelector represents the union of the results of one or more label queries +// over a set of nodes; that is, it represents the OR of the selectors represented +// by the node selector terms. +type NodeSelector struct { + // Required. A list of node selector terms. The terms are ORed. + NodeSelectorTerms []NodeSelectorTerm +} + +// NodeSelectorTerm represents expressions and fields required to select nodes. +// A null or empty node selector term matches no objects. The requirements of +// them are ANDed. +// The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. +type NodeSelectorTerm struct { + // A list of node selector requirements by node's labels. + MatchExpressions []NodeSelectorRequirement + // A list of node selector requirements by node's fields. + MatchFields []NodeSelectorRequirement +} + +// NodeSelectorRequirement is a selector that contains values, a key, and an operator +// that relates the key and values. +type NodeSelectorRequirement struct { + // The label key that the selector applies to. + Key string + // Represents a key's relationship to a set of values. + // Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + Operator NodeSelectorOperator + // An array of string values. If the operator is In or NotIn, + // the values array must be non-empty. If the operator is Exists or DoesNotExist, + // the values array must be empty. If the operator is Gt or Lt, the values + // array must have a single element, which will be interpreted as an integer. + // This array is replaced during a strategic merge patch. + // +optional + Values []string +} + +// NodeSelectorOperator is the set of operators that can be used in +// a node selector requirement. +type NodeSelectorOperator string + +// These are valid values of NodeSelectorOperator +const ( + NodeSelectorOpIn NodeSelectorOperator = "In" + NodeSelectorOpNotIn NodeSelectorOperator = "NotIn" + NodeSelectorOpExists NodeSelectorOperator = "Exists" + NodeSelectorOpDoesNotExist NodeSelectorOperator = "DoesNotExist" + NodeSelectorOpGt NodeSelectorOperator = "Gt" + NodeSelectorOpLt NodeSelectorOperator = "Lt" +) + +// TopologySelectorTerm represents the result of label queries. +// A null or empty topology selector term matches no objects. +// The requirements of them are ANDed. +// It provides a subset of functionality as NodeSelectorTerm. +// This is an alpha feature and may change in the future. +type TopologySelectorTerm struct { + // A list of topology selector requirements by labels. + // +optional + MatchLabelExpressions []TopologySelectorLabelRequirement +} + +// TopologySelectorLabelRequirement is a selector that matches given label. +// This is an alpha feature and may change in the future. +type TopologySelectorLabelRequirement struct { + // The label key that the selector applies to. + Key string + // An array of string values. One value must match the label to be selected. + // Each entry in Values is ORed. + Values []string +} + +// Affinity is a group of affinity scheduling rules. +type Affinity struct { + // Describes node affinity scheduling rules for the pod. + // +optional + NodeAffinity *NodeAffinity + // Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + // +optional + PodAffinity *PodAffinity + // Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + // +optional + PodAntiAffinity *PodAntiAffinity +} + +// PodAffinity is a group of inter pod affinity scheduling rules. +type PodAffinity struct { + // NOT YET IMPLEMENTED. TODO: Uncomment field once it is implemented. + // If the affinity requirements specified by this field are not met at + // scheduling time, the pod will not be scheduled onto the node. + // If the affinity requirements specified by this field cease to be met + // at some point during pod execution (e.g. due to a pod label update), the + // system will try to eventually evict the pod from its node. + // When there are multiple elements, the lists of nodes corresponding to each + // podAffinityTerm are intersected, i.e. all terms must be satisfied. + // +optional + // RequiredDuringSchedulingRequiredDuringExecution []PodAffinityTerm + + // If the affinity requirements specified by this field are not met at + // scheduling time, the pod will not be scheduled onto the node. + // If the affinity requirements specified by this field cease to be met + // at some point during pod execution (e.g. due to a pod label update), the + // system may or may not try to eventually evict the pod from its node. + // When there are multiple elements, the lists of nodes corresponding to each + // podAffinityTerm are intersected, i.e. all terms must be satisfied. + // +optional + RequiredDuringSchedulingIgnoredDuringExecution []PodAffinityTerm + // The scheduler will prefer to schedule pods to nodes that satisfy + // the affinity expressions specified by this field, but it may choose + // a node that violates one or more of the expressions. The node that is + // most preferred is the one with the greatest sum of weights, i.e. + // for each node that meets all of the scheduling requirements (resource + // request, requiredDuringScheduling affinity expressions, etc.), + // compute a sum by iterating through the elements of this field and adding + // "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + // node(s) with the highest sum are the most preferred. + // +optional + PreferredDuringSchedulingIgnoredDuringExecution []WeightedPodAffinityTerm +} + +// PodAntiAffinity is a group of inter pod anti affinity scheduling rules. +type PodAntiAffinity struct { + // NOT YET IMPLEMENTED. TODO: Uncomment field once it is implemented. + // If the anti-affinity requirements specified by this field are not met at + // scheduling time, the pod will not be scheduled onto the node. + // If the anti-affinity requirements specified by this field cease to be met + // at some point during pod execution (e.g. due to a pod label update), the + // system will try to eventually evict the pod from its node. + // When there are multiple elements, the lists of nodes corresponding to each + // podAffinityTerm are intersected, i.e. all terms must be satisfied. + // +optional + // RequiredDuringSchedulingRequiredDuringExecution []PodAffinityTerm + + // If the anti-affinity requirements specified by this field are not met at + // scheduling time, the pod will not be scheduled onto the node. + // If the anti-affinity requirements specified by this field cease to be met + // at some point during pod execution (e.g. due to a pod label update), the + // system may or may not try to eventually evict the pod from its node. + // When there are multiple elements, the lists of nodes corresponding to each + // podAffinityTerm are intersected, i.e. all terms must be satisfied. + // +optional + RequiredDuringSchedulingIgnoredDuringExecution []PodAffinityTerm + // The scheduler will prefer to schedule pods to nodes that satisfy + // the anti-affinity expressions specified by this field, but it may choose + // a node that violates one or more of the expressions. The node that is + // most preferred is the one with the greatest sum of weights, i.e. + // for each node that meets all of the scheduling requirements (resource + // request, requiredDuringScheduling anti-affinity expressions, etc.), + // compute a sum by iterating through the elements of this field and adding + // "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + // node(s) with the highest sum are the most preferred. + // +optional + PreferredDuringSchedulingIgnoredDuringExecution []WeightedPodAffinityTerm +} + +// WeightedPodAffinityTerm represents the weights of all of the matched WeightedPodAffinityTerm +// fields are added per-node to find the most preferred node(s) +type WeightedPodAffinityTerm struct { + // weight associated with matching the corresponding podAffinityTerm, + // in the range 1-100. + Weight int32 + // Required. A pod affinity term, associated with the corresponding weight. + PodAffinityTerm PodAffinityTerm +} + +// PodAffinityTerm defines a set of pods (namely those matching the labelSelector +// relative to the given namespace(s)) that this pod should be +// co-located (affinity) or not co-located (anti-affinity) with, +// where co-located is defined as running on a node whose value of +// the label with key matches that of any node on which +// a pod of the set of pods is running. +type PodAffinityTerm struct { + // A label query over a set of resources, in this case pods. + // +optional + LabelSelector *metav1.LabelSelector + // namespaces specifies a static list of namespace names that the term applies to. + // The term is applied to the union of the namespaces listed in this field + // and the ones selected by namespaceSelector. + // null or empty namespaces list and null namespaceSelector means "this pod's namespace". + // +optional + Namespaces []string + // This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + // the labelSelector in the specified namespaces, where co-located is defined as running on a node + // whose value of the label with key topologyKey matches that of any node on which any of the + // selected pods is running. + // Empty topologyKey is not allowed. + TopologyKey string + // A label query over the set of namespaces that the term applies to. + // The term is applied to the union of the namespaces selected by this field + // and the ones listed in the namespaces field. + // null selector and null or empty namespaces list means "this pod's namespace". + // An empty selector ({}) matches all namespaces. + // +optional + NamespaceSelector *metav1.LabelSelector +} + +// NodeAffinity is a group of node affinity scheduling rules. +type NodeAffinity struct { + // NOT YET IMPLEMENTED. TODO: Uncomment field once it is implemented. + // If the affinity requirements specified by this field are not met at + // scheduling time, the pod will not be scheduled onto the node. + // If the affinity requirements specified by this field cease to be met + // at some point during pod execution (e.g. due to an update), the system + // will try to eventually evict the pod from its node. + // +optional + // RequiredDuringSchedulingRequiredDuringExecution *NodeSelector + + // If the affinity requirements specified by this field are not met at + // scheduling time, the pod will not be scheduled onto the node. + // If the affinity requirements specified by this field cease to be met + // at some point during pod execution (e.g. due to an update), the system + // may or may not try to eventually evict the pod from its node. + // +optional + RequiredDuringSchedulingIgnoredDuringExecution *NodeSelector + // The scheduler will prefer to schedule pods to nodes that satisfy + // the affinity expressions specified by this field, but it may choose + // a node that violates one or more of the expressions. The node that is + // most preferred is the one with the greatest sum of weights, i.e. + // for each node that meets all of the scheduling requirements (resource + // request, requiredDuringScheduling affinity expressions, etc.), + // compute a sum by iterating through the elements of this field and adding + // "weight" to the sum if the node matches the corresponding matchExpressions; the + // node(s) with the highest sum are the most preferred. + // +optional + PreferredDuringSchedulingIgnoredDuringExecution []PreferredSchedulingTerm +} + +// PreferredSchedulingTerm represents an empty preferred scheduling term matches all objects with implicit weight 0 +// (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). +type PreferredSchedulingTerm struct { + // Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + Weight int32 + // A node selector term, associated with the corresponding weight. + Preference NodeSelectorTerm +} + +// Taint represents taint that can be applied to the node. +// The node this Taint is attached to has the "effect" on +// any pod that does not tolerate the Taint. +type Taint struct { + // Required. The taint key to be applied to a node. + Key string + // Required. The taint value corresponding to the taint key. + // +optional + Value string + // Required. The effect of the taint on pods + // that do not tolerate the taint. + // Valid effects are NoSchedule, PreferNoSchedule and NoExecute. + Effect TaintEffect + // TimeAdded represents the time at which the taint was added. + // It is only written for NoExecute taints. + // +optional + TimeAdded *metav1.Time +} + +// TaintEffect defines the effects of Taint +type TaintEffect string + +// These are valid values for TaintEffect +const ( + // Do not allow new pods to schedule onto the node unless they tolerate the taint, + // but allow all pods submitted to Kubelet without going through the scheduler + // to start, and allow all already-running pods to continue running. + // Enforced by the scheduler. + TaintEffectNoSchedule TaintEffect = "NoSchedule" + // Like TaintEffectNoSchedule, but the scheduler tries not to schedule + // new pods onto the node, rather than prohibiting new pods from scheduling + // onto the node entirely. Enforced by the scheduler. + TaintEffectPreferNoSchedule TaintEffect = "PreferNoSchedule" + // NOT YET IMPLEMENTED. TODO: Uncomment field once it is implemented. + // Like TaintEffectNoSchedule, but additionally do not allow pods submitted to + // Kubelet without going through the scheduler to start. + // Enforced by Kubelet and the scheduler. + // TaintEffectNoScheduleNoAdmit TaintEffect = "NoScheduleNoAdmit" + + // Evict any already-running pods that do not tolerate the taint. + // Currently enforced by NodeController. + TaintEffectNoExecute TaintEffect = "NoExecute" +) + +// Toleration represents the toleration object that can be attached to a pod. +// The pod this Toleration is attached to tolerates any taint that matches +// the triple using the matching operator . +type Toleration struct { + // Key is the taint key that the toleration applies to. Empty means match all taint keys. + // If the key is empty, operator must be Exists; this combination means to match all values and all keys. + // +optional + Key string + // Operator represents a key's relationship to the value. + // Valid operators are Exists and Equal. Defaults to Equal. + // Exists is equivalent to wildcard for value, so that a pod can + // tolerate all taints of a particular category. + // +optional + Operator TolerationOperator + // Value is the taint value the toleration matches to. + // If the operator is Exists, the value should be empty, otherwise just a regular string. + // +optional + Value string + // Effect indicates the taint effect to match. Empty means match all taint effects. + // When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + // +optional + Effect TaintEffect + // TolerationSeconds represents the period of time the toleration (which must be + // of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + // it is not set, which means tolerate the taint forever (do not evict). Zero and + // negative values will be treated as 0 (evict immediately) by the system. + // +optional + TolerationSeconds *int64 +} + +// TolerationOperator is the set of operators that can be used in a toleration. +type TolerationOperator string + +// These are valid values for TolerationOperator +const ( + TolerationOpExists TolerationOperator = "Exists" + TolerationOpEqual TolerationOperator = "Equal" +) + +// PodReadinessGate contains the reference to a pod condition +type PodReadinessGate struct { + // ConditionType refers to a condition in the pod's condition list with matching type. + ConditionType PodConditionType +} + +// PodSpec is a description of a pod +type PodSpec struct { + Volumes []Volume + // List of initialization containers belonging to the pod. + InitContainers []Container + // List of containers belonging to the pod. + Containers []Container + // List of ephemeral containers run in this pod. Ephemeral containers may be run in an existing + // pod to perform user-initiated actions such as debugging. This list cannot be specified when + // creating a pod, and it cannot be modified by updating the pod spec. In order to add an + // ephemeral container to an existing pod, use the pod's ephemeralcontainers subresource. + // +optional + EphemeralContainers []EphemeralContainer + // +optional + RestartPolicy RestartPolicy + // Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. + // Value must be non-negative integer. The value zero indicates stop immediately via the kill + // signal (no opportunity to shut down). + // If this value is nil, the default grace period will be used instead. + // The grace period is the duration in seconds after the processes running in the pod are sent + // a termination signal and the time when the processes are forcibly halted with a kill signal. + // Set this value longer than the expected cleanup time for your process. + // +optional + TerminationGracePeriodSeconds *int64 + // Optional duration in seconds relative to the StartTime that the pod may be active on a node + // before the system actively tries to terminate the pod; value must be positive integer + // +optional + ActiveDeadlineSeconds *int64 + // Set DNS policy for the pod. + // Defaults to "ClusterFirst". + // Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. + // DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. + // To have DNS options set along with hostNetwork, you have to specify DNS policy + // explicitly to 'ClusterFirstWithHostNet'. + // +optional + DNSPolicy DNSPolicy + // NodeSelector is a selector which must be true for the pod to fit on a node + // +optional + NodeSelector map[string]string + + // ServiceAccountName is the name of the ServiceAccount to use to run this pod + // The pod will be allowed to use secrets referenced by the ServiceAccount + ServiceAccountName string + // AutomountServiceAccountToken indicates whether a service account token should be automatically mounted. + // +optional + AutomountServiceAccountToken *bool + + // NodeName is a request to schedule this pod onto a specific node. If it is non-empty, + // the scheduler simply schedules this pod onto that node, assuming that it fits resource + // requirements. + // +optional + NodeName string + // SecurityContext holds pod-level security attributes and common container settings. + // Optional: Defaults to empty. See type description for default values of each field. + // +optional + SecurityContext *PodSecurityContext + // ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. + // If specified, these secrets will be passed to individual puller implementations for them to use. + // +optional + ImagePullSecrets []LocalObjectReference + // Specifies the hostname of the Pod. + // If not specified, the pod's hostname will be set to a system-defined value. + // +optional + Hostname string + // If specified, the fully qualified Pod hostname will be "...svc.". + // If not specified, the pod will not have a domainname at all. + // +optional + Subdomain string + // If true the pod's hostname will be configured as the pod's FQDN, rather than the leaf name (the default). + // In Linux containers, this means setting the FQDN in the hostname field of the kernel (the nodename field of struct utsname). + // In Windows containers, this means setting the registry value of hostname for the registry key HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters to FQDN. + // If a pod does not have FQDN, this has no effect. + // +optional + SetHostnameAsFQDN *bool + // If specified, the pod's scheduling constraints + // +optional + Affinity *Affinity + // If specified, the pod will be dispatched by specified scheduler. + // If not specified, the pod will be dispatched by default scheduler. + // +optional + SchedulerName string + // If specified, the pod's tolerations. + // +optional + Tolerations []Toleration + // HostAliases is an optional list of hosts and IPs that will be injected into the pod's hosts + // file if specified. This is only valid for non-hostNetwork pods. + // +optional + HostAliases []HostAlias + // If specified, indicates the pod's priority. "system-node-critical" and + // "system-cluster-critical" are two special keywords which indicate the + // highest priorities with the former being the highest priority. Any other + // name must be defined by creating a PriorityClass object with that name. + // If not specified, the pod priority will be default or zero if there is no + // default. + // +optional + PriorityClassName string + // The priority value. Various system components use this field to find the + // priority of the pod. When Priority Admission Controller is enabled, it + // prevents users from setting this field. The admission controller populates + // this field from PriorityClassName. + // The higher the value, the higher the priority. + // +optional + Priority *int32 + // PreemptionPolicy is the Policy for preempting pods with lower priority. + // One of Never, PreemptLowerPriority. + // Defaults to PreemptLowerPriority if unset. + // +optional + PreemptionPolicy *PreemptionPolicy + // Specifies the DNS parameters of a pod. + // Parameters specified here will be merged to the generated DNS + // configuration based on DNSPolicy. + // +optional + DNSConfig *PodDNSConfig + // If specified, all readiness gates will be evaluated for pod readiness. + // A pod is ready when all its containers are ready AND + // all conditions specified in the readiness gates have status equal to "True" + // More info: https://git.k8s.io/enhancements/keps/sig-network/580-pod-readiness-gates + // +optional + ReadinessGates []PodReadinessGate + // RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used + // to run this pod. If no RuntimeClass resource matches the named class, the pod will not be run. + // If unset or empty, the "legacy" RuntimeClass will be used, which is an implicit class with an + // empty definition that uses the default runtime handler. + // More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class + // +optional + RuntimeClassName *string + // Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. + // This field will be autopopulated at admission time by the RuntimeClass admission controller. If + // the RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests. + // The RuntimeClass admission controller will reject Pod create requests which have the overhead already + // set. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value + // defined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero. + // More info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead + // +optional + Overhead ResourceList + // EnableServiceLinks indicates whether information about services should be injected into pod's + // environment variables, matching the syntax of Docker links. + // If not specified, the default is true. + // +optional + EnableServiceLinks *bool + // TopologySpreadConstraints describes how a group of pods ought to spread across topology + // domains. Scheduler will schedule pods in a way which abides by the constraints. + // All topologySpreadConstraints are ANDed. + // +optional + TopologySpreadConstraints []TopologySpreadConstraint + // Specifies the OS of the containers in the pod. + // Some pod and container fields are restricted if this is set. + // + // If the OS field is set to linux, the following fields must be unset: + // - securityContext.windowsOptions + // + // If the OS field is set to windows, following fields must be unset: + // - spec.hostPID + // - spec.hostIPC + // - spec.hostUsers + // - spec.securityContext.seLinuxOptions + // - spec.securityContext.seccompProfile + // - spec.securityContext.fsGroup + // - spec.securityContext.fsGroupChangePolicy + // - spec.securityContext.sysctls + // - spec.shareProcessNamespace + // - spec.securityContext.runAsUser + // - spec.securityContext.runAsGroup + // - spec.securityContext.supplementalGroups + // - spec.containers[*].securityContext.seLinuxOptions + // - spec.containers[*].securityContext.seccompProfile + // - spec.containers[*].securityContext.capabilities + // - spec.containers[*].securityContext.readOnlyRootFilesystem + // - spec.containers[*].securityContext.privileged + // - spec.containers[*].securityContext.allowPrivilegeEscalation + // - spec.containers[*].securityContext.procMount + // - spec.containers[*].securityContext.runAsUser + // - spec.containers[*].securityContext.runAsGroup + // +optional + OS *PodOS + + // SchedulingGates is an opaque list of values that if specified will block scheduling the pod. + // More info: https://git.k8s.io/enhancements/keps/sig-scheduling/3521-pod-scheduling-readiness. + // + // This is an alpha-level feature enabled by PodSchedulingReadiness feature gate. + // +optional + SchedulingGates []PodSchedulingGate + // ResourceClaims defines which ResourceClaims must be allocated + // and reserved before the Pod is allowed to start. The resources + // will be made available to those containers which consume them + // by name. + // + // This is an alpha field and requires enabling the + // DynamicResourceAllocation feature gate. + // + // This field is immutable. + // + // +featureGate=DynamicResourceAllocation + // +optional + ResourceClaims []PodResourceClaim +} + +// PodResourceClaim references exactly one ResourceClaim through a ClaimSource. +// It adds a name to it that uniquely identifies the ResourceClaim inside the Pod. +// Containers that need access to the ResourceClaim reference it with this name. +type PodResourceClaim struct { + // Name uniquely identifies this resource claim inside the pod. + // This must be a DNS_LABEL. + Name string + + // Source describes where to find the ResourceClaim. + Source ClaimSource +} + +// ClaimSource describes a reference to a ResourceClaim. +// +// Exactly one of these fields should be set. Consumers of this type must +// treat an empty object as if it has an unknown value. +type ClaimSource struct { + // ResourceClaimName is the name of a ResourceClaim object in the same + // namespace as this pod. + ResourceClaimName *string + + // ResourceClaimTemplateName is the name of a ResourceClaimTemplate + // object in the same namespace as this pod. + // + // The template will be used to create a new ResourceClaim, which will + // be bound to this pod. When this pod is deleted, the ResourceClaim + // will also be deleted. The name of the ResourceClaim will be -, where is the + // PodResourceClaim.Name. Pod validation will reject the pod if the + // concatenated name is not valid for a ResourceClaim (e.g. too long). + // + // An existing ResourceClaim with that name that is not owned by the + // pod will not be used for the pod to avoid using an unrelated + // resource by mistake. Scheduling and pod startup are then blocked + // until the unrelated ResourceClaim is removed. + // + // This field is immutable and no changes will be made to the + // corresponding ResourceClaim by the control plane after creating the + // ResourceClaim. + ResourceClaimTemplateName *string +} + +// OSName is the set of OS'es that can be used in OS. +type OSName string + +// These are valid values for OSName +const ( + Linux OSName = "linux" + Windows OSName = "windows" +) + +// PodOS defines the OS parameters of a pod. +type PodOS struct { + // Name is the name of the operating system. The currently supported values are linux and windows. + // Additional value may be defined in future and can be one of: + // https://github.com/opencontainers/runtime-spec/blob/master/config.md#platform-specific-configuration + // Clients should expect to handle additional values and treat unrecognized values in this field as os: null + Name OSName +} + +// PodSchedulingGate is associated to a Pod to guard its scheduling. +type PodSchedulingGate struct { + // Name of the scheduling gate. + // Each scheduling gate must have a unique name field. + Name string +} + +// HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the +// pod's hosts file. +type HostAlias struct { + IP string + Hostnames []string +} + +// Sysctl defines a kernel parameter to be set +type Sysctl struct { + // Name of a property to set + Name string + // Value of a property to set + Value string +} + +// PodFSGroupChangePolicy holds policies that will be used for applying fsGroup to a volume +// when volume is mounted. +type PodFSGroupChangePolicy string + +const ( + // FSGroupChangeOnRootMismatch indicates that volume's ownership and permissions will be changed + // only when permission and ownership of root directory does not match with expected + // permissions on the volume. This can help shorten the time it takes to change + // ownership and permissions of a volume. + FSGroupChangeOnRootMismatch PodFSGroupChangePolicy = "OnRootMismatch" + // FSGroupChangeAlways indicates that volume's ownership and permissions + // should always be changed whenever volume is mounted inside a Pod. This the default + // behavior. + FSGroupChangeAlways PodFSGroupChangePolicy = "Always" +) + +// PodSecurityContext holds pod-level security attributes and common container settings. +// Some fields are also present in container.securityContext. Field values of +// container.securityContext take precedence over field values of PodSecurityContext. +type PodSecurityContext struct { + // Use the host's network namespace. If this option is set, the ports that will be + // used must be specified. + // Optional: Default to false + // +k8s:conversion-gen=false + // +optional + HostNetwork bool + // Use the host's pid namespace. + // Optional: Default to false. + // Note that this field cannot be set when spec.os.name is windows. + // +k8s:conversion-gen=false + // +optional + HostPID bool + // Use the host's ipc namespace. + // Optional: Default to false. + // Note that this field cannot be set when spec.os.name is windows. + // +k8s:conversion-gen=false + // +optional + HostIPC bool + // Share a single process namespace between all of the containers in a pod. + // When this is set containers will be able to view and signal processes from other containers + // in the same pod, and the first process in each container will not be assigned PID 1. + // HostPID and ShareProcessNamespace cannot both be set. + // Note that this field cannot be set when spec.os.name is windows. + // Optional: Default to false. + // +k8s:conversion-gen=false + // +optional + ShareProcessNamespace *bool + // Use the host's user namespace. + // Optional: Default to true. + // If set to true or not present, the pod will be run in the host user namespace, useful + // for when the pod needs a feature only available to the host user namespace, such as + // loading a kernel module with CAP_SYS_MODULE. + // When set to false, a new user namespace is created for the pod. Setting false is useful + // for mitigating container breakout vulnerabilities even allowing users to run their + // containers as root without actually having root privileges on the host. + // Note that this field cannot be set when spec.os.name is windows. + // +k8s:conversion-gen=false + // +optional + HostUsers *bool + // The SELinux context to be applied to all containers. + // If unspecified, the container runtime will allocate a random SELinux context for each + // container. May also be set in SecurityContext. If set in + // both SecurityContext and PodSecurityContext, the value specified in SecurityContext + // takes precedence for that container. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + SELinuxOptions *SELinuxOptions + // The Windows specific settings applied to all containers. + // If unspecified, the options within a container's SecurityContext will be used. + // If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + // Note that this field cannot be set when spec.os.name is linux. + // +optional + WindowsOptions *WindowsSecurityContextOptions + // The UID to run the entrypoint of the container process. + // Defaults to user specified in image metadata if unspecified. + // May also be set in SecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence + // for that container. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + RunAsUser *int64 + // The GID to run the entrypoint of the container process. + // Uses runtime default if unset. + // May also be set in SecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence + // for that container. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + RunAsGroup *int64 + // Indicates that the container must run as a non-root user. + // If true, the Kubelet will validate the image at runtime to ensure that it + // does not run as UID 0 (root) and fail to start the container if it does. + // If unset or false, no such validation will be performed. + // May also be set in SecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence + // for that container. + // +optional + RunAsNonRoot *bool + // A list of groups applied to the first process run in each container, in addition + // to the container's primary GID, the fsGroup (if specified), and group memberships + // defined in the container image for the uid of the container process. If unspecified, + // no additional groups are added to any container. Note that group memberships + // defined in the container image for the uid of the container process are still effective, + // even if they are not included in this list. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + SupplementalGroups []int64 + // A special supplemental group that applies to all containers in a pod. + // Some volume types allow the Kubelet to change the ownership of that volume + // to be owned by the pod: + // + // 1. The owning GID will be the FSGroup + // 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) + // 3. The permission bits are OR'd with rw-rw---- + // + // If unset, the Kubelet will not modify the ownership and permissions of any volume. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + FSGroup *int64 + // fsGroupChangePolicy defines behavior of changing ownership and permission of the volume + // before being exposed inside Pod. This field will only apply to + // volume types which support fsGroup based ownership(and permissions). + // It will have no effect on ephemeral volume types such as: secret, configmaps + // and emptydir. + // Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + FSGroupChangePolicy *PodFSGroupChangePolicy + // Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported + // sysctls (by the container runtime) might fail to launch. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + Sysctls []Sysctl + // The seccomp options to use by the containers in this pod. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + SeccompProfile *SeccompProfile +} + +// SeccompProfile defines a pod/container's seccomp profile settings. +// Only one profile source may be set. +// +union +type SeccompProfile struct { + // +unionDiscriminator + Type SeccompProfileType + // Load a profile defined in static file on the node. + // The profile must be preconfigured on the node to work. + // LocalhostProfile cannot be an absolute nor a descending path. + // +optional + LocalhostProfile *string +} + +// SeccompProfileType defines the supported seccomp profile types. +type SeccompProfileType string + +const ( + // SeccompProfileTypeUnconfined is when no seccomp profile is applied (A.K.A. unconfined). + SeccompProfileTypeUnconfined SeccompProfileType = "Unconfined" + // SeccompProfileTypeRuntimeDefault represents the default container runtime seccomp profile. + SeccompProfileTypeRuntimeDefault SeccompProfileType = "RuntimeDefault" + // SeccompProfileTypeLocalhost represents custom made profiles stored on the node's disk. + SeccompProfileTypeLocalhost SeccompProfileType = "Localhost" +) + +// PodQOSClass defines the supported qos classes of Pods. +type PodQOSClass string + +// These are valid values for PodQOSClass +const ( + // PodQOSGuaranteed is the Guaranteed qos class. + PodQOSGuaranteed PodQOSClass = "Guaranteed" + // PodQOSBurstable is the Burstable qos class. + PodQOSBurstable PodQOSClass = "Burstable" + // PodQOSBestEffort is the BestEffort qos class. + PodQOSBestEffort PodQOSClass = "BestEffort" +) + +// PodDNSConfig defines the DNS parameters of a pod in addition to +// those generated from DNSPolicy. +type PodDNSConfig struct { + // A list of DNS name server IP addresses. + // This will be appended to the base nameservers generated from DNSPolicy. + // Duplicated nameservers will be removed. + // +optional + Nameservers []string + // A list of DNS search domains for host-name lookup. + // This will be appended to the base search paths generated from DNSPolicy. + // Duplicated search paths will be removed. + // +optional + Searches []string + // A list of DNS resolver options. + // This will be merged with the base options generated from DNSPolicy. + // Duplicated entries will be removed. Resolution options given in Options + // will override those that appear in the base DNSPolicy. + // +optional + Options []PodDNSConfigOption +} + +// PodDNSConfigOption defines DNS resolver options of a pod. +type PodDNSConfigOption struct { + // Required. + Name string + // +optional + Value *string +} + +// PodIP represents the IP address of a pod. +// IP address information. Each entry includes: +// +// IP: An IP address allocated to the pod. Routable at least within +// the cluster. +type PodIP struct { + IP string +} + +// EphemeralContainerCommon is a copy of all fields in Container to be inlined in +// EphemeralContainer. This separate type allows easy conversion from EphemeralContainer +// to Container and allows separate documentation for the fields of EphemeralContainer. +// When a new field is added to Container it must be added here as well. +type EphemeralContainerCommon struct { + // Required: This must be a DNS_LABEL. Each container in a pod must + // have a unique name. + Name string + // Required. + Image string + // Optional: The container image's entrypoint is used if this is not provided; cannot be updated. + // Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + // cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + // to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + // produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + // of whether the variable exists or not. + // +optional + Command []string + // Optional: The container image's cmd is used if this is not provided; cannot be updated. + // Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + // cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + // to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + // produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + // of whether the variable exists or not. + // +optional + Args []string + // Optional: Defaults to the container runtime's default working directory. + // +optional + WorkingDir string + // Ports are not allowed for ephemeral containers. + // +optional + Ports []ContainerPort + // List of sources to populate environment variables in the container. + // The keys defined within a source must be a C_IDENTIFIER. All invalid keys + // will be reported as an event when the container is starting. When a key exists in multiple + // sources, the value associated with the last source will take precedence. + // Values defined by an Env with a duplicate key will take precedence. + // Cannot be updated. + // +optional + EnvFrom []EnvFromSource + // +optional + Env []EnvVar + // Resources are not allowed for ephemeral containers. Ephemeral containers use spare resources + // already allocated to the pod. + // +optional + Resources ResourceRequirements + // Pod volumes to mount into the container's filesystem. Subpath mounts are not allowed for ephemeral containers. + // +optional + VolumeMounts []VolumeMount + // volumeDevices is the list of block devices to be used by the container. + // +optional + VolumeDevices []VolumeDevice + // Probes are not allowed for ephemeral containers. + // +optional + LivenessProbe *Probe + // Probes are not allowed for ephemeral containers. + // +optional + ReadinessProbe *Probe + // Probes are not allowed for ephemeral containers. + // +optional + StartupProbe *Probe + // Lifecycle is not allowed for ephemeral containers. + // +optional + Lifecycle *Lifecycle + // Required. + // +optional + TerminationMessagePath string + // +optional + TerminationMessagePolicy TerminationMessagePolicy + // Required: Policy for pulling images for this container + ImagePullPolicy PullPolicy + // Optional: SecurityContext defines the security options the ephemeral container should be run with. + // If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. + // +optional + SecurityContext *SecurityContext + + // Variables for interactive containers, these have very specialized use-cases (e.g. debugging) + // and shouldn't be used for general purpose containers. + // +optional + Stdin bool + // +optional + StdinOnce bool + // +optional + TTY bool +} + +// EphemeralContainerCommon converts to Container. All fields must be kept in sync between +// these two types. +var _ = Container(EphemeralContainerCommon{}) + +// An EphemeralContainer is a temporary container that you may add to an existing Pod for +// user-initiated activities such as debugging. Ephemeral containers have no resource or +// scheduling guarantees, and they will not be restarted when they exit or when a Pod is +// removed or restarted. The kubelet may evict a Pod if an ephemeral container causes the +// Pod to exceed its resource allocation. +// +// To add an ephemeral container, use the ephemeralcontainers subresource of an existing +// Pod. Ephemeral containers may not be removed or restarted. +type EphemeralContainer struct { + // Ephemeral containers have all of the fields of Container, plus additional fields + // specific to ephemeral containers. Fields in common with Container are in the + // following inlined struct so than an EphemeralContainer may easily be converted + // to a Container. + EphemeralContainerCommon + + // If set, the name of the container from PodSpec that this ephemeral container targets. + // The ephemeral container will be run in the namespaces (IPC, PID, etc) of this container. + // If not set then the ephemeral container uses the namespaces configured in the Pod spec. + // + // The container runtime must implement support for this feature. If the runtime does not + // support namespace targeting then the result of setting this field is undefined. + // +optional + TargetContainerName string +} + +// PodStatus represents information about the status of a pod. Status may trail the actual +// state of a system. +type PodStatus struct { + // +optional + Phase PodPhase + // +optional + Conditions []PodCondition + // A human readable message indicating details about why the pod is in this state. + // +optional + Message string + // A brief CamelCase message indicating details about why the pod is in this state. e.g. 'Evicted' + // +optional + Reason string + // nominatedNodeName is set when this pod preempts other pods on the node, but it cannot be + // scheduled right away as preemption victims receive their graceful termination periods. + // This field does not guarantee that the pod will be scheduled on this node. Scheduler may decide + // to place the pod elsewhere if other nodes become available sooner. Scheduler may also decide to + // give the resources on this node to a higher priority pod that is created after preemption. + // +optional + NominatedNodeName string + // +optional + HostIP string + + // PodIPs holds all of the known IP addresses allocated to the pod. Pods may be assigned AT MOST + // one value for each of IPv4 and IPv6. + // +optional + PodIPs []PodIP + + // Date and time at which the object was acknowledged by the Kubelet. + // This is before the Kubelet pulled the container image(s) for the pod. + // +optional + StartTime *metav1.Time + // +optional + QOSClass PodQOSClass + + // The list has one entry per init container in the manifest. The most recent successful + // init container will have ready = true, the most recently started container will have + // startTime set. + // More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-and-container-status + InitContainerStatuses []ContainerStatus + // The list has one entry per app container in the manifest. + // +optional + ContainerStatuses []ContainerStatus + + // Status for any ephemeral containers that have run in this pod. + // +optional + EphemeralContainerStatuses []ContainerStatus +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// PodStatusResult is a wrapper for PodStatus returned by kubelet that can be encode/decoded +type PodStatusResult struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + // Status represents the current information about a pod. This data may not be up + // to date. + // +optional + Status PodStatus +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Pod is a collection of containers, used as either input (create, update) or as output (list, get). +type Pod struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + + // Spec defines the behavior of a pod. + // +optional + Spec PodSpec + + // Status represents the current information about a pod. This data may not be up + // to date. + // +optional + Status PodStatus +} + +// PodTemplateSpec describes the data a pod should have when created from a template +type PodTemplateSpec struct { + // Metadata of the pods created from this template. + // +optional + metav1.ObjectMeta + + // Spec defines the behavior of a pod. + // +optional + Spec PodSpec +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// PodTemplate describes a template for creating copies of a predefined pod. +type PodTemplate struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + + // Template defines the pods that will be created from this pod template + // +optional + Template PodTemplateSpec +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// PodTemplateList is a list of PodTemplates. +type PodTemplateList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + + Items []PodTemplate +} + +// ReplicationControllerSpec is the specification of a replication controller. +// As the internal representation of a replication controller, it may have either +// a TemplateRef or a Template set. +type ReplicationControllerSpec struct { + // Replicas is the number of desired replicas. + Replicas int32 + + // Minimum number of seconds for which a newly created pod should be ready + // without any of its container crashing, for it to be considered available. + // Defaults to 0 (pod will be considered available as soon as it is ready) + // +optional + MinReadySeconds int32 + + // Selector is a label query over pods that should match the Replicas count. + Selector map[string]string + + // TemplateRef is a reference to an object that describes the pod that will be created if + // insufficient replicas are detected. This reference is ignored if a Template is set. + // Must be set before converting to a versioned API object + // +optional + // TemplateRef *ObjectReference + + // Template is the object that describes the pod that will be created if + // insufficient replicas are detected. Internally, this takes precedence over a + // TemplateRef. + // +optional + Template *PodTemplateSpec +} + +// ReplicationControllerStatus represents the current status of a replication +// controller. +type ReplicationControllerStatus struct { + // Replicas is the number of actual replicas. + Replicas int32 + + // The number of pods that have labels matching the labels of the pod template of the replication controller. + // +optional + FullyLabeledReplicas int32 + + // The number of ready replicas for this replication controller. + // +optional + ReadyReplicas int32 + + // The number of available replicas (ready for at least minReadySeconds) for this replication controller. + // +optional + AvailableReplicas int32 + + // ObservedGeneration is the most recent generation observed by the controller. + // +optional + ObservedGeneration int64 + + // Represents the latest available observations of a replication controller's current state. + // +optional + Conditions []ReplicationControllerCondition +} + +// ReplicationControllerConditionType defines the conditions of a replication controller. +type ReplicationControllerConditionType string + +// These are valid conditions of a replication controller. +const ( + // ReplicationControllerReplicaFailure is added in a replication controller when one of its pods + // fails to be created due to insufficient quota, limit ranges, pod security policy, node selectors, + // etc. or deleted due to kubelet being down or finalizers are failing. + ReplicationControllerReplicaFailure ReplicationControllerConditionType = "ReplicaFailure" +) + +// ReplicationControllerCondition describes the state of a replication controller at a certain point. +type ReplicationControllerCondition struct { + // Type of replication controller condition. + Type ReplicationControllerConditionType + // Status of the condition, one of True, False, Unknown. + Status ConditionStatus + // The last time the condition transitioned from one status to another. + // +optional + LastTransitionTime metav1.Time + // The reason for the condition's last transition. + // +optional + Reason string + // A human readable message indicating details about the transition. + // +optional + Message string +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ReplicationController represents the configuration of a replication controller. +type ReplicationController struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + + // Spec defines the desired behavior of this replication controller. + // +optional + Spec ReplicationControllerSpec + + // Status is the current status of this replication controller. This data may be + // out of date by some window of time. + // +optional + Status ReplicationControllerStatus +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ReplicationControllerList is a collection of replication controllers. +type ReplicationControllerList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + + Items []ReplicationController +} + +const ( + // ClusterIPNone - do not assign a cluster IP + // no proxying required and no environment variables should be created for pods + ClusterIPNone = "None" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ServiceList holds a list of services. +type ServiceList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + + Items []Service +} + +// ServiceAffinity Type string +type ServiceAffinity string + +const ( + // ServiceAffinityClientIP is the Client IP based. + ServiceAffinityClientIP ServiceAffinity = "ClientIP" + + // ServiceAffinityNone - no session affinity. + ServiceAffinityNone ServiceAffinity = "None" +) + +const ( + // DefaultClientIPServiceAffinitySeconds is the default timeout seconds + // of Client IP based session affinity - 3 hours. + DefaultClientIPServiceAffinitySeconds int32 = 10800 + // MaxClientIPServiceAffinitySeconds is the max timeout seconds + // of Client IP based session affinity - 1 day. + MaxClientIPServiceAffinitySeconds int32 = 86400 +) + +// SessionAffinityConfig represents the configurations of session affinity. +type SessionAffinityConfig struct { + // clientIP contains the configurations of Client IP based session affinity. + // +optional + ClientIP *ClientIPConfig +} + +// ClientIPConfig represents the configurations of Client IP based session affinity. +type ClientIPConfig struct { + // timeoutSeconds specifies the seconds of ClientIP type session sticky time. + // The value must be >0 && <=86400(for 1 day) if ServiceAffinity == "ClientIP". + // Default value is 10800(for 3 hours). + // +optional + TimeoutSeconds *int32 +} + +// ServiceType string describes ingress methods for a service +type ServiceType string + +const ( + // ServiceTypeClusterIP means a service will only be accessible inside the + // cluster, via the ClusterIP. + ServiceTypeClusterIP ServiceType = "ClusterIP" + + // ServiceTypeNodePort means a service will be exposed on one port of + // every node, in addition to 'ClusterIP' type. + ServiceTypeNodePort ServiceType = "NodePort" + + // ServiceTypeLoadBalancer means a service will be exposed via an + // external load balancer (if the cloud provider supports it), in addition + // to 'NodePort' type. + ServiceTypeLoadBalancer ServiceType = "LoadBalancer" + + // ServiceTypeExternalName means a service consists of only a reference to + // an external name that kubedns or equivalent will return as a CNAME + // record, with no exposing or proxying of any pods involved. + ServiceTypeExternalName ServiceType = "ExternalName" +) + +// ServiceInternalTrafficPolicyType describes the endpoint-selection policy for +// traffic sent to the ClusterIP. +type ServiceInternalTrafficPolicyType string + +const ( + // ServiceInternalTrafficPolicyCluster routes traffic to all endpoints. + ServiceInternalTrafficPolicyCluster ServiceInternalTrafficPolicyType = "Cluster" + + // ServiceInternalTrafficPolicyLocal routes traffic only to endpoints on the same + // node as the traffic was received on (dropping the traffic if there are no + // local endpoints). + ServiceInternalTrafficPolicyLocal ServiceInternalTrafficPolicyType = "Local" +) + +// ServiceExternalTrafficPolicyType describes the endpoint-selection policy for +// traffic to external service entrypoints (NodePorts, ExternalIPs, and +// LoadBalancer IPs). +type ServiceExternalTrafficPolicyType string + +const ( + // ServiceExternalTrafficPolicyTypeCluster routes traffic to all endpoints. + ServiceExternalTrafficPolicyTypeCluster ServiceExternalTrafficPolicyType = "Cluster" + + // ServiceExternalTrafficPolicyTypeLocal preserves the source IP of the traffic by + // routing only to endpoints on the same node as the traffic was received on + // (dropping the traffic if there are no local endpoints). + ServiceExternalTrafficPolicyTypeLocal ServiceExternalTrafficPolicyType = "Local" +) + +// These are the valid conditions of a service. +const ( + // LoadBalancerPortsError represents the condition of the requested ports + // on the cloud load balancer instance. + LoadBalancerPortsError = "LoadBalancerPortsError" +) + +// ServiceStatus represents the current status of a service +type ServiceStatus struct { + // LoadBalancer contains the current status of the load-balancer, + // if one is present. + // +optional + LoadBalancer LoadBalancerStatus + + // Current service condition + // +optional + Conditions []metav1.Condition +} + +// LoadBalancerStatus represents the status of a load-balancer +type LoadBalancerStatus struct { + // Ingress is a list containing ingress points for the load-balancer; + // traffic intended for the service should be sent to these ingress points. + // +optional + Ingress []LoadBalancerIngress +} + +// LoadBalancerIngress represents the status of a load-balancer ingress point: +// traffic intended for the service should be sent to an ingress point. +type LoadBalancerIngress struct { + // IP is set for load-balancer ingress points that are IP based + // (typically GCE or OpenStack load-balancers) + // +optional + IP string + + // Hostname is set for load-balancer ingress points that are DNS based + // (typically AWS load-balancers) + // +optional + Hostname string + + // Ports is a list of records of service ports + // If used, every port defined in the service should have an entry in it + // +optional + Ports []PortStatus +} + +// IPFamily represents the IP Family (IPv4 or IPv6). This type is used +// to express the family of an IP expressed by a type (e.g. service.spec.ipFamilies). +type IPFamily string + +const ( + // IPv4Protocol indicates that this IP is IPv4 protocol + IPv4Protocol IPFamily = "IPv4" + // IPv6Protocol indicates that this IP is IPv6 protocol + IPv6Protocol IPFamily = "IPv6" +) + +// IPFamilyPolicy represents the dual-stack-ness requested or required by a Service +type IPFamilyPolicy string + +const ( + // IPFamilyPolicySingleStack indicates that this service is required to have a single IPFamily. + // The IPFamily assigned is based on the default IPFamily used by the cluster + // or as identified by service.spec.ipFamilies field + IPFamilyPolicySingleStack IPFamilyPolicy = "SingleStack" + // IPFamilyPolicyPreferDualStack indicates that this service prefers dual-stack when + // the cluster is configured for dual-stack. If the cluster is not configured + // for dual-stack the service will be assigned a single IPFamily. If the IPFamily is not + // set in service.spec.ipFamilies then the service will be assigned the default IPFamily + // configured on the cluster + IPFamilyPolicyPreferDualStack IPFamilyPolicy = "PreferDualStack" + // IPFamilyPolicyRequireDualStack indicates that this service requires dual-stack. Using + // IPFamilyPolicyRequireDualStack on a single stack cluster will result in validation errors. The + // IPFamilies (and their order) assigned to this service is based on service.spec.ipFamilies. If + // service.spec.ipFamilies was not provided then it will be assigned according to how they are + // configured on the cluster. If service.spec.ipFamilies has only one entry then the alternative + // IPFamily will be added by apiserver + IPFamilyPolicyRequireDualStack IPFamilyPolicy = "RequireDualStack" +) + +// ServiceSpec describes the attributes that a user creates on a service +type ServiceSpec struct { + // Type determines how the Service is exposed. Defaults to ClusterIP. Valid + // options are ExternalName, ClusterIP, NodePort, and LoadBalancer. + // "ExternalName" maps to the specified externalName. + // "ClusterIP" allocates a cluster-internal IP address for load-balancing to + // endpoints. Endpoints are determined by the selector or if that is not + // specified, by manual construction of an Endpoints object. If clusterIP is + // "None", no virtual IP is allocated and the endpoints are published as a + // set of endpoints rather than a stable IP. + // "NodePort" builds on ClusterIP and allocates a port on every node which + // routes to the clusterIP. + // "LoadBalancer" builds on NodePort and creates an + // external load-balancer (if supported in the current cloud) which routes + // to the clusterIP. + // More info: https://kubernetes.io/docs/concepts/services-networking/service/ + // +optional + Type ServiceType + + // Required: The list of ports that are exposed by this service. + Ports []ServicePort + + // Route service traffic to pods with label keys and values matching this + // selector. If empty or not present, the service is assumed to have an + // external process managing its endpoints, which Kubernetes will not + // modify. Only applies to types ClusterIP, NodePort, and LoadBalancer. + // Ignored if type is ExternalName. + // More info: https://kubernetes.io/docs/concepts/services-networking/service/ + Selector map[string]string + + // ClusterIP is the IP address of the service and is usually assigned + // randomly by the master. If an address is specified manually and is not in + // use by others, it will be allocated to the service; otherwise, creation + // of the service will fail. This field can not be changed through updates. + // Valid values are "None", empty string (""), or a valid IP address. "None" + // can be specified for headless services when proxying is not required. + // Only applies to types ClusterIP, NodePort, and LoadBalancer. Ignored if + // type is ExternalName. + // More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies + // +optional + ClusterIP string + + // ClusterIPs identifies all the ClusterIPs assigned to this + // service. ClusterIPs are assigned or reserved based on the values of + // service.spec.ipFamilies. A maximum of two entries (dual-stack IPs) are + // allowed in ClusterIPs. The IPFamily of each ClusterIP must match + // values provided in service.spec.ipFamilies. Clients using ClusterIPs must + // keep it in sync with ClusterIP (if provided) by having ClusterIP matching + // first element of ClusterIPs. + // +optional + ClusterIPs []string + + // IPFamilies identifies all the IPFamilies assigned for this Service. If a value + // was not provided for IPFamilies it will be defaulted based on the cluster + // configuration and the value of service.spec.ipFamilyPolicy. A maximum of two + // values (dual-stack IPFamilies) are allowed in IPFamilies. IPFamilies field is + // conditionally mutable: it allows for adding or removing a secondary IPFamily, + // but it does not allow changing the primary IPFamily of the service. + // +optional + IPFamilies []IPFamily + + // IPFamilyPolicy represents the dual-stack-ness requested or required by this + // Service. If there is no value provided, then this Service will be considered + // SingleStack (single IPFamily). Services can be SingleStack (single IPFamily), + // PreferDualStack (two dual-stack IPFamilies on dual-stack clusters or single + // IPFamily on single-stack clusters), or RequireDualStack (two dual-stack IPFamilies + // on dual-stack configured clusters, otherwise fail). The IPFamilies and ClusterIPs assigned + // to this service can be controlled by service.spec.ipFamilies and service.spec.clusterIPs + // respectively. + // +optional + IPFamilyPolicy *IPFamilyPolicy + + // ExternalName is the external reference that kubedns or equivalent will + // return as a CNAME record for this service. No proxying will be involved. + // Must be a valid RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + // and requires Type to be ExternalName. + ExternalName string + + // ExternalIPs are used by external load balancers, or can be set by + // users to handle external traffic that arrives at a node. + // +optional + ExternalIPs []string + + // Only applies to Service Type: LoadBalancer + // LoadBalancer will get created with the IP specified in this field. + // This feature depends on whether the underlying cloud-provider supports specifying + // the loadBalancerIP when a load balancer is created. + // This field will be ignored if the cloud-provider does not support the feature. + // Deprecated: This field was under-specified and its meaning varies across implementations, + // and it cannot support dual-stack. + // As of Kubernetes v1.24, users are encouraged to use implementation-specific annotations when available. + // This field may be removed in a future API version. + // +optional + LoadBalancerIP string + + // Optional: Supports "ClientIP" and "None". Used to maintain session affinity. + // +optional + SessionAffinity ServiceAffinity + + // sessionAffinityConfig contains the configurations of session affinity. + // +optional + SessionAffinityConfig *SessionAffinityConfig + + // Optional: If specified and supported by the platform, this will restrict traffic through the cloud-provider + // load-balancer will be restricted to the specified client IPs. This field will be ignored if the + // cloud-provider does not support the feature." + // +optional + LoadBalancerSourceRanges []string + + // externalTrafficPolicy describes how nodes distribute service traffic they + // receive on one of the Service's "externally-facing" addresses (NodePorts, + // ExternalIPs, and LoadBalancer IPs). If set to "Local", the proxy will configure + // the service in a way that assumes that external load balancers will take care + // of balancing the service traffic between nodes, and so each node will deliver + // traffic only to the node-local endpoints of the service, without masquerading + // the client source IP. (Traffic mistakenly sent to a node with no endpoints will + // be dropped.) The default value, "Cluster", uses the standard behavior of + // routing to all endpoints evenly (possibly modified by topology and other + // features). Note that traffic sent to an External IP or LoadBalancer IP from + // within the cluster will always get "Cluster" semantics, but clients sending to + // a NodePort from within the cluster may need to take traffic policy into account + // when picking a node. + // +optional + ExternalTrafficPolicy ServiceExternalTrafficPolicyType + + // healthCheckNodePort specifies the healthcheck nodePort for the service. + // If not specified, HealthCheckNodePort is created by the service api + // backend with the allocated nodePort. Will use user-specified nodePort value + // if specified by the client. Only effects when Type is set to LoadBalancer + // and ExternalTrafficPolicy is set to Local. + // +optional + HealthCheckNodePort int32 + + // publishNotReadyAddresses indicates that any agent which deals with endpoints for this + // Service should disregard any indications of ready/not-ready. + // The primary use case for setting this field is for a StatefulSet's Headless Service to + // propagate SRV DNS records for its Pods for the purpose of peer discovery. + // The Kubernetes controllers that generate Endpoints and EndpointSlice resources for + // Services interpret this to mean that all endpoints are considered "ready" even if the + // Pods themselves are not. Agents which consume only Kubernetes generated endpoints + // through the Endpoints or EndpointSlice resources can safely assume this behavior. + // +optional + PublishNotReadyAddresses bool + + // allocateLoadBalancerNodePorts defines if NodePorts will be automatically + // allocated for services with type LoadBalancer. Default is "true". It + // may be set to "false" if the cluster load-balancer does not rely on + // NodePorts. If the caller requests specific NodePorts (by specifying a + // value), those requests will be respected, regardless of this field. + // This field may only be set for services with type LoadBalancer and will + // be cleared if the type is changed to any other type. + // +optional + AllocateLoadBalancerNodePorts *bool + + // loadBalancerClass is the class of the load balancer implementation this Service belongs to. + // If specified, the value of this field must be a label-style identifier, with an optional prefix, + // e.g. "internal-vip" or "example.com/internal-vip". Unprefixed names are reserved for end-users. + // This field can only be set when the Service type is 'LoadBalancer'. If not set, the default load + // balancer implementation is used, today this is typically done through the cloud provider integration, + // but should apply for any default implementation. If set, it is assumed that a load balancer + // implementation is watching for Services with a matching class. Any default load balancer + // implementation (e.g. cloud providers) should ignore Services that set this field. + // This field can only be set when creating or updating a Service to type 'LoadBalancer'. + // Once set, it can not be changed. This field will be wiped when a service is updated to a non 'LoadBalancer' type. + // +optional + LoadBalancerClass *string + + // InternalTrafficPolicy describes how nodes distribute service traffic they + // receive on the ClusterIP. If set to "Local", the proxy will assume that pods + // only want to talk to endpoints of the service on the same node as the pod, + // dropping the traffic if there are no local endpoints. The default value, + // "Cluster", uses the standard behavior of routing to all endpoints evenly + // (possibly modified by topology and other features). + // +optional + InternalTrafficPolicy *ServiceInternalTrafficPolicyType +} + +// ServicePort represents the port on which the service is exposed +type ServicePort struct { + // Optional if only one ServicePort is defined on this service: The + // name of this port within the service. This must be a DNS_LABEL. + // All ports within a ServiceSpec must have unique names. This maps to + // the 'Name' field in EndpointPort objects. + Name string + + // The IP protocol for this port. Supports "TCP", "UDP", and "SCTP". + Protocol Protocol + + // The application protocol for this port. + // This field follows standard Kubernetes label syntax. + // Un-prefixed names are reserved for IANA standard service names (as per + // RFC-6335 and https://www.iana.org/assignments/service-names). + // Non-standard protocols should use prefixed names such as + // mycompany.com/my-custom-protocol. + // +optional + AppProtocol *string + + // The port that will be exposed on the service. + Port int32 + + // Optional: The target port on pods selected by this service. If this + // is a string, it will be looked up as a named port in the target + // Pod's container ports. If this is not specified, the value + // of the 'port' field is used (an identity map). + // This field is ignored for services with clusterIP=None, and should be + // omitted or set equal to the 'port' field. + TargetPort intstr.IntOrString + + // The port on each node on which this service is exposed. + // Default is to auto-allocate a port if the ServiceType of this Service requires one. + NodePort int32 +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Service is a named abstraction of software service (for example, mysql) consisting of local port +// (for example 3306) that the proxy listens on, and the selector that determines which pods +// will answer requests sent through the proxy. +type Service struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + + // Spec defines the behavior of a service. + // +optional + Spec ServiceSpec + + // Status represents the current status of a service. + // +optional + Status ServiceStatus +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ServiceAccount binds together: +// * a name, understood by users, and perhaps by peripheral systems, for an identity +// * a principal that can be authenticated and authorized +// * a set of secrets +type ServiceAccount struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + + // Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. + // Pods are only limited to this list if this service account has a "kubernetes.io/enforce-mountable-secrets" annotation set to "true". + // This field should not be used to find auto-generated service account token secrets for use outside of pods. + // Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. + Secrets []ObjectReference + + // ImagePullSecrets is a list of references to secrets in the same namespace to use for pulling any images + // in pods that reference this ServiceAccount. ImagePullSecrets are distinct from Secrets because Secrets + // can be mounted in the pod, but ImagePullSecrets are only accessed by the kubelet. + // +optional + ImagePullSecrets []LocalObjectReference + + // AutomountServiceAccountToken indicates whether pods running as this service account should have an API token automatically mounted. + // Can be overridden at the pod level. + // +optional + AutomountServiceAccountToken *bool +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ServiceAccountList is a list of ServiceAccount objects +type ServiceAccountList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + + Items []ServiceAccount +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Endpoints is a collection of endpoints that implement the actual service. Example: +// +// Name: "mysvc", +// Subsets: [ +// { +// Addresses: [{"ip": "10.10.1.1"}, {"ip": "10.10.2.2"}], +// Ports: [{"name": "a", "port": 8675}, {"name": "b", "port": 309}] +// }, +// { +// Addresses: [{"ip": "10.10.3.3"}], +// Ports: [{"name": "a", "port": 93}, {"name": "b", "port": 76}] +// }, +// ] +type Endpoints struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + + // The set of all endpoints is the union of all subsets. + Subsets []EndpointSubset +} + +// EndpointSubset is a group of addresses with a common set of ports. The +// expanded set of endpoints is the Cartesian product of Addresses x Ports. +// For example, given: +// +// { +// Addresses: [{"ip": "10.10.1.1"}, {"ip": "10.10.2.2"}], +// Ports: [{"name": "a", "port": 8675}, {"name": "b", "port": 309}] +// } +// +// The resulting set of endpoints can be viewed as: +// +// a: [ 10.10.1.1:8675, 10.10.2.2:8675 ], +// b: [ 10.10.1.1:309, 10.10.2.2:309 ] +type EndpointSubset struct { + Addresses []EndpointAddress + NotReadyAddresses []EndpointAddress + Ports []EndpointPort +} + +// EndpointAddress is a tuple that describes single IP address. +type EndpointAddress struct { + // The IP of this endpoint. + // IPv6 is also accepted but not fully supported on all platforms. Also, certain + // kubernetes components, like kube-proxy, are not IPv6 ready. + // TODO: This should allow hostname or IP, see #4447. + IP string + // Optional: Hostname of this endpoint + // Meant to be used by DNS servers etc. + // +optional + Hostname string + // Optional: Node hosting this endpoint. This can be used to determine endpoints local to a node. + // +optional + NodeName *string + // Optional: The kubernetes object related to the entry point. + TargetRef *ObjectReference +} + +// EndpointPort is a tuple that describes a single port. +type EndpointPort struct { + // The name of this port (corresponds to ServicePort.Name). Optional + // if only one port is defined. Must be a DNS_LABEL. + Name string + + // The port number. + Port int32 + + // The IP protocol for this port. + Protocol Protocol + + // The application protocol for this port. + // This field follows standard Kubernetes label syntax. + // Un-prefixed names are reserved for IANA standard service names (as per + // RFC-6335 and https://www.iana.org/assignments/service-names). + // Non-standard protocols should use prefixed names such as + // mycompany.com/my-custom-protocol. + // +optional + AppProtocol *string +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// EndpointsList is a list of endpoints. +type EndpointsList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + + Items []Endpoints +} + +// NodeSpec describes the attributes that a node is created with. +type NodeSpec struct { + // PodCIDRs represents the IP ranges assigned to the node for usage by Pods on that node. It may + // contain AT MOST one value for each of IPv4 and IPv6. + // Note: assigning IP ranges to nodes might need to be revisited when we support migratable IPs. + // +optional + PodCIDRs []string + + // ID of the node assigned by the cloud provider + // Note: format is "://" + // +optional + ProviderID string + + // Unschedulable controls node schedulability of new pods. By default node is schedulable. + // +optional + Unschedulable bool + + // If specified, the node's taints. + // +optional + Taints []Taint + + // Deprecated: Previously used to specify the source of the node's configuration for the DynamicKubeletConfig feature. This feature is removed. + // +optional + ConfigSource *NodeConfigSource + + // Deprecated. Not all kubelets will set this field. Remove field after 1.13. + // see: https://issues.k8s.io/61966 + // +optional + DoNotUseExternalID string +} + +// Deprecated: NodeConfigSource specifies a source of node configuration. Exactly one subfield must be non-nil. +type NodeConfigSource struct { + ConfigMap *ConfigMapNodeConfigSource +} + +// Deprecated: ConfigMapNodeConfigSource represents the config map of a node +type ConfigMapNodeConfigSource struct { + // Namespace is the metadata.namespace of the referenced ConfigMap. + // This field is required in all cases. + Namespace string + + // Name is the metadata.name of the referenced ConfigMap. + // This field is required in all cases. + Name string + + // UID is the metadata.UID of the referenced ConfigMap. + // This field is forbidden in Node.Spec, and required in Node.Status. + // +optional + UID types.UID + + // ResourceVersion is the metadata.ResourceVersion of the referenced ConfigMap. + // This field is forbidden in Node.Spec, and required in Node.Status. + // +optional + ResourceVersion string + + // KubeletConfigKey declares which key of the referenced ConfigMap corresponds to the KubeletConfiguration structure + // This field is required in all cases. + KubeletConfigKey string +} + +// DaemonEndpoint contains information about a single Daemon endpoint. +type DaemonEndpoint struct { + /* + The port tag was not properly in quotes in earlier releases, so it must be + uppercase for backwards compatibility (since it was falling back to var name of + 'Port'). + */ + + // Port number of the given endpoint. + Port int32 +} + +// NodeDaemonEndpoints lists ports opened by daemons running on the Node. +type NodeDaemonEndpoints struct { + // Endpoint on which Kubelet is listening. + // +optional + KubeletEndpoint DaemonEndpoint +} + +// NodeSystemInfo is a set of ids/uuids to uniquely identify the node. +type NodeSystemInfo struct { + // MachineID reported by the node. For unique machine identification + // in the cluster this field is preferred. Learn more from man(5) + // machine-id: http://man7.org/linux/man-pages/man5/machine-id.5.html + MachineID string + // SystemUUID reported by the node. For unique machine identification + // MachineID is preferred. This field is specific to Red Hat hosts + // https://access.redhat.com/documentation/en-us/red_hat_subscription_management/1/html/rhsm/uuid + SystemUUID string + // Boot ID reported by the node. + BootID string + // Kernel Version reported by the node. + KernelVersion string + // OS Image reported by the node. + OSImage string + // ContainerRuntime Version reported by the node. + ContainerRuntimeVersion string + // Kubelet Version reported by the node. + KubeletVersion string + // KubeProxy Version reported by the node. + KubeProxyVersion string + // The Operating System reported by the node + OperatingSystem string + // The Architecture reported by the node + Architecture string +} + +// NodeConfigStatus describes the status of the config assigned by Node.Spec.ConfigSource. +type NodeConfigStatus struct { + // Assigned reports the checkpointed config the node will try to use. + // When Node.Spec.ConfigSource is updated, the node checkpoints the associated + // config payload to local disk, along with a record indicating intended + // config. The node refers to this record to choose its config checkpoint, and + // reports this record in Assigned. Assigned only updates in the status after + // the record has been checkpointed to disk. When the Kubelet is restarted, + // it tries to make the Assigned config the Active config by loading and + // validating the checkpointed payload identified by Assigned. + // +optional + Assigned *NodeConfigSource + // Active reports the checkpointed config the node is actively using. + // Active will represent either the current version of the Assigned config, + // or the current LastKnownGood config, depending on whether attempting to use the + // Assigned config results in an error. + // +optional + Active *NodeConfigSource + // LastKnownGood reports the checkpointed config the node will fall back to + // when it encounters an error attempting to use the Assigned config. + // The Assigned config becomes the LastKnownGood config when the node determines + // that the Assigned config is stable and correct. + // This is currently implemented as a 10-minute soak period starting when the local + // record of Assigned config is updated. If the Assigned config is Active at the end + // of this period, it becomes the LastKnownGood. Note that if Spec.ConfigSource is + // reset to nil (use local defaults), the LastKnownGood is also immediately reset to nil, + // because the local default config is always assumed good. + // You should not make assumptions about the node's method of determining config stability + // and correctness, as this may change or become configurable in the future. + // +optional + LastKnownGood *NodeConfigSource + // Error describes any problems reconciling the Spec.ConfigSource to the Active config. + // Errors may occur, for example, attempting to checkpoint Spec.ConfigSource to the local Assigned + // record, attempting to checkpoint the payload associated with Spec.ConfigSource, attempting + // to load or validate the Assigned config, etc. + // Errors may occur at different points while syncing config. Earlier errors (e.g. download or + // checkpointing errors) will not result in a rollback to LastKnownGood, and may resolve across + // Kubelet retries. Later errors (e.g. loading or validating a checkpointed config) will result in + // a rollback to LastKnownGood. In the latter case, it is usually possible to resolve the error + // by fixing the config assigned in Spec.ConfigSource. + // You can find additional information for debugging by searching the error message in the Kubelet log. + // Error is a human-readable description of the error state; machines can check whether or not Error + // is empty, but should not rely on the stability of the Error text across Kubelet versions. + // +optional + Error string +} + +// NodeStatus is information about the current status of a node. +type NodeStatus struct { + // Capacity represents the total resources of a node. + // +optional + Capacity ResourceList + // Allocatable represents the resources of a node that are available for scheduling. + // +optional + Allocatable ResourceList + // NodePhase is the current lifecycle phase of the node. + // +optional + Phase NodePhase + // Conditions is an array of current node conditions. + // +optional + Conditions []NodeCondition + // Queried from cloud provider, if available. + // +optional + Addresses []NodeAddress + // Endpoints of daemons running on the Node. + // +optional + DaemonEndpoints NodeDaemonEndpoints + // Set of ids/uuids to uniquely identify the node. + // +optional + NodeInfo NodeSystemInfo + // List of container images on this node + // +optional + Images []ContainerImage + // List of attachable volumes in use (mounted) by the node. + // +optional + VolumesInUse []UniqueVolumeName + // List of volumes that are attached to the node. + // +optional + VolumesAttached []AttachedVolume + // Status of the config assigned to the node via the dynamic Kubelet config feature. + // +optional + Config *NodeConfigStatus +} + +// UniqueVolumeName defines the name of attached volume +type UniqueVolumeName string + +// AttachedVolume describes a volume attached to a node +type AttachedVolume struct { + // Name of the attached volume + Name UniqueVolumeName + + // DevicePath represents the device path where the volume should be available + DevicePath string +} + +// AvoidPods describes pods that should avoid this node. This is the value for a +// Node annotation with key scheduler.alpha.kubernetes.io/preferAvoidPods and +// will eventually become a field of NodeStatus. +type AvoidPods struct { + // Bounded-sized list of signatures of pods that should avoid this node, sorted + // in timestamp order from oldest to newest. Size of the slice is unspecified. + // +optional + PreferAvoidPods []PreferAvoidPodsEntry +} + +// PreferAvoidPodsEntry describes a class of pods that should avoid this node. +type PreferAvoidPodsEntry struct { + // The class of pods. + PodSignature PodSignature + // Time at which this entry was added to the list. + // +optional + EvictionTime metav1.Time + // (brief) reason why this entry was added to the list. + // +optional + Reason string + // Human readable message indicating why this entry was added to the list. + // +optional + Message string +} + +// PodSignature describes the class of pods that should avoid this node. +// Exactly one field should be set. +type PodSignature struct { + // Reference to controller whose pods should avoid this node. + // +optional + PodController *metav1.OwnerReference +} + +// ContainerImage describe a container image +type ContainerImage struct { + // Names by which this image is known. + // +optional + Names []string + // The size of the image in bytes. + // +optional + SizeBytes int64 +} + +// NodePhase defines the phase in which a node is in +type NodePhase string + +// These are the valid phases of node. +const ( + // NodePending means the node has been created/added by the system, but not configured. + NodePending NodePhase = "Pending" + // NodeRunning means the node has been configured and has Kubernetes components running. + NodeRunning NodePhase = "Running" + // NodeTerminated means the node has been removed from the cluster. + NodeTerminated NodePhase = "Terminated" +) + +// NodeConditionType defines node's condition +type NodeConditionType string + +// These are valid conditions of node. Currently, we don't have enough information to decide +// node condition. In the future, we will add more. The proposed set of conditions are: +// NodeReady, NodeReachable +const ( + // NodeReady means kubelet is healthy and ready to accept pods. + NodeReady NodeConditionType = "Ready" + // NodeMemoryPressure means the kubelet is under pressure due to insufficient available memory. + NodeMemoryPressure NodeConditionType = "MemoryPressure" + // NodeDiskPressure means the kubelet is under pressure due to insufficient available disk. + NodeDiskPressure NodeConditionType = "DiskPressure" + // NodeNetworkUnavailable means that network for the node is not correctly configured. + NodeNetworkUnavailable NodeConditionType = "NetworkUnavailable" +) + +// NodeCondition represents the node's condition +type NodeCondition struct { + Type NodeConditionType + Status ConditionStatus + // +optional + LastHeartbeatTime metav1.Time + // +optional + LastTransitionTime metav1.Time + // +optional + Reason string + // +optional + Message string +} + +// NodeAddressType defines the node's address type +type NodeAddressType string + +// These are valid values of node address type +const ( + // NodeHostName identifies a name of the node. Although every node can be assumed + // to have a NodeAddress of this type, its exact syntax and semantics are not + // defined, and are not consistent between different clusters. + NodeHostName NodeAddressType = "Hostname" + + // NodeInternalIP identifies an IP address which is assigned to one of the node's + // network interfaces. Every node should have at least one address of this type. + // + // An internal IP is normally expected to be reachable from every other node, but + // may not be visible to hosts outside the cluster. By default it is assumed that + // kube-apiserver can reach node internal IPs, though it is possible to configure + // clusters where this is not the case. + // + // NodeInternalIP is the default type of node IP, and does not necessarily imply + // that the IP is ONLY reachable internally. If a node has multiple internal IPs, + // no specific semantics are assigned to the additional IPs. + NodeInternalIP NodeAddressType = "InternalIP" + + // NodeExternalIP identifies an IP address which is, in some way, intended to be + // more usable from outside the cluster then an internal IP, though no specific + // semantics are defined. It may be a globally routable IP, though it is not + // required to be. + // + // External IPs may be assigned directly to an interface on the node, like a + // NodeInternalIP, or alternatively, packets sent to the external IP may be NAT'ed + // to an internal node IP rather than being delivered directly (making the IP less + // efficient for node-to-node traffic than a NodeInternalIP). + NodeExternalIP NodeAddressType = "ExternalIP" + + // NodeInternalDNS identifies a DNS name which resolves to an IP address which has + // the characteristics of a NodeInternalIP. The IP it resolves to may or may not + // be a listed NodeInternalIP address. + NodeInternalDNS NodeAddressType = "InternalDNS" + + // NodeExternalDNS identifies a DNS name which resolves to an IP address which has + // the characteristics of a NodeExternalIP. The IP it resolves to may or may not + // be a listed NodeExternalIP address. + NodeExternalDNS NodeAddressType = "ExternalDNS" +) + +// NodeAddress represents node's address +type NodeAddress struct { + Type NodeAddressType + Address string +} + +// NodeResources is an object for conveying resource information about a node. +// see https://kubernetes.io/docs/concepts/architecture/nodes/#capacity for more details. +type NodeResources struct { + // Capacity represents the available resources of a node + // +optional + Capacity ResourceList +} + +// ResourceName is the name identifying various resources in a ResourceList. +type ResourceName string + +// Resource names must be not more than 63 characters, consisting of upper- or lower-case alphanumeric characters, +// with the -, _, and . characters allowed anywhere, except the first or last character. +// The default convention, matching that for annotations, is to use lower-case names, with dashes, rather than +// camel case, separating compound words. +// Fully-qualified resource typenames are constructed from a DNS-style subdomain, followed by a slash `/` and a name. +const ( + // CPU, in cores. (500m = .5 cores) + ResourceCPU ResourceName = "cpu" + // Memory, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024) + ResourceMemory ResourceName = "memory" + // Volume size, in bytes (e,g. 5Gi = 5GiB = 5 * 1024 * 1024 * 1024) + ResourceStorage ResourceName = "storage" + // Local ephemeral storage, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024) + // The resource name for ResourceEphemeralStorage is alpha and it can change across releases. + ResourceEphemeralStorage ResourceName = "ephemeral-storage" +) + +const ( + // ResourceDefaultNamespacePrefix is the default namespace prefix. + ResourceDefaultNamespacePrefix = "kubernetes.io/" + // ResourceHugePagesPrefix is the name prefix for huge page resources (alpha). + ResourceHugePagesPrefix = "hugepages-" + // ResourceAttachableVolumesPrefix is the name prefix for storage resource limits + ResourceAttachableVolumesPrefix = "attachable-volumes-" +) + +// ResourceList is a set of (resource name, quantity) pairs. +type ResourceList map[ResourceName]resource.Quantity + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Node is a worker node in Kubernetes +// The name of the node according to etcd is in ObjectMeta.Name. +type Node struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + + // Spec defines the behavior of a node. + // +optional + Spec NodeSpec + + // Status describes the current status of a Node + // +optional + Status NodeStatus +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// NodeList is a list of nodes. +type NodeList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + + Items []Node +} + +// NamespaceSpec describes the attributes on a Namespace +type NamespaceSpec struct { + // Finalizers is an opaque list of values that must be empty to permanently remove object from storage + Finalizers []FinalizerName +} + +// FinalizerName is the name identifying a finalizer during namespace lifecycle. +type FinalizerName string + +// These are internal finalizer values to Kubernetes, must be qualified name unless defined here or +// in metav1. +const ( + FinalizerKubernetes FinalizerName = "kubernetes" +) + +// NamespaceStatus is information about the current status of a Namespace. +type NamespaceStatus struct { + // Phase is the current lifecycle phase of the namespace. + // +optional + Phase NamespacePhase + // +optional + Conditions []NamespaceCondition +} + +// NamespacePhase defines the phase in which the namespace is +type NamespacePhase string + +// These are the valid phases of a namespace. +const ( + // NamespaceActive means the namespace is available for use in the system + NamespaceActive NamespacePhase = "Active" + // NamespaceTerminating means the namespace is undergoing graceful termination + NamespaceTerminating NamespacePhase = "Terminating" +) + +// NamespaceConditionType defines constants reporting on status during namespace lifetime and deletion progress +type NamespaceConditionType string + +// These are valid conditions of a namespace. +const ( + NamespaceDeletionDiscoveryFailure NamespaceConditionType = "NamespaceDeletionDiscoveryFailure" + NamespaceDeletionContentFailure NamespaceConditionType = "NamespaceDeletionContentFailure" + NamespaceDeletionGVParsingFailure NamespaceConditionType = "NamespaceDeletionGroupVersionParsingFailure" +) + +// NamespaceCondition contains details about state of namespace. +type NamespaceCondition struct { + // Type of namespace controller condition. + Type NamespaceConditionType + // Status of the condition, one of True, False, Unknown. + Status ConditionStatus + // +optional + LastTransitionTime metav1.Time + // +optional + Reason string + // +optional + Message string +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Namespace provides a scope for Names. +// Use of multiple namespaces is optional +type Namespace struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + + // Spec defines the behavior of the Namespace. + // +optional + Spec NamespaceSpec + + // Status describes the current status of a Namespace + // +optional + Status NamespaceStatus +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// NamespaceList is a list of Namespaces. +type NamespaceList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + + Items []Namespace +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Binding ties one object to another; for example, a pod is bound to a node by a scheduler. +// Deprecated in 1.7, please use the bindings subresource of pods instead. +type Binding struct { + metav1.TypeMeta + // ObjectMeta describes the object that is being bound. + // +optional + metav1.ObjectMeta + + // Target is the object to bind to. + Target ObjectReference +} + +// Preconditions must be fulfilled before an operation (update, delete, etc.) is carried out. +type Preconditions struct { + // Specifies the target UID. + // +optional + UID *types.UID +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// PodLogOptions is the query options for a Pod's logs REST call +type PodLogOptions struct { + metav1.TypeMeta + + // Container for which to return logs + Container string + // If true, follow the logs for the pod + Follow bool + // If true, return previous terminated container logs + Previous bool + // A relative time in seconds before the current time from which to show logs. If this value + // precedes the time a pod was started, only logs since the pod start will be returned. + // If this value is in the future, no logs will be returned. + // Only one of sinceSeconds or sinceTime may be specified. + SinceSeconds *int64 + // An RFC3339 timestamp from which to show logs. If this value + // precedes the time a pod was started, only logs since the pod start will be returned. + // If this value is in the future, no logs will be returned. + // Only one of sinceSeconds or sinceTime may be specified. + SinceTime *metav1.Time + // If true, add an RFC 3339 timestamp with 9 digits of fractional seconds at the beginning of every line + // of log output. + Timestamps bool + // If set, the number of lines from the end of the logs to show. If not specified, + // logs are shown from the creation of the container or sinceSeconds or sinceTime + TailLines *int64 + // If set, the number of bytes to read from the server before terminating the + // log output. This may not display a complete final line of logging, and may return + // slightly more or slightly less than the specified limit. + LimitBytes *int64 + + // insecureSkipTLSVerifyBackend indicates that the apiserver should not confirm the validity of the + // serving certificate of the backend it is connecting to. This will make the HTTPS connection between the apiserver + // and the backend insecure. This means the apiserver cannot verify the log data it is receiving came from the real + // kubelet. If the kubelet is configured to verify the apiserver's TLS credentials, it does not mean the + // connection to the real kubelet is vulnerable to a man in the middle attack (e.g. an attacker could not intercept + // the actual log data coming from the real kubelet). + // +optional + InsecureSkipTLSVerifyBackend bool +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// PodAttachOptions is the query options to a Pod's remote attach call +// TODO: merge w/ PodExecOptions below for stdin, stdout, etc +type PodAttachOptions struct { + metav1.TypeMeta + + // Stdin if true indicates that stdin is to be redirected for the attach call + // +optional + Stdin bool + + // Stdout if true indicates that stdout is to be redirected for the attach call + // +optional + Stdout bool + + // Stderr if true indicates that stderr is to be redirected for the attach call + // +optional + Stderr bool + + // TTY if true indicates that a tty will be allocated for the attach call + // +optional + TTY bool + + // Container to attach to. + // +optional + Container string +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// PodExecOptions is the query options to a Pod's remote exec call +type PodExecOptions struct { + metav1.TypeMeta + + // Stdin if true indicates that stdin is to be redirected for the exec call + Stdin bool + + // Stdout if true indicates that stdout is to be redirected for the exec call + Stdout bool + + // Stderr if true indicates that stderr is to be redirected for the exec call + Stderr bool + + // TTY if true indicates that a tty will be allocated for the exec call + TTY bool + + // Container in which to execute the command. + Container string + + // Command is the remote command to execute; argv array; not executed within a shell. + Command []string +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// PodPortForwardOptions is the query options to a Pod's port forward call +type PodPortForwardOptions struct { + metav1.TypeMeta + + // The list of ports to forward + // +optional + Ports []int32 +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// PodProxyOptions is the query options to a Pod's proxy call +type PodProxyOptions struct { + metav1.TypeMeta + + // Path is the URL path to use for the current proxy request + Path string +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// NodeProxyOptions is the query options to a Node's proxy call +type NodeProxyOptions struct { + metav1.TypeMeta + + // Path is the URL path to use for the current proxy request + Path string +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ServiceProxyOptions is the query options to a Service's proxy call. +type ServiceProxyOptions struct { + metav1.TypeMeta + + // Path is the part of URLs that include service endpoints, suffixes, + // and parameters to use for the current proxy request to service. + // For example, the whole request URL is + // http://localhost/api/v1/namespaces/kube-system/services/elasticsearch-logging/_search?q=user:kimchy. + // Path is _search?q=user:kimchy. + Path string +} + +// ObjectReference contains enough information to let you inspect or modify the referred object. +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type ObjectReference struct { + // +optional + Kind string + // +optional + Namespace string + // +optional + Name string + // +optional + UID types.UID + // +optional + APIVersion string + // +optional + ResourceVersion string + + // Optional. If referring to a piece of an object instead of an entire object, this string + // should contain information to identify the sub-object. For example, if the object + // reference is to a container within a pod, this would take on a value like: + // "spec.containers{name}" (where "name" refers to the name of the container that triggered + // the event) or if no container name is specified "spec.containers[2]" (container with + // index 2 in this pod). This syntax is chosen only to have some well-defined way of + // referencing a part of an object. + // TODO: this design is not final and this field is subject to change in the future. + // +optional + FieldPath string +} + +// LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace. +type LocalObjectReference struct { + // TODO: Add other useful fields. apiVersion, kind, uid? + Name string +} + +// TypedLocalObjectReference contains enough information to let you locate the typed referenced object inside the same namespace. +type TypedLocalObjectReference struct { + // APIGroup is the group for the resource being referenced. + // If APIGroup is not specified, the specified Kind must be in the core API group. + // For any other third-party types, APIGroup is required. + // +optional + APIGroup *string + // Kind is the type of resource being referenced + Kind string + // Name is the name of resource being referenced + Name string +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// SerializedReference represents a serialized object reference +type SerializedReference struct { + metav1.TypeMeta + // +optional + Reference ObjectReference +} + +// EventSource represents the source from which an event is generated +type EventSource struct { + // Component from which the event is generated. + // +optional + Component string + // Node name on which the event is generated. + // +optional + Host string +} + +// Valid values for event types (new types could be added in future) +const ( + // Information only and will not cause any problems + EventTypeNormal string = "Normal" + // These events are to warn that something might go wrong + EventTypeWarning string = "Warning" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Event is a report of an event somewhere in the cluster. Events +// have a limited retention time and triggers and messages may evolve +// with time. Event consumers should not rely on the timing of an event +// with a given Reason reflecting a consistent underlying trigger, or the +// continued existence of events with that Reason. Events should be +// treated as informative, best-effort, supplemental data. +// TODO: Decide whether to store these separately or with the object they apply to. +type Event struct { + metav1.TypeMeta + + metav1.ObjectMeta + + // The object that this event is about. Mapped to events.Event.regarding + // +optional + InvolvedObject ObjectReference + + // Optional; this should be a short, machine understandable string that gives the reason + // for this event being generated. For example, if the event is reporting that a container + // can't start, the Reason might be "ImageNotFound". + // TODO: provide exact specification for format. + // +optional + Reason string + + // Optional. A human-readable description of the status of this operation. + // TODO: decide on maximum length. Mapped to events.Event.note + // +optional + Message string + + // Optional. The component reporting this event. Should be a short machine understandable string. + // +optional + Source EventSource + + // The time at which the event was first recorded. (Time of server receipt is in TypeMeta.) + // +optional + FirstTimestamp metav1.Time + + // The time at which the most recent occurrence of this event was recorded. + // +optional + LastTimestamp metav1.Time + + // The number of times this event has occurred. + // +optional + Count int32 + + // Type of this event (Normal, Warning), new types could be added in the future. + // +optional + Type string + + // Time when this Event was first observed. + // +optional + EventTime metav1.MicroTime + + // Data about the Event series this event represents or nil if it's a singleton Event. + // +optional + Series *EventSeries + + // What action was taken/failed regarding to the Regarding object. + // +optional + Action string + + // Optional secondary object for more complex actions. + // +optional + Related *ObjectReference + + // Name of the controller that emitted this Event, e.g. `kubernetes.io/kubelet`. + // +optional + ReportingController string + + // ID of the controller instance, e.g. `kubelet-xyzf`. + // +optional + ReportingInstance string +} + +// EventSeries represents a series ov events +type EventSeries struct { + // Number of occurrences in this series up to the last heartbeat time + Count int32 + // Time of the last occurrence observed + LastObservedTime metav1.MicroTime +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// EventList is a list of events. +type EventList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + + Items []Event +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// List holds a list of objects, which may not be known by the server. +type List metainternalversion.List + +// LimitType defines a type of object that is limited +type LimitType string + +const ( + // LimitTypePod defines limit that applies to all pods in a namespace + LimitTypePod LimitType = "Pod" + // LimitTypeContainer defines limit that applies to all containers in a namespace + LimitTypeContainer LimitType = "Container" + // LimitTypePersistentVolumeClaim defines limit that applies to all persistent volume claims in a namespace + LimitTypePersistentVolumeClaim LimitType = "PersistentVolumeClaim" +) + +// LimitRangeItem defines a min/max usage limit for any resource that matches on kind +type LimitRangeItem struct { + // Type of resource that this limit applies to + // +optional + Type LimitType + // Max usage constraints on this kind by resource name + // +optional + Max ResourceList + // Min usage constraints on this kind by resource name + // +optional + Min ResourceList + // Default resource requirement limit value by resource name. + // +optional + Default ResourceList + // DefaultRequest resource requirement request value by resource name. + // +optional + DefaultRequest ResourceList + // MaxLimitRequestRatio represents the max burst value for the named resource + // +optional + MaxLimitRequestRatio ResourceList +} + +// LimitRangeSpec defines a min/max usage limit for resources that match on kind +type LimitRangeSpec struct { + // Limits is the list of LimitRangeItem objects that are enforced + Limits []LimitRangeItem +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// LimitRange sets resource usage limits for each kind of resource in a Namespace +type LimitRange struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + + // Spec defines the limits enforced + // +optional + Spec LimitRangeSpec +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// LimitRangeList is a list of LimitRange items. +type LimitRangeList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + + // Items is a list of LimitRange objects + Items []LimitRange +} + +// The following identify resource constants for Kubernetes object types +const ( + // Pods, number + ResourcePods ResourceName = "pods" + // Services, number + ResourceServices ResourceName = "services" + // ReplicationControllers, number + ResourceReplicationControllers ResourceName = "replicationcontrollers" + // ResourceQuotas, number + ResourceQuotas ResourceName = "resourcequotas" + // ResourceSecrets, number + ResourceSecrets ResourceName = "secrets" + // ResourceConfigMaps, number + ResourceConfigMaps ResourceName = "configmaps" + // ResourcePersistentVolumeClaims, number + ResourcePersistentVolumeClaims ResourceName = "persistentvolumeclaims" + // ResourceServicesNodePorts, number + ResourceServicesNodePorts ResourceName = "services.nodeports" + // ResourceServicesLoadBalancers, number + ResourceServicesLoadBalancers ResourceName = "services.loadbalancers" + // CPU request, in cores. (500m = .5 cores) + ResourceRequestsCPU ResourceName = "requests.cpu" + // Memory request, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024) + ResourceRequestsMemory ResourceName = "requests.memory" + // Storage request, in bytes + ResourceRequestsStorage ResourceName = "requests.storage" + // Local ephemeral storage request, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024) + ResourceRequestsEphemeralStorage ResourceName = "requests.ephemeral-storage" + // CPU limit, in cores. (500m = .5 cores) + ResourceLimitsCPU ResourceName = "limits.cpu" + // Memory limit, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024) + ResourceLimitsMemory ResourceName = "limits.memory" + // Local ephemeral storage limit, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024) + ResourceLimitsEphemeralStorage ResourceName = "limits.ephemeral-storage" +) + +// The following identify resource prefix for Kubernetes object types +const ( + // HugePages request, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024) + // As burst is not supported for HugePages, we would only quota its request, and ignore the limit. + ResourceRequestsHugePagesPrefix = "requests.hugepages-" + // Default resource requests prefix + DefaultResourceRequestsPrefix = "requests." +) + +// ResourceQuotaScope defines a filter that must match each object tracked by a quota +type ResourceQuotaScope string + +// These are valid values for resource quota spec +const ( + // Match all pod objects where spec.activeDeadlineSeconds >=0 + ResourceQuotaScopeTerminating ResourceQuotaScope = "Terminating" + // Match all pod objects where spec.activeDeadlineSeconds is nil + ResourceQuotaScopeNotTerminating ResourceQuotaScope = "NotTerminating" + // Match all pod objects that have best effort quality of service + ResourceQuotaScopeBestEffort ResourceQuotaScope = "BestEffort" + // Match all pod objects that do not have best effort quality of service + ResourceQuotaScopeNotBestEffort ResourceQuotaScope = "NotBestEffort" + // Match all pod objects that have priority class mentioned + ResourceQuotaScopePriorityClass ResourceQuotaScope = "PriorityClass" + // Match all pod objects that have cross-namespace pod (anti)affinity mentioned + ResourceQuotaScopeCrossNamespacePodAffinity ResourceQuotaScope = "CrossNamespacePodAffinity" +) + +// ResourceQuotaSpec defines the desired hard limits to enforce for Quota +type ResourceQuotaSpec struct { + // Hard is the set of desired hard limits for each named resource + // +optional + Hard ResourceList + // A collection of filters that must match each object tracked by a quota. + // If not specified, the quota matches all objects. + // +optional + Scopes []ResourceQuotaScope + // ScopeSelector is also a collection of filters like Scopes that must match each object tracked by a quota + // but expressed using ScopeSelectorOperator in combination with possible values. + // +optional + ScopeSelector *ScopeSelector +} + +// ScopeSelector represents the AND of the selectors represented +// by the scoped-resource selector terms. +type ScopeSelector struct { + // A list of scope selector requirements by scope of the resources. + // +optional + MatchExpressions []ScopedResourceSelectorRequirement +} + +// ScopedResourceSelectorRequirement is a selector that contains values, a scope name, and an operator +// that relates the scope name and values. +type ScopedResourceSelectorRequirement struct { + // The name of the scope that the selector applies to. + ScopeName ResourceQuotaScope + // Represents a scope's relationship to a set of values. + // Valid operators are In, NotIn, Exists, DoesNotExist. + Operator ScopeSelectorOperator + // An array of string values. If the operator is In or NotIn, + // the values array must be non-empty. If the operator is Exists or DoesNotExist, + // the values array must be empty. + // This array is replaced during a strategic merge patch. + // +optional + Values []string +} + +// ScopeSelectorOperator is the set of operators that can be used in +// a scope selector requirement. +type ScopeSelectorOperator string + +// These are the valid values for ScopeSelectorOperator +const ( + ScopeSelectorOpIn ScopeSelectorOperator = "In" + ScopeSelectorOpNotIn ScopeSelectorOperator = "NotIn" + ScopeSelectorOpExists ScopeSelectorOperator = "Exists" + ScopeSelectorOpDoesNotExist ScopeSelectorOperator = "DoesNotExist" +) + +// ResourceQuotaStatus defines the enforced hard limits and observed use +type ResourceQuotaStatus struct { + // Hard is the set of enforced hard limits for each named resource + // +optional + Hard ResourceList + // Used is the current observed total usage of the resource in the namespace + // +optional + Used ResourceList +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ResourceQuota sets aggregate quota restrictions enforced per namespace +type ResourceQuota struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + + // Spec defines the desired quota + // +optional + Spec ResourceQuotaSpec + + // Status defines the actual enforced quota and its current usage + // +optional + Status ResourceQuotaStatus +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ResourceQuotaList is a list of ResourceQuota items +type ResourceQuotaList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + + // Items is a list of ResourceQuota objects + Items []ResourceQuota +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Secret holds secret data of a certain type. The total bytes of the values in +// the Data field must be less than MaxSecretSize bytes. +type Secret struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + + // Immutable field, if set, ensures that data stored in the Secret cannot + // be updated (only object metadata can be modified). + // +optional + Immutable *bool + + // Data contains the secret data. Each key must consist of alphanumeric + // characters, '-', '_' or '.'. The serialized form of the secret data is a + // base64 encoded string, representing the arbitrary (possibly non-string) + // data value here. + // +optional + Data map[string][]byte `datapolicy:"password,security-key,token"` + + // Used to facilitate programmatic handling of secret data. + // More info: https://kubernetes.io/docs/concepts/configuration/secret/#secret-types + // +optional + Type SecretType +} + +// MaxSecretSize represents the max secret size. +const MaxSecretSize = 1 * 1024 * 1024 + +// SecretType defines the types of secrets +type SecretType string + +// These are the valid values for SecretType +const ( + // SecretTypeOpaque is the default; arbitrary user-defined data + SecretTypeOpaque SecretType = "Opaque" + + // SecretTypeServiceAccountToken contains a token that identifies a service account to the API + // + // Required fields: + // - Secret.Annotations["kubernetes.io/service-account.name"] - the name of the ServiceAccount the token identifies + // - Secret.Annotations["kubernetes.io/service-account.uid"] - the UID of the ServiceAccount the token identifies + // - Secret.Data["token"] - a token that identifies the service account to the API + SecretTypeServiceAccountToken SecretType = "kubernetes.io/service-account-token" + + // ServiceAccountNameKey is the key of the required annotation for SecretTypeServiceAccountToken secrets + ServiceAccountNameKey = "kubernetes.io/service-account.name" + // ServiceAccountUIDKey is the key of the required annotation for SecretTypeServiceAccountToken secrets + ServiceAccountUIDKey = "kubernetes.io/service-account.uid" + // ServiceAccountTokenKey is the key of the required data for SecretTypeServiceAccountToken secrets + ServiceAccountTokenKey = "token" + // ServiceAccountKubeconfigKey is the key of the optional kubeconfig data for SecretTypeServiceAccountToken secrets + ServiceAccountKubeconfigKey = "kubernetes.kubeconfig" + // ServiceAccountRootCAKey is the key of the optional root certificate authority for SecretTypeServiceAccountToken secrets + ServiceAccountRootCAKey = "ca.crt" + // ServiceAccountNamespaceKey is the key of the optional namespace to use as the default for namespaced API calls + ServiceAccountNamespaceKey = "namespace" + + // SecretTypeDockercfg contains a dockercfg file that follows the same format rules as ~/.dockercfg + // + // Required fields: + // - Secret.Data[".dockercfg"] - a serialized ~/.dockercfg file + SecretTypeDockercfg SecretType = "kubernetes.io/dockercfg" + + // DockerConfigKey is the key of the required data for SecretTypeDockercfg secrets + DockerConfigKey = ".dockercfg" + + // SecretTypeDockerConfigJSON contains a dockercfg file that follows the same format rules as ~/.docker/config.json + // + // Required fields: + // - Secret.Data[".dockerconfigjson"] - a serialized ~/.docker/config.json file + SecretTypeDockerConfigJSON SecretType = "kubernetes.io/dockerconfigjson" + + // DockerConfigJSONKey is the key of the required data for SecretTypeDockerConfigJson secrets + DockerConfigJSONKey = ".dockerconfigjson" + + // SecretTypeBasicAuth contains data needed for basic authentication. + // + // Required at least one of fields: + // - Secret.Data["username"] - username used for authentication + // - Secret.Data["password"] - password or token needed for authentication + SecretTypeBasicAuth SecretType = "kubernetes.io/basic-auth" + + // BasicAuthUsernameKey is the key of the username for SecretTypeBasicAuth secrets + BasicAuthUsernameKey = "username" + // BasicAuthPasswordKey is the key of the password or token for SecretTypeBasicAuth secrets + BasicAuthPasswordKey = "password" + + // SecretTypeSSHAuth contains data needed for SSH authentication. + // + // Required field: + // - Secret.Data["ssh-privatekey"] - private SSH key needed for authentication + SecretTypeSSHAuth SecretType = "kubernetes.io/ssh-auth" + + // SSHAuthPrivateKey is the key of the required SSH private key for SecretTypeSSHAuth secrets + SSHAuthPrivateKey = "ssh-privatekey" + + // SecretTypeTLS contains information about a TLS client or server secret. It + // is primarily used with TLS termination of the Ingress resource, but may be + // used in other types. + // + // Required fields: + // - Secret.Data["tls.key"] - TLS private key. + // Secret.Data["tls.crt"] - TLS certificate. + // TODO: Consider supporting different formats, specifying CA/destinationCA. + SecretTypeTLS SecretType = "kubernetes.io/tls" + + // TLSCertKey is the key for tls certificates in a TLS secret. + TLSCertKey = "tls.crt" + // TLSPrivateKeyKey is the key for the private key field in a TLS secret. + TLSPrivateKeyKey = "tls.key" + // SecretTypeBootstrapToken is used during the automated bootstrap process (first + // implemented by kubeadm). It stores tokens that are used to sign well known + // ConfigMaps. They are used for authn. + SecretTypeBootstrapToken SecretType = "bootstrap.kubernetes.io/token" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// SecretList represents the list of secrets +type SecretList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + + Items []Secret +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ConfigMap holds configuration data for components or applications to consume. +type ConfigMap struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + + // Immutable field, if set, ensures that data stored in the ConfigMap cannot + // be updated (only object metadata can be modified). + // +optional + Immutable *bool + + // Data contains the configuration data. + // Each key must consist of alphanumeric characters, '-', '_' or '.'. + // Values with non-UTF-8 byte sequences must use the BinaryData field. + // The keys stored in Data must not overlap with the keys in + // the BinaryData field, this is enforced during validation process. + // +optional + Data map[string]string + + // BinaryData contains the binary data. + // Each key must consist of alphanumeric characters, '-', '_' or '.'. + // BinaryData can contain byte sequences that are not in the UTF-8 range. + // The keys stored in BinaryData must not overlap with the ones in + // the Data field, this is enforced during validation process. + // Using this field will require 1.10+ apiserver and + // kubelet. + // +optional + BinaryData map[string][]byte +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ConfigMapList is a resource containing a list of ConfigMap objects. +type ConfigMapList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + + // Items is the list of ConfigMaps. + Items []ConfigMap +} + +// These constants are for remote command execution and port forwarding and are +// used by both the client side and server side components. +// +// This is probably not the ideal place for them, but it didn't seem worth it +// to create pkg/exec and pkg/portforward just to contain a single file with +// constants in it. Suggestions for more appropriate alternatives are +// definitely welcome! +const ( + // Enable stdin for remote command execution + ExecStdinParam = "input" + // Enable stdout for remote command execution + ExecStdoutParam = "output" + // Enable stderr for remote command execution + ExecStderrParam = "error" + // Enable TTY for remote command execution + ExecTTYParam = "tty" + // Command to run for remote command execution + ExecCommandParam = "command" + + // Name of header that specifies stream type + StreamType = "streamType" + // Value for streamType header for stdin stream + StreamTypeStdin = "stdin" + // Value for streamType header for stdout stream + StreamTypeStdout = "stdout" + // Value for streamType header for stderr stream + StreamTypeStderr = "stderr" + // Value for streamType header for data stream + StreamTypeData = "data" + // Value for streamType header for error stream + StreamTypeError = "error" + // Value for streamType header for terminal resize stream + StreamTypeResize = "resize" + + // Name of header that specifies the port being forwarded + PortHeader = "port" + // Name of header that specifies a request ID used to associate the error + // and data streams for a single forwarded connection + PortForwardRequestIDHeader = "requestID" +) + +// ComponentConditionType defines type and constants for component health validation. +type ComponentConditionType string + +// These are the valid conditions for the component. +const ( + ComponentHealthy ComponentConditionType = "Healthy" +) + +// ComponentCondition represents the condition of a component +type ComponentCondition struct { + Type ComponentConditionType + Status ConditionStatus + // +optional + Message string + // +optional + Error string +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ComponentStatus (and ComponentStatusList) holds the cluster validation info. +// Deprecated: This API is deprecated in v1.19+ +type ComponentStatus struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + + // +optional + Conditions []ComponentCondition +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ComponentStatusList represents the list of component statuses +// Deprecated: This API is deprecated in v1.19+ +type ComponentStatusList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + + Items []ComponentStatus +} + +// SecurityContext holds security configuration that will be applied to a container. +// Some fields are present in both SecurityContext and PodSecurityContext. When both +// are set, the values in SecurityContext take precedence. +type SecurityContext struct { + // The capabilities to add/drop when running containers. + // Defaults to the default set of capabilities granted by the container runtime. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + Capabilities *Capabilities + // Run container in privileged mode. + // Processes in privileged containers are essentially equivalent to root on the host. + // Defaults to false. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + Privileged *bool + // The SELinux context to be applied to the container. + // If unspecified, the container runtime will allocate a random SELinux context for each + // container. May also be set in PodSecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + SELinuxOptions *SELinuxOptions + // The Windows specific settings applied to all containers. + // If unspecified, the options from the PodSecurityContext will be used. + // If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + // Note that this field cannot be set when spec.os.name is linux. + // +optional + WindowsOptions *WindowsSecurityContextOptions + // The UID to run the entrypoint of the container process. + // Defaults to user specified in image metadata if unspecified. + // May also be set in PodSecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + RunAsUser *int64 + // The GID to run the entrypoint of the container process. + // Uses runtime default if unset. + // May also be set in PodSecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + RunAsGroup *int64 + // Indicates that the container must run as a non-root user. + // If true, the Kubelet will validate the image at runtime to ensure that it + // does not run as UID 0 (root) and fail to start the container if it does. + // If unset or false, no such validation will be performed. + // May also be set in PodSecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence. + // +optional + RunAsNonRoot *bool + // The read-only root filesystem allows you to restrict the locations that an application can write + // files to, ensuring the persistent data can only be written to mounts. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + ReadOnlyRootFilesystem *bool + // AllowPrivilegeEscalation controls whether a process can gain more + // privileges than its parent process. This bool directly controls if + // the no_new_privs flag will be set on the container process. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + AllowPrivilegeEscalation *bool + // ProcMount denotes the type of proc mount to use for the containers. + // The default is DefaultProcMount which uses the container runtime defaults for + // readonly paths and masked paths. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + ProcMount *ProcMountType + // The seccomp options to use by this container. If seccomp options are + // provided at both the pod & container level, the container options + // override the pod options. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + SeccompProfile *SeccompProfile +} + +// ProcMountType defines the type of proc mount +type ProcMountType string + +const ( + // DefaultProcMount uses the container runtime defaults for readonly and masked + // paths for /proc. Most container runtimes mask certain paths in /proc to avoid + // accidental security exposure of special devices or information. + DefaultProcMount ProcMountType = "Default" + + // UnmaskedProcMount bypasses the default masking behavior of the container + // runtime and ensures the newly created /proc the container stays intact with + // no modifications. + UnmaskedProcMount ProcMountType = "Unmasked" +) + +// SELinuxOptions are the labels to be applied to the container. +type SELinuxOptions struct { + // SELinux user label + // +optional + User string + // SELinux role label + // +optional + Role string + // SELinux type label + // +optional + Type string + // SELinux level label. + // +optional + Level string +} + +// WindowsSecurityContextOptions contain Windows-specific options and credentials. +type WindowsSecurityContextOptions struct { + // GMSACredentialSpecName is the name of the GMSA credential spec to use. + // +optional + GMSACredentialSpecName *string + + // GMSACredentialSpec is where the GMSA admission webhook + // (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + // GMSA credential spec named by the GMSACredentialSpecName field. + // +optional + GMSACredentialSpec *string + + // The UserName in Windows to run the entrypoint of the container process. + // Defaults to the user specified in image metadata if unspecified. + // May also be set in PodSecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence. + // +optional + RunAsUserName *string + + // HostProcess determines if a container should be run as a 'Host Process' container. + // This field is alpha-level and will only be honored by components that enable the + // WindowsHostProcessContainers feature flag. Setting this field without the feature + // flag will result in errors when validating the Pod. All of a Pod's containers must + // have the same effective HostProcess value (it is not allowed to have a mix of HostProcess + // containers and non-HostProcess containers). In addition, if HostProcess is true + // then HostNetwork must also be set to true. + // +optional + HostProcess *bool +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// RangeAllocation is an opaque API object (not exposed to end users) that can be persisted to record +// the global allocation state of the cluster. The schema of Range and Data generic, in that Range +// should be a string representation of the inputs to a range (for instance, for IP allocation it +// might be a CIDR) and Data is an opaque blob understood by an allocator which is typically a +// binary range. Consumers should use annotations to record additional information (schema version, +// data encoding hints). A range allocation should *ALWAYS* be recreatable at any time by observation +// of the cluster, thus the object is less strongly typed than most. +type RangeAllocation struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + // A string representing a unique label for a range of resources, such as a CIDR "10.0.0.0/8" or + // port range "10000-30000". Range is not strongly schema'd here. The Range is expected to define + // a start and end unless there is an implicit end. + Range string + // A byte array representing the serialized state of a range allocation. Additional clarifiers on + // the type or format of data should be represented with annotations. For IP allocations, this is + // represented as a bit array starting at the base IP of the CIDR in Range, with each bit representing + // a single allocated address (the fifth bit on CIDR 10.0.0.0/8 is 10.0.0.4). + Data []byte +} + +const ( + // DefaultHardPodAffinitySymmetricWeight is the weight of implicit PreferredDuringScheduling affinity rule. + // + // RequiredDuringScheduling affinity is not symmetric, but there is an implicit PreferredDuringScheduling affinity rule + // corresponding to every RequiredDuringScheduling affinity rule. + // When the --hard-pod-affinity-weight scheduler flag is not specified, + // DefaultHardPodAffinityWeight defines the weight of the implicit PreferredDuringScheduling affinity rule. + DefaultHardPodAffinitySymmetricWeight int32 = 1 +) + +// UnsatisfiableConstraintAction defines the actions that can be taken for an +// unsatisfiable constraint. +type UnsatisfiableConstraintAction string + +const ( + // DoNotSchedule instructs the scheduler not to schedule the pod + // when constraints are not satisfied. + DoNotSchedule UnsatisfiableConstraintAction = "DoNotSchedule" + // ScheduleAnyway instructs the scheduler to schedule the pod + // even if constraints are not satisfied. + ScheduleAnyway UnsatisfiableConstraintAction = "ScheduleAnyway" +) + +// NodeInclusionPolicy defines the type of node inclusion policy +// +enum +type NodeInclusionPolicy string + +const ( + // NodeInclusionPolicyIgnore means ignore this scheduling directive when calculating pod topology spread skew. + NodeInclusionPolicyIgnore NodeInclusionPolicy = "Ignore" + // NodeInclusionPolicyHonor means use this scheduling directive when calculating pod topology spread skew. + NodeInclusionPolicyHonor NodeInclusionPolicy = "Honor" +) + +// TopologySpreadConstraint specifies how to spread matching pods among the given topology. +type TopologySpreadConstraint struct { + // MaxSkew describes the degree to which pods may be unevenly distributed. + // When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference + // between the number of matching pods in the target topology and the global minimum. + // The global minimum is the minimum number of matching pods in an eligible domain + // or zero if the number of eligible domains is less than MinDomains. + // For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same + // labelSelector spread as 2/2/1: + // In this case, the global minimum is 1. + // +-------+-------+-------+ + // | zone1 | zone2 | zone3 | + // +-------+-------+-------+ + // | P P | P P | P | + // +-------+-------+-------+ + // - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; + // scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) + // violate MaxSkew(1). + // - if MaxSkew is 2, incoming pod can be scheduled onto any zone. + // When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence + // to topologies that satisfy it. + // It's a required field. Default value is 1 and 0 is not allowed. + MaxSkew int32 + // TopologyKey is the key of node labels. Nodes that have a label with this key + // and identical values are considered to be in the same topology. + // We consider each as a "bucket", and try to put balanced number + // of pods into each bucket. + // We define a domain as a particular instance of a topology. + // Also, we define an eligible domain as a domain whose nodes meet the requirements of + // nodeAffinityPolicy and nodeTaintsPolicy. + // e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology. + // And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology. + // It's a required field. + TopologyKey string + // WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy + // the spread constraint. + // - DoNotSchedule (default) tells the scheduler not to schedule it. + // - ScheduleAnyway tells the scheduler to schedule the pod in any location, + // but giving higher precedence to topologies that would help reduce the + // skew. + // A constraint is considered "Unsatisfiable" for an incoming pod + // if and only if every possible node assignment for that pod would violate + // "MaxSkew" on some topology. + // For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same + // labelSelector spread as 3/1/1: + // +-------+-------+-------+ + // | zone1 | zone2 | zone3 | + // +-------+-------+-------+ + // | P P P | P | P | + // +-------+-------+-------+ + // If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled + // to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies + // MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler + // won't make it *more* imbalanced. + // It's a required field. + WhenUnsatisfiable UnsatisfiableConstraintAction + // LabelSelector is used to find matching pods. + // Pods that match this label selector are counted to determine the number of pods + // in their corresponding topology domain. + // +optional + LabelSelector *metav1.LabelSelector + // MinDomains indicates a minimum number of eligible domains. + // When the number of eligible domains with matching topology keys is less than minDomains, + // Pod Topology Spread treats "global minimum" as 0, and then the calculation of Skew is performed. + // And when the number of eligible domains with matching topology keys equals or greater than minDomains, + // this value has no effect on scheduling. + // As a result, when the number of eligible domains is less than minDomains, + // scheduler won't schedule more than maxSkew Pods to those domains. + // If value is nil, the constraint behaves as if MinDomains is equal to 1. + // Valid values are integers greater than 0. + // When value is not nil, WhenUnsatisfiable must be DoNotSchedule. + // + // For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same + // labelSelector spread as 2/2/2: + // +-------+-------+-------+ + // | zone1 | zone2 | zone3 | + // +-------+-------+-------+ + // | P P | P P | P P | + // +-------+-------+-------+ + // The number of domains is less than 5(MinDomains), so "global minimum" is treated as 0. + // In this situation, new pod with the same labelSelector cannot be scheduled, + // because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, + // it will violate MaxSkew. + // + // This is a beta field and requires the MinDomainsInPodTopologySpread feature gate to be enabled (enabled by default). + // +optional + MinDomains *int32 + // NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector + // when calculating pod topology spread skew. Options are: + // - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. + // - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. + // + // If this value is nil, the behavior is equivalent to the Honor policy. + // This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. + // +optional + NodeAffinityPolicy *NodeInclusionPolicy + // NodeTaintsPolicy indicates how we will treat node taints when calculating + // pod topology spread skew. Options are: + // - Honor: nodes without taints, along with tainted nodes for which the incoming pod + // has a toleration, are included. + // - Ignore: node taints are ignored. All nodes are included. + // + // If this value is nil, the behavior is equivalent to the Ignore policy. + // This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. + // +optional + NodeTaintsPolicy *NodeInclusionPolicy + // MatchLabelKeys is a set of pod label keys to select the pods over which + // spreading will be calculated. The keys are used to lookup values from the + // incoming pod labels, those key-value labels are ANDed with labelSelector + // to select the group of existing pods over which spreading will be calculated + // for the incoming pod. Keys that don't exist in the incoming pod labels will + // be ignored. A null or empty list means only match against labelSelector. + // +listType=atomic + // +optional + MatchLabelKeys []string +} + +// These are the built-in errors for PortStatus. +const ( + // MixedProtocolNotSupported error in PortStatus means that the cloud provider + // can't ensure the port on the load balancer because mixed values of protocols + // on the same LoadBalancer type of Service are not supported by the cloud provider. + MixedProtocolNotSupported = "MixedProtocolNotSupported" +) + +// PortStatus represents the error condition of a service port +type PortStatus struct { + // Port is the port number of the service port of which status is recorded here + Port int32 + // Protocol is the protocol of the service port of which status is recorded here + Protocol Protocol + // Error is to record the problem with the service port + // The format of the error shall comply with the following rules: + // - built-in error values shall be specified in this file and those shall use + // CamelCase names + // - cloud provider specific error values must have names that comply with the + // format foo.example.com/CamelCase. + // --- + // The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + // +optional + // +kubebuilder:validation:Required + // +kubebuilder:validation:Pattern=`^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$` + // +kubebuilder:validation:MaxLength=316 + Error *string +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/v1/OWNERS b/vendor/k8s.io/kubernetes/pkg/apis/core/v1/OWNERS new file mode 100644 index 000000000..dfcc2e714 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/v1/OWNERS @@ -0,0 +1,24 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +reviewers: + - thockin + - lavalamp + - smarterclayton + - wojtek-t + - deads2k + - yujuhong + - derekwaynecarr + - caesarxuchao + - mikedanese + - liggitt + - sttts + - dchen1107 + - saad-ali + - luxas + - janetkuo + - justinsb + - ncdc + - tallclair + - jsafrane + - dims + - jayunit100 diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/v1/conversion.go b/vendor/k8s.io/kubernetes/pkg/apis/core/v1/conversion.go new file mode 100644 index 000000000..7869f0389 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/v1/conversion.go @@ -0,0 +1,544 @@ +/* +Copyright 2015 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 v1 + +import ( + "fmt" + "reflect" + + v1 "k8s.io/api/core/v1" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/conversion" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/kubernetes/pkg/apis/apps" + "k8s.io/kubernetes/pkg/apis/core" +) + +func addConversionFuncs(scheme *runtime.Scheme) error { + // Add field conversion funcs. + err := scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.WithKind("Pod"), + func(label, value string) (string, string, error) { + switch label { + case "metadata.name", + "metadata.namespace", + "spec.nodeName", + "spec.restartPolicy", + "spec.schedulerName", + "spec.serviceAccountName", + "status.phase", + "status.podIP", + "status.podIPs", + "status.nominatedNodeName": + return label, value, nil + // This is for backwards compatibility with old v1 clients which send spec.host + case "spec.host": + return "spec.nodeName", value, nil + default: + return "", "", fmt.Errorf("field label not supported: %s", label) + } + }, + ) + if err != nil { + return err + } + err = scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.WithKind("Node"), + func(label, value string) (string, string, error) { + switch label { + case "metadata.name": + return label, value, nil + case "spec.unschedulable": + return label, value, nil + default: + return "", "", fmt.Errorf("field label not supported: %s", label) + } + }, + ) + if err != nil { + return err + } + err = scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.WithKind("ReplicationController"), + func(label, value string) (string, string, error) { + switch label { + case "metadata.name", + "metadata.namespace", + "status.replicas": + return label, value, nil + default: + return "", "", fmt.Errorf("field label not supported: %s", label) + } + }) + if err != nil { + return err + } + if err := AddFieldLabelConversionsForEvent(scheme); err != nil { + return err + } + if err := AddFieldLabelConversionsForNamespace(scheme); err != nil { + return err + } + if err := AddFieldLabelConversionsForSecret(scheme); err != nil { + return err + } + return nil +} + +func Convert_v1_ReplicationController_To_apps_ReplicaSet(in *v1.ReplicationController, out *apps.ReplicaSet, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_ReplicationControllerSpec_To_apps_ReplicaSetSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_v1_ReplicationControllerStatus_To_apps_ReplicaSetStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +func Convert_v1_ReplicationControllerSpec_To_apps_ReplicaSetSpec(in *v1.ReplicationControllerSpec, out *apps.ReplicaSetSpec, s conversion.Scope) error { + out.Replicas = *in.Replicas + out.MinReadySeconds = in.MinReadySeconds + if in.Selector != nil { + out.Selector = new(metav1.LabelSelector) + metav1.Convert_Map_string_To_string_To_v1_LabelSelector(&in.Selector, out.Selector, s) + } + if in.Template != nil { + if err := Convert_v1_PodTemplateSpec_To_core_PodTemplateSpec(in.Template, &out.Template, s); err != nil { + return err + } + } + return nil +} + +func Convert_v1_ReplicationControllerStatus_To_apps_ReplicaSetStatus(in *v1.ReplicationControllerStatus, out *apps.ReplicaSetStatus, s conversion.Scope) error { + out.Replicas = in.Replicas + out.FullyLabeledReplicas = in.FullyLabeledReplicas + out.ReadyReplicas = in.ReadyReplicas + out.AvailableReplicas = in.AvailableReplicas + out.ObservedGeneration = in.ObservedGeneration + for _, cond := range in.Conditions { + out.Conditions = append(out.Conditions, apps.ReplicaSetCondition{ + Type: apps.ReplicaSetConditionType(cond.Type), + Status: core.ConditionStatus(cond.Status), + LastTransitionTime: cond.LastTransitionTime, + Reason: cond.Reason, + Message: cond.Message, + }) + } + return nil +} + +func Convert_apps_ReplicaSet_To_v1_ReplicationController(in *apps.ReplicaSet, out *v1.ReplicationController, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_apps_ReplicaSetSpec_To_v1_ReplicationControllerSpec(&in.Spec, &out.Spec, s); err != nil { + fieldErr, ok := err.(*field.Error) + if !ok { + return err + } + if out.Annotations == nil { + out.Annotations = make(map[string]string) + } + out.Annotations[v1.NonConvertibleAnnotationPrefix+"/"+fieldErr.Field] = reflect.ValueOf(fieldErr.BadValue).String() + } + if err := Convert_apps_ReplicaSetStatus_To_v1_ReplicationControllerStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +func Convert_apps_ReplicaSetSpec_To_v1_ReplicationControllerSpec(in *apps.ReplicaSetSpec, out *v1.ReplicationControllerSpec, s conversion.Scope) error { + out.Replicas = new(int32) + *out.Replicas = in.Replicas + out.MinReadySeconds = in.MinReadySeconds + var invalidErr error + if in.Selector != nil { + invalidErr = metav1.Convert_v1_LabelSelector_To_Map_string_To_string(in.Selector, &out.Selector, s) + } + out.Template = new(v1.PodTemplateSpec) + if err := Convert_core_PodTemplateSpec_To_v1_PodTemplateSpec(&in.Template, out.Template, s); err != nil { + return err + } + return invalidErr +} + +func Convert_apps_ReplicaSetStatus_To_v1_ReplicationControllerStatus(in *apps.ReplicaSetStatus, out *v1.ReplicationControllerStatus, s conversion.Scope) error { + out.Replicas = in.Replicas + out.FullyLabeledReplicas = in.FullyLabeledReplicas + out.ReadyReplicas = in.ReadyReplicas + out.AvailableReplicas = in.AvailableReplicas + out.ObservedGeneration = in.ObservedGeneration + for _, cond := range in.Conditions { + out.Conditions = append(out.Conditions, v1.ReplicationControllerCondition{ + Type: v1.ReplicationControllerConditionType(cond.Type), + Status: v1.ConditionStatus(cond.Status), + LastTransitionTime: cond.LastTransitionTime, + Reason: cond.Reason, + Message: cond.Message, + }) + } + return nil +} + +func Convert_core_ReplicationControllerSpec_To_v1_ReplicationControllerSpec(in *core.ReplicationControllerSpec, out *v1.ReplicationControllerSpec, s conversion.Scope) error { + out.Replicas = &in.Replicas + out.MinReadySeconds = in.MinReadySeconds + out.Selector = in.Selector + if in.Template != nil { + out.Template = new(v1.PodTemplateSpec) + if err := Convert_core_PodTemplateSpec_To_v1_PodTemplateSpec(in.Template, out.Template, s); err != nil { + return err + } + } else { + out.Template = nil + } + return nil +} + +func Convert_v1_ReplicationControllerSpec_To_core_ReplicationControllerSpec(in *v1.ReplicationControllerSpec, out *core.ReplicationControllerSpec, s conversion.Scope) error { + if in.Replicas != nil { + out.Replicas = *in.Replicas + } + out.MinReadySeconds = in.MinReadySeconds + out.Selector = in.Selector + if in.Template != nil { + out.Template = new(core.PodTemplateSpec) + if err := Convert_v1_PodTemplateSpec_To_core_PodTemplateSpec(in.Template, out.Template, s); err != nil { + return err + } + } else { + out.Template = nil + } + return nil +} + +func Convert_core_PodTemplateSpec_To_v1_PodTemplateSpec(in *core.PodTemplateSpec, out *v1.PodTemplateSpec, s conversion.Scope) error { + if err := autoConvert_core_PodTemplateSpec_To_v1_PodTemplateSpec(in, out, s); err != nil { + return err + } + + // drop init container annotations so they don't take effect on legacy kubelets. + // remove this once the oldest supported kubelet no longer honors the annotations over the field. + out.Annotations = dropInitContainerAnnotations(out.Annotations) + + return nil +} + +func Convert_v1_PodTemplateSpec_To_core_PodTemplateSpec(in *v1.PodTemplateSpec, out *core.PodTemplateSpec, s conversion.Scope) error { + if err := autoConvert_v1_PodTemplateSpec_To_core_PodTemplateSpec(in, out, s); err != nil { + return err + } + + // drop init container annotations so they don't show up as differences when receiving requests from old clients + out.Annotations = dropInitContainerAnnotations(out.Annotations) + + return nil +} + +func Convert_v1_PodStatus_To_core_PodStatus(in *v1.PodStatus, out *core.PodStatus, s conversion.Scope) error { + if err := autoConvert_v1_PodStatus_To_core_PodStatus(in, out, s); err != nil { + return err + } + + // If both fields (v1.PodIPs and v1.PodIP) are provided and differ, then PodIP is authoritative for compatibility with older kubelets + if (len(in.PodIP) > 0 && len(in.PodIPs) > 0) && (in.PodIP != in.PodIPs[0].IP) { + out.PodIPs = []core.PodIP{ + { + IP: in.PodIP, + }, + } + } + // at the this point, autoConvert copied v1.PodIPs -> core.PodIPs + // if v1.PodIPs was empty but v1.PodIP is not, then set core.PodIPs[0] with v1.PodIP + if len(in.PodIP) > 0 && len(in.PodIPs) == 0 { + out.PodIPs = []core.PodIP{ + { + IP: in.PodIP, + }, + } + } + return nil +} + +func Convert_core_PodStatus_To_v1_PodStatus(in *core.PodStatus, out *v1.PodStatus, s conversion.Scope) error { + if err := autoConvert_core_PodStatus_To_v1_PodStatus(in, out, s); err != nil { + return err + } + // at the this point autoConvert copied core.PodIPs -> v1.PodIPs + // v1.PodIP (singular value field, which does not exist in core) needs to + // be set with core.PodIPs[0] + if len(in.PodIPs) > 0 { + out.PodIP = in.PodIPs[0].IP + } + return nil +} + +// The following two v1.PodSpec conversions are done here to support v1.ServiceAccount +// as an alias for ServiceAccountName. +func Convert_core_PodSpec_To_v1_PodSpec(in *core.PodSpec, out *v1.PodSpec, s conversion.Scope) error { + if err := autoConvert_core_PodSpec_To_v1_PodSpec(in, out, s); err != nil { + return err + } + + // DeprecatedServiceAccount is an alias for ServiceAccountName. + out.DeprecatedServiceAccount = in.ServiceAccountName + + if in.SecurityContext != nil { + // the host namespace fields have to be handled here for backward compatibility + // with v1.0.0 + out.HostPID = in.SecurityContext.HostPID + out.HostNetwork = in.SecurityContext.HostNetwork + out.HostIPC = in.SecurityContext.HostIPC + out.ShareProcessNamespace = in.SecurityContext.ShareProcessNamespace + out.HostUsers = in.SecurityContext.HostUsers + } + + return nil +} + +func Convert_core_NodeSpec_To_v1_NodeSpec(in *core.NodeSpec, out *v1.NodeSpec, s conversion.Scope) error { + if err := autoConvert_core_NodeSpec_To_v1_NodeSpec(in, out, s); err != nil { + return err + } + // at the this point autoConvert copied core.PodCIDRs -> v1.PodCIDRs + // v1.PodCIDR (singular value field, which does not exist in core) needs to + // be set with core.PodCIDRs[0] + if len(in.PodCIDRs) > 0 { + out.PodCIDR = in.PodCIDRs[0] + } + return nil +} + +func Convert_v1_NodeSpec_To_core_NodeSpec(in *v1.NodeSpec, out *core.NodeSpec, s conversion.Scope) error { + if err := autoConvert_v1_NodeSpec_To_core_NodeSpec(in, out, s); err != nil { + return err + } + // If both fields (v1.PodCIDRs and v1.PodCIDR) are provided and differ, then PodCIDR is authoritative for compatibility with older clients + if (len(in.PodCIDR) > 0 && len(in.PodCIDRs) > 0) && (in.PodCIDR != in.PodCIDRs[0]) { + out.PodCIDRs = []string{in.PodCIDR} + } + + // at the this point, autoConvert copied v1.PodCIDRs -> core.PodCIDRs + // if v1.PodCIDRs was empty but v1.PodCIDR is not, then set core.PodCIDRs[0] with v1.PodCIDR + if len(in.PodCIDR) > 0 && len(in.PodCIDRs) == 0 { + out.PodCIDRs = []string{in.PodCIDR} + } + return nil +} + +func Convert_v1_PodSpec_To_core_PodSpec(in *v1.PodSpec, out *core.PodSpec, s conversion.Scope) error { + if err := autoConvert_v1_PodSpec_To_core_PodSpec(in, out, s); err != nil { + return err + } + + // We support DeprecatedServiceAccount as an alias for ServiceAccountName. + // If both are specified, ServiceAccountName (the new field) wins. + if in.ServiceAccountName == "" { + out.ServiceAccountName = in.DeprecatedServiceAccount + } + + // the host namespace fields have to be handled specially for backward compatibility + // with v1.0.0 + if out.SecurityContext == nil { + out.SecurityContext = new(core.PodSecurityContext) + } + out.SecurityContext.HostNetwork = in.HostNetwork + out.SecurityContext.HostPID = in.HostPID + out.SecurityContext.HostIPC = in.HostIPC + out.SecurityContext.ShareProcessNamespace = in.ShareProcessNamespace + out.SecurityContext.HostUsers = in.HostUsers + + return nil +} + +func Convert_v1_Pod_To_core_Pod(in *v1.Pod, out *core.Pod, s conversion.Scope) error { + if err := autoConvert_v1_Pod_To_core_Pod(in, out, s); err != nil { + return err + } + + // drop init container annotations so they don't show up as differences when receiving requests from old clients + out.Annotations = dropInitContainerAnnotations(out.Annotations) + + return nil +} + +func Convert_core_Pod_To_v1_Pod(in *core.Pod, out *v1.Pod, s conversion.Scope) error { + if err := autoConvert_core_Pod_To_v1_Pod(in, out, s); err != nil { + return err + } + + // drop init container annotations so they don't take effect on legacy kubelets. + // remove this once the oldest supported kubelet no longer honors the annotations over the field. + out.Annotations = dropInitContainerAnnotations(out.Annotations) + + return nil +} + +func Convert_v1_Secret_To_core_Secret(in *v1.Secret, out *core.Secret, s conversion.Scope) error { + if err := autoConvert_v1_Secret_To_core_Secret(in, out, s); err != nil { + return err + } + + // StringData overwrites Data + if len(in.StringData) > 0 { + if out.Data == nil { + out.Data = map[string][]byte{} + } + for k, v := range in.StringData { + out.Data[k] = []byte(v) + } + } + + return nil +} + +// +k8s:conversion-fn=copy-only +func Convert_v1_ResourceList_To_core_ResourceList(in *v1.ResourceList, out *core.ResourceList, s conversion.Scope) error { + if *in == nil { + return nil + } + if *out == nil { + *out = make(core.ResourceList, len(*in)) + } + for key, val := range *in { + // Moved to defaults + // TODO(#18538): We round up resource values to milli scale to maintain API compatibility. + // In the future, we should instead reject values that need rounding. + // const milliScale = -3 + // val.RoundUp(milliScale) + + (*out)[core.ResourceName(key)] = val + } + return nil +} + +func AddFieldLabelConversionsForEvent(scheme *runtime.Scheme) error { + return scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.WithKind("Event"), + func(label, value string) (string, string, error) { + switch label { + case "involvedObject.kind", + "involvedObject.namespace", + "involvedObject.name", + "involvedObject.uid", + "involvedObject.apiVersion", + "involvedObject.resourceVersion", + "involvedObject.fieldPath", + "reason", + "reportingComponent", + "source", + "type", + "metadata.namespace", + "metadata.name": + return label, value, nil + default: + return "", "", fmt.Errorf("field label not supported: %s", label) + } + }) +} + +func AddFieldLabelConversionsForNamespace(scheme *runtime.Scheme) error { + return scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.WithKind("Namespace"), + func(label, value string) (string, string, error) { + switch label { + case "status.phase", + "metadata.name": + return label, value, nil + default: + return "", "", fmt.Errorf("field label not supported: %s", label) + } + }) +} + +func AddFieldLabelConversionsForSecret(scheme *runtime.Scheme) error { + return scheme.AddFieldLabelConversionFunc(SchemeGroupVersion.WithKind("Secret"), + func(label, value string) (string, string, error) { + switch label { + case "type", + "metadata.namespace", + "metadata.name": + return label, value, nil + default: + return "", "", fmt.Errorf("field label not supported: %s", label) + } + }) +} + +var initContainerAnnotations = map[string]bool{ + "pod.beta.kubernetes.io/init-containers": true, + "pod.alpha.kubernetes.io/init-containers": true, + "pod.beta.kubernetes.io/init-container-statuses": true, + "pod.alpha.kubernetes.io/init-container-statuses": true, +} + +// dropInitContainerAnnotations returns a copy of the annotations with init container annotations removed, +// or the original annotations if no init container annotations were present. +// +// this can be removed once no clients prior to 1.8 are supported, and no kubelets prior to 1.8 can be run +// (we don't support kubelets older than 2 versions skewed from the apiserver, but we don't prevent them, either) +func dropInitContainerAnnotations(oldAnnotations map[string]string) map[string]string { + if len(oldAnnotations) == 0 { + return oldAnnotations + } + + found := false + for k := range initContainerAnnotations { + if _, ok := oldAnnotations[k]; ok { + found = true + break + } + } + if !found { + return oldAnnotations + } + + newAnnotations := make(map[string]string, len(oldAnnotations)) + for k, v := range oldAnnotations { + if !initContainerAnnotations[k] { + newAnnotations[k] = v + } + } + return newAnnotations +} + +// Convert_core_LoadBalancerStatus_To_v1_LoadBalancerStatus is defined outside the autogenerated file for use by other API packages +func Convert_core_LoadBalancerStatus_To_v1_LoadBalancerStatus(in *core.LoadBalancerStatus, out *v1.LoadBalancerStatus, s conversion.Scope) error { + return autoConvert_core_LoadBalancerStatus_To_v1_LoadBalancerStatus(in, out, s) +} + +// Convert_v1_LoadBalancerStatus_To_core_LoadBalancerStatus is defined outside the autogenerated file for use by other API packages +func Convert_v1_LoadBalancerStatus_To_core_LoadBalancerStatus(in *v1.LoadBalancerStatus, out *core.LoadBalancerStatus, s conversion.Scope) error { + return autoConvert_v1_LoadBalancerStatus_To_core_LoadBalancerStatus(in, out, s) +} + +// Convert_core_Volume_To_v1_Volume is defined outside the autogenerated file for use by other API packages +func Convert_core_Volume_To_v1_Volume(in *core.Volume, out *v1.Volume, s conversion.Scope) error { + return autoConvert_core_Volume_To_v1_Volume(in, out, s) +} + +// Convert_v1_Volume_To_core_Volume is defined outside the autogenerated file for use by other API packages +func Convert_v1_Volume_To_core_Volume(in *v1.Volume, out *core.Volume, s conversion.Scope) error { + return autoConvert_v1_Volume_To_core_Volume(in, out, s) +} + +// Convert_core_PersistentVolumeSpec_To_v1_PersistentVolumeSpec is defined outside the autogenerated file for use by other API packages +func Convert_core_PersistentVolumeSpec_To_v1_PersistentVolumeSpec(in *core.PersistentVolumeSpec, out *v1.PersistentVolumeSpec, s conversion.Scope) error { + return autoConvert_core_PersistentVolumeSpec_To_v1_PersistentVolumeSpec(in, out, s) +} + +// Convert_v1_PersistentVolumeSpec_To_core_PersistentVolumeSpec is defined outside the autogenerated file for use by other API packages +func Convert_v1_PersistentVolumeSpec_To_core_PersistentVolumeSpec(in *v1.PersistentVolumeSpec, out *core.PersistentVolumeSpec, s conversion.Scope) error { + return autoConvert_v1_PersistentVolumeSpec_To_core_PersistentVolumeSpec(in, out, s) +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/v1/defaults.go b/vendor/k8s.io/kubernetes/pkg/apis/core/v1/defaults.go new file mode 100644 index 000000000..b42221691 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/v1/defaults.go @@ -0,0 +1,454 @@ +/* +Copyright 2015 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 v1 + +import ( + "time" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/kubernetes/pkg/util/parsers" + "k8s.io/utils/pointer" +) + +func addDefaultingFuncs(scheme *runtime.Scheme) error { + return RegisterDefaults(scheme) +} + +func SetDefaults_ResourceList(obj *v1.ResourceList) { + for key, val := range *obj { + // TODO(#18538): We round up resource values to milli scale to maintain API compatibility. + // In the future, we should instead reject values that need rounding. + const milliScale = -3 + val.RoundUp(milliScale) + + (*obj)[v1.ResourceName(key)] = val + } +} + +func SetDefaults_ReplicationController(obj *v1.ReplicationController) { + var labels map[string]string + if obj.Spec.Template != nil { + labels = obj.Spec.Template.Labels + } + // TODO: support templates defined elsewhere when we support them in the API + if labels != nil { + if len(obj.Spec.Selector) == 0 { + obj.Spec.Selector = labels + } + if len(obj.Labels) == 0 { + obj.Labels = labels + } + } + if obj.Spec.Replicas == nil { + obj.Spec.Replicas = new(int32) + *obj.Spec.Replicas = 1 + } +} +func SetDefaults_Volume(obj *v1.Volume) { + if pointer.AllPtrFieldsNil(&obj.VolumeSource) { + obj.VolumeSource = v1.VolumeSource{ + EmptyDir: &v1.EmptyDirVolumeSource{}, + } + } +} +func SetDefaults_Container(obj *v1.Container) { + if obj.ImagePullPolicy == "" { + // Ignore error and assume it has been validated elsewhere + _, tag, _, _ := parsers.ParseImageName(obj.Image) + + // Check image tag + if tag == "latest" { + obj.ImagePullPolicy = v1.PullAlways + } else { + obj.ImagePullPolicy = v1.PullIfNotPresent + } + } + if obj.TerminationMessagePath == "" { + obj.TerminationMessagePath = v1.TerminationMessagePathDefault + } + if obj.TerminationMessagePolicy == "" { + obj.TerminationMessagePolicy = v1.TerminationMessageReadFile + } +} + +func SetDefaults_EphemeralContainer(obj *v1.EphemeralContainer) { + SetDefaults_Container((*v1.Container)(&obj.EphemeralContainerCommon)) +} + +func SetDefaults_Service(obj *v1.Service) { + if obj.Spec.SessionAffinity == "" { + obj.Spec.SessionAffinity = v1.ServiceAffinityNone + } + if obj.Spec.SessionAffinity == v1.ServiceAffinityNone { + obj.Spec.SessionAffinityConfig = nil + } + if obj.Spec.SessionAffinity == v1.ServiceAffinityClientIP { + if obj.Spec.SessionAffinityConfig == nil || obj.Spec.SessionAffinityConfig.ClientIP == nil || obj.Spec.SessionAffinityConfig.ClientIP.TimeoutSeconds == nil { + timeoutSeconds := v1.DefaultClientIPServiceAffinitySeconds + obj.Spec.SessionAffinityConfig = &v1.SessionAffinityConfig{ + ClientIP: &v1.ClientIPConfig{ + TimeoutSeconds: &timeoutSeconds, + }, + } + } + } + if obj.Spec.Type == "" { + obj.Spec.Type = v1.ServiceTypeClusterIP + } + for i := range obj.Spec.Ports { + sp := &obj.Spec.Ports[i] + if sp.Protocol == "" { + sp.Protocol = v1.ProtocolTCP + } + if sp.TargetPort == intstr.FromInt(0) || sp.TargetPort == intstr.FromString("") { + sp.TargetPort = intstr.FromInt(int(sp.Port)) + } + } + // Defaults ExternalTrafficPolicy field for NodePort / LoadBalancer service + // to Global for consistency. + if (obj.Spec.Type == v1.ServiceTypeNodePort || + obj.Spec.Type == v1.ServiceTypeLoadBalancer) && + obj.Spec.ExternalTrafficPolicy == "" { + obj.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyTypeCluster + } + + if obj.Spec.InternalTrafficPolicy == nil { + if obj.Spec.Type == v1.ServiceTypeNodePort || obj.Spec.Type == v1.ServiceTypeLoadBalancer || obj.Spec.Type == v1.ServiceTypeClusterIP { + serviceInternalTrafficPolicyCluster := v1.ServiceInternalTrafficPolicyCluster + obj.Spec.InternalTrafficPolicy = &serviceInternalTrafficPolicyCluster + } + } + + if obj.Spec.Type == v1.ServiceTypeLoadBalancer { + if obj.Spec.AllocateLoadBalancerNodePorts == nil { + obj.Spec.AllocateLoadBalancerNodePorts = pointer.BoolPtr(true) + } + } +} +func SetDefaults_Pod(obj *v1.Pod) { + // If limits are specified, but requests are not, default requests to limits + // This is done here rather than a more specific defaulting pass on v1.ResourceRequirements + // because we only want this defaulting semantic to take place on a v1.Pod and not a v1.PodTemplate + for i := range obj.Spec.Containers { + // set requests to limits if requests are not specified, but limits are + if obj.Spec.Containers[i].Resources.Limits != nil { + if obj.Spec.Containers[i].Resources.Requests == nil { + obj.Spec.Containers[i].Resources.Requests = make(v1.ResourceList) + } + for key, value := range obj.Spec.Containers[i].Resources.Limits { + if _, exists := obj.Spec.Containers[i].Resources.Requests[key]; !exists { + obj.Spec.Containers[i].Resources.Requests[key] = value.DeepCopy() + } + } + } + } + for i := range obj.Spec.InitContainers { + if obj.Spec.InitContainers[i].Resources.Limits != nil { + if obj.Spec.InitContainers[i].Resources.Requests == nil { + obj.Spec.InitContainers[i].Resources.Requests = make(v1.ResourceList) + } + for key, value := range obj.Spec.InitContainers[i].Resources.Limits { + if _, exists := obj.Spec.InitContainers[i].Resources.Requests[key]; !exists { + obj.Spec.InitContainers[i].Resources.Requests[key] = value.DeepCopy() + } + } + } + } + if obj.Spec.EnableServiceLinks == nil { + enableServiceLinks := v1.DefaultEnableServiceLinks + obj.Spec.EnableServiceLinks = &enableServiceLinks + } +} +func SetDefaults_PodSpec(obj *v1.PodSpec) { + // New fields added here will break upgrade tests: + // https://github.com/kubernetes/kubernetes/issues/69445 + // In most cases the new defaulted field can added to SetDefaults_Pod instead of here, so + // that it only materializes in the Pod object and not all objects with a PodSpec field. + if obj.DNSPolicy == "" { + obj.DNSPolicy = v1.DNSClusterFirst + } + if obj.RestartPolicy == "" { + obj.RestartPolicy = v1.RestartPolicyAlways + } + if obj.HostNetwork { + defaultHostNetworkPorts(&obj.Containers) + defaultHostNetworkPorts(&obj.InitContainers) + } + if obj.SecurityContext == nil { + obj.SecurityContext = &v1.PodSecurityContext{} + } + if obj.TerminationGracePeriodSeconds == nil { + period := int64(v1.DefaultTerminationGracePeriodSeconds) + obj.TerminationGracePeriodSeconds = &period + } + if obj.SchedulerName == "" { + obj.SchedulerName = v1.DefaultSchedulerName + } +} +func SetDefaults_Probe(obj *v1.Probe) { + if obj.TimeoutSeconds == 0 { + obj.TimeoutSeconds = 1 + } + if obj.PeriodSeconds == 0 { + obj.PeriodSeconds = 10 + } + if obj.SuccessThreshold == 0 { + obj.SuccessThreshold = 1 + } + if obj.FailureThreshold == 0 { + obj.FailureThreshold = 3 + } +} +func SetDefaults_SecretVolumeSource(obj *v1.SecretVolumeSource) { + if obj.DefaultMode == nil { + perm := int32(v1.SecretVolumeSourceDefaultMode) + obj.DefaultMode = &perm + } +} +func SetDefaults_ConfigMapVolumeSource(obj *v1.ConfigMapVolumeSource) { + if obj.DefaultMode == nil { + perm := int32(v1.ConfigMapVolumeSourceDefaultMode) + obj.DefaultMode = &perm + } +} +func SetDefaults_DownwardAPIVolumeSource(obj *v1.DownwardAPIVolumeSource) { + if obj.DefaultMode == nil { + perm := int32(v1.DownwardAPIVolumeSourceDefaultMode) + obj.DefaultMode = &perm + } +} +func SetDefaults_Secret(obj *v1.Secret) { + if obj.Type == "" { + obj.Type = v1.SecretTypeOpaque + } +} +func SetDefaults_ProjectedVolumeSource(obj *v1.ProjectedVolumeSource) { + if obj.DefaultMode == nil { + perm := int32(v1.ProjectedVolumeSourceDefaultMode) + obj.DefaultMode = &perm + } +} +func SetDefaults_ServiceAccountTokenProjection(obj *v1.ServiceAccountTokenProjection) { + hour := int64(time.Hour.Seconds()) + if obj.ExpirationSeconds == nil { + obj.ExpirationSeconds = &hour + } +} +func SetDefaults_PersistentVolume(obj *v1.PersistentVolume) { + if obj.Status.Phase == "" { + obj.Status.Phase = v1.VolumePending + } + if obj.Spec.PersistentVolumeReclaimPolicy == "" { + obj.Spec.PersistentVolumeReclaimPolicy = v1.PersistentVolumeReclaimRetain + } + if obj.Spec.VolumeMode == nil { + obj.Spec.VolumeMode = new(v1.PersistentVolumeMode) + *obj.Spec.VolumeMode = v1.PersistentVolumeFilesystem + } +} +func SetDefaults_PersistentVolumeClaim(obj *v1.PersistentVolumeClaim) { + if obj.Status.Phase == "" { + obj.Status.Phase = v1.ClaimPending + } +} +func SetDefaults_PersistentVolumeClaimSpec(obj *v1.PersistentVolumeClaimSpec) { + if obj.VolumeMode == nil { + obj.VolumeMode = new(v1.PersistentVolumeMode) + *obj.VolumeMode = v1.PersistentVolumeFilesystem + } +} +func SetDefaults_ISCSIVolumeSource(obj *v1.ISCSIVolumeSource) { + if obj.ISCSIInterface == "" { + obj.ISCSIInterface = "default" + } +} +func SetDefaults_ISCSIPersistentVolumeSource(obj *v1.ISCSIPersistentVolumeSource) { + if obj.ISCSIInterface == "" { + obj.ISCSIInterface = "default" + } +} +func SetDefaults_AzureDiskVolumeSource(obj *v1.AzureDiskVolumeSource) { + if obj.CachingMode == nil { + obj.CachingMode = new(v1.AzureDataDiskCachingMode) + *obj.CachingMode = v1.AzureDataDiskCachingReadWrite + } + if obj.Kind == nil { + obj.Kind = new(v1.AzureDataDiskKind) + *obj.Kind = v1.AzureSharedBlobDisk + } + if obj.FSType == nil { + obj.FSType = new(string) + *obj.FSType = "ext4" + } + if obj.ReadOnly == nil { + obj.ReadOnly = new(bool) + *obj.ReadOnly = false + } +} +func SetDefaults_Endpoints(obj *v1.Endpoints) { + for i := range obj.Subsets { + ss := &obj.Subsets[i] + for i := range ss.Ports { + ep := &ss.Ports[i] + if ep.Protocol == "" { + ep.Protocol = v1.ProtocolTCP + } + } + } +} +func SetDefaults_HTTPGetAction(obj *v1.HTTPGetAction) { + if obj.Path == "" { + obj.Path = "/" + } + if obj.Scheme == "" { + obj.Scheme = v1.URISchemeHTTP + } +} + +// SetDefaults_Namespace adds a default label for all namespaces +func SetDefaults_Namespace(obj *v1.Namespace) { + // we can't SetDefaults for nameless namespaces (generateName). + // This code needs to be kept in sync with the implementation that exists + // in Namespace Canonicalize strategy (pkg/registry/core/namespace) + + // note that this can result in many calls to feature enablement in some cases, but + // we assume that there's no real cost there. + if len(obj.Name) > 0 { + if obj.Labels == nil { + obj.Labels = map[string]string{} + } + obj.Labels[v1.LabelMetadataName] = obj.Name + } +} + +func SetDefaults_NamespaceStatus(obj *v1.NamespaceStatus) { + if obj.Phase == "" { + obj.Phase = v1.NamespaceActive + } +} +func SetDefaults_NodeStatus(obj *v1.NodeStatus) { + if obj.Allocatable == nil && obj.Capacity != nil { + obj.Allocatable = make(v1.ResourceList, len(obj.Capacity)) + for key, value := range obj.Capacity { + obj.Allocatable[key] = value.DeepCopy() + } + obj.Allocatable = obj.Capacity + } +} +func SetDefaults_ObjectFieldSelector(obj *v1.ObjectFieldSelector) { + if obj.APIVersion == "" { + obj.APIVersion = "v1" + } +} +func SetDefaults_LimitRangeItem(obj *v1.LimitRangeItem) { + // for container limits, we apply default values + if obj.Type == v1.LimitTypeContainer { + + if obj.Default == nil { + obj.Default = make(v1.ResourceList) + } + if obj.DefaultRequest == nil { + obj.DefaultRequest = make(v1.ResourceList) + } + + // If a default limit is unspecified, but the max is specified, default the limit to the max + for key, value := range obj.Max { + if _, exists := obj.Default[key]; !exists { + obj.Default[key] = value.DeepCopy() + } + } + // If a default limit is specified, but the default request is not, default request to limit + for key, value := range obj.Default { + if _, exists := obj.DefaultRequest[key]; !exists { + obj.DefaultRequest[key] = value.DeepCopy() + } + } + // If a default request is not specified, but the min is provided, default request to the min + for key, value := range obj.Min { + if _, exists := obj.DefaultRequest[key]; !exists { + obj.DefaultRequest[key] = value.DeepCopy() + } + } + } +} +func SetDefaults_ConfigMap(obj *v1.ConfigMap) { + if obj.Data == nil { + obj.Data = make(map[string]string) + } +} + +// With host networking default all container ports to host ports. +func defaultHostNetworkPorts(containers *[]v1.Container) { + for i := range *containers { + for j := range (*containers)[i].Ports { + if (*containers)[i].Ports[j].HostPort == 0 { + (*containers)[i].Ports[j].HostPort = (*containers)[i].Ports[j].ContainerPort + } + } + } +} + +func SetDefaults_RBDVolumeSource(obj *v1.RBDVolumeSource) { + if obj.RBDPool == "" { + obj.RBDPool = "rbd" + } + if obj.RadosUser == "" { + obj.RadosUser = "admin" + } + if obj.Keyring == "" { + obj.Keyring = "/etc/ceph/keyring" + } +} + +func SetDefaults_RBDPersistentVolumeSource(obj *v1.RBDPersistentVolumeSource) { + if obj.RBDPool == "" { + obj.RBDPool = "rbd" + } + if obj.RadosUser == "" { + obj.RadosUser = "admin" + } + if obj.Keyring == "" { + obj.Keyring = "/etc/ceph/keyring" + } +} + +func SetDefaults_ScaleIOVolumeSource(obj *v1.ScaleIOVolumeSource) { + if obj.StorageMode == "" { + obj.StorageMode = "ThinProvisioned" + } + if obj.FSType == "" { + obj.FSType = "xfs" + } +} + +func SetDefaults_ScaleIOPersistentVolumeSource(obj *v1.ScaleIOPersistentVolumeSource) { + if obj.StorageMode == "" { + obj.StorageMode = "ThinProvisioned" + } + if obj.FSType == "" { + obj.FSType = "xfs" + } +} + +func SetDefaults_HostPathVolumeSource(obj *v1.HostPathVolumeSource) { + typeVol := v1.HostPathUnset + if obj.Type == nil { + obj.Type = &typeVol + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/v1/doc.go b/vendor/k8s.io/kubernetes/pkg/apis/core/v1/doc.go new file mode 100644 index 000000000..2dc9f4c50 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/v1/doc.go @@ -0,0 +1,23 @@ +/* +Copyright 2015 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. +*/ + +// +k8s:conversion-gen=k8s.io/kubernetes/pkg/apis/core +// +k8s:conversion-gen-external-types=k8s.io/api/core/v1 +// +k8s:defaulter-gen=TypeMeta +// +k8s:defaulter-gen-input=k8s.io/api/core/v1 + +// Package v1 is the v1 version of the API. +package v1 // import "k8s.io/kubernetes/pkg/apis/core/v1" diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/v1/helper/helpers.go b/vendor/k8s.io/kubernetes/pkg/apis/core/v1/helper/helpers.go new file mode 100644 index 000000000..be33b1f94 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/v1/helper/helpers.go @@ -0,0 +1,431 @@ +/* +Copyright 2014 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 helper + +import ( + "fmt" + "strings" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/selection" + "k8s.io/apimachinery/pkg/util/validation" + "k8s.io/kubernetes/pkg/apis/core/helper" +) + +// IsExtendedResourceName returns true if: +// 1. the resource name is not in the default namespace; +// 2. resource name does not have "requests." prefix, +// to avoid confusion with the convention in quota +// 3. it satisfies the rules in IsQualifiedName() after converted into quota resource name +func IsExtendedResourceName(name v1.ResourceName) bool { + if IsNativeResource(name) || strings.HasPrefix(string(name), v1.DefaultResourceRequestsPrefix) { + return false + } + // Ensure it satisfies the rules in IsQualifiedName() after converted into quota resource name + nameForQuota := fmt.Sprintf("%s%s", v1.DefaultResourceRequestsPrefix, string(name)) + if errs := validation.IsQualifiedName(nameForQuota); len(errs) != 0 { + return false + } + return true +} + +// IsPrefixedNativeResource returns true if the resource name is in the +// *kubernetes.io/ namespace. +func IsPrefixedNativeResource(name v1.ResourceName) bool { + return strings.Contains(string(name), v1.ResourceDefaultNamespacePrefix) +} + +// IsNativeResource returns true if the resource name is in the +// *kubernetes.io/ namespace. Partially-qualified (unprefixed) names are +// implicitly in the kubernetes.io/ namespace. +func IsNativeResource(name v1.ResourceName) bool { + return !strings.Contains(string(name), "/") || + IsPrefixedNativeResource(name) +} + +// IsHugePageResourceName returns true if the resource name has the huge page +// resource prefix. +func IsHugePageResourceName(name v1.ResourceName) bool { + return strings.HasPrefix(string(name), v1.ResourceHugePagesPrefix) +} + +// HugePageResourceName returns a ResourceName with the canonical hugepage +// prefix prepended for the specified page size. The page size is converted +// to its canonical representation. +func HugePageResourceName(pageSize resource.Quantity) v1.ResourceName { + return v1.ResourceName(fmt.Sprintf("%s%s", v1.ResourceHugePagesPrefix, pageSize.String())) +} + +// HugePageSizeFromResourceName returns the page size for the specified huge page +// resource name. If the specified input is not a valid huge page resource name +// an error is returned. +func HugePageSizeFromResourceName(name v1.ResourceName) (resource.Quantity, error) { + if !IsHugePageResourceName(name) { + return resource.Quantity{}, fmt.Errorf("resource name: %s is an invalid hugepage name", name) + } + pageSize := strings.TrimPrefix(string(name), v1.ResourceHugePagesPrefix) + return resource.ParseQuantity(pageSize) +} + +// HugePageUnitSizeFromByteSize returns hugepage size has the format. +// `size` must be guaranteed to divisible into the largest units that can be expressed. +// B (1024 = "1KB", 1048576 = "1MB", etc). +func HugePageUnitSizeFromByteSize(size int64) (string, error) { + // hugePageSizeUnitList is borrowed from opencontainers/runc/libcontainer/cgroups/utils.go + var hugePageSizeUnitList = []string{"B", "KB", "MB", "GB", "TB", "PB"} + idx := 0 + len := len(hugePageSizeUnitList) - 1 + for size%1024 == 0 && idx < len { + size /= 1024 + idx++ + } + if size > 1024 && idx < len { + return "", fmt.Errorf("size: %d%s must be guaranteed to divisible into the largest units", size, hugePageSizeUnitList[idx]) + } + return fmt.Sprintf("%d%s", size, hugePageSizeUnitList[idx]), nil +} + +// IsHugePageMedium returns true if the volume medium is in 'HugePages[-size]' format +func IsHugePageMedium(medium v1.StorageMedium) bool { + if medium == v1.StorageMediumHugePages { + return true + } + return strings.HasPrefix(string(medium), string(v1.StorageMediumHugePagesPrefix)) +} + +// HugePageSizeFromMedium returns the page size for the specified huge page medium. +// If the specified input is not a valid huge page medium an error is returned. +func HugePageSizeFromMedium(medium v1.StorageMedium) (resource.Quantity, error) { + if !IsHugePageMedium(medium) { + return resource.Quantity{}, fmt.Errorf("medium: %s is not a hugepage medium", medium) + } + if medium == v1.StorageMediumHugePages { + return resource.Quantity{}, fmt.Errorf("medium: %s doesn't have size information", medium) + } + pageSize := strings.TrimPrefix(string(medium), string(v1.StorageMediumHugePagesPrefix)) + return resource.ParseQuantity(pageSize) +} + +// IsOvercommitAllowed returns true if the resource is in the default +// namespace and is not hugepages. +func IsOvercommitAllowed(name v1.ResourceName) bool { + return IsNativeResource(name) && + !IsHugePageResourceName(name) +} + +// IsAttachableVolumeResourceName returns true when the resource name is prefixed in attachable volume +func IsAttachableVolumeResourceName(name v1.ResourceName) bool { + return strings.HasPrefix(string(name), v1.ResourceAttachableVolumesPrefix) +} + +// IsServiceIPSet aims to check if the service's ClusterIP is set or not +// the objective is not to perform validation here +func IsServiceIPSet(service *v1.Service) bool { + return service.Spec.ClusterIP != v1.ClusterIPNone && service.Spec.ClusterIP != "" +} + +// LoadBalancerStatusEqual evaluates the given load balancers' ingress IP addresses +// and hostnames and returns true if equal or false if otherwise +// TODO: make method on LoadBalancerStatus? +func LoadBalancerStatusEqual(l, r *v1.LoadBalancerStatus) bool { + return ingressSliceEqual(l.Ingress, r.Ingress) +} + +func ingressSliceEqual(lhs, rhs []v1.LoadBalancerIngress) bool { + if len(lhs) != len(rhs) { + return false + } + for i := range lhs { + if !ingressEqual(&lhs[i], &rhs[i]) { + return false + } + } + return true +} + +func ingressEqual(lhs, rhs *v1.LoadBalancerIngress) bool { + if lhs.IP != rhs.IP { + return false + } + if lhs.Hostname != rhs.Hostname { + return false + } + return true +} + +// GetAccessModesAsString returns a string representation of an array of access modes. +// modes, when present, are always in the same order: RWO,ROX,RWX,RWOP. +func GetAccessModesAsString(modes []v1.PersistentVolumeAccessMode) string { + modes = removeDuplicateAccessModes(modes) + modesStr := []string{} + if ContainsAccessMode(modes, v1.ReadWriteOnce) { + modesStr = append(modesStr, "RWO") + } + if ContainsAccessMode(modes, v1.ReadOnlyMany) { + modesStr = append(modesStr, "ROX") + } + if ContainsAccessMode(modes, v1.ReadWriteMany) { + modesStr = append(modesStr, "RWX") + } + if ContainsAccessMode(modes, v1.ReadWriteOncePod) { + modesStr = append(modesStr, "RWOP") + } + return strings.Join(modesStr, ",") +} + +// GetAccessModesFromString returns an array of AccessModes from a string created by GetAccessModesAsString +func GetAccessModesFromString(modes string) []v1.PersistentVolumeAccessMode { + strmodes := strings.Split(modes, ",") + accessModes := []v1.PersistentVolumeAccessMode{} + for _, s := range strmodes { + s = strings.Trim(s, " ") + switch { + case s == "RWO": + accessModes = append(accessModes, v1.ReadWriteOnce) + case s == "ROX": + accessModes = append(accessModes, v1.ReadOnlyMany) + case s == "RWX": + accessModes = append(accessModes, v1.ReadWriteMany) + case s == "RWOP": + accessModes = append(accessModes, v1.ReadWriteOncePod) + } + } + return accessModes +} + +// removeDuplicateAccessModes returns an array of access modes without any duplicates +func removeDuplicateAccessModes(modes []v1.PersistentVolumeAccessMode) []v1.PersistentVolumeAccessMode { + accessModes := []v1.PersistentVolumeAccessMode{} + for _, m := range modes { + if !ContainsAccessMode(accessModes, m) { + accessModes = append(accessModes, m) + } + } + return accessModes +} + +func ContainsAccessMode(modes []v1.PersistentVolumeAccessMode, mode v1.PersistentVolumeAccessMode) bool { + for _, m := range modes { + if m == mode { + return true + } + } + return false +} + +// NodeSelectorRequirementKeysExistInNodeSelectorTerms checks if a NodeSelectorTerm with key is already specified in terms +func NodeSelectorRequirementKeysExistInNodeSelectorTerms(reqs []v1.NodeSelectorRequirement, terms []v1.NodeSelectorTerm) bool { + for _, req := range reqs { + for _, term := range terms { + for _, r := range term.MatchExpressions { + if r.Key == req.Key { + return true + } + } + } + } + return false +} + +// TopologySelectorRequirementsAsSelector converts the []TopologySelectorLabelRequirement api type into a struct +// that implements labels.Selector. +func TopologySelectorRequirementsAsSelector(tsm []v1.TopologySelectorLabelRequirement) (labels.Selector, error) { + if len(tsm) == 0 { + return labels.Nothing(), nil + } + + selector := labels.NewSelector() + for _, expr := range tsm { + r, err := labels.NewRequirement(expr.Key, selection.In, expr.Values) + if err != nil { + return nil, err + } + selector = selector.Add(*r) + } + + return selector, nil +} + +// MatchTopologySelectorTerms checks whether given labels match topology selector terms in ORed; +// nil or empty term matches no objects; while empty term list matches all objects. +func MatchTopologySelectorTerms(topologySelectorTerms []v1.TopologySelectorTerm, lbls labels.Set) bool { + if len(topologySelectorTerms) == 0 { + // empty term list matches all objects + return true + } + + for _, req := range topologySelectorTerms { + // nil or empty term selects no objects + if len(req.MatchLabelExpressions) == 0 { + continue + } + + labelSelector, err := TopologySelectorRequirementsAsSelector(req.MatchLabelExpressions) + if err != nil || !labelSelector.Matches(lbls) { + continue + } + + return true + } + + return false +} + +// AddOrUpdateTolerationInPodSpec tries to add a toleration to the toleration list in PodSpec. +// Returns true if something was updated, false otherwise. +func AddOrUpdateTolerationInPodSpec(spec *v1.PodSpec, toleration *v1.Toleration) bool { + podTolerations := spec.Tolerations + + var newTolerations []v1.Toleration + updated := false + for i := range podTolerations { + if toleration.MatchToleration(&podTolerations[i]) { + if helper.Semantic.DeepEqual(toleration, podTolerations[i]) { + return false + } + newTolerations = append(newTolerations, *toleration) + updated = true + continue + } + + newTolerations = append(newTolerations, podTolerations[i]) + } + + if !updated { + newTolerations = append(newTolerations, *toleration) + } + + spec.Tolerations = newTolerations + return true +} + +// AddOrUpdateTolerationInPod tries to add a toleration to the pod's toleration list. +// Returns true if something was updated, false otherwise. +func AddOrUpdateTolerationInPod(pod *v1.Pod, toleration *v1.Toleration) bool { + return AddOrUpdateTolerationInPodSpec(&pod.Spec, toleration) +} + +// GetMatchingTolerations returns true and list of Tolerations matching all Taints if all are tolerated, or false otherwise. +func GetMatchingTolerations(taints []v1.Taint, tolerations []v1.Toleration) (bool, []v1.Toleration) { + if len(taints) == 0 { + return true, []v1.Toleration{} + } + if len(tolerations) == 0 && len(taints) > 0 { + return false, []v1.Toleration{} + } + result := []v1.Toleration{} + for i := range taints { + tolerated := false + for j := range tolerations { + if tolerations[j].ToleratesTaint(&taints[i]) { + result = append(result, tolerations[j]) + tolerated = true + break + } + } + if !tolerated { + return false, []v1.Toleration{} + } + } + return true, result +} + +// ScopedResourceSelectorRequirementsAsSelector converts the ScopedResourceSelectorRequirement api type into a struct that implements +// labels.Selector. +func ScopedResourceSelectorRequirementsAsSelector(ssr v1.ScopedResourceSelectorRequirement) (labels.Selector, error) { + selector := labels.NewSelector() + var op selection.Operator + switch ssr.Operator { + case v1.ScopeSelectorOpIn: + op = selection.In + case v1.ScopeSelectorOpNotIn: + op = selection.NotIn + case v1.ScopeSelectorOpExists: + op = selection.Exists + case v1.ScopeSelectorOpDoesNotExist: + op = selection.DoesNotExist + default: + return nil, fmt.Errorf("%q is not a valid scope selector operator", ssr.Operator) + } + r, err := labels.NewRequirement(string(ssr.ScopeName), op, ssr.Values) + if err != nil { + return nil, err + } + selector = selector.Add(*r) + return selector, nil +} + +// nodeSelectorRequirementsAsLabelRequirements converts the NodeSelectorRequirement +// type to a labels.Requirement type. +func nodeSelectorRequirementsAsLabelRequirements(nsr v1.NodeSelectorRequirement) (*labels.Requirement, error) { + var op selection.Operator + switch nsr.Operator { + case v1.NodeSelectorOpIn: + op = selection.In + case v1.NodeSelectorOpNotIn: + op = selection.NotIn + case v1.NodeSelectorOpExists: + op = selection.Exists + case v1.NodeSelectorOpDoesNotExist: + op = selection.DoesNotExist + case v1.NodeSelectorOpGt: + op = selection.GreaterThan + case v1.NodeSelectorOpLt: + op = selection.LessThan + default: + return nil, fmt.Errorf("%q is not a valid node selector operator", nsr.Operator) + } + return labels.NewRequirement(nsr.Key, op, nsr.Values) +} + +// NodeSelectorAsSelector converts the NodeSelector api type into a struct that +// implements labels.Selector +// Note: This function should be kept in sync with the selector methods in +// pkg/labels/selector.go +func NodeSelectorAsSelector(ns *v1.NodeSelector) (labels.Selector, error) { + if ns == nil { + return labels.Nothing(), nil + } + if len(ns.NodeSelectorTerms) == 0 { + return labels.Everything(), nil + } + var requirements []labels.Requirement + + for _, nsTerm := range ns.NodeSelectorTerms { + for _, expr := range nsTerm.MatchExpressions { + req, err := nodeSelectorRequirementsAsLabelRequirements(expr) + if err != nil { + return nil, err + } + requirements = append(requirements, *req) + } + + for _, field := range nsTerm.MatchFields { + req, err := nodeSelectorRequirementsAsLabelRequirements(field) + if err != nil { + return nil, err + } + requirements = append(requirements, *req) + } + } + + selector := labels.NewSelector() + selector = selector.Add(requirements...) + return selector, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/v1/register.go b/vendor/k8s.io/kubernetes/pkg/apis/core/v1/register.go new file mode 100644 index 000000000..adf620fa4 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/v1/register.go @@ -0,0 +1,46 @@ +/* +Copyright 2017 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 v1 + +import ( + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var ( + localSchemeBuilder = &v1.SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addDefaultingFuncs, addConversionFuncs) +} + +// TODO: remove these global variables +// GroupName is the group name use in this package +const GroupName = "" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/v1/zz_generated.conversion.go b/vendor/k8s.io/kubernetes/pkg/apis/core/v1/zz_generated.conversion.go new file mode 100644 index 000000000..c27a86783 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/v1/zz_generated.conversion.go @@ -0,0 +1,8522 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by conversion-gen. DO NOT EDIT. + +package v1 + +import ( + url "net/url" + unsafe "unsafe" + + v1 "k8s.io/api/core/v1" + resource "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + types "k8s.io/apimachinery/pkg/types" + apps "k8s.io/kubernetes/pkg/apis/apps" + core "k8s.io/kubernetes/pkg/apis/core" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*v1.AWSElasticBlockStoreVolumeSource)(nil), (*core.AWSElasticBlockStoreVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_AWSElasticBlockStoreVolumeSource_To_core_AWSElasticBlockStoreVolumeSource(a.(*v1.AWSElasticBlockStoreVolumeSource), b.(*core.AWSElasticBlockStoreVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.AWSElasticBlockStoreVolumeSource)(nil), (*v1.AWSElasticBlockStoreVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_AWSElasticBlockStoreVolumeSource_To_v1_AWSElasticBlockStoreVolumeSource(a.(*core.AWSElasticBlockStoreVolumeSource), b.(*v1.AWSElasticBlockStoreVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.Affinity)(nil), (*core.Affinity)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Affinity_To_core_Affinity(a.(*v1.Affinity), b.(*core.Affinity), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.Affinity)(nil), (*v1.Affinity)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_Affinity_To_v1_Affinity(a.(*core.Affinity), b.(*v1.Affinity), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.AttachedVolume)(nil), (*core.AttachedVolume)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_AttachedVolume_To_core_AttachedVolume(a.(*v1.AttachedVolume), b.(*core.AttachedVolume), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.AttachedVolume)(nil), (*v1.AttachedVolume)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_AttachedVolume_To_v1_AttachedVolume(a.(*core.AttachedVolume), b.(*v1.AttachedVolume), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.AvoidPods)(nil), (*core.AvoidPods)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_AvoidPods_To_core_AvoidPods(a.(*v1.AvoidPods), b.(*core.AvoidPods), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.AvoidPods)(nil), (*v1.AvoidPods)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_AvoidPods_To_v1_AvoidPods(a.(*core.AvoidPods), b.(*v1.AvoidPods), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.AzureDiskVolumeSource)(nil), (*core.AzureDiskVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_AzureDiskVolumeSource_To_core_AzureDiskVolumeSource(a.(*v1.AzureDiskVolumeSource), b.(*core.AzureDiskVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.AzureDiskVolumeSource)(nil), (*v1.AzureDiskVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_AzureDiskVolumeSource_To_v1_AzureDiskVolumeSource(a.(*core.AzureDiskVolumeSource), b.(*v1.AzureDiskVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.AzureFilePersistentVolumeSource)(nil), (*core.AzureFilePersistentVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_AzureFilePersistentVolumeSource_To_core_AzureFilePersistentVolumeSource(a.(*v1.AzureFilePersistentVolumeSource), b.(*core.AzureFilePersistentVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.AzureFilePersistentVolumeSource)(nil), (*v1.AzureFilePersistentVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_AzureFilePersistentVolumeSource_To_v1_AzureFilePersistentVolumeSource(a.(*core.AzureFilePersistentVolumeSource), b.(*v1.AzureFilePersistentVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.AzureFileVolumeSource)(nil), (*core.AzureFileVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_AzureFileVolumeSource_To_core_AzureFileVolumeSource(a.(*v1.AzureFileVolumeSource), b.(*core.AzureFileVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.AzureFileVolumeSource)(nil), (*v1.AzureFileVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_AzureFileVolumeSource_To_v1_AzureFileVolumeSource(a.(*core.AzureFileVolumeSource), b.(*v1.AzureFileVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.Binding)(nil), (*core.Binding)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Binding_To_core_Binding(a.(*v1.Binding), b.(*core.Binding), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.Binding)(nil), (*v1.Binding)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_Binding_To_v1_Binding(a.(*core.Binding), b.(*v1.Binding), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.CSIPersistentVolumeSource)(nil), (*core.CSIPersistentVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_CSIPersistentVolumeSource_To_core_CSIPersistentVolumeSource(a.(*v1.CSIPersistentVolumeSource), b.(*core.CSIPersistentVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.CSIPersistentVolumeSource)(nil), (*v1.CSIPersistentVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_CSIPersistentVolumeSource_To_v1_CSIPersistentVolumeSource(a.(*core.CSIPersistentVolumeSource), b.(*v1.CSIPersistentVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.CSIVolumeSource)(nil), (*core.CSIVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_CSIVolumeSource_To_core_CSIVolumeSource(a.(*v1.CSIVolumeSource), b.(*core.CSIVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.CSIVolumeSource)(nil), (*v1.CSIVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_CSIVolumeSource_To_v1_CSIVolumeSource(a.(*core.CSIVolumeSource), b.(*v1.CSIVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.Capabilities)(nil), (*core.Capabilities)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Capabilities_To_core_Capabilities(a.(*v1.Capabilities), b.(*core.Capabilities), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.Capabilities)(nil), (*v1.Capabilities)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_Capabilities_To_v1_Capabilities(a.(*core.Capabilities), b.(*v1.Capabilities), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.CephFSPersistentVolumeSource)(nil), (*core.CephFSPersistentVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_CephFSPersistentVolumeSource_To_core_CephFSPersistentVolumeSource(a.(*v1.CephFSPersistentVolumeSource), b.(*core.CephFSPersistentVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.CephFSPersistentVolumeSource)(nil), (*v1.CephFSPersistentVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_CephFSPersistentVolumeSource_To_v1_CephFSPersistentVolumeSource(a.(*core.CephFSPersistentVolumeSource), b.(*v1.CephFSPersistentVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.CephFSVolumeSource)(nil), (*core.CephFSVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_CephFSVolumeSource_To_core_CephFSVolumeSource(a.(*v1.CephFSVolumeSource), b.(*core.CephFSVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.CephFSVolumeSource)(nil), (*v1.CephFSVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_CephFSVolumeSource_To_v1_CephFSVolumeSource(a.(*core.CephFSVolumeSource), b.(*v1.CephFSVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.CinderPersistentVolumeSource)(nil), (*core.CinderPersistentVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_CinderPersistentVolumeSource_To_core_CinderPersistentVolumeSource(a.(*v1.CinderPersistentVolumeSource), b.(*core.CinderPersistentVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.CinderPersistentVolumeSource)(nil), (*v1.CinderPersistentVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_CinderPersistentVolumeSource_To_v1_CinderPersistentVolumeSource(a.(*core.CinderPersistentVolumeSource), b.(*v1.CinderPersistentVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.CinderVolumeSource)(nil), (*core.CinderVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_CinderVolumeSource_To_core_CinderVolumeSource(a.(*v1.CinderVolumeSource), b.(*core.CinderVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.CinderVolumeSource)(nil), (*v1.CinderVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_CinderVolumeSource_To_v1_CinderVolumeSource(a.(*core.CinderVolumeSource), b.(*v1.CinderVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ClaimSource)(nil), (*core.ClaimSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ClaimSource_To_core_ClaimSource(a.(*v1.ClaimSource), b.(*core.ClaimSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ClaimSource)(nil), (*v1.ClaimSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ClaimSource_To_v1_ClaimSource(a.(*core.ClaimSource), b.(*v1.ClaimSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ClientIPConfig)(nil), (*core.ClientIPConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ClientIPConfig_To_core_ClientIPConfig(a.(*v1.ClientIPConfig), b.(*core.ClientIPConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ClientIPConfig)(nil), (*v1.ClientIPConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ClientIPConfig_To_v1_ClientIPConfig(a.(*core.ClientIPConfig), b.(*v1.ClientIPConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ComponentCondition)(nil), (*core.ComponentCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ComponentCondition_To_core_ComponentCondition(a.(*v1.ComponentCondition), b.(*core.ComponentCondition), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ComponentCondition)(nil), (*v1.ComponentCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ComponentCondition_To_v1_ComponentCondition(a.(*core.ComponentCondition), b.(*v1.ComponentCondition), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ComponentStatus)(nil), (*core.ComponentStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ComponentStatus_To_core_ComponentStatus(a.(*v1.ComponentStatus), b.(*core.ComponentStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ComponentStatus)(nil), (*v1.ComponentStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ComponentStatus_To_v1_ComponentStatus(a.(*core.ComponentStatus), b.(*v1.ComponentStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ComponentStatusList)(nil), (*core.ComponentStatusList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ComponentStatusList_To_core_ComponentStatusList(a.(*v1.ComponentStatusList), b.(*core.ComponentStatusList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ComponentStatusList)(nil), (*v1.ComponentStatusList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ComponentStatusList_To_v1_ComponentStatusList(a.(*core.ComponentStatusList), b.(*v1.ComponentStatusList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ConfigMap)(nil), (*core.ConfigMap)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ConfigMap_To_core_ConfigMap(a.(*v1.ConfigMap), b.(*core.ConfigMap), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ConfigMap)(nil), (*v1.ConfigMap)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ConfigMap_To_v1_ConfigMap(a.(*core.ConfigMap), b.(*v1.ConfigMap), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ConfigMapEnvSource)(nil), (*core.ConfigMapEnvSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ConfigMapEnvSource_To_core_ConfigMapEnvSource(a.(*v1.ConfigMapEnvSource), b.(*core.ConfigMapEnvSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ConfigMapEnvSource)(nil), (*v1.ConfigMapEnvSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ConfigMapEnvSource_To_v1_ConfigMapEnvSource(a.(*core.ConfigMapEnvSource), b.(*v1.ConfigMapEnvSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ConfigMapKeySelector)(nil), (*core.ConfigMapKeySelector)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ConfigMapKeySelector_To_core_ConfigMapKeySelector(a.(*v1.ConfigMapKeySelector), b.(*core.ConfigMapKeySelector), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ConfigMapKeySelector)(nil), (*v1.ConfigMapKeySelector)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ConfigMapKeySelector_To_v1_ConfigMapKeySelector(a.(*core.ConfigMapKeySelector), b.(*v1.ConfigMapKeySelector), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ConfigMapList)(nil), (*core.ConfigMapList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ConfigMapList_To_core_ConfigMapList(a.(*v1.ConfigMapList), b.(*core.ConfigMapList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ConfigMapList)(nil), (*v1.ConfigMapList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ConfigMapList_To_v1_ConfigMapList(a.(*core.ConfigMapList), b.(*v1.ConfigMapList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ConfigMapNodeConfigSource)(nil), (*core.ConfigMapNodeConfigSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ConfigMapNodeConfigSource_To_core_ConfigMapNodeConfigSource(a.(*v1.ConfigMapNodeConfigSource), b.(*core.ConfigMapNodeConfigSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ConfigMapNodeConfigSource)(nil), (*v1.ConfigMapNodeConfigSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ConfigMapNodeConfigSource_To_v1_ConfigMapNodeConfigSource(a.(*core.ConfigMapNodeConfigSource), b.(*v1.ConfigMapNodeConfigSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ConfigMapProjection)(nil), (*core.ConfigMapProjection)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ConfigMapProjection_To_core_ConfigMapProjection(a.(*v1.ConfigMapProjection), b.(*core.ConfigMapProjection), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ConfigMapProjection)(nil), (*v1.ConfigMapProjection)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ConfigMapProjection_To_v1_ConfigMapProjection(a.(*core.ConfigMapProjection), b.(*v1.ConfigMapProjection), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ConfigMapVolumeSource)(nil), (*core.ConfigMapVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ConfigMapVolumeSource_To_core_ConfigMapVolumeSource(a.(*v1.ConfigMapVolumeSource), b.(*core.ConfigMapVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ConfigMapVolumeSource)(nil), (*v1.ConfigMapVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ConfigMapVolumeSource_To_v1_ConfigMapVolumeSource(a.(*core.ConfigMapVolumeSource), b.(*v1.ConfigMapVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.Container)(nil), (*core.Container)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Container_To_core_Container(a.(*v1.Container), b.(*core.Container), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.Container)(nil), (*v1.Container)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_Container_To_v1_Container(a.(*core.Container), b.(*v1.Container), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ContainerImage)(nil), (*core.ContainerImage)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ContainerImage_To_core_ContainerImage(a.(*v1.ContainerImage), b.(*core.ContainerImage), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ContainerImage)(nil), (*v1.ContainerImage)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ContainerImage_To_v1_ContainerImage(a.(*core.ContainerImage), b.(*v1.ContainerImage), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ContainerPort)(nil), (*core.ContainerPort)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ContainerPort_To_core_ContainerPort(a.(*v1.ContainerPort), b.(*core.ContainerPort), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ContainerPort)(nil), (*v1.ContainerPort)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ContainerPort_To_v1_ContainerPort(a.(*core.ContainerPort), b.(*v1.ContainerPort), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ContainerState)(nil), (*core.ContainerState)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ContainerState_To_core_ContainerState(a.(*v1.ContainerState), b.(*core.ContainerState), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ContainerState)(nil), (*v1.ContainerState)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ContainerState_To_v1_ContainerState(a.(*core.ContainerState), b.(*v1.ContainerState), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ContainerStateRunning)(nil), (*core.ContainerStateRunning)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ContainerStateRunning_To_core_ContainerStateRunning(a.(*v1.ContainerStateRunning), b.(*core.ContainerStateRunning), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ContainerStateRunning)(nil), (*v1.ContainerStateRunning)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ContainerStateRunning_To_v1_ContainerStateRunning(a.(*core.ContainerStateRunning), b.(*v1.ContainerStateRunning), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ContainerStateTerminated)(nil), (*core.ContainerStateTerminated)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ContainerStateTerminated_To_core_ContainerStateTerminated(a.(*v1.ContainerStateTerminated), b.(*core.ContainerStateTerminated), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ContainerStateTerminated)(nil), (*v1.ContainerStateTerminated)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ContainerStateTerminated_To_v1_ContainerStateTerminated(a.(*core.ContainerStateTerminated), b.(*v1.ContainerStateTerminated), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ContainerStateWaiting)(nil), (*core.ContainerStateWaiting)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ContainerStateWaiting_To_core_ContainerStateWaiting(a.(*v1.ContainerStateWaiting), b.(*core.ContainerStateWaiting), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ContainerStateWaiting)(nil), (*v1.ContainerStateWaiting)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ContainerStateWaiting_To_v1_ContainerStateWaiting(a.(*core.ContainerStateWaiting), b.(*v1.ContainerStateWaiting), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ContainerStatus)(nil), (*core.ContainerStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ContainerStatus_To_core_ContainerStatus(a.(*v1.ContainerStatus), b.(*core.ContainerStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ContainerStatus)(nil), (*v1.ContainerStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ContainerStatus_To_v1_ContainerStatus(a.(*core.ContainerStatus), b.(*v1.ContainerStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.DaemonEndpoint)(nil), (*core.DaemonEndpoint)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_DaemonEndpoint_To_core_DaemonEndpoint(a.(*v1.DaemonEndpoint), b.(*core.DaemonEndpoint), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.DaemonEndpoint)(nil), (*v1.DaemonEndpoint)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_DaemonEndpoint_To_v1_DaemonEndpoint(a.(*core.DaemonEndpoint), b.(*v1.DaemonEndpoint), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.DownwardAPIProjection)(nil), (*core.DownwardAPIProjection)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_DownwardAPIProjection_To_core_DownwardAPIProjection(a.(*v1.DownwardAPIProjection), b.(*core.DownwardAPIProjection), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.DownwardAPIProjection)(nil), (*v1.DownwardAPIProjection)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_DownwardAPIProjection_To_v1_DownwardAPIProjection(a.(*core.DownwardAPIProjection), b.(*v1.DownwardAPIProjection), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.DownwardAPIVolumeFile)(nil), (*core.DownwardAPIVolumeFile)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_DownwardAPIVolumeFile_To_core_DownwardAPIVolumeFile(a.(*v1.DownwardAPIVolumeFile), b.(*core.DownwardAPIVolumeFile), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.DownwardAPIVolumeFile)(nil), (*v1.DownwardAPIVolumeFile)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_DownwardAPIVolumeFile_To_v1_DownwardAPIVolumeFile(a.(*core.DownwardAPIVolumeFile), b.(*v1.DownwardAPIVolumeFile), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.DownwardAPIVolumeSource)(nil), (*core.DownwardAPIVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_DownwardAPIVolumeSource_To_core_DownwardAPIVolumeSource(a.(*v1.DownwardAPIVolumeSource), b.(*core.DownwardAPIVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.DownwardAPIVolumeSource)(nil), (*v1.DownwardAPIVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_DownwardAPIVolumeSource_To_v1_DownwardAPIVolumeSource(a.(*core.DownwardAPIVolumeSource), b.(*v1.DownwardAPIVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.EmptyDirVolumeSource)(nil), (*core.EmptyDirVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_EmptyDirVolumeSource_To_core_EmptyDirVolumeSource(a.(*v1.EmptyDirVolumeSource), b.(*core.EmptyDirVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.EmptyDirVolumeSource)(nil), (*v1.EmptyDirVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_EmptyDirVolumeSource_To_v1_EmptyDirVolumeSource(a.(*core.EmptyDirVolumeSource), b.(*v1.EmptyDirVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.EndpointAddress)(nil), (*core.EndpointAddress)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_EndpointAddress_To_core_EndpointAddress(a.(*v1.EndpointAddress), b.(*core.EndpointAddress), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.EndpointAddress)(nil), (*v1.EndpointAddress)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_EndpointAddress_To_v1_EndpointAddress(a.(*core.EndpointAddress), b.(*v1.EndpointAddress), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.EndpointPort)(nil), (*core.EndpointPort)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_EndpointPort_To_core_EndpointPort(a.(*v1.EndpointPort), b.(*core.EndpointPort), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.EndpointPort)(nil), (*v1.EndpointPort)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_EndpointPort_To_v1_EndpointPort(a.(*core.EndpointPort), b.(*v1.EndpointPort), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.EndpointSubset)(nil), (*core.EndpointSubset)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_EndpointSubset_To_core_EndpointSubset(a.(*v1.EndpointSubset), b.(*core.EndpointSubset), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.EndpointSubset)(nil), (*v1.EndpointSubset)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_EndpointSubset_To_v1_EndpointSubset(a.(*core.EndpointSubset), b.(*v1.EndpointSubset), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.Endpoints)(nil), (*core.Endpoints)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Endpoints_To_core_Endpoints(a.(*v1.Endpoints), b.(*core.Endpoints), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.Endpoints)(nil), (*v1.Endpoints)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_Endpoints_To_v1_Endpoints(a.(*core.Endpoints), b.(*v1.Endpoints), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.EndpointsList)(nil), (*core.EndpointsList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_EndpointsList_To_core_EndpointsList(a.(*v1.EndpointsList), b.(*core.EndpointsList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.EndpointsList)(nil), (*v1.EndpointsList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_EndpointsList_To_v1_EndpointsList(a.(*core.EndpointsList), b.(*v1.EndpointsList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.EnvFromSource)(nil), (*core.EnvFromSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_EnvFromSource_To_core_EnvFromSource(a.(*v1.EnvFromSource), b.(*core.EnvFromSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.EnvFromSource)(nil), (*v1.EnvFromSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_EnvFromSource_To_v1_EnvFromSource(a.(*core.EnvFromSource), b.(*v1.EnvFromSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.EnvVar)(nil), (*core.EnvVar)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_EnvVar_To_core_EnvVar(a.(*v1.EnvVar), b.(*core.EnvVar), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.EnvVar)(nil), (*v1.EnvVar)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_EnvVar_To_v1_EnvVar(a.(*core.EnvVar), b.(*v1.EnvVar), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.EnvVarSource)(nil), (*core.EnvVarSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_EnvVarSource_To_core_EnvVarSource(a.(*v1.EnvVarSource), b.(*core.EnvVarSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.EnvVarSource)(nil), (*v1.EnvVarSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_EnvVarSource_To_v1_EnvVarSource(a.(*core.EnvVarSource), b.(*v1.EnvVarSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.EphemeralContainer)(nil), (*core.EphemeralContainer)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_EphemeralContainer_To_core_EphemeralContainer(a.(*v1.EphemeralContainer), b.(*core.EphemeralContainer), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.EphemeralContainer)(nil), (*v1.EphemeralContainer)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_EphemeralContainer_To_v1_EphemeralContainer(a.(*core.EphemeralContainer), b.(*v1.EphemeralContainer), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.EphemeralContainerCommon)(nil), (*core.EphemeralContainerCommon)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_EphemeralContainerCommon_To_core_EphemeralContainerCommon(a.(*v1.EphemeralContainerCommon), b.(*core.EphemeralContainerCommon), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.EphemeralContainerCommon)(nil), (*v1.EphemeralContainerCommon)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_EphemeralContainerCommon_To_v1_EphemeralContainerCommon(a.(*core.EphemeralContainerCommon), b.(*v1.EphemeralContainerCommon), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.EphemeralVolumeSource)(nil), (*core.EphemeralVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_EphemeralVolumeSource_To_core_EphemeralVolumeSource(a.(*v1.EphemeralVolumeSource), b.(*core.EphemeralVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.EphemeralVolumeSource)(nil), (*v1.EphemeralVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_EphemeralVolumeSource_To_v1_EphemeralVolumeSource(a.(*core.EphemeralVolumeSource), b.(*v1.EphemeralVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.Event)(nil), (*core.Event)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Event_To_core_Event(a.(*v1.Event), b.(*core.Event), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.Event)(nil), (*v1.Event)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_Event_To_v1_Event(a.(*core.Event), b.(*v1.Event), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.EventList)(nil), (*core.EventList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_EventList_To_core_EventList(a.(*v1.EventList), b.(*core.EventList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.EventList)(nil), (*v1.EventList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_EventList_To_v1_EventList(a.(*core.EventList), b.(*v1.EventList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.EventSeries)(nil), (*core.EventSeries)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_EventSeries_To_core_EventSeries(a.(*v1.EventSeries), b.(*core.EventSeries), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.EventSeries)(nil), (*v1.EventSeries)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_EventSeries_To_v1_EventSeries(a.(*core.EventSeries), b.(*v1.EventSeries), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.EventSource)(nil), (*core.EventSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_EventSource_To_core_EventSource(a.(*v1.EventSource), b.(*core.EventSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.EventSource)(nil), (*v1.EventSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_EventSource_To_v1_EventSource(a.(*core.EventSource), b.(*v1.EventSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ExecAction)(nil), (*core.ExecAction)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ExecAction_To_core_ExecAction(a.(*v1.ExecAction), b.(*core.ExecAction), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ExecAction)(nil), (*v1.ExecAction)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ExecAction_To_v1_ExecAction(a.(*core.ExecAction), b.(*v1.ExecAction), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.FCVolumeSource)(nil), (*core.FCVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_FCVolumeSource_To_core_FCVolumeSource(a.(*v1.FCVolumeSource), b.(*core.FCVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.FCVolumeSource)(nil), (*v1.FCVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_FCVolumeSource_To_v1_FCVolumeSource(a.(*core.FCVolumeSource), b.(*v1.FCVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.FlexPersistentVolumeSource)(nil), (*core.FlexPersistentVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_FlexPersistentVolumeSource_To_core_FlexPersistentVolumeSource(a.(*v1.FlexPersistentVolumeSource), b.(*core.FlexPersistentVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.FlexPersistentVolumeSource)(nil), (*v1.FlexPersistentVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_FlexPersistentVolumeSource_To_v1_FlexPersistentVolumeSource(a.(*core.FlexPersistentVolumeSource), b.(*v1.FlexPersistentVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.FlexVolumeSource)(nil), (*core.FlexVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_FlexVolumeSource_To_core_FlexVolumeSource(a.(*v1.FlexVolumeSource), b.(*core.FlexVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.FlexVolumeSource)(nil), (*v1.FlexVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_FlexVolumeSource_To_v1_FlexVolumeSource(a.(*core.FlexVolumeSource), b.(*v1.FlexVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.FlockerVolumeSource)(nil), (*core.FlockerVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_FlockerVolumeSource_To_core_FlockerVolumeSource(a.(*v1.FlockerVolumeSource), b.(*core.FlockerVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.FlockerVolumeSource)(nil), (*v1.FlockerVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_FlockerVolumeSource_To_v1_FlockerVolumeSource(a.(*core.FlockerVolumeSource), b.(*v1.FlockerVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.GCEPersistentDiskVolumeSource)(nil), (*core.GCEPersistentDiskVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_GCEPersistentDiskVolumeSource_To_core_GCEPersistentDiskVolumeSource(a.(*v1.GCEPersistentDiskVolumeSource), b.(*core.GCEPersistentDiskVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.GCEPersistentDiskVolumeSource)(nil), (*v1.GCEPersistentDiskVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_GCEPersistentDiskVolumeSource_To_v1_GCEPersistentDiskVolumeSource(a.(*core.GCEPersistentDiskVolumeSource), b.(*v1.GCEPersistentDiskVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.GRPCAction)(nil), (*core.GRPCAction)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_GRPCAction_To_core_GRPCAction(a.(*v1.GRPCAction), b.(*core.GRPCAction), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.GRPCAction)(nil), (*v1.GRPCAction)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_GRPCAction_To_v1_GRPCAction(a.(*core.GRPCAction), b.(*v1.GRPCAction), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.GitRepoVolumeSource)(nil), (*core.GitRepoVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_GitRepoVolumeSource_To_core_GitRepoVolumeSource(a.(*v1.GitRepoVolumeSource), b.(*core.GitRepoVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.GitRepoVolumeSource)(nil), (*v1.GitRepoVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_GitRepoVolumeSource_To_v1_GitRepoVolumeSource(a.(*core.GitRepoVolumeSource), b.(*v1.GitRepoVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.GlusterfsPersistentVolumeSource)(nil), (*core.GlusterfsPersistentVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_GlusterfsPersistentVolumeSource_To_core_GlusterfsPersistentVolumeSource(a.(*v1.GlusterfsPersistentVolumeSource), b.(*core.GlusterfsPersistentVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.GlusterfsPersistentVolumeSource)(nil), (*v1.GlusterfsPersistentVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_GlusterfsPersistentVolumeSource_To_v1_GlusterfsPersistentVolumeSource(a.(*core.GlusterfsPersistentVolumeSource), b.(*v1.GlusterfsPersistentVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.GlusterfsVolumeSource)(nil), (*core.GlusterfsVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_GlusterfsVolumeSource_To_core_GlusterfsVolumeSource(a.(*v1.GlusterfsVolumeSource), b.(*core.GlusterfsVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.GlusterfsVolumeSource)(nil), (*v1.GlusterfsVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_GlusterfsVolumeSource_To_v1_GlusterfsVolumeSource(a.(*core.GlusterfsVolumeSource), b.(*v1.GlusterfsVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.HTTPGetAction)(nil), (*core.HTTPGetAction)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_HTTPGetAction_To_core_HTTPGetAction(a.(*v1.HTTPGetAction), b.(*core.HTTPGetAction), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.HTTPGetAction)(nil), (*v1.HTTPGetAction)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_HTTPGetAction_To_v1_HTTPGetAction(a.(*core.HTTPGetAction), b.(*v1.HTTPGetAction), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.HTTPHeader)(nil), (*core.HTTPHeader)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_HTTPHeader_To_core_HTTPHeader(a.(*v1.HTTPHeader), b.(*core.HTTPHeader), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.HTTPHeader)(nil), (*v1.HTTPHeader)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_HTTPHeader_To_v1_HTTPHeader(a.(*core.HTTPHeader), b.(*v1.HTTPHeader), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.HostAlias)(nil), (*core.HostAlias)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_HostAlias_To_core_HostAlias(a.(*v1.HostAlias), b.(*core.HostAlias), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.HostAlias)(nil), (*v1.HostAlias)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_HostAlias_To_v1_HostAlias(a.(*core.HostAlias), b.(*v1.HostAlias), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.HostPathVolumeSource)(nil), (*core.HostPathVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_HostPathVolumeSource_To_core_HostPathVolumeSource(a.(*v1.HostPathVolumeSource), b.(*core.HostPathVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.HostPathVolumeSource)(nil), (*v1.HostPathVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_HostPathVolumeSource_To_v1_HostPathVolumeSource(a.(*core.HostPathVolumeSource), b.(*v1.HostPathVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ISCSIPersistentVolumeSource)(nil), (*core.ISCSIPersistentVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ISCSIPersistentVolumeSource_To_core_ISCSIPersistentVolumeSource(a.(*v1.ISCSIPersistentVolumeSource), b.(*core.ISCSIPersistentVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ISCSIPersistentVolumeSource)(nil), (*v1.ISCSIPersistentVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ISCSIPersistentVolumeSource_To_v1_ISCSIPersistentVolumeSource(a.(*core.ISCSIPersistentVolumeSource), b.(*v1.ISCSIPersistentVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ISCSIVolumeSource)(nil), (*core.ISCSIVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ISCSIVolumeSource_To_core_ISCSIVolumeSource(a.(*v1.ISCSIVolumeSource), b.(*core.ISCSIVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ISCSIVolumeSource)(nil), (*v1.ISCSIVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ISCSIVolumeSource_To_v1_ISCSIVolumeSource(a.(*core.ISCSIVolumeSource), b.(*v1.ISCSIVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.KeyToPath)(nil), (*core.KeyToPath)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_KeyToPath_To_core_KeyToPath(a.(*v1.KeyToPath), b.(*core.KeyToPath), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.KeyToPath)(nil), (*v1.KeyToPath)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_KeyToPath_To_v1_KeyToPath(a.(*core.KeyToPath), b.(*v1.KeyToPath), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.Lifecycle)(nil), (*core.Lifecycle)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Lifecycle_To_core_Lifecycle(a.(*v1.Lifecycle), b.(*core.Lifecycle), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.Lifecycle)(nil), (*v1.Lifecycle)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_Lifecycle_To_v1_Lifecycle(a.(*core.Lifecycle), b.(*v1.Lifecycle), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.LifecycleHandler)(nil), (*core.LifecycleHandler)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_LifecycleHandler_To_core_LifecycleHandler(a.(*v1.LifecycleHandler), b.(*core.LifecycleHandler), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.LifecycleHandler)(nil), (*v1.LifecycleHandler)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_LifecycleHandler_To_v1_LifecycleHandler(a.(*core.LifecycleHandler), b.(*v1.LifecycleHandler), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.LimitRange)(nil), (*core.LimitRange)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_LimitRange_To_core_LimitRange(a.(*v1.LimitRange), b.(*core.LimitRange), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.LimitRange)(nil), (*v1.LimitRange)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_LimitRange_To_v1_LimitRange(a.(*core.LimitRange), b.(*v1.LimitRange), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.LimitRangeItem)(nil), (*core.LimitRangeItem)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_LimitRangeItem_To_core_LimitRangeItem(a.(*v1.LimitRangeItem), b.(*core.LimitRangeItem), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.LimitRangeItem)(nil), (*v1.LimitRangeItem)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_LimitRangeItem_To_v1_LimitRangeItem(a.(*core.LimitRangeItem), b.(*v1.LimitRangeItem), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.LimitRangeList)(nil), (*core.LimitRangeList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_LimitRangeList_To_core_LimitRangeList(a.(*v1.LimitRangeList), b.(*core.LimitRangeList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.LimitRangeList)(nil), (*v1.LimitRangeList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_LimitRangeList_To_v1_LimitRangeList(a.(*core.LimitRangeList), b.(*v1.LimitRangeList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.LimitRangeSpec)(nil), (*core.LimitRangeSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_LimitRangeSpec_To_core_LimitRangeSpec(a.(*v1.LimitRangeSpec), b.(*core.LimitRangeSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.LimitRangeSpec)(nil), (*v1.LimitRangeSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_LimitRangeSpec_To_v1_LimitRangeSpec(a.(*core.LimitRangeSpec), b.(*v1.LimitRangeSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.List)(nil), (*core.List)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_List_To_core_List(a.(*v1.List), b.(*core.List), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.List)(nil), (*v1.List)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_List_To_v1_List(a.(*core.List), b.(*v1.List), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.LoadBalancerIngress)(nil), (*core.LoadBalancerIngress)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_LoadBalancerIngress_To_core_LoadBalancerIngress(a.(*v1.LoadBalancerIngress), b.(*core.LoadBalancerIngress), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.LoadBalancerIngress)(nil), (*v1.LoadBalancerIngress)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_LoadBalancerIngress_To_v1_LoadBalancerIngress(a.(*core.LoadBalancerIngress), b.(*v1.LoadBalancerIngress), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.LocalObjectReference)(nil), (*core.LocalObjectReference)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_LocalObjectReference_To_core_LocalObjectReference(a.(*v1.LocalObjectReference), b.(*core.LocalObjectReference), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.LocalObjectReference)(nil), (*v1.LocalObjectReference)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_LocalObjectReference_To_v1_LocalObjectReference(a.(*core.LocalObjectReference), b.(*v1.LocalObjectReference), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.LocalVolumeSource)(nil), (*core.LocalVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_LocalVolumeSource_To_core_LocalVolumeSource(a.(*v1.LocalVolumeSource), b.(*core.LocalVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.LocalVolumeSource)(nil), (*v1.LocalVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_LocalVolumeSource_To_v1_LocalVolumeSource(a.(*core.LocalVolumeSource), b.(*v1.LocalVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NFSVolumeSource)(nil), (*core.NFSVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NFSVolumeSource_To_core_NFSVolumeSource(a.(*v1.NFSVolumeSource), b.(*core.NFSVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.NFSVolumeSource)(nil), (*v1.NFSVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_NFSVolumeSource_To_v1_NFSVolumeSource(a.(*core.NFSVolumeSource), b.(*v1.NFSVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.Namespace)(nil), (*core.Namespace)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Namespace_To_core_Namespace(a.(*v1.Namespace), b.(*core.Namespace), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.Namespace)(nil), (*v1.Namespace)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_Namespace_To_v1_Namespace(a.(*core.Namespace), b.(*v1.Namespace), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NamespaceCondition)(nil), (*core.NamespaceCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NamespaceCondition_To_core_NamespaceCondition(a.(*v1.NamespaceCondition), b.(*core.NamespaceCondition), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.NamespaceCondition)(nil), (*v1.NamespaceCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_NamespaceCondition_To_v1_NamespaceCondition(a.(*core.NamespaceCondition), b.(*v1.NamespaceCondition), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NamespaceList)(nil), (*core.NamespaceList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NamespaceList_To_core_NamespaceList(a.(*v1.NamespaceList), b.(*core.NamespaceList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.NamespaceList)(nil), (*v1.NamespaceList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_NamespaceList_To_v1_NamespaceList(a.(*core.NamespaceList), b.(*v1.NamespaceList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NamespaceSpec)(nil), (*core.NamespaceSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NamespaceSpec_To_core_NamespaceSpec(a.(*v1.NamespaceSpec), b.(*core.NamespaceSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.NamespaceSpec)(nil), (*v1.NamespaceSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_NamespaceSpec_To_v1_NamespaceSpec(a.(*core.NamespaceSpec), b.(*v1.NamespaceSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NamespaceStatus)(nil), (*core.NamespaceStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NamespaceStatus_To_core_NamespaceStatus(a.(*v1.NamespaceStatus), b.(*core.NamespaceStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.NamespaceStatus)(nil), (*v1.NamespaceStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_NamespaceStatus_To_v1_NamespaceStatus(a.(*core.NamespaceStatus), b.(*v1.NamespaceStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.Node)(nil), (*core.Node)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Node_To_core_Node(a.(*v1.Node), b.(*core.Node), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.Node)(nil), (*v1.Node)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_Node_To_v1_Node(a.(*core.Node), b.(*v1.Node), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NodeAddress)(nil), (*core.NodeAddress)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeAddress_To_core_NodeAddress(a.(*v1.NodeAddress), b.(*core.NodeAddress), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.NodeAddress)(nil), (*v1.NodeAddress)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_NodeAddress_To_v1_NodeAddress(a.(*core.NodeAddress), b.(*v1.NodeAddress), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NodeAffinity)(nil), (*core.NodeAffinity)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeAffinity_To_core_NodeAffinity(a.(*v1.NodeAffinity), b.(*core.NodeAffinity), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.NodeAffinity)(nil), (*v1.NodeAffinity)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_NodeAffinity_To_v1_NodeAffinity(a.(*core.NodeAffinity), b.(*v1.NodeAffinity), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NodeCondition)(nil), (*core.NodeCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeCondition_To_core_NodeCondition(a.(*v1.NodeCondition), b.(*core.NodeCondition), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.NodeCondition)(nil), (*v1.NodeCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_NodeCondition_To_v1_NodeCondition(a.(*core.NodeCondition), b.(*v1.NodeCondition), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NodeConfigSource)(nil), (*core.NodeConfigSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeConfigSource_To_core_NodeConfigSource(a.(*v1.NodeConfigSource), b.(*core.NodeConfigSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.NodeConfigSource)(nil), (*v1.NodeConfigSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_NodeConfigSource_To_v1_NodeConfigSource(a.(*core.NodeConfigSource), b.(*v1.NodeConfigSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NodeConfigStatus)(nil), (*core.NodeConfigStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeConfigStatus_To_core_NodeConfigStatus(a.(*v1.NodeConfigStatus), b.(*core.NodeConfigStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.NodeConfigStatus)(nil), (*v1.NodeConfigStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_NodeConfigStatus_To_v1_NodeConfigStatus(a.(*core.NodeConfigStatus), b.(*v1.NodeConfigStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NodeDaemonEndpoints)(nil), (*core.NodeDaemonEndpoints)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeDaemonEndpoints_To_core_NodeDaemonEndpoints(a.(*v1.NodeDaemonEndpoints), b.(*core.NodeDaemonEndpoints), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.NodeDaemonEndpoints)(nil), (*v1.NodeDaemonEndpoints)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_NodeDaemonEndpoints_To_v1_NodeDaemonEndpoints(a.(*core.NodeDaemonEndpoints), b.(*v1.NodeDaemonEndpoints), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NodeList)(nil), (*core.NodeList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeList_To_core_NodeList(a.(*v1.NodeList), b.(*core.NodeList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.NodeList)(nil), (*v1.NodeList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_NodeList_To_v1_NodeList(a.(*core.NodeList), b.(*v1.NodeList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NodeProxyOptions)(nil), (*core.NodeProxyOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeProxyOptions_To_core_NodeProxyOptions(a.(*v1.NodeProxyOptions), b.(*core.NodeProxyOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.NodeProxyOptions)(nil), (*v1.NodeProxyOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_NodeProxyOptions_To_v1_NodeProxyOptions(a.(*core.NodeProxyOptions), b.(*v1.NodeProxyOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NodeResources)(nil), (*core.NodeResources)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeResources_To_core_NodeResources(a.(*v1.NodeResources), b.(*core.NodeResources), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.NodeResources)(nil), (*v1.NodeResources)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_NodeResources_To_v1_NodeResources(a.(*core.NodeResources), b.(*v1.NodeResources), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NodeSelector)(nil), (*core.NodeSelector)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeSelector_To_core_NodeSelector(a.(*v1.NodeSelector), b.(*core.NodeSelector), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.NodeSelector)(nil), (*v1.NodeSelector)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_NodeSelector_To_v1_NodeSelector(a.(*core.NodeSelector), b.(*v1.NodeSelector), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NodeSelectorRequirement)(nil), (*core.NodeSelectorRequirement)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeSelectorRequirement_To_core_NodeSelectorRequirement(a.(*v1.NodeSelectorRequirement), b.(*core.NodeSelectorRequirement), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.NodeSelectorRequirement)(nil), (*v1.NodeSelectorRequirement)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_NodeSelectorRequirement_To_v1_NodeSelectorRequirement(a.(*core.NodeSelectorRequirement), b.(*v1.NodeSelectorRequirement), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NodeSelectorTerm)(nil), (*core.NodeSelectorTerm)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeSelectorTerm_To_core_NodeSelectorTerm(a.(*v1.NodeSelectorTerm), b.(*core.NodeSelectorTerm), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.NodeSelectorTerm)(nil), (*v1.NodeSelectorTerm)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_NodeSelectorTerm_To_v1_NodeSelectorTerm(a.(*core.NodeSelectorTerm), b.(*v1.NodeSelectorTerm), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NodeStatus)(nil), (*core.NodeStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeStatus_To_core_NodeStatus(a.(*v1.NodeStatus), b.(*core.NodeStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.NodeStatus)(nil), (*v1.NodeStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_NodeStatus_To_v1_NodeStatus(a.(*core.NodeStatus), b.(*v1.NodeStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NodeSystemInfo)(nil), (*core.NodeSystemInfo)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeSystemInfo_To_core_NodeSystemInfo(a.(*v1.NodeSystemInfo), b.(*core.NodeSystemInfo), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.NodeSystemInfo)(nil), (*v1.NodeSystemInfo)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_NodeSystemInfo_To_v1_NodeSystemInfo(a.(*core.NodeSystemInfo), b.(*v1.NodeSystemInfo), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ObjectFieldSelector)(nil), (*core.ObjectFieldSelector)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ObjectFieldSelector_To_core_ObjectFieldSelector(a.(*v1.ObjectFieldSelector), b.(*core.ObjectFieldSelector), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ObjectFieldSelector)(nil), (*v1.ObjectFieldSelector)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ObjectFieldSelector_To_v1_ObjectFieldSelector(a.(*core.ObjectFieldSelector), b.(*v1.ObjectFieldSelector), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ObjectReference)(nil), (*core.ObjectReference)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ObjectReference_To_core_ObjectReference(a.(*v1.ObjectReference), b.(*core.ObjectReference), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ObjectReference)(nil), (*v1.ObjectReference)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ObjectReference_To_v1_ObjectReference(a.(*core.ObjectReference), b.(*v1.ObjectReference), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PersistentVolume)(nil), (*core.PersistentVolume)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PersistentVolume_To_core_PersistentVolume(a.(*v1.PersistentVolume), b.(*core.PersistentVolume), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PersistentVolume)(nil), (*v1.PersistentVolume)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PersistentVolume_To_v1_PersistentVolume(a.(*core.PersistentVolume), b.(*v1.PersistentVolume), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PersistentVolumeClaim)(nil), (*core.PersistentVolumeClaim)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PersistentVolumeClaim_To_core_PersistentVolumeClaim(a.(*v1.PersistentVolumeClaim), b.(*core.PersistentVolumeClaim), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PersistentVolumeClaim)(nil), (*v1.PersistentVolumeClaim)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PersistentVolumeClaim_To_v1_PersistentVolumeClaim(a.(*core.PersistentVolumeClaim), b.(*v1.PersistentVolumeClaim), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PersistentVolumeClaimCondition)(nil), (*core.PersistentVolumeClaimCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PersistentVolumeClaimCondition_To_core_PersistentVolumeClaimCondition(a.(*v1.PersistentVolumeClaimCondition), b.(*core.PersistentVolumeClaimCondition), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PersistentVolumeClaimCondition)(nil), (*v1.PersistentVolumeClaimCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PersistentVolumeClaimCondition_To_v1_PersistentVolumeClaimCondition(a.(*core.PersistentVolumeClaimCondition), b.(*v1.PersistentVolumeClaimCondition), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PersistentVolumeClaimList)(nil), (*core.PersistentVolumeClaimList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PersistentVolumeClaimList_To_core_PersistentVolumeClaimList(a.(*v1.PersistentVolumeClaimList), b.(*core.PersistentVolumeClaimList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PersistentVolumeClaimList)(nil), (*v1.PersistentVolumeClaimList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PersistentVolumeClaimList_To_v1_PersistentVolumeClaimList(a.(*core.PersistentVolumeClaimList), b.(*v1.PersistentVolumeClaimList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PersistentVolumeClaimSpec)(nil), (*core.PersistentVolumeClaimSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PersistentVolumeClaimSpec_To_core_PersistentVolumeClaimSpec(a.(*v1.PersistentVolumeClaimSpec), b.(*core.PersistentVolumeClaimSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PersistentVolumeClaimSpec)(nil), (*v1.PersistentVolumeClaimSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PersistentVolumeClaimSpec_To_v1_PersistentVolumeClaimSpec(a.(*core.PersistentVolumeClaimSpec), b.(*v1.PersistentVolumeClaimSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PersistentVolumeClaimStatus)(nil), (*core.PersistentVolumeClaimStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PersistentVolumeClaimStatus_To_core_PersistentVolumeClaimStatus(a.(*v1.PersistentVolumeClaimStatus), b.(*core.PersistentVolumeClaimStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PersistentVolumeClaimStatus)(nil), (*v1.PersistentVolumeClaimStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PersistentVolumeClaimStatus_To_v1_PersistentVolumeClaimStatus(a.(*core.PersistentVolumeClaimStatus), b.(*v1.PersistentVolumeClaimStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PersistentVolumeClaimTemplate)(nil), (*core.PersistentVolumeClaimTemplate)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PersistentVolumeClaimTemplate_To_core_PersistentVolumeClaimTemplate(a.(*v1.PersistentVolumeClaimTemplate), b.(*core.PersistentVolumeClaimTemplate), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PersistentVolumeClaimTemplate)(nil), (*v1.PersistentVolumeClaimTemplate)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PersistentVolumeClaimTemplate_To_v1_PersistentVolumeClaimTemplate(a.(*core.PersistentVolumeClaimTemplate), b.(*v1.PersistentVolumeClaimTemplate), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PersistentVolumeClaimVolumeSource)(nil), (*core.PersistentVolumeClaimVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PersistentVolumeClaimVolumeSource_To_core_PersistentVolumeClaimVolumeSource(a.(*v1.PersistentVolumeClaimVolumeSource), b.(*core.PersistentVolumeClaimVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PersistentVolumeClaimVolumeSource)(nil), (*v1.PersistentVolumeClaimVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PersistentVolumeClaimVolumeSource_To_v1_PersistentVolumeClaimVolumeSource(a.(*core.PersistentVolumeClaimVolumeSource), b.(*v1.PersistentVolumeClaimVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PersistentVolumeList)(nil), (*core.PersistentVolumeList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PersistentVolumeList_To_core_PersistentVolumeList(a.(*v1.PersistentVolumeList), b.(*core.PersistentVolumeList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PersistentVolumeList)(nil), (*v1.PersistentVolumeList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PersistentVolumeList_To_v1_PersistentVolumeList(a.(*core.PersistentVolumeList), b.(*v1.PersistentVolumeList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PersistentVolumeSource)(nil), (*core.PersistentVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PersistentVolumeSource_To_core_PersistentVolumeSource(a.(*v1.PersistentVolumeSource), b.(*core.PersistentVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PersistentVolumeSource)(nil), (*v1.PersistentVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PersistentVolumeSource_To_v1_PersistentVolumeSource(a.(*core.PersistentVolumeSource), b.(*v1.PersistentVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PersistentVolumeStatus)(nil), (*core.PersistentVolumeStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PersistentVolumeStatus_To_core_PersistentVolumeStatus(a.(*v1.PersistentVolumeStatus), b.(*core.PersistentVolumeStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PersistentVolumeStatus)(nil), (*v1.PersistentVolumeStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PersistentVolumeStatus_To_v1_PersistentVolumeStatus(a.(*core.PersistentVolumeStatus), b.(*v1.PersistentVolumeStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PhotonPersistentDiskVolumeSource)(nil), (*core.PhotonPersistentDiskVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PhotonPersistentDiskVolumeSource_To_core_PhotonPersistentDiskVolumeSource(a.(*v1.PhotonPersistentDiskVolumeSource), b.(*core.PhotonPersistentDiskVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PhotonPersistentDiskVolumeSource)(nil), (*v1.PhotonPersistentDiskVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PhotonPersistentDiskVolumeSource_To_v1_PhotonPersistentDiskVolumeSource(a.(*core.PhotonPersistentDiskVolumeSource), b.(*v1.PhotonPersistentDiskVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodAffinity)(nil), (*core.PodAffinity)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodAffinity_To_core_PodAffinity(a.(*v1.PodAffinity), b.(*core.PodAffinity), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PodAffinity)(nil), (*v1.PodAffinity)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodAffinity_To_v1_PodAffinity(a.(*core.PodAffinity), b.(*v1.PodAffinity), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodAffinityTerm)(nil), (*core.PodAffinityTerm)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodAffinityTerm_To_core_PodAffinityTerm(a.(*v1.PodAffinityTerm), b.(*core.PodAffinityTerm), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PodAffinityTerm)(nil), (*v1.PodAffinityTerm)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodAffinityTerm_To_v1_PodAffinityTerm(a.(*core.PodAffinityTerm), b.(*v1.PodAffinityTerm), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodAntiAffinity)(nil), (*core.PodAntiAffinity)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodAntiAffinity_To_core_PodAntiAffinity(a.(*v1.PodAntiAffinity), b.(*core.PodAntiAffinity), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PodAntiAffinity)(nil), (*v1.PodAntiAffinity)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodAntiAffinity_To_v1_PodAntiAffinity(a.(*core.PodAntiAffinity), b.(*v1.PodAntiAffinity), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodAttachOptions)(nil), (*core.PodAttachOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodAttachOptions_To_core_PodAttachOptions(a.(*v1.PodAttachOptions), b.(*core.PodAttachOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PodAttachOptions)(nil), (*v1.PodAttachOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodAttachOptions_To_v1_PodAttachOptions(a.(*core.PodAttachOptions), b.(*v1.PodAttachOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodCondition)(nil), (*core.PodCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodCondition_To_core_PodCondition(a.(*v1.PodCondition), b.(*core.PodCondition), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PodCondition)(nil), (*v1.PodCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodCondition_To_v1_PodCondition(a.(*core.PodCondition), b.(*v1.PodCondition), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodDNSConfig)(nil), (*core.PodDNSConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodDNSConfig_To_core_PodDNSConfig(a.(*v1.PodDNSConfig), b.(*core.PodDNSConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PodDNSConfig)(nil), (*v1.PodDNSConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodDNSConfig_To_v1_PodDNSConfig(a.(*core.PodDNSConfig), b.(*v1.PodDNSConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodDNSConfigOption)(nil), (*core.PodDNSConfigOption)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodDNSConfigOption_To_core_PodDNSConfigOption(a.(*v1.PodDNSConfigOption), b.(*core.PodDNSConfigOption), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PodDNSConfigOption)(nil), (*v1.PodDNSConfigOption)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodDNSConfigOption_To_v1_PodDNSConfigOption(a.(*core.PodDNSConfigOption), b.(*v1.PodDNSConfigOption), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodExecOptions)(nil), (*core.PodExecOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodExecOptions_To_core_PodExecOptions(a.(*v1.PodExecOptions), b.(*core.PodExecOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PodExecOptions)(nil), (*v1.PodExecOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodExecOptions_To_v1_PodExecOptions(a.(*core.PodExecOptions), b.(*v1.PodExecOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodIP)(nil), (*core.PodIP)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodIP_To_core_PodIP(a.(*v1.PodIP), b.(*core.PodIP), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PodIP)(nil), (*v1.PodIP)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodIP_To_v1_PodIP(a.(*core.PodIP), b.(*v1.PodIP), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodList)(nil), (*core.PodList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodList_To_core_PodList(a.(*v1.PodList), b.(*core.PodList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PodList)(nil), (*v1.PodList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodList_To_v1_PodList(a.(*core.PodList), b.(*v1.PodList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodLogOptions)(nil), (*core.PodLogOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodLogOptions_To_core_PodLogOptions(a.(*v1.PodLogOptions), b.(*core.PodLogOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PodLogOptions)(nil), (*v1.PodLogOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodLogOptions_To_v1_PodLogOptions(a.(*core.PodLogOptions), b.(*v1.PodLogOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodOS)(nil), (*core.PodOS)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodOS_To_core_PodOS(a.(*v1.PodOS), b.(*core.PodOS), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PodOS)(nil), (*v1.PodOS)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodOS_To_v1_PodOS(a.(*core.PodOS), b.(*v1.PodOS), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodPortForwardOptions)(nil), (*core.PodPortForwardOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodPortForwardOptions_To_core_PodPortForwardOptions(a.(*v1.PodPortForwardOptions), b.(*core.PodPortForwardOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PodPortForwardOptions)(nil), (*v1.PodPortForwardOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodPortForwardOptions_To_v1_PodPortForwardOptions(a.(*core.PodPortForwardOptions), b.(*v1.PodPortForwardOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodProxyOptions)(nil), (*core.PodProxyOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodProxyOptions_To_core_PodProxyOptions(a.(*v1.PodProxyOptions), b.(*core.PodProxyOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PodProxyOptions)(nil), (*v1.PodProxyOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodProxyOptions_To_v1_PodProxyOptions(a.(*core.PodProxyOptions), b.(*v1.PodProxyOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodReadinessGate)(nil), (*core.PodReadinessGate)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodReadinessGate_To_core_PodReadinessGate(a.(*v1.PodReadinessGate), b.(*core.PodReadinessGate), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PodReadinessGate)(nil), (*v1.PodReadinessGate)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodReadinessGate_To_v1_PodReadinessGate(a.(*core.PodReadinessGate), b.(*v1.PodReadinessGate), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodResourceClaim)(nil), (*core.PodResourceClaim)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodResourceClaim_To_core_PodResourceClaim(a.(*v1.PodResourceClaim), b.(*core.PodResourceClaim), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PodResourceClaim)(nil), (*v1.PodResourceClaim)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodResourceClaim_To_v1_PodResourceClaim(a.(*core.PodResourceClaim), b.(*v1.PodResourceClaim), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodSchedulingGate)(nil), (*core.PodSchedulingGate)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodSchedulingGate_To_core_PodSchedulingGate(a.(*v1.PodSchedulingGate), b.(*core.PodSchedulingGate), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PodSchedulingGate)(nil), (*v1.PodSchedulingGate)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodSchedulingGate_To_v1_PodSchedulingGate(a.(*core.PodSchedulingGate), b.(*v1.PodSchedulingGate), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodSecurityContext)(nil), (*core.PodSecurityContext)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodSecurityContext_To_core_PodSecurityContext(a.(*v1.PodSecurityContext), b.(*core.PodSecurityContext), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PodSecurityContext)(nil), (*v1.PodSecurityContext)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodSecurityContext_To_v1_PodSecurityContext(a.(*core.PodSecurityContext), b.(*v1.PodSecurityContext), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodSignature)(nil), (*core.PodSignature)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodSignature_To_core_PodSignature(a.(*v1.PodSignature), b.(*core.PodSignature), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PodSignature)(nil), (*v1.PodSignature)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodSignature_To_v1_PodSignature(a.(*core.PodSignature), b.(*v1.PodSignature), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodStatusResult)(nil), (*core.PodStatusResult)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodStatusResult_To_core_PodStatusResult(a.(*v1.PodStatusResult), b.(*core.PodStatusResult), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PodStatusResult)(nil), (*v1.PodStatusResult)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodStatusResult_To_v1_PodStatusResult(a.(*core.PodStatusResult), b.(*v1.PodStatusResult), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodTemplate)(nil), (*core.PodTemplate)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodTemplate_To_core_PodTemplate(a.(*v1.PodTemplate), b.(*core.PodTemplate), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PodTemplate)(nil), (*v1.PodTemplate)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodTemplate_To_v1_PodTemplate(a.(*core.PodTemplate), b.(*v1.PodTemplate), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodTemplateList)(nil), (*core.PodTemplateList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodTemplateList_To_core_PodTemplateList(a.(*v1.PodTemplateList), b.(*core.PodTemplateList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PodTemplateList)(nil), (*v1.PodTemplateList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodTemplateList_To_v1_PodTemplateList(a.(*core.PodTemplateList), b.(*v1.PodTemplateList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PortStatus)(nil), (*core.PortStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PortStatus_To_core_PortStatus(a.(*v1.PortStatus), b.(*core.PortStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PortStatus)(nil), (*v1.PortStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PortStatus_To_v1_PortStatus(a.(*core.PortStatus), b.(*v1.PortStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PortworxVolumeSource)(nil), (*core.PortworxVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PortworxVolumeSource_To_core_PortworxVolumeSource(a.(*v1.PortworxVolumeSource), b.(*core.PortworxVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PortworxVolumeSource)(nil), (*v1.PortworxVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PortworxVolumeSource_To_v1_PortworxVolumeSource(a.(*core.PortworxVolumeSource), b.(*v1.PortworxVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.Preconditions)(nil), (*core.Preconditions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Preconditions_To_core_Preconditions(a.(*v1.Preconditions), b.(*core.Preconditions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.Preconditions)(nil), (*v1.Preconditions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_Preconditions_To_v1_Preconditions(a.(*core.Preconditions), b.(*v1.Preconditions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PreferAvoidPodsEntry)(nil), (*core.PreferAvoidPodsEntry)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PreferAvoidPodsEntry_To_core_PreferAvoidPodsEntry(a.(*v1.PreferAvoidPodsEntry), b.(*core.PreferAvoidPodsEntry), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PreferAvoidPodsEntry)(nil), (*v1.PreferAvoidPodsEntry)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PreferAvoidPodsEntry_To_v1_PreferAvoidPodsEntry(a.(*core.PreferAvoidPodsEntry), b.(*v1.PreferAvoidPodsEntry), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PreferredSchedulingTerm)(nil), (*core.PreferredSchedulingTerm)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PreferredSchedulingTerm_To_core_PreferredSchedulingTerm(a.(*v1.PreferredSchedulingTerm), b.(*core.PreferredSchedulingTerm), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.PreferredSchedulingTerm)(nil), (*v1.PreferredSchedulingTerm)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PreferredSchedulingTerm_To_v1_PreferredSchedulingTerm(a.(*core.PreferredSchedulingTerm), b.(*v1.PreferredSchedulingTerm), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.Probe)(nil), (*core.Probe)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Probe_To_core_Probe(a.(*v1.Probe), b.(*core.Probe), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.Probe)(nil), (*v1.Probe)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_Probe_To_v1_Probe(a.(*core.Probe), b.(*v1.Probe), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ProbeHandler)(nil), (*core.ProbeHandler)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ProbeHandler_To_core_ProbeHandler(a.(*v1.ProbeHandler), b.(*core.ProbeHandler), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ProbeHandler)(nil), (*v1.ProbeHandler)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ProbeHandler_To_v1_ProbeHandler(a.(*core.ProbeHandler), b.(*v1.ProbeHandler), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ProjectedVolumeSource)(nil), (*core.ProjectedVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ProjectedVolumeSource_To_core_ProjectedVolumeSource(a.(*v1.ProjectedVolumeSource), b.(*core.ProjectedVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ProjectedVolumeSource)(nil), (*v1.ProjectedVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ProjectedVolumeSource_To_v1_ProjectedVolumeSource(a.(*core.ProjectedVolumeSource), b.(*v1.ProjectedVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.QuobyteVolumeSource)(nil), (*core.QuobyteVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_QuobyteVolumeSource_To_core_QuobyteVolumeSource(a.(*v1.QuobyteVolumeSource), b.(*core.QuobyteVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.QuobyteVolumeSource)(nil), (*v1.QuobyteVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_QuobyteVolumeSource_To_v1_QuobyteVolumeSource(a.(*core.QuobyteVolumeSource), b.(*v1.QuobyteVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.RBDPersistentVolumeSource)(nil), (*core.RBDPersistentVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_RBDPersistentVolumeSource_To_core_RBDPersistentVolumeSource(a.(*v1.RBDPersistentVolumeSource), b.(*core.RBDPersistentVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.RBDPersistentVolumeSource)(nil), (*v1.RBDPersistentVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_RBDPersistentVolumeSource_To_v1_RBDPersistentVolumeSource(a.(*core.RBDPersistentVolumeSource), b.(*v1.RBDPersistentVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.RBDVolumeSource)(nil), (*core.RBDVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_RBDVolumeSource_To_core_RBDVolumeSource(a.(*v1.RBDVolumeSource), b.(*core.RBDVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.RBDVolumeSource)(nil), (*v1.RBDVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_RBDVolumeSource_To_v1_RBDVolumeSource(a.(*core.RBDVolumeSource), b.(*v1.RBDVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.RangeAllocation)(nil), (*core.RangeAllocation)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_RangeAllocation_To_core_RangeAllocation(a.(*v1.RangeAllocation), b.(*core.RangeAllocation), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.RangeAllocation)(nil), (*v1.RangeAllocation)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_RangeAllocation_To_v1_RangeAllocation(a.(*core.RangeAllocation), b.(*v1.RangeAllocation), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ReplicationController)(nil), (*core.ReplicationController)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ReplicationController_To_core_ReplicationController(a.(*v1.ReplicationController), b.(*core.ReplicationController), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ReplicationController)(nil), (*v1.ReplicationController)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ReplicationController_To_v1_ReplicationController(a.(*core.ReplicationController), b.(*v1.ReplicationController), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ReplicationControllerCondition)(nil), (*core.ReplicationControllerCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ReplicationControllerCondition_To_core_ReplicationControllerCondition(a.(*v1.ReplicationControllerCondition), b.(*core.ReplicationControllerCondition), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ReplicationControllerCondition)(nil), (*v1.ReplicationControllerCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ReplicationControllerCondition_To_v1_ReplicationControllerCondition(a.(*core.ReplicationControllerCondition), b.(*v1.ReplicationControllerCondition), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ReplicationControllerList)(nil), (*core.ReplicationControllerList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ReplicationControllerList_To_core_ReplicationControllerList(a.(*v1.ReplicationControllerList), b.(*core.ReplicationControllerList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ReplicationControllerList)(nil), (*v1.ReplicationControllerList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ReplicationControllerList_To_v1_ReplicationControllerList(a.(*core.ReplicationControllerList), b.(*v1.ReplicationControllerList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ReplicationControllerStatus)(nil), (*core.ReplicationControllerStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ReplicationControllerStatus_To_core_ReplicationControllerStatus(a.(*v1.ReplicationControllerStatus), b.(*core.ReplicationControllerStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ReplicationControllerStatus)(nil), (*v1.ReplicationControllerStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ReplicationControllerStatus_To_v1_ReplicationControllerStatus(a.(*core.ReplicationControllerStatus), b.(*v1.ReplicationControllerStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ResourceClaim)(nil), (*core.ResourceClaim)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ResourceClaim_To_core_ResourceClaim(a.(*v1.ResourceClaim), b.(*core.ResourceClaim), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ResourceClaim)(nil), (*v1.ResourceClaim)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ResourceClaim_To_v1_ResourceClaim(a.(*core.ResourceClaim), b.(*v1.ResourceClaim), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ResourceFieldSelector)(nil), (*core.ResourceFieldSelector)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ResourceFieldSelector_To_core_ResourceFieldSelector(a.(*v1.ResourceFieldSelector), b.(*core.ResourceFieldSelector), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ResourceFieldSelector)(nil), (*v1.ResourceFieldSelector)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ResourceFieldSelector_To_v1_ResourceFieldSelector(a.(*core.ResourceFieldSelector), b.(*v1.ResourceFieldSelector), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ResourceQuota)(nil), (*core.ResourceQuota)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ResourceQuota_To_core_ResourceQuota(a.(*v1.ResourceQuota), b.(*core.ResourceQuota), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ResourceQuota)(nil), (*v1.ResourceQuota)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ResourceQuota_To_v1_ResourceQuota(a.(*core.ResourceQuota), b.(*v1.ResourceQuota), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ResourceQuotaList)(nil), (*core.ResourceQuotaList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ResourceQuotaList_To_core_ResourceQuotaList(a.(*v1.ResourceQuotaList), b.(*core.ResourceQuotaList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ResourceQuotaList)(nil), (*v1.ResourceQuotaList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ResourceQuotaList_To_v1_ResourceQuotaList(a.(*core.ResourceQuotaList), b.(*v1.ResourceQuotaList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ResourceQuotaSpec)(nil), (*core.ResourceQuotaSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ResourceQuotaSpec_To_core_ResourceQuotaSpec(a.(*v1.ResourceQuotaSpec), b.(*core.ResourceQuotaSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ResourceQuotaSpec)(nil), (*v1.ResourceQuotaSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ResourceQuotaSpec_To_v1_ResourceQuotaSpec(a.(*core.ResourceQuotaSpec), b.(*v1.ResourceQuotaSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ResourceQuotaStatus)(nil), (*core.ResourceQuotaStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ResourceQuotaStatus_To_core_ResourceQuotaStatus(a.(*v1.ResourceQuotaStatus), b.(*core.ResourceQuotaStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ResourceQuotaStatus)(nil), (*v1.ResourceQuotaStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ResourceQuotaStatus_To_v1_ResourceQuotaStatus(a.(*core.ResourceQuotaStatus), b.(*v1.ResourceQuotaStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ResourceRequirements)(nil), (*core.ResourceRequirements)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ResourceRequirements_To_core_ResourceRequirements(a.(*v1.ResourceRequirements), b.(*core.ResourceRequirements), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ResourceRequirements)(nil), (*v1.ResourceRequirements)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ResourceRequirements_To_v1_ResourceRequirements(a.(*core.ResourceRequirements), b.(*v1.ResourceRequirements), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.SELinuxOptions)(nil), (*core.SELinuxOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_SELinuxOptions_To_core_SELinuxOptions(a.(*v1.SELinuxOptions), b.(*core.SELinuxOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.SELinuxOptions)(nil), (*v1.SELinuxOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_SELinuxOptions_To_v1_SELinuxOptions(a.(*core.SELinuxOptions), b.(*v1.SELinuxOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ScaleIOPersistentVolumeSource)(nil), (*core.ScaleIOPersistentVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ScaleIOPersistentVolumeSource_To_core_ScaleIOPersistentVolumeSource(a.(*v1.ScaleIOPersistentVolumeSource), b.(*core.ScaleIOPersistentVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ScaleIOPersistentVolumeSource)(nil), (*v1.ScaleIOPersistentVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ScaleIOPersistentVolumeSource_To_v1_ScaleIOPersistentVolumeSource(a.(*core.ScaleIOPersistentVolumeSource), b.(*v1.ScaleIOPersistentVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ScaleIOVolumeSource)(nil), (*core.ScaleIOVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ScaleIOVolumeSource_To_core_ScaleIOVolumeSource(a.(*v1.ScaleIOVolumeSource), b.(*core.ScaleIOVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ScaleIOVolumeSource)(nil), (*v1.ScaleIOVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ScaleIOVolumeSource_To_v1_ScaleIOVolumeSource(a.(*core.ScaleIOVolumeSource), b.(*v1.ScaleIOVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ScopeSelector)(nil), (*core.ScopeSelector)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ScopeSelector_To_core_ScopeSelector(a.(*v1.ScopeSelector), b.(*core.ScopeSelector), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ScopeSelector)(nil), (*v1.ScopeSelector)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ScopeSelector_To_v1_ScopeSelector(a.(*core.ScopeSelector), b.(*v1.ScopeSelector), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ScopedResourceSelectorRequirement)(nil), (*core.ScopedResourceSelectorRequirement)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ScopedResourceSelectorRequirement_To_core_ScopedResourceSelectorRequirement(a.(*v1.ScopedResourceSelectorRequirement), b.(*core.ScopedResourceSelectorRequirement), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ScopedResourceSelectorRequirement)(nil), (*v1.ScopedResourceSelectorRequirement)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ScopedResourceSelectorRequirement_To_v1_ScopedResourceSelectorRequirement(a.(*core.ScopedResourceSelectorRequirement), b.(*v1.ScopedResourceSelectorRequirement), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.SeccompProfile)(nil), (*core.SeccompProfile)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_SeccompProfile_To_core_SeccompProfile(a.(*v1.SeccompProfile), b.(*core.SeccompProfile), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.SeccompProfile)(nil), (*v1.SeccompProfile)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_SeccompProfile_To_v1_SeccompProfile(a.(*core.SeccompProfile), b.(*v1.SeccompProfile), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.Secret)(nil), (*v1.Secret)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_Secret_To_v1_Secret(a.(*core.Secret), b.(*v1.Secret), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.SecretEnvSource)(nil), (*core.SecretEnvSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_SecretEnvSource_To_core_SecretEnvSource(a.(*v1.SecretEnvSource), b.(*core.SecretEnvSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.SecretEnvSource)(nil), (*v1.SecretEnvSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_SecretEnvSource_To_v1_SecretEnvSource(a.(*core.SecretEnvSource), b.(*v1.SecretEnvSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.SecretKeySelector)(nil), (*core.SecretKeySelector)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_SecretKeySelector_To_core_SecretKeySelector(a.(*v1.SecretKeySelector), b.(*core.SecretKeySelector), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.SecretKeySelector)(nil), (*v1.SecretKeySelector)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_SecretKeySelector_To_v1_SecretKeySelector(a.(*core.SecretKeySelector), b.(*v1.SecretKeySelector), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.SecretList)(nil), (*core.SecretList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_SecretList_To_core_SecretList(a.(*v1.SecretList), b.(*core.SecretList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.SecretList)(nil), (*v1.SecretList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_SecretList_To_v1_SecretList(a.(*core.SecretList), b.(*v1.SecretList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.SecretProjection)(nil), (*core.SecretProjection)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_SecretProjection_To_core_SecretProjection(a.(*v1.SecretProjection), b.(*core.SecretProjection), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.SecretProjection)(nil), (*v1.SecretProjection)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_SecretProjection_To_v1_SecretProjection(a.(*core.SecretProjection), b.(*v1.SecretProjection), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.SecretReference)(nil), (*core.SecretReference)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_SecretReference_To_core_SecretReference(a.(*v1.SecretReference), b.(*core.SecretReference), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.SecretReference)(nil), (*v1.SecretReference)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_SecretReference_To_v1_SecretReference(a.(*core.SecretReference), b.(*v1.SecretReference), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.SecretVolumeSource)(nil), (*core.SecretVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_SecretVolumeSource_To_core_SecretVolumeSource(a.(*v1.SecretVolumeSource), b.(*core.SecretVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.SecretVolumeSource)(nil), (*v1.SecretVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_SecretVolumeSource_To_v1_SecretVolumeSource(a.(*core.SecretVolumeSource), b.(*v1.SecretVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.SecurityContext)(nil), (*core.SecurityContext)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_SecurityContext_To_core_SecurityContext(a.(*v1.SecurityContext), b.(*core.SecurityContext), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.SecurityContext)(nil), (*v1.SecurityContext)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_SecurityContext_To_v1_SecurityContext(a.(*core.SecurityContext), b.(*v1.SecurityContext), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.SerializedReference)(nil), (*core.SerializedReference)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_SerializedReference_To_core_SerializedReference(a.(*v1.SerializedReference), b.(*core.SerializedReference), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.SerializedReference)(nil), (*v1.SerializedReference)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_SerializedReference_To_v1_SerializedReference(a.(*core.SerializedReference), b.(*v1.SerializedReference), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.Service)(nil), (*core.Service)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Service_To_core_Service(a.(*v1.Service), b.(*core.Service), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.Service)(nil), (*v1.Service)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_Service_To_v1_Service(a.(*core.Service), b.(*v1.Service), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ServiceAccount)(nil), (*core.ServiceAccount)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ServiceAccount_To_core_ServiceAccount(a.(*v1.ServiceAccount), b.(*core.ServiceAccount), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ServiceAccount)(nil), (*v1.ServiceAccount)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ServiceAccount_To_v1_ServiceAccount(a.(*core.ServiceAccount), b.(*v1.ServiceAccount), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ServiceAccountList)(nil), (*core.ServiceAccountList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ServiceAccountList_To_core_ServiceAccountList(a.(*v1.ServiceAccountList), b.(*core.ServiceAccountList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ServiceAccountList)(nil), (*v1.ServiceAccountList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ServiceAccountList_To_v1_ServiceAccountList(a.(*core.ServiceAccountList), b.(*v1.ServiceAccountList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ServiceAccountTokenProjection)(nil), (*core.ServiceAccountTokenProjection)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ServiceAccountTokenProjection_To_core_ServiceAccountTokenProjection(a.(*v1.ServiceAccountTokenProjection), b.(*core.ServiceAccountTokenProjection), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ServiceAccountTokenProjection)(nil), (*v1.ServiceAccountTokenProjection)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ServiceAccountTokenProjection_To_v1_ServiceAccountTokenProjection(a.(*core.ServiceAccountTokenProjection), b.(*v1.ServiceAccountTokenProjection), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ServiceList)(nil), (*core.ServiceList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ServiceList_To_core_ServiceList(a.(*v1.ServiceList), b.(*core.ServiceList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ServiceList)(nil), (*v1.ServiceList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ServiceList_To_v1_ServiceList(a.(*core.ServiceList), b.(*v1.ServiceList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ServicePort)(nil), (*core.ServicePort)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ServicePort_To_core_ServicePort(a.(*v1.ServicePort), b.(*core.ServicePort), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ServicePort)(nil), (*v1.ServicePort)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ServicePort_To_v1_ServicePort(a.(*core.ServicePort), b.(*v1.ServicePort), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ServiceProxyOptions)(nil), (*core.ServiceProxyOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ServiceProxyOptions_To_core_ServiceProxyOptions(a.(*v1.ServiceProxyOptions), b.(*core.ServiceProxyOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ServiceProxyOptions)(nil), (*v1.ServiceProxyOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ServiceProxyOptions_To_v1_ServiceProxyOptions(a.(*core.ServiceProxyOptions), b.(*v1.ServiceProxyOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ServiceSpec)(nil), (*core.ServiceSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ServiceSpec_To_core_ServiceSpec(a.(*v1.ServiceSpec), b.(*core.ServiceSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ServiceSpec)(nil), (*v1.ServiceSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ServiceSpec_To_v1_ServiceSpec(a.(*core.ServiceSpec), b.(*v1.ServiceSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ServiceStatus)(nil), (*core.ServiceStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ServiceStatus_To_core_ServiceStatus(a.(*v1.ServiceStatus), b.(*core.ServiceStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.ServiceStatus)(nil), (*v1.ServiceStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ServiceStatus_To_v1_ServiceStatus(a.(*core.ServiceStatus), b.(*v1.ServiceStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.SessionAffinityConfig)(nil), (*core.SessionAffinityConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_SessionAffinityConfig_To_core_SessionAffinityConfig(a.(*v1.SessionAffinityConfig), b.(*core.SessionAffinityConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.SessionAffinityConfig)(nil), (*v1.SessionAffinityConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_SessionAffinityConfig_To_v1_SessionAffinityConfig(a.(*core.SessionAffinityConfig), b.(*v1.SessionAffinityConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.StorageOSPersistentVolumeSource)(nil), (*core.StorageOSPersistentVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_StorageOSPersistentVolumeSource_To_core_StorageOSPersistentVolumeSource(a.(*v1.StorageOSPersistentVolumeSource), b.(*core.StorageOSPersistentVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.StorageOSPersistentVolumeSource)(nil), (*v1.StorageOSPersistentVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_StorageOSPersistentVolumeSource_To_v1_StorageOSPersistentVolumeSource(a.(*core.StorageOSPersistentVolumeSource), b.(*v1.StorageOSPersistentVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.StorageOSVolumeSource)(nil), (*core.StorageOSVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_StorageOSVolumeSource_To_core_StorageOSVolumeSource(a.(*v1.StorageOSVolumeSource), b.(*core.StorageOSVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.StorageOSVolumeSource)(nil), (*v1.StorageOSVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_StorageOSVolumeSource_To_v1_StorageOSVolumeSource(a.(*core.StorageOSVolumeSource), b.(*v1.StorageOSVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.Sysctl)(nil), (*core.Sysctl)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Sysctl_To_core_Sysctl(a.(*v1.Sysctl), b.(*core.Sysctl), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.Sysctl)(nil), (*v1.Sysctl)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_Sysctl_To_v1_Sysctl(a.(*core.Sysctl), b.(*v1.Sysctl), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.TCPSocketAction)(nil), (*core.TCPSocketAction)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TCPSocketAction_To_core_TCPSocketAction(a.(*v1.TCPSocketAction), b.(*core.TCPSocketAction), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.TCPSocketAction)(nil), (*v1.TCPSocketAction)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_TCPSocketAction_To_v1_TCPSocketAction(a.(*core.TCPSocketAction), b.(*v1.TCPSocketAction), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.Taint)(nil), (*core.Taint)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Taint_To_core_Taint(a.(*v1.Taint), b.(*core.Taint), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.Taint)(nil), (*v1.Taint)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_Taint_To_v1_Taint(a.(*core.Taint), b.(*v1.Taint), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.Toleration)(nil), (*core.Toleration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Toleration_To_core_Toleration(a.(*v1.Toleration), b.(*core.Toleration), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.Toleration)(nil), (*v1.Toleration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_Toleration_To_v1_Toleration(a.(*core.Toleration), b.(*v1.Toleration), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.TopologySelectorLabelRequirement)(nil), (*core.TopologySelectorLabelRequirement)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TopologySelectorLabelRequirement_To_core_TopologySelectorLabelRequirement(a.(*v1.TopologySelectorLabelRequirement), b.(*core.TopologySelectorLabelRequirement), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.TopologySelectorLabelRequirement)(nil), (*v1.TopologySelectorLabelRequirement)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_TopologySelectorLabelRequirement_To_v1_TopologySelectorLabelRequirement(a.(*core.TopologySelectorLabelRequirement), b.(*v1.TopologySelectorLabelRequirement), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.TopologySelectorTerm)(nil), (*core.TopologySelectorTerm)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TopologySelectorTerm_To_core_TopologySelectorTerm(a.(*v1.TopologySelectorTerm), b.(*core.TopologySelectorTerm), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.TopologySelectorTerm)(nil), (*v1.TopologySelectorTerm)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_TopologySelectorTerm_To_v1_TopologySelectorTerm(a.(*core.TopologySelectorTerm), b.(*v1.TopologySelectorTerm), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.TopologySpreadConstraint)(nil), (*core.TopologySpreadConstraint)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TopologySpreadConstraint_To_core_TopologySpreadConstraint(a.(*v1.TopologySpreadConstraint), b.(*core.TopologySpreadConstraint), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.TopologySpreadConstraint)(nil), (*v1.TopologySpreadConstraint)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_TopologySpreadConstraint_To_v1_TopologySpreadConstraint(a.(*core.TopologySpreadConstraint), b.(*v1.TopologySpreadConstraint), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.TypedLocalObjectReference)(nil), (*core.TypedLocalObjectReference)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TypedLocalObjectReference_To_core_TypedLocalObjectReference(a.(*v1.TypedLocalObjectReference), b.(*core.TypedLocalObjectReference), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.TypedLocalObjectReference)(nil), (*v1.TypedLocalObjectReference)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_TypedLocalObjectReference_To_v1_TypedLocalObjectReference(a.(*core.TypedLocalObjectReference), b.(*v1.TypedLocalObjectReference), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.TypedObjectReference)(nil), (*core.TypedObjectReference)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TypedObjectReference_To_core_TypedObjectReference(a.(*v1.TypedObjectReference), b.(*core.TypedObjectReference), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.TypedObjectReference)(nil), (*v1.TypedObjectReference)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_TypedObjectReference_To_v1_TypedObjectReference(a.(*core.TypedObjectReference), b.(*v1.TypedObjectReference), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.VolumeDevice)(nil), (*core.VolumeDevice)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_VolumeDevice_To_core_VolumeDevice(a.(*v1.VolumeDevice), b.(*core.VolumeDevice), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.VolumeDevice)(nil), (*v1.VolumeDevice)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_VolumeDevice_To_v1_VolumeDevice(a.(*core.VolumeDevice), b.(*v1.VolumeDevice), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.VolumeMount)(nil), (*core.VolumeMount)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_VolumeMount_To_core_VolumeMount(a.(*v1.VolumeMount), b.(*core.VolumeMount), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.VolumeMount)(nil), (*v1.VolumeMount)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_VolumeMount_To_v1_VolumeMount(a.(*core.VolumeMount), b.(*v1.VolumeMount), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.VolumeNodeAffinity)(nil), (*core.VolumeNodeAffinity)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_VolumeNodeAffinity_To_core_VolumeNodeAffinity(a.(*v1.VolumeNodeAffinity), b.(*core.VolumeNodeAffinity), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.VolumeNodeAffinity)(nil), (*v1.VolumeNodeAffinity)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_VolumeNodeAffinity_To_v1_VolumeNodeAffinity(a.(*core.VolumeNodeAffinity), b.(*v1.VolumeNodeAffinity), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.VolumeProjection)(nil), (*core.VolumeProjection)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_VolumeProjection_To_core_VolumeProjection(a.(*v1.VolumeProjection), b.(*core.VolumeProjection), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.VolumeProjection)(nil), (*v1.VolumeProjection)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_VolumeProjection_To_v1_VolumeProjection(a.(*core.VolumeProjection), b.(*v1.VolumeProjection), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.VolumeSource)(nil), (*core.VolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_VolumeSource_To_core_VolumeSource(a.(*v1.VolumeSource), b.(*core.VolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.VolumeSource)(nil), (*v1.VolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_VolumeSource_To_v1_VolumeSource(a.(*core.VolumeSource), b.(*v1.VolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.VsphereVirtualDiskVolumeSource)(nil), (*core.VsphereVirtualDiskVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_VsphereVirtualDiskVolumeSource_To_core_VsphereVirtualDiskVolumeSource(a.(*v1.VsphereVirtualDiskVolumeSource), b.(*core.VsphereVirtualDiskVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.VsphereVirtualDiskVolumeSource)(nil), (*v1.VsphereVirtualDiskVolumeSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_VsphereVirtualDiskVolumeSource_To_v1_VsphereVirtualDiskVolumeSource(a.(*core.VsphereVirtualDiskVolumeSource), b.(*v1.VsphereVirtualDiskVolumeSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.WeightedPodAffinityTerm)(nil), (*core.WeightedPodAffinityTerm)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_WeightedPodAffinityTerm_To_core_WeightedPodAffinityTerm(a.(*v1.WeightedPodAffinityTerm), b.(*core.WeightedPodAffinityTerm), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.WeightedPodAffinityTerm)(nil), (*v1.WeightedPodAffinityTerm)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_WeightedPodAffinityTerm_To_v1_WeightedPodAffinityTerm(a.(*core.WeightedPodAffinityTerm), b.(*v1.WeightedPodAffinityTerm), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.WindowsSecurityContextOptions)(nil), (*core.WindowsSecurityContextOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_WindowsSecurityContextOptions_To_core_WindowsSecurityContextOptions(a.(*v1.WindowsSecurityContextOptions), b.(*core.WindowsSecurityContextOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.WindowsSecurityContextOptions)(nil), (*v1.WindowsSecurityContextOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_WindowsSecurityContextOptions_To_v1_WindowsSecurityContextOptions(a.(*core.WindowsSecurityContextOptions), b.(*v1.WindowsSecurityContextOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*url.Values)(nil), (*v1.NodeProxyOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_url_Values_To_v1_NodeProxyOptions(a.(*url.Values), b.(*v1.NodeProxyOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*url.Values)(nil), (*v1.PodAttachOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_url_Values_To_v1_PodAttachOptions(a.(*url.Values), b.(*v1.PodAttachOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*url.Values)(nil), (*v1.PodExecOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_url_Values_To_v1_PodExecOptions(a.(*url.Values), b.(*v1.PodExecOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*url.Values)(nil), (*v1.PodLogOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_url_Values_To_v1_PodLogOptions(a.(*url.Values), b.(*v1.PodLogOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*url.Values)(nil), (*v1.PodPortForwardOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_url_Values_To_v1_PodPortForwardOptions(a.(*url.Values), b.(*v1.PodPortForwardOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*url.Values)(nil), (*v1.PodProxyOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_url_Values_To_v1_PodProxyOptions(a.(*url.Values), b.(*v1.PodProxyOptions), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*url.Values)(nil), (*v1.ServiceProxyOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_url_Values_To_v1_ServiceProxyOptions(a.(*url.Values), b.(*v1.ServiceProxyOptions), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*apps.ReplicaSetSpec)(nil), (*v1.ReplicationControllerSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_apps_ReplicaSetSpec_To_v1_ReplicationControllerSpec(a.(*apps.ReplicaSetSpec), b.(*v1.ReplicationControllerSpec), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*apps.ReplicaSetStatus)(nil), (*v1.ReplicationControllerStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_apps_ReplicaSetStatus_To_v1_ReplicationControllerStatus(a.(*apps.ReplicaSetStatus), b.(*v1.ReplicationControllerStatus), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*apps.ReplicaSet)(nil), (*v1.ReplicationController)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_apps_ReplicaSet_To_v1_ReplicationController(a.(*apps.ReplicaSet), b.(*v1.ReplicationController), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*core.LoadBalancerStatus)(nil), (*v1.LoadBalancerStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_LoadBalancerStatus_To_v1_LoadBalancerStatus(a.(*core.LoadBalancerStatus), b.(*v1.LoadBalancerStatus), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*core.NodeSpec)(nil), (*v1.NodeSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_NodeSpec_To_v1_NodeSpec(a.(*core.NodeSpec), b.(*v1.NodeSpec), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*core.PersistentVolumeSpec)(nil), (*v1.PersistentVolumeSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PersistentVolumeSpec_To_v1_PersistentVolumeSpec(a.(*core.PersistentVolumeSpec), b.(*v1.PersistentVolumeSpec), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*core.PodSpec)(nil), (*v1.PodSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodSpec_To_v1_PodSpec(a.(*core.PodSpec), b.(*v1.PodSpec), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*core.PodStatus)(nil), (*v1.PodStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodStatus_To_v1_PodStatus(a.(*core.PodStatus), b.(*v1.PodStatus), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*core.PodTemplateSpec)(nil), (*v1.PodTemplateSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_PodTemplateSpec_To_v1_PodTemplateSpec(a.(*core.PodTemplateSpec), b.(*v1.PodTemplateSpec), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*core.Pod)(nil), (*v1.Pod)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_Pod_To_v1_Pod(a.(*core.Pod), b.(*v1.Pod), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*core.ReplicationControllerSpec)(nil), (*v1.ReplicationControllerSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_ReplicationControllerSpec_To_v1_ReplicationControllerSpec(a.(*core.ReplicationControllerSpec), b.(*v1.ReplicationControllerSpec), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*core.Volume)(nil), (*v1.Volume)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_Volume_To_v1_Volume(a.(*core.Volume), b.(*v1.Volume), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1.LoadBalancerStatus)(nil), (*core.LoadBalancerStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_LoadBalancerStatus_To_core_LoadBalancerStatus(a.(*v1.LoadBalancerStatus), b.(*core.LoadBalancerStatus), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1.NodeSpec)(nil), (*core.NodeSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeSpec_To_core_NodeSpec(a.(*v1.NodeSpec), b.(*core.NodeSpec), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1.PersistentVolumeSpec)(nil), (*core.PersistentVolumeSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PersistentVolumeSpec_To_core_PersistentVolumeSpec(a.(*v1.PersistentVolumeSpec), b.(*core.PersistentVolumeSpec), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1.PodSpec)(nil), (*core.PodSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodSpec_To_core_PodSpec(a.(*v1.PodSpec), b.(*core.PodSpec), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1.PodStatus)(nil), (*core.PodStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodStatus_To_core_PodStatus(a.(*v1.PodStatus), b.(*core.PodStatus), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1.PodTemplateSpec)(nil), (*core.PodTemplateSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodTemplateSpec_To_core_PodTemplateSpec(a.(*v1.PodTemplateSpec), b.(*core.PodTemplateSpec), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1.Pod)(nil), (*core.Pod)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Pod_To_core_Pod(a.(*v1.Pod), b.(*core.Pod), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1.ReplicationControllerSpec)(nil), (*apps.ReplicaSetSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ReplicationControllerSpec_To_apps_ReplicaSetSpec(a.(*v1.ReplicationControllerSpec), b.(*apps.ReplicaSetSpec), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1.ReplicationControllerSpec)(nil), (*core.ReplicationControllerSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ReplicationControllerSpec_To_core_ReplicationControllerSpec(a.(*v1.ReplicationControllerSpec), b.(*core.ReplicationControllerSpec), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1.ReplicationControllerStatus)(nil), (*apps.ReplicaSetStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ReplicationControllerStatus_To_apps_ReplicaSetStatus(a.(*v1.ReplicationControllerStatus), b.(*apps.ReplicaSetStatus), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1.ReplicationController)(nil), (*apps.ReplicaSet)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ReplicationController_To_apps_ReplicaSet(a.(*v1.ReplicationController), b.(*apps.ReplicaSet), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1.ResourceList)(nil), (*core.ResourceList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ResourceList_To_core_ResourceList(a.(*v1.ResourceList), b.(*core.ResourceList), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1.Secret)(nil), (*core.Secret)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Secret_To_core_Secret(a.(*v1.Secret), b.(*core.Secret), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1.Volume)(nil), (*core.Volume)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Volume_To_core_Volume(a.(*v1.Volume), b.(*core.Volume), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v1_AWSElasticBlockStoreVolumeSource_To_core_AWSElasticBlockStoreVolumeSource(in *v1.AWSElasticBlockStoreVolumeSource, out *core.AWSElasticBlockStoreVolumeSource, s conversion.Scope) error { + out.VolumeID = in.VolumeID + out.FSType = in.FSType + out.Partition = in.Partition + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_v1_AWSElasticBlockStoreVolumeSource_To_core_AWSElasticBlockStoreVolumeSource is an autogenerated conversion function. +func Convert_v1_AWSElasticBlockStoreVolumeSource_To_core_AWSElasticBlockStoreVolumeSource(in *v1.AWSElasticBlockStoreVolumeSource, out *core.AWSElasticBlockStoreVolumeSource, s conversion.Scope) error { + return autoConvert_v1_AWSElasticBlockStoreVolumeSource_To_core_AWSElasticBlockStoreVolumeSource(in, out, s) +} + +func autoConvert_core_AWSElasticBlockStoreVolumeSource_To_v1_AWSElasticBlockStoreVolumeSource(in *core.AWSElasticBlockStoreVolumeSource, out *v1.AWSElasticBlockStoreVolumeSource, s conversion.Scope) error { + out.VolumeID = in.VolumeID + out.FSType = in.FSType + out.Partition = in.Partition + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_core_AWSElasticBlockStoreVolumeSource_To_v1_AWSElasticBlockStoreVolumeSource is an autogenerated conversion function. +func Convert_core_AWSElasticBlockStoreVolumeSource_To_v1_AWSElasticBlockStoreVolumeSource(in *core.AWSElasticBlockStoreVolumeSource, out *v1.AWSElasticBlockStoreVolumeSource, s conversion.Scope) error { + return autoConvert_core_AWSElasticBlockStoreVolumeSource_To_v1_AWSElasticBlockStoreVolumeSource(in, out, s) +} + +func autoConvert_v1_Affinity_To_core_Affinity(in *v1.Affinity, out *core.Affinity, s conversion.Scope) error { + out.NodeAffinity = (*core.NodeAffinity)(unsafe.Pointer(in.NodeAffinity)) + out.PodAffinity = (*core.PodAffinity)(unsafe.Pointer(in.PodAffinity)) + out.PodAntiAffinity = (*core.PodAntiAffinity)(unsafe.Pointer(in.PodAntiAffinity)) + return nil +} + +// Convert_v1_Affinity_To_core_Affinity is an autogenerated conversion function. +func Convert_v1_Affinity_To_core_Affinity(in *v1.Affinity, out *core.Affinity, s conversion.Scope) error { + return autoConvert_v1_Affinity_To_core_Affinity(in, out, s) +} + +func autoConvert_core_Affinity_To_v1_Affinity(in *core.Affinity, out *v1.Affinity, s conversion.Scope) error { + out.NodeAffinity = (*v1.NodeAffinity)(unsafe.Pointer(in.NodeAffinity)) + out.PodAffinity = (*v1.PodAffinity)(unsafe.Pointer(in.PodAffinity)) + out.PodAntiAffinity = (*v1.PodAntiAffinity)(unsafe.Pointer(in.PodAntiAffinity)) + return nil +} + +// Convert_core_Affinity_To_v1_Affinity is an autogenerated conversion function. +func Convert_core_Affinity_To_v1_Affinity(in *core.Affinity, out *v1.Affinity, s conversion.Scope) error { + return autoConvert_core_Affinity_To_v1_Affinity(in, out, s) +} + +func autoConvert_v1_AttachedVolume_To_core_AttachedVolume(in *v1.AttachedVolume, out *core.AttachedVolume, s conversion.Scope) error { + out.Name = core.UniqueVolumeName(in.Name) + out.DevicePath = in.DevicePath + return nil +} + +// Convert_v1_AttachedVolume_To_core_AttachedVolume is an autogenerated conversion function. +func Convert_v1_AttachedVolume_To_core_AttachedVolume(in *v1.AttachedVolume, out *core.AttachedVolume, s conversion.Scope) error { + return autoConvert_v1_AttachedVolume_To_core_AttachedVolume(in, out, s) +} + +func autoConvert_core_AttachedVolume_To_v1_AttachedVolume(in *core.AttachedVolume, out *v1.AttachedVolume, s conversion.Scope) error { + out.Name = v1.UniqueVolumeName(in.Name) + out.DevicePath = in.DevicePath + return nil +} + +// Convert_core_AttachedVolume_To_v1_AttachedVolume is an autogenerated conversion function. +func Convert_core_AttachedVolume_To_v1_AttachedVolume(in *core.AttachedVolume, out *v1.AttachedVolume, s conversion.Scope) error { + return autoConvert_core_AttachedVolume_To_v1_AttachedVolume(in, out, s) +} + +func autoConvert_v1_AvoidPods_To_core_AvoidPods(in *v1.AvoidPods, out *core.AvoidPods, s conversion.Scope) error { + out.PreferAvoidPods = *(*[]core.PreferAvoidPodsEntry)(unsafe.Pointer(&in.PreferAvoidPods)) + return nil +} + +// Convert_v1_AvoidPods_To_core_AvoidPods is an autogenerated conversion function. +func Convert_v1_AvoidPods_To_core_AvoidPods(in *v1.AvoidPods, out *core.AvoidPods, s conversion.Scope) error { + return autoConvert_v1_AvoidPods_To_core_AvoidPods(in, out, s) +} + +func autoConvert_core_AvoidPods_To_v1_AvoidPods(in *core.AvoidPods, out *v1.AvoidPods, s conversion.Scope) error { + out.PreferAvoidPods = *(*[]v1.PreferAvoidPodsEntry)(unsafe.Pointer(&in.PreferAvoidPods)) + return nil +} + +// Convert_core_AvoidPods_To_v1_AvoidPods is an autogenerated conversion function. +func Convert_core_AvoidPods_To_v1_AvoidPods(in *core.AvoidPods, out *v1.AvoidPods, s conversion.Scope) error { + return autoConvert_core_AvoidPods_To_v1_AvoidPods(in, out, s) +} + +func autoConvert_v1_AzureDiskVolumeSource_To_core_AzureDiskVolumeSource(in *v1.AzureDiskVolumeSource, out *core.AzureDiskVolumeSource, s conversion.Scope) error { + out.DiskName = in.DiskName + out.DataDiskURI = in.DataDiskURI + out.CachingMode = (*core.AzureDataDiskCachingMode)(unsafe.Pointer(in.CachingMode)) + out.FSType = (*string)(unsafe.Pointer(in.FSType)) + out.ReadOnly = (*bool)(unsafe.Pointer(in.ReadOnly)) + out.Kind = (*core.AzureDataDiskKind)(unsafe.Pointer(in.Kind)) + return nil +} + +// Convert_v1_AzureDiskVolumeSource_To_core_AzureDiskVolumeSource is an autogenerated conversion function. +func Convert_v1_AzureDiskVolumeSource_To_core_AzureDiskVolumeSource(in *v1.AzureDiskVolumeSource, out *core.AzureDiskVolumeSource, s conversion.Scope) error { + return autoConvert_v1_AzureDiskVolumeSource_To_core_AzureDiskVolumeSource(in, out, s) +} + +func autoConvert_core_AzureDiskVolumeSource_To_v1_AzureDiskVolumeSource(in *core.AzureDiskVolumeSource, out *v1.AzureDiskVolumeSource, s conversion.Scope) error { + out.DiskName = in.DiskName + out.DataDiskURI = in.DataDiskURI + out.CachingMode = (*v1.AzureDataDiskCachingMode)(unsafe.Pointer(in.CachingMode)) + out.FSType = (*string)(unsafe.Pointer(in.FSType)) + out.ReadOnly = (*bool)(unsafe.Pointer(in.ReadOnly)) + out.Kind = (*v1.AzureDataDiskKind)(unsafe.Pointer(in.Kind)) + return nil +} + +// Convert_core_AzureDiskVolumeSource_To_v1_AzureDiskVolumeSource is an autogenerated conversion function. +func Convert_core_AzureDiskVolumeSource_To_v1_AzureDiskVolumeSource(in *core.AzureDiskVolumeSource, out *v1.AzureDiskVolumeSource, s conversion.Scope) error { + return autoConvert_core_AzureDiskVolumeSource_To_v1_AzureDiskVolumeSource(in, out, s) +} + +func autoConvert_v1_AzureFilePersistentVolumeSource_To_core_AzureFilePersistentVolumeSource(in *v1.AzureFilePersistentVolumeSource, out *core.AzureFilePersistentVolumeSource, s conversion.Scope) error { + out.SecretName = in.SecretName + out.ShareName = in.ShareName + out.ReadOnly = in.ReadOnly + out.SecretNamespace = (*string)(unsafe.Pointer(in.SecretNamespace)) + return nil +} + +// Convert_v1_AzureFilePersistentVolumeSource_To_core_AzureFilePersistentVolumeSource is an autogenerated conversion function. +func Convert_v1_AzureFilePersistentVolumeSource_To_core_AzureFilePersistentVolumeSource(in *v1.AzureFilePersistentVolumeSource, out *core.AzureFilePersistentVolumeSource, s conversion.Scope) error { + return autoConvert_v1_AzureFilePersistentVolumeSource_To_core_AzureFilePersistentVolumeSource(in, out, s) +} + +func autoConvert_core_AzureFilePersistentVolumeSource_To_v1_AzureFilePersistentVolumeSource(in *core.AzureFilePersistentVolumeSource, out *v1.AzureFilePersistentVolumeSource, s conversion.Scope) error { + out.SecretName = in.SecretName + out.ShareName = in.ShareName + out.ReadOnly = in.ReadOnly + out.SecretNamespace = (*string)(unsafe.Pointer(in.SecretNamespace)) + return nil +} + +// Convert_core_AzureFilePersistentVolumeSource_To_v1_AzureFilePersistentVolumeSource is an autogenerated conversion function. +func Convert_core_AzureFilePersistentVolumeSource_To_v1_AzureFilePersistentVolumeSource(in *core.AzureFilePersistentVolumeSource, out *v1.AzureFilePersistentVolumeSource, s conversion.Scope) error { + return autoConvert_core_AzureFilePersistentVolumeSource_To_v1_AzureFilePersistentVolumeSource(in, out, s) +} + +func autoConvert_v1_AzureFileVolumeSource_To_core_AzureFileVolumeSource(in *v1.AzureFileVolumeSource, out *core.AzureFileVolumeSource, s conversion.Scope) error { + out.SecretName = in.SecretName + out.ShareName = in.ShareName + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_v1_AzureFileVolumeSource_To_core_AzureFileVolumeSource is an autogenerated conversion function. +func Convert_v1_AzureFileVolumeSource_To_core_AzureFileVolumeSource(in *v1.AzureFileVolumeSource, out *core.AzureFileVolumeSource, s conversion.Scope) error { + return autoConvert_v1_AzureFileVolumeSource_To_core_AzureFileVolumeSource(in, out, s) +} + +func autoConvert_core_AzureFileVolumeSource_To_v1_AzureFileVolumeSource(in *core.AzureFileVolumeSource, out *v1.AzureFileVolumeSource, s conversion.Scope) error { + out.SecretName = in.SecretName + out.ShareName = in.ShareName + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_core_AzureFileVolumeSource_To_v1_AzureFileVolumeSource is an autogenerated conversion function. +func Convert_core_AzureFileVolumeSource_To_v1_AzureFileVolumeSource(in *core.AzureFileVolumeSource, out *v1.AzureFileVolumeSource, s conversion.Scope) error { + return autoConvert_core_AzureFileVolumeSource_To_v1_AzureFileVolumeSource(in, out, s) +} + +func autoConvert_v1_Binding_To_core_Binding(in *v1.Binding, out *core.Binding, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_ObjectReference_To_core_ObjectReference(&in.Target, &out.Target, s); err != nil { + return err + } + return nil +} + +// Convert_v1_Binding_To_core_Binding is an autogenerated conversion function. +func Convert_v1_Binding_To_core_Binding(in *v1.Binding, out *core.Binding, s conversion.Scope) error { + return autoConvert_v1_Binding_To_core_Binding(in, out, s) +} + +func autoConvert_core_Binding_To_v1_Binding(in *core.Binding, out *v1.Binding, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_core_ObjectReference_To_v1_ObjectReference(&in.Target, &out.Target, s); err != nil { + return err + } + return nil +} + +// Convert_core_Binding_To_v1_Binding is an autogenerated conversion function. +func Convert_core_Binding_To_v1_Binding(in *core.Binding, out *v1.Binding, s conversion.Scope) error { + return autoConvert_core_Binding_To_v1_Binding(in, out, s) +} + +func autoConvert_v1_CSIPersistentVolumeSource_To_core_CSIPersistentVolumeSource(in *v1.CSIPersistentVolumeSource, out *core.CSIPersistentVolumeSource, s conversion.Scope) error { + out.Driver = in.Driver + out.VolumeHandle = in.VolumeHandle + out.ReadOnly = in.ReadOnly + out.FSType = in.FSType + out.VolumeAttributes = *(*map[string]string)(unsafe.Pointer(&in.VolumeAttributes)) + out.ControllerPublishSecretRef = (*core.SecretReference)(unsafe.Pointer(in.ControllerPublishSecretRef)) + out.NodeStageSecretRef = (*core.SecretReference)(unsafe.Pointer(in.NodeStageSecretRef)) + out.NodePublishSecretRef = (*core.SecretReference)(unsafe.Pointer(in.NodePublishSecretRef)) + out.ControllerExpandSecretRef = (*core.SecretReference)(unsafe.Pointer(in.ControllerExpandSecretRef)) + out.NodeExpandSecretRef = (*core.SecretReference)(unsafe.Pointer(in.NodeExpandSecretRef)) + return nil +} + +// Convert_v1_CSIPersistentVolumeSource_To_core_CSIPersistentVolumeSource is an autogenerated conversion function. +func Convert_v1_CSIPersistentVolumeSource_To_core_CSIPersistentVolumeSource(in *v1.CSIPersistentVolumeSource, out *core.CSIPersistentVolumeSource, s conversion.Scope) error { + return autoConvert_v1_CSIPersistentVolumeSource_To_core_CSIPersistentVolumeSource(in, out, s) +} + +func autoConvert_core_CSIPersistentVolumeSource_To_v1_CSIPersistentVolumeSource(in *core.CSIPersistentVolumeSource, out *v1.CSIPersistentVolumeSource, s conversion.Scope) error { + out.Driver = in.Driver + out.VolumeHandle = in.VolumeHandle + out.ReadOnly = in.ReadOnly + out.FSType = in.FSType + out.VolumeAttributes = *(*map[string]string)(unsafe.Pointer(&in.VolumeAttributes)) + out.ControllerPublishSecretRef = (*v1.SecretReference)(unsafe.Pointer(in.ControllerPublishSecretRef)) + out.NodeStageSecretRef = (*v1.SecretReference)(unsafe.Pointer(in.NodeStageSecretRef)) + out.NodePublishSecretRef = (*v1.SecretReference)(unsafe.Pointer(in.NodePublishSecretRef)) + out.ControllerExpandSecretRef = (*v1.SecretReference)(unsafe.Pointer(in.ControllerExpandSecretRef)) + out.NodeExpandSecretRef = (*v1.SecretReference)(unsafe.Pointer(in.NodeExpandSecretRef)) + return nil +} + +// Convert_core_CSIPersistentVolumeSource_To_v1_CSIPersistentVolumeSource is an autogenerated conversion function. +func Convert_core_CSIPersistentVolumeSource_To_v1_CSIPersistentVolumeSource(in *core.CSIPersistentVolumeSource, out *v1.CSIPersistentVolumeSource, s conversion.Scope) error { + return autoConvert_core_CSIPersistentVolumeSource_To_v1_CSIPersistentVolumeSource(in, out, s) +} + +func autoConvert_v1_CSIVolumeSource_To_core_CSIVolumeSource(in *v1.CSIVolumeSource, out *core.CSIVolumeSource, s conversion.Scope) error { + out.Driver = in.Driver + out.ReadOnly = (*bool)(unsafe.Pointer(in.ReadOnly)) + out.FSType = (*string)(unsafe.Pointer(in.FSType)) + out.VolumeAttributes = *(*map[string]string)(unsafe.Pointer(&in.VolumeAttributes)) + out.NodePublishSecretRef = (*core.LocalObjectReference)(unsafe.Pointer(in.NodePublishSecretRef)) + return nil +} + +// Convert_v1_CSIVolumeSource_To_core_CSIVolumeSource is an autogenerated conversion function. +func Convert_v1_CSIVolumeSource_To_core_CSIVolumeSource(in *v1.CSIVolumeSource, out *core.CSIVolumeSource, s conversion.Scope) error { + return autoConvert_v1_CSIVolumeSource_To_core_CSIVolumeSource(in, out, s) +} + +func autoConvert_core_CSIVolumeSource_To_v1_CSIVolumeSource(in *core.CSIVolumeSource, out *v1.CSIVolumeSource, s conversion.Scope) error { + out.Driver = in.Driver + out.ReadOnly = (*bool)(unsafe.Pointer(in.ReadOnly)) + out.FSType = (*string)(unsafe.Pointer(in.FSType)) + out.VolumeAttributes = *(*map[string]string)(unsafe.Pointer(&in.VolumeAttributes)) + out.NodePublishSecretRef = (*v1.LocalObjectReference)(unsafe.Pointer(in.NodePublishSecretRef)) + return nil +} + +// Convert_core_CSIVolumeSource_To_v1_CSIVolumeSource is an autogenerated conversion function. +func Convert_core_CSIVolumeSource_To_v1_CSIVolumeSource(in *core.CSIVolumeSource, out *v1.CSIVolumeSource, s conversion.Scope) error { + return autoConvert_core_CSIVolumeSource_To_v1_CSIVolumeSource(in, out, s) +} + +func autoConvert_v1_Capabilities_To_core_Capabilities(in *v1.Capabilities, out *core.Capabilities, s conversion.Scope) error { + out.Add = *(*[]core.Capability)(unsafe.Pointer(&in.Add)) + out.Drop = *(*[]core.Capability)(unsafe.Pointer(&in.Drop)) + return nil +} + +// Convert_v1_Capabilities_To_core_Capabilities is an autogenerated conversion function. +func Convert_v1_Capabilities_To_core_Capabilities(in *v1.Capabilities, out *core.Capabilities, s conversion.Scope) error { + return autoConvert_v1_Capabilities_To_core_Capabilities(in, out, s) +} + +func autoConvert_core_Capabilities_To_v1_Capabilities(in *core.Capabilities, out *v1.Capabilities, s conversion.Scope) error { + out.Add = *(*[]v1.Capability)(unsafe.Pointer(&in.Add)) + out.Drop = *(*[]v1.Capability)(unsafe.Pointer(&in.Drop)) + return nil +} + +// Convert_core_Capabilities_To_v1_Capabilities is an autogenerated conversion function. +func Convert_core_Capabilities_To_v1_Capabilities(in *core.Capabilities, out *v1.Capabilities, s conversion.Scope) error { + return autoConvert_core_Capabilities_To_v1_Capabilities(in, out, s) +} + +func autoConvert_v1_CephFSPersistentVolumeSource_To_core_CephFSPersistentVolumeSource(in *v1.CephFSPersistentVolumeSource, out *core.CephFSPersistentVolumeSource, s conversion.Scope) error { + out.Monitors = *(*[]string)(unsafe.Pointer(&in.Monitors)) + out.Path = in.Path + out.User = in.User + out.SecretFile = in.SecretFile + out.SecretRef = (*core.SecretReference)(unsafe.Pointer(in.SecretRef)) + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_v1_CephFSPersistentVolumeSource_To_core_CephFSPersistentVolumeSource is an autogenerated conversion function. +func Convert_v1_CephFSPersistentVolumeSource_To_core_CephFSPersistentVolumeSource(in *v1.CephFSPersistentVolumeSource, out *core.CephFSPersistentVolumeSource, s conversion.Scope) error { + return autoConvert_v1_CephFSPersistentVolumeSource_To_core_CephFSPersistentVolumeSource(in, out, s) +} + +func autoConvert_core_CephFSPersistentVolumeSource_To_v1_CephFSPersistentVolumeSource(in *core.CephFSPersistentVolumeSource, out *v1.CephFSPersistentVolumeSource, s conversion.Scope) error { + out.Monitors = *(*[]string)(unsafe.Pointer(&in.Monitors)) + out.Path = in.Path + out.User = in.User + out.SecretFile = in.SecretFile + out.SecretRef = (*v1.SecretReference)(unsafe.Pointer(in.SecretRef)) + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_core_CephFSPersistentVolumeSource_To_v1_CephFSPersistentVolumeSource is an autogenerated conversion function. +func Convert_core_CephFSPersistentVolumeSource_To_v1_CephFSPersistentVolumeSource(in *core.CephFSPersistentVolumeSource, out *v1.CephFSPersistentVolumeSource, s conversion.Scope) error { + return autoConvert_core_CephFSPersistentVolumeSource_To_v1_CephFSPersistentVolumeSource(in, out, s) +} + +func autoConvert_v1_CephFSVolumeSource_To_core_CephFSVolumeSource(in *v1.CephFSVolumeSource, out *core.CephFSVolumeSource, s conversion.Scope) error { + out.Monitors = *(*[]string)(unsafe.Pointer(&in.Monitors)) + out.Path = in.Path + out.User = in.User + out.SecretFile = in.SecretFile + out.SecretRef = (*core.LocalObjectReference)(unsafe.Pointer(in.SecretRef)) + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_v1_CephFSVolumeSource_To_core_CephFSVolumeSource is an autogenerated conversion function. +func Convert_v1_CephFSVolumeSource_To_core_CephFSVolumeSource(in *v1.CephFSVolumeSource, out *core.CephFSVolumeSource, s conversion.Scope) error { + return autoConvert_v1_CephFSVolumeSource_To_core_CephFSVolumeSource(in, out, s) +} + +func autoConvert_core_CephFSVolumeSource_To_v1_CephFSVolumeSource(in *core.CephFSVolumeSource, out *v1.CephFSVolumeSource, s conversion.Scope) error { + out.Monitors = *(*[]string)(unsafe.Pointer(&in.Monitors)) + out.Path = in.Path + out.User = in.User + out.SecretFile = in.SecretFile + out.SecretRef = (*v1.LocalObjectReference)(unsafe.Pointer(in.SecretRef)) + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_core_CephFSVolumeSource_To_v1_CephFSVolumeSource is an autogenerated conversion function. +func Convert_core_CephFSVolumeSource_To_v1_CephFSVolumeSource(in *core.CephFSVolumeSource, out *v1.CephFSVolumeSource, s conversion.Scope) error { + return autoConvert_core_CephFSVolumeSource_To_v1_CephFSVolumeSource(in, out, s) +} + +func autoConvert_v1_CinderPersistentVolumeSource_To_core_CinderPersistentVolumeSource(in *v1.CinderPersistentVolumeSource, out *core.CinderPersistentVolumeSource, s conversion.Scope) error { + out.VolumeID = in.VolumeID + out.FSType = in.FSType + out.ReadOnly = in.ReadOnly + out.SecretRef = (*core.SecretReference)(unsafe.Pointer(in.SecretRef)) + return nil +} + +// Convert_v1_CinderPersistentVolumeSource_To_core_CinderPersistentVolumeSource is an autogenerated conversion function. +func Convert_v1_CinderPersistentVolumeSource_To_core_CinderPersistentVolumeSource(in *v1.CinderPersistentVolumeSource, out *core.CinderPersistentVolumeSource, s conversion.Scope) error { + return autoConvert_v1_CinderPersistentVolumeSource_To_core_CinderPersistentVolumeSource(in, out, s) +} + +func autoConvert_core_CinderPersistentVolumeSource_To_v1_CinderPersistentVolumeSource(in *core.CinderPersistentVolumeSource, out *v1.CinderPersistentVolumeSource, s conversion.Scope) error { + out.VolumeID = in.VolumeID + out.FSType = in.FSType + out.ReadOnly = in.ReadOnly + out.SecretRef = (*v1.SecretReference)(unsafe.Pointer(in.SecretRef)) + return nil +} + +// Convert_core_CinderPersistentVolumeSource_To_v1_CinderPersistentVolumeSource is an autogenerated conversion function. +func Convert_core_CinderPersistentVolumeSource_To_v1_CinderPersistentVolumeSource(in *core.CinderPersistentVolumeSource, out *v1.CinderPersistentVolumeSource, s conversion.Scope) error { + return autoConvert_core_CinderPersistentVolumeSource_To_v1_CinderPersistentVolumeSource(in, out, s) +} + +func autoConvert_v1_CinderVolumeSource_To_core_CinderVolumeSource(in *v1.CinderVolumeSource, out *core.CinderVolumeSource, s conversion.Scope) error { + out.VolumeID = in.VolumeID + out.FSType = in.FSType + out.ReadOnly = in.ReadOnly + out.SecretRef = (*core.LocalObjectReference)(unsafe.Pointer(in.SecretRef)) + return nil +} + +// Convert_v1_CinderVolumeSource_To_core_CinderVolumeSource is an autogenerated conversion function. +func Convert_v1_CinderVolumeSource_To_core_CinderVolumeSource(in *v1.CinderVolumeSource, out *core.CinderVolumeSource, s conversion.Scope) error { + return autoConvert_v1_CinderVolumeSource_To_core_CinderVolumeSource(in, out, s) +} + +func autoConvert_core_CinderVolumeSource_To_v1_CinderVolumeSource(in *core.CinderVolumeSource, out *v1.CinderVolumeSource, s conversion.Scope) error { + out.VolumeID = in.VolumeID + out.FSType = in.FSType + out.ReadOnly = in.ReadOnly + out.SecretRef = (*v1.LocalObjectReference)(unsafe.Pointer(in.SecretRef)) + return nil +} + +// Convert_core_CinderVolumeSource_To_v1_CinderVolumeSource is an autogenerated conversion function. +func Convert_core_CinderVolumeSource_To_v1_CinderVolumeSource(in *core.CinderVolumeSource, out *v1.CinderVolumeSource, s conversion.Scope) error { + return autoConvert_core_CinderVolumeSource_To_v1_CinderVolumeSource(in, out, s) +} + +func autoConvert_v1_ClaimSource_To_core_ClaimSource(in *v1.ClaimSource, out *core.ClaimSource, s conversion.Scope) error { + out.ResourceClaimName = (*string)(unsafe.Pointer(in.ResourceClaimName)) + out.ResourceClaimTemplateName = (*string)(unsafe.Pointer(in.ResourceClaimTemplateName)) + return nil +} + +// Convert_v1_ClaimSource_To_core_ClaimSource is an autogenerated conversion function. +func Convert_v1_ClaimSource_To_core_ClaimSource(in *v1.ClaimSource, out *core.ClaimSource, s conversion.Scope) error { + return autoConvert_v1_ClaimSource_To_core_ClaimSource(in, out, s) +} + +func autoConvert_core_ClaimSource_To_v1_ClaimSource(in *core.ClaimSource, out *v1.ClaimSource, s conversion.Scope) error { + out.ResourceClaimName = (*string)(unsafe.Pointer(in.ResourceClaimName)) + out.ResourceClaimTemplateName = (*string)(unsafe.Pointer(in.ResourceClaimTemplateName)) + return nil +} + +// Convert_core_ClaimSource_To_v1_ClaimSource is an autogenerated conversion function. +func Convert_core_ClaimSource_To_v1_ClaimSource(in *core.ClaimSource, out *v1.ClaimSource, s conversion.Scope) error { + return autoConvert_core_ClaimSource_To_v1_ClaimSource(in, out, s) +} + +func autoConvert_v1_ClientIPConfig_To_core_ClientIPConfig(in *v1.ClientIPConfig, out *core.ClientIPConfig, s conversion.Scope) error { + out.TimeoutSeconds = (*int32)(unsafe.Pointer(in.TimeoutSeconds)) + return nil +} + +// Convert_v1_ClientIPConfig_To_core_ClientIPConfig is an autogenerated conversion function. +func Convert_v1_ClientIPConfig_To_core_ClientIPConfig(in *v1.ClientIPConfig, out *core.ClientIPConfig, s conversion.Scope) error { + return autoConvert_v1_ClientIPConfig_To_core_ClientIPConfig(in, out, s) +} + +func autoConvert_core_ClientIPConfig_To_v1_ClientIPConfig(in *core.ClientIPConfig, out *v1.ClientIPConfig, s conversion.Scope) error { + out.TimeoutSeconds = (*int32)(unsafe.Pointer(in.TimeoutSeconds)) + return nil +} + +// Convert_core_ClientIPConfig_To_v1_ClientIPConfig is an autogenerated conversion function. +func Convert_core_ClientIPConfig_To_v1_ClientIPConfig(in *core.ClientIPConfig, out *v1.ClientIPConfig, s conversion.Scope) error { + return autoConvert_core_ClientIPConfig_To_v1_ClientIPConfig(in, out, s) +} + +func autoConvert_v1_ComponentCondition_To_core_ComponentCondition(in *v1.ComponentCondition, out *core.ComponentCondition, s conversion.Scope) error { + out.Type = core.ComponentConditionType(in.Type) + out.Status = core.ConditionStatus(in.Status) + out.Message = in.Message + out.Error = in.Error + return nil +} + +// Convert_v1_ComponentCondition_To_core_ComponentCondition is an autogenerated conversion function. +func Convert_v1_ComponentCondition_To_core_ComponentCondition(in *v1.ComponentCondition, out *core.ComponentCondition, s conversion.Scope) error { + return autoConvert_v1_ComponentCondition_To_core_ComponentCondition(in, out, s) +} + +func autoConvert_core_ComponentCondition_To_v1_ComponentCondition(in *core.ComponentCondition, out *v1.ComponentCondition, s conversion.Scope) error { + out.Type = v1.ComponentConditionType(in.Type) + out.Status = v1.ConditionStatus(in.Status) + out.Message = in.Message + out.Error = in.Error + return nil +} + +// Convert_core_ComponentCondition_To_v1_ComponentCondition is an autogenerated conversion function. +func Convert_core_ComponentCondition_To_v1_ComponentCondition(in *core.ComponentCondition, out *v1.ComponentCondition, s conversion.Scope) error { + return autoConvert_core_ComponentCondition_To_v1_ComponentCondition(in, out, s) +} + +func autoConvert_v1_ComponentStatus_To_core_ComponentStatus(in *v1.ComponentStatus, out *core.ComponentStatus, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + out.Conditions = *(*[]core.ComponentCondition)(unsafe.Pointer(&in.Conditions)) + return nil +} + +// Convert_v1_ComponentStatus_To_core_ComponentStatus is an autogenerated conversion function. +func Convert_v1_ComponentStatus_To_core_ComponentStatus(in *v1.ComponentStatus, out *core.ComponentStatus, s conversion.Scope) error { + return autoConvert_v1_ComponentStatus_To_core_ComponentStatus(in, out, s) +} + +func autoConvert_core_ComponentStatus_To_v1_ComponentStatus(in *core.ComponentStatus, out *v1.ComponentStatus, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + out.Conditions = *(*[]v1.ComponentCondition)(unsafe.Pointer(&in.Conditions)) + return nil +} + +// Convert_core_ComponentStatus_To_v1_ComponentStatus is an autogenerated conversion function. +func Convert_core_ComponentStatus_To_v1_ComponentStatus(in *core.ComponentStatus, out *v1.ComponentStatus, s conversion.Scope) error { + return autoConvert_core_ComponentStatus_To_v1_ComponentStatus(in, out, s) +} + +func autoConvert_v1_ComponentStatusList_To_core_ComponentStatusList(in *v1.ComponentStatusList, out *core.ComponentStatusList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]core.ComponentStatus)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1_ComponentStatusList_To_core_ComponentStatusList is an autogenerated conversion function. +func Convert_v1_ComponentStatusList_To_core_ComponentStatusList(in *v1.ComponentStatusList, out *core.ComponentStatusList, s conversion.Scope) error { + return autoConvert_v1_ComponentStatusList_To_core_ComponentStatusList(in, out, s) +} + +func autoConvert_core_ComponentStatusList_To_v1_ComponentStatusList(in *core.ComponentStatusList, out *v1.ComponentStatusList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]v1.ComponentStatus)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_core_ComponentStatusList_To_v1_ComponentStatusList is an autogenerated conversion function. +func Convert_core_ComponentStatusList_To_v1_ComponentStatusList(in *core.ComponentStatusList, out *v1.ComponentStatusList, s conversion.Scope) error { + return autoConvert_core_ComponentStatusList_To_v1_ComponentStatusList(in, out, s) +} + +func autoConvert_v1_ConfigMap_To_core_ConfigMap(in *v1.ConfigMap, out *core.ConfigMap, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + out.Immutable = (*bool)(unsafe.Pointer(in.Immutable)) + out.Data = *(*map[string]string)(unsafe.Pointer(&in.Data)) + out.BinaryData = *(*map[string][]byte)(unsafe.Pointer(&in.BinaryData)) + return nil +} + +// Convert_v1_ConfigMap_To_core_ConfigMap is an autogenerated conversion function. +func Convert_v1_ConfigMap_To_core_ConfigMap(in *v1.ConfigMap, out *core.ConfigMap, s conversion.Scope) error { + return autoConvert_v1_ConfigMap_To_core_ConfigMap(in, out, s) +} + +func autoConvert_core_ConfigMap_To_v1_ConfigMap(in *core.ConfigMap, out *v1.ConfigMap, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + out.Immutable = (*bool)(unsafe.Pointer(in.Immutable)) + out.Data = *(*map[string]string)(unsafe.Pointer(&in.Data)) + out.BinaryData = *(*map[string][]byte)(unsafe.Pointer(&in.BinaryData)) + return nil +} + +// Convert_core_ConfigMap_To_v1_ConfigMap is an autogenerated conversion function. +func Convert_core_ConfigMap_To_v1_ConfigMap(in *core.ConfigMap, out *v1.ConfigMap, s conversion.Scope) error { + return autoConvert_core_ConfigMap_To_v1_ConfigMap(in, out, s) +} + +func autoConvert_v1_ConfigMapEnvSource_To_core_ConfigMapEnvSource(in *v1.ConfigMapEnvSource, out *core.ConfigMapEnvSource, s conversion.Scope) error { + if err := Convert_v1_LocalObjectReference_To_core_LocalObjectReference(&in.LocalObjectReference, &out.LocalObjectReference, s); err != nil { + return err + } + out.Optional = (*bool)(unsafe.Pointer(in.Optional)) + return nil +} + +// Convert_v1_ConfigMapEnvSource_To_core_ConfigMapEnvSource is an autogenerated conversion function. +func Convert_v1_ConfigMapEnvSource_To_core_ConfigMapEnvSource(in *v1.ConfigMapEnvSource, out *core.ConfigMapEnvSource, s conversion.Scope) error { + return autoConvert_v1_ConfigMapEnvSource_To_core_ConfigMapEnvSource(in, out, s) +} + +func autoConvert_core_ConfigMapEnvSource_To_v1_ConfigMapEnvSource(in *core.ConfigMapEnvSource, out *v1.ConfigMapEnvSource, s conversion.Scope) error { + if err := Convert_core_LocalObjectReference_To_v1_LocalObjectReference(&in.LocalObjectReference, &out.LocalObjectReference, s); err != nil { + return err + } + out.Optional = (*bool)(unsafe.Pointer(in.Optional)) + return nil +} + +// Convert_core_ConfigMapEnvSource_To_v1_ConfigMapEnvSource is an autogenerated conversion function. +func Convert_core_ConfigMapEnvSource_To_v1_ConfigMapEnvSource(in *core.ConfigMapEnvSource, out *v1.ConfigMapEnvSource, s conversion.Scope) error { + return autoConvert_core_ConfigMapEnvSource_To_v1_ConfigMapEnvSource(in, out, s) +} + +func autoConvert_v1_ConfigMapKeySelector_To_core_ConfigMapKeySelector(in *v1.ConfigMapKeySelector, out *core.ConfigMapKeySelector, s conversion.Scope) error { + if err := Convert_v1_LocalObjectReference_To_core_LocalObjectReference(&in.LocalObjectReference, &out.LocalObjectReference, s); err != nil { + return err + } + out.Key = in.Key + out.Optional = (*bool)(unsafe.Pointer(in.Optional)) + return nil +} + +// Convert_v1_ConfigMapKeySelector_To_core_ConfigMapKeySelector is an autogenerated conversion function. +func Convert_v1_ConfigMapKeySelector_To_core_ConfigMapKeySelector(in *v1.ConfigMapKeySelector, out *core.ConfigMapKeySelector, s conversion.Scope) error { + return autoConvert_v1_ConfigMapKeySelector_To_core_ConfigMapKeySelector(in, out, s) +} + +func autoConvert_core_ConfigMapKeySelector_To_v1_ConfigMapKeySelector(in *core.ConfigMapKeySelector, out *v1.ConfigMapKeySelector, s conversion.Scope) error { + if err := Convert_core_LocalObjectReference_To_v1_LocalObjectReference(&in.LocalObjectReference, &out.LocalObjectReference, s); err != nil { + return err + } + out.Key = in.Key + out.Optional = (*bool)(unsafe.Pointer(in.Optional)) + return nil +} + +// Convert_core_ConfigMapKeySelector_To_v1_ConfigMapKeySelector is an autogenerated conversion function. +func Convert_core_ConfigMapKeySelector_To_v1_ConfigMapKeySelector(in *core.ConfigMapKeySelector, out *v1.ConfigMapKeySelector, s conversion.Scope) error { + return autoConvert_core_ConfigMapKeySelector_To_v1_ConfigMapKeySelector(in, out, s) +} + +func autoConvert_v1_ConfigMapList_To_core_ConfigMapList(in *v1.ConfigMapList, out *core.ConfigMapList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]core.ConfigMap)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1_ConfigMapList_To_core_ConfigMapList is an autogenerated conversion function. +func Convert_v1_ConfigMapList_To_core_ConfigMapList(in *v1.ConfigMapList, out *core.ConfigMapList, s conversion.Scope) error { + return autoConvert_v1_ConfigMapList_To_core_ConfigMapList(in, out, s) +} + +func autoConvert_core_ConfigMapList_To_v1_ConfigMapList(in *core.ConfigMapList, out *v1.ConfigMapList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]v1.ConfigMap)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_core_ConfigMapList_To_v1_ConfigMapList is an autogenerated conversion function. +func Convert_core_ConfigMapList_To_v1_ConfigMapList(in *core.ConfigMapList, out *v1.ConfigMapList, s conversion.Scope) error { + return autoConvert_core_ConfigMapList_To_v1_ConfigMapList(in, out, s) +} + +func autoConvert_v1_ConfigMapNodeConfigSource_To_core_ConfigMapNodeConfigSource(in *v1.ConfigMapNodeConfigSource, out *core.ConfigMapNodeConfigSource, s conversion.Scope) error { + out.Namespace = in.Namespace + out.Name = in.Name + out.UID = types.UID(in.UID) + out.ResourceVersion = in.ResourceVersion + out.KubeletConfigKey = in.KubeletConfigKey + return nil +} + +// Convert_v1_ConfigMapNodeConfigSource_To_core_ConfigMapNodeConfigSource is an autogenerated conversion function. +func Convert_v1_ConfigMapNodeConfigSource_To_core_ConfigMapNodeConfigSource(in *v1.ConfigMapNodeConfigSource, out *core.ConfigMapNodeConfigSource, s conversion.Scope) error { + return autoConvert_v1_ConfigMapNodeConfigSource_To_core_ConfigMapNodeConfigSource(in, out, s) +} + +func autoConvert_core_ConfigMapNodeConfigSource_To_v1_ConfigMapNodeConfigSource(in *core.ConfigMapNodeConfigSource, out *v1.ConfigMapNodeConfigSource, s conversion.Scope) error { + out.Namespace = in.Namespace + out.Name = in.Name + out.UID = types.UID(in.UID) + out.ResourceVersion = in.ResourceVersion + out.KubeletConfigKey = in.KubeletConfigKey + return nil +} + +// Convert_core_ConfigMapNodeConfigSource_To_v1_ConfigMapNodeConfigSource is an autogenerated conversion function. +func Convert_core_ConfigMapNodeConfigSource_To_v1_ConfigMapNodeConfigSource(in *core.ConfigMapNodeConfigSource, out *v1.ConfigMapNodeConfigSource, s conversion.Scope) error { + return autoConvert_core_ConfigMapNodeConfigSource_To_v1_ConfigMapNodeConfigSource(in, out, s) +} + +func autoConvert_v1_ConfigMapProjection_To_core_ConfigMapProjection(in *v1.ConfigMapProjection, out *core.ConfigMapProjection, s conversion.Scope) error { + if err := Convert_v1_LocalObjectReference_To_core_LocalObjectReference(&in.LocalObjectReference, &out.LocalObjectReference, s); err != nil { + return err + } + out.Items = *(*[]core.KeyToPath)(unsafe.Pointer(&in.Items)) + out.Optional = (*bool)(unsafe.Pointer(in.Optional)) + return nil +} + +// Convert_v1_ConfigMapProjection_To_core_ConfigMapProjection is an autogenerated conversion function. +func Convert_v1_ConfigMapProjection_To_core_ConfigMapProjection(in *v1.ConfigMapProjection, out *core.ConfigMapProjection, s conversion.Scope) error { + return autoConvert_v1_ConfigMapProjection_To_core_ConfigMapProjection(in, out, s) +} + +func autoConvert_core_ConfigMapProjection_To_v1_ConfigMapProjection(in *core.ConfigMapProjection, out *v1.ConfigMapProjection, s conversion.Scope) error { + if err := Convert_core_LocalObjectReference_To_v1_LocalObjectReference(&in.LocalObjectReference, &out.LocalObjectReference, s); err != nil { + return err + } + out.Items = *(*[]v1.KeyToPath)(unsafe.Pointer(&in.Items)) + out.Optional = (*bool)(unsafe.Pointer(in.Optional)) + return nil +} + +// Convert_core_ConfigMapProjection_To_v1_ConfigMapProjection is an autogenerated conversion function. +func Convert_core_ConfigMapProjection_To_v1_ConfigMapProjection(in *core.ConfigMapProjection, out *v1.ConfigMapProjection, s conversion.Scope) error { + return autoConvert_core_ConfigMapProjection_To_v1_ConfigMapProjection(in, out, s) +} + +func autoConvert_v1_ConfigMapVolumeSource_To_core_ConfigMapVolumeSource(in *v1.ConfigMapVolumeSource, out *core.ConfigMapVolumeSource, s conversion.Scope) error { + if err := Convert_v1_LocalObjectReference_To_core_LocalObjectReference(&in.LocalObjectReference, &out.LocalObjectReference, s); err != nil { + return err + } + out.Items = *(*[]core.KeyToPath)(unsafe.Pointer(&in.Items)) + out.DefaultMode = (*int32)(unsafe.Pointer(in.DefaultMode)) + out.Optional = (*bool)(unsafe.Pointer(in.Optional)) + return nil +} + +// Convert_v1_ConfigMapVolumeSource_To_core_ConfigMapVolumeSource is an autogenerated conversion function. +func Convert_v1_ConfigMapVolumeSource_To_core_ConfigMapVolumeSource(in *v1.ConfigMapVolumeSource, out *core.ConfigMapVolumeSource, s conversion.Scope) error { + return autoConvert_v1_ConfigMapVolumeSource_To_core_ConfigMapVolumeSource(in, out, s) +} + +func autoConvert_core_ConfigMapVolumeSource_To_v1_ConfigMapVolumeSource(in *core.ConfigMapVolumeSource, out *v1.ConfigMapVolumeSource, s conversion.Scope) error { + if err := Convert_core_LocalObjectReference_To_v1_LocalObjectReference(&in.LocalObjectReference, &out.LocalObjectReference, s); err != nil { + return err + } + out.Items = *(*[]v1.KeyToPath)(unsafe.Pointer(&in.Items)) + out.DefaultMode = (*int32)(unsafe.Pointer(in.DefaultMode)) + out.Optional = (*bool)(unsafe.Pointer(in.Optional)) + return nil +} + +// Convert_core_ConfigMapVolumeSource_To_v1_ConfigMapVolumeSource is an autogenerated conversion function. +func Convert_core_ConfigMapVolumeSource_To_v1_ConfigMapVolumeSource(in *core.ConfigMapVolumeSource, out *v1.ConfigMapVolumeSource, s conversion.Scope) error { + return autoConvert_core_ConfigMapVolumeSource_To_v1_ConfigMapVolumeSource(in, out, s) +} + +func autoConvert_v1_Container_To_core_Container(in *v1.Container, out *core.Container, s conversion.Scope) error { + out.Name = in.Name + out.Image = in.Image + out.Command = *(*[]string)(unsafe.Pointer(&in.Command)) + out.Args = *(*[]string)(unsafe.Pointer(&in.Args)) + out.WorkingDir = in.WorkingDir + out.Ports = *(*[]core.ContainerPort)(unsafe.Pointer(&in.Ports)) + out.EnvFrom = *(*[]core.EnvFromSource)(unsafe.Pointer(&in.EnvFrom)) + out.Env = *(*[]core.EnvVar)(unsafe.Pointer(&in.Env)) + if err := Convert_v1_ResourceRequirements_To_core_ResourceRequirements(&in.Resources, &out.Resources, s); err != nil { + return err + } + out.VolumeMounts = *(*[]core.VolumeMount)(unsafe.Pointer(&in.VolumeMounts)) + out.VolumeDevices = *(*[]core.VolumeDevice)(unsafe.Pointer(&in.VolumeDevices)) + out.LivenessProbe = (*core.Probe)(unsafe.Pointer(in.LivenessProbe)) + out.ReadinessProbe = (*core.Probe)(unsafe.Pointer(in.ReadinessProbe)) + out.StartupProbe = (*core.Probe)(unsafe.Pointer(in.StartupProbe)) + out.Lifecycle = (*core.Lifecycle)(unsafe.Pointer(in.Lifecycle)) + out.TerminationMessagePath = in.TerminationMessagePath + out.TerminationMessagePolicy = core.TerminationMessagePolicy(in.TerminationMessagePolicy) + out.ImagePullPolicy = core.PullPolicy(in.ImagePullPolicy) + out.SecurityContext = (*core.SecurityContext)(unsafe.Pointer(in.SecurityContext)) + out.Stdin = in.Stdin + out.StdinOnce = in.StdinOnce + out.TTY = in.TTY + return nil +} + +// Convert_v1_Container_To_core_Container is an autogenerated conversion function. +func Convert_v1_Container_To_core_Container(in *v1.Container, out *core.Container, s conversion.Scope) error { + return autoConvert_v1_Container_To_core_Container(in, out, s) +} + +func autoConvert_core_Container_To_v1_Container(in *core.Container, out *v1.Container, s conversion.Scope) error { + out.Name = in.Name + out.Image = in.Image + out.Command = *(*[]string)(unsafe.Pointer(&in.Command)) + out.Args = *(*[]string)(unsafe.Pointer(&in.Args)) + out.WorkingDir = in.WorkingDir + out.Ports = *(*[]v1.ContainerPort)(unsafe.Pointer(&in.Ports)) + out.EnvFrom = *(*[]v1.EnvFromSource)(unsafe.Pointer(&in.EnvFrom)) + out.Env = *(*[]v1.EnvVar)(unsafe.Pointer(&in.Env)) + if err := Convert_core_ResourceRequirements_To_v1_ResourceRequirements(&in.Resources, &out.Resources, s); err != nil { + return err + } + out.VolumeMounts = *(*[]v1.VolumeMount)(unsafe.Pointer(&in.VolumeMounts)) + out.VolumeDevices = *(*[]v1.VolumeDevice)(unsafe.Pointer(&in.VolumeDevices)) + out.LivenessProbe = (*v1.Probe)(unsafe.Pointer(in.LivenessProbe)) + out.ReadinessProbe = (*v1.Probe)(unsafe.Pointer(in.ReadinessProbe)) + out.StartupProbe = (*v1.Probe)(unsafe.Pointer(in.StartupProbe)) + out.Lifecycle = (*v1.Lifecycle)(unsafe.Pointer(in.Lifecycle)) + out.TerminationMessagePath = in.TerminationMessagePath + out.TerminationMessagePolicy = v1.TerminationMessagePolicy(in.TerminationMessagePolicy) + out.ImagePullPolicy = v1.PullPolicy(in.ImagePullPolicy) + out.SecurityContext = (*v1.SecurityContext)(unsafe.Pointer(in.SecurityContext)) + out.Stdin = in.Stdin + out.StdinOnce = in.StdinOnce + out.TTY = in.TTY + return nil +} + +// Convert_core_Container_To_v1_Container is an autogenerated conversion function. +func Convert_core_Container_To_v1_Container(in *core.Container, out *v1.Container, s conversion.Scope) error { + return autoConvert_core_Container_To_v1_Container(in, out, s) +} + +func autoConvert_v1_ContainerImage_To_core_ContainerImage(in *v1.ContainerImage, out *core.ContainerImage, s conversion.Scope) error { + out.Names = *(*[]string)(unsafe.Pointer(&in.Names)) + out.SizeBytes = in.SizeBytes + return nil +} + +// Convert_v1_ContainerImage_To_core_ContainerImage is an autogenerated conversion function. +func Convert_v1_ContainerImage_To_core_ContainerImage(in *v1.ContainerImage, out *core.ContainerImage, s conversion.Scope) error { + return autoConvert_v1_ContainerImage_To_core_ContainerImage(in, out, s) +} + +func autoConvert_core_ContainerImage_To_v1_ContainerImage(in *core.ContainerImage, out *v1.ContainerImage, s conversion.Scope) error { + out.Names = *(*[]string)(unsafe.Pointer(&in.Names)) + out.SizeBytes = in.SizeBytes + return nil +} + +// Convert_core_ContainerImage_To_v1_ContainerImage is an autogenerated conversion function. +func Convert_core_ContainerImage_To_v1_ContainerImage(in *core.ContainerImage, out *v1.ContainerImage, s conversion.Scope) error { + return autoConvert_core_ContainerImage_To_v1_ContainerImage(in, out, s) +} + +func autoConvert_v1_ContainerPort_To_core_ContainerPort(in *v1.ContainerPort, out *core.ContainerPort, s conversion.Scope) error { + out.Name = in.Name + out.HostPort = in.HostPort + out.ContainerPort = in.ContainerPort + out.Protocol = core.Protocol(in.Protocol) + out.HostIP = in.HostIP + return nil +} + +// Convert_v1_ContainerPort_To_core_ContainerPort is an autogenerated conversion function. +func Convert_v1_ContainerPort_To_core_ContainerPort(in *v1.ContainerPort, out *core.ContainerPort, s conversion.Scope) error { + return autoConvert_v1_ContainerPort_To_core_ContainerPort(in, out, s) +} + +func autoConvert_core_ContainerPort_To_v1_ContainerPort(in *core.ContainerPort, out *v1.ContainerPort, s conversion.Scope) error { + out.Name = in.Name + out.HostPort = in.HostPort + out.ContainerPort = in.ContainerPort + out.Protocol = v1.Protocol(in.Protocol) + out.HostIP = in.HostIP + return nil +} + +// Convert_core_ContainerPort_To_v1_ContainerPort is an autogenerated conversion function. +func Convert_core_ContainerPort_To_v1_ContainerPort(in *core.ContainerPort, out *v1.ContainerPort, s conversion.Scope) error { + return autoConvert_core_ContainerPort_To_v1_ContainerPort(in, out, s) +} + +func autoConvert_v1_ContainerState_To_core_ContainerState(in *v1.ContainerState, out *core.ContainerState, s conversion.Scope) error { + out.Waiting = (*core.ContainerStateWaiting)(unsafe.Pointer(in.Waiting)) + out.Running = (*core.ContainerStateRunning)(unsafe.Pointer(in.Running)) + out.Terminated = (*core.ContainerStateTerminated)(unsafe.Pointer(in.Terminated)) + return nil +} + +// Convert_v1_ContainerState_To_core_ContainerState is an autogenerated conversion function. +func Convert_v1_ContainerState_To_core_ContainerState(in *v1.ContainerState, out *core.ContainerState, s conversion.Scope) error { + return autoConvert_v1_ContainerState_To_core_ContainerState(in, out, s) +} + +func autoConvert_core_ContainerState_To_v1_ContainerState(in *core.ContainerState, out *v1.ContainerState, s conversion.Scope) error { + out.Waiting = (*v1.ContainerStateWaiting)(unsafe.Pointer(in.Waiting)) + out.Running = (*v1.ContainerStateRunning)(unsafe.Pointer(in.Running)) + out.Terminated = (*v1.ContainerStateTerminated)(unsafe.Pointer(in.Terminated)) + return nil +} + +// Convert_core_ContainerState_To_v1_ContainerState is an autogenerated conversion function. +func Convert_core_ContainerState_To_v1_ContainerState(in *core.ContainerState, out *v1.ContainerState, s conversion.Scope) error { + return autoConvert_core_ContainerState_To_v1_ContainerState(in, out, s) +} + +func autoConvert_v1_ContainerStateRunning_To_core_ContainerStateRunning(in *v1.ContainerStateRunning, out *core.ContainerStateRunning, s conversion.Scope) error { + out.StartedAt = in.StartedAt + return nil +} + +// Convert_v1_ContainerStateRunning_To_core_ContainerStateRunning is an autogenerated conversion function. +func Convert_v1_ContainerStateRunning_To_core_ContainerStateRunning(in *v1.ContainerStateRunning, out *core.ContainerStateRunning, s conversion.Scope) error { + return autoConvert_v1_ContainerStateRunning_To_core_ContainerStateRunning(in, out, s) +} + +func autoConvert_core_ContainerStateRunning_To_v1_ContainerStateRunning(in *core.ContainerStateRunning, out *v1.ContainerStateRunning, s conversion.Scope) error { + out.StartedAt = in.StartedAt + return nil +} + +// Convert_core_ContainerStateRunning_To_v1_ContainerStateRunning is an autogenerated conversion function. +func Convert_core_ContainerStateRunning_To_v1_ContainerStateRunning(in *core.ContainerStateRunning, out *v1.ContainerStateRunning, s conversion.Scope) error { + return autoConvert_core_ContainerStateRunning_To_v1_ContainerStateRunning(in, out, s) +} + +func autoConvert_v1_ContainerStateTerminated_To_core_ContainerStateTerminated(in *v1.ContainerStateTerminated, out *core.ContainerStateTerminated, s conversion.Scope) error { + out.ExitCode = in.ExitCode + out.Signal = in.Signal + out.Reason = in.Reason + out.Message = in.Message + out.StartedAt = in.StartedAt + out.FinishedAt = in.FinishedAt + out.ContainerID = in.ContainerID + return nil +} + +// Convert_v1_ContainerStateTerminated_To_core_ContainerStateTerminated is an autogenerated conversion function. +func Convert_v1_ContainerStateTerminated_To_core_ContainerStateTerminated(in *v1.ContainerStateTerminated, out *core.ContainerStateTerminated, s conversion.Scope) error { + return autoConvert_v1_ContainerStateTerminated_To_core_ContainerStateTerminated(in, out, s) +} + +func autoConvert_core_ContainerStateTerminated_To_v1_ContainerStateTerminated(in *core.ContainerStateTerminated, out *v1.ContainerStateTerminated, s conversion.Scope) error { + out.ExitCode = in.ExitCode + out.Signal = in.Signal + out.Reason = in.Reason + out.Message = in.Message + out.StartedAt = in.StartedAt + out.FinishedAt = in.FinishedAt + out.ContainerID = in.ContainerID + return nil +} + +// Convert_core_ContainerStateTerminated_To_v1_ContainerStateTerminated is an autogenerated conversion function. +func Convert_core_ContainerStateTerminated_To_v1_ContainerStateTerminated(in *core.ContainerStateTerminated, out *v1.ContainerStateTerminated, s conversion.Scope) error { + return autoConvert_core_ContainerStateTerminated_To_v1_ContainerStateTerminated(in, out, s) +} + +func autoConvert_v1_ContainerStateWaiting_To_core_ContainerStateWaiting(in *v1.ContainerStateWaiting, out *core.ContainerStateWaiting, s conversion.Scope) error { + out.Reason = in.Reason + out.Message = in.Message + return nil +} + +// Convert_v1_ContainerStateWaiting_To_core_ContainerStateWaiting is an autogenerated conversion function. +func Convert_v1_ContainerStateWaiting_To_core_ContainerStateWaiting(in *v1.ContainerStateWaiting, out *core.ContainerStateWaiting, s conversion.Scope) error { + return autoConvert_v1_ContainerStateWaiting_To_core_ContainerStateWaiting(in, out, s) +} + +func autoConvert_core_ContainerStateWaiting_To_v1_ContainerStateWaiting(in *core.ContainerStateWaiting, out *v1.ContainerStateWaiting, s conversion.Scope) error { + out.Reason = in.Reason + out.Message = in.Message + return nil +} + +// Convert_core_ContainerStateWaiting_To_v1_ContainerStateWaiting is an autogenerated conversion function. +func Convert_core_ContainerStateWaiting_To_v1_ContainerStateWaiting(in *core.ContainerStateWaiting, out *v1.ContainerStateWaiting, s conversion.Scope) error { + return autoConvert_core_ContainerStateWaiting_To_v1_ContainerStateWaiting(in, out, s) +} + +func autoConvert_v1_ContainerStatus_To_core_ContainerStatus(in *v1.ContainerStatus, out *core.ContainerStatus, s conversion.Scope) error { + out.Name = in.Name + if err := Convert_v1_ContainerState_To_core_ContainerState(&in.State, &out.State, s); err != nil { + return err + } + if err := Convert_v1_ContainerState_To_core_ContainerState(&in.LastTerminationState, &out.LastTerminationState, s); err != nil { + return err + } + out.Ready = in.Ready + out.RestartCount = in.RestartCount + out.Image = in.Image + out.ImageID = in.ImageID + out.ContainerID = in.ContainerID + out.Started = (*bool)(unsafe.Pointer(in.Started)) + return nil +} + +// Convert_v1_ContainerStatus_To_core_ContainerStatus is an autogenerated conversion function. +func Convert_v1_ContainerStatus_To_core_ContainerStatus(in *v1.ContainerStatus, out *core.ContainerStatus, s conversion.Scope) error { + return autoConvert_v1_ContainerStatus_To_core_ContainerStatus(in, out, s) +} + +func autoConvert_core_ContainerStatus_To_v1_ContainerStatus(in *core.ContainerStatus, out *v1.ContainerStatus, s conversion.Scope) error { + out.Name = in.Name + if err := Convert_core_ContainerState_To_v1_ContainerState(&in.State, &out.State, s); err != nil { + return err + } + if err := Convert_core_ContainerState_To_v1_ContainerState(&in.LastTerminationState, &out.LastTerminationState, s); err != nil { + return err + } + out.Ready = in.Ready + out.RestartCount = in.RestartCount + out.Image = in.Image + out.ImageID = in.ImageID + out.ContainerID = in.ContainerID + out.Started = (*bool)(unsafe.Pointer(in.Started)) + return nil +} + +// Convert_core_ContainerStatus_To_v1_ContainerStatus is an autogenerated conversion function. +func Convert_core_ContainerStatus_To_v1_ContainerStatus(in *core.ContainerStatus, out *v1.ContainerStatus, s conversion.Scope) error { + return autoConvert_core_ContainerStatus_To_v1_ContainerStatus(in, out, s) +} + +func autoConvert_v1_DaemonEndpoint_To_core_DaemonEndpoint(in *v1.DaemonEndpoint, out *core.DaemonEndpoint, s conversion.Scope) error { + out.Port = in.Port + return nil +} + +// Convert_v1_DaemonEndpoint_To_core_DaemonEndpoint is an autogenerated conversion function. +func Convert_v1_DaemonEndpoint_To_core_DaemonEndpoint(in *v1.DaemonEndpoint, out *core.DaemonEndpoint, s conversion.Scope) error { + return autoConvert_v1_DaemonEndpoint_To_core_DaemonEndpoint(in, out, s) +} + +func autoConvert_core_DaemonEndpoint_To_v1_DaemonEndpoint(in *core.DaemonEndpoint, out *v1.DaemonEndpoint, s conversion.Scope) error { + out.Port = in.Port + return nil +} + +// Convert_core_DaemonEndpoint_To_v1_DaemonEndpoint is an autogenerated conversion function. +func Convert_core_DaemonEndpoint_To_v1_DaemonEndpoint(in *core.DaemonEndpoint, out *v1.DaemonEndpoint, s conversion.Scope) error { + return autoConvert_core_DaemonEndpoint_To_v1_DaemonEndpoint(in, out, s) +} + +func autoConvert_v1_DownwardAPIProjection_To_core_DownwardAPIProjection(in *v1.DownwardAPIProjection, out *core.DownwardAPIProjection, s conversion.Scope) error { + out.Items = *(*[]core.DownwardAPIVolumeFile)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1_DownwardAPIProjection_To_core_DownwardAPIProjection is an autogenerated conversion function. +func Convert_v1_DownwardAPIProjection_To_core_DownwardAPIProjection(in *v1.DownwardAPIProjection, out *core.DownwardAPIProjection, s conversion.Scope) error { + return autoConvert_v1_DownwardAPIProjection_To_core_DownwardAPIProjection(in, out, s) +} + +func autoConvert_core_DownwardAPIProjection_To_v1_DownwardAPIProjection(in *core.DownwardAPIProjection, out *v1.DownwardAPIProjection, s conversion.Scope) error { + out.Items = *(*[]v1.DownwardAPIVolumeFile)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_core_DownwardAPIProjection_To_v1_DownwardAPIProjection is an autogenerated conversion function. +func Convert_core_DownwardAPIProjection_To_v1_DownwardAPIProjection(in *core.DownwardAPIProjection, out *v1.DownwardAPIProjection, s conversion.Scope) error { + return autoConvert_core_DownwardAPIProjection_To_v1_DownwardAPIProjection(in, out, s) +} + +func autoConvert_v1_DownwardAPIVolumeFile_To_core_DownwardAPIVolumeFile(in *v1.DownwardAPIVolumeFile, out *core.DownwardAPIVolumeFile, s conversion.Scope) error { + out.Path = in.Path + out.FieldRef = (*core.ObjectFieldSelector)(unsafe.Pointer(in.FieldRef)) + out.ResourceFieldRef = (*core.ResourceFieldSelector)(unsafe.Pointer(in.ResourceFieldRef)) + out.Mode = (*int32)(unsafe.Pointer(in.Mode)) + return nil +} + +// Convert_v1_DownwardAPIVolumeFile_To_core_DownwardAPIVolumeFile is an autogenerated conversion function. +func Convert_v1_DownwardAPIVolumeFile_To_core_DownwardAPIVolumeFile(in *v1.DownwardAPIVolumeFile, out *core.DownwardAPIVolumeFile, s conversion.Scope) error { + return autoConvert_v1_DownwardAPIVolumeFile_To_core_DownwardAPIVolumeFile(in, out, s) +} + +func autoConvert_core_DownwardAPIVolumeFile_To_v1_DownwardAPIVolumeFile(in *core.DownwardAPIVolumeFile, out *v1.DownwardAPIVolumeFile, s conversion.Scope) error { + out.Path = in.Path + out.FieldRef = (*v1.ObjectFieldSelector)(unsafe.Pointer(in.FieldRef)) + out.ResourceFieldRef = (*v1.ResourceFieldSelector)(unsafe.Pointer(in.ResourceFieldRef)) + out.Mode = (*int32)(unsafe.Pointer(in.Mode)) + return nil +} + +// Convert_core_DownwardAPIVolumeFile_To_v1_DownwardAPIVolumeFile is an autogenerated conversion function. +func Convert_core_DownwardAPIVolumeFile_To_v1_DownwardAPIVolumeFile(in *core.DownwardAPIVolumeFile, out *v1.DownwardAPIVolumeFile, s conversion.Scope) error { + return autoConvert_core_DownwardAPIVolumeFile_To_v1_DownwardAPIVolumeFile(in, out, s) +} + +func autoConvert_v1_DownwardAPIVolumeSource_To_core_DownwardAPIVolumeSource(in *v1.DownwardAPIVolumeSource, out *core.DownwardAPIVolumeSource, s conversion.Scope) error { + out.Items = *(*[]core.DownwardAPIVolumeFile)(unsafe.Pointer(&in.Items)) + out.DefaultMode = (*int32)(unsafe.Pointer(in.DefaultMode)) + return nil +} + +// Convert_v1_DownwardAPIVolumeSource_To_core_DownwardAPIVolumeSource is an autogenerated conversion function. +func Convert_v1_DownwardAPIVolumeSource_To_core_DownwardAPIVolumeSource(in *v1.DownwardAPIVolumeSource, out *core.DownwardAPIVolumeSource, s conversion.Scope) error { + return autoConvert_v1_DownwardAPIVolumeSource_To_core_DownwardAPIVolumeSource(in, out, s) +} + +func autoConvert_core_DownwardAPIVolumeSource_To_v1_DownwardAPIVolumeSource(in *core.DownwardAPIVolumeSource, out *v1.DownwardAPIVolumeSource, s conversion.Scope) error { + out.Items = *(*[]v1.DownwardAPIVolumeFile)(unsafe.Pointer(&in.Items)) + out.DefaultMode = (*int32)(unsafe.Pointer(in.DefaultMode)) + return nil +} + +// Convert_core_DownwardAPIVolumeSource_To_v1_DownwardAPIVolumeSource is an autogenerated conversion function. +func Convert_core_DownwardAPIVolumeSource_To_v1_DownwardAPIVolumeSource(in *core.DownwardAPIVolumeSource, out *v1.DownwardAPIVolumeSource, s conversion.Scope) error { + return autoConvert_core_DownwardAPIVolumeSource_To_v1_DownwardAPIVolumeSource(in, out, s) +} + +func autoConvert_v1_EmptyDirVolumeSource_To_core_EmptyDirVolumeSource(in *v1.EmptyDirVolumeSource, out *core.EmptyDirVolumeSource, s conversion.Scope) error { + out.Medium = core.StorageMedium(in.Medium) + out.SizeLimit = (*resource.Quantity)(unsafe.Pointer(in.SizeLimit)) + return nil +} + +// Convert_v1_EmptyDirVolumeSource_To_core_EmptyDirVolumeSource is an autogenerated conversion function. +func Convert_v1_EmptyDirVolumeSource_To_core_EmptyDirVolumeSource(in *v1.EmptyDirVolumeSource, out *core.EmptyDirVolumeSource, s conversion.Scope) error { + return autoConvert_v1_EmptyDirVolumeSource_To_core_EmptyDirVolumeSource(in, out, s) +} + +func autoConvert_core_EmptyDirVolumeSource_To_v1_EmptyDirVolumeSource(in *core.EmptyDirVolumeSource, out *v1.EmptyDirVolumeSource, s conversion.Scope) error { + out.Medium = v1.StorageMedium(in.Medium) + out.SizeLimit = (*resource.Quantity)(unsafe.Pointer(in.SizeLimit)) + return nil +} + +// Convert_core_EmptyDirVolumeSource_To_v1_EmptyDirVolumeSource is an autogenerated conversion function. +func Convert_core_EmptyDirVolumeSource_To_v1_EmptyDirVolumeSource(in *core.EmptyDirVolumeSource, out *v1.EmptyDirVolumeSource, s conversion.Scope) error { + return autoConvert_core_EmptyDirVolumeSource_To_v1_EmptyDirVolumeSource(in, out, s) +} + +func autoConvert_v1_EndpointAddress_To_core_EndpointAddress(in *v1.EndpointAddress, out *core.EndpointAddress, s conversion.Scope) error { + out.IP = in.IP + out.Hostname = in.Hostname + out.NodeName = (*string)(unsafe.Pointer(in.NodeName)) + out.TargetRef = (*core.ObjectReference)(unsafe.Pointer(in.TargetRef)) + return nil +} + +// Convert_v1_EndpointAddress_To_core_EndpointAddress is an autogenerated conversion function. +func Convert_v1_EndpointAddress_To_core_EndpointAddress(in *v1.EndpointAddress, out *core.EndpointAddress, s conversion.Scope) error { + return autoConvert_v1_EndpointAddress_To_core_EndpointAddress(in, out, s) +} + +func autoConvert_core_EndpointAddress_To_v1_EndpointAddress(in *core.EndpointAddress, out *v1.EndpointAddress, s conversion.Scope) error { + out.IP = in.IP + out.Hostname = in.Hostname + out.NodeName = (*string)(unsafe.Pointer(in.NodeName)) + out.TargetRef = (*v1.ObjectReference)(unsafe.Pointer(in.TargetRef)) + return nil +} + +// Convert_core_EndpointAddress_To_v1_EndpointAddress is an autogenerated conversion function. +func Convert_core_EndpointAddress_To_v1_EndpointAddress(in *core.EndpointAddress, out *v1.EndpointAddress, s conversion.Scope) error { + return autoConvert_core_EndpointAddress_To_v1_EndpointAddress(in, out, s) +} + +func autoConvert_v1_EndpointPort_To_core_EndpointPort(in *v1.EndpointPort, out *core.EndpointPort, s conversion.Scope) error { + out.Name = in.Name + out.Port = in.Port + out.Protocol = core.Protocol(in.Protocol) + out.AppProtocol = (*string)(unsafe.Pointer(in.AppProtocol)) + return nil +} + +// Convert_v1_EndpointPort_To_core_EndpointPort is an autogenerated conversion function. +func Convert_v1_EndpointPort_To_core_EndpointPort(in *v1.EndpointPort, out *core.EndpointPort, s conversion.Scope) error { + return autoConvert_v1_EndpointPort_To_core_EndpointPort(in, out, s) +} + +func autoConvert_core_EndpointPort_To_v1_EndpointPort(in *core.EndpointPort, out *v1.EndpointPort, s conversion.Scope) error { + out.Name = in.Name + out.Port = in.Port + out.Protocol = v1.Protocol(in.Protocol) + out.AppProtocol = (*string)(unsafe.Pointer(in.AppProtocol)) + return nil +} + +// Convert_core_EndpointPort_To_v1_EndpointPort is an autogenerated conversion function. +func Convert_core_EndpointPort_To_v1_EndpointPort(in *core.EndpointPort, out *v1.EndpointPort, s conversion.Scope) error { + return autoConvert_core_EndpointPort_To_v1_EndpointPort(in, out, s) +} + +func autoConvert_v1_EndpointSubset_To_core_EndpointSubset(in *v1.EndpointSubset, out *core.EndpointSubset, s conversion.Scope) error { + out.Addresses = *(*[]core.EndpointAddress)(unsafe.Pointer(&in.Addresses)) + out.NotReadyAddresses = *(*[]core.EndpointAddress)(unsafe.Pointer(&in.NotReadyAddresses)) + out.Ports = *(*[]core.EndpointPort)(unsafe.Pointer(&in.Ports)) + return nil +} + +// Convert_v1_EndpointSubset_To_core_EndpointSubset is an autogenerated conversion function. +func Convert_v1_EndpointSubset_To_core_EndpointSubset(in *v1.EndpointSubset, out *core.EndpointSubset, s conversion.Scope) error { + return autoConvert_v1_EndpointSubset_To_core_EndpointSubset(in, out, s) +} + +func autoConvert_core_EndpointSubset_To_v1_EndpointSubset(in *core.EndpointSubset, out *v1.EndpointSubset, s conversion.Scope) error { + out.Addresses = *(*[]v1.EndpointAddress)(unsafe.Pointer(&in.Addresses)) + out.NotReadyAddresses = *(*[]v1.EndpointAddress)(unsafe.Pointer(&in.NotReadyAddresses)) + out.Ports = *(*[]v1.EndpointPort)(unsafe.Pointer(&in.Ports)) + return nil +} + +// Convert_core_EndpointSubset_To_v1_EndpointSubset is an autogenerated conversion function. +func Convert_core_EndpointSubset_To_v1_EndpointSubset(in *core.EndpointSubset, out *v1.EndpointSubset, s conversion.Scope) error { + return autoConvert_core_EndpointSubset_To_v1_EndpointSubset(in, out, s) +} + +func autoConvert_v1_Endpoints_To_core_Endpoints(in *v1.Endpoints, out *core.Endpoints, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + out.Subsets = *(*[]core.EndpointSubset)(unsafe.Pointer(&in.Subsets)) + return nil +} + +// Convert_v1_Endpoints_To_core_Endpoints is an autogenerated conversion function. +func Convert_v1_Endpoints_To_core_Endpoints(in *v1.Endpoints, out *core.Endpoints, s conversion.Scope) error { + return autoConvert_v1_Endpoints_To_core_Endpoints(in, out, s) +} + +func autoConvert_core_Endpoints_To_v1_Endpoints(in *core.Endpoints, out *v1.Endpoints, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + out.Subsets = *(*[]v1.EndpointSubset)(unsafe.Pointer(&in.Subsets)) + return nil +} + +// Convert_core_Endpoints_To_v1_Endpoints is an autogenerated conversion function. +func Convert_core_Endpoints_To_v1_Endpoints(in *core.Endpoints, out *v1.Endpoints, s conversion.Scope) error { + return autoConvert_core_Endpoints_To_v1_Endpoints(in, out, s) +} + +func autoConvert_v1_EndpointsList_To_core_EndpointsList(in *v1.EndpointsList, out *core.EndpointsList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]core.Endpoints)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1_EndpointsList_To_core_EndpointsList is an autogenerated conversion function. +func Convert_v1_EndpointsList_To_core_EndpointsList(in *v1.EndpointsList, out *core.EndpointsList, s conversion.Scope) error { + return autoConvert_v1_EndpointsList_To_core_EndpointsList(in, out, s) +} + +func autoConvert_core_EndpointsList_To_v1_EndpointsList(in *core.EndpointsList, out *v1.EndpointsList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]v1.Endpoints)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_core_EndpointsList_To_v1_EndpointsList is an autogenerated conversion function. +func Convert_core_EndpointsList_To_v1_EndpointsList(in *core.EndpointsList, out *v1.EndpointsList, s conversion.Scope) error { + return autoConvert_core_EndpointsList_To_v1_EndpointsList(in, out, s) +} + +func autoConvert_v1_EnvFromSource_To_core_EnvFromSource(in *v1.EnvFromSource, out *core.EnvFromSource, s conversion.Scope) error { + out.Prefix = in.Prefix + out.ConfigMapRef = (*core.ConfigMapEnvSource)(unsafe.Pointer(in.ConfigMapRef)) + out.SecretRef = (*core.SecretEnvSource)(unsafe.Pointer(in.SecretRef)) + return nil +} + +// Convert_v1_EnvFromSource_To_core_EnvFromSource is an autogenerated conversion function. +func Convert_v1_EnvFromSource_To_core_EnvFromSource(in *v1.EnvFromSource, out *core.EnvFromSource, s conversion.Scope) error { + return autoConvert_v1_EnvFromSource_To_core_EnvFromSource(in, out, s) +} + +func autoConvert_core_EnvFromSource_To_v1_EnvFromSource(in *core.EnvFromSource, out *v1.EnvFromSource, s conversion.Scope) error { + out.Prefix = in.Prefix + out.ConfigMapRef = (*v1.ConfigMapEnvSource)(unsafe.Pointer(in.ConfigMapRef)) + out.SecretRef = (*v1.SecretEnvSource)(unsafe.Pointer(in.SecretRef)) + return nil +} + +// Convert_core_EnvFromSource_To_v1_EnvFromSource is an autogenerated conversion function. +func Convert_core_EnvFromSource_To_v1_EnvFromSource(in *core.EnvFromSource, out *v1.EnvFromSource, s conversion.Scope) error { + return autoConvert_core_EnvFromSource_To_v1_EnvFromSource(in, out, s) +} + +func autoConvert_v1_EnvVar_To_core_EnvVar(in *v1.EnvVar, out *core.EnvVar, s conversion.Scope) error { + out.Name = in.Name + out.Value = in.Value + out.ValueFrom = (*core.EnvVarSource)(unsafe.Pointer(in.ValueFrom)) + return nil +} + +// Convert_v1_EnvVar_To_core_EnvVar is an autogenerated conversion function. +func Convert_v1_EnvVar_To_core_EnvVar(in *v1.EnvVar, out *core.EnvVar, s conversion.Scope) error { + return autoConvert_v1_EnvVar_To_core_EnvVar(in, out, s) +} + +func autoConvert_core_EnvVar_To_v1_EnvVar(in *core.EnvVar, out *v1.EnvVar, s conversion.Scope) error { + out.Name = in.Name + out.Value = in.Value + out.ValueFrom = (*v1.EnvVarSource)(unsafe.Pointer(in.ValueFrom)) + return nil +} + +// Convert_core_EnvVar_To_v1_EnvVar is an autogenerated conversion function. +func Convert_core_EnvVar_To_v1_EnvVar(in *core.EnvVar, out *v1.EnvVar, s conversion.Scope) error { + return autoConvert_core_EnvVar_To_v1_EnvVar(in, out, s) +} + +func autoConvert_v1_EnvVarSource_To_core_EnvVarSource(in *v1.EnvVarSource, out *core.EnvVarSource, s conversion.Scope) error { + out.FieldRef = (*core.ObjectFieldSelector)(unsafe.Pointer(in.FieldRef)) + out.ResourceFieldRef = (*core.ResourceFieldSelector)(unsafe.Pointer(in.ResourceFieldRef)) + out.ConfigMapKeyRef = (*core.ConfigMapKeySelector)(unsafe.Pointer(in.ConfigMapKeyRef)) + out.SecretKeyRef = (*core.SecretKeySelector)(unsafe.Pointer(in.SecretKeyRef)) + return nil +} + +// Convert_v1_EnvVarSource_To_core_EnvVarSource is an autogenerated conversion function. +func Convert_v1_EnvVarSource_To_core_EnvVarSource(in *v1.EnvVarSource, out *core.EnvVarSource, s conversion.Scope) error { + return autoConvert_v1_EnvVarSource_To_core_EnvVarSource(in, out, s) +} + +func autoConvert_core_EnvVarSource_To_v1_EnvVarSource(in *core.EnvVarSource, out *v1.EnvVarSource, s conversion.Scope) error { + out.FieldRef = (*v1.ObjectFieldSelector)(unsafe.Pointer(in.FieldRef)) + out.ResourceFieldRef = (*v1.ResourceFieldSelector)(unsafe.Pointer(in.ResourceFieldRef)) + out.ConfigMapKeyRef = (*v1.ConfigMapKeySelector)(unsafe.Pointer(in.ConfigMapKeyRef)) + out.SecretKeyRef = (*v1.SecretKeySelector)(unsafe.Pointer(in.SecretKeyRef)) + return nil +} + +// Convert_core_EnvVarSource_To_v1_EnvVarSource is an autogenerated conversion function. +func Convert_core_EnvVarSource_To_v1_EnvVarSource(in *core.EnvVarSource, out *v1.EnvVarSource, s conversion.Scope) error { + return autoConvert_core_EnvVarSource_To_v1_EnvVarSource(in, out, s) +} + +func autoConvert_v1_EphemeralContainer_To_core_EphemeralContainer(in *v1.EphemeralContainer, out *core.EphemeralContainer, s conversion.Scope) error { + if err := Convert_v1_EphemeralContainerCommon_To_core_EphemeralContainerCommon(&in.EphemeralContainerCommon, &out.EphemeralContainerCommon, s); err != nil { + return err + } + out.TargetContainerName = in.TargetContainerName + return nil +} + +// Convert_v1_EphemeralContainer_To_core_EphemeralContainer is an autogenerated conversion function. +func Convert_v1_EphemeralContainer_To_core_EphemeralContainer(in *v1.EphemeralContainer, out *core.EphemeralContainer, s conversion.Scope) error { + return autoConvert_v1_EphemeralContainer_To_core_EphemeralContainer(in, out, s) +} + +func autoConvert_core_EphemeralContainer_To_v1_EphemeralContainer(in *core.EphemeralContainer, out *v1.EphemeralContainer, s conversion.Scope) error { + if err := Convert_core_EphemeralContainerCommon_To_v1_EphemeralContainerCommon(&in.EphemeralContainerCommon, &out.EphemeralContainerCommon, s); err != nil { + return err + } + out.TargetContainerName = in.TargetContainerName + return nil +} + +// Convert_core_EphemeralContainer_To_v1_EphemeralContainer is an autogenerated conversion function. +func Convert_core_EphemeralContainer_To_v1_EphemeralContainer(in *core.EphemeralContainer, out *v1.EphemeralContainer, s conversion.Scope) error { + return autoConvert_core_EphemeralContainer_To_v1_EphemeralContainer(in, out, s) +} + +func autoConvert_v1_EphemeralContainerCommon_To_core_EphemeralContainerCommon(in *v1.EphemeralContainerCommon, out *core.EphemeralContainerCommon, s conversion.Scope) error { + out.Name = in.Name + out.Image = in.Image + out.Command = *(*[]string)(unsafe.Pointer(&in.Command)) + out.Args = *(*[]string)(unsafe.Pointer(&in.Args)) + out.WorkingDir = in.WorkingDir + out.Ports = *(*[]core.ContainerPort)(unsafe.Pointer(&in.Ports)) + out.EnvFrom = *(*[]core.EnvFromSource)(unsafe.Pointer(&in.EnvFrom)) + out.Env = *(*[]core.EnvVar)(unsafe.Pointer(&in.Env)) + if err := Convert_v1_ResourceRequirements_To_core_ResourceRequirements(&in.Resources, &out.Resources, s); err != nil { + return err + } + out.VolumeMounts = *(*[]core.VolumeMount)(unsafe.Pointer(&in.VolumeMounts)) + out.VolumeDevices = *(*[]core.VolumeDevice)(unsafe.Pointer(&in.VolumeDevices)) + out.LivenessProbe = (*core.Probe)(unsafe.Pointer(in.LivenessProbe)) + out.ReadinessProbe = (*core.Probe)(unsafe.Pointer(in.ReadinessProbe)) + out.StartupProbe = (*core.Probe)(unsafe.Pointer(in.StartupProbe)) + out.Lifecycle = (*core.Lifecycle)(unsafe.Pointer(in.Lifecycle)) + out.TerminationMessagePath = in.TerminationMessagePath + out.TerminationMessagePolicy = core.TerminationMessagePolicy(in.TerminationMessagePolicy) + out.ImagePullPolicy = core.PullPolicy(in.ImagePullPolicy) + out.SecurityContext = (*core.SecurityContext)(unsafe.Pointer(in.SecurityContext)) + out.Stdin = in.Stdin + out.StdinOnce = in.StdinOnce + out.TTY = in.TTY + return nil +} + +// Convert_v1_EphemeralContainerCommon_To_core_EphemeralContainerCommon is an autogenerated conversion function. +func Convert_v1_EphemeralContainerCommon_To_core_EphemeralContainerCommon(in *v1.EphemeralContainerCommon, out *core.EphemeralContainerCommon, s conversion.Scope) error { + return autoConvert_v1_EphemeralContainerCommon_To_core_EphemeralContainerCommon(in, out, s) +} + +func autoConvert_core_EphemeralContainerCommon_To_v1_EphemeralContainerCommon(in *core.EphemeralContainerCommon, out *v1.EphemeralContainerCommon, s conversion.Scope) error { + out.Name = in.Name + out.Image = in.Image + out.Command = *(*[]string)(unsafe.Pointer(&in.Command)) + out.Args = *(*[]string)(unsafe.Pointer(&in.Args)) + out.WorkingDir = in.WorkingDir + out.Ports = *(*[]v1.ContainerPort)(unsafe.Pointer(&in.Ports)) + out.EnvFrom = *(*[]v1.EnvFromSource)(unsafe.Pointer(&in.EnvFrom)) + out.Env = *(*[]v1.EnvVar)(unsafe.Pointer(&in.Env)) + if err := Convert_core_ResourceRequirements_To_v1_ResourceRequirements(&in.Resources, &out.Resources, s); err != nil { + return err + } + out.VolumeMounts = *(*[]v1.VolumeMount)(unsafe.Pointer(&in.VolumeMounts)) + out.VolumeDevices = *(*[]v1.VolumeDevice)(unsafe.Pointer(&in.VolumeDevices)) + out.LivenessProbe = (*v1.Probe)(unsafe.Pointer(in.LivenessProbe)) + out.ReadinessProbe = (*v1.Probe)(unsafe.Pointer(in.ReadinessProbe)) + out.StartupProbe = (*v1.Probe)(unsafe.Pointer(in.StartupProbe)) + out.Lifecycle = (*v1.Lifecycle)(unsafe.Pointer(in.Lifecycle)) + out.TerminationMessagePath = in.TerminationMessagePath + out.TerminationMessagePolicy = v1.TerminationMessagePolicy(in.TerminationMessagePolicy) + out.ImagePullPolicy = v1.PullPolicy(in.ImagePullPolicy) + out.SecurityContext = (*v1.SecurityContext)(unsafe.Pointer(in.SecurityContext)) + out.Stdin = in.Stdin + out.StdinOnce = in.StdinOnce + out.TTY = in.TTY + return nil +} + +// Convert_core_EphemeralContainerCommon_To_v1_EphemeralContainerCommon is an autogenerated conversion function. +func Convert_core_EphemeralContainerCommon_To_v1_EphemeralContainerCommon(in *core.EphemeralContainerCommon, out *v1.EphemeralContainerCommon, s conversion.Scope) error { + return autoConvert_core_EphemeralContainerCommon_To_v1_EphemeralContainerCommon(in, out, s) +} + +func autoConvert_v1_EphemeralVolumeSource_To_core_EphemeralVolumeSource(in *v1.EphemeralVolumeSource, out *core.EphemeralVolumeSource, s conversion.Scope) error { + out.VolumeClaimTemplate = (*core.PersistentVolumeClaimTemplate)(unsafe.Pointer(in.VolumeClaimTemplate)) + return nil +} + +// Convert_v1_EphemeralVolumeSource_To_core_EphemeralVolumeSource is an autogenerated conversion function. +func Convert_v1_EphemeralVolumeSource_To_core_EphemeralVolumeSource(in *v1.EphemeralVolumeSource, out *core.EphemeralVolumeSource, s conversion.Scope) error { + return autoConvert_v1_EphemeralVolumeSource_To_core_EphemeralVolumeSource(in, out, s) +} + +func autoConvert_core_EphemeralVolumeSource_To_v1_EphemeralVolumeSource(in *core.EphemeralVolumeSource, out *v1.EphemeralVolumeSource, s conversion.Scope) error { + out.VolumeClaimTemplate = (*v1.PersistentVolumeClaimTemplate)(unsafe.Pointer(in.VolumeClaimTemplate)) + return nil +} + +// Convert_core_EphemeralVolumeSource_To_v1_EphemeralVolumeSource is an autogenerated conversion function. +func Convert_core_EphemeralVolumeSource_To_v1_EphemeralVolumeSource(in *core.EphemeralVolumeSource, out *v1.EphemeralVolumeSource, s conversion.Scope) error { + return autoConvert_core_EphemeralVolumeSource_To_v1_EphemeralVolumeSource(in, out, s) +} + +func autoConvert_v1_Event_To_core_Event(in *v1.Event, out *core.Event, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_ObjectReference_To_core_ObjectReference(&in.InvolvedObject, &out.InvolvedObject, s); err != nil { + return err + } + out.Reason = in.Reason + out.Message = in.Message + if err := Convert_v1_EventSource_To_core_EventSource(&in.Source, &out.Source, s); err != nil { + return err + } + out.FirstTimestamp = in.FirstTimestamp + out.LastTimestamp = in.LastTimestamp + out.Count = in.Count + out.Type = in.Type + out.EventTime = in.EventTime + out.Series = (*core.EventSeries)(unsafe.Pointer(in.Series)) + out.Action = in.Action + out.Related = (*core.ObjectReference)(unsafe.Pointer(in.Related)) + out.ReportingController = in.ReportingController + out.ReportingInstance = in.ReportingInstance + return nil +} + +// Convert_v1_Event_To_core_Event is an autogenerated conversion function. +func Convert_v1_Event_To_core_Event(in *v1.Event, out *core.Event, s conversion.Scope) error { + return autoConvert_v1_Event_To_core_Event(in, out, s) +} + +func autoConvert_core_Event_To_v1_Event(in *core.Event, out *v1.Event, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_core_ObjectReference_To_v1_ObjectReference(&in.InvolvedObject, &out.InvolvedObject, s); err != nil { + return err + } + out.Reason = in.Reason + out.Message = in.Message + if err := Convert_core_EventSource_To_v1_EventSource(&in.Source, &out.Source, s); err != nil { + return err + } + out.FirstTimestamp = in.FirstTimestamp + out.LastTimestamp = in.LastTimestamp + out.Count = in.Count + out.Type = in.Type + out.EventTime = in.EventTime + out.Series = (*v1.EventSeries)(unsafe.Pointer(in.Series)) + out.Action = in.Action + out.Related = (*v1.ObjectReference)(unsafe.Pointer(in.Related)) + out.ReportingController = in.ReportingController + out.ReportingInstance = in.ReportingInstance + return nil +} + +// Convert_core_Event_To_v1_Event is an autogenerated conversion function. +func Convert_core_Event_To_v1_Event(in *core.Event, out *v1.Event, s conversion.Scope) error { + return autoConvert_core_Event_To_v1_Event(in, out, s) +} + +func autoConvert_v1_EventList_To_core_EventList(in *v1.EventList, out *core.EventList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]core.Event)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1_EventList_To_core_EventList is an autogenerated conversion function. +func Convert_v1_EventList_To_core_EventList(in *v1.EventList, out *core.EventList, s conversion.Scope) error { + return autoConvert_v1_EventList_To_core_EventList(in, out, s) +} + +func autoConvert_core_EventList_To_v1_EventList(in *core.EventList, out *v1.EventList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]v1.Event)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_core_EventList_To_v1_EventList is an autogenerated conversion function. +func Convert_core_EventList_To_v1_EventList(in *core.EventList, out *v1.EventList, s conversion.Scope) error { + return autoConvert_core_EventList_To_v1_EventList(in, out, s) +} + +func autoConvert_v1_EventSeries_To_core_EventSeries(in *v1.EventSeries, out *core.EventSeries, s conversion.Scope) error { + out.Count = in.Count + out.LastObservedTime = in.LastObservedTime + return nil +} + +// Convert_v1_EventSeries_To_core_EventSeries is an autogenerated conversion function. +func Convert_v1_EventSeries_To_core_EventSeries(in *v1.EventSeries, out *core.EventSeries, s conversion.Scope) error { + return autoConvert_v1_EventSeries_To_core_EventSeries(in, out, s) +} + +func autoConvert_core_EventSeries_To_v1_EventSeries(in *core.EventSeries, out *v1.EventSeries, s conversion.Scope) error { + out.Count = in.Count + out.LastObservedTime = in.LastObservedTime + return nil +} + +// Convert_core_EventSeries_To_v1_EventSeries is an autogenerated conversion function. +func Convert_core_EventSeries_To_v1_EventSeries(in *core.EventSeries, out *v1.EventSeries, s conversion.Scope) error { + return autoConvert_core_EventSeries_To_v1_EventSeries(in, out, s) +} + +func autoConvert_v1_EventSource_To_core_EventSource(in *v1.EventSource, out *core.EventSource, s conversion.Scope) error { + out.Component = in.Component + out.Host = in.Host + return nil +} + +// Convert_v1_EventSource_To_core_EventSource is an autogenerated conversion function. +func Convert_v1_EventSource_To_core_EventSource(in *v1.EventSource, out *core.EventSource, s conversion.Scope) error { + return autoConvert_v1_EventSource_To_core_EventSource(in, out, s) +} + +func autoConvert_core_EventSource_To_v1_EventSource(in *core.EventSource, out *v1.EventSource, s conversion.Scope) error { + out.Component = in.Component + out.Host = in.Host + return nil +} + +// Convert_core_EventSource_To_v1_EventSource is an autogenerated conversion function. +func Convert_core_EventSource_To_v1_EventSource(in *core.EventSource, out *v1.EventSource, s conversion.Scope) error { + return autoConvert_core_EventSource_To_v1_EventSource(in, out, s) +} + +func autoConvert_v1_ExecAction_To_core_ExecAction(in *v1.ExecAction, out *core.ExecAction, s conversion.Scope) error { + out.Command = *(*[]string)(unsafe.Pointer(&in.Command)) + return nil +} + +// Convert_v1_ExecAction_To_core_ExecAction is an autogenerated conversion function. +func Convert_v1_ExecAction_To_core_ExecAction(in *v1.ExecAction, out *core.ExecAction, s conversion.Scope) error { + return autoConvert_v1_ExecAction_To_core_ExecAction(in, out, s) +} + +func autoConvert_core_ExecAction_To_v1_ExecAction(in *core.ExecAction, out *v1.ExecAction, s conversion.Scope) error { + out.Command = *(*[]string)(unsafe.Pointer(&in.Command)) + return nil +} + +// Convert_core_ExecAction_To_v1_ExecAction is an autogenerated conversion function. +func Convert_core_ExecAction_To_v1_ExecAction(in *core.ExecAction, out *v1.ExecAction, s conversion.Scope) error { + return autoConvert_core_ExecAction_To_v1_ExecAction(in, out, s) +} + +func autoConvert_v1_FCVolumeSource_To_core_FCVolumeSource(in *v1.FCVolumeSource, out *core.FCVolumeSource, s conversion.Scope) error { + out.TargetWWNs = *(*[]string)(unsafe.Pointer(&in.TargetWWNs)) + out.Lun = (*int32)(unsafe.Pointer(in.Lun)) + out.FSType = in.FSType + out.ReadOnly = in.ReadOnly + out.WWIDs = *(*[]string)(unsafe.Pointer(&in.WWIDs)) + return nil +} + +// Convert_v1_FCVolumeSource_To_core_FCVolumeSource is an autogenerated conversion function. +func Convert_v1_FCVolumeSource_To_core_FCVolumeSource(in *v1.FCVolumeSource, out *core.FCVolumeSource, s conversion.Scope) error { + return autoConvert_v1_FCVolumeSource_To_core_FCVolumeSource(in, out, s) +} + +func autoConvert_core_FCVolumeSource_To_v1_FCVolumeSource(in *core.FCVolumeSource, out *v1.FCVolumeSource, s conversion.Scope) error { + out.TargetWWNs = *(*[]string)(unsafe.Pointer(&in.TargetWWNs)) + out.Lun = (*int32)(unsafe.Pointer(in.Lun)) + out.FSType = in.FSType + out.ReadOnly = in.ReadOnly + out.WWIDs = *(*[]string)(unsafe.Pointer(&in.WWIDs)) + return nil +} + +// Convert_core_FCVolumeSource_To_v1_FCVolumeSource is an autogenerated conversion function. +func Convert_core_FCVolumeSource_To_v1_FCVolumeSource(in *core.FCVolumeSource, out *v1.FCVolumeSource, s conversion.Scope) error { + return autoConvert_core_FCVolumeSource_To_v1_FCVolumeSource(in, out, s) +} + +func autoConvert_v1_FlexPersistentVolumeSource_To_core_FlexPersistentVolumeSource(in *v1.FlexPersistentVolumeSource, out *core.FlexPersistentVolumeSource, s conversion.Scope) error { + out.Driver = in.Driver + out.FSType = in.FSType + out.SecretRef = (*core.SecretReference)(unsafe.Pointer(in.SecretRef)) + out.ReadOnly = in.ReadOnly + out.Options = *(*map[string]string)(unsafe.Pointer(&in.Options)) + return nil +} + +// Convert_v1_FlexPersistentVolumeSource_To_core_FlexPersistentVolumeSource is an autogenerated conversion function. +func Convert_v1_FlexPersistentVolumeSource_To_core_FlexPersistentVolumeSource(in *v1.FlexPersistentVolumeSource, out *core.FlexPersistentVolumeSource, s conversion.Scope) error { + return autoConvert_v1_FlexPersistentVolumeSource_To_core_FlexPersistentVolumeSource(in, out, s) +} + +func autoConvert_core_FlexPersistentVolumeSource_To_v1_FlexPersistentVolumeSource(in *core.FlexPersistentVolumeSource, out *v1.FlexPersistentVolumeSource, s conversion.Scope) error { + out.Driver = in.Driver + out.FSType = in.FSType + out.SecretRef = (*v1.SecretReference)(unsafe.Pointer(in.SecretRef)) + out.ReadOnly = in.ReadOnly + out.Options = *(*map[string]string)(unsafe.Pointer(&in.Options)) + return nil +} + +// Convert_core_FlexPersistentVolumeSource_To_v1_FlexPersistentVolumeSource is an autogenerated conversion function. +func Convert_core_FlexPersistentVolumeSource_To_v1_FlexPersistentVolumeSource(in *core.FlexPersistentVolumeSource, out *v1.FlexPersistentVolumeSource, s conversion.Scope) error { + return autoConvert_core_FlexPersistentVolumeSource_To_v1_FlexPersistentVolumeSource(in, out, s) +} + +func autoConvert_v1_FlexVolumeSource_To_core_FlexVolumeSource(in *v1.FlexVolumeSource, out *core.FlexVolumeSource, s conversion.Scope) error { + out.Driver = in.Driver + out.FSType = in.FSType + out.SecretRef = (*core.LocalObjectReference)(unsafe.Pointer(in.SecretRef)) + out.ReadOnly = in.ReadOnly + out.Options = *(*map[string]string)(unsafe.Pointer(&in.Options)) + return nil +} + +// Convert_v1_FlexVolumeSource_To_core_FlexVolumeSource is an autogenerated conversion function. +func Convert_v1_FlexVolumeSource_To_core_FlexVolumeSource(in *v1.FlexVolumeSource, out *core.FlexVolumeSource, s conversion.Scope) error { + return autoConvert_v1_FlexVolumeSource_To_core_FlexVolumeSource(in, out, s) +} + +func autoConvert_core_FlexVolumeSource_To_v1_FlexVolumeSource(in *core.FlexVolumeSource, out *v1.FlexVolumeSource, s conversion.Scope) error { + out.Driver = in.Driver + out.FSType = in.FSType + out.SecretRef = (*v1.LocalObjectReference)(unsafe.Pointer(in.SecretRef)) + out.ReadOnly = in.ReadOnly + out.Options = *(*map[string]string)(unsafe.Pointer(&in.Options)) + return nil +} + +// Convert_core_FlexVolumeSource_To_v1_FlexVolumeSource is an autogenerated conversion function. +func Convert_core_FlexVolumeSource_To_v1_FlexVolumeSource(in *core.FlexVolumeSource, out *v1.FlexVolumeSource, s conversion.Scope) error { + return autoConvert_core_FlexVolumeSource_To_v1_FlexVolumeSource(in, out, s) +} + +func autoConvert_v1_FlockerVolumeSource_To_core_FlockerVolumeSource(in *v1.FlockerVolumeSource, out *core.FlockerVolumeSource, s conversion.Scope) error { + out.DatasetName = in.DatasetName + out.DatasetUUID = in.DatasetUUID + return nil +} + +// Convert_v1_FlockerVolumeSource_To_core_FlockerVolumeSource is an autogenerated conversion function. +func Convert_v1_FlockerVolumeSource_To_core_FlockerVolumeSource(in *v1.FlockerVolumeSource, out *core.FlockerVolumeSource, s conversion.Scope) error { + return autoConvert_v1_FlockerVolumeSource_To_core_FlockerVolumeSource(in, out, s) +} + +func autoConvert_core_FlockerVolumeSource_To_v1_FlockerVolumeSource(in *core.FlockerVolumeSource, out *v1.FlockerVolumeSource, s conversion.Scope) error { + out.DatasetName = in.DatasetName + out.DatasetUUID = in.DatasetUUID + return nil +} + +// Convert_core_FlockerVolumeSource_To_v1_FlockerVolumeSource is an autogenerated conversion function. +func Convert_core_FlockerVolumeSource_To_v1_FlockerVolumeSource(in *core.FlockerVolumeSource, out *v1.FlockerVolumeSource, s conversion.Scope) error { + return autoConvert_core_FlockerVolumeSource_To_v1_FlockerVolumeSource(in, out, s) +} + +func autoConvert_v1_GCEPersistentDiskVolumeSource_To_core_GCEPersistentDiskVolumeSource(in *v1.GCEPersistentDiskVolumeSource, out *core.GCEPersistentDiskVolumeSource, s conversion.Scope) error { + out.PDName = in.PDName + out.FSType = in.FSType + out.Partition = in.Partition + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_v1_GCEPersistentDiskVolumeSource_To_core_GCEPersistentDiskVolumeSource is an autogenerated conversion function. +func Convert_v1_GCEPersistentDiskVolumeSource_To_core_GCEPersistentDiskVolumeSource(in *v1.GCEPersistentDiskVolumeSource, out *core.GCEPersistentDiskVolumeSource, s conversion.Scope) error { + return autoConvert_v1_GCEPersistentDiskVolumeSource_To_core_GCEPersistentDiskVolumeSource(in, out, s) +} + +func autoConvert_core_GCEPersistentDiskVolumeSource_To_v1_GCEPersistentDiskVolumeSource(in *core.GCEPersistentDiskVolumeSource, out *v1.GCEPersistentDiskVolumeSource, s conversion.Scope) error { + out.PDName = in.PDName + out.FSType = in.FSType + out.Partition = in.Partition + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_core_GCEPersistentDiskVolumeSource_To_v1_GCEPersistentDiskVolumeSource is an autogenerated conversion function. +func Convert_core_GCEPersistentDiskVolumeSource_To_v1_GCEPersistentDiskVolumeSource(in *core.GCEPersistentDiskVolumeSource, out *v1.GCEPersistentDiskVolumeSource, s conversion.Scope) error { + return autoConvert_core_GCEPersistentDiskVolumeSource_To_v1_GCEPersistentDiskVolumeSource(in, out, s) +} + +func autoConvert_v1_GRPCAction_To_core_GRPCAction(in *v1.GRPCAction, out *core.GRPCAction, s conversion.Scope) error { + out.Port = in.Port + out.Service = (*string)(unsafe.Pointer(in.Service)) + return nil +} + +// Convert_v1_GRPCAction_To_core_GRPCAction is an autogenerated conversion function. +func Convert_v1_GRPCAction_To_core_GRPCAction(in *v1.GRPCAction, out *core.GRPCAction, s conversion.Scope) error { + return autoConvert_v1_GRPCAction_To_core_GRPCAction(in, out, s) +} + +func autoConvert_core_GRPCAction_To_v1_GRPCAction(in *core.GRPCAction, out *v1.GRPCAction, s conversion.Scope) error { + out.Port = in.Port + out.Service = (*string)(unsafe.Pointer(in.Service)) + return nil +} + +// Convert_core_GRPCAction_To_v1_GRPCAction is an autogenerated conversion function. +func Convert_core_GRPCAction_To_v1_GRPCAction(in *core.GRPCAction, out *v1.GRPCAction, s conversion.Scope) error { + return autoConvert_core_GRPCAction_To_v1_GRPCAction(in, out, s) +} + +func autoConvert_v1_GitRepoVolumeSource_To_core_GitRepoVolumeSource(in *v1.GitRepoVolumeSource, out *core.GitRepoVolumeSource, s conversion.Scope) error { + out.Repository = in.Repository + out.Revision = in.Revision + out.Directory = in.Directory + return nil +} + +// Convert_v1_GitRepoVolumeSource_To_core_GitRepoVolumeSource is an autogenerated conversion function. +func Convert_v1_GitRepoVolumeSource_To_core_GitRepoVolumeSource(in *v1.GitRepoVolumeSource, out *core.GitRepoVolumeSource, s conversion.Scope) error { + return autoConvert_v1_GitRepoVolumeSource_To_core_GitRepoVolumeSource(in, out, s) +} + +func autoConvert_core_GitRepoVolumeSource_To_v1_GitRepoVolumeSource(in *core.GitRepoVolumeSource, out *v1.GitRepoVolumeSource, s conversion.Scope) error { + out.Repository = in.Repository + out.Revision = in.Revision + out.Directory = in.Directory + return nil +} + +// Convert_core_GitRepoVolumeSource_To_v1_GitRepoVolumeSource is an autogenerated conversion function. +func Convert_core_GitRepoVolumeSource_To_v1_GitRepoVolumeSource(in *core.GitRepoVolumeSource, out *v1.GitRepoVolumeSource, s conversion.Scope) error { + return autoConvert_core_GitRepoVolumeSource_To_v1_GitRepoVolumeSource(in, out, s) +} + +func autoConvert_v1_GlusterfsPersistentVolumeSource_To_core_GlusterfsPersistentVolumeSource(in *v1.GlusterfsPersistentVolumeSource, out *core.GlusterfsPersistentVolumeSource, s conversion.Scope) error { + out.EndpointsName = in.EndpointsName + out.Path = in.Path + out.ReadOnly = in.ReadOnly + out.EndpointsNamespace = (*string)(unsafe.Pointer(in.EndpointsNamespace)) + return nil +} + +// Convert_v1_GlusterfsPersistentVolumeSource_To_core_GlusterfsPersistentVolumeSource is an autogenerated conversion function. +func Convert_v1_GlusterfsPersistentVolumeSource_To_core_GlusterfsPersistentVolumeSource(in *v1.GlusterfsPersistentVolumeSource, out *core.GlusterfsPersistentVolumeSource, s conversion.Scope) error { + return autoConvert_v1_GlusterfsPersistentVolumeSource_To_core_GlusterfsPersistentVolumeSource(in, out, s) +} + +func autoConvert_core_GlusterfsPersistentVolumeSource_To_v1_GlusterfsPersistentVolumeSource(in *core.GlusterfsPersistentVolumeSource, out *v1.GlusterfsPersistentVolumeSource, s conversion.Scope) error { + out.EndpointsName = in.EndpointsName + out.Path = in.Path + out.ReadOnly = in.ReadOnly + out.EndpointsNamespace = (*string)(unsafe.Pointer(in.EndpointsNamespace)) + return nil +} + +// Convert_core_GlusterfsPersistentVolumeSource_To_v1_GlusterfsPersistentVolumeSource is an autogenerated conversion function. +func Convert_core_GlusterfsPersistentVolumeSource_To_v1_GlusterfsPersistentVolumeSource(in *core.GlusterfsPersistentVolumeSource, out *v1.GlusterfsPersistentVolumeSource, s conversion.Scope) error { + return autoConvert_core_GlusterfsPersistentVolumeSource_To_v1_GlusterfsPersistentVolumeSource(in, out, s) +} + +func autoConvert_v1_GlusterfsVolumeSource_To_core_GlusterfsVolumeSource(in *v1.GlusterfsVolumeSource, out *core.GlusterfsVolumeSource, s conversion.Scope) error { + out.EndpointsName = in.EndpointsName + out.Path = in.Path + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_v1_GlusterfsVolumeSource_To_core_GlusterfsVolumeSource is an autogenerated conversion function. +func Convert_v1_GlusterfsVolumeSource_To_core_GlusterfsVolumeSource(in *v1.GlusterfsVolumeSource, out *core.GlusterfsVolumeSource, s conversion.Scope) error { + return autoConvert_v1_GlusterfsVolumeSource_To_core_GlusterfsVolumeSource(in, out, s) +} + +func autoConvert_core_GlusterfsVolumeSource_To_v1_GlusterfsVolumeSource(in *core.GlusterfsVolumeSource, out *v1.GlusterfsVolumeSource, s conversion.Scope) error { + out.EndpointsName = in.EndpointsName + out.Path = in.Path + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_core_GlusterfsVolumeSource_To_v1_GlusterfsVolumeSource is an autogenerated conversion function. +func Convert_core_GlusterfsVolumeSource_To_v1_GlusterfsVolumeSource(in *core.GlusterfsVolumeSource, out *v1.GlusterfsVolumeSource, s conversion.Scope) error { + return autoConvert_core_GlusterfsVolumeSource_To_v1_GlusterfsVolumeSource(in, out, s) +} + +func autoConvert_v1_HTTPGetAction_To_core_HTTPGetAction(in *v1.HTTPGetAction, out *core.HTTPGetAction, s conversion.Scope) error { + out.Path = in.Path + out.Port = in.Port + out.Host = in.Host + out.Scheme = core.URIScheme(in.Scheme) + out.HTTPHeaders = *(*[]core.HTTPHeader)(unsafe.Pointer(&in.HTTPHeaders)) + return nil +} + +// Convert_v1_HTTPGetAction_To_core_HTTPGetAction is an autogenerated conversion function. +func Convert_v1_HTTPGetAction_To_core_HTTPGetAction(in *v1.HTTPGetAction, out *core.HTTPGetAction, s conversion.Scope) error { + return autoConvert_v1_HTTPGetAction_To_core_HTTPGetAction(in, out, s) +} + +func autoConvert_core_HTTPGetAction_To_v1_HTTPGetAction(in *core.HTTPGetAction, out *v1.HTTPGetAction, s conversion.Scope) error { + out.Path = in.Path + out.Port = in.Port + out.Host = in.Host + out.Scheme = v1.URIScheme(in.Scheme) + out.HTTPHeaders = *(*[]v1.HTTPHeader)(unsafe.Pointer(&in.HTTPHeaders)) + return nil +} + +// Convert_core_HTTPGetAction_To_v1_HTTPGetAction is an autogenerated conversion function. +func Convert_core_HTTPGetAction_To_v1_HTTPGetAction(in *core.HTTPGetAction, out *v1.HTTPGetAction, s conversion.Scope) error { + return autoConvert_core_HTTPGetAction_To_v1_HTTPGetAction(in, out, s) +} + +func autoConvert_v1_HTTPHeader_To_core_HTTPHeader(in *v1.HTTPHeader, out *core.HTTPHeader, s conversion.Scope) error { + out.Name = in.Name + out.Value = in.Value + return nil +} + +// Convert_v1_HTTPHeader_To_core_HTTPHeader is an autogenerated conversion function. +func Convert_v1_HTTPHeader_To_core_HTTPHeader(in *v1.HTTPHeader, out *core.HTTPHeader, s conversion.Scope) error { + return autoConvert_v1_HTTPHeader_To_core_HTTPHeader(in, out, s) +} + +func autoConvert_core_HTTPHeader_To_v1_HTTPHeader(in *core.HTTPHeader, out *v1.HTTPHeader, s conversion.Scope) error { + out.Name = in.Name + out.Value = in.Value + return nil +} + +// Convert_core_HTTPHeader_To_v1_HTTPHeader is an autogenerated conversion function. +func Convert_core_HTTPHeader_To_v1_HTTPHeader(in *core.HTTPHeader, out *v1.HTTPHeader, s conversion.Scope) error { + return autoConvert_core_HTTPHeader_To_v1_HTTPHeader(in, out, s) +} + +func autoConvert_v1_HostAlias_To_core_HostAlias(in *v1.HostAlias, out *core.HostAlias, s conversion.Scope) error { + out.IP = in.IP + out.Hostnames = *(*[]string)(unsafe.Pointer(&in.Hostnames)) + return nil +} + +// Convert_v1_HostAlias_To_core_HostAlias is an autogenerated conversion function. +func Convert_v1_HostAlias_To_core_HostAlias(in *v1.HostAlias, out *core.HostAlias, s conversion.Scope) error { + return autoConvert_v1_HostAlias_To_core_HostAlias(in, out, s) +} + +func autoConvert_core_HostAlias_To_v1_HostAlias(in *core.HostAlias, out *v1.HostAlias, s conversion.Scope) error { + out.IP = in.IP + out.Hostnames = *(*[]string)(unsafe.Pointer(&in.Hostnames)) + return nil +} + +// Convert_core_HostAlias_To_v1_HostAlias is an autogenerated conversion function. +func Convert_core_HostAlias_To_v1_HostAlias(in *core.HostAlias, out *v1.HostAlias, s conversion.Scope) error { + return autoConvert_core_HostAlias_To_v1_HostAlias(in, out, s) +} + +func autoConvert_v1_HostPathVolumeSource_To_core_HostPathVolumeSource(in *v1.HostPathVolumeSource, out *core.HostPathVolumeSource, s conversion.Scope) error { + out.Path = in.Path + out.Type = (*core.HostPathType)(unsafe.Pointer(in.Type)) + return nil +} + +// Convert_v1_HostPathVolumeSource_To_core_HostPathVolumeSource is an autogenerated conversion function. +func Convert_v1_HostPathVolumeSource_To_core_HostPathVolumeSource(in *v1.HostPathVolumeSource, out *core.HostPathVolumeSource, s conversion.Scope) error { + return autoConvert_v1_HostPathVolumeSource_To_core_HostPathVolumeSource(in, out, s) +} + +func autoConvert_core_HostPathVolumeSource_To_v1_HostPathVolumeSource(in *core.HostPathVolumeSource, out *v1.HostPathVolumeSource, s conversion.Scope) error { + out.Path = in.Path + out.Type = (*v1.HostPathType)(unsafe.Pointer(in.Type)) + return nil +} + +// Convert_core_HostPathVolumeSource_To_v1_HostPathVolumeSource is an autogenerated conversion function. +func Convert_core_HostPathVolumeSource_To_v1_HostPathVolumeSource(in *core.HostPathVolumeSource, out *v1.HostPathVolumeSource, s conversion.Scope) error { + return autoConvert_core_HostPathVolumeSource_To_v1_HostPathVolumeSource(in, out, s) +} + +func autoConvert_v1_ISCSIPersistentVolumeSource_To_core_ISCSIPersistentVolumeSource(in *v1.ISCSIPersistentVolumeSource, out *core.ISCSIPersistentVolumeSource, s conversion.Scope) error { + out.TargetPortal = in.TargetPortal + out.IQN = in.IQN + out.Lun = in.Lun + out.ISCSIInterface = in.ISCSIInterface + out.FSType = in.FSType + out.ReadOnly = in.ReadOnly + out.Portals = *(*[]string)(unsafe.Pointer(&in.Portals)) + out.DiscoveryCHAPAuth = in.DiscoveryCHAPAuth + out.SessionCHAPAuth = in.SessionCHAPAuth + out.SecretRef = (*core.SecretReference)(unsafe.Pointer(in.SecretRef)) + out.InitiatorName = (*string)(unsafe.Pointer(in.InitiatorName)) + return nil +} + +// Convert_v1_ISCSIPersistentVolumeSource_To_core_ISCSIPersistentVolumeSource is an autogenerated conversion function. +func Convert_v1_ISCSIPersistentVolumeSource_To_core_ISCSIPersistentVolumeSource(in *v1.ISCSIPersistentVolumeSource, out *core.ISCSIPersistentVolumeSource, s conversion.Scope) error { + return autoConvert_v1_ISCSIPersistentVolumeSource_To_core_ISCSIPersistentVolumeSource(in, out, s) +} + +func autoConvert_core_ISCSIPersistentVolumeSource_To_v1_ISCSIPersistentVolumeSource(in *core.ISCSIPersistentVolumeSource, out *v1.ISCSIPersistentVolumeSource, s conversion.Scope) error { + out.TargetPortal = in.TargetPortal + out.IQN = in.IQN + out.Lun = in.Lun + out.ISCSIInterface = in.ISCSIInterface + out.FSType = in.FSType + out.ReadOnly = in.ReadOnly + out.Portals = *(*[]string)(unsafe.Pointer(&in.Portals)) + out.DiscoveryCHAPAuth = in.DiscoveryCHAPAuth + out.SessionCHAPAuth = in.SessionCHAPAuth + out.SecretRef = (*v1.SecretReference)(unsafe.Pointer(in.SecretRef)) + out.InitiatorName = (*string)(unsafe.Pointer(in.InitiatorName)) + return nil +} + +// Convert_core_ISCSIPersistentVolumeSource_To_v1_ISCSIPersistentVolumeSource is an autogenerated conversion function. +func Convert_core_ISCSIPersistentVolumeSource_To_v1_ISCSIPersistentVolumeSource(in *core.ISCSIPersistentVolumeSource, out *v1.ISCSIPersistentVolumeSource, s conversion.Scope) error { + return autoConvert_core_ISCSIPersistentVolumeSource_To_v1_ISCSIPersistentVolumeSource(in, out, s) +} + +func autoConvert_v1_ISCSIVolumeSource_To_core_ISCSIVolumeSource(in *v1.ISCSIVolumeSource, out *core.ISCSIVolumeSource, s conversion.Scope) error { + out.TargetPortal = in.TargetPortal + out.IQN = in.IQN + out.Lun = in.Lun + out.ISCSIInterface = in.ISCSIInterface + out.FSType = in.FSType + out.ReadOnly = in.ReadOnly + out.Portals = *(*[]string)(unsafe.Pointer(&in.Portals)) + out.DiscoveryCHAPAuth = in.DiscoveryCHAPAuth + out.SessionCHAPAuth = in.SessionCHAPAuth + out.SecretRef = (*core.LocalObjectReference)(unsafe.Pointer(in.SecretRef)) + out.InitiatorName = (*string)(unsafe.Pointer(in.InitiatorName)) + return nil +} + +// Convert_v1_ISCSIVolumeSource_To_core_ISCSIVolumeSource is an autogenerated conversion function. +func Convert_v1_ISCSIVolumeSource_To_core_ISCSIVolumeSource(in *v1.ISCSIVolumeSource, out *core.ISCSIVolumeSource, s conversion.Scope) error { + return autoConvert_v1_ISCSIVolumeSource_To_core_ISCSIVolumeSource(in, out, s) +} + +func autoConvert_core_ISCSIVolumeSource_To_v1_ISCSIVolumeSource(in *core.ISCSIVolumeSource, out *v1.ISCSIVolumeSource, s conversion.Scope) error { + out.TargetPortal = in.TargetPortal + out.IQN = in.IQN + out.Lun = in.Lun + out.ISCSIInterface = in.ISCSIInterface + out.FSType = in.FSType + out.ReadOnly = in.ReadOnly + out.Portals = *(*[]string)(unsafe.Pointer(&in.Portals)) + out.DiscoveryCHAPAuth = in.DiscoveryCHAPAuth + out.SessionCHAPAuth = in.SessionCHAPAuth + out.SecretRef = (*v1.LocalObjectReference)(unsafe.Pointer(in.SecretRef)) + out.InitiatorName = (*string)(unsafe.Pointer(in.InitiatorName)) + return nil +} + +// Convert_core_ISCSIVolumeSource_To_v1_ISCSIVolumeSource is an autogenerated conversion function. +func Convert_core_ISCSIVolumeSource_To_v1_ISCSIVolumeSource(in *core.ISCSIVolumeSource, out *v1.ISCSIVolumeSource, s conversion.Scope) error { + return autoConvert_core_ISCSIVolumeSource_To_v1_ISCSIVolumeSource(in, out, s) +} + +func autoConvert_v1_KeyToPath_To_core_KeyToPath(in *v1.KeyToPath, out *core.KeyToPath, s conversion.Scope) error { + out.Key = in.Key + out.Path = in.Path + out.Mode = (*int32)(unsafe.Pointer(in.Mode)) + return nil +} + +// Convert_v1_KeyToPath_To_core_KeyToPath is an autogenerated conversion function. +func Convert_v1_KeyToPath_To_core_KeyToPath(in *v1.KeyToPath, out *core.KeyToPath, s conversion.Scope) error { + return autoConvert_v1_KeyToPath_To_core_KeyToPath(in, out, s) +} + +func autoConvert_core_KeyToPath_To_v1_KeyToPath(in *core.KeyToPath, out *v1.KeyToPath, s conversion.Scope) error { + out.Key = in.Key + out.Path = in.Path + out.Mode = (*int32)(unsafe.Pointer(in.Mode)) + return nil +} + +// Convert_core_KeyToPath_To_v1_KeyToPath is an autogenerated conversion function. +func Convert_core_KeyToPath_To_v1_KeyToPath(in *core.KeyToPath, out *v1.KeyToPath, s conversion.Scope) error { + return autoConvert_core_KeyToPath_To_v1_KeyToPath(in, out, s) +} + +func autoConvert_v1_Lifecycle_To_core_Lifecycle(in *v1.Lifecycle, out *core.Lifecycle, s conversion.Scope) error { + out.PostStart = (*core.LifecycleHandler)(unsafe.Pointer(in.PostStart)) + out.PreStop = (*core.LifecycleHandler)(unsafe.Pointer(in.PreStop)) + return nil +} + +// Convert_v1_Lifecycle_To_core_Lifecycle is an autogenerated conversion function. +func Convert_v1_Lifecycle_To_core_Lifecycle(in *v1.Lifecycle, out *core.Lifecycle, s conversion.Scope) error { + return autoConvert_v1_Lifecycle_To_core_Lifecycle(in, out, s) +} + +func autoConvert_core_Lifecycle_To_v1_Lifecycle(in *core.Lifecycle, out *v1.Lifecycle, s conversion.Scope) error { + out.PostStart = (*v1.LifecycleHandler)(unsafe.Pointer(in.PostStart)) + out.PreStop = (*v1.LifecycleHandler)(unsafe.Pointer(in.PreStop)) + return nil +} + +// Convert_core_Lifecycle_To_v1_Lifecycle is an autogenerated conversion function. +func Convert_core_Lifecycle_To_v1_Lifecycle(in *core.Lifecycle, out *v1.Lifecycle, s conversion.Scope) error { + return autoConvert_core_Lifecycle_To_v1_Lifecycle(in, out, s) +} + +func autoConvert_v1_LifecycleHandler_To_core_LifecycleHandler(in *v1.LifecycleHandler, out *core.LifecycleHandler, s conversion.Scope) error { + out.Exec = (*core.ExecAction)(unsafe.Pointer(in.Exec)) + out.HTTPGet = (*core.HTTPGetAction)(unsafe.Pointer(in.HTTPGet)) + out.TCPSocket = (*core.TCPSocketAction)(unsafe.Pointer(in.TCPSocket)) + return nil +} + +// Convert_v1_LifecycleHandler_To_core_LifecycleHandler is an autogenerated conversion function. +func Convert_v1_LifecycleHandler_To_core_LifecycleHandler(in *v1.LifecycleHandler, out *core.LifecycleHandler, s conversion.Scope) error { + return autoConvert_v1_LifecycleHandler_To_core_LifecycleHandler(in, out, s) +} + +func autoConvert_core_LifecycleHandler_To_v1_LifecycleHandler(in *core.LifecycleHandler, out *v1.LifecycleHandler, s conversion.Scope) error { + out.Exec = (*v1.ExecAction)(unsafe.Pointer(in.Exec)) + out.HTTPGet = (*v1.HTTPGetAction)(unsafe.Pointer(in.HTTPGet)) + out.TCPSocket = (*v1.TCPSocketAction)(unsafe.Pointer(in.TCPSocket)) + return nil +} + +// Convert_core_LifecycleHandler_To_v1_LifecycleHandler is an autogenerated conversion function. +func Convert_core_LifecycleHandler_To_v1_LifecycleHandler(in *core.LifecycleHandler, out *v1.LifecycleHandler, s conversion.Scope) error { + return autoConvert_core_LifecycleHandler_To_v1_LifecycleHandler(in, out, s) +} + +func autoConvert_v1_LimitRange_To_core_LimitRange(in *v1.LimitRange, out *core.LimitRange, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_LimitRangeSpec_To_core_LimitRangeSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + return nil +} + +// Convert_v1_LimitRange_To_core_LimitRange is an autogenerated conversion function. +func Convert_v1_LimitRange_To_core_LimitRange(in *v1.LimitRange, out *core.LimitRange, s conversion.Scope) error { + return autoConvert_v1_LimitRange_To_core_LimitRange(in, out, s) +} + +func autoConvert_core_LimitRange_To_v1_LimitRange(in *core.LimitRange, out *v1.LimitRange, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_core_LimitRangeSpec_To_v1_LimitRangeSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + return nil +} + +// Convert_core_LimitRange_To_v1_LimitRange is an autogenerated conversion function. +func Convert_core_LimitRange_To_v1_LimitRange(in *core.LimitRange, out *v1.LimitRange, s conversion.Scope) error { + return autoConvert_core_LimitRange_To_v1_LimitRange(in, out, s) +} + +func autoConvert_v1_LimitRangeItem_To_core_LimitRangeItem(in *v1.LimitRangeItem, out *core.LimitRangeItem, s conversion.Scope) error { + out.Type = core.LimitType(in.Type) + out.Max = *(*core.ResourceList)(unsafe.Pointer(&in.Max)) + out.Min = *(*core.ResourceList)(unsafe.Pointer(&in.Min)) + out.Default = *(*core.ResourceList)(unsafe.Pointer(&in.Default)) + out.DefaultRequest = *(*core.ResourceList)(unsafe.Pointer(&in.DefaultRequest)) + out.MaxLimitRequestRatio = *(*core.ResourceList)(unsafe.Pointer(&in.MaxLimitRequestRatio)) + return nil +} + +// Convert_v1_LimitRangeItem_To_core_LimitRangeItem is an autogenerated conversion function. +func Convert_v1_LimitRangeItem_To_core_LimitRangeItem(in *v1.LimitRangeItem, out *core.LimitRangeItem, s conversion.Scope) error { + return autoConvert_v1_LimitRangeItem_To_core_LimitRangeItem(in, out, s) +} + +func autoConvert_core_LimitRangeItem_To_v1_LimitRangeItem(in *core.LimitRangeItem, out *v1.LimitRangeItem, s conversion.Scope) error { + out.Type = v1.LimitType(in.Type) + out.Max = *(*v1.ResourceList)(unsafe.Pointer(&in.Max)) + out.Min = *(*v1.ResourceList)(unsafe.Pointer(&in.Min)) + out.Default = *(*v1.ResourceList)(unsafe.Pointer(&in.Default)) + out.DefaultRequest = *(*v1.ResourceList)(unsafe.Pointer(&in.DefaultRequest)) + out.MaxLimitRequestRatio = *(*v1.ResourceList)(unsafe.Pointer(&in.MaxLimitRequestRatio)) + return nil +} + +// Convert_core_LimitRangeItem_To_v1_LimitRangeItem is an autogenerated conversion function. +func Convert_core_LimitRangeItem_To_v1_LimitRangeItem(in *core.LimitRangeItem, out *v1.LimitRangeItem, s conversion.Scope) error { + return autoConvert_core_LimitRangeItem_To_v1_LimitRangeItem(in, out, s) +} + +func autoConvert_v1_LimitRangeList_To_core_LimitRangeList(in *v1.LimitRangeList, out *core.LimitRangeList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]core.LimitRange)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1_LimitRangeList_To_core_LimitRangeList is an autogenerated conversion function. +func Convert_v1_LimitRangeList_To_core_LimitRangeList(in *v1.LimitRangeList, out *core.LimitRangeList, s conversion.Scope) error { + return autoConvert_v1_LimitRangeList_To_core_LimitRangeList(in, out, s) +} + +func autoConvert_core_LimitRangeList_To_v1_LimitRangeList(in *core.LimitRangeList, out *v1.LimitRangeList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]v1.LimitRange)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_core_LimitRangeList_To_v1_LimitRangeList is an autogenerated conversion function. +func Convert_core_LimitRangeList_To_v1_LimitRangeList(in *core.LimitRangeList, out *v1.LimitRangeList, s conversion.Scope) error { + return autoConvert_core_LimitRangeList_To_v1_LimitRangeList(in, out, s) +} + +func autoConvert_v1_LimitRangeSpec_To_core_LimitRangeSpec(in *v1.LimitRangeSpec, out *core.LimitRangeSpec, s conversion.Scope) error { + out.Limits = *(*[]core.LimitRangeItem)(unsafe.Pointer(&in.Limits)) + return nil +} + +// Convert_v1_LimitRangeSpec_To_core_LimitRangeSpec is an autogenerated conversion function. +func Convert_v1_LimitRangeSpec_To_core_LimitRangeSpec(in *v1.LimitRangeSpec, out *core.LimitRangeSpec, s conversion.Scope) error { + return autoConvert_v1_LimitRangeSpec_To_core_LimitRangeSpec(in, out, s) +} + +func autoConvert_core_LimitRangeSpec_To_v1_LimitRangeSpec(in *core.LimitRangeSpec, out *v1.LimitRangeSpec, s conversion.Scope) error { + out.Limits = *(*[]v1.LimitRangeItem)(unsafe.Pointer(&in.Limits)) + return nil +} + +// Convert_core_LimitRangeSpec_To_v1_LimitRangeSpec is an autogenerated conversion function. +func Convert_core_LimitRangeSpec_To_v1_LimitRangeSpec(in *core.LimitRangeSpec, out *v1.LimitRangeSpec, s conversion.Scope) error { + return autoConvert_core_LimitRangeSpec_To_v1_LimitRangeSpec(in, out, s) +} + +func autoConvert_v1_List_To_core_List(in *v1.List, out *core.List, s conversion.Scope) error { + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]runtime.Object, len(*in)) + for i := range *in { + if err := runtime.Convert_runtime_RawExtension_To_runtime_Object(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +// Convert_v1_List_To_core_List is an autogenerated conversion function. +func Convert_v1_List_To_core_List(in *v1.List, out *core.List, s conversion.Scope) error { + return autoConvert_v1_List_To_core_List(in, out, s) +} + +func autoConvert_core_List_To_v1_List(in *core.List, out *v1.List, s conversion.Scope) error { + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]runtime.RawExtension, len(*in)) + for i := range *in { + if err := runtime.Convert_runtime_Object_To_runtime_RawExtension(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +// Convert_core_List_To_v1_List is an autogenerated conversion function. +func Convert_core_List_To_v1_List(in *core.List, out *v1.List, s conversion.Scope) error { + return autoConvert_core_List_To_v1_List(in, out, s) +} + +func autoConvert_v1_LoadBalancerIngress_To_core_LoadBalancerIngress(in *v1.LoadBalancerIngress, out *core.LoadBalancerIngress, s conversion.Scope) error { + out.IP = in.IP + out.Hostname = in.Hostname + out.Ports = *(*[]core.PortStatus)(unsafe.Pointer(&in.Ports)) + return nil +} + +// Convert_v1_LoadBalancerIngress_To_core_LoadBalancerIngress is an autogenerated conversion function. +func Convert_v1_LoadBalancerIngress_To_core_LoadBalancerIngress(in *v1.LoadBalancerIngress, out *core.LoadBalancerIngress, s conversion.Scope) error { + return autoConvert_v1_LoadBalancerIngress_To_core_LoadBalancerIngress(in, out, s) +} + +func autoConvert_core_LoadBalancerIngress_To_v1_LoadBalancerIngress(in *core.LoadBalancerIngress, out *v1.LoadBalancerIngress, s conversion.Scope) error { + out.IP = in.IP + out.Hostname = in.Hostname + out.Ports = *(*[]v1.PortStatus)(unsafe.Pointer(&in.Ports)) + return nil +} + +// Convert_core_LoadBalancerIngress_To_v1_LoadBalancerIngress is an autogenerated conversion function. +func Convert_core_LoadBalancerIngress_To_v1_LoadBalancerIngress(in *core.LoadBalancerIngress, out *v1.LoadBalancerIngress, s conversion.Scope) error { + return autoConvert_core_LoadBalancerIngress_To_v1_LoadBalancerIngress(in, out, s) +} + +func autoConvert_v1_LoadBalancerStatus_To_core_LoadBalancerStatus(in *v1.LoadBalancerStatus, out *core.LoadBalancerStatus, s conversion.Scope) error { + out.Ingress = *(*[]core.LoadBalancerIngress)(unsafe.Pointer(&in.Ingress)) + return nil +} + +func autoConvert_core_LoadBalancerStatus_To_v1_LoadBalancerStatus(in *core.LoadBalancerStatus, out *v1.LoadBalancerStatus, s conversion.Scope) error { + out.Ingress = *(*[]v1.LoadBalancerIngress)(unsafe.Pointer(&in.Ingress)) + return nil +} + +func autoConvert_v1_LocalObjectReference_To_core_LocalObjectReference(in *v1.LocalObjectReference, out *core.LocalObjectReference, s conversion.Scope) error { + out.Name = in.Name + return nil +} + +// Convert_v1_LocalObjectReference_To_core_LocalObjectReference is an autogenerated conversion function. +func Convert_v1_LocalObjectReference_To_core_LocalObjectReference(in *v1.LocalObjectReference, out *core.LocalObjectReference, s conversion.Scope) error { + return autoConvert_v1_LocalObjectReference_To_core_LocalObjectReference(in, out, s) +} + +func autoConvert_core_LocalObjectReference_To_v1_LocalObjectReference(in *core.LocalObjectReference, out *v1.LocalObjectReference, s conversion.Scope) error { + out.Name = in.Name + return nil +} + +// Convert_core_LocalObjectReference_To_v1_LocalObjectReference is an autogenerated conversion function. +func Convert_core_LocalObjectReference_To_v1_LocalObjectReference(in *core.LocalObjectReference, out *v1.LocalObjectReference, s conversion.Scope) error { + return autoConvert_core_LocalObjectReference_To_v1_LocalObjectReference(in, out, s) +} + +func autoConvert_v1_LocalVolumeSource_To_core_LocalVolumeSource(in *v1.LocalVolumeSource, out *core.LocalVolumeSource, s conversion.Scope) error { + out.Path = in.Path + out.FSType = (*string)(unsafe.Pointer(in.FSType)) + return nil +} + +// Convert_v1_LocalVolumeSource_To_core_LocalVolumeSource is an autogenerated conversion function. +func Convert_v1_LocalVolumeSource_To_core_LocalVolumeSource(in *v1.LocalVolumeSource, out *core.LocalVolumeSource, s conversion.Scope) error { + return autoConvert_v1_LocalVolumeSource_To_core_LocalVolumeSource(in, out, s) +} + +func autoConvert_core_LocalVolumeSource_To_v1_LocalVolumeSource(in *core.LocalVolumeSource, out *v1.LocalVolumeSource, s conversion.Scope) error { + out.Path = in.Path + out.FSType = (*string)(unsafe.Pointer(in.FSType)) + return nil +} + +// Convert_core_LocalVolumeSource_To_v1_LocalVolumeSource is an autogenerated conversion function. +func Convert_core_LocalVolumeSource_To_v1_LocalVolumeSource(in *core.LocalVolumeSource, out *v1.LocalVolumeSource, s conversion.Scope) error { + return autoConvert_core_LocalVolumeSource_To_v1_LocalVolumeSource(in, out, s) +} + +func autoConvert_v1_NFSVolumeSource_To_core_NFSVolumeSource(in *v1.NFSVolumeSource, out *core.NFSVolumeSource, s conversion.Scope) error { + out.Server = in.Server + out.Path = in.Path + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_v1_NFSVolumeSource_To_core_NFSVolumeSource is an autogenerated conversion function. +func Convert_v1_NFSVolumeSource_To_core_NFSVolumeSource(in *v1.NFSVolumeSource, out *core.NFSVolumeSource, s conversion.Scope) error { + return autoConvert_v1_NFSVolumeSource_To_core_NFSVolumeSource(in, out, s) +} + +func autoConvert_core_NFSVolumeSource_To_v1_NFSVolumeSource(in *core.NFSVolumeSource, out *v1.NFSVolumeSource, s conversion.Scope) error { + out.Server = in.Server + out.Path = in.Path + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_core_NFSVolumeSource_To_v1_NFSVolumeSource is an autogenerated conversion function. +func Convert_core_NFSVolumeSource_To_v1_NFSVolumeSource(in *core.NFSVolumeSource, out *v1.NFSVolumeSource, s conversion.Scope) error { + return autoConvert_core_NFSVolumeSource_To_v1_NFSVolumeSource(in, out, s) +} + +func autoConvert_v1_Namespace_To_core_Namespace(in *v1.Namespace, out *core.Namespace, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_NamespaceSpec_To_core_NamespaceSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_v1_NamespaceStatus_To_core_NamespaceStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1_Namespace_To_core_Namespace is an autogenerated conversion function. +func Convert_v1_Namespace_To_core_Namespace(in *v1.Namespace, out *core.Namespace, s conversion.Scope) error { + return autoConvert_v1_Namespace_To_core_Namespace(in, out, s) +} + +func autoConvert_core_Namespace_To_v1_Namespace(in *core.Namespace, out *v1.Namespace, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_core_NamespaceSpec_To_v1_NamespaceSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_core_NamespaceStatus_To_v1_NamespaceStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_core_Namespace_To_v1_Namespace is an autogenerated conversion function. +func Convert_core_Namespace_To_v1_Namespace(in *core.Namespace, out *v1.Namespace, s conversion.Scope) error { + return autoConvert_core_Namespace_To_v1_Namespace(in, out, s) +} + +func autoConvert_v1_NamespaceCondition_To_core_NamespaceCondition(in *v1.NamespaceCondition, out *core.NamespaceCondition, s conversion.Scope) error { + out.Type = core.NamespaceConditionType(in.Type) + out.Status = core.ConditionStatus(in.Status) + out.LastTransitionTime = in.LastTransitionTime + out.Reason = in.Reason + out.Message = in.Message + return nil +} + +// Convert_v1_NamespaceCondition_To_core_NamespaceCondition is an autogenerated conversion function. +func Convert_v1_NamespaceCondition_To_core_NamespaceCondition(in *v1.NamespaceCondition, out *core.NamespaceCondition, s conversion.Scope) error { + return autoConvert_v1_NamespaceCondition_To_core_NamespaceCondition(in, out, s) +} + +func autoConvert_core_NamespaceCondition_To_v1_NamespaceCondition(in *core.NamespaceCondition, out *v1.NamespaceCondition, s conversion.Scope) error { + out.Type = v1.NamespaceConditionType(in.Type) + out.Status = v1.ConditionStatus(in.Status) + out.LastTransitionTime = in.LastTransitionTime + out.Reason = in.Reason + out.Message = in.Message + return nil +} + +// Convert_core_NamespaceCondition_To_v1_NamespaceCondition is an autogenerated conversion function. +func Convert_core_NamespaceCondition_To_v1_NamespaceCondition(in *core.NamespaceCondition, out *v1.NamespaceCondition, s conversion.Scope) error { + return autoConvert_core_NamespaceCondition_To_v1_NamespaceCondition(in, out, s) +} + +func autoConvert_v1_NamespaceList_To_core_NamespaceList(in *v1.NamespaceList, out *core.NamespaceList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]core.Namespace)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1_NamespaceList_To_core_NamespaceList is an autogenerated conversion function. +func Convert_v1_NamespaceList_To_core_NamespaceList(in *v1.NamespaceList, out *core.NamespaceList, s conversion.Scope) error { + return autoConvert_v1_NamespaceList_To_core_NamespaceList(in, out, s) +} + +func autoConvert_core_NamespaceList_To_v1_NamespaceList(in *core.NamespaceList, out *v1.NamespaceList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]v1.Namespace)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_core_NamespaceList_To_v1_NamespaceList is an autogenerated conversion function. +func Convert_core_NamespaceList_To_v1_NamespaceList(in *core.NamespaceList, out *v1.NamespaceList, s conversion.Scope) error { + return autoConvert_core_NamespaceList_To_v1_NamespaceList(in, out, s) +} + +func autoConvert_v1_NamespaceSpec_To_core_NamespaceSpec(in *v1.NamespaceSpec, out *core.NamespaceSpec, s conversion.Scope) error { + out.Finalizers = *(*[]core.FinalizerName)(unsafe.Pointer(&in.Finalizers)) + return nil +} + +// Convert_v1_NamespaceSpec_To_core_NamespaceSpec is an autogenerated conversion function. +func Convert_v1_NamespaceSpec_To_core_NamespaceSpec(in *v1.NamespaceSpec, out *core.NamespaceSpec, s conversion.Scope) error { + return autoConvert_v1_NamespaceSpec_To_core_NamespaceSpec(in, out, s) +} + +func autoConvert_core_NamespaceSpec_To_v1_NamespaceSpec(in *core.NamespaceSpec, out *v1.NamespaceSpec, s conversion.Scope) error { + out.Finalizers = *(*[]v1.FinalizerName)(unsafe.Pointer(&in.Finalizers)) + return nil +} + +// Convert_core_NamespaceSpec_To_v1_NamespaceSpec is an autogenerated conversion function. +func Convert_core_NamespaceSpec_To_v1_NamespaceSpec(in *core.NamespaceSpec, out *v1.NamespaceSpec, s conversion.Scope) error { + return autoConvert_core_NamespaceSpec_To_v1_NamespaceSpec(in, out, s) +} + +func autoConvert_v1_NamespaceStatus_To_core_NamespaceStatus(in *v1.NamespaceStatus, out *core.NamespaceStatus, s conversion.Scope) error { + out.Phase = core.NamespacePhase(in.Phase) + out.Conditions = *(*[]core.NamespaceCondition)(unsafe.Pointer(&in.Conditions)) + return nil +} + +// Convert_v1_NamespaceStatus_To_core_NamespaceStatus is an autogenerated conversion function. +func Convert_v1_NamespaceStatus_To_core_NamespaceStatus(in *v1.NamespaceStatus, out *core.NamespaceStatus, s conversion.Scope) error { + return autoConvert_v1_NamespaceStatus_To_core_NamespaceStatus(in, out, s) +} + +func autoConvert_core_NamespaceStatus_To_v1_NamespaceStatus(in *core.NamespaceStatus, out *v1.NamespaceStatus, s conversion.Scope) error { + out.Phase = v1.NamespacePhase(in.Phase) + out.Conditions = *(*[]v1.NamespaceCondition)(unsafe.Pointer(&in.Conditions)) + return nil +} + +// Convert_core_NamespaceStatus_To_v1_NamespaceStatus is an autogenerated conversion function. +func Convert_core_NamespaceStatus_To_v1_NamespaceStatus(in *core.NamespaceStatus, out *v1.NamespaceStatus, s conversion.Scope) error { + return autoConvert_core_NamespaceStatus_To_v1_NamespaceStatus(in, out, s) +} + +func autoConvert_v1_Node_To_core_Node(in *v1.Node, out *core.Node, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_NodeSpec_To_core_NodeSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_v1_NodeStatus_To_core_NodeStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1_Node_To_core_Node is an autogenerated conversion function. +func Convert_v1_Node_To_core_Node(in *v1.Node, out *core.Node, s conversion.Scope) error { + return autoConvert_v1_Node_To_core_Node(in, out, s) +} + +func autoConvert_core_Node_To_v1_Node(in *core.Node, out *v1.Node, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_core_NodeSpec_To_v1_NodeSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_core_NodeStatus_To_v1_NodeStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_core_Node_To_v1_Node is an autogenerated conversion function. +func Convert_core_Node_To_v1_Node(in *core.Node, out *v1.Node, s conversion.Scope) error { + return autoConvert_core_Node_To_v1_Node(in, out, s) +} + +func autoConvert_v1_NodeAddress_To_core_NodeAddress(in *v1.NodeAddress, out *core.NodeAddress, s conversion.Scope) error { + out.Type = core.NodeAddressType(in.Type) + out.Address = in.Address + return nil +} + +// Convert_v1_NodeAddress_To_core_NodeAddress is an autogenerated conversion function. +func Convert_v1_NodeAddress_To_core_NodeAddress(in *v1.NodeAddress, out *core.NodeAddress, s conversion.Scope) error { + return autoConvert_v1_NodeAddress_To_core_NodeAddress(in, out, s) +} + +func autoConvert_core_NodeAddress_To_v1_NodeAddress(in *core.NodeAddress, out *v1.NodeAddress, s conversion.Scope) error { + out.Type = v1.NodeAddressType(in.Type) + out.Address = in.Address + return nil +} + +// Convert_core_NodeAddress_To_v1_NodeAddress is an autogenerated conversion function. +func Convert_core_NodeAddress_To_v1_NodeAddress(in *core.NodeAddress, out *v1.NodeAddress, s conversion.Scope) error { + return autoConvert_core_NodeAddress_To_v1_NodeAddress(in, out, s) +} + +func autoConvert_v1_NodeAffinity_To_core_NodeAffinity(in *v1.NodeAffinity, out *core.NodeAffinity, s conversion.Scope) error { + out.RequiredDuringSchedulingIgnoredDuringExecution = (*core.NodeSelector)(unsafe.Pointer(in.RequiredDuringSchedulingIgnoredDuringExecution)) + out.PreferredDuringSchedulingIgnoredDuringExecution = *(*[]core.PreferredSchedulingTerm)(unsafe.Pointer(&in.PreferredDuringSchedulingIgnoredDuringExecution)) + return nil +} + +// Convert_v1_NodeAffinity_To_core_NodeAffinity is an autogenerated conversion function. +func Convert_v1_NodeAffinity_To_core_NodeAffinity(in *v1.NodeAffinity, out *core.NodeAffinity, s conversion.Scope) error { + return autoConvert_v1_NodeAffinity_To_core_NodeAffinity(in, out, s) +} + +func autoConvert_core_NodeAffinity_To_v1_NodeAffinity(in *core.NodeAffinity, out *v1.NodeAffinity, s conversion.Scope) error { + out.RequiredDuringSchedulingIgnoredDuringExecution = (*v1.NodeSelector)(unsafe.Pointer(in.RequiredDuringSchedulingIgnoredDuringExecution)) + out.PreferredDuringSchedulingIgnoredDuringExecution = *(*[]v1.PreferredSchedulingTerm)(unsafe.Pointer(&in.PreferredDuringSchedulingIgnoredDuringExecution)) + return nil +} + +// Convert_core_NodeAffinity_To_v1_NodeAffinity is an autogenerated conversion function. +func Convert_core_NodeAffinity_To_v1_NodeAffinity(in *core.NodeAffinity, out *v1.NodeAffinity, s conversion.Scope) error { + return autoConvert_core_NodeAffinity_To_v1_NodeAffinity(in, out, s) +} + +func autoConvert_v1_NodeCondition_To_core_NodeCondition(in *v1.NodeCondition, out *core.NodeCondition, s conversion.Scope) error { + out.Type = core.NodeConditionType(in.Type) + out.Status = core.ConditionStatus(in.Status) + out.LastHeartbeatTime = in.LastHeartbeatTime + out.LastTransitionTime = in.LastTransitionTime + out.Reason = in.Reason + out.Message = in.Message + return nil +} + +// Convert_v1_NodeCondition_To_core_NodeCondition is an autogenerated conversion function. +func Convert_v1_NodeCondition_To_core_NodeCondition(in *v1.NodeCondition, out *core.NodeCondition, s conversion.Scope) error { + return autoConvert_v1_NodeCondition_To_core_NodeCondition(in, out, s) +} + +func autoConvert_core_NodeCondition_To_v1_NodeCondition(in *core.NodeCondition, out *v1.NodeCondition, s conversion.Scope) error { + out.Type = v1.NodeConditionType(in.Type) + out.Status = v1.ConditionStatus(in.Status) + out.LastHeartbeatTime = in.LastHeartbeatTime + out.LastTransitionTime = in.LastTransitionTime + out.Reason = in.Reason + out.Message = in.Message + return nil +} + +// Convert_core_NodeCondition_To_v1_NodeCondition is an autogenerated conversion function. +func Convert_core_NodeCondition_To_v1_NodeCondition(in *core.NodeCondition, out *v1.NodeCondition, s conversion.Scope) error { + return autoConvert_core_NodeCondition_To_v1_NodeCondition(in, out, s) +} + +func autoConvert_v1_NodeConfigSource_To_core_NodeConfigSource(in *v1.NodeConfigSource, out *core.NodeConfigSource, s conversion.Scope) error { + out.ConfigMap = (*core.ConfigMapNodeConfigSource)(unsafe.Pointer(in.ConfigMap)) + return nil +} + +// Convert_v1_NodeConfigSource_To_core_NodeConfigSource is an autogenerated conversion function. +func Convert_v1_NodeConfigSource_To_core_NodeConfigSource(in *v1.NodeConfigSource, out *core.NodeConfigSource, s conversion.Scope) error { + return autoConvert_v1_NodeConfigSource_To_core_NodeConfigSource(in, out, s) +} + +func autoConvert_core_NodeConfigSource_To_v1_NodeConfigSource(in *core.NodeConfigSource, out *v1.NodeConfigSource, s conversion.Scope) error { + out.ConfigMap = (*v1.ConfigMapNodeConfigSource)(unsafe.Pointer(in.ConfigMap)) + return nil +} + +// Convert_core_NodeConfigSource_To_v1_NodeConfigSource is an autogenerated conversion function. +func Convert_core_NodeConfigSource_To_v1_NodeConfigSource(in *core.NodeConfigSource, out *v1.NodeConfigSource, s conversion.Scope) error { + return autoConvert_core_NodeConfigSource_To_v1_NodeConfigSource(in, out, s) +} + +func autoConvert_v1_NodeConfigStatus_To_core_NodeConfigStatus(in *v1.NodeConfigStatus, out *core.NodeConfigStatus, s conversion.Scope) error { + out.Assigned = (*core.NodeConfigSource)(unsafe.Pointer(in.Assigned)) + out.Active = (*core.NodeConfigSource)(unsafe.Pointer(in.Active)) + out.LastKnownGood = (*core.NodeConfigSource)(unsafe.Pointer(in.LastKnownGood)) + out.Error = in.Error + return nil +} + +// Convert_v1_NodeConfigStatus_To_core_NodeConfigStatus is an autogenerated conversion function. +func Convert_v1_NodeConfigStatus_To_core_NodeConfigStatus(in *v1.NodeConfigStatus, out *core.NodeConfigStatus, s conversion.Scope) error { + return autoConvert_v1_NodeConfigStatus_To_core_NodeConfigStatus(in, out, s) +} + +func autoConvert_core_NodeConfigStatus_To_v1_NodeConfigStatus(in *core.NodeConfigStatus, out *v1.NodeConfigStatus, s conversion.Scope) error { + out.Assigned = (*v1.NodeConfigSource)(unsafe.Pointer(in.Assigned)) + out.Active = (*v1.NodeConfigSource)(unsafe.Pointer(in.Active)) + out.LastKnownGood = (*v1.NodeConfigSource)(unsafe.Pointer(in.LastKnownGood)) + out.Error = in.Error + return nil +} + +// Convert_core_NodeConfigStatus_To_v1_NodeConfigStatus is an autogenerated conversion function. +func Convert_core_NodeConfigStatus_To_v1_NodeConfigStatus(in *core.NodeConfigStatus, out *v1.NodeConfigStatus, s conversion.Scope) error { + return autoConvert_core_NodeConfigStatus_To_v1_NodeConfigStatus(in, out, s) +} + +func autoConvert_v1_NodeDaemonEndpoints_To_core_NodeDaemonEndpoints(in *v1.NodeDaemonEndpoints, out *core.NodeDaemonEndpoints, s conversion.Scope) error { + if err := Convert_v1_DaemonEndpoint_To_core_DaemonEndpoint(&in.KubeletEndpoint, &out.KubeletEndpoint, s); err != nil { + return err + } + return nil +} + +// Convert_v1_NodeDaemonEndpoints_To_core_NodeDaemonEndpoints is an autogenerated conversion function. +func Convert_v1_NodeDaemonEndpoints_To_core_NodeDaemonEndpoints(in *v1.NodeDaemonEndpoints, out *core.NodeDaemonEndpoints, s conversion.Scope) error { + return autoConvert_v1_NodeDaemonEndpoints_To_core_NodeDaemonEndpoints(in, out, s) +} + +func autoConvert_core_NodeDaemonEndpoints_To_v1_NodeDaemonEndpoints(in *core.NodeDaemonEndpoints, out *v1.NodeDaemonEndpoints, s conversion.Scope) error { + if err := Convert_core_DaemonEndpoint_To_v1_DaemonEndpoint(&in.KubeletEndpoint, &out.KubeletEndpoint, s); err != nil { + return err + } + return nil +} + +// Convert_core_NodeDaemonEndpoints_To_v1_NodeDaemonEndpoints is an autogenerated conversion function. +func Convert_core_NodeDaemonEndpoints_To_v1_NodeDaemonEndpoints(in *core.NodeDaemonEndpoints, out *v1.NodeDaemonEndpoints, s conversion.Scope) error { + return autoConvert_core_NodeDaemonEndpoints_To_v1_NodeDaemonEndpoints(in, out, s) +} + +func autoConvert_v1_NodeList_To_core_NodeList(in *v1.NodeList, out *core.NodeList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]core.Node, len(*in)) + for i := range *in { + if err := Convert_v1_Node_To_core_Node(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +// Convert_v1_NodeList_To_core_NodeList is an autogenerated conversion function. +func Convert_v1_NodeList_To_core_NodeList(in *v1.NodeList, out *core.NodeList, s conversion.Scope) error { + return autoConvert_v1_NodeList_To_core_NodeList(in, out, s) +} + +func autoConvert_core_NodeList_To_v1_NodeList(in *core.NodeList, out *v1.NodeList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]v1.Node, len(*in)) + for i := range *in { + if err := Convert_core_Node_To_v1_Node(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +// Convert_core_NodeList_To_v1_NodeList is an autogenerated conversion function. +func Convert_core_NodeList_To_v1_NodeList(in *core.NodeList, out *v1.NodeList, s conversion.Scope) error { + return autoConvert_core_NodeList_To_v1_NodeList(in, out, s) +} + +func autoConvert_v1_NodeProxyOptions_To_core_NodeProxyOptions(in *v1.NodeProxyOptions, out *core.NodeProxyOptions, s conversion.Scope) error { + out.Path = in.Path + return nil +} + +// Convert_v1_NodeProxyOptions_To_core_NodeProxyOptions is an autogenerated conversion function. +func Convert_v1_NodeProxyOptions_To_core_NodeProxyOptions(in *v1.NodeProxyOptions, out *core.NodeProxyOptions, s conversion.Scope) error { + return autoConvert_v1_NodeProxyOptions_To_core_NodeProxyOptions(in, out, s) +} + +func autoConvert_core_NodeProxyOptions_To_v1_NodeProxyOptions(in *core.NodeProxyOptions, out *v1.NodeProxyOptions, s conversion.Scope) error { + out.Path = in.Path + return nil +} + +// Convert_core_NodeProxyOptions_To_v1_NodeProxyOptions is an autogenerated conversion function. +func Convert_core_NodeProxyOptions_To_v1_NodeProxyOptions(in *core.NodeProxyOptions, out *v1.NodeProxyOptions, s conversion.Scope) error { + return autoConvert_core_NodeProxyOptions_To_v1_NodeProxyOptions(in, out, s) +} + +func autoConvert_url_Values_To_v1_NodeProxyOptions(in *url.Values, out *v1.NodeProxyOptions, s conversion.Scope) error { + // WARNING: Field TypeMeta does not have json tag, skipping. + + if values, ok := map[string][]string(*in)["path"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_string(&values, &out.Path, s); err != nil { + return err + } + } else { + out.Path = "" + } + return nil +} + +// Convert_url_Values_To_v1_NodeProxyOptions is an autogenerated conversion function. +func Convert_url_Values_To_v1_NodeProxyOptions(in *url.Values, out *v1.NodeProxyOptions, s conversion.Scope) error { + return autoConvert_url_Values_To_v1_NodeProxyOptions(in, out, s) +} + +func autoConvert_v1_NodeResources_To_core_NodeResources(in *v1.NodeResources, out *core.NodeResources, s conversion.Scope) error { + out.Capacity = *(*core.ResourceList)(unsafe.Pointer(&in.Capacity)) + return nil +} + +// Convert_v1_NodeResources_To_core_NodeResources is an autogenerated conversion function. +func Convert_v1_NodeResources_To_core_NodeResources(in *v1.NodeResources, out *core.NodeResources, s conversion.Scope) error { + return autoConvert_v1_NodeResources_To_core_NodeResources(in, out, s) +} + +func autoConvert_core_NodeResources_To_v1_NodeResources(in *core.NodeResources, out *v1.NodeResources, s conversion.Scope) error { + out.Capacity = *(*v1.ResourceList)(unsafe.Pointer(&in.Capacity)) + return nil +} + +// Convert_core_NodeResources_To_v1_NodeResources is an autogenerated conversion function. +func Convert_core_NodeResources_To_v1_NodeResources(in *core.NodeResources, out *v1.NodeResources, s conversion.Scope) error { + return autoConvert_core_NodeResources_To_v1_NodeResources(in, out, s) +} + +func autoConvert_v1_NodeSelector_To_core_NodeSelector(in *v1.NodeSelector, out *core.NodeSelector, s conversion.Scope) error { + out.NodeSelectorTerms = *(*[]core.NodeSelectorTerm)(unsafe.Pointer(&in.NodeSelectorTerms)) + return nil +} + +// Convert_v1_NodeSelector_To_core_NodeSelector is an autogenerated conversion function. +func Convert_v1_NodeSelector_To_core_NodeSelector(in *v1.NodeSelector, out *core.NodeSelector, s conversion.Scope) error { + return autoConvert_v1_NodeSelector_To_core_NodeSelector(in, out, s) +} + +func autoConvert_core_NodeSelector_To_v1_NodeSelector(in *core.NodeSelector, out *v1.NodeSelector, s conversion.Scope) error { + out.NodeSelectorTerms = *(*[]v1.NodeSelectorTerm)(unsafe.Pointer(&in.NodeSelectorTerms)) + return nil +} + +// Convert_core_NodeSelector_To_v1_NodeSelector is an autogenerated conversion function. +func Convert_core_NodeSelector_To_v1_NodeSelector(in *core.NodeSelector, out *v1.NodeSelector, s conversion.Scope) error { + return autoConvert_core_NodeSelector_To_v1_NodeSelector(in, out, s) +} + +func autoConvert_v1_NodeSelectorRequirement_To_core_NodeSelectorRequirement(in *v1.NodeSelectorRequirement, out *core.NodeSelectorRequirement, s conversion.Scope) error { + out.Key = in.Key + out.Operator = core.NodeSelectorOperator(in.Operator) + out.Values = *(*[]string)(unsafe.Pointer(&in.Values)) + return nil +} + +// Convert_v1_NodeSelectorRequirement_To_core_NodeSelectorRequirement is an autogenerated conversion function. +func Convert_v1_NodeSelectorRequirement_To_core_NodeSelectorRequirement(in *v1.NodeSelectorRequirement, out *core.NodeSelectorRequirement, s conversion.Scope) error { + return autoConvert_v1_NodeSelectorRequirement_To_core_NodeSelectorRequirement(in, out, s) +} + +func autoConvert_core_NodeSelectorRequirement_To_v1_NodeSelectorRequirement(in *core.NodeSelectorRequirement, out *v1.NodeSelectorRequirement, s conversion.Scope) error { + out.Key = in.Key + out.Operator = v1.NodeSelectorOperator(in.Operator) + out.Values = *(*[]string)(unsafe.Pointer(&in.Values)) + return nil +} + +// Convert_core_NodeSelectorRequirement_To_v1_NodeSelectorRequirement is an autogenerated conversion function. +func Convert_core_NodeSelectorRequirement_To_v1_NodeSelectorRequirement(in *core.NodeSelectorRequirement, out *v1.NodeSelectorRequirement, s conversion.Scope) error { + return autoConvert_core_NodeSelectorRequirement_To_v1_NodeSelectorRequirement(in, out, s) +} + +func autoConvert_v1_NodeSelectorTerm_To_core_NodeSelectorTerm(in *v1.NodeSelectorTerm, out *core.NodeSelectorTerm, s conversion.Scope) error { + out.MatchExpressions = *(*[]core.NodeSelectorRequirement)(unsafe.Pointer(&in.MatchExpressions)) + out.MatchFields = *(*[]core.NodeSelectorRequirement)(unsafe.Pointer(&in.MatchFields)) + return nil +} + +// Convert_v1_NodeSelectorTerm_To_core_NodeSelectorTerm is an autogenerated conversion function. +func Convert_v1_NodeSelectorTerm_To_core_NodeSelectorTerm(in *v1.NodeSelectorTerm, out *core.NodeSelectorTerm, s conversion.Scope) error { + return autoConvert_v1_NodeSelectorTerm_To_core_NodeSelectorTerm(in, out, s) +} + +func autoConvert_core_NodeSelectorTerm_To_v1_NodeSelectorTerm(in *core.NodeSelectorTerm, out *v1.NodeSelectorTerm, s conversion.Scope) error { + out.MatchExpressions = *(*[]v1.NodeSelectorRequirement)(unsafe.Pointer(&in.MatchExpressions)) + out.MatchFields = *(*[]v1.NodeSelectorRequirement)(unsafe.Pointer(&in.MatchFields)) + return nil +} + +// Convert_core_NodeSelectorTerm_To_v1_NodeSelectorTerm is an autogenerated conversion function. +func Convert_core_NodeSelectorTerm_To_v1_NodeSelectorTerm(in *core.NodeSelectorTerm, out *v1.NodeSelectorTerm, s conversion.Scope) error { + return autoConvert_core_NodeSelectorTerm_To_v1_NodeSelectorTerm(in, out, s) +} + +func autoConvert_v1_NodeSpec_To_core_NodeSpec(in *v1.NodeSpec, out *core.NodeSpec, s conversion.Scope) error { + // WARNING: in.PodCIDR requires manual conversion: does not exist in peer-type + out.PodCIDRs = *(*[]string)(unsafe.Pointer(&in.PodCIDRs)) + out.ProviderID = in.ProviderID + out.Unschedulable = in.Unschedulable + out.Taints = *(*[]core.Taint)(unsafe.Pointer(&in.Taints)) + out.ConfigSource = (*core.NodeConfigSource)(unsafe.Pointer(in.ConfigSource)) + out.DoNotUseExternalID = in.DoNotUseExternalID + return nil +} + +func autoConvert_core_NodeSpec_To_v1_NodeSpec(in *core.NodeSpec, out *v1.NodeSpec, s conversion.Scope) error { + out.PodCIDRs = *(*[]string)(unsafe.Pointer(&in.PodCIDRs)) + out.ProviderID = in.ProviderID + out.Unschedulable = in.Unschedulable + out.Taints = *(*[]v1.Taint)(unsafe.Pointer(&in.Taints)) + out.ConfigSource = (*v1.NodeConfigSource)(unsafe.Pointer(in.ConfigSource)) + out.DoNotUseExternalID = in.DoNotUseExternalID + return nil +} + +func autoConvert_v1_NodeStatus_To_core_NodeStatus(in *v1.NodeStatus, out *core.NodeStatus, s conversion.Scope) error { + out.Capacity = *(*core.ResourceList)(unsafe.Pointer(&in.Capacity)) + out.Allocatable = *(*core.ResourceList)(unsafe.Pointer(&in.Allocatable)) + out.Phase = core.NodePhase(in.Phase) + out.Conditions = *(*[]core.NodeCondition)(unsafe.Pointer(&in.Conditions)) + out.Addresses = *(*[]core.NodeAddress)(unsafe.Pointer(&in.Addresses)) + if err := Convert_v1_NodeDaemonEndpoints_To_core_NodeDaemonEndpoints(&in.DaemonEndpoints, &out.DaemonEndpoints, s); err != nil { + return err + } + if err := Convert_v1_NodeSystemInfo_To_core_NodeSystemInfo(&in.NodeInfo, &out.NodeInfo, s); err != nil { + return err + } + out.Images = *(*[]core.ContainerImage)(unsafe.Pointer(&in.Images)) + out.VolumesInUse = *(*[]core.UniqueVolumeName)(unsafe.Pointer(&in.VolumesInUse)) + out.VolumesAttached = *(*[]core.AttachedVolume)(unsafe.Pointer(&in.VolumesAttached)) + out.Config = (*core.NodeConfigStatus)(unsafe.Pointer(in.Config)) + return nil +} + +// Convert_v1_NodeStatus_To_core_NodeStatus is an autogenerated conversion function. +func Convert_v1_NodeStatus_To_core_NodeStatus(in *v1.NodeStatus, out *core.NodeStatus, s conversion.Scope) error { + return autoConvert_v1_NodeStatus_To_core_NodeStatus(in, out, s) +} + +func autoConvert_core_NodeStatus_To_v1_NodeStatus(in *core.NodeStatus, out *v1.NodeStatus, s conversion.Scope) error { + out.Capacity = *(*v1.ResourceList)(unsafe.Pointer(&in.Capacity)) + out.Allocatable = *(*v1.ResourceList)(unsafe.Pointer(&in.Allocatable)) + out.Phase = v1.NodePhase(in.Phase) + out.Conditions = *(*[]v1.NodeCondition)(unsafe.Pointer(&in.Conditions)) + out.Addresses = *(*[]v1.NodeAddress)(unsafe.Pointer(&in.Addresses)) + if err := Convert_core_NodeDaemonEndpoints_To_v1_NodeDaemonEndpoints(&in.DaemonEndpoints, &out.DaemonEndpoints, s); err != nil { + return err + } + if err := Convert_core_NodeSystemInfo_To_v1_NodeSystemInfo(&in.NodeInfo, &out.NodeInfo, s); err != nil { + return err + } + out.Images = *(*[]v1.ContainerImage)(unsafe.Pointer(&in.Images)) + out.VolumesInUse = *(*[]v1.UniqueVolumeName)(unsafe.Pointer(&in.VolumesInUse)) + out.VolumesAttached = *(*[]v1.AttachedVolume)(unsafe.Pointer(&in.VolumesAttached)) + out.Config = (*v1.NodeConfigStatus)(unsafe.Pointer(in.Config)) + return nil +} + +// Convert_core_NodeStatus_To_v1_NodeStatus is an autogenerated conversion function. +func Convert_core_NodeStatus_To_v1_NodeStatus(in *core.NodeStatus, out *v1.NodeStatus, s conversion.Scope) error { + return autoConvert_core_NodeStatus_To_v1_NodeStatus(in, out, s) +} + +func autoConvert_v1_NodeSystemInfo_To_core_NodeSystemInfo(in *v1.NodeSystemInfo, out *core.NodeSystemInfo, s conversion.Scope) error { + out.MachineID = in.MachineID + out.SystemUUID = in.SystemUUID + out.BootID = in.BootID + out.KernelVersion = in.KernelVersion + out.OSImage = in.OSImage + out.ContainerRuntimeVersion = in.ContainerRuntimeVersion + out.KubeletVersion = in.KubeletVersion + out.KubeProxyVersion = in.KubeProxyVersion + out.OperatingSystem = in.OperatingSystem + out.Architecture = in.Architecture + return nil +} + +// Convert_v1_NodeSystemInfo_To_core_NodeSystemInfo is an autogenerated conversion function. +func Convert_v1_NodeSystemInfo_To_core_NodeSystemInfo(in *v1.NodeSystemInfo, out *core.NodeSystemInfo, s conversion.Scope) error { + return autoConvert_v1_NodeSystemInfo_To_core_NodeSystemInfo(in, out, s) +} + +func autoConvert_core_NodeSystemInfo_To_v1_NodeSystemInfo(in *core.NodeSystemInfo, out *v1.NodeSystemInfo, s conversion.Scope) error { + out.MachineID = in.MachineID + out.SystemUUID = in.SystemUUID + out.BootID = in.BootID + out.KernelVersion = in.KernelVersion + out.OSImage = in.OSImage + out.ContainerRuntimeVersion = in.ContainerRuntimeVersion + out.KubeletVersion = in.KubeletVersion + out.KubeProxyVersion = in.KubeProxyVersion + out.OperatingSystem = in.OperatingSystem + out.Architecture = in.Architecture + return nil +} + +// Convert_core_NodeSystemInfo_To_v1_NodeSystemInfo is an autogenerated conversion function. +func Convert_core_NodeSystemInfo_To_v1_NodeSystemInfo(in *core.NodeSystemInfo, out *v1.NodeSystemInfo, s conversion.Scope) error { + return autoConvert_core_NodeSystemInfo_To_v1_NodeSystemInfo(in, out, s) +} + +func autoConvert_v1_ObjectFieldSelector_To_core_ObjectFieldSelector(in *v1.ObjectFieldSelector, out *core.ObjectFieldSelector, s conversion.Scope) error { + out.APIVersion = in.APIVersion + out.FieldPath = in.FieldPath + return nil +} + +// Convert_v1_ObjectFieldSelector_To_core_ObjectFieldSelector is an autogenerated conversion function. +func Convert_v1_ObjectFieldSelector_To_core_ObjectFieldSelector(in *v1.ObjectFieldSelector, out *core.ObjectFieldSelector, s conversion.Scope) error { + return autoConvert_v1_ObjectFieldSelector_To_core_ObjectFieldSelector(in, out, s) +} + +func autoConvert_core_ObjectFieldSelector_To_v1_ObjectFieldSelector(in *core.ObjectFieldSelector, out *v1.ObjectFieldSelector, s conversion.Scope) error { + out.APIVersion = in.APIVersion + out.FieldPath = in.FieldPath + return nil +} + +// Convert_core_ObjectFieldSelector_To_v1_ObjectFieldSelector is an autogenerated conversion function. +func Convert_core_ObjectFieldSelector_To_v1_ObjectFieldSelector(in *core.ObjectFieldSelector, out *v1.ObjectFieldSelector, s conversion.Scope) error { + return autoConvert_core_ObjectFieldSelector_To_v1_ObjectFieldSelector(in, out, s) +} + +func autoConvert_v1_ObjectReference_To_core_ObjectReference(in *v1.ObjectReference, out *core.ObjectReference, s conversion.Scope) error { + out.Kind = in.Kind + out.Namespace = in.Namespace + out.Name = in.Name + out.UID = types.UID(in.UID) + out.APIVersion = in.APIVersion + out.ResourceVersion = in.ResourceVersion + out.FieldPath = in.FieldPath + return nil +} + +// Convert_v1_ObjectReference_To_core_ObjectReference is an autogenerated conversion function. +func Convert_v1_ObjectReference_To_core_ObjectReference(in *v1.ObjectReference, out *core.ObjectReference, s conversion.Scope) error { + return autoConvert_v1_ObjectReference_To_core_ObjectReference(in, out, s) +} + +func autoConvert_core_ObjectReference_To_v1_ObjectReference(in *core.ObjectReference, out *v1.ObjectReference, s conversion.Scope) error { + out.Kind = in.Kind + out.Namespace = in.Namespace + out.Name = in.Name + out.UID = types.UID(in.UID) + out.APIVersion = in.APIVersion + out.ResourceVersion = in.ResourceVersion + out.FieldPath = in.FieldPath + return nil +} + +// Convert_core_ObjectReference_To_v1_ObjectReference is an autogenerated conversion function. +func Convert_core_ObjectReference_To_v1_ObjectReference(in *core.ObjectReference, out *v1.ObjectReference, s conversion.Scope) error { + return autoConvert_core_ObjectReference_To_v1_ObjectReference(in, out, s) +} + +func autoConvert_v1_PersistentVolume_To_core_PersistentVolume(in *v1.PersistentVolume, out *core.PersistentVolume, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_PersistentVolumeSpec_To_core_PersistentVolumeSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_v1_PersistentVolumeStatus_To_core_PersistentVolumeStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1_PersistentVolume_To_core_PersistentVolume is an autogenerated conversion function. +func Convert_v1_PersistentVolume_To_core_PersistentVolume(in *v1.PersistentVolume, out *core.PersistentVolume, s conversion.Scope) error { + return autoConvert_v1_PersistentVolume_To_core_PersistentVolume(in, out, s) +} + +func autoConvert_core_PersistentVolume_To_v1_PersistentVolume(in *core.PersistentVolume, out *v1.PersistentVolume, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_core_PersistentVolumeSpec_To_v1_PersistentVolumeSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_core_PersistentVolumeStatus_To_v1_PersistentVolumeStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_core_PersistentVolume_To_v1_PersistentVolume is an autogenerated conversion function. +func Convert_core_PersistentVolume_To_v1_PersistentVolume(in *core.PersistentVolume, out *v1.PersistentVolume, s conversion.Scope) error { + return autoConvert_core_PersistentVolume_To_v1_PersistentVolume(in, out, s) +} + +func autoConvert_v1_PersistentVolumeClaim_To_core_PersistentVolumeClaim(in *v1.PersistentVolumeClaim, out *core.PersistentVolumeClaim, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_PersistentVolumeClaimSpec_To_core_PersistentVolumeClaimSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_v1_PersistentVolumeClaimStatus_To_core_PersistentVolumeClaimStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1_PersistentVolumeClaim_To_core_PersistentVolumeClaim is an autogenerated conversion function. +func Convert_v1_PersistentVolumeClaim_To_core_PersistentVolumeClaim(in *v1.PersistentVolumeClaim, out *core.PersistentVolumeClaim, s conversion.Scope) error { + return autoConvert_v1_PersistentVolumeClaim_To_core_PersistentVolumeClaim(in, out, s) +} + +func autoConvert_core_PersistentVolumeClaim_To_v1_PersistentVolumeClaim(in *core.PersistentVolumeClaim, out *v1.PersistentVolumeClaim, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_core_PersistentVolumeClaimSpec_To_v1_PersistentVolumeClaimSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_core_PersistentVolumeClaimStatus_To_v1_PersistentVolumeClaimStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_core_PersistentVolumeClaim_To_v1_PersistentVolumeClaim is an autogenerated conversion function. +func Convert_core_PersistentVolumeClaim_To_v1_PersistentVolumeClaim(in *core.PersistentVolumeClaim, out *v1.PersistentVolumeClaim, s conversion.Scope) error { + return autoConvert_core_PersistentVolumeClaim_To_v1_PersistentVolumeClaim(in, out, s) +} + +func autoConvert_v1_PersistentVolumeClaimCondition_To_core_PersistentVolumeClaimCondition(in *v1.PersistentVolumeClaimCondition, out *core.PersistentVolumeClaimCondition, s conversion.Scope) error { + out.Type = core.PersistentVolumeClaimConditionType(in.Type) + out.Status = core.ConditionStatus(in.Status) + out.LastProbeTime = in.LastProbeTime + out.LastTransitionTime = in.LastTransitionTime + out.Reason = in.Reason + out.Message = in.Message + return nil +} + +// Convert_v1_PersistentVolumeClaimCondition_To_core_PersistentVolumeClaimCondition is an autogenerated conversion function. +func Convert_v1_PersistentVolumeClaimCondition_To_core_PersistentVolumeClaimCondition(in *v1.PersistentVolumeClaimCondition, out *core.PersistentVolumeClaimCondition, s conversion.Scope) error { + return autoConvert_v1_PersistentVolumeClaimCondition_To_core_PersistentVolumeClaimCondition(in, out, s) +} + +func autoConvert_core_PersistentVolumeClaimCondition_To_v1_PersistentVolumeClaimCondition(in *core.PersistentVolumeClaimCondition, out *v1.PersistentVolumeClaimCondition, s conversion.Scope) error { + out.Type = v1.PersistentVolumeClaimConditionType(in.Type) + out.Status = v1.ConditionStatus(in.Status) + out.LastProbeTime = in.LastProbeTime + out.LastTransitionTime = in.LastTransitionTime + out.Reason = in.Reason + out.Message = in.Message + return nil +} + +// Convert_core_PersistentVolumeClaimCondition_To_v1_PersistentVolumeClaimCondition is an autogenerated conversion function. +func Convert_core_PersistentVolumeClaimCondition_To_v1_PersistentVolumeClaimCondition(in *core.PersistentVolumeClaimCondition, out *v1.PersistentVolumeClaimCondition, s conversion.Scope) error { + return autoConvert_core_PersistentVolumeClaimCondition_To_v1_PersistentVolumeClaimCondition(in, out, s) +} + +func autoConvert_v1_PersistentVolumeClaimList_To_core_PersistentVolumeClaimList(in *v1.PersistentVolumeClaimList, out *core.PersistentVolumeClaimList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]core.PersistentVolumeClaim)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1_PersistentVolumeClaimList_To_core_PersistentVolumeClaimList is an autogenerated conversion function. +func Convert_v1_PersistentVolumeClaimList_To_core_PersistentVolumeClaimList(in *v1.PersistentVolumeClaimList, out *core.PersistentVolumeClaimList, s conversion.Scope) error { + return autoConvert_v1_PersistentVolumeClaimList_To_core_PersistentVolumeClaimList(in, out, s) +} + +func autoConvert_core_PersistentVolumeClaimList_To_v1_PersistentVolumeClaimList(in *core.PersistentVolumeClaimList, out *v1.PersistentVolumeClaimList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]v1.PersistentVolumeClaim)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_core_PersistentVolumeClaimList_To_v1_PersistentVolumeClaimList is an autogenerated conversion function. +func Convert_core_PersistentVolumeClaimList_To_v1_PersistentVolumeClaimList(in *core.PersistentVolumeClaimList, out *v1.PersistentVolumeClaimList, s conversion.Scope) error { + return autoConvert_core_PersistentVolumeClaimList_To_v1_PersistentVolumeClaimList(in, out, s) +} + +func autoConvert_v1_PersistentVolumeClaimSpec_To_core_PersistentVolumeClaimSpec(in *v1.PersistentVolumeClaimSpec, out *core.PersistentVolumeClaimSpec, s conversion.Scope) error { + out.AccessModes = *(*[]core.PersistentVolumeAccessMode)(unsafe.Pointer(&in.AccessModes)) + out.Selector = (*metav1.LabelSelector)(unsafe.Pointer(in.Selector)) + if err := Convert_v1_ResourceRequirements_To_core_ResourceRequirements(&in.Resources, &out.Resources, s); err != nil { + return err + } + out.VolumeName = in.VolumeName + out.StorageClassName = (*string)(unsafe.Pointer(in.StorageClassName)) + out.VolumeMode = (*core.PersistentVolumeMode)(unsafe.Pointer(in.VolumeMode)) + out.DataSource = (*core.TypedLocalObjectReference)(unsafe.Pointer(in.DataSource)) + out.DataSourceRef = (*core.TypedObjectReference)(unsafe.Pointer(in.DataSourceRef)) + return nil +} + +// Convert_v1_PersistentVolumeClaimSpec_To_core_PersistentVolumeClaimSpec is an autogenerated conversion function. +func Convert_v1_PersistentVolumeClaimSpec_To_core_PersistentVolumeClaimSpec(in *v1.PersistentVolumeClaimSpec, out *core.PersistentVolumeClaimSpec, s conversion.Scope) error { + return autoConvert_v1_PersistentVolumeClaimSpec_To_core_PersistentVolumeClaimSpec(in, out, s) +} + +func autoConvert_core_PersistentVolumeClaimSpec_To_v1_PersistentVolumeClaimSpec(in *core.PersistentVolumeClaimSpec, out *v1.PersistentVolumeClaimSpec, s conversion.Scope) error { + out.AccessModes = *(*[]v1.PersistentVolumeAccessMode)(unsafe.Pointer(&in.AccessModes)) + out.Selector = (*metav1.LabelSelector)(unsafe.Pointer(in.Selector)) + if err := Convert_core_ResourceRequirements_To_v1_ResourceRequirements(&in.Resources, &out.Resources, s); err != nil { + return err + } + out.VolumeName = in.VolumeName + out.StorageClassName = (*string)(unsafe.Pointer(in.StorageClassName)) + out.VolumeMode = (*v1.PersistentVolumeMode)(unsafe.Pointer(in.VolumeMode)) + out.DataSource = (*v1.TypedLocalObjectReference)(unsafe.Pointer(in.DataSource)) + out.DataSourceRef = (*v1.TypedObjectReference)(unsafe.Pointer(in.DataSourceRef)) + return nil +} + +// Convert_core_PersistentVolumeClaimSpec_To_v1_PersistentVolumeClaimSpec is an autogenerated conversion function. +func Convert_core_PersistentVolumeClaimSpec_To_v1_PersistentVolumeClaimSpec(in *core.PersistentVolumeClaimSpec, out *v1.PersistentVolumeClaimSpec, s conversion.Scope) error { + return autoConvert_core_PersistentVolumeClaimSpec_To_v1_PersistentVolumeClaimSpec(in, out, s) +} + +func autoConvert_v1_PersistentVolumeClaimStatus_To_core_PersistentVolumeClaimStatus(in *v1.PersistentVolumeClaimStatus, out *core.PersistentVolumeClaimStatus, s conversion.Scope) error { + out.Phase = core.PersistentVolumeClaimPhase(in.Phase) + out.AccessModes = *(*[]core.PersistentVolumeAccessMode)(unsafe.Pointer(&in.AccessModes)) + out.Capacity = *(*core.ResourceList)(unsafe.Pointer(&in.Capacity)) + out.Conditions = *(*[]core.PersistentVolumeClaimCondition)(unsafe.Pointer(&in.Conditions)) + out.AllocatedResources = *(*core.ResourceList)(unsafe.Pointer(&in.AllocatedResources)) + out.ResizeStatus = (*core.PersistentVolumeClaimResizeStatus)(unsafe.Pointer(in.ResizeStatus)) + return nil +} + +// Convert_v1_PersistentVolumeClaimStatus_To_core_PersistentVolumeClaimStatus is an autogenerated conversion function. +func Convert_v1_PersistentVolumeClaimStatus_To_core_PersistentVolumeClaimStatus(in *v1.PersistentVolumeClaimStatus, out *core.PersistentVolumeClaimStatus, s conversion.Scope) error { + return autoConvert_v1_PersistentVolumeClaimStatus_To_core_PersistentVolumeClaimStatus(in, out, s) +} + +func autoConvert_core_PersistentVolumeClaimStatus_To_v1_PersistentVolumeClaimStatus(in *core.PersistentVolumeClaimStatus, out *v1.PersistentVolumeClaimStatus, s conversion.Scope) error { + out.Phase = v1.PersistentVolumeClaimPhase(in.Phase) + out.AccessModes = *(*[]v1.PersistentVolumeAccessMode)(unsafe.Pointer(&in.AccessModes)) + out.Capacity = *(*v1.ResourceList)(unsafe.Pointer(&in.Capacity)) + out.Conditions = *(*[]v1.PersistentVolumeClaimCondition)(unsafe.Pointer(&in.Conditions)) + out.AllocatedResources = *(*v1.ResourceList)(unsafe.Pointer(&in.AllocatedResources)) + out.ResizeStatus = (*v1.PersistentVolumeClaimResizeStatus)(unsafe.Pointer(in.ResizeStatus)) + return nil +} + +// Convert_core_PersistentVolumeClaimStatus_To_v1_PersistentVolumeClaimStatus is an autogenerated conversion function. +func Convert_core_PersistentVolumeClaimStatus_To_v1_PersistentVolumeClaimStatus(in *core.PersistentVolumeClaimStatus, out *v1.PersistentVolumeClaimStatus, s conversion.Scope) error { + return autoConvert_core_PersistentVolumeClaimStatus_To_v1_PersistentVolumeClaimStatus(in, out, s) +} + +func autoConvert_v1_PersistentVolumeClaimTemplate_To_core_PersistentVolumeClaimTemplate(in *v1.PersistentVolumeClaimTemplate, out *core.PersistentVolumeClaimTemplate, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_PersistentVolumeClaimSpec_To_core_PersistentVolumeClaimSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + return nil +} + +// Convert_v1_PersistentVolumeClaimTemplate_To_core_PersistentVolumeClaimTemplate is an autogenerated conversion function. +func Convert_v1_PersistentVolumeClaimTemplate_To_core_PersistentVolumeClaimTemplate(in *v1.PersistentVolumeClaimTemplate, out *core.PersistentVolumeClaimTemplate, s conversion.Scope) error { + return autoConvert_v1_PersistentVolumeClaimTemplate_To_core_PersistentVolumeClaimTemplate(in, out, s) +} + +func autoConvert_core_PersistentVolumeClaimTemplate_To_v1_PersistentVolumeClaimTemplate(in *core.PersistentVolumeClaimTemplate, out *v1.PersistentVolumeClaimTemplate, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_core_PersistentVolumeClaimSpec_To_v1_PersistentVolumeClaimSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + return nil +} + +// Convert_core_PersistentVolumeClaimTemplate_To_v1_PersistentVolumeClaimTemplate is an autogenerated conversion function. +func Convert_core_PersistentVolumeClaimTemplate_To_v1_PersistentVolumeClaimTemplate(in *core.PersistentVolumeClaimTemplate, out *v1.PersistentVolumeClaimTemplate, s conversion.Scope) error { + return autoConvert_core_PersistentVolumeClaimTemplate_To_v1_PersistentVolumeClaimTemplate(in, out, s) +} + +func autoConvert_v1_PersistentVolumeClaimVolumeSource_To_core_PersistentVolumeClaimVolumeSource(in *v1.PersistentVolumeClaimVolumeSource, out *core.PersistentVolumeClaimVolumeSource, s conversion.Scope) error { + out.ClaimName = in.ClaimName + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_v1_PersistentVolumeClaimVolumeSource_To_core_PersistentVolumeClaimVolumeSource is an autogenerated conversion function. +func Convert_v1_PersistentVolumeClaimVolumeSource_To_core_PersistentVolumeClaimVolumeSource(in *v1.PersistentVolumeClaimVolumeSource, out *core.PersistentVolumeClaimVolumeSource, s conversion.Scope) error { + return autoConvert_v1_PersistentVolumeClaimVolumeSource_To_core_PersistentVolumeClaimVolumeSource(in, out, s) +} + +func autoConvert_core_PersistentVolumeClaimVolumeSource_To_v1_PersistentVolumeClaimVolumeSource(in *core.PersistentVolumeClaimVolumeSource, out *v1.PersistentVolumeClaimVolumeSource, s conversion.Scope) error { + out.ClaimName = in.ClaimName + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_core_PersistentVolumeClaimVolumeSource_To_v1_PersistentVolumeClaimVolumeSource is an autogenerated conversion function. +func Convert_core_PersistentVolumeClaimVolumeSource_To_v1_PersistentVolumeClaimVolumeSource(in *core.PersistentVolumeClaimVolumeSource, out *v1.PersistentVolumeClaimVolumeSource, s conversion.Scope) error { + return autoConvert_core_PersistentVolumeClaimVolumeSource_To_v1_PersistentVolumeClaimVolumeSource(in, out, s) +} + +func autoConvert_v1_PersistentVolumeList_To_core_PersistentVolumeList(in *v1.PersistentVolumeList, out *core.PersistentVolumeList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]core.PersistentVolume, len(*in)) + for i := range *in { + if err := Convert_v1_PersistentVolume_To_core_PersistentVolume(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +// Convert_v1_PersistentVolumeList_To_core_PersistentVolumeList is an autogenerated conversion function. +func Convert_v1_PersistentVolumeList_To_core_PersistentVolumeList(in *v1.PersistentVolumeList, out *core.PersistentVolumeList, s conversion.Scope) error { + return autoConvert_v1_PersistentVolumeList_To_core_PersistentVolumeList(in, out, s) +} + +func autoConvert_core_PersistentVolumeList_To_v1_PersistentVolumeList(in *core.PersistentVolumeList, out *v1.PersistentVolumeList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]v1.PersistentVolume, len(*in)) + for i := range *in { + if err := Convert_core_PersistentVolume_To_v1_PersistentVolume(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +// Convert_core_PersistentVolumeList_To_v1_PersistentVolumeList is an autogenerated conversion function. +func Convert_core_PersistentVolumeList_To_v1_PersistentVolumeList(in *core.PersistentVolumeList, out *v1.PersistentVolumeList, s conversion.Scope) error { + return autoConvert_core_PersistentVolumeList_To_v1_PersistentVolumeList(in, out, s) +} + +func autoConvert_v1_PersistentVolumeSource_To_core_PersistentVolumeSource(in *v1.PersistentVolumeSource, out *core.PersistentVolumeSource, s conversion.Scope) error { + out.GCEPersistentDisk = (*core.GCEPersistentDiskVolumeSource)(unsafe.Pointer(in.GCEPersistentDisk)) + out.AWSElasticBlockStore = (*core.AWSElasticBlockStoreVolumeSource)(unsafe.Pointer(in.AWSElasticBlockStore)) + out.HostPath = (*core.HostPathVolumeSource)(unsafe.Pointer(in.HostPath)) + out.Glusterfs = (*core.GlusterfsPersistentVolumeSource)(unsafe.Pointer(in.Glusterfs)) + out.NFS = (*core.NFSVolumeSource)(unsafe.Pointer(in.NFS)) + out.RBD = (*core.RBDPersistentVolumeSource)(unsafe.Pointer(in.RBD)) + out.ISCSI = (*core.ISCSIPersistentVolumeSource)(unsafe.Pointer(in.ISCSI)) + out.Cinder = (*core.CinderPersistentVolumeSource)(unsafe.Pointer(in.Cinder)) + out.CephFS = (*core.CephFSPersistentVolumeSource)(unsafe.Pointer(in.CephFS)) + out.FC = (*core.FCVolumeSource)(unsafe.Pointer(in.FC)) + out.Flocker = (*core.FlockerVolumeSource)(unsafe.Pointer(in.Flocker)) + out.FlexVolume = (*core.FlexPersistentVolumeSource)(unsafe.Pointer(in.FlexVolume)) + out.AzureFile = (*core.AzureFilePersistentVolumeSource)(unsafe.Pointer(in.AzureFile)) + out.VsphereVolume = (*core.VsphereVirtualDiskVolumeSource)(unsafe.Pointer(in.VsphereVolume)) + out.Quobyte = (*core.QuobyteVolumeSource)(unsafe.Pointer(in.Quobyte)) + out.AzureDisk = (*core.AzureDiskVolumeSource)(unsafe.Pointer(in.AzureDisk)) + out.PhotonPersistentDisk = (*core.PhotonPersistentDiskVolumeSource)(unsafe.Pointer(in.PhotonPersistentDisk)) + out.PortworxVolume = (*core.PortworxVolumeSource)(unsafe.Pointer(in.PortworxVolume)) + out.ScaleIO = (*core.ScaleIOPersistentVolumeSource)(unsafe.Pointer(in.ScaleIO)) + out.Local = (*core.LocalVolumeSource)(unsafe.Pointer(in.Local)) + out.StorageOS = (*core.StorageOSPersistentVolumeSource)(unsafe.Pointer(in.StorageOS)) + out.CSI = (*core.CSIPersistentVolumeSource)(unsafe.Pointer(in.CSI)) + return nil +} + +// Convert_v1_PersistentVolumeSource_To_core_PersistentVolumeSource is an autogenerated conversion function. +func Convert_v1_PersistentVolumeSource_To_core_PersistentVolumeSource(in *v1.PersistentVolumeSource, out *core.PersistentVolumeSource, s conversion.Scope) error { + return autoConvert_v1_PersistentVolumeSource_To_core_PersistentVolumeSource(in, out, s) +} + +func autoConvert_core_PersistentVolumeSource_To_v1_PersistentVolumeSource(in *core.PersistentVolumeSource, out *v1.PersistentVolumeSource, s conversion.Scope) error { + out.GCEPersistentDisk = (*v1.GCEPersistentDiskVolumeSource)(unsafe.Pointer(in.GCEPersistentDisk)) + out.AWSElasticBlockStore = (*v1.AWSElasticBlockStoreVolumeSource)(unsafe.Pointer(in.AWSElasticBlockStore)) + out.HostPath = (*v1.HostPathVolumeSource)(unsafe.Pointer(in.HostPath)) + out.Glusterfs = (*v1.GlusterfsPersistentVolumeSource)(unsafe.Pointer(in.Glusterfs)) + out.NFS = (*v1.NFSVolumeSource)(unsafe.Pointer(in.NFS)) + out.RBD = (*v1.RBDPersistentVolumeSource)(unsafe.Pointer(in.RBD)) + out.Quobyte = (*v1.QuobyteVolumeSource)(unsafe.Pointer(in.Quobyte)) + out.ISCSI = (*v1.ISCSIPersistentVolumeSource)(unsafe.Pointer(in.ISCSI)) + out.FlexVolume = (*v1.FlexPersistentVolumeSource)(unsafe.Pointer(in.FlexVolume)) + out.Cinder = (*v1.CinderPersistentVolumeSource)(unsafe.Pointer(in.Cinder)) + out.CephFS = (*v1.CephFSPersistentVolumeSource)(unsafe.Pointer(in.CephFS)) + out.FC = (*v1.FCVolumeSource)(unsafe.Pointer(in.FC)) + out.Flocker = (*v1.FlockerVolumeSource)(unsafe.Pointer(in.Flocker)) + out.AzureFile = (*v1.AzureFilePersistentVolumeSource)(unsafe.Pointer(in.AzureFile)) + out.VsphereVolume = (*v1.VsphereVirtualDiskVolumeSource)(unsafe.Pointer(in.VsphereVolume)) + out.AzureDisk = (*v1.AzureDiskVolumeSource)(unsafe.Pointer(in.AzureDisk)) + out.PhotonPersistentDisk = (*v1.PhotonPersistentDiskVolumeSource)(unsafe.Pointer(in.PhotonPersistentDisk)) + out.PortworxVolume = (*v1.PortworxVolumeSource)(unsafe.Pointer(in.PortworxVolume)) + out.ScaleIO = (*v1.ScaleIOPersistentVolumeSource)(unsafe.Pointer(in.ScaleIO)) + out.Local = (*v1.LocalVolumeSource)(unsafe.Pointer(in.Local)) + out.StorageOS = (*v1.StorageOSPersistentVolumeSource)(unsafe.Pointer(in.StorageOS)) + out.CSI = (*v1.CSIPersistentVolumeSource)(unsafe.Pointer(in.CSI)) + return nil +} + +// Convert_core_PersistentVolumeSource_To_v1_PersistentVolumeSource is an autogenerated conversion function. +func Convert_core_PersistentVolumeSource_To_v1_PersistentVolumeSource(in *core.PersistentVolumeSource, out *v1.PersistentVolumeSource, s conversion.Scope) error { + return autoConvert_core_PersistentVolumeSource_To_v1_PersistentVolumeSource(in, out, s) +} + +func autoConvert_v1_PersistentVolumeSpec_To_core_PersistentVolumeSpec(in *v1.PersistentVolumeSpec, out *core.PersistentVolumeSpec, s conversion.Scope) error { + out.Capacity = *(*core.ResourceList)(unsafe.Pointer(&in.Capacity)) + if err := Convert_v1_PersistentVolumeSource_To_core_PersistentVolumeSource(&in.PersistentVolumeSource, &out.PersistentVolumeSource, s); err != nil { + return err + } + out.AccessModes = *(*[]core.PersistentVolumeAccessMode)(unsafe.Pointer(&in.AccessModes)) + out.ClaimRef = (*core.ObjectReference)(unsafe.Pointer(in.ClaimRef)) + out.PersistentVolumeReclaimPolicy = core.PersistentVolumeReclaimPolicy(in.PersistentVolumeReclaimPolicy) + out.StorageClassName = in.StorageClassName + out.MountOptions = *(*[]string)(unsafe.Pointer(&in.MountOptions)) + out.VolumeMode = (*core.PersistentVolumeMode)(unsafe.Pointer(in.VolumeMode)) + out.NodeAffinity = (*core.VolumeNodeAffinity)(unsafe.Pointer(in.NodeAffinity)) + return nil +} + +func autoConvert_core_PersistentVolumeSpec_To_v1_PersistentVolumeSpec(in *core.PersistentVolumeSpec, out *v1.PersistentVolumeSpec, s conversion.Scope) error { + out.Capacity = *(*v1.ResourceList)(unsafe.Pointer(&in.Capacity)) + if err := Convert_core_PersistentVolumeSource_To_v1_PersistentVolumeSource(&in.PersistentVolumeSource, &out.PersistentVolumeSource, s); err != nil { + return err + } + out.AccessModes = *(*[]v1.PersistentVolumeAccessMode)(unsafe.Pointer(&in.AccessModes)) + out.ClaimRef = (*v1.ObjectReference)(unsafe.Pointer(in.ClaimRef)) + out.PersistentVolumeReclaimPolicy = v1.PersistentVolumeReclaimPolicy(in.PersistentVolumeReclaimPolicy) + out.StorageClassName = in.StorageClassName + out.MountOptions = *(*[]string)(unsafe.Pointer(&in.MountOptions)) + out.VolumeMode = (*v1.PersistentVolumeMode)(unsafe.Pointer(in.VolumeMode)) + out.NodeAffinity = (*v1.VolumeNodeAffinity)(unsafe.Pointer(in.NodeAffinity)) + return nil +} + +func autoConvert_v1_PersistentVolumeStatus_To_core_PersistentVolumeStatus(in *v1.PersistentVolumeStatus, out *core.PersistentVolumeStatus, s conversion.Scope) error { + out.Phase = core.PersistentVolumePhase(in.Phase) + out.Message = in.Message + out.Reason = in.Reason + return nil +} + +// Convert_v1_PersistentVolumeStatus_To_core_PersistentVolumeStatus is an autogenerated conversion function. +func Convert_v1_PersistentVolumeStatus_To_core_PersistentVolumeStatus(in *v1.PersistentVolumeStatus, out *core.PersistentVolumeStatus, s conversion.Scope) error { + return autoConvert_v1_PersistentVolumeStatus_To_core_PersistentVolumeStatus(in, out, s) +} + +func autoConvert_core_PersistentVolumeStatus_To_v1_PersistentVolumeStatus(in *core.PersistentVolumeStatus, out *v1.PersistentVolumeStatus, s conversion.Scope) error { + out.Phase = v1.PersistentVolumePhase(in.Phase) + out.Message = in.Message + out.Reason = in.Reason + return nil +} + +// Convert_core_PersistentVolumeStatus_To_v1_PersistentVolumeStatus is an autogenerated conversion function. +func Convert_core_PersistentVolumeStatus_To_v1_PersistentVolumeStatus(in *core.PersistentVolumeStatus, out *v1.PersistentVolumeStatus, s conversion.Scope) error { + return autoConvert_core_PersistentVolumeStatus_To_v1_PersistentVolumeStatus(in, out, s) +} + +func autoConvert_v1_PhotonPersistentDiskVolumeSource_To_core_PhotonPersistentDiskVolumeSource(in *v1.PhotonPersistentDiskVolumeSource, out *core.PhotonPersistentDiskVolumeSource, s conversion.Scope) error { + out.PdID = in.PdID + out.FSType = in.FSType + return nil +} + +// Convert_v1_PhotonPersistentDiskVolumeSource_To_core_PhotonPersistentDiskVolumeSource is an autogenerated conversion function. +func Convert_v1_PhotonPersistentDiskVolumeSource_To_core_PhotonPersistentDiskVolumeSource(in *v1.PhotonPersistentDiskVolumeSource, out *core.PhotonPersistentDiskVolumeSource, s conversion.Scope) error { + return autoConvert_v1_PhotonPersistentDiskVolumeSource_To_core_PhotonPersistentDiskVolumeSource(in, out, s) +} + +func autoConvert_core_PhotonPersistentDiskVolumeSource_To_v1_PhotonPersistentDiskVolumeSource(in *core.PhotonPersistentDiskVolumeSource, out *v1.PhotonPersistentDiskVolumeSource, s conversion.Scope) error { + out.PdID = in.PdID + out.FSType = in.FSType + return nil +} + +// Convert_core_PhotonPersistentDiskVolumeSource_To_v1_PhotonPersistentDiskVolumeSource is an autogenerated conversion function. +func Convert_core_PhotonPersistentDiskVolumeSource_To_v1_PhotonPersistentDiskVolumeSource(in *core.PhotonPersistentDiskVolumeSource, out *v1.PhotonPersistentDiskVolumeSource, s conversion.Scope) error { + return autoConvert_core_PhotonPersistentDiskVolumeSource_To_v1_PhotonPersistentDiskVolumeSource(in, out, s) +} + +func autoConvert_v1_Pod_To_core_Pod(in *v1.Pod, out *core.Pod, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_PodSpec_To_core_PodSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_v1_PodStatus_To_core_PodStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +func autoConvert_core_Pod_To_v1_Pod(in *core.Pod, out *v1.Pod, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_core_PodSpec_To_v1_PodSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_core_PodStatus_To_v1_PodStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +func autoConvert_v1_PodAffinity_To_core_PodAffinity(in *v1.PodAffinity, out *core.PodAffinity, s conversion.Scope) error { + out.RequiredDuringSchedulingIgnoredDuringExecution = *(*[]core.PodAffinityTerm)(unsafe.Pointer(&in.RequiredDuringSchedulingIgnoredDuringExecution)) + out.PreferredDuringSchedulingIgnoredDuringExecution = *(*[]core.WeightedPodAffinityTerm)(unsafe.Pointer(&in.PreferredDuringSchedulingIgnoredDuringExecution)) + return nil +} + +// Convert_v1_PodAffinity_To_core_PodAffinity is an autogenerated conversion function. +func Convert_v1_PodAffinity_To_core_PodAffinity(in *v1.PodAffinity, out *core.PodAffinity, s conversion.Scope) error { + return autoConvert_v1_PodAffinity_To_core_PodAffinity(in, out, s) +} + +func autoConvert_core_PodAffinity_To_v1_PodAffinity(in *core.PodAffinity, out *v1.PodAffinity, s conversion.Scope) error { + out.RequiredDuringSchedulingIgnoredDuringExecution = *(*[]v1.PodAffinityTerm)(unsafe.Pointer(&in.RequiredDuringSchedulingIgnoredDuringExecution)) + out.PreferredDuringSchedulingIgnoredDuringExecution = *(*[]v1.WeightedPodAffinityTerm)(unsafe.Pointer(&in.PreferredDuringSchedulingIgnoredDuringExecution)) + return nil +} + +// Convert_core_PodAffinity_To_v1_PodAffinity is an autogenerated conversion function. +func Convert_core_PodAffinity_To_v1_PodAffinity(in *core.PodAffinity, out *v1.PodAffinity, s conversion.Scope) error { + return autoConvert_core_PodAffinity_To_v1_PodAffinity(in, out, s) +} + +func autoConvert_v1_PodAffinityTerm_To_core_PodAffinityTerm(in *v1.PodAffinityTerm, out *core.PodAffinityTerm, s conversion.Scope) error { + out.LabelSelector = (*metav1.LabelSelector)(unsafe.Pointer(in.LabelSelector)) + out.Namespaces = *(*[]string)(unsafe.Pointer(&in.Namespaces)) + out.TopologyKey = in.TopologyKey + out.NamespaceSelector = (*metav1.LabelSelector)(unsafe.Pointer(in.NamespaceSelector)) + return nil +} + +// Convert_v1_PodAffinityTerm_To_core_PodAffinityTerm is an autogenerated conversion function. +func Convert_v1_PodAffinityTerm_To_core_PodAffinityTerm(in *v1.PodAffinityTerm, out *core.PodAffinityTerm, s conversion.Scope) error { + return autoConvert_v1_PodAffinityTerm_To_core_PodAffinityTerm(in, out, s) +} + +func autoConvert_core_PodAffinityTerm_To_v1_PodAffinityTerm(in *core.PodAffinityTerm, out *v1.PodAffinityTerm, s conversion.Scope) error { + out.LabelSelector = (*metav1.LabelSelector)(unsafe.Pointer(in.LabelSelector)) + out.Namespaces = *(*[]string)(unsafe.Pointer(&in.Namespaces)) + out.TopologyKey = in.TopologyKey + out.NamespaceSelector = (*metav1.LabelSelector)(unsafe.Pointer(in.NamespaceSelector)) + return nil +} + +// Convert_core_PodAffinityTerm_To_v1_PodAffinityTerm is an autogenerated conversion function. +func Convert_core_PodAffinityTerm_To_v1_PodAffinityTerm(in *core.PodAffinityTerm, out *v1.PodAffinityTerm, s conversion.Scope) error { + return autoConvert_core_PodAffinityTerm_To_v1_PodAffinityTerm(in, out, s) +} + +func autoConvert_v1_PodAntiAffinity_To_core_PodAntiAffinity(in *v1.PodAntiAffinity, out *core.PodAntiAffinity, s conversion.Scope) error { + out.RequiredDuringSchedulingIgnoredDuringExecution = *(*[]core.PodAffinityTerm)(unsafe.Pointer(&in.RequiredDuringSchedulingIgnoredDuringExecution)) + out.PreferredDuringSchedulingIgnoredDuringExecution = *(*[]core.WeightedPodAffinityTerm)(unsafe.Pointer(&in.PreferredDuringSchedulingIgnoredDuringExecution)) + return nil +} + +// Convert_v1_PodAntiAffinity_To_core_PodAntiAffinity is an autogenerated conversion function. +func Convert_v1_PodAntiAffinity_To_core_PodAntiAffinity(in *v1.PodAntiAffinity, out *core.PodAntiAffinity, s conversion.Scope) error { + return autoConvert_v1_PodAntiAffinity_To_core_PodAntiAffinity(in, out, s) +} + +func autoConvert_core_PodAntiAffinity_To_v1_PodAntiAffinity(in *core.PodAntiAffinity, out *v1.PodAntiAffinity, s conversion.Scope) error { + out.RequiredDuringSchedulingIgnoredDuringExecution = *(*[]v1.PodAffinityTerm)(unsafe.Pointer(&in.RequiredDuringSchedulingIgnoredDuringExecution)) + out.PreferredDuringSchedulingIgnoredDuringExecution = *(*[]v1.WeightedPodAffinityTerm)(unsafe.Pointer(&in.PreferredDuringSchedulingIgnoredDuringExecution)) + return nil +} + +// Convert_core_PodAntiAffinity_To_v1_PodAntiAffinity is an autogenerated conversion function. +func Convert_core_PodAntiAffinity_To_v1_PodAntiAffinity(in *core.PodAntiAffinity, out *v1.PodAntiAffinity, s conversion.Scope) error { + return autoConvert_core_PodAntiAffinity_To_v1_PodAntiAffinity(in, out, s) +} + +func autoConvert_v1_PodAttachOptions_To_core_PodAttachOptions(in *v1.PodAttachOptions, out *core.PodAttachOptions, s conversion.Scope) error { + out.Stdin = in.Stdin + out.Stdout = in.Stdout + out.Stderr = in.Stderr + out.TTY = in.TTY + out.Container = in.Container + return nil +} + +// Convert_v1_PodAttachOptions_To_core_PodAttachOptions is an autogenerated conversion function. +func Convert_v1_PodAttachOptions_To_core_PodAttachOptions(in *v1.PodAttachOptions, out *core.PodAttachOptions, s conversion.Scope) error { + return autoConvert_v1_PodAttachOptions_To_core_PodAttachOptions(in, out, s) +} + +func autoConvert_core_PodAttachOptions_To_v1_PodAttachOptions(in *core.PodAttachOptions, out *v1.PodAttachOptions, s conversion.Scope) error { + out.Stdin = in.Stdin + out.Stdout = in.Stdout + out.Stderr = in.Stderr + out.TTY = in.TTY + out.Container = in.Container + return nil +} + +// Convert_core_PodAttachOptions_To_v1_PodAttachOptions is an autogenerated conversion function. +func Convert_core_PodAttachOptions_To_v1_PodAttachOptions(in *core.PodAttachOptions, out *v1.PodAttachOptions, s conversion.Scope) error { + return autoConvert_core_PodAttachOptions_To_v1_PodAttachOptions(in, out, s) +} + +func autoConvert_url_Values_To_v1_PodAttachOptions(in *url.Values, out *v1.PodAttachOptions, s conversion.Scope) error { + // WARNING: Field TypeMeta does not have json tag, skipping. + + if values, ok := map[string][]string(*in)["stdin"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_bool(&values, &out.Stdin, s); err != nil { + return err + } + } else { + out.Stdin = false + } + if values, ok := map[string][]string(*in)["stdout"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_bool(&values, &out.Stdout, s); err != nil { + return err + } + } else { + out.Stdout = false + } + if values, ok := map[string][]string(*in)["stderr"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_bool(&values, &out.Stderr, s); err != nil { + return err + } + } else { + out.Stderr = false + } + if values, ok := map[string][]string(*in)["tty"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_bool(&values, &out.TTY, s); err != nil { + return err + } + } else { + out.TTY = false + } + if values, ok := map[string][]string(*in)["container"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_string(&values, &out.Container, s); err != nil { + return err + } + } else { + out.Container = "" + } + return nil +} + +// Convert_url_Values_To_v1_PodAttachOptions is an autogenerated conversion function. +func Convert_url_Values_To_v1_PodAttachOptions(in *url.Values, out *v1.PodAttachOptions, s conversion.Scope) error { + return autoConvert_url_Values_To_v1_PodAttachOptions(in, out, s) +} + +func autoConvert_v1_PodCondition_To_core_PodCondition(in *v1.PodCondition, out *core.PodCondition, s conversion.Scope) error { + out.Type = core.PodConditionType(in.Type) + out.Status = core.ConditionStatus(in.Status) + out.LastProbeTime = in.LastProbeTime + out.LastTransitionTime = in.LastTransitionTime + out.Reason = in.Reason + out.Message = in.Message + return nil +} + +// Convert_v1_PodCondition_To_core_PodCondition is an autogenerated conversion function. +func Convert_v1_PodCondition_To_core_PodCondition(in *v1.PodCondition, out *core.PodCondition, s conversion.Scope) error { + return autoConvert_v1_PodCondition_To_core_PodCondition(in, out, s) +} + +func autoConvert_core_PodCondition_To_v1_PodCondition(in *core.PodCondition, out *v1.PodCondition, s conversion.Scope) error { + out.Type = v1.PodConditionType(in.Type) + out.Status = v1.ConditionStatus(in.Status) + out.LastProbeTime = in.LastProbeTime + out.LastTransitionTime = in.LastTransitionTime + out.Reason = in.Reason + out.Message = in.Message + return nil +} + +// Convert_core_PodCondition_To_v1_PodCondition is an autogenerated conversion function. +func Convert_core_PodCondition_To_v1_PodCondition(in *core.PodCondition, out *v1.PodCondition, s conversion.Scope) error { + return autoConvert_core_PodCondition_To_v1_PodCondition(in, out, s) +} + +func autoConvert_v1_PodDNSConfig_To_core_PodDNSConfig(in *v1.PodDNSConfig, out *core.PodDNSConfig, s conversion.Scope) error { + out.Nameservers = *(*[]string)(unsafe.Pointer(&in.Nameservers)) + out.Searches = *(*[]string)(unsafe.Pointer(&in.Searches)) + out.Options = *(*[]core.PodDNSConfigOption)(unsafe.Pointer(&in.Options)) + return nil +} + +// Convert_v1_PodDNSConfig_To_core_PodDNSConfig is an autogenerated conversion function. +func Convert_v1_PodDNSConfig_To_core_PodDNSConfig(in *v1.PodDNSConfig, out *core.PodDNSConfig, s conversion.Scope) error { + return autoConvert_v1_PodDNSConfig_To_core_PodDNSConfig(in, out, s) +} + +func autoConvert_core_PodDNSConfig_To_v1_PodDNSConfig(in *core.PodDNSConfig, out *v1.PodDNSConfig, s conversion.Scope) error { + out.Nameservers = *(*[]string)(unsafe.Pointer(&in.Nameservers)) + out.Searches = *(*[]string)(unsafe.Pointer(&in.Searches)) + out.Options = *(*[]v1.PodDNSConfigOption)(unsafe.Pointer(&in.Options)) + return nil +} + +// Convert_core_PodDNSConfig_To_v1_PodDNSConfig is an autogenerated conversion function. +func Convert_core_PodDNSConfig_To_v1_PodDNSConfig(in *core.PodDNSConfig, out *v1.PodDNSConfig, s conversion.Scope) error { + return autoConvert_core_PodDNSConfig_To_v1_PodDNSConfig(in, out, s) +} + +func autoConvert_v1_PodDNSConfigOption_To_core_PodDNSConfigOption(in *v1.PodDNSConfigOption, out *core.PodDNSConfigOption, s conversion.Scope) error { + out.Name = in.Name + out.Value = (*string)(unsafe.Pointer(in.Value)) + return nil +} + +// Convert_v1_PodDNSConfigOption_To_core_PodDNSConfigOption is an autogenerated conversion function. +func Convert_v1_PodDNSConfigOption_To_core_PodDNSConfigOption(in *v1.PodDNSConfigOption, out *core.PodDNSConfigOption, s conversion.Scope) error { + return autoConvert_v1_PodDNSConfigOption_To_core_PodDNSConfigOption(in, out, s) +} + +func autoConvert_core_PodDNSConfigOption_To_v1_PodDNSConfigOption(in *core.PodDNSConfigOption, out *v1.PodDNSConfigOption, s conversion.Scope) error { + out.Name = in.Name + out.Value = (*string)(unsafe.Pointer(in.Value)) + return nil +} + +// Convert_core_PodDNSConfigOption_To_v1_PodDNSConfigOption is an autogenerated conversion function. +func Convert_core_PodDNSConfigOption_To_v1_PodDNSConfigOption(in *core.PodDNSConfigOption, out *v1.PodDNSConfigOption, s conversion.Scope) error { + return autoConvert_core_PodDNSConfigOption_To_v1_PodDNSConfigOption(in, out, s) +} + +func autoConvert_v1_PodExecOptions_To_core_PodExecOptions(in *v1.PodExecOptions, out *core.PodExecOptions, s conversion.Scope) error { + out.Stdin = in.Stdin + out.Stdout = in.Stdout + out.Stderr = in.Stderr + out.TTY = in.TTY + out.Container = in.Container + out.Command = *(*[]string)(unsafe.Pointer(&in.Command)) + return nil +} + +// Convert_v1_PodExecOptions_To_core_PodExecOptions is an autogenerated conversion function. +func Convert_v1_PodExecOptions_To_core_PodExecOptions(in *v1.PodExecOptions, out *core.PodExecOptions, s conversion.Scope) error { + return autoConvert_v1_PodExecOptions_To_core_PodExecOptions(in, out, s) +} + +func autoConvert_core_PodExecOptions_To_v1_PodExecOptions(in *core.PodExecOptions, out *v1.PodExecOptions, s conversion.Scope) error { + out.Stdin = in.Stdin + out.Stdout = in.Stdout + out.Stderr = in.Stderr + out.TTY = in.TTY + out.Container = in.Container + out.Command = *(*[]string)(unsafe.Pointer(&in.Command)) + return nil +} + +// Convert_core_PodExecOptions_To_v1_PodExecOptions is an autogenerated conversion function. +func Convert_core_PodExecOptions_To_v1_PodExecOptions(in *core.PodExecOptions, out *v1.PodExecOptions, s conversion.Scope) error { + return autoConvert_core_PodExecOptions_To_v1_PodExecOptions(in, out, s) +} + +func autoConvert_url_Values_To_v1_PodExecOptions(in *url.Values, out *v1.PodExecOptions, s conversion.Scope) error { + // WARNING: Field TypeMeta does not have json tag, skipping. + + if values, ok := map[string][]string(*in)["stdin"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_bool(&values, &out.Stdin, s); err != nil { + return err + } + } else { + out.Stdin = false + } + if values, ok := map[string][]string(*in)["stdout"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_bool(&values, &out.Stdout, s); err != nil { + return err + } + } else { + out.Stdout = false + } + if values, ok := map[string][]string(*in)["stderr"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_bool(&values, &out.Stderr, s); err != nil { + return err + } + } else { + out.Stderr = false + } + if values, ok := map[string][]string(*in)["tty"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_bool(&values, &out.TTY, s); err != nil { + return err + } + } else { + out.TTY = false + } + if values, ok := map[string][]string(*in)["container"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_string(&values, &out.Container, s); err != nil { + return err + } + } else { + out.Container = "" + } + if values, ok := map[string][]string(*in)["command"]; ok && len(values) > 0 { + out.Command = *(*[]string)(unsafe.Pointer(&values)) + } else { + out.Command = nil + } + return nil +} + +// Convert_url_Values_To_v1_PodExecOptions is an autogenerated conversion function. +func Convert_url_Values_To_v1_PodExecOptions(in *url.Values, out *v1.PodExecOptions, s conversion.Scope) error { + return autoConvert_url_Values_To_v1_PodExecOptions(in, out, s) +} + +func autoConvert_v1_PodIP_To_core_PodIP(in *v1.PodIP, out *core.PodIP, s conversion.Scope) error { + out.IP = in.IP + return nil +} + +// Convert_v1_PodIP_To_core_PodIP is an autogenerated conversion function. +func Convert_v1_PodIP_To_core_PodIP(in *v1.PodIP, out *core.PodIP, s conversion.Scope) error { + return autoConvert_v1_PodIP_To_core_PodIP(in, out, s) +} + +func autoConvert_core_PodIP_To_v1_PodIP(in *core.PodIP, out *v1.PodIP, s conversion.Scope) error { + out.IP = in.IP + return nil +} + +// Convert_core_PodIP_To_v1_PodIP is an autogenerated conversion function. +func Convert_core_PodIP_To_v1_PodIP(in *core.PodIP, out *v1.PodIP, s conversion.Scope) error { + return autoConvert_core_PodIP_To_v1_PodIP(in, out, s) +} + +func autoConvert_v1_PodList_To_core_PodList(in *v1.PodList, out *core.PodList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]core.Pod, len(*in)) + for i := range *in { + if err := Convert_v1_Pod_To_core_Pod(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +// Convert_v1_PodList_To_core_PodList is an autogenerated conversion function. +func Convert_v1_PodList_To_core_PodList(in *v1.PodList, out *core.PodList, s conversion.Scope) error { + return autoConvert_v1_PodList_To_core_PodList(in, out, s) +} + +func autoConvert_core_PodList_To_v1_PodList(in *core.PodList, out *v1.PodList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]v1.Pod, len(*in)) + for i := range *in { + if err := Convert_core_Pod_To_v1_Pod(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +// Convert_core_PodList_To_v1_PodList is an autogenerated conversion function. +func Convert_core_PodList_To_v1_PodList(in *core.PodList, out *v1.PodList, s conversion.Scope) error { + return autoConvert_core_PodList_To_v1_PodList(in, out, s) +} + +func autoConvert_v1_PodLogOptions_To_core_PodLogOptions(in *v1.PodLogOptions, out *core.PodLogOptions, s conversion.Scope) error { + out.Container = in.Container + out.Follow = in.Follow + out.Previous = in.Previous + out.SinceSeconds = (*int64)(unsafe.Pointer(in.SinceSeconds)) + out.SinceTime = (*metav1.Time)(unsafe.Pointer(in.SinceTime)) + out.Timestamps = in.Timestamps + out.TailLines = (*int64)(unsafe.Pointer(in.TailLines)) + out.LimitBytes = (*int64)(unsafe.Pointer(in.LimitBytes)) + out.InsecureSkipTLSVerifyBackend = in.InsecureSkipTLSVerifyBackend + return nil +} + +// Convert_v1_PodLogOptions_To_core_PodLogOptions is an autogenerated conversion function. +func Convert_v1_PodLogOptions_To_core_PodLogOptions(in *v1.PodLogOptions, out *core.PodLogOptions, s conversion.Scope) error { + return autoConvert_v1_PodLogOptions_To_core_PodLogOptions(in, out, s) +} + +func autoConvert_core_PodLogOptions_To_v1_PodLogOptions(in *core.PodLogOptions, out *v1.PodLogOptions, s conversion.Scope) error { + out.Container = in.Container + out.Follow = in.Follow + out.Previous = in.Previous + out.SinceSeconds = (*int64)(unsafe.Pointer(in.SinceSeconds)) + out.SinceTime = (*metav1.Time)(unsafe.Pointer(in.SinceTime)) + out.Timestamps = in.Timestamps + out.TailLines = (*int64)(unsafe.Pointer(in.TailLines)) + out.LimitBytes = (*int64)(unsafe.Pointer(in.LimitBytes)) + out.InsecureSkipTLSVerifyBackend = in.InsecureSkipTLSVerifyBackend + return nil +} + +// Convert_core_PodLogOptions_To_v1_PodLogOptions is an autogenerated conversion function. +func Convert_core_PodLogOptions_To_v1_PodLogOptions(in *core.PodLogOptions, out *v1.PodLogOptions, s conversion.Scope) error { + return autoConvert_core_PodLogOptions_To_v1_PodLogOptions(in, out, s) +} + +func autoConvert_url_Values_To_v1_PodLogOptions(in *url.Values, out *v1.PodLogOptions, s conversion.Scope) error { + // WARNING: Field TypeMeta does not have json tag, skipping. + + if values, ok := map[string][]string(*in)["container"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_string(&values, &out.Container, s); err != nil { + return err + } + } else { + out.Container = "" + } + if values, ok := map[string][]string(*in)["follow"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_bool(&values, &out.Follow, s); err != nil { + return err + } + } else { + out.Follow = false + } + if values, ok := map[string][]string(*in)["previous"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_bool(&values, &out.Previous, s); err != nil { + return err + } + } else { + out.Previous = false + } + if values, ok := map[string][]string(*in)["sinceSeconds"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_Pointer_int64(&values, &out.SinceSeconds, s); err != nil { + return err + } + } else { + out.SinceSeconds = nil + } + if values, ok := map[string][]string(*in)["sinceTime"]; ok && len(values) > 0 { + if err := metav1.Convert_Slice_string_To_Pointer_v1_Time(&values, &out.SinceTime, s); err != nil { + return err + } + } else { + out.SinceTime = nil + } + if values, ok := map[string][]string(*in)["timestamps"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_bool(&values, &out.Timestamps, s); err != nil { + return err + } + } else { + out.Timestamps = false + } + if values, ok := map[string][]string(*in)["tailLines"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_Pointer_int64(&values, &out.TailLines, s); err != nil { + return err + } + } else { + out.TailLines = nil + } + if values, ok := map[string][]string(*in)["limitBytes"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_Pointer_int64(&values, &out.LimitBytes, s); err != nil { + return err + } + } else { + out.LimitBytes = nil + } + if values, ok := map[string][]string(*in)["insecureSkipTLSVerifyBackend"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_bool(&values, &out.InsecureSkipTLSVerifyBackend, s); err != nil { + return err + } + } else { + out.InsecureSkipTLSVerifyBackend = false + } + return nil +} + +// Convert_url_Values_To_v1_PodLogOptions is an autogenerated conversion function. +func Convert_url_Values_To_v1_PodLogOptions(in *url.Values, out *v1.PodLogOptions, s conversion.Scope) error { + return autoConvert_url_Values_To_v1_PodLogOptions(in, out, s) +} + +func autoConvert_v1_PodOS_To_core_PodOS(in *v1.PodOS, out *core.PodOS, s conversion.Scope) error { + out.Name = core.OSName(in.Name) + return nil +} + +// Convert_v1_PodOS_To_core_PodOS is an autogenerated conversion function. +func Convert_v1_PodOS_To_core_PodOS(in *v1.PodOS, out *core.PodOS, s conversion.Scope) error { + return autoConvert_v1_PodOS_To_core_PodOS(in, out, s) +} + +func autoConvert_core_PodOS_To_v1_PodOS(in *core.PodOS, out *v1.PodOS, s conversion.Scope) error { + out.Name = v1.OSName(in.Name) + return nil +} + +// Convert_core_PodOS_To_v1_PodOS is an autogenerated conversion function. +func Convert_core_PodOS_To_v1_PodOS(in *core.PodOS, out *v1.PodOS, s conversion.Scope) error { + return autoConvert_core_PodOS_To_v1_PodOS(in, out, s) +} + +func autoConvert_v1_PodPortForwardOptions_To_core_PodPortForwardOptions(in *v1.PodPortForwardOptions, out *core.PodPortForwardOptions, s conversion.Scope) error { + out.Ports = *(*[]int32)(unsafe.Pointer(&in.Ports)) + return nil +} + +// Convert_v1_PodPortForwardOptions_To_core_PodPortForwardOptions is an autogenerated conversion function. +func Convert_v1_PodPortForwardOptions_To_core_PodPortForwardOptions(in *v1.PodPortForwardOptions, out *core.PodPortForwardOptions, s conversion.Scope) error { + return autoConvert_v1_PodPortForwardOptions_To_core_PodPortForwardOptions(in, out, s) +} + +func autoConvert_core_PodPortForwardOptions_To_v1_PodPortForwardOptions(in *core.PodPortForwardOptions, out *v1.PodPortForwardOptions, s conversion.Scope) error { + out.Ports = *(*[]int32)(unsafe.Pointer(&in.Ports)) + return nil +} + +// Convert_core_PodPortForwardOptions_To_v1_PodPortForwardOptions is an autogenerated conversion function. +func Convert_core_PodPortForwardOptions_To_v1_PodPortForwardOptions(in *core.PodPortForwardOptions, out *v1.PodPortForwardOptions, s conversion.Scope) error { + return autoConvert_core_PodPortForwardOptions_To_v1_PodPortForwardOptions(in, out, s) +} + +func autoConvert_url_Values_To_v1_PodPortForwardOptions(in *url.Values, out *v1.PodPortForwardOptions, s conversion.Scope) error { + // WARNING: Field TypeMeta does not have json tag, skipping. + + if values, ok := map[string][]string(*in)["ports"]; ok && len(values) > 0 { + if err := metav1.Convert_Slice_string_To_Slice_int32(&values, &out.Ports, s); err != nil { + return err + } + } else { + out.Ports = nil + } + return nil +} + +// Convert_url_Values_To_v1_PodPortForwardOptions is an autogenerated conversion function. +func Convert_url_Values_To_v1_PodPortForwardOptions(in *url.Values, out *v1.PodPortForwardOptions, s conversion.Scope) error { + return autoConvert_url_Values_To_v1_PodPortForwardOptions(in, out, s) +} + +func autoConvert_v1_PodProxyOptions_To_core_PodProxyOptions(in *v1.PodProxyOptions, out *core.PodProxyOptions, s conversion.Scope) error { + out.Path = in.Path + return nil +} + +// Convert_v1_PodProxyOptions_To_core_PodProxyOptions is an autogenerated conversion function. +func Convert_v1_PodProxyOptions_To_core_PodProxyOptions(in *v1.PodProxyOptions, out *core.PodProxyOptions, s conversion.Scope) error { + return autoConvert_v1_PodProxyOptions_To_core_PodProxyOptions(in, out, s) +} + +func autoConvert_core_PodProxyOptions_To_v1_PodProxyOptions(in *core.PodProxyOptions, out *v1.PodProxyOptions, s conversion.Scope) error { + out.Path = in.Path + return nil +} + +// Convert_core_PodProxyOptions_To_v1_PodProxyOptions is an autogenerated conversion function. +func Convert_core_PodProxyOptions_To_v1_PodProxyOptions(in *core.PodProxyOptions, out *v1.PodProxyOptions, s conversion.Scope) error { + return autoConvert_core_PodProxyOptions_To_v1_PodProxyOptions(in, out, s) +} + +func autoConvert_url_Values_To_v1_PodProxyOptions(in *url.Values, out *v1.PodProxyOptions, s conversion.Scope) error { + // WARNING: Field TypeMeta does not have json tag, skipping. + + if values, ok := map[string][]string(*in)["path"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_string(&values, &out.Path, s); err != nil { + return err + } + } else { + out.Path = "" + } + return nil +} + +// Convert_url_Values_To_v1_PodProxyOptions is an autogenerated conversion function. +func Convert_url_Values_To_v1_PodProxyOptions(in *url.Values, out *v1.PodProxyOptions, s conversion.Scope) error { + return autoConvert_url_Values_To_v1_PodProxyOptions(in, out, s) +} + +func autoConvert_v1_PodReadinessGate_To_core_PodReadinessGate(in *v1.PodReadinessGate, out *core.PodReadinessGate, s conversion.Scope) error { + out.ConditionType = core.PodConditionType(in.ConditionType) + return nil +} + +// Convert_v1_PodReadinessGate_To_core_PodReadinessGate is an autogenerated conversion function. +func Convert_v1_PodReadinessGate_To_core_PodReadinessGate(in *v1.PodReadinessGate, out *core.PodReadinessGate, s conversion.Scope) error { + return autoConvert_v1_PodReadinessGate_To_core_PodReadinessGate(in, out, s) +} + +func autoConvert_core_PodReadinessGate_To_v1_PodReadinessGate(in *core.PodReadinessGate, out *v1.PodReadinessGate, s conversion.Scope) error { + out.ConditionType = v1.PodConditionType(in.ConditionType) + return nil +} + +// Convert_core_PodReadinessGate_To_v1_PodReadinessGate is an autogenerated conversion function. +func Convert_core_PodReadinessGate_To_v1_PodReadinessGate(in *core.PodReadinessGate, out *v1.PodReadinessGate, s conversion.Scope) error { + return autoConvert_core_PodReadinessGate_To_v1_PodReadinessGate(in, out, s) +} + +func autoConvert_v1_PodResourceClaim_To_core_PodResourceClaim(in *v1.PodResourceClaim, out *core.PodResourceClaim, s conversion.Scope) error { + out.Name = in.Name + if err := Convert_v1_ClaimSource_To_core_ClaimSource(&in.Source, &out.Source, s); err != nil { + return err + } + return nil +} + +// Convert_v1_PodResourceClaim_To_core_PodResourceClaim is an autogenerated conversion function. +func Convert_v1_PodResourceClaim_To_core_PodResourceClaim(in *v1.PodResourceClaim, out *core.PodResourceClaim, s conversion.Scope) error { + return autoConvert_v1_PodResourceClaim_To_core_PodResourceClaim(in, out, s) +} + +func autoConvert_core_PodResourceClaim_To_v1_PodResourceClaim(in *core.PodResourceClaim, out *v1.PodResourceClaim, s conversion.Scope) error { + out.Name = in.Name + if err := Convert_core_ClaimSource_To_v1_ClaimSource(&in.Source, &out.Source, s); err != nil { + return err + } + return nil +} + +// Convert_core_PodResourceClaim_To_v1_PodResourceClaim is an autogenerated conversion function. +func Convert_core_PodResourceClaim_To_v1_PodResourceClaim(in *core.PodResourceClaim, out *v1.PodResourceClaim, s conversion.Scope) error { + return autoConvert_core_PodResourceClaim_To_v1_PodResourceClaim(in, out, s) +} + +func autoConvert_v1_PodSchedulingGate_To_core_PodSchedulingGate(in *v1.PodSchedulingGate, out *core.PodSchedulingGate, s conversion.Scope) error { + out.Name = in.Name + return nil +} + +// Convert_v1_PodSchedulingGate_To_core_PodSchedulingGate is an autogenerated conversion function. +func Convert_v1_PodSchedulingGate_To_core_PodSchedulingGate(in *v1.PodSchedulingGate, out *core.PodSchedulingGate, s conversion.Scope) error { + return autoConvert_v1_PodSchedulingGate_To_core_PodSchedulingGate(in, out, s) +} + +func autoConvert_core_PodSchedulingGate_To_v1_PodSchedulingGate(in *core.PodSchedulingGate, out *v1.PodSchedulingGate, s conversion.Scope) error { + out.Name = in.Name + return nil +} + +// Convert_core_PodSchedulingGate_To_v1_PodSchedulingGate is an autogenerated conversion function. +func Convert_core_PodSchedulingGate_To_v1_PodSchedulingGate(in *core.PodSchedulingGate, out *v1.PodSchedulingGate, s conversion.Scope) error { + return autoConvert_core_PodSchedulingGate_To_v1_PodSchedulingGate(in, out, s) +} + +func autoConvert_v1_PodSecurityContext_To_core_PodSecurityContext(in *v1.PodSecurityContext, out *core.PodSecurityContext, s conversion.Scope) error { + out.SELinuxOptions = (*core.SELinuxOptions)(unsafe.Pointer(in.SELinuxOptions)) + out.WindowsOptions = (*core.WindowsSecurityContextOptions)(unsafe.Pointer(in.WindowsOptions)) + out.RunAsUser = (*int64)(unsafe.Pointer(in.RunAsUser)) + out.RunAsGroup = (*int64)(unsafe.Pointer(in.RunAsGroup)) + out.RunAsNonRoot = (*bool)(unsafe.Pointer(in.RunAsNonRoot)) + out.SupplementalGroups = *(*[]int64)(unsafe.Pointer(&in.SupplementalGroups)) + out.FSGroup = (*int64)(unsafe.Pointer(in.FSGroup)) + out.Sysctls = *(*[]core.Sysctl)(unsafe.Pointer(&in.Sysctls)) + out.FSGroupChangePolicy = (*core.PodFSGroupChangePolicy)(unsafe.Pointer(in.FSGroupChangePolicy)) + out.SeccompProfile = (*core.SeccompProfile)(unsafe.Pointer(in.SeccompProfile)) + return nil +} + +// Convert_v1_PodSecurityContext_To_core_PodSecurityContext is an autogenerated conversion function. +func Convert_v1_PodSecurityContext_To_core_PodSecurityContext(in *v1.PodSecurityContext, out *core.PodSecurityContext, s conversion.Scope) error { + return autoConvert_v1_PodSecurityContext_To_core_PodSecurityContext(in, out, s) +} + +func autoConvert_core_PodSecurityContext_To_v1_PodSecurityContext(in *core.PodSecurityContext, out *v1.PodSecurityContext, s conversion.Scope) error { + // INFO: in.HostNetwork opted out of conversion generation + // INFO: in.HostPID opted out of conversion generation + // INFO: in.HostIPC opted out of conversion generation + // INFO: in.ShareProcessNamespace opted out of conversion generation + // INFO: in.HostUsers opted out of conversion generation + out.SELinuxOptions = (*v1.SELinuxOptions)(unsafe.Pointer(in.SELinuxOptions)) + out.WindowsOptions = (*v1.WindowsSecurityContextOptions)(unsafe.Pointer(in.WindowsOptions)) + out.RunAsUser = (*int64)(unsafe.Pointer(in.RunAsUser)) + out.RunAsGroup = (*int64)(unsafe.Pointer(in.RunAsGroup)) + out.RunAsNonRoot = (*bool)(unsafe.Pointer(in.RunAsNonRoot)) + out.SupplementalGroups = *(*[]int64)(unsafe.Pointer(&in.SupplementalGroups)) + out.FSGroup = (*int64)(unsafe.Pointer(in.FSGroup)) + out.FSGroupChangePolicy = (*v1.PodFSGroupChangePolicy)(unsafe.Pointer(in.FSGroupChangePolicy)) + out.Sysctls = *(*[]v1.Sysctl)(unsafe.Pointer(&in.Sysctls)) + out.SeccompProfile = (*v1.SeccompProfile)(unsafe.Pointer(in.SeccompProfile)) + return nil +} + +// Convert_core_PodSecurityContext_To_v1_PodSecurityContext is an autogenerated conversion function. +func Convert_core_PodSecurityContext_To_v1_PodSecurityContext(in *core.PodSecurityContext, out *v1.PodSecurityContext, s conversion.Scope) error { + return autoConvert_core_PodSecurityContext_To_v1_PodSecurityContext(in, out, s) +} + +func autoConvert_v1_PodSignature_To_core_PodSignature(in *v1.PodSignature, out *core.PodSignature, s conversion.Scope) error { + out.PodController = (*metav1.OwnerReference)(unsafe.Pointer(in.PodController)) + return nil +} + +// Convert_v1_PodSignature_To_core_PodSignature is an autogenerated conversion function. +func Convert_v1_PodSignature_To_core_PodSignature(in *v1.PodSignature, out *core.PodSignature, s conversion.Scope) error { + return autoConvert_v1_PodSignature_To_core_PodSignature(in, out, s) +} + +func autoConvert_core_PodSignature_To_v1_PodSignature(in *core.PodSignature, out *v1.PodSignature, s conversion.Scope) error { + out.PodController = (*metav1.OwnerReference)(unsafe.Pointer(in.PodController)) + return nil +} + +// Convert_core_PodSignature_To_v1_PodSignature is an autogenerated conversion function. +func Convert_core_PodSignature_To_v1_PodSignature(in *core.PodSignature, out *v1.PodSignature, s conversion.Scope) error { + return autoConvert_core_PodSignature_To_v1_PodSignature(in, out, s) +} + +func autoConvert_v1_PodSpec_To_core_PodSpec(in *v1.PodSpec, out *core.PodSpec, s conversion.Scope) error { + if in.Volumes != nil { + in, out := &in.Volumes, &out.Volumes + *out = make([]core.Volume, len(*in)) + for i := range *in { + if err := Convert_v1_Volume_To_core_Volume(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Volumes = nil + } + out.InitContainers = *(*[]core.Container)(unsafe.Pointer(&in.InitContainers)) + out.Containers = *(*[]core.Container)(unsafe.Pointer(&in.Containers)) + out.EphemeralContainers = *(*[]core.EphemeralContainer)(unsafe.Pointer(&in.EphemeralContainers)) + out.RestartPolicy = core.RestartPolicy(in.RestartPolicy) + out.TerminationGracePeriodSeconds = (*int64)(unsafe.Pointer(in.TerminationGracePeriodSeconds)) + out.ActiveDeadlineSeconds = (*int64)(unsafe.Pointer(in.ActiveDeadlineSeconds)) + out.DNSPolicy = core.DNSPolicy(in.DNSPolicy) + out.NodeSelector = *(*map[string]string)(unsafe.Pointer(&in.NodeSelector)) + out.ServiceAccountName = in.ServiceAccountName + // INFO: in.DeprecatedServiceAccount opted out of conversion generation + out.AutomountServiceAccountToken = (*bool)(unsafe.Pointer(in.AutomountServiceAccountToken)) + out.NodeName = in.NodeName + // INFO: in.HostNetwork opted out of conversion generation + // INFO: in.HostPID opted out of conversion generation + // INFO: in.HostIPC opted out of conversion generation + // INFO: in.ShareProcessNamespace opted out of conversion generation + if in.SecurityContext != nil { + in, out := &in.SecurityContext, &out.SecurityContext + *out = new(core.PodSecurityContext) + if err := Convert_v1_PodSecurityContext_To_core_PodSecurityContext(*in, *out, s); err != nil { + return err + } + } else { + out.SecurityContext = nil + } + out.ImagePullSecrets = *(*[]core.LocalObjectReference)(unsafe.Pointer(&in.ImagePullSecrets)) + out.Hostname = in.Hostname + out.Subdomain = in.Subdomain + out.Affinity = (*core.Affinity)(unsafe.Pointer(in.Affinity)) + out.SchedulerName = in.SchedulerName + out.Tolerations = *(*[]core.Toleration)(unsafe.Pointer(&in.Tolerations)) + out.HostAliases = *(*[]core.HostAlias)(unsafe.Pointer(&in.HostAliases)) + out.PriorityClassName = in.PriorityClassName + out.Priority = (*int32)(unsafe.Pointer(in.Priority)) + out.DNSConfig = (*core.PodDNSConfig)(unsafe.Pointer(in.DNSConfig)) + out.ReadinessGates = *(*[]core.PodReadinessGate)(unsafe.Pointer(&in.ReadinessGates)) + out.RuntimeClassName = (*string)(unsafe.Pointer(in.RuntimeClassName)) + out.EnableServiceLinks = (*bool)(unsafe.Pointer(in.EnableServiceLinks)) + out.PreemptionPolicy = (*core.PreemptionPolicy)(unsafe.Pointer(in.PreemptionPolicy)) + out.Overhead = *(*core.ResourceList)(unsafe.Pointer(&in.Overhead)) + out.TopologySpreadConstraints = *(*[]core.TopologySpreadConstraint)(unsafe.Pointer(&in.TopologySpreadConstraints)) + out.SetHostnameAsFQDN = (*bool)(unsafe.Pointer(in.SetHostnameAsFQDN)) + out.OS = (*core.PodOS)(unsafe.Pointer(in.OS)) + // INFO: in.HostUsers opted out of conversion generation + out.SchedulingGates = *(*[]core.PodSchedulingGate)(unsafe.Pointer(&in.SchedulingGates)) + out.ResourceClaims = *(*[]core.PodResourceClaim)(unsafe.Pointer(&in.ResourceClaims)) + return nil +} + +func autoConvert_core_PodSpec_To_v1_PodSpec(in *core.PodSpec, out *v1.PodSpec, s conversion.Scope) error { + if in.Volumes != nil { + in, out := &in.Volumes, &out.Volumes + *out = make([]v1.Volume, len(*in)) + for i := range *in { + if err := Convert_core_Volume_To_v1_Volume(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Volumes = nil + } + out.InitContainers = *(*[]v1.Container)(unsafe.Pointer(&in.InitContainers)) + out.Containers = *(*[]v1.Container)(unsafe.Pointer(&in.Containers)) + out.EphemeralContainers = *(*[]v1.EphemeralContainer)(unsafe.Pointer(&in.EphemeralContainers)) + out.RestartPolicy = v1.RestartPolicy(in.RestartPolicy) + out.TerminationGracePeriodSeconds = (*int64)(unsafe.Pointer(in.TerminationGracePeriodSeconds)) + out.ActiveDeadlineSeconds = (*int64)(unsafe.Pointer(in.ActiveDeadlineSeconds)) + out.DNSPolicy = v1.DNSPolicy(in.DNSPolicy) + out.NodeSelector = *(*map[string]string)(unsafe.Pointer(&in.NodeSelector)) + out.ServiceAccountName = in.ServiceAccountName + out.AutomountServiceAccountToken = (*bool)(unsafe.Pointer(in.AutomountServiceAccountToken)) + out.NodeName = in.NodeName + if in.SecurityContext != nil { + in, out := &in.SecurityContext, &out.SecurityContext + *out = new(v1.PodSecurityContext) + if err := Convert_core_PodSecurityContext_To_v1_PodSecurityContext(*in, *out, s); err != nil { + return err + } + } else { + out.SecurityContext = nil + } + out.ImagePullSecrets = *(*[]v1.LocalObjectReference)(unsafe.Pointer(&in.ImagePullSecrets)) + out.Hostname = in.Hostname + out.Subdomain = in.Subdomain + out.SetHostnameAsFQDN = (*bool)(unsafe.Pointer(in.SetHostnameAsFQDN)) + out.Affinity = (*v1.Affinity)(unsafe.Pointer(in.Affinity)) + out.SchedulerName = in.SchedulerName + out.Tolerations = *(*[]v1.Toleration)(unsafe.Pointer(&in.Tolerations)) + out.HostAliases = *(*[]v1.HostAlias)(unsafe.Pointer(&in.HostAliases)) + out.PriorityClassName = in.PriorityClassName + out.Priority = (*int32)(unsafe.Pointer(in.Priority)) + out.PreemptionPolicy = (*v1.PreemptionPolicy)(unsafe.Pointer(in.PreemptionPolicy)) + out.DNSConfig = (*v1.PodDNSConfig)(unsafe.Pointer(in.DNSConfig)) + out.ReadinessGates = *(*[]v1.PodReadinessGate)(unsafe.Pointer(&in.ReadinessGates)) + out.RuntimeClassName = (*string)(unsafe.Pointer(in.RuntimeClassName)) + out.Overhead = *(*v1.ResourceList)(unsafe.Pointer(&in.Overhead)) + out.EnableServiceLinks = (*bool)(unsafe.Pointer(in.EnableServiceLinks)) + out.TopologySpreadConstraints = *(*[]v1.TopologySpreadConstraint)(unsafe.Pointer(&in.TopologySpreadConstraints)) + out.OS = (*v1.PodOS)(unsafe.Pointer(in.OS)) + out.SchedulingGates = *(*[]v1.PodSchedulingGate)(unsafe.Pointer(&in.SchedulingGates)) + out.ResourceClaims = *(*[]v1.PodResourceClaim)(unsafe.Pointer(&in.ResourceClaims)) + return nil +} + +func autoConvert_v1_PodStatus_To_core_PodStatus(in *v1.PodStatus, out *core.PodStatus, s conversion.Scope) error { + out.Phase = core.PodPhase(in.Phase) + out.Conditions = *(*[]core.PodCondition)(unsafe.Pointer(&in.Conditions)) + out.Message = in.Message + out.Reason = in.Reason + out.NominatedNodeName = in.NominatedNodeName + out.HostIP = in.HostIP + // WARNING: in.PodIP requires manual conversion: does not exist in peer-type + out.PodIPs = *(*[]core.PodIP)(unsafe.Pointer(&in.PodIPs)) + out.StartTime = (*metav1.Time)(unsafe.Pointer(in.StartTime)) + out.InitContainerStatuses = *(*[]core.ContainerStatus)(unsafe.Pointer(&in.InitContainerStatuses)) + out.ContainerStatuses = *(*[]core.ContainerStatus)(unsafe.Pointer(&in.ContainerStatuses)) + out.QOSClass = core.PodQOSClass(in.QOSClass) + out.EphemeralContainerStatuses = *(*[]core.ContainerStatus)(unsafe.Pointer(&in.EphemeralContainerStatuses)) + return nil +} + +func autoConvert_core_PodStatus_To_v1_PodStatus(in *core.PodStatus, out *v1.PodStatus, s conversion.Scope) error { + out.Phase = v1.PodPhase(in.Phase) + out.Conditions = *(*[]v1.PodCondition)(unsafe.Pointer(&in.Conditions)) + out.Message = in.Message + out.Reason = in.Reason + out.NominatedNodeName = in.NominatedNodeName + out.HostIP = in.HostIP + out.PodIPs = *(*[]v1.PodIP)(unsafe.Pointer(&in.PodIPs)) + out.StartTime = (*metav1.Time)(unsafe.Pointer(in.StartTime)) + out.QOSClass = v1.PodQOSClass(in.QOSClass) + out.InitContainerStatuses = *(*[]v1.ContainerStatus)(unsafe.Pointer(&in.InitContainerStatuses)) + out.ContainerStatuses = *(*[]v1.ContainerStatus)(unsafe.Pointer(&in.ContainerStatuses)) + out.EphemeralContainerStatuses = *(*[]v1.ContainerStatus)(unsafe.Pointer(&in.EphemeralContainerStatuses)) + return nil +} + +func autoConvert_v1_PodStatusResult_To_core_PodStatusResult(in *v1.PodStatusResult, out *core.PodStatusResult, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_PodStatus_To_core_PodStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1_PodStatusResult_To_core_PodStatusResult is an autogenerated conversion function. +func Convert_v1_PodStatusResult_To_core_PodStatusResult(in *v1.PodStatusResult, out *core.PodStatusResult, s conversion.Scope) error { + return autoConvert_v1_PodStatusResult_To_core_PodStatusResult(in, out, s) +} + +func autoConvert_core_PodStatusResult_To_v1_PodStatusResult(in *core.PodStatusResult, out *v1.PodStatusResult, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_core_PodStatus_To_v1_PodStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_core_PodStatusResult_To_v1_PodStatusResult is an autogenerated conversion function. +func Convert_core_PodStatusResult_To_v1_PodStatusResult(in *core.PodStatusResult, out *v1.PodStatusResult, s conversion.Scope) error { + return autoConvert_core_PodStatusResult_To_v1_PodStatusResult(in, out, s) +} + +func autoConvert_v1_PodTemplate_To_core_PodTemplate(in *v1.PodTemplate, out *core.PodTemplate, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_PodTemplateSpec_To_core_PodTemplateSpec(&in.Template, &out.Template, s); err != nil { + return err + } + return nil +} + +// Convert_v1_PodTemplate_To_core_PodTemplate is an autogenerated conversion function. +func Convert_v1_PodTemplate_To_core_PodTemplate(in *v1.PodTemplate, out *core.PodTemplate, s conversion.Scope) error { + return autoConvert_v1_PodTemplate_To_core_PodTemplate(in, out, s) +} + +func autoConvert_core_PodTemplate_To_v1_PodTemplate(in *core.PodTemplate, out *v1.PodTemplate, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_core_PodTemplateSpec_To_v1_PodTemplateSpec(&in.Template, &out.Template, s); err != nil { + return err + } + return nil +} + +// Convert_core_PodTemplate_To_v1_PodTemplate is an autogenerated conversion function. +func Convert_core_PodTemplate_To_v1_PodTemplate(in *core.PodTemplate, out *v1.PodTemplate, s conversion.Scope) error { + return autoConvert_core_PodTemplate_To_v1_PodTemplate(in, out, s) +} + +func autoConvert_v1_PodTemplateList_To_core_PodTemplateList(in *v1.PodTemplateList, out *core.PodTemplateList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]core.PodTemplate, len(*in)) + for i := range *in { + if err := Convert_v1_PodTemplate_To_core_PodTemplate(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +// Convert_v1_PodTemplateList_To_core_PodTemplateList is an autogenerated conversion function. +func Convert_v1_PodTemplateList_To_core_PodTemplateList(in *v1.PodTemplateList, out *core.PodTemplateList, s conversion.Scope) error { + return autoConvert_v1_PodTemplateList_To_core_PodTemplateList(in, out, s) +} + +func autoConvert_core_PodTemplateList_To_v1_PodTemplateList(in *core.PodTemplateList, out *v1.PodTemplateList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]v1.PodTemplate, len(*in)) + for i := range *in { + if err := Convert_core_PodTemplate_To_v1_PodTemplate(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +// Convert_core_PodTemplateList_To_v1_PodTemplateList is an autogenerated conversion function. +func Convert_core_PodTemplateList_To_v1_PodTemplateList(in *core.PodTemplateList, out *v1.PodTemplateList, s conversion.Scope) error { + return autoConvert_core_PodTemplateList_To_v1_PodTemplateList(in, out, s) +} + +func autoConvert_v1_PodTemplateSpec_To_core_PodTemplateSpec(in *v1.PodTemplateSpec, out *core.PodTemplateSpec, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_PodSpec_To_core_PodSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + return nil +} + +func autoConvert_core_PodTemplateSpec_To_v1_PodTemplateSpec(in *core.PodTemplateSpec, out *v1.PodTemplateSpec, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_core_PodSpec_To_v1_PodSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + return nil +} + +func autoConvert_v1_PortStatus_To_core_PortStatus(in *v1.PortStatus, out *core.PortStatus, s conversion.Scope) error { + out.Port = in.Port + out.Protocol = core.Protocol(in.Protocol) + out.Error = (*string)(unsafe.Pointer(in.Error)) + return nil +} + +// Convert_v1_PortStatus_To_core_PortStatus is an autogenerated conversion function. +func Convert_v1_PortStatus_To_core_PortStatus(in *v1.PortStatus, out *core.PortStatus, s conversion.Scope) error { + return autoConvert_v1_PortStatus_To_core_PortStatus(in, out, s) +} + +func autoConvert_core_PortStatus_To_v1_PortStatus(in *core.PortStatus, out *v1.PortStatus, s conversion.Scope) error { + out.Port = in.Port + out.Protocol = v1.Protocol(in.Protocol) + out.Error = (*string)(unsafe.Pointer(in.Error)) + return nil +} + +// Convert_core_PortStatus_To_v1_PortStatus is an autogenerated conversion function. +func Convert_core_PortStatus_To_v1_PortStatus(in *core.PortStatus, out *v1.PortStatus, s conversion.Scope) error { + return autoConvert_core_PortStatus_To_v1_PortStatus(in, out, s) +} + +func autoConvert_v1_PortworxVolumeSource_To_core_PortworxVolumeSource(in *v1.PortworxVolumeSource, out *core.PortworxVolumeSource, s conversion.Scope) error { + out.VolumeID = in.VolumeID + out.FSType = in.FSType + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_v1_PortworxVolumeSource_To_core_PortworxVolumeSource is an autogenerated conversion function. +func Convert_v1_PortworxVolumeSource_To_core_PortworxVolumeSource(in *v1.PortworxVolumeSource, out *core.PortworxVolumeSource, s conversion.Scope) error { + return autoConvert_v1_PortworxVolumeSource_To_core_PortworxVolumeSource(in, out, s) +} + +func autoConvert_core_PortworxVolumeSource_To_v1_PortworxVolumeSource(in *core.PortworxVolumeSource, out *v1.PortworxVolumeSource, s conversion.Scope) error { + out.VolumeID = in.VolumeID + out.FSType = in.FSType + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_core_PortworxVolumeSource_To_v1_PortworxVolumeSource is an autogenerated conversion function. +func Convert_core_PortworxVolumeSource_To_v1_PortworxVolumeSource(in *core.PortworxVolumeSource, out *v1.PortworxVolumeSource, s conversion.Scope) error { + return autoConvert_core_PortworxVolumeSource_To_v1_PortworxVolumeSource(in, out, s) +} + +func autoConvert_v1_Preconditions_To_core_Preconditions(in *v1.Preconditions, out *core.Preconditions, s conversion.Scope) error { + out.UID = (*types.UID)(unsafe.Pointer(in.UID)) + return nil +} + +// Convert_v1_Preconditions_To_core_Preconditions is an autogenerated conversion function. +func Convert_v1_Preconditions_To_core_Preconditions(in *v1.Preconditions, out *core.Preconditions, s conversion.Scope) error { + return autoConvert_v1_Preconditions_To_core_Preconditions(in, out, s) +} + +func autoConvert_core_Preconditions_To_v1_Preconditions(in *core.Preconditions, out *v1.Preconditions, s conversion.Scope) error { + out.UID = (*types.UID)(unsafe.Pointer(in.UID)) + return nil +} + +// Convert_core_Preconditions_To_v1_Preconditions is an autogenerated conversion function. +func Convert_core_Preconditions_To_v1_Preconditions(in *core.Preconditions, out *v1.Preconditions, s conversion.Scope) error { + return autoConvert_core_Preconditions_To_v1_Preconditions(in, out, s) +} + +func autoConvert_v1_PreferAvoidPodsEntry_To_core_PreferAvoidPodsEntry(in *v1.PreferAvoidPodsEntry, out *core.PreferAvoidPodsEntry, s conversion.Scope) error { + if err := Convert_v1_PodSignature_To_core_PodSignature(&in.PodSignature, &out.PodSignature, s); err != nil { + return err + } + out.EvictionTime = in.EvictionTime + out.Reason = in.Reason + out.Message = in.Message + return nil +} + +// Convert_v1_PreferAvoidPodsEntry_To_core_PreferAvoidPodsEntry is an autogenerated conversion function. +func Convert_v1_PreferAvoidPodsEntry_To_core_PreferAvoidPodsEntry(in *v1.PreferAvoidPodsEntry, out *core.PreferAvoidPodsEntry, s conversion.Scope) error { + return autoConvert_v1_PreferAvoidPodsEntry_To_core_PreferAvoidPodsEntry(in, out, s) +} + +func autoConvert_core_PreferAvoidPodsEntry_To_v1_PreferAvoidPodsEntry(in *core.PreferAvoidPodsEntry, out *v1.PreferAvoidPodsEntry, s conversion.Scope) error { + if err := Convert_core_PodSignature_To_v1_PodSignature(&in.PodSignature, &out.PodSignature, s); err != nil { + return err + } + out.EvictionTime = in.EvictionTime + out.Reason = in.Reason + out.Message = in.Message + return nil +} + +// Convert_core_PreferAvoidPodsEntry_To_v1_PreferAvoidPodsEntry is an autogenerated conversion function. +func Convert_core_PreferAvoidPodsEntry_To_v1_PreferAvoidPodsEntry(in *core.PreferAvoidPodsEntry, out *v1.PreferAvoidPodsEntry, s conversion.Scope) error { + return autoConvert_core_PreferAvoidPodsEntry_To_v1_PreferAvoidPodsEntry(in, out, s) +} + +func autoConvert_v1_PreferredSchedulingTerm_To_core_PreferredSchedulingTerm(in *v1.PreferredSchedulingTerm, out *core.PreferredSchedulingTerm, s conversion.Scope) error { + out.Weight = in.Weight + if err := Convert_v1_NodeSelectorTerm_To_core_NodeSelectorTerm(&in.Preference, &out.Preference, s); err != nil { + return err + } + return nil +} + +// Convert_v1_PreferredSchedulingTerm_To_core_PreferredSchedulingTerm is an autogenerated conversion function. +func Convert_v1_PreferredSchedulingTerm_To_core_PreferredSchedulingTerm(in *v1.PreferredSchedulingTerm, out *core.PreferredSchedulingTerm, s conversion.Scope) error { + return autoConvert_v1_PreferredSchedulingTerm_To_core_PreferredSchedulingTerm(in, out, s) +} + +func autoConvert_core_PreferredSchedulingTerm_To_v1_PreferredSchedulingTerm(in *core.PreferredSchedulingTerm, out *v1.PreferredSchedulingTerm, s conversion.Scope) error { + out.Weight = in.Weight + if err := Convert_core_NodeSelectorTerm_To_v1_NodeSelectorTerm(&in.Preference, &out.Preference, s); err != nil { + return err + } + return nil +} + +// Convert_core_PreferredSchedulingTerm_To_v1_PreferredSchedulingTerm is an autogenerated conversion function. +func Convert_core_PreferredSchedulingTerm_To_v1_PreferredSchedulingTerm(in *core.PreferredSchedulingTerm, out *v1.PreferredSchedulingTerm, s conversion.Scope) error { + return autoConvert_core_PreferredSchedulingTerm_To_v1_PreferredSchedulingTerm(in, out, s) +} + +func autoConvert_v1_Probe_To_core_Probe(in *v1.Probe, out *core.Probe, s conversion.Scope) error { + if err := Convert_v1_ProbeHandler_To_core_ProbeHandler(&in.ProbeHandler, &out.ProbeHandler, s); err != nil { + return err + } + out.InitialDelaySeconds = in.InitialDelaySeconds + out.TimeoutSeconds = in.TimeoutSeconds + out.PeriodSeconds = in.PeriodSeconds + out.SuccessThreshold = in.SuccessThreshold + out.FailureThreshold = in.FailureThreshold + out.TerminationGracePeriodSeconds = (*int64)(unsafe.Pointer(in.TerminationGracePeriodSeconds)) + return nil +} + +// Convert_v1_Probe_To_core_Probe is an autogenerated conversion function. +func Convert_v1_Probe_To_core_Probe(in *v1.Probe, out *core.Probe, s conversion.Scope) error { + return autoConvert_v1_Probe_To_core_Probe(in, out, s) +} + +func autoConvert_core_Probe_To_v1_Probe(in *core.Probe, out *v1.Probe, s conversion.Scope) error { + if err := Convert_core_ProbeHandler_To_v1_ProbeHandler(&in.ProbeHandler, &out.ProbeHandler, s); err != nil { + return err + } + out.InitialDelaySeconds = in.InitialDelaySeconds + out.TimeoutSeconds = in.TimeoutSeconds + out.PeriodSeconds = in.PeriodSeconds + out.SuccessThreshold = in.SuccessThreshold + out.FailureThreshold = in.FailureThreshold + out.TerminationGracePeriodSeconds = (*int64)(unsafe.Pointer(in.TerminationGracePeriodSeconds)) + return nil +} + +// Convert_core_Probe_To_v1_Probe is an autogenerated conversion function. +func Convert_core_Probe_To_v1_Probe(in *core.Probe, out *v1.Probe, s conversion.Scope) error { + return autoConvert_core_Probe_To_v1_Probe(in, out, s) +} + +func autoConvert_v1_ProbeHandler_To_core_ProbeHandler(in *v1.ProbeHandler, out *core.ProbeHandler, s conversion.Scope) error { + out.Exec = (*core.ExecAction)(unsafe.Pointer(in.Exec)) + out.HTTPGet = (*core.HTTPGetAction)(unsafe.Pointer(in.HTTPGet)) + out.TCPSocket = (*core.TCPSocketAction)(unsafe.Pointer(in.TCPSocket)) + out.GRPC = (*core.GRPCAction)(unsafe.Pointer(in.GRPC)) + return nil +} + +// Convert_v1_ProbeHandler_To_core_ProbeHandler is an autogenerated conversion function. +func Convert_v1_ProbeHandler_To_core_ProbeHandler(in *v1.ProbeHandler, out *core.ProbeHandler, s conversion.Scope) error { + return autoConvert_v1_ProbeHandler_To_core_ProbeHandler(in, out, s) +} + +func autoConvert_core_ProbeHandler_To_v1_ProbeHandler(in *core.ProbeHandler, out *v1.ProbeHandler, s conversion.Scope) error { + out.Exec = (*v1.ExecAction)(unsafe.Pointer(in.Exec)) + out.HTTPGet = (*v1.HTTPGetAction)(unsafe.Pointer(in.HTTPGet)) + out.TCPSocket = (*v1.TCPSocketAction)(unsafe.Pointer(in.TCPSocket)) + out.GRPC = (*v1.GRPCAction)(unsafe.Pointer(in.GRPC)) + return nil +} + +// Convert_core_ProbeHandler_To_v1_ProbeHandler is an autogenerated conversion function. +func Convert_core_ProbeHandler_To_v1_ProbeHandler(in *core.ProbeHandler, out *v1.ProbeHandler, s conversion.Scope) error { + return autoConvert_core_ProbeHandler_To_v1_ProbeHandler(in, out, s) +} + +func autoConvert_v1_ProjectedVolumeSource_To_core_ProjectedVolumeSource(in *v1.ProjectedVolumeSource, out *core.ProjectedVolumeSource, s conversion.Scope) error { + if in.Sources != nil { + in, out := &in.Sources, &out.Sources + *out = make([]core.VolumeProjection, len(*in)) + for i := range *in { + if err := Convert_v1_VolumeProjection_To_core_VolumeProjection(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Sources = nil + } + out.DefaultMode = (*int32)(unsafe.Pointer(in.DefaultMode)) + return nil +} + +// Convert_v1_ProjectedVolumeSource_To_core_ProjectedVolumeSource is an autogenerated conversion function. +func Convert_v1_ProjectedVolumeSource_To_core_ProjectedVolumeSource(in *v1.ProjectedVolumeSource, out *core.ProjectedVolumeSource, s conversion.Scope) error { + return autoConvert_v1_ProjectedVolumeSource_To_core_ProjectedVolumeSource(in, out, s) +} + +func autoConvert_core_ProjectedVolumeSource_To_v1_ProjectedVolumeSource(in *core.ProjectedVolumeSource, out *v1.ProjectedVolumeSource, s conversion.Scope) error { + if in.Sources != nil { + in, out := &in.Sources, &out.Sources + *out = make([]v1.VolumeProjection, len(*in)) + for i := range *in { + if err := Convert_core_VolumeProjection_To_v1_VolumeProjection(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Sources = nil + } + out.DefaultMode = (*int32)(unsafe.Pointer(in.DefaultMode)) + return nil +} + +// Convert_core_ProjectedVolumeSource_To_v1_ProjectedVolumeSource is an autogenerated conversion function. +func Convert_core_ProjectedVolumeSource_To_v1_ProjectedVolumeSource(in *core.ProjectedVolumeSource, out *v1.ProjectedVolumeSource, s conversion.Scope) error { + return autoConvert_core_ProjectedVolumeSource_To_v1_ProjectedVolumeSource(in, out, s) +} + +func autoConvert_v1_QuobyteVolumeSource_To_core_QuobyteVolumeSource(in *v1.QuobyteVolumeSource, out *core.QuobyteVolumeSource, s conversion.Scope) error { + out.Registry = in.Registry + out.Volume = in.Volume + out.ReadOnly = in.ReadOnly + out.User = in.User + out.Group = in.Group + out.Tenant = in.Tenant + return nil +} + +// Convert_v1_QuobyteVolumeSource_To_core_QuobyteVolumeSource is an autogenerated conversion function. +func Convert_v1_QuobyteVolumeSource_To_core_QuobyteVolumeSource(in *v1.QuobyteVolumeSource, out *core.QuobyteVolumeSource, s conversion.Scope) error { + return autoConvert_v1_QuobyteVolumeSource_To_core_QuobyteVolumeSource(in, out, s) +} + +func autoConvert_core_QuobyteVolumeSource_To_v1_QuobyteVolumeSource(in *core.QuobyteVolumeSource, out *v1.QuobyteVolumeSource, s conversion.Scope) error { + out.Registry = in.Registry + out.Volume = in.Volume + out.ReadOnly = in.ReadOnly + out.User = in.User + out.Group = in.Group + out.Tenant = in.Tenant + return nil +} + +// Convert_core_QuobyteVolumeSource_To_v1_QuobyteVolumeSource is an autogenerated conversion function. +func Convert_core_QuobyteVolumeSource_To_v1_QuobyteVolumeSource(in *core.QuobyteVolumeSource, out *v1.QuobyteVolumeSource, s conversion.Scope) error { + return autoConvert_core_QuobyteVolumeSource_To_v1_QuobyteVolumeSource(in, out, s) +} + +func autoConvert_v1_RBDPersistentVolumeSource_To_core_RBDPersistentVolumeSource(in *v1.RBDPersistentVolumeSource, out *core.RBDPersistentVolumeSource, s conversion.Scope) error { + out.CephMonitors = *(*[]string)(unsafe.Pointer(&in.CephMonitors)) + out.RBDImage = in.RBDImage + out.FSType = in.FSType + out.RBDPool = in.RBDPool + out.RadosUser = in.RadosUser + out.Keyring = in.Keyring + out.SecretRef = (*core.SecretReference)(unsafe.Pointer(in.SecretRef)) + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_v1_RBDPersistentVolumeSource_To_core_RBDPersistentVolumeSource is an autogenerated conversion function. +func Convert_v1_RBDPersistentVolumeSource_To_core_RBDPersistentVolumeSource(in *v1.RBDPersistentVolumeSource, out *core.RBDPersistentVolumeSource, s conversion.Scope) error { + return autoConvert_v1_RBDPersistentVolumeSource_To_core_RBDPersistentVolumeSource(in, out, s) +} + +func autoConvert_core_RBDPersistentVolumeSource_To_v1_RBDPersistentVolumeSource(in *core.RBDPersistentVolumeSource, out *v1.RBDPersistentVolumeSource, s conversion.Scope) error { + out.CephMonitors = *(*[]string)(unsafe.Pointer(&in.CephMonitors)) + out.RBDImage = in.RBDImage + out.FSType = in.FSType + out.RBDPool = in.RBDPool + out.RadosUser = in.RadosUser + out.Keyring = in.Keyring + out.SecretRef = (*v1.SecretReference)(unsafe.Pointer(in.SecretRef)) + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_core_RBDPersistentVolumeSource_To_v1_RBDPersistentVolumeSource is an autogenerated conversion function. +func Convert_core_RBDPersistentVolumeSource_To_v1_RBDPersistentVolumeSource(in *core.RBDPersistentVolumeSource, out *v1.RBDPersistentVolumeSource, s conversion.Scope) error { + return autoConvert_core_RBDPersistentVolumeSource_To_v1_RBDPersistentVolumeSource(in, out, s) +} + +func autoConvert_v1_RBDVolumeSource_To_core_RBDVolumeSource(in *v1.RBDVolumeSource, out *core.RBDVolumeSource, s conversion.Scope) error { + out.CephMonitors = *(*[]string)(unsafe.Pointer(&in.CephMonitors)) + out.RBDImage = in.RBDImage + out.FSType = in.FSType + out.RBDPool = in.RBDPool + out.RadosUser = in.RadosUser + out.Keyring = in.Keyring + out.SecretRef = (*core.LocalObjectReference)(unsafe.Pointer(in.SecretRef)) + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_v1_RBDVolumeSource_To_core_RBDVolumeSource is an autogenerated conversion function. +func Convert_v1_RBDVolumeSource_To_core_RBDVolumeSource(in *v1.RBDVolumeSource, out *core.RBDVolumeSource, s conversion.Scope) error { + return autoConvert_v1_RBDVolumeSource_To_core_RBDVolumeSource(in, out, s) +} + +func autoConvert_core_RBDVolumeSource_To_v1_RBDVolumeSource(in *core.RBDVolumeSource, out *v1.RBDVolumeSource, s conversion.Scope) error { + out.CephMonitors = *(*[]string)(unsafe.Pointer(&in.CephMonitors)) + out.RBDImage = in.RBDImage + out.FSType = in.FSType + out.RBDPool = in.RBDPool + out.RadosUser = in.RadosUser + out.Keyring = in.Keyring + out.SecretRef = (*v1.LocalObjectReference)(unsafe.Pointer(in.SecretRef)) + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_core_RBDVolumeSource_To_v1_RBDVolumeSource is an autogenerated conversion function. +func Convert_core_RBDVolumeSource_To_v1_RBDVolumeSource(in *core.RBDVolumeSource, out *v1.RBDVolumeSource, s conversion.Scope) error { + return autoConvert_core_RBDVolumeSource_To_v1_RBDVolumeSource(in, out, s) +} + +func autoConvert_v1_RangeAllocation_To_core_RangeAllocation(in *v1.RangeAllocation, out *core.RangeAllocation, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + out.Range = in.Range + out.Data = *(*[]byte)(unsafe.Pointer(&in.Data)) + return nil +} + +// Convert_v1_RangeAllocation_To_core_RangeAllocation is an autogenerated conversion function. +func Convert_v1_RangeAllocation_To_core_RangeAllocation(in *v1.RangeAllocation, out *core.RangeAllocation, s conversion.Scope) error { + return autoConvert_v1_RangeAllocation_To_core_RangeAllocation(in, out, s) +} + +func autoConvert_core_RangeAllocation_To_v1_RangeAllocation(in *core.RangeAllocation, out *v1.RangeAllocation, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + out.Range = in.Range + out.Data = *(*[]byte)(unsafe.Pointer(&in.Data)) + return nil +} + +// Convert_core_RangeAllocation_To_v1_RangeAllocation is an autogenerated conversion function. +func Convert_core_RangeAllocation_To_v1_RangeAllocation(in *core.RangeAllocation, out *v1.RangeAllocation, s conversion.Scope) error { + return autoConvert_core_RangeAllocation_To_v1_RangeAllocation(in, out, s) +} + +func autoConvert_v1_ReplicationController_To_core_ReplicationController(in *v1.ReplicationController, out *core.ReplicationController, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_ReplicationControllerSpec_To_core_ReplicationControllerSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_v1_ReplicationControllerStatus_To_core_ReplicationControllerStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1_ReplicationController_To_core_ReplicationController is an autogenerated conversion function. +func Convert_v1_ReplicationController_To_core_ReplicationController(in *v1.ReplicationController, out *core.ReplicationController, s conversion.Scope) error { + return autoConvert_v1_ReplicationController_To_core_ReplicationController(in, out, s) +} + +func autoConvert_core_ReplicationController_To_v1_ReplicationController(in *core.ReplicationController, out *v1.ReplicationController, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_core_ReplicationControllerSpec_To_v1_ReplicationControllerSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_core_ReplicationControllerStatus_To_v1_ReplicationControllerStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_core_ReplicationController_To_v1_ReplicationController is an autogenerated conversion function. +func Convert_core_ReplicationController_To_v1_ReplicationController(in *core.ReplicationController, out *v1.ReplicationController, s conversion.Scope) error { + return autoConvert_core_ReplicationController_To_v1_ReplicationController(in, out, s) +} + +func autoConvert_v1_ReplicationControllerCondition_To_core_ReplicationControllerCondition(in *v1.ReplicationControllerCondition, out *core.ReplicationControllerCondition, s conversion.Scope) error { + out.Type = core.ReplicationControllerConditionType(in.Type) + out.Status = core.ConditionStatus(in.Status) + out.LastTransitionTime = in.LastTransitionTime + out.Reason = in.Reason + out.Message = in.Message + return nil +} + +// Convert_v1_ReplicationControllerCondition_To_core_ReplicationControllerCondition is an autogenerated conversion function. +func Convert_v1_ReplicationControllerCondition_To_core_ReplicationControllerCondition(in *v1.ReplicationControllerCondition, out *core.ReplicationControllerCondition, s conversion.Scope) error { + return autoConvert_v1_ReplicationControllerCondition_To_core_ReplicationControllerCondition(in, out, s) +} + +func autoConvert_core_ReplicationControllerCondition_To_v1_ReplicationControllerCondition(in *core.ReplicationControllerCondition, out *v1.ReplicationControllerCondition, s conversion.Scope) error { + out.Type = v1.ReplicationControllerConditionType(in.Type) + out.Status = v1.ConditionStatus(in.Status) + out.LastTransitionTime = in.LastTransitionTime + out.Reason = in.Reason + out.Message = in.Message + return nil +} + +// Convert_core_ReplicationControllerCondition_To_v1_ReplicationControllerCondition is an autogenerated conversion function. +func Convert_core_ReplicationControllerCondition_To_v1_ReplicationControllerCondition(in *core.ReplicationControllerCondition, out *v1.ReplicationControllerCondition, s conversion.Scope) error { + return autoConvert_core_ReplicationControllerCondition_To_v1_ReplicationControllerCondition(in, out, s) +} + +func autoConvert_v1_ReplicationControllerList_To_core_ReplicationControllerList(in *v1.ReplicationControllerList, out *core.ReplicationControllerList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]core.ReplicationController, len(*in)) + for i := range *in { + if err := Convert_v1_ReplicationController_To_core_ReplicationController(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +// Convert_v1_ReplicationControllerList_To_core_ReplicationControllerList is an autogenerated conversion function. +func Convert_v1_ReplicationControllerList_To_core_ReplicationControllerList(in *v1.ReplicationControllerList, out *core.ReplicationControllerList, s conversion.Scope) error { + return autoConvert_v1_ReplicationControllerList_To_core_ReplicationControllerList(in, out, s) +} + +func autoConvert_core_ReplicationControllerList_To_v1_ReplicationControllerList(in *core.ReplicationControllerList, out *v1.ReplicationControllerList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]v1.ReplicationController, len(*in)) + for i := range *in { + if err := Convert_core_ReplicationController_To_v1_ReplicationController(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +// Convert_core_ReplicationControllerList_To_v1_ReplicationControllerList is an autogenerated conversion function. +func Convert_core_ReplicationControllerList_To_v1_ReplicationControllerList(in *core.ReplicationControllerList, out *v1.ReplicationControllerList, s conversion.Scope) error { + return autoConvert_core_ReplicationControllerList_To_v1_ReplicationControllerList(in, out, s) +} + +func autoConvert_v1_ReplicationControllerSpec_To_core_ReplicationControllerSpec(in *v1.ReplicationControllerSpec, out *core.ReplicationControllerSpec, s conversion.Scope) error { + if err := metav1.Convert_Pointer_int32_To_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } + out.MinReadySeconds = in.MinReadySeconds + out.Selector = *(*map[string]string)(unsafe.Pointer(&in.Selector)) + if in.Template != nil { + in, out := &in.Template, &out.Template + *out = new(core.PodTemplateSpec) + if err := Convert_v1_PodTemplateSpec_To_core_PodTemplateSpec(*in, *out, s); err != nil { + return err + } + } else { + out.Template = nil + } + return nil +} + +func autoConvert_core_ReplicationControllerSpec_To_v1_ReplicationControllerSpec(in *core.ReplicationControllerSpec, out *v1.ReplicationControllerSpec, s conversion.Scope) error { + if err := metav1.Convert_int32_To_Pointer_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } + out.MinReadySeconds = in.MinReadySeconds + out.Selector = *(*map[string]string)(unsafe.Pointer(&in.Selector)) + if in.Template != nil { + in, out := &in.Template, &out.Template + *out = new(v1.PodTemplateSpec) + if err := Convert_core_PodTemplateSpec_To_v1_PodTemplateSpec(*in, *out, s); err != nil { + return err + } + } else { + out.Template = nil + } + return nil +} + +func autoConvert_v1_ReplicationControllerStatus_To_core_ReplicationControllerStatus(in *v1.ReplicationControllerStatus, out *core.ReplicationControllerStatus, s conversion.Scope) error { + out.Replicas = in.Replicas + out.FullyLabeledReplicas = in.FullyLabeledReplicas + out.ReadyReplicas = in.ReadyReplicas + out.AvailableReplicas = in.AvailableReplicas + out.ObservedGeneration = in.ObservedGeneration + out.Conditions = *(*[]core.ReplicationControllerCondition)(unsafe.Pointer(&in.Conditions)) + return nil +} + +// Convert_v1_ReplicationControllerStatus_To_core_ReplicationControllerStatus is an autogenerated conversion function. +func Convert_v1_ReplicationControllerStatus_To_core_ReplicationControllerStatus(in *v1.ReplicationControllerStatus, out *core.ReplicationControllerStatus, s conversion.Scope) error { + return autoConvert_v1_ReplicationControllerStatus_To_core_ReplicationControllerStatus(in, out, s) +} + +func autoConvert_core_ReplicationControllerStatus_To_v1_ReplicationControllerStatus(in *core.ReplicationControllerStatus, out *v1.ReplicationControllerStatus, s conversion.Scope) error { + out.Replicas = in.Replicas + out.FullyLabeledReplicas = in.FullyLabeledReplicas + out.ReadyReplicas = in.ReadyReplicas + out.AvailableReplicas = in.AvailableReplicas + out.ObservedGeneration = in.ObservedGeneration + out.Conditions = *(*[]v1.ReplicationControllerCondition)(unsafe.Pointer(&in.Conditions)) + return nil +} + +// Convert_core_ReplicationControllerStatus_To_v1_ReplicationControllerStatus is an autogenerated conversion function. +func Convert_core_ReplicationControllerStatus_To_v1_ReplicationControllerStatus(in *core.ReplicationControllerStatus, out *v1.ReplicationControllerStatus, s conversion.Scope) error { + return autoConvert_core_ReplicationControllerStatus_To_v1_ReplicationControllerStatus(in, out, s) +} + +func autoConvert_v1_ResourceClaim_To_core_ResourceClaim(in *v1.ResourceClaim, out *core.ResourceClaim, s conversion.Scope) error { + out.Name = in.Name + return nil +} + +// Convert_v1_ResourceClaim_To_core_ResourceClaim is an autogenerated conversion function. +func Convert_v1_ResourceClaim_To_core_ResourceClaim(in *v1.ResourceClaim, out *core.ResourceClaim, s conversion.Scope) error { + return autoConvert_v1_ResourceClaim_To_core_ResourceClaim(in, out, s) +} + +func autoConvert_core_ResourceClaim_To_v1_ResourceClaim(in *core.ResourceClaim, out *v1.ResourceClaim, s conversion.Scope) error { + out.Name = in.Name + return nil +} + +// Convert_core_ResourceClaim_To_v1_ResourceClaim is an autogenerated conversion function. +func Convert_core_ResourceClaim_To_v1_ResourceClaim(in *core.ResourceClaim, out *v1.ResourceClaim, s conversion.Scope) error { + return autoConvert_core_ResourceClaim_To_v1_ResourceClaim(in, out, s) +} + +func autoConvert_v1_ResourceFieldSelector_To_core_ResourceFieldSelector(in *v1.ResourceFieldSelector, out *core.ResourceFieldSelector, s conversion.Scope) error { + out.ContainerName = in.ContainerName + out.Resource = in.Resource + out.Divisor = in.Divisor + return nil +} + +// Convert_v1_ResourceFieldSelector_To_core_ResourceFieldSelector is an autogenerated conversion function. +func Convert_v1_ResourceFieldSelector_To_core_ResourceFieldSelector(in *v1.ResourceFieldSelector, out *core.ResourceFieldSelector, s conversion.Scope) error { + return autoConvert_v1_ResourceFieldSelector_To_core_ResourceFieldSelector(in, out, s) +} + +func autoConvert_core_ResourceFieldSelector_To_v1_ResourceFieldSelector(in *core.ResourceFieldSelector, out *v1.ResourceFieldSelector, s conversion.Scope) error { + out.ContainerName = in.ContainerName + out.Resource = in.Resource + out.Divisor = in.Divisor + return nil +} + +// Convert_core_ResourceFieldSelector_To_v1_ResourceFieldSelector is an autogenerated conversion function. +func Convert_core_ResourceFieldSelector_To_v1_ResourceFieldSelector(in *core.ResourceFieldSelector, out *v1.ResourceFieldSelector, s conversion.Scope) error { + return autoConvert_core_ResourceFieldSelector_To_v1_ResourceFieldSelector(in, out, s) +} + +func autoConvert_v1_ResourceQuota_To_core_ResourceQuota(in *v1.ResourceQuota, out *core.ResourceQuota, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_ResourceQuotaSpec_To_core_ResourceQuotaSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_v1_ResourceQuotaStatus_To_core_ResourceQuotaStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1_ResourceQuota_To_core_ResourceQuota is an autogenerated conversion function. +func Convert_v1_ResourceQuota_To_core_ResourceQuota(in *v1.ResourceQuota, out *core.ResourceQuota, s conversion.Scope) error { + return autoConvert_v1_ResourceQuota_To_core_ResourceQuota(in, out, s) +} + +func autoConvert_core_ResourceQuota_To_v1_ResourceQuota(in *core.ResourceQuota, out *v1.ResourceQuota, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_core_ResourceQuotaSpec_To_v1_ResourceQuotaSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_core_ResourceQuotaStatus_To_v1_ResourceQuotaStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_core_ResourceQuota_To_v1_ResourceQuota is an autogenerated conversion function. +func Convert_core_ResourceQuota_To_v1_ResourceQuota(in *core.ResourceQuota, out *v1.ResourceQuota, s conversion.Scope) error { + return autoConvert_core_ResourceQuota_To_v1_ResourceQuota(in, out, s) +} + +func autoConvert_v1_ResourceQuotaList_To_core_ResourceQuotaList(in *v1.ResourceQuotaList, out *core.ResourceQuotaList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]core.ResourceQuota)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1_ResourceQuotaList_To_core_ResourceQuotaList is an autogenerated conversion function. +func Convert_v1_ResourceQuotaList_To_core_ResourceQuotaList(in *v1.ResourceQuotaList, out *core.ResourceQuotaList, s conversion.Scope) error { + return autoConvert_v1_ResourceQuotaList_To_core_ResourceQuotaList(in, out, s) +} + +func autoConvert_core_ResourceQuotaList_To_v1_ResourceQuotaList(in *core.ResourceQuotaList, out *v1.ResourceQuotaList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]v1.ResourceQuota)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_core_ResourceQuotaList_To_v1_ResourceQuotaList is an autogenerated conversion function. +func Convert_core_ResourceQuotaList_To_v1_ResourceQuotaList(in *core.ResourceQuotaList, out *v1.ResourceQuotaList, s conversion.Scope) error { + return autoConvert_core_ResourceQuotaList_To_v1_ResourceQuotaList(in, out, s) +} + +func autoConvert_v1_ResourceQuotaSpec_To_core_ResourceQuotaSpec(in *v1.ResourceQuotaSpec, out *core.ResourceQuotaSpec, s conversion.Scope) error { + out.Hard = *(*core.ResourceList)(unsafe.Pointer(&in.Hard)) + out.Scopes = *(*[]core.ResourceQuotaScope)(unsafe.Pointer(&in.Scopes)) + out.ScopeSelector = (*core.ScopeSelector)(unsafe.Pointer(in.ScopeSelector)) + return nil +} + +// Convert_v1_ResourceQuotaSpec_To_core_ResourceQuotaSpec is an autogenerated conversion function. +func Convert_v1_ResourceQuotaSpec_To_core_ResourceQuotaSpec(in *v1.ResourceQuotaSpec, out *core.ResourceQuotaSpec, s conversion.Scope) error { + return autoConvert_v1_ResourceQuotaSpec_To_core_ResourceQuotaSpec(in, out, s) +} + +func autoConvert_core_ResourceQuotaSpec_To_v1_ResourceQuotaSpec(in *core.ResourceQuotaSpec, out *v1.ResourceQuotaSpec, s conversion.Scope) error { + out.Hard = *(*v1.ResourceList)(unsafe.Pointer(&in.Hard)) + out.Scopes = *(*[]v1.ResourceQuotaScope)(unsafe.Pointer(&in.Scopes)) + out.ScopeSelector = (*v1.ScopeSelector)(unsafe.Pointer(in.ScopeSelector)) + return nil +} + +// Convert_core_ResourceQuotaSpec_To_v1_ResourceQuotaSpec is an autogenerated conversion function. +func Convert_core_ResourceQuotaSpec_To_v1_ResourceQuotaSpec(in *core.ResourceQuotaSpec, out *v1.ResourceQuotaSpec, s conversion.Scope) error { + return autoConvert_core_ResourceQuotaSpec_To_v1_ResourceQuotaSpec(in, out, s) +} + +func autoConvert_v1_ResourceQuotaStatus_To_core_ResourceQuotaStatus(in *v1.ResourceQuotaStatus, out *core.ResourceQuotaStatus, s conversion.Scope) error { + out.Hard = *(*core.ResourceList)(unsafe.Pointer(&in.Hard)) + out.Used = *(*core.ResourceList)(unsafe.Pointer(&in.Used)) + return nil +} + +// Convert_v1_ResourceQuotaStatus_To_core_ResourceQuotaStatus is an autogenerated conversion function. +func Convert_v1_ResourceQuotaStatus_To_core_ResourceQuotaStatus(in *v1.ResourceQuotaStatus, out *core.ResourceQuotaStatus, s conversion.Scope) error { + return autoConvert_v1_ResourceQuotaStatus_To_core_ResourceQuotaStatus(in, out, s) +} + +func autoConvert_core_ResourceQuotaStatus_To_v1_ResourceQuotaStatus(in *core.ResourceQuotaStatus, out *v1.ResourceQuotaStatus, s conversion.Scope) error { + out.Hard = *(*v1.ResourceList)(unsafe.Pointer(&in.Hard)) + out.Used = *(*v1.ResourceList)(unsafe.Pointer(&in.Used)) + return nil +} + +// Convert_core_ResourceQuotaStatus_To_v1_ResourceQuotaStatus is an autogenerated conversion function. +func Convert_core_ResourceQuotaStatus_To_v1_ResourceQuotaStatus(in *core.ResourceQuotaStatus, out *v1.ResourceQuotaStatus, s conversion.Scope) error { + return autoConvert_core_ResourceQuotaStatus_To_v1_ResourceQuotaStatus(in, out, s) +} + +func autoConvert_v1_ResourceRequirements_To_core_ResourceRequirements(in *v1.ResourceRequirements, out *core.ResourceRequirements, s conversion.Scope) error { + out.Limits = *(*core.ResourceList)(unsafe.Pointer(&in.Limits)) + out.Requests = *(*core.ResourceList)(unsafe.Pointer(&in.Requests)) + out.Claims = *(*[]core.ResourceClaim)(unsafe.Pointer(&in.Claims)) + return nil +} + +// Convert_v1_ResourceRequirements_To_core_ResourceRequirements is an autogenerated conversion function. +func Convert_v1_ResourceRequirements_To_core_ResourceRequirements(in *v1.ResourceRequirements, out *core.ResourceRequirements, s conversion.Scope) error { + return autoConvert_v1_ResourceRequirements_To_core_ResourceRequirements(in, out, s) +} + +func autoConvert_core_ResourceRequirements_To_v1_ResourceRequirements(in *core.ResourceRequirements, out *v1.ResourceRequirements, s conversion.Scope) error { + out.Limits = *(*v1.ResourceList)(unsafe.Pointer(&in.Limits)) + out.Requests = *(*v1.ResourceList)(unsafe.Pointer(&in.Requests)) + out.Claims = *(*[]v1.ResourceClaim)(unsafe.Pointer(&in.Claims)) + return nil +} + +// Convert_core_ResourceRequirements_To_v1_ResourceRequirements is an autogenerated conversion function. +func Convert_core_ResourceRequirements_To_v1_ResourceRequirements(in *core.ResourceRequirements, out *v1.ResourceRequirements, s conversion.Scope) error { + return autoConvert_core_ResourceRequirements_To_v1_ResourceRequirements(in, out, s) +} + +func autoConvert_v1_SELinuxOptions_To_core_SELinuxOptions(in *v1.SELinuxOptions, out *core.SELinuxOptions, s conversion.Scope) error { + out.User = in.User + out.Role = in.Role + out.Type = in.Type + out.Level = in.Level + return nil +} + +// Convert_v1_SELinuxOptions_To_core_SELinuxOptions is an autogenerated conversion function. +func Convert_v1_SELinuxOptions_To_core_SELinuxOptions(in *v1.SELinuxOptions, out *core.SELinuxOptions, s conversion.Scope) error { + return autoConvert_v1_SELinuxOptions_To_core_SELinuxOptions(in, out, s) +} + +func autoConvert_core_SELinuxOptions_To_v1_SELinuxOptions(in *core.SELinuxOptions, out *v1.SELinuxOptions, s conversion.Scope) error { + out.User = in.User + out.Role = in.Role + out.Type = in.Type + out.Level = in.Level + return nil +} + +// Convert_core_SELinuxOptions_To_v1_SELinuxOptions is an autogenerated conversion function. +func Convert_core_SELinuxOptions_To_v1_SELinuxOptions(in *core.SELinuxOptions, out *v1.SELinuxOptions, s conversion.Scope) error { + return autoConvert_core_SELinuxOptions_To_v1_SELinuxOptions(in, out, s) +} + +func autoConvert_v1_ScaleIOPersistentVolumeSource_To_core_ScaleIOPersistentVolumeSource(in *v1.ScaleIOPersistentVolumeSource, out *core.ScaleIOPersistentVolumeSource, s conversion.Scope) error { + out.Gateway = in.Gateway + out.System = in.System + out.SecretRef = (*core.SecretReference)(unsafe.Pointer(in.SecretRef)) + out.SSLEnabled = in.SSLEnabled + out.ProtectionDomain = in.ProtectionDomain + out.StoragePool = in.StoragePool + out.StorageMode = in.StorageMode + out.VolumeName = in.VolumeName + out.FSType = in.FSType + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_v1_ScaleIOPersistentVolumeSource_To_core_ScaleIOPersistentVolumeSource is an autogenerated conversion function. +func Convert_v1_ScaleIOPersistentVolumeSource_To_core_ScaleIOPersistentVolumeSource(in *v1.ScaleIOPersistentVolumeSource, out *core.ScaleIOPersistentVolumeSource, s conversion.Scope) error { + return autoConvert_v1_ScaleIOPersistentVolumeSource_To_core_ScaleIOPersistentVolumeSource(in, out, s) +} + +func autoConvert_core_ScaleIOPersistentVolumeSource_To_v1_ScaleIOPersistentVolumeSource(in *core.ScaleIOPersistentVolumeSource, out *v1.ScaleIOPersistentVolumeSource, s conversion.Scope) error { + out.Gateway = in.Gateway + out.System = in.System + out.SecretRef = (*v1.SecretReference)(unsafe.Pointer(in.SecretRef)) + out.SSLEnabled = in.SSLEnabled + out.ProtectionDomain = in.ProtectionDomain + out.StoragePool = in.StoragePool + out.StorageMode = in.StorageMode + out.VolumeName = in.VolumeName + out.FSType = in.FSType + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_core_ScaleIOPersistentVolumeSource_To_v1_ScaleIOPersistentVolumeSource is an autogenerated conversion function. +func Convert_core_ScaleIOPersistentVolumeSource_To_v1_ScaleIOPersistentVolumeSource(in *core.ScaleIOPersistentVolumeSource, out *v1.ScaleIOPersistentVolumeSource, s conversion.Scope) error { + return autoConvert_core_ScaleIOPersistentVolumeSource_To_v1_ScaleIOPersistentVolumeSource(in, out, s) +} + +func autoConvert_v1_ScaleIOVolumeSource_To_core_ScaleIOVolumeSource(in *v1.ScaleIOVolumeSource, out *core.ScaleIOVolumeSource, s conversion.Scope) error { + out.Gateway = in.Gateway + out.System = in.System + out.SecretRef = (*core.LocalObjectReference)(unsafe.Pointer(in.SecretRef)) + out.SSLEnabled = in.SSLEnabled + out.ProtectionDomain = in.ProtectionDomain + out.StoragePool = in.StoragePool + out.StorageMode = in.StorageMode + out.VolumeName = in.VolumeName + out.FSType = in.FSType + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_v1_ScaleIOVolumeSource_To_core_ScaleIOVolumeSource is an autogenerated conversion function. +func Convert_v1_ScaleIOVolumeSource_To_core_ScaleIOVolumeSource(in *v1.ScaleIOVolumeSource, out *core.ScaleIOVolumeSource, s conversion.Scope) error { + return autoConvert_v1_ScaleIOVolumeSource_To_core_ScaleIOVolumeSource(in, out, s) +} + +func autoConvert_core_ScaleIOVolumeSource_To_v1_ScaleIOVolumeSource(in *core.ScaleIOVolumeSource, out *v1.ScaleIOVolumeSource, s conversion.Scope) error { + out.Gateway = in.Gateway + out.System = in.System + out.SecretRef = (*v1.LocalObjectReference)(unsafe.Pointer(in.SecretRef)) + out.SSLEnabled = in.SSLEnabled + out.ProtectionDomain = in.ProtectionDomain + out.StoragePool = in.StoragePool + out.StorageMode = in.StorageMode + out.VolumeName = in.VolumeName + out.FSType = in.FSType + out.ReadOnly = in.ReadOnly + return nil +} + +// Convert_core_ScaleIOVolumeSource_To_v1_ScaleIOVolumeSource is an autogenerated conversion function. +func Convert_core_ScaleIOVolumeSource_To_v1_ScaleIOVolumeSource(in *core.ScaleIOVolumeSource, out *v1.ScaleIOVolumeSource, s conversion.Scope) error { + return autoConvert_core_ScaleIOVolumeSource_To_v1_ScaleIOVolumeSource(in, out, s) +} + +func autoConvert_v1_ScopeSelector_To_core_ScopeSelector(in *v1.ScopeSelector, out *core.ScopeSelector, s conversion.Scope) error { + out.MatchExpressions = *(*[]core.ScopedResourceSelectorRequirement)(unsafe.Pointer(&in.MatchExpressions)) + return nil +} + +// Convert_v1_ScopeSelector_To_core_ScopeSelector is an autogenerated conversion function. +func Convert_v1_ScopeSelector_To_core_ScopeSelector(in *v1.ScopeSelector, out *core.ScopeSelector, s conversion.Scope) error { + return autoConvert_v1_ScopeSelector_To_core_ScopeSelector(in, out, s) +} + +func autoConvert_core_ScopeSelector_To_v1_ScopeSelector(in *core.ScopeSelector, out *v1.ScopeSelector, s conversion.Scope) error { + out.MatchExpressions = *(*[]v1.ScopedResourceSelectorRequirement)(unsafe.Pointer(&in.MatchExpressions)) + return nil +} + +// Convert_core_ScopeSelector_To_v1_ScopeSelector is an autogenerated conversion function. +func Convert_core_ScopeSelector_To_v1_ScopeSelector(in *core.ScopeSelector, out *v1.ScopeSelector, s conversion.Scope) error { + return autoConvert_core_ScopeSelector_To_v1_ScopeSelector(in, out, s) +} + +func autoConvert_v1_ScopedResourceSelectorRequirement_To_core_ScopedResourceSelectorRequirement(in *v1.ScopedResourceSelectorRequirement, out *core.ScopedResourceSelectorRequirement, s conversion.Scope) error { + out.ScopeName = core.ResourceQuotaScope(in.ScopeName) + out.Operator = core.ScopeSelectorOperator(in.Operator) + out.Values = *(*[]string)(unsafe.Pointer(&in.Values)) + return nil +} + +// Convert_v1_ScopedResourceSelectorRequirement_To_core_ScopedResourceSelectorRequirement is an autogenerated conversion function. +func Convert_v1_ScopedResourceSelectorRequirement_To_core_ScopedResourceSelectorRequirement(in *v1.ScopedResourceSelectorRequirement, out *core.ScopedResourceSelectorRequirement, s conversion.Scope) error { + return autoConvert_v1_ScopedResourceSelectorRequirement_To_core_ScopedResourceSelectorRequirement(in, out, s) +} + +func autoConvert_core_ScopedResourceSelectorRequirement_To_v1_ScopedResourceSelectorRequirement(in *core.ScopedResourceSelectorRequirement, out *v1.ScopedResourceSelectorRequirement, s conversion.Scope) error { + out.ScopeName = v1.ResourceQuotaScope(in.ScopeName) + out.Operator = v1.ScopeSelectorOperator(in.Operator) + out.Values = *(*[]string)(unsafe.Pointer(&in.Values)) + return nil +} + +// Convert_core_ScopedResourceSelectorRequirement_To_v1_ScopedResourceSelectorRequirement is an autogenerated conversion function. +func Convert_core_ScopedResourceSelectorRequirement_To_v1_ScopedResourceSelectorRequirement(in *core.ScopedResourceSelectorRequirement, out *v1.ScopedResourceSelectorRequirement, s conversion.Scope) error { + return autoConvert_core_ScopedResourceSelectorRequirement_To_v1_ScopedResourceSelectorRequirement(in, out, s) +} + +func autoConvert_v1_SeccompProfile_To_core_SeccompProfile(in *v1.SeccompProfile, out *core.SeccompProfile, s conversion.Scope) error { + out.Type = core.SeccompProfileType(in.Type) + out.LocalhostProfile = (*string)(unsafe.Pointer(in.LocalhostProfile)) + return nil +} + +// Convert_v1_SeccompProfile_To_core_SeccompProfile is an autogenerated conversion function. +func Convert_v1_SeccompProfile_To_core_SeccompProfile(in *v1.SeccompProfile, out *core.SeccompProfile, s conversion.Scope) error { + return autoConvert_v1_SeccompProfile_To_core_SeccompProfile(in, out, s) +} + +func autoConvert_core_SeccompProfile_To_v1_SeccompProfile(in *core.SeccompProfile, out *v1.SeccompProfile, s conversion.Scope) error { + out.Type = v1.SeccompProfileType(in.Type) + out.LocalhostProfile = (*string)(unsafe.Pointer(in.LocalhostProfile)) + return nil +} + +// Convert_core_SeccompProfile_To_v1_SeccompProfile is an autogenerated conversion function. +func Convert_core_SeccompProfile_To_v1_SeccompProfile(in *core.SeccompProfile, out *v1.SeccompProfile, s conversion.Scope) error { + return autoConvert_core_SeccompProfile_To_v1_SeccompProfile(in, out, s) +} + +func autoConvert_v1_Secret_To_core_Secret(in *v1.Secret, out *core.Secret, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + out.Immutable = (*bool)(unsafe.Pointer(in.Immutable)) + out.Data = *(*map[string][]byte)(unsafe.Pointer(&in.Data)) + // INFO: in.StringData opted out of conversion generation + out.Type = core.SecretType(in.Type) + return nil +} + +func autoConvert_core_Secret_To_v1_Secret(in *core.Secret, out *v1.Secret, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + out.Immutable = (*bool)(unsafe.Pointer(in.Immutable)) + out.Data = *(*map[string][]byte)(unsafe.Pointer(&in.Data)) + out.Type = v1.SecretType(in.Type) + return nil +} + +// Convert_core_Secret_To_v1_Secret is an autogenerated conversion function. +func Convert_core_Secret_To_v1_Secret(in *core.Secret, out *v1.Secret, s conversion.Scope) error { + return autoConvert_core_Secret_To_v1_Secret(in, out, s) +} + +func autoConvert_v1_SecretEnvSource_To_core_SecretEnvSource(in *v1.SecretEnvSource, out *core.SecretEnvSource, s conversion.Scope) error { + if err := Convert_v1_LocalObjectReference_To_core_LocalObjectReference(&in.LocalObjectReference, &out.LocalObjectReference, s); err != nil { + return err + } + out.Optional = (*bool)(unsafe.Pointer(in.Optional)) + return nil +} + +// Convert_v1_SecretEnvSource_To_core_SecretEnvSource is an autogenerated conversion function. +func Convert_v1_SecretEnvSource_To_core_SecretEnvSource(in *v1.SecretEnvSource, out *core.SecretEnvSource, s conversion.Scope) error { + return autoConvert_v1_SecretEnvSource_To_core_SecretEnvSource(in, out, s) +} + +func autoConvert_core_SecretEnvSource_To_v1_SecretEnvSource(in *core.SecretEnvSource, out *v1.SecretEnvSource, s conversion.Scope) error { + if err := Convert_core_LocalObjectReference_To_v1_LocalObjectReference(&in.LocalObjectReference, &out.LocalObjectReference, s); err != nil { + return err + } + out.Optional = (*bool)(unsafe.Pointer(in.Optional)) + return nil +} + +// Convert_core_SecretEnvSource_To_v1_SecretEnvSource is an autogenerated conversion function. +func Convert_core_SecretEnvSource_To_v1_SecretEnvSource(in *core.SecretEnvSource, out *v1.SecretEnvSource, s conversion.Scope) error { + return autoConvert_core_SecretEnvSource_To_v1_SecretEnvSource(in, out, s) +} + +func autoConvert_v1_SecretKeySelector_To_core_SecretKeySelector(in *v1.SecretKeySelector, out *core.SecretKeySelector, s conversion.Scope) error { + if err := Convert_v1_LocalObjectReference_To_core_LocalObjectReference(&in.LocalObjectReference, &out.LocalObjectReference, s); err != nil { + return err + } + out.Key = in.Key + out.Optional = (*bool)(unsafe.Pointer(in.Optional)) + return nil +} + +// Convert_v1_SecretKeySelector_To_core_SecretKeySelector is an autogenerated conversion function. +func Convert_v1_SecretKeySelector_To_core_SecretKeySelector(in *v1.SecretKeySelector, out *core.SecretKeySelector, s conversion.Scope) error { + return autoConvert_v1_SecretKeySelector_To_core_SecretKeySelector(in, out, s) +} + +func autoConvert_core_SecretKeySelector_To_v1_SecretKeySelector(in *core.SecretKeySelector, out *v1.SecretKeySelector, s conversion.Scope) error { + if err := Convert_core_LocalObjectReference_To_v1_LocalObjectReference(&in.LocalObjectReference, &out.LocalObjectReference, s); err != nil { + return err + } + out.Key = in.Key + out.Optional = (*bool)(unsafe.Pointer(in.Optional)) + return nil +} + +// Convert_core_SecretKeySelector_To_v1_SecretKeySelector is an autogenerated conversion function. +func Convert_core_SecretKeySelector_To_v1_SecretKeySelector(in *core.SecretKeySelector, out *v1.SecretKeySelector, s conversion.Scope) error { + return autoConvert_core_SecretKeySelector_To_v1_SecretKeySelector(in, out, s) +} + +func autoConvert_v1_SecretList_To_core_SecretList(in *v1.SecretList, out *core.SecretList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]core.Secret, len(*in)) + for i := range *in { + if err := Convert_v1_Secret_To_core_Secret(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +// Convert_v1_SecretList_To_core_SecretList is an autogenerated conversion function. +func Convert_v1_SecretList_To_core_SecretList(in *v1.SecretList, out *core.SecretList, s conversion.Scope) error { + return autoConvert_v1_SecretList_To_core_SecretList(in, out, s) +} + +func autoConvert_core_SecretList_To_v1_SecretList(in *core.SecretList, out *v1.SecretList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]v1.Secret, len(*in)) + for i := range *in { + if err := Convert_core_Secret_To_v1_Secret(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +// Convert_core_SecretList_To_v1_SecretList is an autogenerated conversion function. +func Convert_core_SecretList_To_v1_SecretList(in *core.SecretList, out *v1.SecretList, s conversion.Scope) error { + return autoConvert_core_SecretList_To_v1_SecretList(in, out, s) +} + +func autoConvert_v1_SecretProjection_To_core_SecretProjection(in *v1.SecretProjection, out *core.SecretProjection, s conversion.Scope) error { + if err := Convert_v1_LocalObjectReference_To_core_LocalObjectReference(&in.LocalObjectReference, &out.LocalObjectReference, s); err != nil { + return err + } + out.Items = *(*[]core.KeyToPath)(unsafe.Pointer(&in.Items)) + out.Optional = (*bool)(unsafe.Pointer(in.Optional)) + return nil +} + +// Convert_v1_SecretProjection_To_core_SecretProjection is an autogenerated conversion function. +func Convert_v1_SecretProjection_To_core_SecretProjection(in *v1.SecretProjection, out *core.SecretProjection, s conversion.Scope) error { + return autoConvert_v1_SecretProjection_To_core_SecretProjection(in, out, s) +} + +func autoConvert_core_SecretProjection_To_v1_SecretProjection(in *core.SecretProjection, out *v1.SecretProjection, s conversion.Scope) error { + if err := Convert_core_LocalObjectReference_To_v1_LocalObjectReference(&in.LocalObjectReference, &out.LocalObjectReference, s); err != nil { + return err + } + out.Items = *(*[]v1.KeyToPath)(unsafe.Pointer(&in.Items)) + out.Optional = (*bool)(unsafe.Pointer(in.Optional)) + return nil +} + +// Convert_core_SecretProjection_To_v1_SecretProjection is an autogenerated conversion function. +func Convert_core_SecretProjection_To_v1_SecretProjection(in *core.SecretProjection, out *v1.SecretProjection, s conversion.Scope) error { + return autoConvert_core_SecretProjection_To_v1_SecretProjection(in, out, s) +} + +func autoConvert_v1_SecretReference_To_core_SecretReference(in *v1.SecretReference, out *core.SecretReference, s conversion.Scope) error { + out.Name = in.Name + out.Namespace = in.Namespace + return nil +} + +// Convert_v1_SecretReference_To_core_SecretReference is an autogenerated conversion function. +func Convert_v1_SecretReference_To_core_SecretReference(in *v1.SecretReference, out *core.SecretReference, s conversion.Scope) error { + return autoConvert_v1_SecretReference_To_core_SecretReference(in, out, s) +} + +func autoConvert_core_SecretReference_To_v1_SecretReference(in *core.SecretReference, out *v1.SecretReference, s conversion.Scope) error { + out.Name = in.Name + out.Namespace = in.Namespace + return nil +} + +// Convert_core_SecretReference_To_v1_SecretReference is an autogenerated conversion function. +func Convert_core_SecretReference_To_v1_SecretReference(in *core.SecretReference, out *v1.SecretReference, s conversion.Scope) error { + return autoConvert_core_SecretReference_To_v1_SecretReference(in, out, s) +} + +func autoConvert_v1_SecretVolumeSource_To_core_SecretVolumeSource(in *v1.SecretVolumeSource, out *core.SecretVolumeSource, s conversion.Scope) error { + out.SecretName = in.SecretName + out.Items = *(*[]core.KeyToPath)(unsafe.Pointer(&in.Items)) + out.DefaultMode = (*int32)(unsafe.Pointer(in.DefaultMode)) + out.Optional = (*bool)(unsafe.Pointer(in.Optional)) + return nil +} + +// Convert_v1_SecretVolumeSource_To_core_SecretVolumeSource is an autogenerated conversion function. +func Convert_v1_SecretVolumeSource_To_core_SecretVolumeSource(in *v1.SecretVolumeSource, out *core.SecretVolumeSource, s conversion.Scope) error { + return autoConvert_v1_SecretVolumeSource_To_core_SecretVolumeSource(in, out, s) +} + +func autoConvert_core_SecretVolumeSource_To_v1_SecretVolumeSource(in *core.SecretVolumeSource, out *v1.SecretVolumeSource, s conversion.Scope) error { + out.SecretName = in.SecretName + out.Items = *(*[]v1.KeyToPath)(unsafe.Pointer(&in.Items)) + out.DefaultMode = (*int32)(unsafe.Pointer(in.DefaultMode)) + out.Optional = (*bool)(unsafe.Pointer(in.Optional)) + return nil +} + +// Convert_core_SecretVolumeSource_To_v1_SecretVolumeSource is an autogenerated conversion function. +func Convert_core_SecretVolumeSource_To_v1_SecretVolumeSource(in *core.SecretVolumeSource, out *v1.SecretVolumeSource, s conversion.Scope) error { + return autoConvert_core_SecretVolumeSource_To_v1_SecretVolumeSource(in, out, s) +} + +func autoConvert_v1_SecurityContext_To_core_SecurityContext(in *v1.SecurityContext, out *core.SecurityContext, s conversion.Scope) error { + out.Capabilities = (*core.Capabilities)(unsafe.Pointer(in.Capabilities)) + out.Privileged = (*bool)(unsafe.Pointer(in.Privileged)) + out.SELinuxOptions = (*core.SELinuxOptions)(unsafe.Pointer(in.SELinuxOptions)) + out.WindowsOptions = (*core.WindowsSecurityContextOptions)(unsafe.Pointer(in.WindowsOptions)) + out.RunAsUser = (*int64)(unsafe.Pointer(in.RunAsUser)) + out.RunAsGroup = (*int64)(unsafe.Pointer(in.RunAsGroup)) + out.RunAsNonRoot = (*bool)(unsafe.Pointer(in.RunAsNonRoot)) + out.ReadOnlyRootFilesystem = (*bool)(unsafe.Pointer(in.ReadOnlyRootFilesystem)) + out.AllowPrivilegeEscalation = (*bool)(unsafe.Pointer(in.AllowPrivilegeEscalation)) + out.ProcMount = (*core.ProcMountType)(unsafe.Pointer(in.ProcMount)) + out.SeccompProfile = (*core.SeccompProfile)(unsafe.Pointer(in.SeccompProfile)) + return nil +} + +// Convert_v1_SecurityContext_To_core_SecurityContext is an autogenerated conversion function. +func Convert_v1_SecurityContext_To_core_SecurityContext(in *v1.SecurityContext, out *core.SecurityContext, s conversion.Scope) error { + return autoConvert_v1_SecurityContext_To_core_SecurityContext(in, out, s) +} + +func autoConvert_core_SecurityContext_To_v1_SecurityContext(in *core.SecurityContext, out *v1.SecurityContext, s conversion.Scope) error { + out.Capabilities = (*v1.Capabilities)(unsafe.Pointer(in.Capabilities)) + out.Privileged = (*bool)(unsafe.Pointer(in.Privileged)) + out.SELinuxOptions = (*v1.SELinuxOptions)(unsafe.Pointer(in.SELinuxOptions)) + out.WindowsOptions = (*v1.WindowsSecurityContextOptions)(unsafe.Pointer(in.WindowsOptions)) + out.RunAsUser = (*int64)(unsafe.Pointer(in.RunAsUser)) + out.RunAsGroup = (*int64)(unsafe.Pointer(in.RunAsGroup)) + out.RunAsNonRoot = (*bool)(unsafe.Pointer(in.RunAsNonRoot)) + out.ReadOnlyRootFilesystem = (*bool)(unsafe.Pointer(in.ReadOnlyRootFilesystem)) + out.AllowPrivilegeEscalation = (*bool)(unsafe.Pointer(in.AllowPrivilegeEscalation)) + out.ProcMount = (*v1.ProcMountType)(unsafe.Pointer(in.ProcMount)) + out.SeccompProfile = (*v1.SeccompProfile)(unsafe.Pointer(in.SeccompProfile)) + return nil +} + +// Convert_core_SecurityContext_To_v1_SecurityContext is an autogenerated conversion function. +func Convert_core_SecurityContext_To_v1_SecurityContext(in *core.SecurityContext, out *v1.SecurityContext, s conversion.Scope) error { + return autoConvert_core_SecurityContext_To_v1_SecurityContext(in, out, s) +} + +func autoConvert_v1_SerializedReference_To_core_SerializedReference(in *v1.SerializedReference, out *core.SerializedReference, s conversion.Scope) error { + if err := Convert_v1_ObjectReference_To_core_ObjectReference(&in.Reference, &out.Reference, s); err != nil { + return err + } + return nil +} + +// Convert_v1_SerializedReference_To_core_SerializedReference is an autogenerated conversion function. +func Convert_v1_SerializedReference_To_core_SerializedReference(in *v1.SerializedReference, out *core.SerializedReference, s conversion.Scope) error { + return autoConvert_v1_SerializedReference_To_core_SerializedReference(in, out, s) +} + +func autoConvert_core_SerializedReference_To_v1_SerializedReference(in *core.SerializedReference, out *v1.SerializedReference, s conversion.Scope) error { + if err := Convert_core_ObjectReference_To_v1_ObjectReference(&in.Reference, &out.Reference, s); err != nil { + return err + } + return nil +} + +// Convert_core_SerializedReference_To_v1_SerializedReference is an autogenerated conversion function. +func Convert_core_SerializedReference_To_v1_SerializedReference(in *core.SerializedReference, out *v1.SerializedReference, s conversion.Scope) error { + return autoConvert_core_SerializedReference_To_v1_SerializedReference(in, out, s) +} + +func autoConvert_v1_Service_To_core_Service(in *v1.Service, out *core.Service, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_ServiceSpec_To_core_ServiceSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_v1_ServiceStatus_To_core_ServiceStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1_Service_To_core_Service is an autogenerated conversion function. +func Convert_v1_Service_To_core_Service(in *v1.Service, out *core.Service, s conversion.Scope) error { + return autoConvert_v1_Service_To_core_Service(in, out, s) +} + +func autoConvert_core_Service_To_v1_Service(in *core.Service, out *v1.Service, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_core_ServiceSpec_To_v1_ServiceSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_core_ServiceStatus_To_v1_ServiceStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_core_Service_To_v1_Service is an autogenerated conversion function. +func Convert_core_Service_To_v1_Service(in *core.Service, out *v1.Service, s conversion.Scope) error { + return autoConvert_core_Service_To_v1_Service(in, out, s) +} + +func autoConvert_v1_ServiceAccount_To_core_ServiceAccount(in *v1.ServiceAccount, out *core.ServiceAccount, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + out.Secrets = *(*[]core.ObjectReference)(unsafe.Pointer(&in.Secrets)) + out.ImagePullSecrets = *(*[]core.LocalObjectReference)(unsafe.Pointer(&in.ImagePullSecrets)) + out.AutomountServiceAccountToken = (*bool)(unsafe.Pointer(in.AutomountServiceAccountToken)) + return nil +} + +// Convert_v1_ServiceAccount_To_core_ServiceAccount is an autogenerated conversion function. +func Convert_v1_ServiceAccount_To_core_ServiceAccount(in *v1.ServiceAccount, out *core.ServiceAccount, s conversion.Scope) error { + return autoConvert_v1_ServiceAccount_To_core_ServiceAccount(in, out, s) +} + +func autoConvert_core_ServiceAccount_To_v1_ServiceAccount(in *core.ServiceAccount, out *v1.ServiceAccount, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + out.Secrets = *(*[]v1.ObjectReference)(unsafe.Pointer(&in.Secrets)) + out.ImagePullSecrets = *(*[]v1.LocalObjectReference)(unsafe.Pointer(&in.ImagePullSecrets)) + out.AutomountServiceAccountToken = (*bool)(unsafe.Pointer(in.AutomountServiceAccountToken)) + return nil +} + +// Convert_core_ServiceAccount_To_v1_ServiceAccount is an autogenerated conversion function. +func Convert_core_ServiceAccount_To_v1_ServiceAccount(in *core.ServiceAccount, out *v1.ServiceAccount, s conversion.Scope) error { + return autoConvert_core_ServiceAccount_To_v1_ServiceAccount(in, out, s) +} + +func autoConvert_v1_ServiceAccountList_To_core_ServiceAccountList(in *v1.ServiceAccountList, out *core.ServiceAccountList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]core.ServiceAccount)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1_ServiceAccountList_To_core_ServiceAccountList is an autogenerated conversion function. +func Convert_v1_ServiceAccountList_To_core_ServiceAccountList(in *v1.ServiceAccountList, out *core.ServiceAccountList, s conversion.Scope) error { + return autoConvert_v1_ServiceAccountList_To_core_ServiceAccountList(in, out, s) +} + +func autoConvert_core_ServiceAccountList_To_v1_ServiceAccountList(in *core.ServiceAccountList, out *v1.ServiceAccountList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]v1.ServiceAccount)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_core_ServiceAccountList_To_v1_ServiceAccountList is an autogenerated conversion function. +func Convert_core_ServiceAccountList_To_v1_ServiceAccountList(in *core.ServiceAccountList, out *v1.ServiceAccountList, s conversion.Scope) error { + return autoConvert_core_ServiceAccountList_To_v1_ServiceAccountList(in, out, s) +} + +func autoConvert_v1_ServiceAccountTokenProjection_To_core_ServiceAccountTokenProjection(in *v1.ServiceAccountTokenProjection, out *core.ServiceAccountTokenProjection, s conversion.Scope) error { + out.Audience = in.Audience + if err := metav1.Convert_Pointer_int64_To_int64(&in.ExpirationSeconds, &out.ExpirationSeconds, s); err != nil { + return err + } + out.Path = in.Path + return nil +} + +// Convert_v1_ServiceAccountTokenProjection_To_core_ServiceAccountTokenProjection is an autogenerated conversion function. +func Convert_v1_ServiceAccountTokenProjection_To_core_ServiceAccountTokenProjection(in *v1.ServiceAccountTokenProjection, out *core.ServiceAccountTokenProjection, s conversion.Scope) error { + return autoConvert_v1_ServiceAccountTokenProjection_To_core_ServiceAccountTokenProjection(in, out, s) +} + +func autoConvert_core_ServiceAccountTokenProjection_To_v1_ServiceAccountTokenProjection(in *core.ServiceAccountTokenProjection, out *v1.ServiceAccountTokenProjection, s conversion.Scope) error { + out.Audience = in.Audience + if err := metav1.Convert_int64_To_Pointer_int64(&in.ExpirationSeconds, &out.ExpirationSeconds, s); err != nil { + return err + } + out.Path = in.Path + return nil +} + +// Convert_core_ServiceAccountTokenProjection_To_v1_ServiceAccountTokenProjection is an autogenerated conversion function. +func Convert_core_ServiceAccountTokenProjection_To_v1_ServiceAccountTokenProjection(in *core.ServiceAccountTokenProjection, out *v1.ServiceAccountTokenProjection, s conversion.Scope) error { + return autoConvert_core_ServiceAccountTokenProjection_To_v1_ServiceAccountTokenProjection(in, out, s) +} + +func autoConvert_v1_ServiceList_To_core_ServiceList(in *v1.ServiceList, out *core.ServiceList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]core.Service, len(*in)) + for i := range *in { + if err := Convert_v1_Service_To_core_Service(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +// Convert_v1_ServiceList_To_core_ServiceList is an autogenerated conversion function. +func Convert_v1_ServiceList_To_core_ServiceList(in *v1.ServiceList, out *core.ServiceList, s conversion.Scope) error { + return autoConvert_v1_ServiceList_To_core_ServiceList(in, out, s) +} + +func autoConvert_core_ServiceList_To_v1_ServiceList(in *core.ServiceList, out *v1.ServiceList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]v1.Service, len(*in)) + for i := range *in { + if err := Convert_core_Service_To_v1_Service(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +// Convert_core_ServiceList_To_v1_ServiceList is an autogenerated conversion function. +func Convert_core_ServiceList_To_v1_ServiceList(in *core.ServiceList, out *v1.ServiceList, s conversion.Scope) error { + return autoConvert_core_ServiceList_To_v1_ServiceList(in, out, s) +} + +func autoConvert_v1_ServicePort_To_core_ServicePort(in *v1.ServicePort, out *core.ServicePort, s conversion.Scope) error { + out.Name = in.Name + out.Protocol = core.Protocol(in.Protocol) + out.AppProtocol = (*string)(unsafe.Pointer(in.AppProtocol)) + out.Port = in.Port + out.TargetPort = in.TargetPort + out.NodePort = in.NodePort + return nil +} + +// Convert_v1_ServicePort_To_core_ServicePort is an autogenerated conversion function. +func Convert_v1_ServicePort_To_core_ServicePort(in *v1.ServicePort, out *core.ServicePort, s conversion.Scope) error { + return autoConvert_v1_ServicePort_To_core_ServicePort(in, out, s) +} + +func autoConvert_core_ServicePort_To_v1_ServicePort(in *core.ServicePort, out *v1.ServicePort, s conversion.Scope) error { + out.Name = in.Name + out.Protocol = v1.Protocol(in.Protocol) + out.AppProtocol = (*string)(unsafe.Pointer(in.AppProtocol)) + out.Port = in.Port + out.TargetPort = in.TargetPort + out.NodePort = in.NodePort + return nil +} + +// Convert_core_ServicePort_To_v1_ServicePort is an autogenerated conversion function. +func Convert_core_ServicePort_To_v1_ServicePort(in *core.ServicePort, out *v1.ServicePort, s conversion.Scope) error { + return autoConvert_core_ServicePort_To_v1_ServicePort(in, out, s) +} + +func autoConvert_v1_ServiceProxyOptions_To_core_ServiceProxyOptions(in *v1.ServiceProxyOptions, out *core.ServiceProxyOptions, s conversion.Scope) error { + out.Path = in.Path + return nil +} + +// Convert_v1_ServiceProxyOptions_To_core_ServiceProxyOptions is an autogenerated conversion function. +func Convert_v1_ServiceProxyOptions_To_core_ServiceProxyOptions(in *v1.ServiceProxyOptions, out *core.ServiceProxyOptions, s conversion.Scope) error { + return autoConvert_v1_ServiceProxyOptions_To_core_ServiceProxyOptions(in, out, s) +} + +func autoConvert_core_ServiceProxyOptions_To_v1_ServiceProxyOptions(in *core.ServiceProxyOptions, out *v1.ServiceProxyOptions, s conversion.Scope) error { + out.Path = in.Path + return nil +} + +// Convert_core_ServiceProxyOptions_To_v1_ServiceProxyOptions is an autogenerated conversion function. +func Convert_core_ServiceProxyOptions_To_v1_ServiceProxyOptions(in *core.ServiceProxyOptions, out *v1.ServiceProxyOptions, s conversion.Scope) error { + return autoConvert_core_ServiceProxyOptions_To_v1_ServiceProxyOptions(in, out, s) +} + +func autoConvert_url_Values_To_v1_ServiceProxyOptions(in *url.Values, out *v1.ServiceProxyOptions, s conversion.Scope) error { + // WARNING: Field TypeMeta does not have json tag, skipping. + + if values, ok := map[string][]string(*in)["path"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_string(&values, &out.Path, s); err != nil { + return err + } + } else { + out.Path = "" + } + return nil +} + +// Convert_url_Values_To_v1_ServiceProxyOptions is an autogenerated conversion function. +func Convert_url_Values_To_v1_ServiceProxyOptions(in *url.Values, out *v1.ServiceProxyOptions, s conversion.Scope) error { + return autoConvert_url_Values_To_v1_ServiceProxyOptions(in, out, s) +} + +func autoConvert_v1_ServiceSpec_To_core_ServiceSpec(in *v1.ServiceSpec, out *core.ServiceSpec, s conversion.Scope) error { + out.Ports = *(*[]core.ServicePort)(unsafe.Pointer(&in.Ports)) + out.Selector = *(*map[string]string)(unsafe.Pointer(&in.Selector)) + out.ClusterIP = in.ClusterIP + out.ClusterIPs = *(*[]string)(unsafe.Pointer(&in.ClusterIPs)) + out.Type = core.ServiceType(in.Type) + out.ExternalIPs = *(*[]string)(unsafe.Pointer(&in.ExternalIPs)) + out.SessionAffinity = core.ServiceAffinity(in.SessionAffinity) + out.LoadBalancerIP = in.LoadBalancerIP + out.LoadBalancerSourceRanges = *(*[]string)(unsafe.Pointer(&in.LoadBalancerSourceRanges)) + out.ExternalName = in.ExternalName + out.ExternalTrafficPolicy = core.ServiceExternalTrafficPolicyType(in.ExternalTrafficPolicy) + out.HealthCheckNodePort = in.HealthCheckNodePort + out.PublishNotReadyAddresses = in.PublishNotReadyAddresses + out.SessionAffinityConfig = (*core.SessionAffinityConfig)(unsafe.Pointer(in.SessionAffinityConfig)) + out.IPFamilies = *(*[]core.IPFamily)(unsafe.Pointer(&in.IPFamilies)) + out.IPFamilyPolicy = (*core.IPFamilyPolicy)(unsafe.Pointer(in.IPFamilyPolicy)) + out.AllocateLoadBalancerNodePorts = (*bool)(unsafe.Pointer(in.AllocateLoadBalancerNodePorts)) + out.LoadBalancerClass = (*string)(unsafe.Pointer(in.LoadBalancerClass)) + out.InternalTrafficPolicy = (*core.ServiceInternalTrafficPolicyType)(unsafe.Pointer(in.InternalTrafficPolicy)) + return nil +} + +// Convert_v1_ServiceSpec_To_core_ServiceSpec is an autogenerated conversion function. +func Convert_v1_ServiceSpec_To_core_ServiceSpec(in *v1.ServiceSpec, out *core.ServiceSpec, s conversion.Scope) error { + return autoConvert_v1_ServiceSpec_To_core_ServiceSpec(in, out, s) +} + +func autoConvert_core_ServiceSpec_To_v1_ServiceSpec(in *core.ServiceSpec, out *v1.ServiceSpec, s conversion.Scope) error { + out.Type = v1.ServiceType(in.Type) + out.Ports = *(*[]v1.ServicePort)(unsafe.Pointer(&in.Ports)) + out.Selector = *(*map[string]string)(unsafe.Pointer(&in.Selector)) + out.ClusterIP = in.ClusterIP + out.ClusterIPs = *(*[]string)(unsafe.Pointer(&in.ClusterIPs)) + out.IPFamilies = *(*[]v1.IPFamily)(unsafe.Pointer(&in.IPFamilies)) + out.IPFamilyPolicy = (*v1.IPFamilyPolicy)(unsafe.Pointer(in.IPFamilyPolicy)) + out.ExternalName = in.ExternalName + out.ExternalIPs = *(*[]string)(unsafe.Pointer(&in.ExternalIPs)) + out.LoadBalancerIP = in.LoadBalancerIP + out.SessionAffinity = v1.ServiceAffinity(in.SessionAffinity) + out.SessionAffinityConfig = (*v1.SessionAffinityConfig)(unsafe.Pointer(in.SessionAffinityConfig)) + out.LoadBalancerSourceRanges = *(*[]string)(unsafe.Pointer(&in.LoadBalancerSourceRanges)) + out.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyType(in.ExternalTrafficPolicy) + out.HealthCheckNodePort = in.HealthCheckNodePort + out.PublishNotReadyAddresses = in.PublishNotReadyAddresses + out.AllocateLoadBalancerNodePorts = (*bool)(unsafe.Pointer(in.AllocateLoadBalancerNodePorts)) + out.LoadBalancerClass = (*string)(unsafe.Pointer(in.LoadBalancerClass)) + out.InternalTrafficPolicy = (*v1.ServiceInternalTrafficPolicyType)(unsafe.Pointer(in.InternalTrafficPolicy)) + return nil +} + +// Convert_core_ServiceSpec_To_v1_ServiceSpec is an autogenerated conversion function. +func Convert_core_ServiceSpec_To_v1_ServiceSpec(in *core.ServiceSpec, out *v1.ServiceSpec, s conversion.Scope) error { + return autoConvert_core_ServiceSpec_To_v1_ServiceSpec(in, out, s) +} + +func autoConvert_v1_ServiceStatus_To_core_ServiceStatus(in *v1.ServiceStatus, out *core.ServiceStatus, s conversion.Scope) error { + if err := Convert_v1_LoadBalancerStatus_To_core_LoadBalancerStatus(&in.LoadBalancer, &out.LoadBalancer, s); err != nil { + return err + } + out.Conditions = *(*[]metav1.Condition)(unsafe.Pointer(&in.Conditions)) + return nil +} + +// Convert_v1_ServiceStatus_To_core_ServiceStatus is an autogenerated conversion function. +func Convert_v1_ServiceStatus_To_core_ServiceStatus(in *v1.ServiceStatus, out *core.ServiceStatus, s conversion.Scope) error { + return autoConvert_v1_ServiceStatus_To_core_ServiceStatus(in, out, s) +} + +func autoConvert_core_ServiceStatus_To_v1_ServiceStatus(in *core.ServiceStatus, out *v1.ServiceStatus, s conversion.Scope) error { + if err := Convert_core_LoadBalancerStatus_To_v1_LoadBalancerStatus(&in.LoadBalancer, &out.LoadBalancer, s); err != nil { + return err + } + out.Conditions = *(*[]metav1.Condition)(unsafe.Pointer(&in.Conditions)) + return nil +} + +// Convert_core_ServiceStatus_To_v1_ServiceStatus is an autogenerated conversion function. +func Convert_core_ServiceStatus_To_v1_ServiceStatus(in *core.ServiceStatus, out *v1.ServiceStatus, s conversion.Scope) error { + return autoConvert_core_ServiceStatus_To_v1_ServiceStatus(in, out, s) +} + +func autoConvert_v1_SessionAffinityConfig_To_core_SessionAffinityConfig(in *v1.SessionAffinityConfig, out *core.SessionAffinityConfig, s conversion.Scope) error { + out.ClientIP = (*core.ClientIPConfig)(unsafe.Pointer(in.ClientIP)) + return nil +} + +// Convert_v1_SessionAffinityConfig_To_core_SessionAffinityConfig is an autogenerated conversion function. +func Convert_v1_SessionAffinityConfig_To_core_SessionAffinityConfig(in *v1.SessionAffinityConfig, out *core.SessionAffinityConfig, s conversion.Scope) error { + return autoConvert_v1_SessionAffinityConfig_To_core_SessionAffinityConfig(in, out, s) +} + +func autoConvert_core_SessionAffinityConfig_To_v1_SessionAffinityConfig(in *core.SessionAffinityConfig, out *v1.SessionAffinityConfig, s conversion.Scope) error { + out.ClientIP = (*v1.ClientIPConfig)(unsafe.Pointer(in.ClientIP)) + return nil +} + +// Convert_core_SessionAffinityConfig_To_v1_SessionAffinityConfig is an autogenerated conversion function. +func Convert_core_SessionAffinityConfig_To_v1_SessionAffinityConfig(in *core.SessionAffinityConfig, out *v1.SessionAffinityConfig, s conversion.Scope) error { + return autoConvert_core_SessionAffinityConfig_To_v1_SessionAffinityConfig(in, out, s) +} + +func autoConvert_v1_StorageOSPersistentVolumeSource_To_core_StorageOSPersistentVolumeSource(in *v1.StorageOSPersistentVolumeSource, out *core.StorageOSPersistentVolumeSource, s conversion.Scope) error { + out.VolumeName = in.VolumeName + out.VolumeNamespace = in.VolumeNamespace + out.FSType = in.FSType + out.ReadOnly = in.ReadOnly + out.SecretRef = (*core.ObjectReference)(unsafe.Pointer(in.SecretRef)) + return nil +} + +// Convert_v1_StorageOSPersistentVolumeSource_To_core_StorageOSPersistentVolumeSource is an autogenerated conversion function. +func Convert_v1_StorageOSPersistentVolumeSource_To_core_StorageOSPersistentVolumeSource(in *v1.StorageOSPersistentVolumeSource, out *core.StorageOSPersistentVolumeSource, s conversion.Scope) error { + return autoConvert_v1_StorageOSPersistentVolumeSource_To_core_StorageOSPersistentVolumeSource(in, out, s) +} + +func autoConvert_core_StorageOSPersistentVolumeSource_To_v1_StorageOSPersistentVolumeSource(in *core.StorageOSPersistentVolumeSource, out *v1.StorageOSPersistentVolumeSource, s conversion.Scope) error { + out.VolumeName = in.VolumeName + out.VolumeNamespace = in.VolumeNamespace + out.FSType = in.FSType + out.ReadOnly = in.ReadOnly + out.SecretRef = (*v1.ObjectReference)(unsafe.Pointer(in.SecretRef)) + return nil +} + +// Convert_core_StorageOSPersistentVolumeSource_To_v1_StorageOSPersistentVolumeSource is an autogenerated conversion function. +func Convert_core_StorageOSPersistentVolumeSource_To_v1_StorageOSPersistentVolumeSource(in *core.StorageOSPersistentVolumeSource, out *v1.StorageOSPersistentVolumeSource, s conversion.Scope) error { + return autoConvert_core_StorageOSPersistentVolumeSource_To_v1_StorageOSPersistentVolumeSource(in, out, s) +} + +func autoConvert_v1_StorageOSVolumeSource_To_core_StorageOSVolumeSource(in *v1.StorageOSVolumeSource, out *core.StorageOSVolumeSource, s conversion.Scope) error { + out.VolumeName = in.VolumeName + out.VolumeNamespace = in.VolumeNamespace + out.FSType = in.FSType + out.ReadOnly = in.ReadOnly + out.SecretRef = (*core.LocalObjectReference)(unsafe.Pointer(in.SecretRef)) + return nil +} + +// Convert_v1_StorageOSVolumeSource_To_core_StorageOSVolumeSource is an autogenerated conversion function. +func Convert_v1_StorageOSVolumeSource_To_core_StorageOSVolumeSource(in *v1.StorageOSVolumeSource, out *core.StorageOSVolumeSource, s conversion.Scope) error { + return autoConvert_v1_StorageOSVolumeSource_To_core_StorageOSVolumeSource(in, out, s) +} + +func autoConvert_core_StorageOSVolumeSource_To_v1_StorageOSVolumeSource(in *core.StorageOSVolumeSource, out *v1.StorageOSVolumeSource, s conversion.Scope) error { + out.VolumeName = in.VolumeName + out.VolumeNamespace = in.VolumeNamespace + out.FSType = in.FSType + out.ReadOnly = in.ReadOnly + out.SecretRef = (*v1.LocalObjectReference)(unsafe.Pointer(in.SecretRef)) + return nil +} + +// Convert_core_StorageOSVolumeSource_To_v1_StorageOSVolumeSource is an autogenerated conversion function. +func Convert_core_StorageOSVolumeSource_To_v1_StorageOSVolumeSource(in *core.StorageOSVolumeSource, out *v1.StorageOSVolumeSource, s conversion.Scope) error { + return autoConvert_core_StorageOSVolumeSource_To_v1_StorageOSVolumeSource(in, out, s) +} + +func autoConvert_v1_Sysctl_To_core_Sysctl(in *v1.Sysctl, out *core.Sysctl, s conversion.Scope) error { + out.Name = in.Name + out.Value = in.Value + return nil +} + +// Convert_v1_Sysctl_To_core_Sysctl is an autogenerated conversion function. +func Convert_v1_Sysctl_To_core_Sysctl(in *v1.Sysctl, out *core.Sysctl, s conversion.Scope) error { + return autoConvert_v1_Sysctl_To_core_Sysctl(in, out, s) +} + +func autoConvert_core_Sysctl_To_v1_Sysctl(in *core.Sysctl, out *v1.Sysctl, s conversion.Scope) error { + out.Name = in.Name + out.Value = in.Value + return nil +} + +// Convert_core_Sysctl_To_v1_Sysctl is an autogenerated conversion function. +func Convert_core_Sysctl_To_v1_Sysctl(in *core.Sysctl, out *v1.Sysctl, s conversion.Scope) error { + return autoConvert_core_Sysctl_To_v1_Sysctl(in, out, s) +} + +func autoConvert_v1_TCPSocketAction_To_core_TCPSocketAction(in *v1.TCPSocketAction, out *core.TCPSocketAction, s conversion.Scope) error { + out.Port = in.Port + out.Host = in.Host + return nil +} + +// Convert_v1_TCPSocketAction_To_core_TCPSocketAction is an autogenerated conversion function. +func Convert_v1_TCPSocketAction_To_core_TCPSocketAction(in *v1.TCPSocketAction, out *core.TCPSocketAction, s conversion.Scope) error { + return autoConvert_v1_TCPSocketAction_To_core_TCPSocketAction(in, out, s) +} + +func autoConvert_core_TCPSocketAction_To_v1_TCPSocketAction(in *core.TCPSocketAction, out *v1.TCPSocketAction, s conversion.Scope) error { + out.Port = in.Port + out.Host = in.Host + return nil +} + +// Convert_core_TCPSocketAction_To_v1_TCPSocketAction is an autogenerated conversion function. +func Convert_core_TCPSocketAction_To_v1_TCPSocketAction(in *core.TCPSocketAction, out *v1.TCPSocketAction, s conversion.Scope) error { + return autoConvert_core_TCPSocketAction_To_v1_TCPSocketAction(in, out, s) +} + +func autoConvert_v1_Taint_To_core_Taint(in *v1.Taint, out *core.Taint, s conversion.Scope) error { + out.Key = in.Key + out.Value = in.Value + out.Effect = core.TaintEffect(in.Effect) + out.TimeAdded = (*metav1.Time)(unsafe.Pointer(in.TimeAdded)) + return nil +} + +// Convert_v1_Taint_To_core_Taint is an autogenerated conversion function. +func Convert_v1_Taint_To_core_Taint(in *v1.Taint, out *core.Taint, s conversion.Scope) error { + return autoConvert_v1_Taint_To_core_Taint(in, out, s) +} + +func autoConvert_core_Taint_To_v1_Taint(in *core.Taint, out *v1.Taint, s conversion.Scope) error { + out.Key = in.Key + out.Value = in.Value + out.Effect = v1.TaintEffect(in.Effect) + out.TimeAdded = (*metav1.Time)(unsafe.Pointer(in.TimeAdded)) + return nil +} + +// Convert_core_Taint_To_v1_Taint is an autogenerated conversion function. +func Convert_core_Taint_To_v1_Taint(in *core.Taint, out *v1.Taint, s conversion.Scope) error { + return autoConvert_core_Taint_To_v1_Taint(in, out, s) +} + +func autoConvert_v1_Toleration_To_core_Toleration(in *v1.Toleration, out *core.Toleration, s conversion.Scope) error { + out.Key = in.Key + out.Operator = core.TolerationOperator(in.Operator) + out.Value = in.Value + out.Effect = core.TaintEffect(in.Effect) + out.TolerationSeconds = (*int64)(unsafe.Pointer(in.TolerationSeconds)) + return nil +} + +// Convert_v1_Toleration_To_core_Toleration is an autogenerated conversion function. +func Convert_v1_Toleration_To_core_Toleration(in *v1.Toleration, out *core.Toleration, s conversion.Scope) error { + return autoConvert_v1_Toleration_To_core_Toleration(in, out, s) +} + +func autoConvert_core_Toleration_To_v1_Toleration(in *core.Toleration, out *v1.Toleration, s conversion.Scope) error { + out.Key = in.Key + out.Operator = v1.TolerationOperator(in.Operator) + out.Value = in.Value + out.Effect = v1.TaintEffect(in.Effect) + out.TolerationSeconds = (*int64)(unsafe.Pointer(in.TolerationSeconds)) + return nil +} + +// Convert_core_Toleration_To_v1_Toleration is an autogenerated conversion function. +func Convert_core_Toleration_To_v1_Toleration(in *core.Toleration, out *v1.Toleration, s conversion.Scope) error { + return autoConvert_core_Toleration_To_v1_Toleration(in, out, s) +} + +func autoConvert_v1_TopologySelectorLabelRequirement_To_core_TopologySelectorLabelRequirement(in *v1.TopologySelectorLabelRequirement, out *core.TopologySelectorLabelRequirement, s conversion.Scope) error { + out.Key = in.Key + out.Values = *(*[]string)(unsafe.Pointer(&in.Values)) + return nil +} + +// Convert_v1_TopologySelectorLabelRequirement_To_core_TopologySelectorLabelRequirement is an autogenerated conversion function. +func Convert_v1_TopologySelectorLabelRequirement_To_core_TopologySelectorLabelRequirement(in *v1.TopologySelectorLabelRequirement, out *core.TopologySelectorLabelRequirement, s conversion.Scope) error { + return autoConvert_v1_TopologySelectorLabelRequirement_To_core_TopologySelectorLabelRequirement(in, out, s) +} + +func autoConvert_core_TopologySelectorLabelRequirement_To_v1_TopologySelectorLabelRequirement(in *core.TopologySelectorLabelRequirement, out *v1.TopologySelectorLabelRequirement, s conversion.Scope) error { + out.Key = in.Key + out.Values = *(*[]string)(unsafe.Pointer(&in.Values)) + return nil +} + +// Convert_core_TopologySelectorLabelRequirement_To_v1_TopologySelectorLabelRequirement is an autogenerated conversion function. +func Convert_core_TopologySelectorLabelRequirement_To_v1_TopologySelectorLabelRequirement(in *core.TopologySelectorLabelRequirement, out *v1.TopologySelectorLabelRequirement, s conversion.Scope) error { + return autoConvert_core_TopologySelectorLabelRequirement_To_v1_TopologySelectorLabelRequirement(in, out, s) +} + +func autoConvert_v1_TopologySelectorTerm_To_core_TopologySelectorTerm(in *v1.TopologySelectorTerm, out *core.TopologySelectorTerm, s conversion.Scope) error { + out.MatchLabelExpressions = *(*[]core.TopologySelectorLabelRequirement)(unsafe.Pointer(&in.MatchLabelExpressions)) + return nil +} + +// Convert_v1_TopologySelectorTerm_To_core_TopologySelectorTerm is an autogenerated conversion function. +func Convert_v1_TopologySelectorTerm_To_core_TopologySelectorTerm(in *v1.TopologySelectorTerm, out *core.TopologySelectorTerm, s conversion.Scope) error { + return autoConvert_v1_TopologySelectorTerm_To_core_TopologySelectorTerm(in, out, s) +} + +func autoConvert_core_TopologySelectorTerm_To_v1_TopologySelectorTerm(in *core.TopologySelectorTerm, out *v1.TopologySelectorTerm, s conversion.Scope) error { + out.MatchLabelExpressions = *(*[]v1.TopologySelectorLabelRequirement)(unsafe.Pointer(&in.MatchLabelExpressions)) + return nil +} + +// Convert_core_TopologySelectorTerm_To_v1_TopologySelectorTerm is an autogenerated conversion function. +func Convert_core_TopologySelectorTerm_To_v1_TopologySelectorTerm(in *core.TopologySelectorTerm, out *v1.TopologySelectorTerm, s conversion.Scope) error { + return autoConvert_core_TopologySelectorTerm_To_v1_TopologySelectorTerm(in, out, s) +} + +func autoConvert_v1_TopologySpreadConstraint_To_core_TopologySpreadConstraint(in *v1.TopologySpreadConstraint, out *core.TopologySpreadConstraint, s conversion.Scope) error { + out.MaxSkew = in.MaxSkew + out.TopologyKey = in.TopologyKey + out.WhenUnsatisfiable = core.UnsatisfiableConstraintAction(in.WhenUnsatisfiable) + out.LabelSelector = (*metav1.LabelSelector)(unsafe.Pointer(in.LabelSelector)) + out.MinDomains = (*int32)(unsafe.Pointer(in.MinDomains)) + out.NodeAffinityPolicy = (*core.NodeInclusionPolicy)(unsafe.Pointer(in.NodeAffinityPolicy)) + out.NodeTaintsPolicy = (*core.NodeInclusionPolicy)(unsafe.Pointer(in.NodeTaintsPolicy)) + out.MatchLabelKeys = *(*[]string)(unsafe.Pointer(&in.MatchLabelKeys)) + return nil +} + +// Convert_v1_TopologySpreadConstraint_To_core_TopologySpreadConstraint is an autogenerated conversion function. +func Convert_v1_TopologySpreadConstraint_To_core_TopologySpreadConstraint(in *v1.TopologySpreadConstraint, out *core.TopologySpreadConstraint, s conversion.Scope) error { + return autoConvert_v1_TopologySpreadConstraint_To_core_TopologySpreadConstraint(in, out, s) +} + +func autoConvert_core_TopologySpreadConstraint_To_v1_TopologySpreadConstraint(in *core.TopologySpreadConstraint, out *v1.TopologySpreadConstraint, s conversion.Scope) error { + out.MaxSkew = in.MaxSkew + out.TopologyKey = in.TopologyKey + out.WhenUnsatisfiable = v1.UnsatisfiableConstraintAction(in.WhenUnsatisfiable) + out.LabelSelector = (*metav1.LabelSelector)(unsafe.Pointer(in.LabelSelector)) + out.MinDomains = (*int32)(unsafe.Pointer(in.MinDomains)) + out.NodeAffinityPolicy = (*v1.NodeInclusionPolicy)(unsafe.Pointer(in.NodeAffinityPolicy)) + out.NodeTaintsPolicy = (*v1.NodeInclusionPolicy)(unsafe.Pointer(in.NodeTaintsPolicy)) + out.MatchLabelKeys = *(*[]string)(unsafe.Pointer(&in.MatchLabelKeys)) + return nil +} + +// Convert_core_TopologySpreadConstraint_To_v1_TopologySpreadConstraint is an autogenerated conversion function. +func Convert_core_TopologySpreadConstraint_To_v1_TopologySpreadConstraint(in *core.TopologySpreadConstraint, out *v1.TopologySpreadConstraint, s conversion.Scope) error { + return autoConvert_core_TopologySpreadConstraint_To_v1_TopologySpreadConstraint(in, out, s) +} + +func autoConvert_v1_TypedLocalObjectReference_To_core_TypedLocalObjectReference(in *v1.TypedLocalObjectReference, out *core.TypedLocalObjectReference, s conversion.Scope) error { + out.APIGroup = (*string)(unsafe.Pointer(in.APIGroup)) + out.Kind = in.Kind + out.Name = in.Name + return nil +} + +// Convert_v1_TypedLocalObjectReference_To_core_TypedLocalObjectReference is an autogenerated conversion function. +func Convert_v1_TypedLocalObjectReference_To_core_TypedLocalObjectReference(in *v1.TypedLocalObjectReference, out *core.TypedLocalObjectReference, s conversion.Scope) error { + return autoConvert_v1_TypedLocalObjectReference_To_core_TypedLocalObjectReference(in, out, s) +} + +func autoConvert_core_TypedLocalObjectReference_To_v1_TypedLocalObjectReference(in *core.TypedLocalObjectReference, out *v1.TypedLocalObjectReference, s conversion.Scope) error { + out.APIGroup = (*string)(unsafe.Pointer(in.APIGroup)) + out.Kind = in.Kind + out.Name = in.Name + return nil +} + +// Convert_core_TypedLocalObjectReference_To_v1_TypedLocalObjectReference is an autogenerated conversion function. +func Convert_core_TypedLocalObjectReference_To_v1_TypedLocalObjectReference(in *core.TypedLocalObjectReference, out *v1.TypedLocalObjectReference, s conversion.Scope) error { + return autoConvert_core_TypedLocalObjectReference_To_v1_TypedLocalObjectReference(in, out, s) +} + +func autoConvert_v1_TypedObjectReference_To_core_TypedObjectReference(in *v1.TypedObjectReference, out *core.TypedObjectReference, s conversion.Scope) error { + out.APIGroup = (*string)(unsafe.Pointer(in.APIGroup)) + out.Kind = in.Kind + out.Name = in.Name + out.Namespace = (*string)(unsafe.Pointer(in.Namespace)) + return nil +} + +// Convert_v1_TypedObjectReference_To_core_TypedObjectReference is an autogenerated conversion function. +func Convert_v1_TypedObjectReference_To_core_TypedObjectReference(in *v1.TypedObjectReference, out *core.TypedObjectReference, s conversion.Scope) error { + return autoConvert_v1_TypedObjectReference_To_core_TypedObjectReference(in, out, s) +} + +func autoConvert_core_TypedObjectReference_To_v1_TypedObjectReference(in *core.TypedObjectReference, out *v1.TypedObjectReference, s conversion.Scope) error { + out.APIGroup = (*string)(unsafe.Pointer(in.APIGroup)) + out.Kind = in.Kind + out.Name = in.Name + out.Namespace = (*string)(unsafe.Pointer(in.Namespace)) + return nil +} + +// Convert_core_TypedObjectReference_To_v1_TypedObjectReference is an autogenerated conversion function. +func Convert_core_TypedObjectReference_To_v1_TypedObjectReference(in *core.TypedObjectReference, out *v1.TypedObjectReference, s conversion.Scope) error { + return autoConvert_core_TypedObjectReference_To_v1_TypedObjectReference(in, out, s) +} + +func autoConvert_v1_Volume_To_core_Volume(in *v1.Volume, out *core.Volume, s conversion.Scope) error { + out.Name = in.Name + if err := Convert_v1_VolumeSource_To_core_VolumeSource(&in.VolumeSource, &out.VolumeSource, s); err != nil { + return err + } + return nil +} + +func autoConvert_core_Volume_To_v1_Volume(in *core.Volume, out *v1.Volume, s conversion.Scope) error { + out.Name = in.Name + if err := Convert_core_VolumeSource_To_v1_VolumeSource(&in.VolumeSource, &out.VolumeSource, s); err != nil { + return err + } + return nil +} + +func autoConvert_v1_VolumeDevice_To_core_VolumeDevice(in *v1.VolumeDevice, out *core.VolumeDevice, s conversion.Scope) error { + out.Name = in.Name + out.DevicePath = in.DevicePath + return nil +} + +// Convert_v1_VolumeDevice_To_core_VolumeDevice is an autogenerated conversion function. +func Convert_v1_VolumeDevice_To_core_VolumeDevice(in *v1.VolumeDevice, out *core.VolumeDevice, s conversion.Scope) error { + return autoConvert_v1_VolumeDevice_To_core_VolumeDevice(in, out, s) +} + +func autoConvert_core_VolumeDevice_To_v1_VolumeDevice(in *core.VolumeDevice, out *v1.VolumeDevice, s conversion.Scope) error { + out.Name = in.Name + out.DevicePath = in.DevicePath + return nil +} + +// Convert_core_VolumeDevice_To_v1_VolumeDevice is an autogenerated conversion function. +func Convert_core_VolumeDevice_To_v1_VolumeDevice(in *core.VolumeDevice, out *v1.VolumeDevice, s conversion.Scope) error { + return autoConvert_core_VolumeDevice_To_v1_VolumeDevice(in, out, s) +} + +func autoConvert_v1_VolumeMount_To_core_VolumeMount(in *v1.VolumeMount, out *core.VolumeMount, s conversion.Scope) error { + out.Name = in.Name + out.ReadOnly = in.ReadOnly + out.MountPath = in.MountPath + out.SubPath = in.SubPath + out.MountPropagation = (*core.MountPropagationMode)(unsafe.Pointer(in.MountPropagation)) + out.SubPathExpr = in.SubPathExpr + return nil +} + +// Convert_v1_VolumeMount_To_core_VolumeMount is an autogenerated conversion function. +func Convert_v1_VolumeMount_To_core_VolumeMount(in *v1.VolumeMount, out *core.VolumeMount, s conversion.Scope) error { + return autoConvert_v1_VolumeMount_To_core_VolumeMount(in, out, s) +} + +func autoConvert_core_VolumeMount_To_v1_VolumeMount(in *core.VolumeMount, out *v1.VolumeMount, s conversion.Scope) error { + out.Name = in.Name + out.ReadOnly = in.ReadOnly + out.MountPath = in.MountPath + out.SubPath = in.SubPath + out.MountPropagation = (*v1.MountPropagationMode)(unsafe.Pointer(in.MountPropagation)) + out.SubPathExpr = in.SubPathExpr + return nil +} + +// Convert_core_VolumeMount_To_v1_VolumeMount is an autogenerated conversion function. +func Convert_core_VolumeMount_To_v1_VolumeMount(in *core.VolumeMount, out *v1.VolumeMount, s conversion.Scope) error { + return autoConvert_core_VolumeMount_To_v1_VolumeMount(in, out, s) +} + +func autoConvert_v1_VolumeNodeAffinity_To_core_VolumeNodeAffinity(in *v1.VolumeNodeAffinity, out *core.VolumeNodeAffinity, s conversion.Scope) error { + out.Required = (*core.NodeSelector)(unsafe.Pointer(in.Required)) + return nil +} + +// Convert_v1_VolumeNodeAffinity_To_core_VolumeNodeAffinity is an autogenerated conversion function. +func Convert_v1_VolumeNodeAffinity_To_core_VolumeNodeAffinity(in *v1.VolumeNodeAffinity, out *core.VolumeNodeAffinity, s conversion.Scope) error { + return autoConvert_v1_VolumeNodeAffinity_To_core_VolumeNodeAffinity(in, out, s) +} + +func autoConvert_core_VolumeNodeAffinity_To_v1_VolumeNodeAffinity(in *core.VolumeNodeAffinity, out *v1.VolumeNodeAffinity, s conversion.Scope) error { + out.Required = (*v1.NodeSelector)(unsafe.Pointer(in.Required)) + return nil +} + +// Convert_core_VolumeNodeAffinity_To_v1_VolumeNodeAffinity is an autogenerated conversion function. +func Convert_core_VolumeNodeAffinity_To_v1_VolumeNodeAffinity(in *core.VolumeNodeAffinity, out *v1.VolumeNodeAffinity, s conversion.Scope) error { + return autoConvert_core_VolumeNodeAffinity_To_v1_VolumeNodeAffinity(in, out, s) +} + +func autoConvert_v1_VolumeProjection_To_core_VolumeProjection(in *v1.VolumeProjection, out *core.VolumeProjection, s conversion.Scope) error { + out.Secret = (*core.SecretProjection)(unsafe.Pointer(in.Secret)) + out.DownwardAPI = (*core.DownwardAPIProjection)(unsafe.Pointer(in.DownwardAPI)) + out.ConfigMap = (*core.ConfigMapProjection)(unsafe.Pointer(in.ConfigMap)) + if in.ServiceAccountToken != nil { + in, out := &in.ServiceAccountToken, &out.ServiceAccountToken + *out = new(core.ServiceAccountTokenProjection) + if err := Convert_v1_ServiceAccountTokenProjection_To_core_ServiceAccountTokenProjection(*in, *out, s); err != nil { + return err + } + } else { + out.ServiceAccountToken = nil + } + return nil +} + +// Convert_v1_VolumeProjection_To_core_VolumeProjection is an autogenerated conversion function. +func Convert_v1_VolumeProjection_To_core_VolumeProjection(in *v1.VolumeProjection, out *core.VolumeProjection, s conversion.Scope) error { + return autoConvert_v1_VolumeProjection_To_core_VolumeProjection(in, out, s) +} + +func autoConvert_core_VolumeProjection_To_v1_VolumeProjection(in *core.VolumeProjection, out *v1.VolumeProjection, s conversion.Scope) error { + out.Secret = (*v1.SecretProjection)(unsafe.Pointer(in.Secret)) + out.DownwardAPI = (*v1.DownwardAPIProjection)(unsafe.Pointer(in.DownwardAPI)) + out.ConfigMap = (*v1.ConfigMapProjection)(unsafe.Pointer(in.ConfigMap)) + if in.ServiceAccountToken != nil { + in, out := &in.ServiceAccountToken, &out.ServiceAccountToken + *out = new(v1.ServiceAccountTokenProjection) + if err := Convert_core_ServiceAccountTokenProjection_To_v1_ServiceAccountTokenProjection(*in, *out, s); err != nil { + return err + } + } else { + out.ServiceAccountToken = nil + } + return nil +} + +// Convert_core_VolumeProjection_To_v1_VolumeProjection is an autogenerated conversion function. +func Convert_core_VolumeProjection_To_v1_VolumeProjection(in *core.VolumeProjection, out *v1.VolumeProjection, s conversion.Scope) error { + return autoConvert_core_VolumeProjection_To_v1_VolumeProjection(in, out, s) +} + +func autoConvert_v1_VolumeSource_To_core_VolumeSource(in *v1.VolumeSource, out *core.VolumeSource, s conversion.Scope) error { + out.HostPath = (*core.HostPathVolumeSource)(unsafe.Pointer(in.HostPath)) + out.EmptyDir = (*core.EmptyDirVolumeSource)(unsafe.Pointer(in.EmptyDir)) + out.GCEPersistentDisk = (*core.GCEPersistentDiskVolumeSource)(unsafe.Pointer(in.GCEPersistentDisk)) + out.AWSElasticBlockStore = (*core.AWSElasticBlockStoreVolumeSource)(unsafe.Pointer(in.AWSElasticBlockStore)) + out.GitRepo = (*core.GitRepoVolumeSource)(unsafe.Pointer(in.GitRepo)) + out.Secret = (*core.SecretVolumeSource)(unsafe.Pointer(in.Secret)) + out.NFS = (*core.NFSVolumeSource)(unsafe.Pointer(in.NFS)) + out.ISCSI = (*core.ISCSIVolumeSource)(unsafe.Pointer(in.ISCSI)) + out.Glusterfs = (*core.GlusterfsVolumeSource)(unsafe.Pointer(in.Glusterfs)) + out.PersistentVolumeClaim = (*core.PersistentVolumeClaimVolumeSource)(unsafe.Pointer(in.PersistentVolumeClaim)) + out.RBD = (*core.RBDVolumeSource)(unsafe.Pointer(in.RBD)) + out.FlexVolume = (*core.FlexVolumeSource)(unsafe.Pointer(in.FlexVolume)) + out.Cinder = (*core.CinderVolumeSource)(unsafe.Pointer(in.Cinder)) + out.CephFS = (*core.CephFSVolumeSource)(unsafe.Pointer(in.CephFS)) + out.Flocker = (*core.FlockerVolumeSource)(unsafe.Pointer(in.Flocker)) + out.DownwardAPI = (*core.DownwardAPIVolumeSource)(unsafe.Pointer(in.DownwardAPI)) + out.FC = (*core.FCVolumeSource)(unsafe.Pointer(in.FC)) + out.AzureFile = (*core.AzureFileVolumeSource)(unsafe.Pointer(in.AzureFile)) + out.ConfigMap = (*core.ConfigMapVolumeSource)(unsafe.Pointer(in.ConfigMap)) + out.VsphereVolume = (*core.VsphereVirtualDiskVolumeSource)(unsafe.Pointer(in.VsphereVolume)) + out.Quobyte = (*core.QuobyteVolumeSource)(unsafe.Pointer(in.Quobyte)) + out.AzureDisk = (*core.AzureDiskVolumeSource)(unsafe.Pointer(in.AzureDisk)) + out.PhotonPersistentDisk = (*core.PhotonPersistentDiskVolumeSource)(unsafe.Pointer(in.PhotonPersistentDisk)) + if in.Projected != nil { + in, out := &in.Projected, &out.Projected + *out = new(core.ProjectedVolumeSource) + if err := Convert_v1_ProjectedVolumeSource_To_core_ProjectedVolumeSource(*in, *out, s); err != nil { + return err + } + } else { + out.Projected = nil + } + out.PortworxVolume = (*core.PortworxVolumeSource)(unsafe.Pointer(in.PortworxVolume)) + out.ScaleIO = (*core.ScaleIOVolumeSource)(unsafe.Pointer(in.ScaleIO)) + out.StorageOS = (*core.StorageOSVolumeSource)(unsafe.Pointer(in.StorageOS)) + out.CSI = (*core.CSIVolumeSource)(unsafe.Pointer(in.CSI)) + out.Ephemeral = (*core.EphemeralVolumeSource)(unsafe.Pointer(in.Ephemeral)) + return nil +} + +// Convert_v1_VolumeSource_To_core_VolumeSource is an autogenerated conversion function. +func Convert_v1_VolumeSource_To_core_VolumeSource(in *v1.VolumeSource, out *core.VolumeSource, s conversion.Scope) error { + return autoConvert_v1_VolumeSource_To_core_VolumeSource(in, out, s) +} + +func autoConvert_core_VolumeSource_To_v1_VolumeSource(in *core.VolumeSource, out *v1.VolumeSource, s conversion.Scope) error { + out.HostPath = (*v1.HostPathVolumeSource)(unsafe.Pointer(in.HostPath)) + out.EmptyDir = (*v1.EmptyDirVolumeSource)(unsafe.Pointer(in.EmptyDir)) + out.GCEPersistentDisk = (*v1.GCEPersistentDiskVolumeSource)(unsafe.Pointer(in.GCEPersistentDisk)) + out.AWSElasticBlockStore = (*v1.AWSElasticBlockStoreVolumeSource)(unsafe.Pointer(in.AWSElasticBlockStore)) + out.GitRepo = (*v1.GitRepoVolumeSource)(unsafe.Pointer(in.GitRepo)) + out.Secret = (*v1.SecretVolumeSource)(unsafe.Pointer(in.Secret)) + out.NFS = (*v1.NFSVolumeSource)(unsafe.Pointer(in.NFS)) + out.ISCSI = (*v1.ISCSIVolumeSource)(unsafe.Pointer(in.ISCSI)) + out.Glusterfs = (*v1.GlusterfsVolumeSource)(unsafe.Pointer(in.Glusterfs)) + out.PersistentVolumeClaim = (*v1.PersistentVolumeClaimVolumeSource)(unsafe.Pointer(in.PersistentVolumeClaim)) + out.RBD = (*v1.RBDVolumeSource)(unsafe.Pointer(in.RBD)) + out.Quobyte = (*v1.QuobyteVolumeSource)(unsafe.Pointer(in.Quobyte)) + out.FlexVolume = (*v1.FlexVolumeSource)(unsafe.Pointer(in.FlexVolume)) + out.Cinder = (*v1.CinderVolumeSource)(unsafe.Pointer(in.Cinder)) + out.CephFS = (*v1.CephFSVolumeSource)(unsafe.Pointer(in.CephFS)) + out.Flocker = (*v1.FlockerVolumeSource)(unsafe.Pointer(in.Flocker)) + out.DownwardAPI = (*v1.DownwardAPIVolumeSource)(unsafe.Pointer(in.DownwardAPI)) + out.FC = (*v1.FCVolumeSource)(unsafe.Pointer(in.FC)) + out.AzureFile = (*v1.AzureFileVolumeSource)(unsafe.Pointer(in.AzureFile)) + out.ConfigMap = (*v1.ConfigMapVolumeSource)(unsafe.Pointer(in.ConfigMap)) + out.VsphereVolume = (*v1.VsphereVirtualDiskVolumeSource)(unsafe.Pointer(in.VsphereVolume)) + out.AzureDisk = (*v1.AzureDiskVolumeSource)(unsafe.Pointer(in.AzureDisk)) + out.PhotonPersistentDisk = (*v1.PhotonPersistentDiskVolumeSource)(unsafe.Pointer(in.PhotonPersistentDisk)) + if in.Projected != nil { + in, out := &in.Projected, &out.Projected + *out = new(v1.ProjectedVolumeSource) + if err := Convert_core_ProjectedVolumeSource_To_v1_ProjectedVolumeSource(*in, *out, s); err != nil { + return err + } + } else { + out.Projected = nil + } + out.PortworxVolume = (*v1.PortworxVolumeSource)(unsafe.Pointer(in.PortworxVolume)) + out.ScaleIO = (*v1.ScaleIOVolumeSource)(unsafe.Pointer(in.ScaleIO)) + out.StorageOS = (*v1.StorageOSVolumeSource)(unsafe.Pointer(in.StorageOS)) + out.CSI = (*v1.CSIVolumeSource)(unsafe.Pointer(in.CSI)) + out.Ephemeral = (*v1.EphemeralVolumeSource)(unsafe.Pointer(in.Ephemeral)) + return nil +} + +// Convert_core_VolumeSource_To_v1_VolumeSource is an autogenerated conversion function. +func Convert_core_VolumeSource_To_v1_VolumeSource(in *core.VolumeSource, out *v1.VolumeSource, s conversion.Scope) error { + return autoConvert_core_VolumeSource_To_v1_VolumeSource(in, out, s) +} + +func autoConvert_v1_VsphereVirtualDiskVolumeSource_To_core_VsphereVirtualDiskVolumeSource(in *v1.VsphereVirtualDiskVolumeSource, out *core.VsphereVirtualDiskVolumeSource, s conversion.Scope) error { + out.VolumePath = in.VolumePath + out.FSType = in.FSType + out.StoragePolicyName = in.StoragePolicyName + out.StoragePolicyID = in.StoragePolicyID + return nil +} + +// Convert_v1_VsphereVirtualDiskVolumeSource_To_core_VsphereVirtualDiskVolumeSource is an autogenerated conversion function. +func Convert_v1_VsphereVirtualDiskVolumeSource_To_core_VsphereVirtualDiskVolumeSource(in *v1.VsphereVirtualDiskVolumeSource, out *core.VsphereVirtualDiskVolumeSource, s conversion.Scope) error { + return autoConvert_v1_VsphereVirtualDiskVolumeSource_To_core_VsphereVirtualDiskVolumeSource(in, out, s) +} + +func autoConvert_core_VsphereVirtualDiskVolumeSource_To_v1_VsphereVirtualDiskVolumeSource(in *core.VsphereVirtualDiskVolumeSource, out *v1.VsphereVirtualDiskVolumeSource, s conversion.Scope) error { + out.VolumePath = in.VolumePath + out.FSType = in.FSType + out.StoragePolicyName = in.StoragePolicyName + out.StoragePolicyID = in.StoragePolicyID + return nil +} + +// Convert_core_VsphereVirtualDiskVolumeSource_To_v1_VsphereVirtualDiskVolumeSource is an autogenerated conversion function. +func Convert_core_VsphereVirtualDiskVolumeSource_To_v1_VsphereVirtualDiskVolumeSource(in *core.VsphereVirtualDiskVolumeSource, out *v1.VsphereVirtualDiskVolumeSource, s conversion.Scope) error { + return autoConvert_core_VsphereVirtualDiskVolumeSource_To_v1_VsphereVirtualDiskVolumeSource(in, out, s) +} + +func autoConvert_v1_WeightedPodAffinityTerm_To_core_WeightedPodAffinityTerm(in *v1.WeightedPodAffinityTerm, out *core.WeightedPodAffinityTerm, s conversion.Scope) error { + out.Weight = in.Weight + if err := Convert_v1_PodAffinityTerm_To_core_PodAffinityTerm(&in.PodAffinityTerm, &out.PodAffinityTerm, s); err != nil { + return err + } + return nil +} + +// Convert_v1_WeightedPodAffinityTerm_To_core_WeightedPodAffinityTerm is an autogenerated conversion function. +func Convert_v1_WeightedPodAffinityTerm_To_core_WeightedPodAffinityTerm(in *v1.WeightedPodAffinityTerm, out *core.WeightedPodAffinityTerm, s conversion.Scope) error { + return autoConvert_v1_WeightedPodAffinityTerm_To_core_WeightedPodAffinityTerm(in, out, s) +} + +func autoConvert_core_WeightedPodAffinityTerm_To_v1_WeightedPodAffinityTerm(in *core.WeightedPodAffinityTerm, out *v1.WeightedPodAffinityTerm, s conversion.Scope) error { + out.Weight = in.Weight + if err := Convert_core_PodAffinityTerm_To_v1_PodAffinityTerm(&in.PodAffinityTerm, &out.PodAffinityTerm, s); err != nil { + return err + } + return nil +} + +// Convert_core_WeightedPodAffinityTerm_To_v1_WeightedPodAffinityTerm is an autogenerated conversion function. +func Convert_core_WeightedPodAffinityTerm_To_v1_WeightedPodAffinityTerm(in *core.WeightedPodAffinityTerm, out *v1.WeightedPodAffinityTerm, s conversion.Scope) error { + return autoConvert_core_WeightedPodAffinityTerm_To_v1_WeightedPodAffinityTerm(in, out, s) +} + +func autoConvert_v1_WindowsSecurityContextOptions_To_core_WindowsSecurityContextOptions(in *v1.WindowsSecurityContextOptions, out *core.WindowsSecurityContextOptions, s conversion.Scope) error { + out.GMSACredentialSpecName = (*string)(unsafe.Pointer(in.GMSACredentialSpecName)) + out.GMSACredentialSpec = (*string)(unsafe.Pointer(in.GMSACredentialSpec)) + out.RunAsUserName = (*string)(unsafe.Pointer(in.RunAsUserName)) + out.HostProcess = (*bool)(unsafe.Pointer(in.HostProcess)) + return nil +} + +// Convert_v1_WindowsSecurityContextOptions_To_core_WindowsSecurityContextOptions is an autogenerated conversion function. +func Convert_v1_WindowsSecurityContextOptions_To_core_WindowsSecurityContextOptions(in *v1.WindowsSecurityContextOptions, out *core.WindowsSecurityContextOptions, s conversion.Scope) error { + return autoConvert_v1_WindowsSecurityContextOptions_To_core_WindowsSecurityContextOptions(in, out, s) +} + +func autoConvert_core_WindowsSecurityContextOptions_To_v1_WindowsSecurityContextOptions(in *core.WindowsSecurityContextOptions, out *v1.WindowsSecurityContextOptions, s conversion.Scope) error { + out.GMSACredentialSpecName = (*string)(unsafe.Pointer(in.GMSACredentialSpecName)) + out.GMSACredentialSpec = (*string)(unsafe.Pointer(in.GMSACredentialSpec)) + out.RunAsUserName = (*string)(unsafe.Pointer(in.RunAsUserName)) + out.HostProcess = (*bool)(unsafe.Pointer(in.HostProcess)) + return nil +} + +// Convert_core_WindowsSecurityContextOptions_To_v1_WindowsSecurityContextOptions is an autogenerated conversion function. +func Convert_core_WindowsSecurityContextOptions_To_v1_WindowsSecurityContextOptions(in *core.WindowsSecurityContextOptions, out *v1.WindowsSecurityContextOptions, s conversion.Scope) error { + return autoConvert_core_WindowsSecurityContextOptions_To_v1_WindowsSecurityContextOptions(in, out, s) +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/v1/zz_generated.defaults.go b/vendor/k8s.io/kubernetes/pkg/apis/core/v1/zz_generated.defaults.go new file mode 100644 index 000000000..7706bbf9a --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/v1/zz_generated.defaults.go @@ -0,0 +1,1040 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1 + +import ( + v1 "k8s.io/api/core/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + scheme.AddTypeDefaultingFunc(&v1.ConfigMap{}, func(obj interface{}) { SetObjectDefaults_ConfigMap(obj.(*v1.ConfigMap)) }) + scheme.AddTypeDefaultingFunc(&v1.ConfigMapList{}, func(obj interface{}) { SetObjectDefaults_ConfigMapList(obj.(*v1.ConfigMapList)) }) + scheme.AddTypeDefaultingFunc(&v1.Endpoints{}, func(obj interface{}) { SetObjectDefaults_Endpoints(obj.(*v1.Endpoints)) }) + scheme.AddTypeDefaultingFunc(&v1.EndpointsList{}, func(obj interface{}) { SetObjectDefaults_EndpointsList(obj.(*v1.EndpointsList)) }) + scheme.AddTypeDefaultingFunc(&v1.LimitRange{}, func(obj interface{}) { SetObjectDefaults_LimitRange(obj.(*v1.LimitRange)) }) + scheme.AddTypeDefaultingFunc(&v1.LimitRangeList{}, func(obj interface{}) { SetObjectDefaults_LimitRangeList(obj.(*v1.LimitRangeList)) }) + scheme.AddTypeDefaultingFunc(&v1.Namespace{}, func(obj interface{}) { SetObjectDefaults_Namespace(obj.(*v1.Namespace)) }) + scheme.AddTypeDefaultingFunc(&v1.NamespaceList{}, func(obj interface{}) { SetObjectDefaults_NamespaceList(obj.(*v1.NamespaceList)) }) + scheme.AddTypeDefaultingFunc(&v1.Node{}, func(obj interface{}) { SetObjectDefaults_Node(obj.(*v1.Node)) }) + scheme.AddTypeDefaultingFunc(&v1.NodeList{}, func(obj interface{}) { SetObjectDefaults_NodeList(obj.(*v1.NodeList)) }) + scheme.AddTypeDefaultingFunc(&v1.PersistentVolume{}, func(obj interface{}) { SetObjectDefaults_PersistentVolume(obj.(*v1.PersistentVolume)) }) + scheme.AddTypeDefaultingFunc(&v1.PersistentVolumeClaim{}, func(obj interface{}) { SetObjectDefaults_PersistentVolumeClaim(obj.(*v1.PersistentVolumeClaim)) }) + scheme.AddTypeDefaultingFunc(&v1.PersistentVolumeClaimList{}, func(obj interface{}) { + SetObjectDefaults_PersistentVolumeClaimList(obj.(*v1.PersistentVolumeClaimList)) + }) + scheme.AddTypeDefaultingFunc(&v1.PersistentVolumeList{}, func(obj interface{}) { SetObjectDefaults_PersistentVolumeList(obj.(*v1.PersistentVolumeList)) }) + scheme.AddTypeDefaultingFunc(&v1.Pod{}, func(obj interface{}) { SetObjectDefaults_Pod(obj.(*v1.Pod)) }) + scheme.AddTypeDefaultingFunc(&v1.PodList{}, func(obj interface{}) { SetObjectDefaults_PodList(obj.(*v1.PodList)) }) + scheme.AddTypeDefaultingFunc(&v1.PodTemplate{}, func(obj interface{}) { SetObjectDefaults_PodTemplate(obj.(*v1.PodTemplate)) }) + scheme.AddTypeDefaultingFunc(&v1.PodTemplateList{}, func(obj interface{}) { SetObjectDefaults_PodTemplateList(obj.(*v1.PodTemplateList)) }) + scheme.AddTypeDefaultingFunc(&v1.ReplicationController{}, func(obj interface{}) { SetObjectDefaults_ReplicationController(obj.(*v1.ReplicationController)) }) + scheme.AddTypeDefaultingFunc(&v1.ReplicationControllerList{}, func(obj interface{}) { + SetObjectDefaults_ReplicationControllerList(obj.(*v1.ReplicationControllerList)) + }) + scheme.AddTypeDefaultingFunc(&v1.ResourceQuota{}, func(obj interface{}) { SetObjectDefaults_ResourceQuota(obj.(*v1.ResourceQuota)) }) + scheme.AddTypeDefaultingFunc(&v1.ResourceQuotaList{}, func(obj interface{}) { SetObjectDefaults_ResourceQuotaList(obj.(*v1.ResourceQuotaList)) }) + scheme.AddTypeDefaultingFunc(&v1.Secret{}, func(obj interface{}) { SetObjectDefaults_Secret(obj.(*v1.Secret)) }) + scheme.AddTypeDefaultingFunc(&v1.SecretList{}, func(obj interface{}) { SetObjectDefaults_SecretList(obj.(*v1.SecretList)) }) + scheme.AddTypeDefaultingFunc(&v1.Service{}, func(obj interface{}) { SetObjectDefaults_Service(obj.(*v1.Service)) }) + scheme.AddTypeDefaultingFunc(&v1.ServiceList{}, func(obj interface{}) { SetObjectDefaults_ServiceList(obj.(*v1.ServiceList)) }) + return nil +} + +func SetObjectDefaults_ConfigMap(in *v1.ConfigMap) { + SetDefaults_ConfigMap(in) +} + +func SetObjectDefaults_ConfigMapList(in *v1.ConfigMapList) { + for i := range in.Items { + a := &in.Items[i] + SetObjectDefaults_ConfigMap(a) + } +} + +func SetObjectDefaults_Endpoints(in *v1.Endpoints) { + SetDefaults_Endpoints(in) +} + +func SetObjectDefaults_EndpointsList(in *v1.EndpointsList) { + for i := range in.Items { + a := &in.Items[i] + SetObjectDefaults_Endpoints(a) + } +} + +func SetObjectDefaults_LimitRange(in *v1.LimitRange) { + for i := range in.Spec.Limits { + a := &in.Spec.Limits[i] + SetDefaults_LimitRangeItem(a) + SetDefaults_ResourceList(&a.Max) + SetDefaults_ResourceList(&a.Min) + SetDefaults_ResourceList(&a.Default) + SetDefaults_ResourceList(&a.DefaultRequest) + SetDefaults_ResourceList(&a.MaxLimitRequestRatio) + } +} + +func SetObjectDefaults_LimitRangeList(in *v1.LimitRangeList) { + for i := range in.Items { + a := &in.Items[i] + SetObjectDefaults_LimitRange(a) + } +} + +func SetObjectDefaults_Namespace(in *v1.Namespace) { + SetDefaults_Namespace(in) + SetDefaults_NamespaceStatus(&in.Status) +} + +func SetObjectDefaults_NamespaceList(in *v1.NamespaceList) { + for i := range in.Items { + a := &in.Items[i] + SetObjectDefaults_Namespace(a) + } +} + +func SetObjectDefaults_Node(in *v1.Node) { + SetDefaults_NodeStatus(&in.Status) + SetDefaults_ResourceList(&in.Status.Capacity) + SetDefaults_ResourceList(&in.Status.Allocatable) +} + +func SetObjectDefaults_NodeList(in *v1.NodeList) { + for i := range in.Items { + a := &in.Items[i] + SetObjectDefaults_Node(a) + } +} + +func SetObjectDefaults_PersistentVolume(in *v1.PersistentVolume) { + SetDefaults_PersistentVolume(in) + SetDefaults_ResourceList(&in.Spec.Capacity) + if in.Spec.PersistentVolumeSource.HostPath != nil { + SetDefaults_HostPathVolumeSource(in.Spec.PersistentVolumeSource.HostPath) + } + if in.Spec.PersistentVolumeSource.RBD != nil { + SetDefaults_RBDPersistentVolumeSource(in.Spec.PersistentVolumeSource.RBD) + } + if in.Spec.PersistentVolumeSource.ISCSI != nil { + SetDefaults_ISCSIPersistentVolumeSource(in.Spec.PersistentVolumeSource.ISCSI) + } + if in.Spec.PersistentVolumeSource.AzureDisk != nil { + SetDefaults_AzureDiskVolumeSource(in.Spec.PersistentVolumeSource.AzureDisk) + } + if in.Spec.PersistentVolumeSource.ScaleIO != nil { + SetDefaults_ScaleIOPersistentVolumeSource(in.Spec.PersistentVolumeSource.ScaleIO) + } +} + +func SetObjectDefaults_PersistentVolumeClaim(in *v1.PersistentVolumeClaim) { + SetDefaults_PersistentVolumeClaim(in) + SetDefaults_PersistentVolumeClaimSpec(&in.Spec) + SetDefaults_ResourceList(&in.Spec.Resources.Limits) + SetDefaults_ResourceList(&in.Spec.Resources.Requests) + SetDefaults_ResourceList(&in.Status.Capacity) + SetDefaults_ResourceList(&in.Status.AllocatedResources) +} + +func SetObjectDefaults_PersistentVolumeClaimList(in *v1.PersistentVolumeClaimList) { + for i := range in.Items { + a := &in.Items[i] + SetObjectDefaults_PersistentVolumeClaim(a) + } +} + +func SetObjectDefaults_PersistentVolumeList(in *v1.PersistentVolumeList) { + for i := range in.Items { + a := &in.Items[i] + SetObjectDefaults_PersistentVolume(a) + } +} + +func SetObjectDefaults_Pod(in *v1.Pod) { + SetDefaults_Pod(in) + SetDefaults_PodSpec(&in.Spec) + for i := range in.Spec.Volumes { + a := &in.Spec.Volumes[i] + SetDefaults_Volume(a) + if a.VolumeSource.HostPath != nil { + SetDefaults_HostPathVolumeSource(a.VolumeSource.HostPath) + } + if a.VolumeSource.Secret != nil { + SetDefaults_SecretVolumeSource(a.VolumeSource.Secret) + } + if a.VolumeSource.ISCSI != nil { + SetDefaults_ISCSIVolumeSource(a.VolumeSource.ISCSI) + } + if a.VolumeSource.RBD != nil { + SetDefaults_RBDVolumeSource(a.VolumeSource.RBD) + } + if a.VolumeSource.DownwardAPI != nil { + SetDefaults_DownwardAPIVolumeSource(a.VolumeSource.DownwardAPI) + for j := range a.VolumeSource.DownwardAPI.Items { + b := &a.VolumeSource.DownwardAPI.Items[j] + if b.FieldRef != nil { + SetDefaults_ObjectFieldSelector(b.FieldRef) + } + } + } + if a.VolumeSource.ConfigMap != nil { + SetDefaults_ConfigMapVolumeSource(a.VolumeSource.ConfigMap) + } + if a.VolumeSource.AzureDisk != nil { + SetDefaults_AzureDiskVolumeSource(a.VolumeSource.AzureDisk) + } + if a.VolumeSource.Projected != nil { + SetDefaults_ProjectedVolumeSource(a.VolumeSource.Projected) + for j := range a.VolumeSource.Projected.Sources { + b := &a.VolumeSource.Projected.Sources[j] + if b.DownwardAPI != nil { + for k := range b.DownwardAPI.Items { + c := &b.DownwardAPI.Items[k] + if c.FieldRef != nil { + SetDefaults_ObjectFieldSelector(c.FieldRef) + } + } + } + if b.ServiceAccountToken != nil { + SetDefaults_ServiceAccountTokenProjection(b.ServiceAccountToken) + } + } + } + if a.VolumeSource.ScaleIO != nil { + SetDefaults_ScaleIOVolumeSource(a.VolumeSource.ScaleIO) + } + if a.VolumeSource.Ephemeral != nil { + if a.VolumeSource.Ephemeral.VolumeClaimTemplate != nil { + SetDefaults_PersistentVolumeClaimSpec(&a.VolumeSource.Ephemeral.VolumeClaimTemplate.Spec) + SetDefaults_ResourceList(&a.VolumeSource.Ephemeral.VolumeClaimTemplate.Spec.Resources.Limits) + SetDefaults_ResourceList(&a.VolumeSource.Ephemeral.VolumeClaimTemplate.Spec.Resources.Requests) + } + } + } + for i := range in.Spec.InitContainers { + a := &in.Spec.InitContainers[i] + SetDefaults_Container(a) + for j := range a.Ports { + b := &a.Ports[j] + if b.Protocol == "" { + b.Protocol = "TCP" + } + } + for j := range a.Env { + b := &a.Env[j] + if b.ValueFrom != nil { + if b.ValueFrom.FieldRef != nil { + SetDefaults_ObjectFieldSelector(b.ValueFrom.FieldRef) + } + } + } + SetDefaults_ResourceList(&a.Resources.Limits) + SetDefaults_ResourceList(&a.Resources.Requests) + if a.LivenessProbe != nil { + SetDefaults_Probe(a.LivenessProbe) + if a.LivenessProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.LivenessProbe.ProbeHandler.HTTPGet) + } + if a.LivenessProbe.ProbeHandler.GRPC != nil { + if a.LivenessProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.LivenessProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.ReadinessProbe != nil { + SetDefaults_Probe(a.ReadinessProbe) + if a.ReadinessProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.ReadinessProbe.ProbeHandler.HTTPGet) + } + if a.ReadinessProbe.ProbeHandler.GRPC != nil { + if a.ReadinessProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.ReadinessProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.StartupProbe != nil { + SetDefaults_Probe(a.StartupProbe) + if a.StartupProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.StartupProbe.ProbeHandler.HTTPGet) + } + if a.StartupProbe.ProbeHandler.GRPC != nil { + if a.StartupProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.StartupProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.Lifecycle != nil { + if a.Lifecycle.PostStart != nil { + if a.Lifecycle.PostStart.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.Lifecycle.PostStart.HTTPGet) + } + } + if a.Lifecycle.PreStop != nil { + if a.Lifecycle.PreStop.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.Lifecycle.PreStop.HTTPGet) + } + } + } + } + for i := range in.Spec.Containers { + a := &in.Spec.Containers[i] + SetDefaults_Container(a) + for j := range a.Ports { + b := &a.Ports[j] + if b.Protocol == "" { + b.Protocol = "TCP" + } + } + for j := range a.Env { + b := &a.Env[j] + if b.ValueFrom != nil { + if b.ValueFrom.FieldRef != nil { + SetDefaults_ObjectFieldSelector(b.ValueFrom.FieldRef) + } + } + } + SetDefaults_ResourceList(&a.Resources.Limits) + SetDefaults_ResourceList(&a.Resources.Requests) + if a.LivenessProbe != nil { + SetDefaults_Probe(a.LivenessProbe) + if a.LivenessProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.LivenessProbe.ProbeHandler.HTTPGet) + } + if a.LivenessProbe.ProbeHandler.GRPC != nil { + if a.LivenessProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.LivenessProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.ReadinessProbe != nil { + SetDefaults_Probe(a.ReadinessProbe) + if a.ReadinessProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.ReadinessProbe.ProbeHandler.HTTPGet) + } + if a.ReadinessProbe.ProbeHandler.GRPC != nil { + if a.ReadinessProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.ReadinessProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.StartupProbe != nil { + SetDefaults_Probe(a.StartupProbe) + if a.StartupProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.StartupProbe.ProbeHandler.HTTPGet) + } + if a.StartupProbe.ProbeHandler.GRPC != nil { + if a.StartupProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.StartupProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.Lifecycle != nil { + if a.Lifecycle.PostStart != nil { + if a.Lifecycle.PostStart.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.Lifecycle.PostStart.HTTPGet) + } + } + if a.Lifecycle.PreStop != nil { + if a.Lifecycle.PreStop.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.Lifecycle.PreStop.HTTPGet) + } + } + } + } + for i := range in.Spec.EphemeralContainers { + a := &in.Spec.EphemeralContainers[i] + SetDefaults_EphemeralContainer(a) + for j := range a.EphemeralContainerCommon.Ports { + b := &a.EphemeralContainerCommon.Ports[j] + if b.Protocol == "" { + b.Protocol = "TCP" + } + } + for j := range a.EphemeralContainerCommon.Env { + b := &a.EphemeralContainerCommon.Env[j] + if b.ValueFrom != nil { + if b.ValueFrom.FieldRef != nil { + SetDefaults_ObjectFieldSelector(b.ValueFrom.FieldRef) + } + } + } + SetDefaults_ResourceList(&a.EphemeralContainerCommon.Resources.Limits) + SetDefaults_ResourceList(&a.EphemeralContainerCommon.Resources.Requests) + if a.EphemeralContainerCommon.LivenessProbe != nil { + SetDefaults_Probe(a.EphemeralContainerCommon.LivenessProbe) + if a.EphemeralContainerCommon.LivenessProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.EphemeralContainerCommon.LivenessProbe.ProbeHandler.HTTPGet) + } + if a.EphemeralContainerCommon.LivenessProbe.ProbeHandler.GRPC != nil { + if a.EphemeralContainerCommon.LivenessProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.EphemeralContainerCommon.LivenessProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.EphemeralContainerCommon.ReadinessProbe != nil { + SetDefaults_Probe(a.EphemeralContainerCommon.ReadinessProbe) + if a.EphemeralContainerCommon.ReadinessProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.EphemeralContainerCommon.ReadinessProbe.ProbeHandler.HTTPGet) + } + if a.EphemeralContainerCommon.ReadinessProbe.ProbeHandler.GRPC != nil { + if a.EphemeralContainerCommon.ReadinessProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.EphemeralContainerCommon.ReadinessProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.EphemeralContainerCommon.StartupProbe != nil { + SetDefaults_Probe(a.EphemeralContainerCommon.StartupProbe) + if a.EphemeralContainerCommon.StartupProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.EphemeralContainerCommon.StartupProbe.ProbeHandler.HTTPGet) + } + if a.EphemeralContainerCommon.StartupProbe.ProbeHandler.GRPC != nil { + if a.EphemeralContainerCommon.StartupProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.EphemeralContainerCommon.StartupProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.EphemeralContainerCommon.Lifecycle != nil { + if a.EphemeralContainerCommon.Lifecycle.PostStart != nil { + if a.EphemeralContainerCommon.Lifecycle.PostStart.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.EphemeralContainerCommon.Lifecycle.PostStart.HTTPGet) + } + } + if a.EphemeralContainerCommon.Lifecycle.PreStop != nil { + if a.EphemeralContainerCommon.Lifecycle.PreStop.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.EphemeralContainerCommon.Lifecycle.PreStop.HTTPGet) + } + } + } + } + SetDefaults_ResourceList(&in.Spec.Overhead) +} + +func SetObjectDefaults_PodList(in *v1.PodList) { + for i := range in.Items { + a := &in.Items[i] + SetObjectDefaults_Pod(a) + } +} + +func SetObjectDefaults_PodTemplate(in *v1.PodTemplate) { + SetDefaults_PodSpec(&in.Template.Spec) + for i := range in.Template.Spec.Volumes { + a := &in.Template.Spec.Volumes[i] + SetDefaults_Volume(a) + if a.VolumeSource.HostPath != nil { + SetDefaults_HostPathVolumeSource(a.VolumeSource.HostPath) + } + if a.VolumeSource.Secret != nil { + SetDefaults_SecretVolumeSource(a.VolumeSource.Secret) + } + if a.VolumeSource.ISCSI != nil { + SetDefaults_ISCSIVolumeSource(a.VolumeSource.ISCSI) + } + if a.VolumeSource.RBD != nil { + SetDefaults_RBDVolumeSource(a.VolumeSource.RBD) + } + if a.VolumeSource.DownwardAPI != nil { + SetDefaults_DownwardAPIVolumeSource(a.VolumeSource.DownwardAPI) + for j := range a.VolumeSource.DownwardAPI.Items { + b := &a.VolumeSource.DownwardAPI.Items[j] + if b.FieldRef != nil { + SetDefaults_ObjectFieldSelector(b.FieldRef) + } + } + } + if a.VolumeSource.ConfigMap != nil { + SetDefaults_ConfigMapVolumeSource(a.VolumeSource.ConfigMap) + } + if a.VolumeSource.AzureDisk != nil { + SetDefaults_AzureDiskVolumeSource(a.VolumeSource.AzureDisk) + } + if a.VolumeSource.Projected != nil { + SetDefaults_ProjectedVolumeSource(a.VolumeSource.Projected) + for j := range a.VolumeSource.Projected.Sources { + b := &a.VolumeSource.Projected.Sources[j] + if b.DownwardAPI != nil { + for k := range b.DownwardAPI.Items { + c := &b.DownwardAPI.Items[k] + if c.FieldRef != nil { + SetDefaults_ObjectFieldSelector(c.FieldRef) + } + } + } + if b.ServiceAccountToken != nil { + SetDefaults_ServiceAccountTokenProjection(b.ServiceAccountToken) + } + } + } + if a.VolumeSource.ScaleIO != nil { + SetDefaults_ScaleIOVolumeSource(a.VolumeSource.ScaleIO) + } + if a.VolumeSource.Ephemeral != nil { + if a.VolumeSource.Ephemeral.VolumeClaimTemplate != nil { + SetDefaults_PersistentVolumeClaimSpec(&a.VolumeSource.Ephemeral.VolumeClaimTemplate.Spec) + SetDefaults_ResourceList(&a.VolumeSource.Ephemeral.VolumeClaimTemplate.Spec.Resources.Limits) + SetDefaults_ResourceList(&a.VolumeSource.Ephemeral.VolumeClaimTemplate.Spec.Resources.Requests) + } + } + } + for i := range in.Template.Spec.InitContainers { + a := &in.Template.Spec.InitContainers[i] + SetDefaults_Container(a) + for j := range a.Ports { + b := &a.Ports[j] + if b.Protocol == "" { + b.Protocol = "TCP" + } + } + for j := range a.Env { + b := &a.Env[j] + if b.ValueFrom != nil { + if b.ValueFrom.FieldRef != nil { + SetDefaults_ObjectFieldSelector(b.ValueFrom.FieldRef) + } + } + } + SetDefaults_ResourceList(&a.Resources.Limits) + SetDefaults_ResourceList(&a.Resources.Requests) + if a.LivenessProbe != nil { + SetDefaults_Probe(a.LivenessProbe) + if a.LivenessProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.LivenessProbe.ProbeHandler.HTTPGet) + } + if a.LivenessProbe.ProbeHandler.GRPC != nil { + if a.LivenessProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.LivenessProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.ReadinessProbe != nil { + SetDefaults_Probe(a.ReadinessProbe) + if a.ReadinessProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.ReadinessProbe.ProbeHandler.HTTPGet) + } + if a.ReadinessProbe.ProbeHandler.GRPC != nil { + if a.ReadinessProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.ReadinessProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.StartupProbe != nil { + SetDefaults_Probe(a.StartupProbe) + if a.StartupProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.StartupProbe.ProbeHandler.HTTPGet) + } + if a.StartupProbe.ProbeHandler.GRPC != nil { + if a.StartupProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.StartupProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.Lifecycle != nil { + if a.Lifecycle.PostStart != nil { + if a.Lifecycle.PostStart.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.Lifecycle.PostStart.HTTPGet) + } + } + if a.Lifecycle.PreStop != nil { + if a.Lifecycle.PreStop.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.Lifecycle.PreStop.HTTPGet) + } + } + } + } + for i := range in.Template.Spec.Containers { + a := &in.Template.Spec.Containers[i] + SetDefaults_Container(a) + for j := range a.Ports { + b := &a.Ports[j] + if b.Protocol == "" { + b.Protocol = "TCP" + } + } + for j := range a.Env { + b := &a.Env[j] + if b.ValueFrom != nil { + if b.ValueFrom.FieldRef != nil { + SetDefaults_ObjectFieldSelector(b.ValueFrom.FieldRef) + } + } + } + SetDefaults_ResourceList(&a.Resources.Limits) + SetDefaults_ResourceList(&a.Resources.Requests) + if a.LivenessProbe != nil { + SetDefaults_Probe(a.LivenessProbe) + if a.LivenessProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.LivenessProbe.ProbeHandler.HTTPGet) + } + if a.LivenessProbe.ProbeHandler.GRPC != nil { + if a.LivenessProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.LivenessProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.ReadinessProbe != nil { + SetDefaults_Probe(a.ReadinessProbe) + if a.ReadinessProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.ReadinessProbe.ProbeHandler.HTTPGet) + } + if a.ReadinessProbe.ProbeHandler.GRPC != nil { + if a.ReadinessProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.ReadinessProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.StartupProbe != nil { + SetDefaults_Probe(a.StartupProbe) + if a.StartupProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.StartupProbe.ProbeHandler.HTTPGet) + } + if a.StartupProbe.ProbeHandler.GRPC != nil { + if a.StartupProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.StartupProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.Lifecycle != nil { + if a.Lifecycle.PostStart != nil { + if a.Lifecycle.PostStart.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.Lifecycle.PostStart.HTTPGet) + } + } + if a.Lifecycle.PreStop != nil { + if a.Lifecycle.PreStop.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.Lifecycle.PreStop.HTTPGet) + } + } + } + } + for i := range in.Template.Spec.EphemeralContainers { + a := &in.Template.Spec.EphemeralContainers[i] + SetDefaults_EphemeralContainer(a) + for j := range a.EphemeralContainerCommon.Ports { + b := &a.EphemeralContainerCommon.Ports[j] + if b.Protocol == "" { + b.Protocol = "TCP" + } + } + for j := range a.EphemeralContainerCommon.Env { + b := &a.EphemeralContainerCommon.Env[j] + if b.ValueFrom != nil { + if b.ValueFrom.FieldRef != nil { + SetDefaults_ObjectFieldSelector(b.ValueFrom.FieldRef) + } + } + } + SetDefaults_ResourceList(&a.EphemeralContainerCommon.Resources.Limits) + SetDefaults_ResourceList(&a.EphemeralContainerCommon.Resources.Requests) + if a.EphemeralContainerCommon.LivenessProbe != nil { + SetDefaults_Probe(a.EphemeralContainerCommon.LivenessProbe) + if a.EphemeralContainerCommon.LivenessProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.EphemeralContainerCommon.LivenessProbe.ProbeHandler.HTTPGet) + } + if a.EphemeralContainerCommon.LivenessProbe.ProbeHandler.GRPC != nil { + if a.EphemeralContainerCommon.LivenessProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.EphemeralContainerCommon.LivenessProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.EphemeralContainerCommon.ReadinessProbe != nil { + SetDefaults_Probe(a.EphemeralContainerCommon.ReadinessProbe) + if a.EphemeralContainerCommon.ReadinessProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.EphemeralContainerCommon.ReadinessProbe.ProbeHandler.HTTPGet) + } + if a.EphemeralContainerCommon.ReadinessProbe.ProbeHandler.GRPC != nil { + if a.EphemeralContainerCommon.ReadinessProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.EphemeralContainerCommon.ReadinessProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.EphemeralContainerCommon.StartupProbe != nil { + SetDefaults_Probe(a.EphemeralContainerCommon.StartupProbe) + if a.EphemeralContainerCommon.StartupProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.EphemeralContainerCommon.StartupProbe.ProbeHandler.HTTPGet) + } + if a.EphemeralContainerCommon.StartupProbe.ProbeHandler.GRPC != nil { + if a.EphemeralContainerCommon.StartupProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.EphemeralContainerCommon.StartupProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.EphemeralContainerCommon.Lifecycle != nil { + if a.EphemeralContainerCommon.Lifecycle.PostStart != nil { + if a.EphemeralContainerCommon.Lifecycle.PostStart.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.EphemeralContainerCommon.Lifecycle.PostStart.HTTPGet) + } + } + if a.EphemeralContainerCommon.Lifecycle.PreStop != nil { + if a.EphemeralContainerCommon.Lifecycle.PreStop.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.EphemeralContainerCommon.Lifecycle.PreStop.HTTPGet) + } + } + } + } + SetDefaults_ResourceList(&in.Template.Spec.Overhead) +} + +func SetObjectDefaults_PodTemplateList(in *v1.PodTemplateList) { + for i := range in.Items { + a := &in.Items[i] + SetObjectDefaults_PodTemplate(a) + } +} + +func SetObjectDefaults_ReplicationController(in *v1.ReplicationController) { + SetDefaults_ReplicationController(in) + if in.Spec.Template != nil { + SetDefaults_PodSpec(&in.Spec.Template.Spec) + for i := range in.Spec.Template.Spec.Volumes { + a := &in.Spec.Template.Spec.Volumes[i] + SetDefaults_Volume(a) + if a.VolumeSource.HostPath != nil { + SetDefaults_HostPathVolumeSource(a.VolumeSource.HostPath) + } + if a.VolumeSource.Secret != nil { + SetDefaults_SecretVolumeSource(a.VolumeSource.Secret) + } + if a.VolumeSource.ISCSI != nil { + SetDefaults_ISCSIVolumeSource(a.VolumeSource.ISCSI) + } + if a.VolumeSource.RBD != nil { + SetDefaults_RBDVolumeSource(a.VolumeSource.RBD) + } + if a.VolumeSource.DownwardAPI != nil { + SetDefaults_DownwardAPIVolumeSource(a.VolumeSource.DownwardAPI) + for j := range a.VolumeSource.DownwardAPI.Items { + b := &a.VolumeSource.DownwardAPI.Items[j] + if b.FieldRef != nil { + SetDefaults_ObjectFieldSelector(b.FieldRef) + } + } + } + if a.VolumeSource.ConfigMap != nil { + SetDefaults_ConfigMapVolumeSource(a.VolumeSource.ConfigMap) + } + if a.VolumeSource.AzureDisk != nil { + SetDefaults_AzureDiskVolumeSource(a.VolumeSource.AzureDisk) + } + if a.VolumeSource.Projected != nil { + SetDefaults_ProjectedVolumeSource(a.VolumeSource.Projected) + for j := range a.VolumeSource.Projected.Sources { + b := &a.VolumeSource.Projected.Sources[j] + if b.DownwardAPI != nil { + for k := range b.DownwardAPI.Items { + c := &b.DownwardAPI.Items[k] + if c.FieldRef != nil { + SetDefaults_ObjectFieldSelector(c.FieldRef) + } + } + } + if b.ServiceAccountToken != nil { + SetDefaults_ServiceAccountTokenProjection(b.ServiceAccountToken) + } + } + } + if a.VolumeSource.ScaleIO != nil { + SetDefaults_ScaleIOVolumeSource(a.VolumeSource.ScaleIO) + } + if a.VolumeSource.Ephemeral != nil { + if a.VolumeSource.Ephemeral.VolumeClaimTemplate != nil { + SetDefaults_PersistentVolumeClaimSpec(&a.VolumeSource.Ephemeral.VolumeClaimTemplate.Spec) + SetDefaults_ResourceList(&a.VolumeSource.Ephemeral.VolumeClaimTemplate.Spec.Resources.Limits) + SetDefaults_ResourceList(&a.VolumeSource.Ephemeral.VolumeClaimTemplate.Spec.Resources.Requests) + } + } + } + for i := range in.Spec.Template.Spec.InitContainers { + a := &in.Spec.Template.Spec.InitContainers[i] + SetDefaults_Container(a) + for j := range a.Ports { + b := &a.Ports[j] + if b.Protocol == "" { + b.Protocol = "TCP" + } + } + for j := range a.Env { + b := &a.Env[j] + if b.ValueFrom != nil { + if b.ValueFrom.FieldRef != nil { + SetDefaults_ObjectFieldSelector(b.ValueFrom.FieldRef) + } + } + } + SetDefaults_ResourceList(&a.Resources.Limits) + SetDefaults_ResourceList(&a.Resources.Requests) + if a.LivenessProbe != nil { + SetDefaults_Probe(a.LivenessProbe) + if a.LivenessProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.LivenessProbe.ProbeHandler.HTTPGet) + } + if a.LivenessProbe.ProbeHandler.GRPC != nil { + if a.LivenessProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.LivenessProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.ReadinessProbe != nil { + SetDefaults_Probe(a.ReadinessProbe) + if a.ReadinessProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.ReadinessProbe.ProbeHandler.HTTPGet) + } + if a.ReadinessProbe.ProbeHandler.GRPC != nil { + if a.ReadinessProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.ReadinessProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.StartupProbe != nil { + SetDefaults_Probe(a.StartupProbe) + if a.StartupProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.StartupProbe.ProbeHandler.HTTPGet) + } + if a.StartupProbe.ProbeHandler.GRPC != nil { + if a.StartupProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.StartupProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.Lifecycle != nil { + if a.Lifecycle.PostStart != nil { + if a.Lifecycle.PostStart.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.Lifecycle.PostStart.HTTPGet) + } + } + if a.Lifecycle.PreStop != nil { + if a.Lifecycle.PreStop.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.Lifecycle.PreStop.HTTPGet) + } + } + } + } + for i := range in.Spec.Template.Spec.Containers { + a := &in.Spec.Template.Spec.Containers[i] + SetDefaults_Container(a) + for j := range a.Ports { + b := &a.Ports[j] + if b.Protocol == "" { + b.Protocol = "TCP" + } + } + for j := range a.Env { + b := &a.Env[j] + if b.ValueFrom != nil { + if b.ValueFrom.FieldRef != nil { + SetDefaults_ObjectFieldSelector(b.ValueFrom.FieldRef) + } + } + } + SetDefaults_ResourceList(&a.Resources.Limits) + SetDefaults_ResourceList(&a.Resources.Requests) + if a.LivenessProbe != nil { + SetDefaults_Probe(a.LivenessProbe) + if a.LivenessProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.LivenessProbe.ProbeHandler.HTTPGet) + } + if a.LivenessProbe.ProbeHandler.GRPC != nil { + if a.LivenessProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.LivenessProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.ReadinessProbe != nil { + SetDefaults_Probe(a.ReadinessProbe) + if a.ReadinessProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.ReadinessProbe.ProbeHandler.HTTPGet) + } + if a.ReadinessProbe.ProbeHandler.GRPC != nil { + if a.ReadinessProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.ReadinessProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.StartupProbe != nil { + SetDefaults_Probe(a.StartupProbe) + if a.StartupProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.StartupProbe.ProbeHandler.HTTPGet) + } + if a.StartupProbe.ProbeHandler.GRPC != nil { + if a.StartupProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.StartupProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.Lifecycle != nil { + if a.Lifecycle.PostStart != nil { + if a.Lifecycle.PostStart.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.Lifecycle.PostStart.HTTPGet) + } + } + if a.Lifecycle.PreStop != nil { + if a.Lifecycle.PreStop.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.Lifecycle.PreStop.HTTPGet) + } + } + } + } + for i := range in.Spec.Template.Spec.EphemeralContainers { + a := &in.Spec.Template.Spec.EphemeralContainers[i] + SetDefaults_EphemeralContainer(a) + for j := range a.EphemeralContainerCommon.Ports { + b := &a.EphemeralContainerCommon.Ports[j] + if b.Protocol == "" { + b.Protocol = "TCP" + } + } + for j := range a.EphemeralContainerCommon.Env { + b := &a.EphemeralContainerCommon.Env[j] + if b.ValueFrom != nil { + if b.ValueFrom.FieldRef != nil { + SetDefaults_ObjectFieldSelector(b.ValueFrom.FieldRef) + } + } + } + SetDefaults_ResourceList(&a.EphemeralContainerCommon.Resources.Limits) + SetDefaults_ResourceList(&a.EphemeralContainerCommon.Resources.Requests) + if a.EphemeralContainerCommon.LivenessProbe != nil { + SetDefaults_Probe(a.EphemeralContainerCommon.LivenessProbe) + if a.EphemeralContainerCommon.LivenessProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.EphemeralContainerCommon.LivenessProbe.ProbeHandler.HTTPGet) + } + if a.EphemeralContainerCommon.LivenessProbe.ProbeHandler.GRPC != nil { + if a.EphemeralContainerCommon.LivenessProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.EphemeralContainerCommon.LivenessProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.EphemeralContainerCommon.ReadinessProbe != nil { + SetDefaults_Probe(a.EphemeralContainerCommon.ReadinessProbe) + if a.EphemeralContainerCommon.ReadinessProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.EphemeralContainerCommon.ReadinessProbe.ProbeHandler.HTTPGet) + } + if a.EphemeralContainerCommon.ReadinessProbe.ProbeHandler.GRPC != nil { + if a.EphemeralContainerCommon.ReadinessProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.EphemeralContainerCommon.ReadinessProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.EphemeralContainerCommon.StartupProbe != nil { + SetDefaults_Probe(a.EphemeralContainerCommon.StartupProbe) + if a.EphemeralContainerCommon.StartupProbe.ProbeHandler.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.EphemeralContainerCommon.StartupProbe.ProbeHandler.HTTPGet) + } + if a.EphemeralContainerCommon.StartupProbe.ProbeHandler.GRPC != nil { + if a.EphemeralContainerCommon.StartupProbe.ProbeHandler.GRPC.Service == nil { + var ptrVar1 string = "" + a.EphemeralContainerCommon.StartupProbe.ProbeHandler.GRPC.Service = &ptrVar1 + } + } + } + if a.EphemeralContainerCommon.Lifecycle != nil { + if a.EphemeralContainerCommon.Lifecycle.PostStart != nil { + if a.EphemeralContainerCommon.Lifecycle.PostStart.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.EphemeralContainerCommon.Lifecycle.PostStart.HTTPGet) + } + } + if a.EphemeralContainerCommon.Lifecycle.PreStop != nil { + if a.EphemeralContainerCommon.Lifecycle.PreStop.HTTPGet != nil { + SetDefaults_HTTPGetAction(a.EphemeralContainerCommon.Lifecycle.PreStop.HTTPGet) + } + } + } + } + SetDefaults_ResourceList(&in.Spec.Template.Spec.Overhead) + } +} + +func SetObjectDefaults_ReplicationControllerList(in *v1.ReplicationControllerList) { + for i := range in.Items { + a := &in.Items[i] + SetObjectDefaults_ReplicationController(a) + } +} + +func SetObjectDefaults_ResourceQuota(in *v1.ResourceQuota) { + SetDefaults_ResourceList(&in.Spec.Hard) + SetDefaults_ResourceList(&in.Status.Hard) + SetDefaults_ResourceList(&in.Status.Used) +} + +func SetObjectDefaults_ResourceQuotaList(in *v1.ResourceQuotaList) { + for i := range in.Items { + a := &in.Items[i] + SetObjectDefaults_ResourceQuota(a) + } +} + +func SetObjectDefaults_Secret(in *v1.Secret) { + SetDefaults_Secret(in) +} + +func SetObjectDefaults_SecretList(in *v1.SecretList) { + for i := range in.Items { + a := &in.Items[i] + SetObjectDefaults_Secret(a) + } +} + +func SetObjectDefaults_Service(in *v1.Service) { + SetDefaults_Service(in) + for i := range in.Spec.Ports { + a := &in.Spec.Ports[i] + if a.Protocol == "" { + a.Protocol = "TCP" + } + } +} + +func SetObjectDefaults_ServiceList(in *v1.ServiceList) { + for i := range in.Items { + a := &in.Items[i] + SetObjectDefaults_Service(a) + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/validation/OWNERS b/vendor/k8s.io/kubernetes/pkg/apis/core/validation/OWNERS new file mode 100644 index 000000000..054fa14fa --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/validation/OWNERS @@ -0,0 +1,22 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +reviewers: + - thockin + - lavalamp + - smarterclayton + - wojtek-t + - deads2k + - yujuhong + - derekwaynecarr + - caesarxuchao + - mikedanese + - liggitt + - sttts + - dchen1107 + - janetkuo + - justinsb + - pwittrock + - tallclair + - soltysh + - jsafrane + - dims diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/validation/doc.go b/vendor/k8s.io/kubernetes/pkg/apis/core/validation/doc.go new file mode 100644 index 000000000..0c1cfaab5 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/validation/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2014 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 validation has functions for validating the correctness of api +// objects and explaining what is wrong with them when they aren't valid. +package validation // import "k8s.io/kubernetes/pkg/apis/core/validation" diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/validation/events.go b/vendor/k8s.io/kubernetes/pkg/apis/core/validation/events.go new file mode 100644 index 000000000..d2578f229 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/validation/events.go @@ -0,0 +1,193 @@ +/* +Copyright 2014 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 validation + +import ( + "fmt" + "reflect" + "time" + + v1 "k8s.io/api/core/v1" + eventsv1beta1 "k8s.io/api/events/v1beta1" + apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/validation" + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/kubernetes/pkg/apis/core" +) + +const ( + ReportingInstanceLengthLimit = 128 + ActionLengthLimit = 128 + ReasonLengthLimit = 128 + NoteLengthLimit = 1024 +) + +func ValidateEventCreate(event *core.Event, requestVersion schema.GroupVersion) field.ErrorList { + // Make sure events always pass legacy validation. + allErrs := legacyValidateEvent(event, requestVersion) + if requestVersion == v1.SchemeGroupVersion || requestVersion == eventsv1beta1.SchemeGroupVersion { + // No further validation for backwards compatibility. + return allErrs + } + + // Strict validation applies to creation via events.k8s.io/v1 API and newer. + allErrs = append(allErrs, ValidateObjectMeta(&event.ObjectMeta, true, apimachineryvalidation.NameIsDNSSubdomain, field.NewPath("metadata"))...) + allErrs = append(allErrs, validateV1EventSeries(event)...) + zeroTime := time.Time{} + if event.EventTime.Time == zeroTime { + allErrs = append(allErrs, field.Required(field.NewPath("eventTime"), "")) + } + if event.Type != v1.EventTypeNormal && event.Type != v1.EventTypeWarning { + allErrs = append(allErrs, field.Invalid(field.NewPath("type"), "", fmt.Sprintf("has invalid value: %v", event.Type))) + } + if event.FirstTimestamp.Time != zeroTime { + allErrs = append(allErrs, field.Invalid(field.NewPath("firstTimestamp"), "", "needs to be unset")) + } + if event.LastTimestamp.Time != zeroTime { + allErrs = append(allErrs, field.Invalid(field.NewPath("lastTimestamp"), "", "needs to be unset")) + } + if event.Count != 0 { + allErrs = append(allErrs, field.Invalid(field.NewPath("count"), "", "needs to be unset")) + } + if event.Source.Component != "" || event.Source.Host != "" { + allErrs = append(allErrs, field.Invalid(field.NewPath("source"), "", "needs to be unset")) + } + return allErrs +} + +func ValidateEventUpdate(newEvent, oldEvent *core.Event, requestVersion schema.GroupVersion) field.ErrorList { + // Make sure the new event always passes legacy validation. + allErrs := legacyValidateEvent(newEvent, requestVersion) + if requestVersion == v1.SchemeGroupVersion || requestVersion == eventsv1beta1.SchemeGroupVersion { + // No further validation for backwards compatibility. + return allErrs + } + + // Strict validation applies to update via events.k8s.io/v1 API and newer. + allErrs = append(allErrs, ValidateObjectMetaUpdate(&newEvent.ObjectMeta, &oldEvent.ObjectMeta, field.NewPath("metadata"))...) + // if the series was modified, validate the new data + if !reflect.DeepEqual(newEvent.Series, oldEvent.Series) { + allErrs = append(allErrs, validateV1EventSeries(newEvent)...) + } + + allErrs = append(allErrs, ValidateImmutableField(newEvent.InvolvedObject, oldEvent.InvolvedObject, field.NewPath("involvedObject"))...) + allErrs = append(allErrs, ValidateImmutableField(newEvent.Reason, oldEvent.Reason, field.NewPath("reason"))...) + allErrs = append(allErrs, ValidateImmutableField(newEvent.Message, oldEvent.Message, field.NewPath("message"))...) + allErrs = append(allErrs, ValidateImmutableField(newEvent.Source, oldEvent.Source, field.NewPath("source"))...) + allErrs = append(allErrs, ValidateImmutableField(newEvent.FirstTimestamp, oldEvent.FirstTimestamp, field.NewPath("firstTimestamp"))...) + allErrs = append(allErrs, ValidateImmutableField(newEvent.LastTimestamp, oldEvent.LastTimestamp, field.NewPath("lastTimestamp"))...) + allErrs = append(allErrs, ValidateImmutableField(newEvent.Count, oldEvent.Count, field.NewPath("count"))...) + allErrs = append(allErrs, ValidateImmutableField(newEvent.Reason, oldEvent.Reason, field.NewPath("reason"))...) + allErrs = append(allErrs, ValidateImmutableField(newEvent.Type, oldEvent.Type, field.NewPath("type"))...) + + // Disallow changes to eventTime greater than microsecond-level precision. + // Tolerating sub-microsecond changes is required to tolerate updates + // from clients that correctly truncate to microsecond-precision when serializing, + // or from clients built with incorrect nanosecond-precision protobuf serialization. + // See https://github.com/kubernetes/kubernetes/issues/111928 + newTruncated := newEvent.EventTime.Truncate(time.Microsecond).UTC() + oldTruncated := oldEvent.EventTime.Truncate(time.Microsecond).UTC() + if newTruncated != oldTruncated { + allErrs = append(allErrs, ValidateImmutableField(newEvent.EventTime, oldEvent.EventTime, field.NewPath("eventTime"))...) + } + + allErrs = append(allErrs, ValidateImmutableField(newEvent.Action, oldEvent.Action, field.NewPath("action"))...) + allErrs = append(allErrs, ValidateImmutableField(newEvent.Related, oldEvent.Related, field.NewPath("related"))...) + allErrs = append(allErrs, ValidateImmutableField(newEvent.ReportingController, oldEvent.ReportingController, field.NewPath("reportingController"))...) + allErrs = append(allErrs, ValidateImmutableField(newEvent.ReportingInstance, oldEvent.ReportingInstance, field.NewPath("reportingInstance"))...) + + return allErrs +} + +func validateV1EventSeries(event *core.Event) field.ErrorList { + allErrs := field.ErrorList{} + zeroTime := time.Time{} + if event.Series != nil { + if event.Series.Count < 2 { + allErrs = append(allErrs, field.Invalid(field.NewPath("series.count"), "", "should be at least 2")) + } + if event.Series.LastObservedTime.Time == zeroTime { + allErrs = append(allErrs, field.Required(field.NewPath("series.lastObservedTime"), "")) + } + } + return allErrs +} + +// legacyValidateEvent makes sure that the event makes sense. +func legacyValidateEvent(event *core.Event, requestVersion schema.GroupVersion) field.ErrorList { + allErrs := field.ErrorList{} + // Because go + zeroTime := time.Time{} + + reportingControllerFieldName := "reportingController" + if requestVersion == v1.SchemeGroupVersion { + reportingControllerFieldName = "reportingComponent" + } + + // "New" Events need to have EventTime set, so it's validating old object. + if event.EventTime.Time == zeroTime { + // Make sure event.Namespace and the involvedInvolvedObject.Namespace agree + if len(event.InvolvedObject.Namespace) == 0 { + // event.Namespace must also be empty (or "default", for compatibility with old clients) + if event.Namespace != metav1.NamespaceNone && event.Namespace != metav1.NamespaceDefault { + allErrs = append(allErrs, field.Invalid(field.NewPath("involvedObject", "namespace"), event.InvolvedObject.Namespace, "does not match event.namespace")) + } + } else { + // event namespace must match + if event.Namespace != event.InvolvedObject.Namespace { + allErrs = append(allErrs, field.Invalid(field.NewPath("involvedObject", "namespace"), event.InvolvedObject.Namespace, "does not match event.namespace")) + } + } + + } else { + if len(event.InvolvedObject.Namespace) == 0 && event.Namespace != metav1.NamespaceDefault && event.Namespace != metav1.NamespaceSystem { + allErrs = append(allErrs, field.Invalid(field.NewPath("involvedObject", "namespace"), event.InvolvedObject.Namespace, "does not match event.namespace")) + } + if len(event.ReportingController) == 0 { + allErrs = append(allErrs, field.Required(field.NewPath(reportingControllerFieldName), "")) + } + allErrs = append(allErrs, ValidateQualifiedName(event.ReportingController, field.NewPath(reportingControllerFieldName))...) + if len(event.ReportingInstance) == 0 { + allErrs = append(allErrs, field.Required(field.NewPath("reportingInstance"), "")) + } + if len(event.ReportingInstance) > ReportingInstanceLengthLimit { + allErrs = append(allErrs, field.Invalid(field.NewPath("reportingInstance"), "", fmt.Sprintf("can have at most %v characters", ReportingInstanceLengthLimit))) + } + if len(event.Action) == 0 { + allErrs = append(allErrs, field.Required(field.NewPath("action"), "")) + } + if len(event.Action) > ActionLengthLimit { + allErrs = append(allErrs, field.Invalid(field.NewPath("action"), "", fmt.Sprintf("can have at most %v characters", ActionLengthLimit))) + } + if len(event.Reason) == 0 { + allErrs = append(allErrs, field.Required(field.NewPath("reason"), "")) + } + if len(event.Reason) > ReasonLengthLimit { + allErrs = append(allErrs, field.Invalid(field.NewPath("reason"), "", fmt.Sprintf("can have at most %v characters", ReasonLengthLimit))) + } + if len(event.Message) > NoteLengthLimit { + allErrs = append(allErrs, field.Invalid(field.NewPath("message"), "", fmt.Sprintf("can have at most %v characters", NoteLengthLimit))) + } + } + + for _, msg := range validation.IsDNS1123Subdomain(event.Namespace) { + allErrs = append(allErrs, field.Invalid(field.NewPath("namespace"), event.Namespace, msg)) + } + return allErrs +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/validation/validation.go b/vendor/k8s.io/kubernetes/pkg/apis/core/validation/validation.go new file mode 100644 index 000000000..1668db832 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/validation/validation.go @@ -0,0 +1,7174 @@ +/* +Copyright 2014 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 validation + +import ( + "encoding/json" + "fmt" + "math" + "net" + "path" + "path/filepath" + "reflect" + "regexp" + "strings" + "unicode" + "unicode/utf8" + + "github.com/google/go-cmp/cmp" + v1 "k8s.io/api/core/v1" + apiequality "k8s.io/apimachinery/pkg/api/equality" + "k8s.io/apimachinery/pkg/api/resource" + apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + unversionedvalidation "k8s.io/apimachinery/pkg/apis/meta/v1/validation" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/validation" + "k8s.io/apimachinery/pkg/util/validation/field" + utilfeature "k8s.io/apiserver/pkg/util/feature" + schedulinghelper "k8s.io/component-helpers/scheduling/corev1" + apiservice "k8s.io/kubernetes/pkg/api/service" + "k8s.io/kubernetes/pkg/apis/core" + "k8s.io/kubernetes/pkg/apis/core/helper" + podshelper "k8s.io/kubernetes/pkg/apis/core/pods" + corev1 "k8s.io/kubernetes/pkg/apis/core/v1" + "k8s.io/kubernetes/pkg/capabilities" + "k8s.io/kubernetes/pkg/cluster/ports" + "k8s.io/kubernetes/pkg/features" + "k8s.io/kubernetes/pkg/fieldpath" + netutils "k8s.io/utils/net" +) + +const isNegativeErrorMsg string = apimachineryvalidation.IsNegativeErrorMsg +const isInvalidQuotaResource string = `must be a standard resource for quota` +const fieldImmutableErrorMsg string = apimachineryvalidation.FieldImmutableErrorMsg +const isNotIntegerErrorMsg string = `must be an integer` +const isNotPositiveErrorMsg string = `must be greater than zero` + +var pdPartitionErrorMsg string = validation.InclusiveRangeError(1, 255) +var fileModeErrorMsg = "must be a number between 0 and 0777 (octal), both inclusive" + +// BannedOwners is a black list of object that are not allowed to be owners. +var BannedOwners = apimachineryvalidation.BannedOwners + +var iscsiInitiatorIqnRegex = regexp.MustCompile(`iqn\.\d{4}-\d{2}\.([[:alnum:]-.]+)(:[^,;*&$|\s]+)$`) +var iscsiInitiatorEuiRegex = regexp.MustCompile(`^eui.[[:alnum:]]{16}$`) +var iscsiInitiatorNaaRegex = regexp.MustCompile(`^naa.[[:alnum:]]{32}$`) + +var allowedEphemeralContainerFields = map[string]bool{ + "Name": true, + "Image": true, + "Command": true, + "Args": true, + "WorkingDir": true, + "Ports": false, + "EnvFrom": true, + "Env": true, + "Resources": false, + "VolumeMounts": true, + "VolumeDevices": true, + "LivenessProbe": false, + "ReadinessProbe": false, + "StartupProbe": false, + "Lifecycle": false, + "TerminationMessagePath": true, + "TerminationMessagePolicy": true, + "ImagePullPolicy": true, + "SecurityContext": true, + "Stdin": true, + "StdinOnce": true, + "TTY": true, +} + +// validOS stores the set of valid OSes within pod spec. +// The valid values currently are linux, windows. +// In future, they can be expanded to values from +// https://github.com/opencontainers/runtime-spec/blob/master/config.md#platform-specific-configuration +var validOS = sets.NewString(string(core.Linux), string(core.Windows)) + +// ValidateHasLabel requires that metav1.ObjectMeta has a Label with key and expectedValue +func ValidateHasLabel(meta metav1.ObjectMeta, fldPath *field.Path, key, expectedValue string) field.ErrorList { + allErrs := field.ErrorList{} + actualValue, found := meta.Labels[key] + if !found { + allErrs = append(allErrs, field.Required(fldPath.Child("labels").Key(key), + fmt.Sprintf("must be '%s'", expectedValue))) + return allErrs + } + if actualValue != expectedValue { + allErrs = append(allErrs, field.Invalid(fldPath.Child("labels").Key(key), meta.Labels, + fmt.Sprintf("must be '%s'", expectedValue))) + } + return allErrs +} + +// ValidateAnnotations validates that a set of annotations are correctly defined. +func ValidateAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList { + return apimachineryvalidation.ValidateAnnotations(annotations, fldPath) +} + +func ValidateDNS1123Label(value string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + for _, msg := range validation.IsDNS1123Label(value) { + allErrs = append(allErrs, field.Invalid(fldPath, value, msg)) + } + return allErrs +} + +// ValidateQualifiedName validates if name is what Kubernetes calls a "qualified name". +func ValidateQualifiedName(value string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + for _, msg := range validation.IsQualifiedName(value) { + allErrs = append(allErrs, field.Invalid(fldPath, value, msg)) + } + return allErrs +} + +// ValidateDNS1123Subdomain validates that a name is a proper DNS subdomain. +func ValidateDNS1123Subdomain(value string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + for _, msg := range validation.IsDNS1123Subdomain(value) { + allErrs = append(allErrs, field.Invalid(fldPath, value, msg)) + } + return allErrs +} + +func ValidatePodSpecificAnnotations(annotations map[string]string, spec *core.PodSpec, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { + allErrs := field.ErrorList{} + + if value, isMirror := annotations[core.MirrorPodAnnotationKey]; isMirror { + if len(spec.NodeName) == 0 { + allErrs = append(allErrs, field.Invalid(fldPath.Key(core.MirrorPodAnnotationKey), value, "must set spec.nodeName if mirror pod annotation is set")) + } + } + + if annotations[core.TolerationsAnnotationKey] != "" { + allErrs = append(allErrs, ValidateTolerationsInPodAnnotations(annotations, fldPath)...) + } + + if !opts.AllowInvalidPodDeletionCost { + if _, err := helper.GetDeletionCostFromPodAnnotations(annotations); err != nil { + allErrs = append(allErrs, field.Invalid(fldPath.Key(core.PodDeletionCost), annotations[core.PodDeletionCost], "must be a 32bit integer")) + } + } + + allErrs = append(allErrs, ValidateSeccompPodAnnotations(annotations, fldPath)...) + allErrs = append(allErrs, ValidateAppArmorPodAnnotations(annotations, spec, fldPath)...) + + return allErrs +} + +// ValidateTolerationsInPodAnnotations tests that the serialized tolerations in Pod.Annotations has valid data +func ValidateTolerationsInPodAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + tolerations, err := helper.GetTolerationsFromPodAnnotations(annotations) + if err != nil { + allErrs = append(allErrs, field.Invalid(fldPath, core.TolerationsAnnotationKey, err.Error())) + return allErrs + } + + if len(tolerations) > 0 { + allErrs = append(allErrs, ValidateTolerations(tolerations, fldPath.Child(core.TolerationsAnnotationKey))...) + } + + return allErrs +} + +func ValidatePodSpecificAnnotationUpdates(newPod, oldPod *core.Pod, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { + allErrs := field.ErrorList{} + newAnnotations := newPod.Annotations + oldAnnotations := oldPod.Annotations + for k, oldVal := range oldAnnotations { + if newVal, exists := newAnnotations[k]; exists && newVal == oldVal { + continue // No change. + } + if strings.HasPrefix(k, v1.AppArmorBetaContainerAnnotationKeyPrefix) { + allErrs = append(allErrs, field.Forbidden(fldPath.Key(k), "may not remove or update AppArmor annotations")) + } + if k == core.MirrorPodAnnotationKey { + allErrs = append(allErrs, field.Forbidden(fldPath.Key(k), "may not remove or update mirror pod annotation")) + } + } + // Check for additions + for k := range newAnnotations { + if _, ok := oldAnnotations[k]; ok { + continue // No change. + } + if strings.HasPrefix(k, v1.AppArmorBetaContainerAnnotationKeyPrefix) { + allErrs = append(allErrs, field.Forbidden(fldPath.Key(k), "may not add AppArmor annotations")) + } + if k == core.MirrorPodAnnotationKey { + allErrs = append(allErrs, field.Forbidden(fldPath.Key(k), "may not add mirror pod annotation")) + } + } + allErrs = append(allErrs, ValidatePodSpecificAnnotations(newAnnotations, &newPod.Spec, fldPath, opts)...) + return allErrs +} + +func ValidateEndpointsSpecificAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + return allErrs +} + +// ValidateNameFunc validates that the provided name is valid for a given resource type. +// Not all resources have the same validation rules for names. Prefix is true +// if the name will have a value appended to it. If the name is not valid, +// this returns a list of descriptions of individual characteristics of the +// value that were not valid. Otherwise this returns an empty list or nil. +type ValidateNameFunc apimachineryvalidation.ValidateNameFunc + +// ValidatePodName can be used to check whether the given pod name is valid. +// Prefix indicates this name will be used as part of generation, in which case +// trailing dashes are allowed. +var ValidatePodName = apimachineryvalidation.NameIsDNSSubdomain + +// ValidateReplicationControllerName can be used to check whether the given replication +// controller name is valid. +// Prefix indicates this name will be used as part of generation, in which case +// trailing dashes are allowed. +var ValidateReplicationControllerName = apimachineryvalidation.NameIsDNSSubdomain + +// ValidateServiceName can be used to check whether the given service name is valid. +// Prefix indicates this name will be used as part of generation, in which case +// trailing dashes are allowed. +var ValidateServiceName = apimachineryvalidation.NameIsDNS1035Label + +// ValidateNodeName can be used to check whether the given node name is valid. +// Prefix indicates this name will be used as part of generation, in which case +// trailing dashes are allowed. +var ValidateNodeName = apimachineryvalidation.NameIsDNSSubdomain + +// ValidateNamespaceName can be used to check whether the given namespace name is valid. +// Prefix indicates this name will be used as part of generation, in which case +// trailing dashes are allowed. +var ValidateNamespaceName = apimachineryvalidation.ValidateNamespaceName + +// ValidateLimitRangeName can be used to check whether the given limit range name is valid. +// Prefix indicates this name will be used as part of generation, in which case +// trailing dashes are allowed. +var ValidateLimitRangeName = apimachineryvalidation.NameIsDNSSubdomain + +// ValidateResourceQuotaName can be used to check whether the given +// resource quota name is valid. +// Prefix indicates this name will be used as part of generation, in which case +// trailing dashes are allowed. +var ValidateResourceQuotaName = apimachineryvalidation.NameIsDNSSubdomain + +// ValidateSecretName can be used to check whether the given secret name is valid. +// Prefix indicates this name will be used as part of generation, in which case +// trailing dashes are allowed. +var ValidateSecretName = apimachineryvalidation.NameIsDNSSubdomain + +// ValidateServiceAccountName can be used to check whether the given service account name is valid. +// Prefix indicates this name will be used as part of generation, in which case +// trailing dashes are allowed. +var ValidateServiceAccountName = apimachineryvalidation.ValidateServiceAccountName + +// ValidateEndpointsName can be used to check whether the given endpoints name is valid. +// Prefix indicates this name will be used as part of generation, in which case +// trailing dashes are allowed. +var ValidateEndpointsName = apimachineryvalidation.NameIsDNSSubdomain + +// ValidateClassName can be used to check whether the given class name is valid. +// It is defined here to avoid import cycle between pkg/apis/storage/validation +// (where it should be) and this file. +var ValidateClassName = apimachineryvalidation.NameIsDNSSubdomain + +// ValidatePriorityClassName can be used to check whether the given priority +// class name is valid. +var ValidatePriorityClassName = apimachineryvalidation.NameIsDNSSubdomain + +// ValidateRuntimeClassName can be used to check whether the given RuntimeClass name is valid. +// Prefix indicates this name will be used as part of generation, in which case +// trailing dashes are allowed. +func ValidateRuntimeClassName(name string, fldPath *field.Path) field.ErrorList { + var allErrs field.ErrorList + for _, msg := range apimachineryvalidation.NameIsDNSSubdomain(name, false) { + allErrs = append(allErrs, field.Invalid(fldPath, name, msg)) + } + return allErrs +} + +// validateOverhead can be used to check whether the given Overhead is valid. +func validateOverhead(overhead core.ResourceList, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { + // reuse the ResourceRequirements validation logic + return ValidateResourceRequirements(&core.ResourceRequirements{Limits: overhead}, nil, fldPath, opts) +} + +// Validates that given value is not negative. +func ValidateNonnegativeField(value int64, fldPath *field.Path) field.ErrorList { + return apimachineryvalidation.ValidateNonnegativeField(value, fldPath) +} + +// Validates that a Quantity is not negative +func ValidateNonnegativeQuantity(value resource.Quantity, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if value.Cmp(resource.Quantity{}) < 0 { + allErrs = append(allErrs, field.Invalid(fldPath, value.String(), isNegativeErrorMsg)) + } + return allErrs +} + +// Validates that a Quantity is positive +func ValidatePositiveQuantityValue(value resource.Quantity, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if value.Cmp(resource.Quantity{}) <= 0 { + allErrs = append(allErrs, field.Invalid(fldPath, value.String(), isNotPositiveErrorMsg)) + } + return allErrs +} + +func ValidateImmutableField(newVal, oldVal interface{}, fldPath *field.Path) field.ErrorList { + return apimachineryvalidation.ValidateImmutableField(newVal, oldVal, fldPath) +} + +func ValidateImmutableAnnotation(newVal string, oldVal string, annotation string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + if oldVal != newVal { + allErrs = append(allErrs, field.Invalid(fldPath.Child("annotations", annotation), newVal, fieldImmutableErrorMsg)) + } + return allErrs +} + +// ValidateObjectMeta validates an object's metadata on creation. It expects that name generation has already +// been performed. +// It doesn't return an error for rootscoped resources with namespace, because namespace should already be cleared before. +// TODO: Remove calls to this method scattered in validations of specific resources, e.g., ValidatePodUpdate. +func ValidateObjectMeta(meta *metav1.ObjectMeta, requiresNamespace bool, nameFn ValidateNameFunc, fldPath *field.Path) field.ErrorList { + allErrs := apimachineryvalidation.ValidateObjectMeta(meta, requiresNamespace, apimachineryvalidation.ValidateNameFunc(nameFn), fldPath) + // run additional checks for the finalizer name + for i := range meta.Finalizers { + allErrs = append(allErrs, validateKubeFinalizerName(string(meta.Finalizers[i]), fldPath.Child("finalizers").Index(i))...) + } + return allErrs +} + +// ValidateObjectMetaUpdate validates an object's metadata when updated +func ValidateObjectMetaUpdate(newMeta, oldMeta *metav1.ObjectMeta, fldPath *field.Path) field.ErrorList { + allErrs := apimachineryvalidation.ValidateObjectMetaUpdate(newMeta, oldMeta, fldPath) + // run additional checks for the finalizer name + for i := range newMeta.Finalizers { + allErrs = append(allErrs, validateKubeFinalizerName(string(newMeta.Finalizers[i]), fldPath.Child("finalizers").Index(i))...) + } + + return allErrs +} + +func ValidateVolumes(volumes []core.Volume, podMeta *metav1.ObjectMeta, fldPath *field.Path, opts PodValidationOptions) (map[string]core.VolumeSource, field.ErrorList) { + allErrs := field.ErrorList{} + + allNames := sets.String{} + allCreatedPVCs := sets.String{} + // Determine which PVCs will be created for this pod. We need + // the exact name of the pod for this. Without it, this sanity + // check has to be skipped. + if podMeta != nil && podMeta.Name != "" { + for _, vol := range volumes { + if vol.VolumeSource.Ephemeral != nil { + allCreatedPVCs.Insert(podMeta.Name + "-" + vol.Name) + } + } + } + vols := make(map[string]core.VolumeSource) + for i, vol := range volumes { + idxPath := fldPath.Index(i) + namePath := idxPath.Child("name") + el := validateVolumeSource(&vol.VolumeSource, idxPath, vol.Name, podMeta, opts) + if len(vol.Name) == 0 { + el = append(el, field.Required(namePath, "")) + } else { + el = append(el, ValidateDNS1123Label(vol.Name, namePath)...) + } + if allNames.Has(vol.Name) { + el = append(el, field.Duplicate(namePath, vol.Name)) + } + if len(el) == 0 { + allNames.Insert(vol.Name) + vols[vol.Name] = vol.VolumeSource + } else { + allErrs = append(allErrs, el...) + } + // A PersistentVolumeClaimSource should not reference a created PVC. That doesn't + // make sense. + if vol.PersistentVolumeClaim != nil && allCreatedPVCs.Has(vol.PersistentVolumeClaim.ClaimName) { + allErrs = append(allErrs, field.Invalid(idxPath.Child("persistentVolumeClaim").Child("claimName"), vol.PersistentVolumeClaim.ClaimName, + "must not reference a PVC that gets created for an ephemeral volume")) + } + } + + return vols, allErrs +} + +func IsMatchedVolume(name string, volumes map[string]core.VolumeSource) bool { + if _, ok := volumes[name]; ok { + return true + } + return false +} + +// isMatched checks whether the volume with the given name is used by a +// container and if so, if it involves a PVC. +func isMatchedDevice(name string, volumes map[string]core.VolumeSource) (isMatched bool, isPVC bool) { + if source, ok := volumes[name]; ok { + if source.PersistentVolumeClaim != nil || + source.Ephemeral != nil { + return true, true + } + return true, false + } + return false, false +} + +func mountNameAlreadyExists(name string, devices map[string]string) bool { + if _, ok := devices[name]; ok { + return true + } + return false +} + +func mountPathAlreadyExists(mountPath string, devices map[string]string) bool { + for _, devPath := range devices { + if mountPath == devPath { + return true + } + } + + return false +} + +func deviceNameAlreadyExists(name string, mounts map[string]string) bool { + if _, ok := mounts[name]; ok { + return true + } + return false +} + +func devicePathAlreadyExists(devicePath string, mounts map[string]string) bool { + for _, mountPath := range mounts { + if mountPath == devicePath { + return true + } + } + + return false +} + +func validateVolumeSource(source *core.VolumeSource, fldPath *field.Path, volName string, podMeta *metav1.ObjectMeta, opts PodValidationOptions) field.ErrorList { + numVolumes := 0 + allErrs := field.ErrorList{} + if source.EmptyDir != nil { + numVolumes++ + if source.EmptyDir.SizeLimit != nil && source.EmptyDir.SizeLimit.Cmp(resource.Quantity{}) < 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("emptyDir").Child("sizeLimit"), "SizeLimit field must be a valid resource quantity")) + } + } + if source.HostPath != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("hostPath"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateHostPathVolumeSource(source.HostPath, fldPath.Child("hostPath"))...) + } + } + if source.GitRepo != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("gitRepo"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateGitRepoVolumeSource(source.GitRepo, fldPath.Child("gitRepo"))...) + } + } + if source.GCEPersistentDisk != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("gcePersistentDisk"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateGCEPersistentDiskVolumeSource(source.GCEPersistentDisk, fldPath.Child("persistentDisk"))...) + } + } + if source.AWSElasticBlockStore != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("awsElasticBlockStore"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateAWSElasticBlockStoreVolumeSource(source.AWSElasticBlockStore, fldPath.Child("awsElasticBlockStore"))...) + } + } + if source.Secret != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("secret"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateSecretVolumeSource(source.Secret, fldPath.Child("secret"))...) + } + } + if source.NFS != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("nfs"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateNFSVolumeSource(source.NFS, fldPath.Child("nfs"))...) + } + } + if source.ISCSI != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("iscsi"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateISCSIVolumeSource(source.ISCSI, fldPath.Child("iscsi"))...) + } + if source.ISCSI.InitiatorName != nil && len(volName+":"+source.ISCSI.TargetPortal) > 64 { + tooLongErr := "Total length of : must be under 64 characters if iscsi.initiatorName is specified." + allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), volName, tooLongErr)) + } + } + if source.Glusterfs != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("glusterfs"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateGlusterfsVolumeSource(source.Glusterfs, fldPath.Child("glusterfs"))...) + } + } + if source.Flocker != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("flocker"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateFlockerVolumeSource(source.Flocker, fldPath.Child("flocker"))...) + } + } + if source.PersistentVolumeClaim != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("persistentVolumeClaim"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validatePersistentClaimVolumeSource(source.PersistentVolumeClaim, fldPath.Child("persistentVolumeClaim"))...) + } + } + if source.RBD != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("rbd"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateRBDVolumeSource(source.RBD, fldPath.Child("rbd"))...) + } + } + if source.Cinder != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("cinder"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateCinderVolumeSource(source.Cinder, fldPath.Child("cinder"))...) + } + } + if source.CephFS != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("cephFS"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateCephFSVolumeSource(source.CephFS, fldPath.Child("cephfs"))...) + } + } + if source.Quobyte != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("quobyte"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateQuobyteVolumeSource(source.Quobyte, fldPath.Child("quobyte"))...) + } + } + if source.DownwardAPI != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("downwarAPI"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateDownwardAPIVolumeSource(source.DownwardAPI, fldPath.Child("downwardAPI"), opts)...) + } + } + if source.FC != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("fc"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateFCVolumeSource(source.FC, fldPath.Child("fc"))...) + } + } + if source.FlexVolume != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("flexVolume"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateFlexVolumeSource(source.FlexVolume, fldPath.Child("flexVolume"))...) + } + } + if source.ConfigMap != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("configMap"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateConfigMapVolumeSource(source.ConfigMap, fldPath.Child("configMap"))...) + } + } + + if source.AzureFile != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("azureFile"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateAzureFile(source.AzureFile, fldPath.Child("azureFile"))...) + } + } + + if source.VsphereVolume != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("vsphereVolume"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateVsphereVolumeSource(source.VsphereVolume, fldPath.Child("vsphereVolume"))...) + } + } + if source.PhotonPersistentDisk != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("photonPersistentDisk"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validatePhotonPersistentDiskVolumeSource(source.PhotonPersistentDisk, fldPath.Child("photonPersistentDisk"))...) + } + } + if source.PortworxVolume != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("portworxVolume"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validatePortworxVolumeSource(source.PortworxVolume, fldPath.Child("portworxVolume"))...) + } + } + if source.AzureDisk != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("azureDisk"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateAzureDisk(source.AzureDisk, fldPath.Child("azureDisk"))...) + } + } + if source.StorageOS != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("storageos"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateStorageOSVolumeSource(source.StorageOS, fldPath.Child("storageos"))...) + } + } + if source.Projected != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("projected"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateProjectedVolumeSource(source.Projected, fldPath.Child("projected"), opts)...) + } + } + if source.ScaleIO != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("scaleIO"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateScaleIOVolumeSource(source.ScaleIO, fldPath.Child("scaleIO"))...) + } + } + if source.CSI != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("csi"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateCSIVolumeSource(source.CSI, fldPath.Child("csi"))...) + } + } + if source.Ephemeral != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("ephemeral"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateEphemeralVolumeSource(source.Ephemeral, fldPath.Child("ephemeral"))...) + // Check the expected name for the PVC. This gets skipped if information is missing, + // because that already gets flagged as a problem elsewhere. For example, + // ValidateObjectMeta as called by validatePodMetadataAndSpec checks that the name is set. + if podMeta != nil && podMeta.Name != "" && volName != "" { + pvcName := podMeta.Name + "-" + volName + for _, msg := range ValidatePersistentVolumeName(pvcName, false) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), volName, fmt.Sprintf("PVC name %q: %v", pvcName, msg))) + } + } + } + } + + if numVolumes == 0 { + allErrs = append(allErrs, field.Required(fldPath, "must specify a volume type")) + } + + return allErrs +} + +func validateHostPathVolumeSource(hostPath *core.HostPathVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(hostPath.Path) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("path"), "")) + return allErrs + } + + allErrs = append(allErrs, validatePathNoBacksteps(hostPath.Path, fldPath.Child("path"))...) + allErrs = append(allErrs, validateHostPathType(hostPath.Type, fldPath.Child("type"))...) + return allErrs +} + +func validateGitRepoVolumeSource(gitRepo *core.GitRepoVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(gitRepo.Repository) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("repository"), "")) + } + + pathErrs := validateLocalDescendingPath(gitRepo.Directory, fldPath.Child("directory")) + allErrs = append(allErrs, pathErrs...) + return allErrs +} + +func validateISCSIVolumeSource(iscsi *core.ISCSIVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(iscsi.TargetPortal) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("targetPortal"), "")) + } + if len(iscsi.IQN) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("iqn"), "")) + } else { + if !strings.HasPrefix(iscsi.IQN, "iqn") && !strings.HasPrefix(iscsi.IQN, "eui") && !strings.HasPrefix(iscsi.IQN, "naa") { + allErrs = append(allErrs, field.Invalid(fldPath.Child("iqn"), iscsi.IQN, "must be valid format starting with iqn, eui, or naa")) + } else if strings.HasPrefix(iscsi.IQN, "iqn") && !iscsiInitiatorIqnRegex.MatchString(iscsi.IQN) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("iqn"), iscsi.IQN, "must be valid format")) + } else if strings.HasPrefix(iscsi.IQN, "eui") && !iscsiInitiatorEuiRegex.MatchString(iscsi.IQN) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("iqn"), iscsi.IQN, "must be valid format")) + } else if strings.HasPrefix(iscsi.IQN, "naa") && !iscsiInitiatorNaaRegex.MatchString(iscsi.IQN) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("iqn"), iscsi.IQN, "must be valid format")) + } + } + if iscsi.Lun < 0 || iscsi.Lun > 255 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("lun"), iscsi.Lun, validation.InclusiveRangeError(0, 255))) + } + if (iscsi.DiscoveryCHAPAuth || iscsi.SessionCHAPAuth) && iscsi.SecretRef == nil { + allErrs = append(allErrs, field.Required(fldPath.Child("secretRef"), "")) + } + if iscsi.InitiatorName != nil { + initiator := *iscsi.InitiatorName + if !strings.HasPrefix(initiator, "iqn") && !strings.HasPrefix(initiator, "eui") && !strings.HasPrefix(initiator, "naa") { + allErrs = append(allErrs, field.Invalid(fldPath.Child("initiatorname"), initiator, "must be valid format starting with iqn, eui, or naa")) + } + if strings.HasPrefix(initiator, "iqn") && !iscsiInitiatorIqnRegex.MatchString(initiator) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("initiatorname"), initiator, "must be valid format")) + } else if strings.HasPrefix(initiator, "eui") && !iscsiInitiatorEuiRegex.MatchString(initiator) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("initiatorname"), initiator, "must be valid format")) + } else if strings.HasPrefix(initiator, "naa") && !iscsiInitiatorNaaRegex.MatchString(initiator) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("initiatorname"), initiator, "must be valid format")) + } + } + return allErrs +} + +func validateISCSIPersistentVolumeSource(iscsi *core.ISCSIPersistentVolumeSource, pvName string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(iscsi.TargetPortal) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("targetPortal"), "")) + } + if iscsi.InitiatorName != nil && len(pvName+":"+iscsi.TargetPortal) > 64 { + tooLongErr := "Total length of : must be under 64 characters if iscsi.initiatorName is specified." + allErrs = append(allErrs, field.Invalid(fldPath.Child("targetportal"), iscsi.TargetPortal, tooLongErr)) + } + if len(iscsi.IQN) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("iqn"), "")) + } else { + if !strings.HasPrefix(iscsi.IQN, "iqn") && !strings.HasPrefix(iscsi.IQN, "eui") && !strings.HasPrefix(iscsi.IQN, "naa") { + allErrs = append(allErrs, field.Invalid(fldPath.Child("iqn"), iscsi.IQN, "must be valid format")) + } else if strings.HasPrefix(iscsi.IQN, "iqn") && !iscsiInitiatorIqnRegex.MatchString(iscsi.IQN) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("iqn"), iscsi.IQN, "must be valid format")) + } else if strings.HasPrefix(iscsi.IQN, "eui") && !iscsiInitiatorEuiRegex.MatchString(iscsi.IQN) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("iqn"), iscsi.IQN, "must be valid format")) + } else if strings.HasPrefix(iscsi.IQN, "naa") && !iscsiInitiatorNaaRegex.MatchString(iscsi.IQN) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("iqn"), iscsi.IQN, "must be valid format")) + } + } + if iscsi.Lun < 0 || iscsi.Lun > 255 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("lun"), iscsi.Lun, validation.InclusiveRangeError(0, 255))) + } + if (iscsi.DiscoveryCHAPAuth || iscsi.SessionCHAPAuth) && iscsi.SecretRef == nil { + allErrs = append(allErrs, field.Required(fldPath.Child("secretRef"), "")) + } + if iscsi.SecretRef != nil { + if len(iscsi.SecretRef.Name) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("secretRef", "name"), "")) + } + } + if iscsi.InitiatorName != nil { + initiator := *iscsi.InitiatorName + if !strings.HasPrefix(initiator, "iqn") && !strings.HasPrefix(initiator, "eui") && !strings.HasPrefix(initiator, "naa") { + allErrs = append(allErrs, field.Invalid(fldPath.Child("initiatorname"), initiator, "must be valid format")) + } + if strings.HasPrefix(initiator, "iqn") && !iscsiInitiatorIqnRegex.MatchString(initiator) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("initiatorname"), initiator, "must be valid format")) + } else if strings.HasPrefix(initiator, "eui") && !iscsiInitiatorEuiRegex.MatchString(initiator) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("initiatorname"), initiator, "must be valid format")) + } else if strings.HasPrefix(initiator, "naa") && !iscsiInitiatorNaaRegex.MatchString(initiator) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("initiatorname"), initiator, "must be valid format")) + } + } + return allErrs +} + +func validateFCVolumeSource(fc *core.FCVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(fc.TargetWWNs) < 1 && len(fc.WWIDs) < 1 { + allErrs = append(allErrs, field.Required(fldPath.Child("targetWWNs"), "must specify either targetWWNs or wwids, but not both")) + } + + if len(fc.TargetWWNs) != 0 && len(fc.WWIDs) != 0 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("targetWWNs"), fc.TargetWWNs, "targetWWNs and wwids can not be specified simultaneously")) + } + + if len(fc.TargetWWNs) != 0 { + if fc.Lun == nil { + allErrs = append(allErrs, field.Required(fldPath.Child("lun"), "lun is required if targetWWNs is specified")) + } else { + if *fc.Lun < 0 || *fc.Lun > 255 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("lun"), fc.Lun, validation.InclusiveRangeError(0, 255))) + } + } + } + return allErrs +} + +func validateGCEPersistentDiskVolumeSource(pd *core.GCEPersistentDiskVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(pd.PDName) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("pdName"), "")) + } + if pd.Partition < 0 || pd.Partition > 255 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("partition"), pd.Partition, pdPartitionErrorMsg)) + } + return allErrs +} + +func validateAWSElasticBlockStoreVolumeSource(PD *core.AWSElasticBlockStoreVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(PD.VolumeID) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("volumeID"), "")) + } + if PD.Partition < 0 || PD.Partition > 255 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("partition"), PD.Partition, pdPartitionErrorMsg)) + } + return allErrs +} + +func validateSecretVolumeSource(secretSource *core.SecretVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(secretSource.SecretName) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("secretName"), "")) + } + + secretMode := secretSource.DefaultMode + if secretMode != nil && (*secretMode > 0777 || *secretMode < 0) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("defaultMode"), *secretMode, fileModeErrorMsg)) + } + + itemsPath := fldPath.Child("items") + for i, kp := range secretSource.Items { + itemPath := itemsPath.Index(i) + allErrs = append(allErrs, validateKeyToPath(&kp, itemPath)...) + } + return allErrs +} + +func validateConfigMapVolumeSource(configMapSource *core.ConfigMapVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(configMapSource.Name) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("name"), "")) + } + + configMapMode := configMapSource.DefaultMode + if configMapMode != nil && (*configMapMode > 0777 || *configMapMode < 0) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("defaultMode"), *configMapMode, fileModeErrorMsg)) + } + + itemsPath := fldPath.Child("items") + for i, kp := range configMapSource.Items { + itemPath := itemsPath.Index(i) + allErrs = append(allErrs, validateKeyToPath(&kp, itemPath)...) + } + return allErrs +} + +func validateKeyToPath(kp *core.KeyToPath, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(kp.Key) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("key"), "")) + } + if len(kp.Path) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("path"), "")) + } + allErrs = append(allErrs, validateLocalNonReservedPath(kp.Path, fldPath.Child("path"))...) + if kp.Mode != nil && (*kp.Mode > 0777 || *kp.Mode < 0) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("mode"), *kp.Mode, fileModeErrorMsg)) + } + + return allErrs +} + +func validatePersistentClaimVolumeSource(claim *core.PersistentVolumeClaimVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(claim.ClaimName) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("claimName"), "")) + } + return allErrs +} + +func validateNFSVolumeSource(nfs *core.NFSVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(nfs.Server) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("server"), "")) + } + if len(nfs.Path) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("path"), "")) + } + if !path.IsAbs(nfs.Path) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("path"), nfs.Path, "must be an absolute path")) + } + return allErrs +} + +func validateQuobyteVolumeSource(quobyte *core.QuobyteVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(quobyte.Registry) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("registry"), "must be a host:port pair or multiple pairs separated by commas")) + } else if len(quobyte.Tenant) >= 65 { + allErrs = append(allErrs, field.Required(fldPath.Child("tenant"), "must be a UUID and may not exceed a length of 64 characters")) + } else { + for _, hostPortPair := range strings.Split(quobyte.Registry, ",") { + if _, _, err := net.SplitHostPort(hostPortPair); err != nil { + allErrs = append(allErrs, field.Invalid(fldPath.Child("registry"), quobyte.Registry, "must be a host:port pair or multiple pairs separated by commas")) + } + } + } + + if len(quobyte.Volume) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("volume"), "")) + } + return allErrs +} + +func validateGlusterfsVolumeSource(glusterfs *core.GlusterfsVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(glusterfs.EndpointsName) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("endpoints"), "")) + } + if len(glusterfs.Path) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("path"), "")) + } + return allErrs +} +func validateGlusterfsPersistentVolumeSource(glusterfs *core.GlusterfsPersistentVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(glusterfs.EndpointsName) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("endpoints"), "")) + } + if len(glusterfs.Path) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("path"), "")) + } + if glusterfs.EndpointsNamespace != nil { + endpointNs := glusterfs.EndpointsNamespace + if *endpointNs == "" { + allErrs = append(allErrs, field.Invalid(fldPath.Child("endpointsNamespace"), *endpointNs, "if the endpointnamespace is set, it must be a valid namespace name")) + } else { + for _, msg := range ValidateNamespaceName(*endpointNs, false) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("endpointsNamespace"), *endpointNs, msg)) + } + } + } + return allErrs +} + +func validateFlockerVolumeSource(flocker *core.FlockerVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(flocker.DatasetName) == 0 && len(flocker.DatasetUUID) == 0 { + // TODO: consider adding a RequiredOneOf() error for this and similar cases + allErrs = append(allErrs, field.Required(fldPath, "one of datasetName and datasetUUID is required")) + } + if len(flocker.DatasetName) != 0 && len(flocker.DatasetUUID) != 0 { + allErrs = append(allErrs, field.Invalid(fldPath, "resource", "datasetName and datasetUUID can not be specified simultaneously")) + } + if strings.Contains(flocker.DatasetName, "/") { + allErrs = append(allErrs, field.Invalid(fldPath.Child("datasetName"), flocker.DatasetName, "must not contain '/'")) + } + return allErrs +} + +var validVolumeDownwardAPIFieldPathExpressions = sets.NewString( + "metadata.name", + "metadata.namespace", + "metadata.labels", + "metadata.annotations", + "metadata.uid") + +func validateDownwardAPIVolumeFile(file *core.DownwardAPIVolumeFile, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { + allErrs := field.ErrorList{} + if len(file.Path) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("path"), "")) + } + allErrs = append(allErrs, validateLocalNonReservedPath(file.Path, fldPath.Child("path"))...) + if file.FieldRef != nil { + allErrs = append(allErrs, validateObjectFieldSelector(file.FieldRef, &validVolumeDownwardAPIFieldPathExpressions, fldPath.Child("fieldRef"))...) + if file.ResourceFieldRef != nil { + allErrs = append(allErrs, field.Invalid(fldPath, "resource", "fieldRef and resourceFieldRef can not be specified simultaneously")) + } + } else if file.ResourceFieldRef != nil { + localValidContainerResourceFieldPathPrefixes := validContainerResourceFieldPathPrefixes + if opts.AllowDownwardAPIHugePages { + localValidContainerResourceFieldPathPrefixes = validContainerResourceFieldPathPrefixesWithDownwardAPIHugePages + } + allErrs = append(allErrs, validateContainerResourceFieldSelector(file.ResourceFieldRef, &validContainerResourceFieldPathExpressions, &localValidContainerResourceFieldPathPrefixes, fldPath.Child("resourceFieldRef"), true)...) + } else { + allErrs = append(allErrs, field.Required(fldPath, "one of fieldRef and resourceFieldRef is required")) + } + if file.Mode != nil && (*file.Mode > 0777 || *file.Mode < 0) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("mode"), *file.Mode, fileModeErrorMsg)) + } + + return allErrs +} + +func validateDownwardAPIVolumeSource(downwardAPIVolume *core.DownwardAPIVolumeSource, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { + allErrs := field.ErrorList{} + + downwardAPIMode := downwardAPIVolume.DefaultMode + if downwardAPIMode != nil && (*downwardAPIMode > 0777 || *downwardAPIMode < 0) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("defaultMode"), *downwardAPIMode, fileModeErrorMsg)) + } + + for _, file := range downwardAPIVolume.Items { + allErrs = append(allErrs, validateDownwardAPIVolumeFile(&file, fldPath, opts)...) + } + return allErrs +} + +func validateProjectionSources(projection *core.ProjectedVolumeSource, projectionMode *int32, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { + allErrs := field.ErrorList{} + allPaths := sets.String{} + + for i, source := range projection.Sources { + numSources := 0 + srcPath := fldPath.Child("sources").Index(i) + if projPath := srcPath.Child("secret"); source.Secret != nil { + numSources++ + if len(source.Secret.Name) == 0 { + allErrs = append(allErrs, field.Required(projPath.Child("name"), "")) + } + itemsPath := projPath.Child("items") + for i, kp := range source.Secret.Items { + itemPath := itemsPath.Index(i) + allErrs = append(allErrs, validateKeyToPath(&kp, itemPath)...) + if len(kp.Path) > 0 { + curPath := kp.Path + if !allPaths.Has(curPath) { + allPaths.Insert(curPath) + } else { + allErrs = append(allErrs, field.Invalid(fldPath, source.Secret.Name, "conflicting duplicate paths")) + } + } + } + } + if projPath := srcPath.Child("configMap"); source.ConfigMap != nil { + numSources++ + if len(source.ConfigMap.Name) == 0 { + allErrs = append(allErrs, field.Required(projPath.Child("name"), "")) + } + itemsPath := projPath.Child("items") + for i, kp := range source.ConfigMap.Items { + itemPath := itemsPath.Index(i) + allErrs = append(allErrs, validateKeyToPath(&kp, itemPath)...) + if len(kp.Path) > 0 { + curPath := kp.Path + if !allPaths.Has(curPath) { + allPaths.Insert(curPath) + } else { + allErrs = append(allErrs, field.Invalid(fldPath, source.ConfigMap.Name, "conflicting duplicate paths")) + } + } + } + } + if projPath := srcPath.Child("downwardAPI"); source.DownwardAPI != nil { + numSources++ + for _, file := range source.DownwardAPI.Items { + allErrs = append(allErrs, validateDownwardAPIVolumeFile(&file, projPath, opts)...) + if len(file.Path) > 0 { + curPath := file.Path + if !allPaths.Has(curPath) { + allPaths.Insert(curPath) + } else { + allErrs = append(allErrs, field.Invalid(fldPath, curPath, "conflicting duplicate paths")) + } + } + } + } + if projPath := srcPath.Child("serviceAccountToken"); source.ServiceAccountToken != nil { + numSources++ + if source.ServiceAccountToken.ExpirationSeconds < 10*60 { + allErrs = append(allErrs, field.Invalid(projPath.Child("expirationSeconds"), source.ServiceAccountToken.ExpirationSeconds, "may not specify a duration less than 10 minutes")) + } + if source.ServiceAccountToken.ExpirationSeconds > 1<<32 { + allErrs = append(allErrs, field.Invalid(projPath.Child("expirationSeconds"), source.ServiceAccountToken.ExpirationSeconds, "may not specify a duration larger than 2^32 seconds")) + } + if source.ServiceAccountToken.Path == "" { + allErrs = append(allErrs, field.Required(fldPath.Child("path"), "")) + } + } + if numSources > 1 { + allErrs = append(allErrs, field.Forbidden(srcPath, "may not specify more than 1 volume type")) + } + } + return allErrs +} + +func validateProjectedVolumeSource(projection *core.ProjectedVolumeSource, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { + allErrs := field.ErrorList{} + + projectionMode := projection.DefaultMode + if projectionMode != nil && (*projectionMode > 0777 || *projectionMode < 0) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("defaultMode"), *projectionMode, fileModeErrorMsg)) + } + + allErrs = append(allErrs, validateProjectionSources(projection, projectionMode, fldPath, opts)...) + return allErrs +} + +var supportedHostPathTypes = sets.NewString( + string(core.HostPathUnset), + string(core.HostPathDirectoryOrCreate), + string(core.HostPathDirectory), + string(core.HostPathFileOrCreate), + string(core.HostPathFile), + string(core.HostPathSocket), + string(core.HostPathCharDev), + string(core.HostPathBlockDev)) + +func validateHostPathType(hostPathType *core.HostPathType, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + if hostPathType != nil && !supportedHostPathTypes.Has(string(*hostPathType)) { + allErrs = append(allErrs, field.NotSupported(fldPath, hostPathType, supportedHostPathTypes.List())) + } + + return allErrs +} + +// This validate will make sure targetPath: +// 1. is not abs path +// 2. does not have any element which is ".." +func validateLocalDescendingPath(targetPath string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if path.IsAbs(targetPath) { + allErrs = append(allErrs, field.Invalid(fldPath, targetPath, "must be a relative path")) + } + + allErrs = append(allErrs, validatePathNoBacksteps(targetPath, fldPath)...) + + return allErrs +} + +// validatePathNoBacksteps makes sure the targetPath does not have any `..` path elements when split +// +// This assumes the OS of the apiserver and the nodes are the same. The same check should be done +// on the node to ensure there are no backsteps. +func validatePathNoBacksteps(targetPath string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + parts := strings.Split(filepath.ToSlash(targetPath), "/") + for _, item := range parts { + if item == ".." { + allErrs = append(allErrs, field.Invalid(fldPath, targetPath, "must not contain '..'")) + break // even for `../../..`, one error is sufficient to make the point + } + } + return allErrs +} + +// validateMountPropagation verifies that MountPropagation field is valid and +// allowed for given container. +func validateMountPropagation(mountPropagation *core.MountPropagationMode, container *core.Container, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + if mountPropagation == nil { + return allErrs + } + + supportedMountPropagations := sets.NewString(string(core.MountPropagationBidirectional), string(core.MountPropagationHostToContainer), string(core.MountPropagationNone)) + if !supportedMountPropagations.Has(string(*mountPropagation)) { + allErrs = append(allErrs, field.NotSupported(fldPath, *mountPropagation, supportedMountPropagations.List())) + } + + if container == nil { + // The container is not available yet. + // Stop validation now, Pod validation will refuse final + // Pods with Bidirectional propagation in non-privileged containers. + return allErrs + } + + privileged := container.SecurityContext != nil && container.SecurityContext.Privileged != nil && *container.SecurityContext.Privileged + if *mountPropagation == core.MountPropagationBidirectional && !privileged { + allErrs = append(allErrs, field.Forbidden(fldPath, "Bidirectional mount propagation is available only to privileged containers")) + } + return allErrs +} + +// This validate will make sure targetPath: +// 1. is not abs path +// 2. does not contain any '..' elements +// 3. does not start with '..' +func validateLocalNonReservedPath(targetPath string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + allErrs = append(allErrs, validateLocalDescendingPath(targetPath, fldPath)...) + // Don't report this error if the check for .. elements already caught it. + if strings.HasPrefix(targetPath, "..") && !strings.HasPrefix(targetPath, "../") { + allErrs = append(allErrs, field.Invalid(fldPath, targetPath, "must not start with '..'")) + } + return allErrs +} + +func validateRBDVolumeSource(rbd *core.RBDVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(rbd.CephMonitors) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("monitors"), "")) + } + if len(rbd.RBDImage) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("image"), "")) + } + return allErrs +} + +func validateRBDPersistentVolumeSource(rbd *core.RBDPersistentVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(rbd.CephMonitors) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("monitors"), "")) + } + if len(rbd.RBDImage) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("image"), "")) + } + return allErrs +} + +func validateCinderVolumeSource(cd *core.CinderVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(cd.VolumeID) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("volumeID"), "")) + } + if cd.SecretRef != nil { + if len(cd.SecretRef.Name) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("secretRef", "name"), "")) + } + } + return allErrs +} + +func validateCinderPersistentVolumeSource(cd *core.CinderPersistentVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(cd.VolumeID) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("volumeID"), "")) + } + if cd.SecretRef != nil { + if len(cd.SecretRef.Name) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("secretRef", "name"), "")) + } + if len(cd.SecretRef.Namespace) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("secretRef", "namespace"), "")) + } + } + return allErrs +} + +func validateCephFSVolumeSource(cephfs *core.CephFSVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(cephfs.Monitors) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("monitors"), "")) + } + return allErrs +} + +func validateCephFSPersistentVolumeSource(cephfs *core.CephFSPersistentVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(cephfs.Monitors) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("monitors"), "")) + } + return allErrs +} + +func validateFlexVolumeSource(fv *core.FlexVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(fv.Driver) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("driver"), "")) + } + + // Make sure user-specified options don't use kubernetes namespaces + for k := range fv.Options { + namespace := k + if parts := strings.SplitN(k, "/", 2); len(parts) == 2 { + namespace = parts[0] + } + normalized := "." + strings.ToLower(namespace) + if strings.HasSuffix(normalized, ".kubernetes.io") || strings.HasSuffix(normalized, ".k8s.io") { + allErrs = append(allErrs, field.Invalid(fldPath.Child("options").Key(k), k, "kubernetes.io and k8s.io namespaces are reserved")) + } + } + + return allErrs +} + +func validateFlexPersistentVolumeSource(fv *core.FlexPersistentVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(fv.Driver) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("driver"), "")) + } + + // Make sure user-specified options don't use kubernetes namespaces + for k := range fv.Options { + namespace := k + if parts := strings.SplitN(k, "/", 2); len(parts) == 2 { + namespace = parts[0] + } + normalized := "." + strings.ToLower(namespace) + if strings.HasSuffix(normalized, ".kubernetes.io") || strings.HasSuffix(normalized, ".k8s.io") { + allErrs = append(allErrs, field.Invalid(fldPath.Child("options").Key(k), k, "kubernetes.io and k8s.io namespaces are reserved")) + } + } + + return allErrs +} + +func validateAzureFile(azure *core.AzureFileVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if azure.SecretName == "" { + allErrs = append(allErrs, field.Required(fldPath.Child("secretName"), "")) + } + if azure.ShareName == "" { + allErrs = append(allErrs, field.Required(fldPath.Child("shareName"), "")) + } + return allErrs +} + +func validateAzureFilePV(azure *core.AzureFilePersistentVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if azure.SecretName == "" { + allErrs = append(allErrs, field.Required(fldPath.Child("secretName"), "")) + } + if azure.ShareName == "" { + allErrs = append(allErrs, field.Required(fldPath.Child("shareName"), "")) + } + if azure.SecretNamespace != nil { + if len(*azure.SecretNamespace) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("secretNamespace"), "")) + } + } + return allErrs +} + +func validateAzureDisk(azure *core.AzureDiskVolumeSource, fldPath *field.Path) field.ErrorList { + var supportedCachingModes = sets.NewString(string(core.AzureDataDiskCachingNone), string(core.AzureDataDiskCachingReadOnly), string(core.AzureDataDiskCachingReadWrite)) + var supportedDiskKinds = sets.NewString(string(core.AzureSharedBlobDisk), string(core.AzureDedicatedBlobDisk), string(core.AzureManagedDisk)) + + diskURISupportedManaged := []string{"/subscriptions/{sub-id}/resourcegroups/{group-name}/providers/microsoft.compute/disks/{disk-id}"} + diskURISupportedblob := []string{"https://{account-name}.blob.core.windows.net/{container-name}/{disk-name}.vhd"} + + allErrs := field.ErrorList{} + if azure.DiskName == "" { + allErrs = append(allErrs, field.Required(fldPath.Child("diskName"), "")) + } + + if azure.DataDiskURI == "" { + allErrs = append(allErrs, field.Required(fldPath.Child("diskURI"), "")) + } + + if azure.CachingMode != nil && !supportedCachingModes.Has(string(*azure.CachingMode)) { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("cachingMode"), *azure.CachingMode, supportedCachingModes.List())) + } + + if azure.Kind != nil && !supportedDiskKinds.Has(string(*azure.Kind)) { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("kind"), *azure.Kind, supportedDiskKinds.List())) + } + + // validate that DiskUri is the correct format + if azure.Kind != nil && *azure.Kind == core.AzureManagedDisk && strings.Index(azure.DataDiskURI, "/subscriptions/") != 0 { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("diskURI"), azure.DataDiskURI, diskURISupportedManaged)) + } + + if azure.Kind != nil && *azure.Kind != core.AzureManagedDisk && strings.Index(azure.DataDiskURI, "https://") != 0 { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("diskURI"), azure.DataDiskURI, diskURISupportedblob)) + } + + return allErrs +} + +func validateVsphereVolumeSource(cd *core.VsphereVirtualDiskVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(cd.VolumePath) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("volumePath"), "")) + } + return allErrs +} + +func validatePhotonPersistentDiskVolumeSource(cd *core.PhotonPersistentDiskVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(cd.PdID) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("pdID"), "")) + } + return allErrs +} + +func validatePortworxVolumeSource(pwx *core.PortworxVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(pwx.VolumeID) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("volumeID"), "")) + } + return allErrs +} + +func validateScaleIOVolumeSource(sio *core.ScaleIOVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if sio.Gateway == "" { + allErrs = append(allErrs, field.Required(fldPath.Child("gateway"), "")) + } + if sio.System == "" { + allErrs = append(allErrs, field.Required(fldPath.Child("system"), "")) + } + if sio.VolumeName == "" { + allErrs = append(allErrs, field.Required(fldPath.Child("volumeName"), "")) + } + return allErrs +} + +func validateScaleIOPersistentVolumeSource(sio *core.ScaleIOPersistentVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if sio.Gateway == "" { + allErrs = append(allErrs, field.Required(fldPath.Child("gateway"), "")) + } + if sio.System == "" { + allErrs = append(allErrs, field.Required(fldPath.Child("system"), "")) + } + if sio.VolumeName == "" { + allErrs = append(allErrs, field.Required(fldPath.Child("volumeName"), "")) + } + return allErrs +} + +func validateLocalVolumeSource(ls *core.LocalVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if ls.Path == "" { + allErrs = append(allErrs, field.Required(fldPath.Child("path"), "")) + return allErrs + } + + allErrs = append(allErrs, validatePathNoBacksteps(ls.Path, fldPath.Child("path"))...) + return allErrs +} + +func validateStorageOSVolumeSource(storageos *core.StorageOSVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(storageos.VolumeName) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("volumeName"), "")) + } else { + allErrs = append(allErrs, ValidateDNS1123Label(storageos.VolumeName, fldPath.Child("volumeName"))...) + } + if len(storageos.VolumeNamespace) > 0 { + allErrs = append(allErrs, ValidateDNS1123Label(storageos.VolumeNamespace, fldPath.Child("volumeNamespace"))...) + } + if storageos.SecretRef != nil { + if len(storageos.SecretRef.Name) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("secretRef", "name"), "")) + } + } + return allErrs +} + +func validateStorageOSPersistentVolumeSource(storageos *core.StorageOSPersistentVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(storageos.VolumeName) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("volumeName"), "")) + } else { + allErrs = append(allErrs, ValidateDNS1123Label(storageos.VolumeName, fldPath.Child("volumeName"))...) + } + if len(storageos.VolumeNamespace) > 0 { + allErrs = append(allErrs, ValidateDNS1123Label(storageos.VolumeNamespace, fldPath.Child("volumeNamespace"))...) + } + if storageos.SecretRef != nil { + if len(storageos.SecretRef.Name) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("secretRef", "name"), "")) + } + if len(storageos.SecretRef.Namespace) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("secretRef", "namespace"), "")) + } + } + return allErrs +} + +// validatePVSecretReference check whether provided SecretReference object is valid in terms of secret name and namespace. + +func validatePVSecretReference(secretRef *core.SecretReference, allowDNSSubDomainSecretName bool, fldPath *field.Path) field.ErrorList { + var allErrs field.ErrorList + if len(secretRef.Name) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("name"), "")) + } else if allowDNSSubDomainSecretName { + allErrs = append(allErrs, ValidateDNS1123Subdomain(secretRef.Name, fldPath.Child("name"))...) + } else { + allErrs = append(allErrs, ValidateDNS1123Label(secretRef.Name, fldPath.Child("name"))...) + } + + if len(secretRef.Namespace) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("namespace"), "")) + } else { + allErrs = append(allErrs, ValidateDNS1123Label(secretRef.Namespace, fldPath.Child("namespace"))...) + } + return allErrs +} + +func ValidateCSIDriverName(driverName string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + if len(driverName) == 0 { + allErrs = append(allErrs, field.Required(fldPath, "")) + } + + if len(driverName) > 63 { + allErrs = append(allErrs, field.TooLong(fldPath, driverName, 63)) + } + + for _, msg := range validation.IsDNS1123Subdomain(strings.ToLower(driverName)) { + allErrs = append(allErrs, field.Invalid(fldPath, driverName, msg)) + } + + return allErrs +} + +func validateCSIPersistentVolumeSource(csi *core.CSIPersistentVolumeSource, allowDNSSubDomainSecretName bool, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + allErrs = append(allErrs, ValidateCSIDriverName(csi.Driver, fldPath.Child("driver"))...) + + if len(csi.VolumeHandle) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("volumeHandle"), "")) + } + if csi.ControllerPublishSecretRef != nil { + allErrs = append(allErrs, validatePVSecretReference(csi.ControllerPublishSecretRef, allowDNSSubDomainSecretName, fldPath.Child("controllerPublishSecretRef"))...) + } + if csi.ControllerExpandSecretRef != nil { + allErrs = append(allErrs, validatePVSecretReference(csi.ControllerExpandSecretRef, allowDNSSubDomainSecretName, fldPath.Child("controllerExpandSecretRef"))...) + } + if csi.NodePublishSecretRef != nil { + allErrs = append(allErrs, validatePVSecretReference(csi.NodePublishSecretRef, allowDNSSubDomainSecretName, fldPath.Child("nodePublishSecretRef"))...) + } + if csi.NodeExpandSecretRef != nil { + allErrs = append(allErrs, validatePVSecretReference(csi.NodeExpandSecretRef, allowDNSSubDomainSecretName, fldPath.Child("nodeExpandSecretRef"))...) + } + return allErrs +} + +func validateCSIVolumeSource(csi *core.CSIVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + allErrs = append(allErrs, ValidateCSIDriverName(csi.Driver, fldPath.Child("driver"))...) + + if csi.NodePublishSecretRef != nil { + if len(csi.NodePublishSecretRef.Name) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("nodePublishSecretRef", "name"), "")) + } else { + for _, msg := range ValidateSecretName(csi.NodePublishSecretRef.Name, false) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), csi.NodePublishSecretRef.Name, msg)) + } + } + } + + return allErrs +} + +func validateEphemeralVolumeSource(ephemeral *core.EphemeralVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if ephemeral.VolumeClaimTemplate == nil { + allErrs = append(allErrs, field.Required(fldPath.Child("volumeClaimTemplate"), "")) + } else { + opts := ValidationOptionsForPersistentVolumeClaimTemplate(ephemeral.VolumeClaimTemplate, nil) + allErrs = append(allErrs, ValidatePersistentVolumeClaimTemplate(ephemeral.VolumeClaimTemplate, fldPath.Child("volumeClaimTemplate"), opts)...) + } + return allErrs +} + +// ValidatePersistentVolumeClaimTemplate verifies that the embedded object meta and spec are valid. +// Checking of the object data is very minimal because only labels and annotations are used. +func ValidatePersistentVolumeClaimTemplate(claimTemplate *core.PersistentVolumeClaimTemplate, fldPath *field.Path, opts PersistentVolumeClaimSpecValidationOptions) field.ErrorList { + allErrs := ValidateTemplateObjectMeta(&claimTemplate.ObjectMeta, fldPath.Child("metadata")) + allErrs = append(allErrs, ValidatePersistentVolumeClaimSpec(&claimTemplate.Spec, fldPath.Child("spec"), opts)...) + return allErrs +} + +func ValidateTemplateObjectMeta(objMeta *metav1.ObjectMeta, fldPath *field.Path) field.ErrorList { + allErrs := apimachineryvalidation.ValidateAnnotations(objMeta.Annotations, fldPath.Child("annotations")) + allErrs = append(allErrs, unversionedvalidation.ValidateLabels(objMeta.Labels, fldPath.Child("labels"))...) + // All other fields are not supported and thus must not be set + // to avoid confusion. We could reject individual fields, + // but then adding a new one to ObjectMeta wouldn't be checked + // unless this code gets updated. Instead, we ensure that + // only allowed fields are set via reflection. + allErrs = append(allErrs, validateFieldAllowList(*objMeta, allowedTemplateObjectMetaFields, "cannot be set", fldPath)...) + return allErrs +} + +var allowedTemplateObjectMetaFields = map[string]bool{ + "Annotations": true, + "Labels": true, +} + +// PersistentVolumeSpecValidationOptions contains the different settings for PeristentVolume validation +type PersistentVolumeSpecValidationOptions struct { + // Allow spec to contain the "ReadWiteOncePod" access mode + AllowReadWriteOncePod bool + // Allow the secretRef Name field to be of DNSSubDomain Format + AllowDNSSubDomainSecretName bool +} + +// ValidatePersistentVolumeName checks that a name is appropriate for a +// PersistentVolumeName object. +var ValidatePersistentVolumeName = apimachineryvalidation.NameIsDNSSubdomain + +var supportedAccessModes = sets.NewString(string(core.ReadWriteOnce), string(core.ReadOnlyMany), string(core.ReadWriteMany)) + +var supportedReclaimPolicy = sets.NewString(string(core.PersistentVolumeReclaimDelete), string(core.PersistentVolumeReclaimRecycle), string(core.PersistentVolumeReclaimRetain)) + +var supportedVolumeModes = sets.NewString(string(core.PersistentVolumeBlock), string(core.PersistentVolumeFilesystem)) + +func ValidationOptionsForPersistentVolume(pv, oldPv *core.PersistentVolume) PersistentVolumeSpecValidationOptions { + opts := PersistentVolumeSpecValidationOptions{ + AllowReadWriteOncePod: utilfeature.DefaultFeatureGate.Enabled(features.ReadWriteOncePod), + AllowDNSSubDomainSecretName: false, + } + if oldPv == nil { + // If there's no old PV, use the options based solely on feature enablement + return opts + } + if helper.ContainsAccessMode(oldPv.Spec.AccessModes, core.ReadWriteOncePod) { + // If the old object allowed "ReadWriteOncePod", continue to allow it in the new object + opts.AllowReadWriteOncePod = true + } + if oldCSI := oldPv.Spec.CSI; oldCSI != nil { + opts.AllowDNSSubDomainSecretName = + secretRefRequiresSubdomainSecretName(oldCSI.ControllerExpandSecretRef) || + secretRefRequiresSubdomainSecretName(oldCSI.ControllerPublishSecretRef) || + secretRefRequiresSubdomainSecretName(oldCSI.NodeStageSecretRef) || + secretRefRequiresSubdomainSecretName(oldCSI.NodePublishSecretRef) + } + return opts +} + +func secretRefRequiresSubdomainSecretName(secretRef *core.SecretReference) bool { + // ref and name were specified and name didn't fit within label validation + return secretRef != nil && len(secretRef.Name) > 0 && len(validation.IsDNS1123Label(secretRef.Name)) > 0 +} + +func ValidatePersistentVolumeSpec(pvSpec *core.PersistentVolumeSpec, pvName string, validateInlinePersistentVolumeSpec bool, fldPath *field.Path, opts PersistentVolumeSpecValidationOptions) field.ErrorList { + allErrs := field.ErrorList{} + + if validateInlinePersistentVolumeSpec { + if pvSpec.ClaimRef != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("claimRef"), "may not be specified in the context of inline volumes")) + } + if len(pvSpec.Capacity) != 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("capacity"), "may not be specified in the context of inline volumes")) + } + if pvSpec.CSI == nil { + allErrs = append(allErrs, field.Required(fldPath.Child("csi"), "has to be specified in the context of inline volumes")) + } + } + + if len(pvSpec.AccessModes) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("accessModes"), "")) + } + + expandedSupportedAccessModes := sets.StringKeySet(supportedAccessModes) + if opts.AllowReadWriteOncePod { + expandedSupportedAccessModes.Insert(string(core.ReadWriteOncePod)) + } + + foundReadWriteOncePod, foundNonReadWriteOncePod := false, false + for _, mode := range pvSpec.AccessModes { + if !expandedSupportedAccessModes.Has(string(mode)) { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("accessModes"), mode, expandedSupportedAccessModes.List())) + } + + if mode == core.ReadWriteOncePod { + foundReadWriteOncePod = true + } else if supportedAccessModes.Has(string(mode)) { + foundNonReadWriteOncePod = true + } + } + if foundReadWriteOncePod && foundNonReadWriteOncePod { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("accessModes"), "may not use ReadWriteOncePod with other access modes")) + } + + if !validateInlinePersistentVolumeSpec { + if len(pvSpec.Capacity) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("capacity"), "")) + } + + if _, ok := pvSpec.Capacity[core.ResourceStorage]; !ok || len(pvSpec.Capacity) > 1 { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("capacity"), pvSpec.Capacity, []string{string(core.ResourceStorage)})) + } + capPath := fldPath.Child("capacity") + for r, qty := range pvSpec.Capacity { + allErrs = append(allErrs, validateBasicResource(qty, capPath.Key(string(r)))...) + allErrs = append(allErrs, ValidatePositiveQuantityValue(qty, capPath.Key(string(r)))...) + } + } + + if len(string(pvSpec.PersistentVolumeReclaimPolicy)) > 0 { + if validateInlinePersistentVolumeSpec { + if pvSpec.PersistentVolumeReclaimPolicy != core.PersistentVolumeReclaimRetain { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("persistentVolumeReclaimPolicy"), "may only be "+string(core.PersistentVolumeReclaimRetain)+" in the context of inline volumes")) + } + } else { + if !supportedReclaimPolicy.Has(string(pvSpec.PersistentVolumeReclaimPolicy)) { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("persistentVolumeReclaimPolicy"), pvSpec.PersistentVolumeReclaimPolicy, supportedReclaimPolicy.List())) + } + } + } + + var nodeAffinitySpecified bool + var errs field.ErrorList + if pvSpec.NodeAffinity != nil { + if validateInlinePersistentVolumeSpec { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("nodeAffinity"), "may not be specified in the context of inline volumes")) + } else { + nodeAffinitySpecified, errs = validateVolumeNodeAffinity(pvSpec.NodeAffinity, fldPath.Child("nodeAffinity")) + allErrs = append(allErrs, errs...) + } + } + numVolumes := 0 + if pvSpec.HostPath != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("hostPath"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateHostPathVolumeSource(pvSpec.HostPath, fldPath.Child("hostPath"))...) + } + } + if pvSpec.GCEPersistentDisk != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("gcePersistentDisk"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateGCEPersistentDiskVolumeSource(pvSpec.GCEPersistentDisk, fldPath.Child("persistentDisk"))...) + } + } + if pvSpec.AWSElasticBlockStore != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("awsElasticBlockStore"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateAWSElasticBlockStoreVolumeSource(pvSpec.AWSElasticBlockStore, fldPath.Child("awsElasticBlockStore"))...) + } + } + if pvSpec.Glusterfs != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("glusterfs"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateGlusterfsPersistentVolumeSource(pvSpec.Glusterfs, fldPath.Child("glusterfs"))...) + } + } + if pvSpec.Flocker != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("flocker"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateFlockerVolumeSource(pvSpec.Flocker, fldPath.Child("flocker"))...) + } + } + if pvSpec.NFS != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("nfs"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateNFSVolumeSource(pvSpec.NFS, fldPath.Child("nfs"))...) + } + } + if pvSpec.RBD != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("rbd"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateRBDPersistentVolumeSource(pvSpec.RBD, fldPath.Child("rbd"))...) + } + } + if pvSpec.Quobyte != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("quobyte"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateQuobyteVolumeSource(pvSpec.Quobyte, fldPath.Child("quobyte"))...) + } + } + if pvSpec.CephFS != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("cephFS"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateCephFSPersistentVolumeSource(pvSpec.CephFS, fldPath.Child("cephfs"))...) + } + } + if pvSpec.ISCSI != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("iscsi"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateISCSIPersistentVolumeSource(pvSpec.ISCSI, pvName, fldPath.Child("iscsi"))...) + } + } + if pvSpec.Cinder != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("cinder"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateCinderPersistentVolumeSource(pvSpec.Cinder, fldPath.Child("cinder"))...) + } + } + if pvSpec.FC != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("fc"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateFCVolumeSource(pvSpec.FC, fldPath.Child("fc"))...) + } + } + if pvSpec.FlexVolume != nil { + numVolumes++ + allErrs = append(allErrs, validateFlexPersistentVolumeSource(pvSpec.FlexVolume, fldPath.Child("flexVolume"))...) + } + if pvSpec.AzureFile != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("azureFile"), "may not specify more than 1 volume type")) + + } else { + numVolumes++ + allErrs = append(allErrs, validateAzureFilePV(pvSpec.AzureFile, fldPath.Child("azureFile"))...) + } + } + + if pvSpec.VsphereVolume != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("vsphereVolume"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateVsphereVolumeSource(pvSpec.VsphereVolume, fldPath.Child("vsphereVolume"))...) + } + } + if pvSpec.PhotonPersistentDisk != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("photonPersistentDisk"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validatePhotonPersistentDiskVolumeSource(pvSpec.PhotonPersistentDisk, fldPath.Child("photonPersistentDisk"))...) + } + } + if pvSpec.PortworxVolume != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("portworxVolume"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validatePortworxVolumeSource(pvSpec.PortworxVolume, fldPath.Child("portworxVolume"))...) + } + } + if pvSpec.AzureDisk != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("azureDisk"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateAzureDisk(pvSpec.AzureDisk, fldPath.Child("azureDisk"))...) + } + } + if pvSpec.ScaleIO != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("scaleIO"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateScaleIOPersistentVolumeSource(pvSpec.ScaleIO, fldPath.Child("scaleIO"))...) + } + } + if pvSpec.Local != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("local"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateLocalVolumeSource(pvSpec.Local, fldPath.Child("local"))...) + // NodeAffinity is required + if !nodeAffinitySpecified { + allErrs = append(allErrs, field.Required(fldPath.Child("nodeAffinity"), "Local volume requires node affinity")) + } + } + } + if pvSpec.StorageOS != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("storageos"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateStorageOSPersistentVolumeSource(pvSpec.StorageOS, fldPath.Child("storageos"))...) + } + } + + if pvSpec.CSI != nil { + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("csi"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateCSIPersistentVolumeSource(pvSpec.CSI, opts.AllowDNSSubDomainSecretName, fldPath.Child("csi"))...) + } + } + + if numVolumes == 0 { + allErrs = append(allErrs, field.Required(fldPath, "must specify a volume type")) + } + + // do not allow hostPath mounts of '/' to have a 'recycle' reclaim policy + if pvSpec.HostPath != nil && path.Clean(pvSpec.HostPath.Path) == "/" && pvSpec.PersistentVolumeReclaimPolicy == core.PersistentVolumeReclaimRecycle { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("persistentVolumeReclaimPolicy"), "may not be 'recycle' for a hostPath mount of '/'")) + } + + if len(pvSpec.StorageClassName) > 0 { + if validateInlinePersistentVolumeSpec { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("storageClassName"), "may not be specified in the context of inline volumes")) + } else { + for _, msg := range ValidateClassName(pvSpec.StorageClassName, false) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("storageClassName"), pvSpec.StorageClassName, msg)) + } + } + } + if pvSpec.VolumeMode != nil { + if validateInlinePersistentVolumeSpec { + if *pvSpec.VolumeMode != core.PersistentVolumeFilesystem { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("volumeMode"), "may not specify volumeMode other than "+string(core.PersistentVolumeFilesystem)+" in the context of inline volumes")) + } + } else { + if !supportedVolumeModes.Has(string(*pvSpec.VolumeMode)) { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("volumeMode"), *pvSpec.VolumeMode, supportedVolumeModes.List())) + } + } + } + return allErrs +} + +func ValidatePersistentVolume(pv *core.PersistentVolume, opts PersistentVolumeSpecValidationOptions) field.ErrorList { + metaPath := field.NewPath("metadata") + allErrs := ValidateObjectMeta(&pv.ObjectMeta, false, ValidatePersistentVolumeName, metaPath) + allErrs = append(allErrs, ValidatePersistentVolumeSpec(&pv.Spec, pv.ObjectMeta.Name, false, field.NewPath("spec"), opts)...) + return allErrs +} + +// ValidatePersistentVolumeUpdate tests to see if the update is legal for an end user to make. +// newPv is updated with fields that cannot be changed. +func ValidatePersistentVolumeUpdate(newPv, oldPv *core.PersistentVolume, opts PersistentVolumeSpecValidationOptions) field.ErrorList { + allErrs := ValidatePersistentVolume(newPv, opts) + + // if oldPV does not have ControllerExpandSecretRef then allow it to be set + if (oldPv.Spec.CSI != nil && oldPv.Spec.CSI.ControllerExpandSecretRef == nil) && + (newPv.Spec.CSI != nil && newPv.Spec.CSI.ControllerExpandSecretRef != nil) { + newPv = newPv.DeepCopy() + newPv.Spec.CSI.ControllerExpandSecretRef = nil + } + + // PersistentVolumeSource should be immutable after creation. + if !apiequality.Semantic.DeepEqual(newPv.Spec.PersistentVolumeSource, oldPv.Spec.PersistentVolumeSource) { + pvcSourceDiff := cmp.Diff(oldPv.Spec.PersistentVolumeSource, newPv.Spec.PersistentVolumeSource) + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "persistentvolumesource"), fmt.Sprintf("spec.persistentvolumesource is immutable after creation\n%v", pvcSourceDiff))) + } + allErrs = append(allErrs, ValidateImmutableField(newPv.Spec.VolumeMode, oldPv.Spec.VolumeMode, field.NewPath("volumeMode"))...) + + // Allow setting NodeAffinity if oldPv NodeAffinity was not set + if oldPv.Spec.NodeAffinity != nil { + allErrs = append(allErrs, ValidateImmutableField(newPv.Spec.NodeAffinity, oldPv.Spec.NodeAffinity, field.NewPath("nodeAffinity"))...) + } + + return allErrs +} + +// ValidatePersistentVolumeStatusUpdate tests to see if the status update is legal for an end user to make. +func ValidatePersistentVolumeStatusUpdate(newPv, oldPv *core.PersistentVolume) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newPv.ObjectMeta, &oldPv.ObjectMeta, field.NewPath("metadata")) + if len(newPv.ResourceVersion) == 0 { + allErrs = append(allErrs, field.Required(field.NewPath("resourceVersion"), "")) + } + return allErrs +} + +type PersistentVolumeClaimSpecValidationOptions struct { + // Allow spec to contain the "ReadWiteOncePod" access mode + AllowReadWriteOncePod bool + // Allow users to recover from previously failing expansion operation + EnableRecoverFromExpansionFailure bool + // Allow assigning StorageClass to unbound PVCs retroactively + EnableRetroactiveDefaultStorageClass bool + // Allow to validate the label value of the label selector + AllowInvalidLabelValueInSelector bool +} + +func ValidationOptionsForPersistentVolumeClaim(pvc, oldPvc *core.PersistentVolumeClaim) PersistentVolumeClaimSpecValidationOptions { + opts := PersistentVolumeClaimSpecValidationOptions{ + AllowReadWriteOncePod: utilfeature.DefaultFeatureGate.Enabled(features.ReadWriteOncePod), + EnableRecoverFromExpansionFailure: utilfeature.DefaultFeatureGate.Enabled(features.RecoverVolumeExpansionFailure), + EnableRetroactiveDefaultStorageClass: utilfeature.DefaultFeatureGate.Enabled(features.RetroactiveDefaultStorageClass), + AllowInvalidLabelValueInSelector: false, + } + if oldPvc == nil { + // If there's no old PVC, use the options based solely on feature enablement + return opts + } + labelSelectorValidationOpts := unversionedvalidation.LabelSelectorValidationOptions{ + AllowInvalidLabelValueInSelector: opts.AllowInvalidLabelValueInSelector, + } + if len(unversionedvalidation.ValidateLabelSelector(oldPvc.Spec.Selector, labelSelectorValidationOpts, nil)) > 0 { + // If the old object had an invalid label selector, continue to allow it in the new object + opts.AllowInvalidLabelValueInSelector = true + } + + if helper.ContainsAccessMode(oldPvc.Spec.AccessModes, core.ReadWriteOncePod) { + // If the old object allowed "ReadWriteOncePod", continue to allow it in the new object + opts.AllowReadWriteOncePod = true + } + return opts +} + +func ValidationOptionsForPersistentVolumeClaimTemplate(claimTemplate, oldClaimTemplate *core.PersistentVolumeClaimTemplate) PersistentVolumeClaimSpecValidationOptions { + opts := PersistentVolumeClaimSpecValidationOptions{ + AllowReadWriteOncePod: utilfeature.DefaultFeatureGate.Enabled(features.ReadWriteOncePod), + AllowInvalidLabelValueInSelector: false, + } + if oldClaimTemplate == nil { + // If there's no old PVC template, use the options based solely on feature enablement + return opts + } + labelSelectorValidationOpts := unversionedvalidation.LabelSelectorValidationOptions{ + AllowInvalidLabelValueInSelector: opts.AllowInvalidLabelValueInSelector, + } + if len(unversionedvalidation.ValidateLabelSelector(oldClaimTemplate.Spec.Selector, labelSelectorValidationOpts, nil)) > 0 { + // If the old object had an invalid label selector, continue to allow it in the new object + opts.AllowInvalidLabelValueInSelector = true + } + if helper.ContainsAccessMode(oldClaimTemplate.Spec.AccessModes, core.ReadWriteOncePod) { + // If the old object allowed "ReadWriteOncePod", continue to allow it in the new object + opts.AllowReadWriteOncePod = true + } + return opts +} + +// ValidatePersistentVolumeClaim validates a PersistentVolumeClaim +func ValidatePersistentVolumeClaim(pvc *core.PersistentVolumeClaim, opts PersistentVolumeClaimSpecValidationOptions) field.ErrorList { + allErrs := ValidateObjectMeta(&pvc.ObjectMeta, true, ValidatePersistentVolumeName, field.NewPath("metadata")) + allErrs = append(allErrs, ValidatePersistentVolumeClaimSpec(&pvc.Spec, field.NewPath("spec"), opts)...) + return allErrs +} + +// validateDataSource validates a DataSource/DataSourceRef in a PersistentVolumeClaimSpec +func validateDataSource(dataSource *core.TypedLocalObjectReference, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + if len(dataSource.Name) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("name"), "")) + } + if len(dataSource.Kind) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("kind"), "")) + } + apiGroup := "" + if dataSource.APIGroup != nil { + apiGroup = *dataSource.APIGroup + } + if len(apiGroup) == 0 && dataSource.Kind != "PersistentVolumeClaim" { + allErrs = append(allErrs, field.Invalid(fldPath, dataSource.Kind, "must be 'PersistentVolumeClaim' when referencing the default apiGroup")) + } + + return allErrs +} + +// validateDataSourceRef validates a DataSourceRef in a PersistentVolumeClaimSpec +func validateDataSourceRef(dataSourceRef *core.TypedObjectReference, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + if len(dataSourceRef.Name) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("name"), "")) + } + if len(dataSourceRef.Kind) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("kind"), "")) + } + apiGroup := "" + if dataSourceRef.APIGroup != nil { + apiGroup = *dataSourceRef.APIGroup + } + if len(apiGroup) == 0 && dataSourceRef.Kind != "PersistentVolumeClaim" { + allErrs = append(allErrs, field.Invalid(fldPath, dataSourceRef.Kind, "must be 'PersistentVolumeClaim' when referencing the default apiGroup")) + } + + if dataSourceRef.Namespace != nil && len(*dataSourceRef.Namespace) > 0 { + for _, msg := range ValidateNameFunc(ValidateNamespaceName)(*dataSourceRef.Namespace, false) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("namespace"), *dataSourceRef.Namespace, msg)) + } + } + + return allErrs +} + +// ValidatePersistentVolumeClaimSpec validates a PersistentVolumeClaimSpec +func ValidatePersistentVolumeClaimSpec(spec *core.PersistentVolumeClaimSpec, fldPath *field.Path, opts PersistentVolumeClaimSpecValidationOptions) field.ErrorList { + allErrs := field.ErrorList{} + if len(spec.AccessModes) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("accessModes"), "at least 1 access mode is required")) + } + if spec.Selector != nil { + labelSelectorValidationOpts := unversionedvalidation.LabelSelectorValidationOptions{ + AllowInvalidLabelValueInSelector: opts.AllowInvalidLabelValueInSelector, + } + allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(spec.Selector, labelSelectorValidationOpts, fldPath.Child("selector"))...) + } + + expandedSupportedAccessModes := sets.StringKeySet(supportedAccessModes) + if opts.AllowReadWriteOncePod { + expandedSupportedAccessModes.Insert(string(core.ReadWriteOncePod)) + } + + foundReadWriteOncePod, foundNonReadWriteOncePod := false, false + for _, mode := range spec.AccessModes { + if !expandedSupportedAccessModes.Has(string(mode)) { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("accessModes"), mode, expandedSupportedAccessModes.List())) + } + + if mode == core.ReadWriteOncePod { + foundReadWriteOncePod = true + } else if supportedAccessModes.Has(string(mode)) { + foundNonReadWriteOncePod = true + } + } + if foundReadWriteOncePod && foundNonReadWriteOncePod { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("accessModes"), "may not use ReadWriteOncePod with other access modes")) + } + + storageValue, ok := spec.Resources.Requests[core.ResourceStorage] + if !ok { + allErrs = append(allErrs, field.Required(fldPath.Child("resources").Key(string(core.ResourceStorage)), "")) + } else if errs := ValidatePositiveQuantityValue(storageValue, fldPath.Child("resources").Key(string(core.ResourceStorage))); len(errs) > 0 { + allErrs = append(allErrs, errs...) + } else { + allErrs = append(allErrs, ValidateResourceQuantityValue(string(core.ResourceStorage), storageValue, fldPath.Child("resources").Key(string(core.ResourceStorage)))...) + } + + if spec.StorageClassName != nil && len(*spec.StorageClassName) > 0 { + for _, msg := range ValidateClassName(*spec.StorageClassName, false) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("storageClassName"), *spec.StorageClassName, msg)) + } + } + if spec.VolumeMode != nil && !supportedVolumeModes.Has(string(*spec.VolumeMode)) { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("volumeMode"), *spec.VolumeMode, supportedVolumeModes.List())) + } + + if spec.DataSource != nil { + allErrs = append(allErrs, validateDataSource(spec.DataSource, fldPath.Child("dataSource"))...) + } + if spec.DataSourceRef != nil { + allErrs = append(allErrs, validateDataSourceRef(spec.DataSourceRef, fldPath.Child("dataSourceRef"))...) + } + if spec.DataSourceRef != nil && spec.DataSourceRef.Namespace != nil && len(*spec.DataSourceRef.Namespace) > 0 { + if spec.DataSource != nil { + allErrs = append(allErrs, field.Invalid(fldPath, fldPath.Child("dataSource"), + "may not be specified when dataSourceRef.namespace is specified")) + } + } else if spec.DataSource != nil && spec.DataSourceRef != nil { + if !isDataSourceEqualDataSourceRef(spec.DataSource, spec.DataSourceRef) { + allErrs = append(allErrs, field.Invalid(fldPath, fldPath.Child("dataSource"), + "must match dataSourceRef")) + } + } + + return allErrs +} + +func isDataSourceEqualDataSourceRef(dataSource *core.TypedLocalObjectReference, dataSourceRef *core.TypedObjectReference) bool { + return reflect.DeepEqual(dataSource.APIGroup, dataSourceRef.APIGroup) && dataSource.Kind == dataSourceRef.Kind && dataSource.Name == dataSourceRef.Name +} + +// ValidatePersistentVolumeClaimUpdate validates an update to a PersistentVolumeClaim +func ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc *core.PersistentVolumeClaim, opts PersistentVolumeClaimSpecValidationOptions) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newPvc.ObjectMeta, &oldPvc.ObjectMeta, field.NewPath("metadata")) + allErrs = append(allErrs, ValidatePersistentVolumeClaim(newPvc, opts)...) + newPvcClone := newPvc.DeepCopy() + oldPvcClone := oldPvc.DeepCopy() + + // PVController needs to update PVC.Spec w/ VolumeName. + // Claims are immutable in order to enforce quota, range limits, etc. without gaming the system. + if len(oldPvc.Spec.VolumeName) == 0 { + // volumeName changes are allowed once. + oldPvcClone.Spec.VolumeName = newPvcClone.Spec.VolumeName // +k8s:verify-mutation:reason=clone + } + + if validateStorageClassUpgradeFromAnnotation(oldPvcClone.Annotations, newPvcClone.Annotations, + oldPvcClone.Spec.StorageClassName, newPvcClone.Spec.StorageClassName) { + newPvcClone.Spec.StorageClassName = nil + metav1.SetMetaDataAnnotation(&newPvcClone.ObjectMeta, core.BetaStorageClassAnnotation, oldPvcClone.Annotations[core.BetaStorageClassAnnotation]) + } else { + // storageclass annotation should be immutable after creation + // TODO: remove Beta when no longer needed + allErrs = append(allErrs, ValidateImmutableAnnotation(newPvc.ObjectMeta.Annotations[v1.BetaStorageClassAnnotation], oldPvc.ObjectMeta.Annotations[v1.BetaStorageClassAnnotation], v1.BetaStorageClassAnnotation, field.NewPath("metadata"))...) + + // If update from annotation to attribute failed we can attempt try to validate update from nil value. + if validateStorageClassUpgradeFromNil(oldPvc.Annotations, oldPvc.Spec.StorageClassName, newPvc.Spec.StorageClassName, opts) { + newPvcClone.Spec.StorageClassName = oldPvcClone.Spec.StorageClassName // +k8s:verify-mutation:reason=clone + } + // TODO: add a specific error with a hint that storage class name can not be changed + // (instead of letting spec comparison below return generic field forbidden error) + } + + // lets make sure storage values are same. + if newPvc.Status.Phase == core.ClaimBound && newPvcClone.Spec.Resources.Requests != nil { + newPvcClone.Spec.Resources.Requests["storage"] = oldPvc.Spec.Resources.Requests["storage"] // +k8s:verify-mutation:reason=clone + } + + oldSize := oldPvc.Spec.Resources.Requests["storage"] + newSize := newPvc.Spec.Resources.Requests["storage"] + statusSize := oldPvc.Status.Capacity["storage"] + + if !apiequality.Semantic.DeepEqual(newPvcClone.Spec, oldPvcClone.Spec) { + specDiff := cmp.Diff(oldPvcClone.Spec, newPvcClone.Spec) + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), fmt.Sprintf("spec is immutable after creation except resources.requests for bound claims\n%v", specDiff))) + } + if newSize.Cmp(oldSize) < 0 { + if !opts.EnableRecoverFromExpansionFailure { + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "resources", "requests", "storage"), "field can not be less than previous value")) + } else { + // This validation permits reducing pvc requested size up to capacity recorded in pvc.status + // so that users can recover from volume expansion failure, but Kubernetes does not actually + // support volume shrinking + if newSize.Cmp(statusSize) <= 0 { + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "resources", "requests", "storage"), "field can not be less than status.capacity")) + } + } + } + + allErrs = append(allErrs, ValidateImmutableField(newPvc.Spec.VolumeMode, oldPvc.Spec.VolumeMode, field.NewPath("volumeMode"))...) + + return allErrs +} + +// Provide an upgrade path from PVC with storage class specified in beta +// annotation to storage class specified in attribute. We allow update of +// StorageClassName only if following four conditions are met at the same time: +// 1. The old pvc's StorageClassAnnotation is set +// 2. The old pvc's StorageClassName is not set +// 3. The new pvc's StorageClassName is set and equal to the old value in annotation +// 4. If the new pvc's StorageClassAnnotation is set,it must be equal to the old pv/pvc's StorageClassAnnotation +func validateStorageClassUpgradeFromAnnotation(oldAnnotations, newAnnotations map[string]string, oldScName, newScName *string) bool { + oldSc, oldAnnotationExist := oldAnnotations[core.BetaStorageClassAnnotation] + newScInAnnotation, newAnnotationExist := newAnnotations[core.BetaStorageClassAnnotation] + return oldAnnotationExist /* condition 1 */ && + oldScName == nil /* condition 2*/ && + (newScName != nil && *newScName == oldSc) /* condition 3 */ && + (!newAnnotationExist || newScInAnnotation == oldSc) /* condition 4 */ +} + +// Provide an upgrade path from PVC with nil storage class. We allow update of +// StorageClassName only if following four conditions are met at the same time: +// 1. RetroactiveDefaultStorageClass FeatureGate is enabled +// 2. The new pvc's StorageClassName is not nil +// 3. The old pvc's StorageClassName is nil +// 4. The old pvc either does not have beta annotation set, or the beta annotation matches new pvc's StorageClassName +func validateStorageClassUpgradeFromNil(oldAnnotations map[string]string, oldScName, newScName *string, opts PersistentVolumeClaimSpecValidationOptions) bool { + oldAnnotation, oldAnnotationExist := oldAnnotations[core.BetaStorageClassAnnotation] + return opts.EnableRetroactiveDefaultStorageClass /* condition 1 */ && + newScName != nil /* condition 2 */ && + oldScName == nil /* condition 3 */ && + (!oldAnnotationExist || *newScName == oldAnnotation) /* condition 4 */ +} + +var resizeStatusSet = sets.NewString(string(core.PersistentVolumeClaimNoExpansionInProgress), + string(core.PersistentVolumeClaimControllerExpansionInProgress), + string(core.PersistentVolumeClaimControllerExpansionFailed), + string(core.PersistentVolumeClaimNodeExpansionPending), + string(core.PersistentVolumeClaimNodeExpansionInProgress), + string(core.PersistentVolumeClaimNodeExpansionFailed)) + +// ValidatePersistentVolumeClaimStatusUpdate validates an update to status of a PersistentVolumeClaim +func ValidatePersistentVolumeClaimStatusUpdate(newPvc, oldPvc *core.PersistentVolumeClaim, validationOpts PersistentVolumeClaimSpecValidationOptions) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newPvc.ObjectMeta, &oldPvc.ObjectMeta, field.NewPath("metadata")) + if len(newPvc.ResourceVersion) == 0 { + allErrs = append(allErrs, field.Required(field.NewPath("resourceVersion"), "")) + } + if len(newPvc.Spec.AccessModes) == 0 { + allErrs = append(allErrs, field.Required(field.NewPath("Spec", "accessModes"), "")) + } + + capPath := field.NewPath("status", "capacity") + for r, qty := range newPvc.Status.Capacity { + allErrs = append(allErrs, validateBasicResource(qty, capPath.Key(string(r)))...) + } + if validationOpts.EnableRecoverFromExpansionFailure { + resizeStatusPath := field.NewPath("status", "resizeStatus") + if newPvc.Status.ResizeStatus != nil { + resizeStatus := *newPvc.Status.ResizeStatus + if !resizeStatusSet.Has(string(resizeStatus)) { + allErrs = append(allErrs, field.NotSupported(resizeStatusPath, resizeStatus, resizeStatusSet.List())) + } + } + allocPath := field.NewPath("status", "allocatedResources") + for r, qty := range newPvc.Status.AllocatedResources { + if r != core.ResourceStorage { + allErrs = append(allErrs, field.NotSupported(allocPath, r, []string{string(core.ResourceStorage)})) + continue + } + if errs := validateBasicResource(qty, allocPath.Key(string(r))); len(errs) > 0 { + allErrs = append(allErrs, errs...) + } else { + allErrs = append(allErrs, ValidateResourceQuantityValue(string(core.ResourceStorage), qty, allocPath.Key(string(r)))...) + } + } + } + return allErrs +} + +var supportedPortProtocols = sets.NewString(string(core.ProtocolTCP), string(core.ProtocolUDP), string(core.ProtocolSCTP)) + +func validateContainerPorts(ports []core.ContainerPort, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + allNames := sets.String{} + for i, port := range ports { + idxPath := fldPath.Index(i) + if len(port.Name) > 0 { + if msgs := validation.IsValidPortName(port.Name); len(msgs) != 0 { + for i = range msgs { + allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), port.Name, msgs[i])) + } + } else if allNames.Has(port.Name) { + allErrs = append(allErrs, field.Duplicate(idxPath.Child("name"), port.Name)) + } else { + allNames.Insert(port.Name) + } + } + if port.ContainerPort == 0 { + allErrs = append(allErrs, field.Required(idxPath.Child("containerPort"), "")) + } else { + for _, msg := range validation.IsValidPortNum(int(port.ContainerPort)) { + allErrs = append(allErrs, field.Invalid(idxPath.Child("containerPort"), port.ContainerPort, msg)) + } + } + if port.HostPort != 0 { + for _, msg := range validation.IsValidPortNum(int(port.HostPort)) { + allErrs = append(allErrs, field.Invalid(idxPath.Child("hostPort"), port.HostPort, msg)) + } + } + if len(port.Protocol) == 0 { + allErrs = append(allErrs, field.Required(idxPath.Child("protocol"), "")) + } else if !supportedPortProtocols.Has(string(port.Protocol)) { + allErrs = append(allErrs, field.NotSupported(idxPath.Child("protocol"), port.Protocol, supportedPortProtocols.List())) + } + } + return allErrs +} + +// ValidateEnv validates env vars +func ValidateEnv(vars []core.EnvVar, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { + allErrs := field.ErrorList{} + + for i, ev := range vars { + idxPath := fldPath.Index(i) + if len(ev.Name) == 0 { + allErrs = append(allErrs, field.Required(idxPath.Child("name"), "")) + } else { + for _, msg := range validation.IsEnvVarName(ev.Name) { + allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), ev.Name, msg)) + } + } + allErrs = append(allErrs, validateEnvVarValueFrom(ev, idxPath.Child("valueFrom"), opts)...) + } + return allErrs +} + +var validEnvDownwardAPIFieldPathExpressions = sets.NewString( + "metadata.name", + "metadata.namespace", + "metadata.uid", + "spec.nodeName", + "spec.serviceAccountName", + "status.hostIP", + "status.podIP", + "status.podIPs") + +var validContainerResourceFieldPathExpressions = sets.NewString("limits.cpu", "limits.memory", "limits.ephemeral-storage", "requests.cpu", "requests.memory", "requests.ephemeral-storage") + +// NOTE: this is only valid with DownwardAPIHugePages enabled +var validContainerResourceFieldPathPrefixes = sets.NewString() +var validContainerResourceFieldPathPrefixesWithDownwardAPIHugePages = sets.NewString(hugepagesRequestsPrefixDownwardAPI, hugepagesLimitsPrefixDownwardAPI) + +const hugepagesRequestsPrefixDownwardAPI string = `requests.hugepages-` +const hugepagesLimitsPrefixDownwardAPI string = `limits.hugepages-` + +func validateEnvVarValueFrom(ev core.EnvVar, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { + allErrs := field.ErrorList{} + + if ev.ValueFrom == nil { + return allErrs + } + + numSources := 0 + + if ev.ValueFrom.FieldRef != nil { + numSources++ + allErrs = append(allErrs, validateObjectFieldSelector(ev.ValueFrom.FieldRef, &validEnvDownwardAPIFieldPathExpressions, fldPath.Child("fieldRef"))...) + } + if ev.ValueFrom.ResourceFieldRef != nil { + numSources++ + localValidContainerResourceFieldPathPrefixes := validContainerResourceFieldPathPrefixes + if opts.AllowDownwardAPIHugePages { + localValidContainerResourceFieldPathPrefixes = validContainerResourceFieldPathPrefixesWithDownwardAPIHugePages + } + allErrs = append(allErrs, validateContainerResourceFieldSelector(ev.ValueFrom.ResourceFieldRef, &validContainerResourceFieldPathExpressions, &localValidContainerResourceFieldPathPrefixes, fldPath.Child("resourceFieldRef"), false)...) + } + if ev.ValueFrom.ConfigMapKeyRef != nil { + numSources++ + allErrs = append(allErrs, validateConfigMapKeySelector(ev.ValueFrom.ConfigMapKeyRef, fldPath.Child("configMapKeyRef"))...) + } + if ev.ValueFrom.SecretKeyRef != nil { + numSources++ + allErrs = append(allErrs, validateSecretKeySelector(ev.ValueFrom.SecretKeyRef, fldPath.Child("secretKeyRef"))...) + } + + if numSources == 0 { + allErrs = append(allErrs, field.Invalid(fldPath, "", "must specify one of: `fieldRef`, `resourceFieldRef`, `configMapKeyRef` or `secretKeyRef`")) + } else if len(ev.Value) != 0 { + if numSources != 0 { + allErrs = append(allErrs, field.Invalid(fldPath, "", "may not be specified when `value` is not empty")) + } + } else if numSources > 1 { + allErrs = append(allErrs, field.Invalid(fldPath, "", "may not have more than one field specified at a time")) + } + + return allErrs +} + +func validateObjectFieldSelector(fs *core.ObjectFieldSelector, expressions *sets.String, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + if len(fs.APIVersion) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("apiVersion"), "")) + return allErrs + } + if len(fs.FieldPath) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("fieldPath"), "")) + return allErrs + } + + internalFieldPath, _, err := podshelper.ConvertDownwardAPIFieldLabel(fs.APIVersion, fs.FieldPath, "") + if err != nil { + allErrs = append(allErrs, field.Invalid(fldPath.Child("fieldPath"), fs.FieldPath, fmt.Sprintf("error converting fieldPath: %v", err))) + return allErrs + } + + if path, subscript, ok := fieldpath.SplitMaybeSubscriptedPath(internalFieldPath); ok { + switch path { + case "metadata.annotations": + allErrs = append(allErrs, ValidateQualifiedName(strings.ToLower(subscript), fldPath)...) + case "metadata.labels": + allErrs = append(allErrs, ValidateQualifiedName(subscript, fldPath)...) + default: + allErrs = append(allErrs, field.Invalid(fldPath, path, "does not support subscript")) + } + } else if !expressions.Has(path) { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("fieldPath"), path, expressions.List())) + return allErrs + } + + return allErrs +} + +func validateContainerResourceFieldSelector(fs *core.ResourceFieldSelector, expressions *sets.String, prefixes *sets.String, fldPath *field.Path, volume bool) field.ErrorList { + allErrs := field.ErrorList{} + + if volume && len(fs.ContainerName) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("containerName"), "")) + } else if len(fs.Resource) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("resource"), "")) + } else if !expressions.Has(fs.Resource) { + // check if the prefix is present + foundPrefix := false + if prefixes != nil { + for _, prefix := range prefixes.List() { + if strings.HasPrefix(fs.Resource, prefix) { + foundPrefix = true + } + } + } + if !foundPrefix { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("resource"), fs.Resource, expressions.List())) + } + } + allErrs = append(allErrs, validateContainerResourceDivisor(fs.Resource, fs.Divisor, fldPath)...) + return allErrs +} + +func ValidateEnvFrom(vars []core.EnvFromSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + for i, ev := range vars { + idxPath := fldPath.Index(i) + if len(ev.Prefix) > 0 { + for _, msg := range validation.IsEnvVarName(ev.Prefix) { + allErrs = append(allErrs, field.Invalid(idxPath.Child("prefix"), ev.Prefix, msg)) + } + } + + numSources := 0 + if ev.ConfigMapRef != nil { + numSources++ + allErrs = append(allErrs, validateConfigMapEnvSource(ev.ConfigMapRef, idxPath.Child("configMapRef"))...) + } + if ev.SecretRef != nil { + numSources++ + allErrs = append(allErrs, validateSecretEnvSource(ev.SecretRef, idxPath.Child("secretRef"))...) + } + + if numSources == 0 { + allErrs = append(allErrs, field.Invalid(fldPath, "", "must specify one of: `configMapRef` or `secretRef`")) + } else if numSources > 1 { + allErrs = append(allErrs, field.Invalid(fldPath, "", "may not have more than one field specified at a time")) + } + } + return allErrs +} + +func validateConfigMapEnvSource(configMapSource *core.ConfigMapEnvSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(configMapSource.Name) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("name"), "")) + } else { + for _, msg := range ValidateConfigMapName(configMapSource.Name, true) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), configMapSource.Name, msg)) + } + } + return allErrs +} + +func validateSecretEnvSource(secretSource *core.SecretEnvSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(secretSource.Name) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("name"), "")) + } else { + for _, msg := range ValidateSecretName(secretSource.Name, true) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), secretSource.Name, msg)) + } + } + return allErrs +} + +var validContainerResourceDivisorForCPU = sets.NewString("1m", "1") +var validContainerResourceDivisorForMemory = sets.NewString("1", "1k", "1M", "1G", "1T", "1P", "1E", "1Ki", "1Mi", "1Gi", "1Ti", "1Pi", "1Ei") +var validContainerResourceDivisorForHugePages = sets.NewString("1", "1k", "1M", "1G", "1T", "1P", "1E", "1Ki", "1Mi", "1Gi", "1Ti", "1Pi", "1Ei") +var validContainerResourceDivisorForEphemeralStorage = sets.NewString("1", "1k", "1M", "1G", "1T", "1P", "1E", "1Ki", "1Mi", "1Gi", "1Ti", "1Pi", "1Ei") + +func validateContainerResourceDivisor(rName string, divisor resource.Quantity, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + unsetDivisor := resource.Quantity{} + if unsetDivisor.Cmp(divisor) == 0 { + return allErrs + } + switch rName { + case "limits.cpu", "requests.cpu": + if !validContainerResourceDivisorForCPU.Has(divisor.String()) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("divisor"), rName, "only divisor's values 1m and 1 are supported with the cpu resource")) + } + case "limits.memory", "requests.memory": + if !validContainerResourceDivisorForMemory.Has(divisor.String()) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("divisor"), rName, "only divisor's values 1, 1k, 1M, 1G, 1T, 1P, 1E, 1Ki, 1Mi, 1Gi, 1Ti, 1Pi, 1Ei are supported with the memory resource")) + } + case "limits.ephemeral-storage", "requests.ephemeral-storage": + if !validContainerResourceDivisorForEphemeralStorage.Has(divisor.String()) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("divisor"), rName, "only divisor's values 1, 1k, 1M, 1G, 1T, 1P, 1E, 1Ki, 1Mi, 1Gi, 1Ti, 1Pi, 1Ei are supported with the local ephemeral storage resource")) + } + } + if strings.HasPrefix(rName, hugepagesRequestsPrefixDownwardAPI) || strings.HasPrefix(rName, hugepagesLimitsPrefixDownwardAPI) { + if !validContainerResourceDivisorForHugePages.Has(divisor.String()) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("divisor"), rName, "only divisor's values 1, 1k, 1M, 1G, 1T, 1P, 1E, 1Ki, 1Mi, 1Gi, 1Ti, 1Pi, 1Ei are supported with the hugepages resource")) + } + } + return allErrs +} + +func validateConfigMapKeySelector(s *core.ConfigMapKeySelector, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + nameFn := ValidateNameFunc(ValidateSecretName) + for _, msg := range nameFn(s.Name, false) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), s.Name, msg)) + } + if len(s.Key) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("key"), "")) + } else { + for _, msg := range validation.IsConfigMapKey(s.Key) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("key"), s.Key, msg)) + } + } + + return allErrs +} + +func validateSecretKeySelector(s *core.SecretKeySelector, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + nameFn := ValidateNameFunc(ValidateSecretName) + for _, msg := range nameFn(s.Name, false) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), s.Name, msg)) + } + if len(s.Key) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("key"), "")) + } else { + for _, msg := range validation.IsConfigMapKey(s.Key) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("key"), s.Key, msg)) + } + } + + return allErrs +} + +func GetVolumeMountMap(mounts []core.VolumeMount) map[string]string { + volmounts := make(map[string]string) + + for _, mnt := range mounts { + volmounts[mnt.Name] = mnt.MountPath + } + + return volmounts +} + +func GetVolumeDeviceMap(devices []core.VolumeDevice) map[string]string { + volDevices := make(map[string]string) + + for _, dev := range devices { + volDevices[dev.Name] = dev.DevicePath + } + + return volDevices +} + +func ValidateVolumeMounts(mounts []core.VolumeMount, voldevices map[string]string, volumes map[string]core.VolumeSource, container *core.Container, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + mountpoints := sets.NewString() + + for i, mnt := range mounts { + idxPath := fldPath.Index(i) + if len(mnt.Name) == 0 { + allErrs = append(allErrs, field.Required(idxPath.Child("name"), "")) + } + if !IsMatchedVolume(mnt.Name, volumes) { + allErrs = append(allErrs, field.NotFound(idxPath.Child("name"), mnt.Name)) + } + if len(mnt.MountPath) == 0 { + allErrs = append(allErrs, field.Required(idxPath.Child("mountPath"), "")) + } + if mountpoints.Has(mnt.MountPath) { + allErrs = append(allErrs, field.Invalid(idxPath.Child("mountPath"), mnt.MountPath, "must be unique")) + } + mountpoints.Insert(mnt.MountPath) + + // check for overlap with VolumeDevice + if mountNameAlreadyExists(mnt.Name, voldevices) { + allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), mnt.Name, "must not already exist in volumeDevices")) + } + if mountPathAlreadyExists(mnt.MountPath, voldevices) { + allErrs = append(allErrs, field.Invalid(idxPath.Child("mountPath"), mnt.MountPath, "must not already exist as a path in volumeDevices")) + } + + if len(mnt.SubPath) > 0 { + allErrs = append(allErrs, validateLocalDescendingPath(mnt.SubPath, fldPath.Child("subPath"))...) + } + + if len(mnt.SubPathExpr) > 0 { + if len(mnt.SubPath) > 0 { + allErrs = append(allErrs, field.Invalid(idxPath.Child("subPathExpr"), mnt.SubPathExpr, "subPathExpr and subPath are mutually exclusive")) + } + + allErrs = append(allErrs, validateLocalDescendingPath(mnt.SubPathExpr, fldPath.Child("subPathExpr"))...) + } + + if mnt.MountPropagation != nil { + allErrs = append(allErrs, validateMountPropagation(mnt.MountPropagation, container, fldPath.Child("mountPropagation"))...) + } + } + return allErrs +} + +func ValidateVolumeDevices(devices []core.VolumeDevice, volmounts map[string]string, volumes map[string]core.VolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + devicepath := sets.NewString() + devicename := sets.NewString() + + for i, dev := range devices { + idxPath := fldPath.Index(i) + devName := dev.Name + devPath := dev.DevicePath + didMatch, isPVC := isMatchedDevice(devName, volumes) + if len(devName) == 0 { + allErrs = append(allErrs, field.Required(idxPath.Child("name"), "")) + } + if devicename.Has(devName) { + allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), devName, "must be unique")) + } + // Must be based on PersistentVolumeClaim (PVC reference or generic ephemeral inline volume) + if didMatch && !isPVC { + allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), devName, "can only use volume source type of PersistentVolumeClaim or Ephemeral for block mode")) + } + if !didMatch { + allErrs = append(allErrs, field.NotFound(idxPath.Child("name"), devName)) + } + if len(devPath) == 0 { + allErrs = append(allErrs, field.Required(idxPath.Child("devicePath"), "")) + } + if devicepath.Has(devPath) { + allErrs = append(allErrs, field.Invalid(idxPath.Child("devicePath"), devPath, "must be unique")) + } + if len(devPath) > 0 && len(validatePathNoBacksteps(devPath, fldPath.Child("devicePath"))) > 0 { + allErrs = append(allErrs, field.Invalid(idxPath.Child("devicePath"), devPath, "can not contain backsteps ('..')")) + } else { + devicepath.Insert(devPath) + } + // check for overlap with VolumeMount + if deviceNameAlreadyExists(devName, volmounts) { + allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), devName, "must not already exist in volumeMounts")) + } + if devicePathAlreadyExists(devPath, volmounts) { + allErrs = append(allErrs, field.Invalid(idxPath.Child("devicePath"), devPath, "must not already exist as a path in volumeMounts")) + } + if len(devName) > 0 { + devicename.Insert(devName) + } + } + return allErrs +} + +func validatePodResourceClaims(claims []core.PodResourceClaim, fldPath *field.Path) field.ErrorList { + var allErrs field.ErrorList + podClaimNames := sets.NewString() + for i, claim := range claims { + allErrs = append(allErrs, validatePodResourceClaim(claim, &podClaimNames, fldPath.Index(i))...) + } + return allErrs +} + +// gatherPodResourceClaimNames returns a set of all non-empty +// PodResourceClaim.Name values. Validation that those names are valid is +// handled by validatePodResourceClaims. +func gatherPodResourceClaimNames(claims []core.PodResourceClaim) sets.String { + podClaimNames := sets.String{} + for _, claim := range claims { + if claim.Name != "" { + podClaimNames.Insert(claim.Name) + } + } + return podClaimNames +} + +func validatePodResourceClaim(claim core.PodResourceClaim, podClaimNames *sets.String, fldPath *field.Path) field.ErrorList { + var allErrs field.ErrorList + if claim.Name == "" { + allErrs = append(allErrs, field.Required(fldPath.Child("name"), "")) + } else if podClaimNames.Has(claim.Name) { + allErrs = append(allErrs, field.Duplicate(fldPath.Child("name"), claim.Name)) + } else { + allErrs = append(allErrs, ValidateDNS1123Label(claim.Name, fldPath.Child("name"))...) + podClaimNames.Insert(claim.Name) + } + allErrs = append(allErrs, validatePodResourceClaimSource(claim.Source, fldPath.Child("source"))...) + + return allErrs +} + +func validatePodResourceClaimSource(claimSource core.ClaimSource, fldPath *field.Path) field.ErrorList { + var allErrs field.ErrorList + if claimSource.ResourceClaimName != nil && claimSource.ResourceClaimTemplateName != nil { + allErrs = append(allErrs, field.Invalid(fldPath, claimSource, "at most one of `resourceClaimName` or `resourceClaimTemplateName` may be specified")) + } + if claimSource.ResourceClaimName == nil && claimSource.ResourceClaimTemplateName == nil { + allErrs = append(allErrs, field.Invalid(fldPath, claimSource, "must specify one of: `resourceClaimName`, `resourceClaimTemplateName`")) + } + return allErrs +} + +func validateProbe(probe *core.Probe, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + if probe == nil { + return allErrs + } + allErrs = append(allErrs, validateHandler(handlerFromProbe(&probe.ProbeHandler), fldPath)...) + + allErrs = append(allErrs, ValidateNonnegativeField(int64(probe.InitialDelaySeconds), fldPath.Child("initialDelaySeconds"))...) + allErrs = append(allErrs, ValidateNonnegativeField(int64(probe.TimeoutSeconds), fldPath.Child("timeoutSeconds"))...) + allErrs = append(allErrs, ValidateNonnegativeField(int64(probe.PeriodSeconds), fldPath.Child("periodSeconds"))...) + allErrs = append(allErrs, ValidateNonnegativeField(int64(probe.SuccessThreshold), fldPath.Child("successThreshold"))...) + allErrs = append(allErrs, ValidateNonnegativeField(int64(probe.FailureThreshold), fldPath.Child("failureThreshold"))...) + if probe.TerminationGracePeriodSeconds != nil && *probe.TerminationGracePeriodSeconds <= 0 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("terminationGracePeriodSeconds"), *probe.TerminationGracePeriodSeconds, "must be greater than 0")) + } + return allErrs +} + +type commonHandler struct { + Exec *core.ExecAction + HTTPGet *core.HTTPGetAction + TCPSocket *core.TCPSocketAction + GRPC *core.GRPCAction +} + +func handlerFromProbe(ph *core.ProbeHandler) commonHandler { + return commonHandler{ + Exec: ph.Exec, + HTTPGet: ph.HTTPGet, + TCPSocket: ph.TCPSocket, + GRPC: ph.GRPC, + } +} + +func handlerFromLifecycle(lh *core.LifecycleHandler) commonHandler { + return commonHandler{ + Exec: lh.Exec, + HTTPGet: lh.HTTPGet, + TCPSocket: lh.TCPSocket, + } +} + +func validateClientIPAffinityConfig(config *core.SessionAffinityConfig, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if config == nil { + allErrs = append(allErrs, field.Required(fldPath, fmt.Sprintf("when session affinity type is %s", core.ServiceAffinityClientIP))) + return allErrs + } + if config.ClientIP == nil { + allErrs = append(allErrs, field.Required(fldPath.Child("clientIP"), fmt.Sprintf("when session affinity type is %s", core.ServiceAffinityClientIP))) + return allErrs + } + if config.ClientIP.TimeoutSeconds == nil { + allErrs = append(allErrs, field.Required(fldPath.Child("clientIP").Child("timeoutSeconds"), fmt.Sprintf("when session affinity type is %s", core.ServiceAffinityClientIP))) + return allErrs + } + allErrs = append(allErrs, validateAffinityTimeout(config.ClientIP.TimeoutSeconds, fldPath.Child("clientIP").Child("timeoutSeconds"))...) + + return allErrs +} + +func validateAffinityTimeout(timeout *int32, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if *timeout <= 0 || *timeout > core.MaxClientIPServiceAffinitySeconds { + allErrs = append(allErrs, field.Invalid(fldPath, timeout, fmt.Sprintf("must be greater than 0 and less than %d", core.MaxClientIPServiceAffinitySeconds))) + } + return allErrs +} + +// AccumulateUniqueHostPorts extracts each HostPort of each Container, +// accumulating the results and returning an error if any ports conflict. +func AccumulateUniqueHostPorts(containers []core.Container, accumulator *sets.String, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + for ci, ctr := range containers { + idxPath := fldPath.Index(ci) + portsPath := idxPath.Child("ports") + for pi := range ctr.Ports { + idxPath := portsPath.Index(pi) + port := ctr.Ports[pi].HostPort + if port == 0 { + continue + } + str := fmt.Sprintf("%s/%s/%d", ctr.Ports[pi].Protocol, ctr.Ports[pi].HostIP, port) + if accumulator.Has(str) { + allErrs = append(allErrs, field.Duplicate(idxPath.Child("hostPort"), str)) + } else { + accumulator.Insert(str) + } + } + } + return allErrs +} + +// checkHostPortConflicts checks for colliding Port.HostPort values across +// a slice of containers. +func checkHostPortConflicts(containers []core.Container, fldPath *field.Path) field.ErrorList { + allPorts := sets.String{} + return AccumulateUniqueHostPorts(containers, &allPorts, fldPath) +} + +func validateExecAction(exec *core.ExecAction, fldPath *field.Path) field.ErrorList { + allErrors := field.ErrorList{} + if len(exec.Command) == 0 { + allErrors = append(allErrors, field.Required(fldPath.Child("command"), "")) + } + return allErrors +} + +var supportedHTTPSchemes = sets.NewString(string(core.URISchemeHTTP), string(core.URISchemeHTTPS)) + +func validateHTTPGetAction(http *core.HTTPGetAction, fldPath *field.Path) field.ErrorList { + allErrors := field.ErrorList{} + if len(http.Path) == 0 { + allErrors = append(allErrors, field.Required(fldPath.Child("path"), "")) + } + allErrors = append(allErrors, ValidatePortNumOrName(http.Port, fldPath.Child("port"))...) + if !supportedHTTPSchemes.Has(string(http.Scheme)) { + allErrors = append(allErrors, field.NotSupported(fldPath.Child("scheme"), http.Scheme, supportedHTTPSchemes.List())) + } + for _, header := range http.HTTPHeaders { + for _, msg := range validation.IsHTTPHeaderName(header.Name) { + allErrors = append(allErrors, field.Invalid(fldPath.Child("httpHeaders"), header.Name, msg)) + } + } + return allErrors +} + +func ValidatePortNumOrName(port intstr.IntOrString, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if port.Type == intstr.Int { + for _, msg := range validation.IsValidPortNum(port.IntValue()) { + allErrs = append(allErrs, field.Invalid(fldPath, port.IntValue(), msg)) + } + } else if port.Type == intstr.String { + for _, msg := range validation.IsValidPortName(port.StrVal) { + allErrs = append(allErrs, field.Invalid(fldPath, port.StrVal, msg)) + } + } else { + allErrs = append(allErrs, field.InternalError(fldPath, fmt.Errorf("unknown type: %v", port.Type))) + } + return allErrs +} + +func validateTCPSocketAction(tcp *core.TCPSocketAction, fldPath *field.Path) field.ErrorList { + return ValidatePortNumOrName(tcp.Port, fldPath.Child("port")) +} +func validateGRPCAction(grpc *core.GRPCAction, fldPath *field.Path) field.ErrorList { + return ValidatePortNumOrName(intstr.FromInt(int(grpc.Port)), fldPath.Child("port")) +} +func validateHandler(handler commonHandler, fldPath *field.Path) field.ErrorList { + numHandlers := 0 + allErrors := field.ErrorList{} + if handler.Exec != nil { + if numHandlers > 0 { + allErrors = append(allErrors, field.Forbidden(fldPath.Child("exec"), "may not specify more than 1 handler type")) + } else { + numHandlers++ + allErrors = append(allErrors, validateExecAction(handler.Exec, fldPath.Child("exec"))...) + } + } + if handler.HTTPGet != nil { + if numHandlers > 0 { + allErrors = append(allErrors, field.Forbidden(fldPath.Child("httpGet"), "may not specify more than 1 handler type")) + } else { + numHandlers++ + allErrors = append(allErrors, validateHTTPGetAction(handler.HTTPGet, fldPath.Child("httpGet"))...) + } + } + if handler.TCPSocket != nil { + if numHandlers > 0 { + allErrors = append(allErrors, field.Forbidden(fldPath.Child("tcpSocket"), "may not specify more than 1 handler type")) + } else { + numHandlers++ + allErrors = append(allErrors, validateTCPSocketAction(handler.TCPSocket, fldPath.Child("tcpSocket"))...) + } + } + if handler.GRPC != nil { + if numHandlers > 0 { + allErrors = append(allErrors, field.Forbidden(fldPath.Child("grpc"), "may not specify more than 1 handler type")) + } else { + numHandlers++ + allErrors = append(allErrors, validateGRPCAction(handler.GRPC, fldPath.Child("grpc"))...) + } + } + if numHandlers == 0 { + allErrors = append(allErrors, field.Required(fldPath, "must specify a handler type")) + } + return allErrors +} + +func validateLifecycle(lifecycle *core.Lifecycle, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if lifecycle.PostStart != nil { + allErrs = append(allErrs, validateHandler(handlerFromLifecycle(lifecycle.PostStart), fldPath.Child("postStart"))...) + } + if lifecycle.PreStop != nil { + allErrs = append(allErrs, validateHandler(handlerFromLifecycle(lifecycle.PreStop), fldPath.Child("preStop"))...) + } + return allErrs +} + +var supportedPullPolicies = sets.NewString(string(core.PullAlways), string(core.PullIfNotPresent), string(core.PullNever)) + +func validatePullPolicy(policy core.PullPolicy, fldPath *field.Path) field.ErrorList { + allErrors := field.ErrorList{} + + switch policy { + case core.PullAlways, core.PullIfNotPresent, core.PullNever: + break + case "": + allErrors = append(allErrors, field.Required(fldPath, "")) + default: + allErrors = append(allErrors, field.NotSupported(fldPath, policy, supportedPullPolicies.List())) + } + + return allErrors +} + +// validateEphemeralContainers is called by pod spec and template validation to validate the list of ephemeral containers. +// Note that this is called for pod template even though ephemeral containers aren't allowed in pod templates. +func validateEphemeralContainers(ephemeralContainers []core.EphemeralContainer, containers, initContainers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.String, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { + var allErrs field.ErrorList + + if len(ephemeralContainers) == 0 { + return allErrs + } + + otherNames, allNames := sets.String{}, sets.String{} + for _, c := range containers { + otherNames.Insert(c.Name) + allNames.Insert(c.Name) + } + for _, c := range initContainers { + otherNames.Insert(c.Name) + allNames.Insert(c.Name) + } + + for i, ec := range ephemeralContainers { + idxPath := fldPath.Index(i) + + c := (*core.Container)(&ec.EphemeralContainerCommon) + allErrs = append(allErrs, validateContainerCommon(c, volumes, podClaimNames, idxPath, opts)...) + // Ephemeral containers don't need looser constraints for pod templates, so it's convenient to apply both validations + // here where we've already converted EphemeralContainerCommon to Container. + allErrs = append(allErrs, validateContainerOnlyForPod(c, idxPath)...) + + // Ephemeral containers must have a name unique across all container types. + if allNames.Has(ec.Name) { + allErrs = append(allErrs, field.Duplicate(idxPath.Child("name"), ec.Name)) + } else { + allNames.Insert(ec.Name) + } + + // The target container name must exist and be non-ephemeral. + if ec.TargetContainerName != "" && !otherNames.Has(ec.TargetContainerName) { + allErrs = append(allErrs, field.NotFound(idxPath.Child("targetContainerName"), ec.TargetContainerName)) + } + + // Ephemeral containers should not be relied upon for fundamental pod services, so fields such as + // Lifecycle, probes, resources and ports should be disallowed. This is implemented as a list + // of allowed fields so that new fields will be given consideration prior to inclusion in ephemeral containers. + allErrs = append(allErrs, validateFieldAllowList(ec.EphemeralContainerCommon, allowedEphemeralContainerFields, "cannot be set for an Ephemeral Container", idxPath)...) + + // VolumeMount subpaths have the potential to leak resources since they're implemented with bind mounts + // that aren't cleaned up until the pod exits. Since they also imply that the container is being used + // as part of the workload, they're disallowed entirely. + for i, vm := range ec.VolumeMounts { + if vm.SubPath != "" { + allErrs = append(allErrs, field.Forbidden(idxPath.Child("volumeMounts").Index(i).Child("subPath"), "cannot be set for an Ephemeral Container")) + } + if vm.SubPathExpr != "" { + allErrs = append(allErrs, field.Forbidden(idxPath.Child("volumeMounts").Index(i).Child("subPathExpr"), "cannot be set for an Ephemeral Container")) + } + } + } + + return allErrs +} + +// ValidateFieldAcceptList checks that only allowed fields are set. +// The value must be a struct (not a pointer to a struct!). +func validateFieldAllowList(value interface{}, allowedFields map[string]bool, errorText string, fldPath *field.Path) field.ErrorList { + var allErrs field.ErrorList + + reflectType, reflectValue := reflect.TypeOf(value), reflect.ValueOf(value) + for i := 0; i < reflectType.NumField(); i++ { + f := reflectType.Field(i) + if allowedFields[f.Name] { + continue + } + + // Compare the value of this field to its zero value to determine if it has been set + if !reflect.DeepEqual(reflectValue.Field(i).Interface(), reflect.Zero(f.Type).Interface()) { + r, n := utf8.DecodeRuneInString(f.Name) + lcName := string(unicode.ToLower(r)) + f.Name[n:] + allErrs = append(allErrs, field.Forbidden(fldPath.Child(lcName), errorText)) + } + } + + return allErrs +} + +// validateInitContainers is called by pod spec and template validation to validate the list of init containers +func validateInitContainers(containers []core.Container, regularContainers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.String, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { + var allErrs field.ErrorList + + allNames := sets.String{} + for _, ctr := range regularContainers { + allNames.Insert(ctr.Name) + } + for i, ctr := range containers { + idxPath := fldPath.Index(i) + + // Apply the validation common to all container types + allErrs = append(allErrs, validateContainerCommon(&ctr, volumes, podClaimNames, idxPath, opts)...) + + // Names must be unique within regular and init containers. Collisions with ephemeral containers + // will be detected by validateEphemeralContainers(). + if allNames.Has(ctr.Name) { + allErrs = append(allErrs, field.Duplicate(idxPath.Child("name"), ctr.Name)) + } else if len(ctr.Name) > 0 { + allNames.Insert(ctr.Name) + } + + // Check for port conflicts in init containers individually since init containers run one-by-one. + allErrs = append(allErrs, checkHostPortConflicts([]core.Container{ctr}, fldPath)...) + + // These fields are disallowed for init containers. + if ctr.Lifecycle != nil { + allErrs = append(allErrs, field.Forbidden(idxPath.Child("lifecycle"), "may not be set for init containers")) + } + if ctr.LivenessProbe != nil { + allErrs = append(allErrs, field.Forbidden(idxPath.Child("livenessProbe"), "may not be set for init containers")) + } + if ctr.ReadinessProbe != nil { + allErrs = append(allErrs, field.Forbidden(idxPath.Child("readinessProbe"), "may not be set for init containers")) + } + if ctr.StartupProbe != nil { + allErrs = append(allErrs, field.Forbidden(idxPath.Child("startupProbe"), "may not be set for init containers")) + } + } + + return allErrs +} + +// validateContainerCommon applies validation common to all container types. It's called by regular, init, and ephemeral +// container list validation to require a properly formatted name, image, etc. +func validateContainerCommon(ctr *core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.String, path *field.Path, opts PodValidationOptions) field.ErrorList { + var allErrs field.ErrorList + + namePath := path.Child("name") + if len(ctr.Name) == 0 { + allErrs = append(allErrs, field.Required(namePath, "")) + } else { + allErrs = append(allErrs, ValidateDNS1123Label(ctr.Name, namePath)...) + } + + // TODO: do not validate leading and trailing whitespace to preserve backward compatibility. + // for example: https://github.com/openshift/origin/issues/14659 image = " " is special token in pod template + // others may have done similar + if len(ctr.Image) == 0 { + allErrs = append(allErrs, field.Required(path.Child("image"), "")) + } + + switch ctr.TerminationMessagePolicy { + case core.TerminationMessageReadFile, core.TerminationMessageFallbackToLogsOnError: + case "": + allErrs = append(allErrs, field.Required(path.Child("terminationMessagePolicy"), "")) + default: + supported := []string{ + string(core.TerminationMessageReadFile), + string(core.TerminationMessageFallbackToLogsOnError), + } + allErrs = append(allErrs, field.NotSupported(path.Child("terminationMessagePolicy"), ctr.TerminationMessagePolicy, supported)) + } + + volMounts := GetVolumeMountMap(ctr.VolumeMounts) + volDevices := GetVolumeDeviceMap(ctr.VolumeDevices) + allErrs = append(allErrs, validateContainerPorts(ctr.Ports, path.Child("ports"))...) + allErrs = append(allErrs, ValidateEnv(ctr.Env, path.Child("env"), opts)...) + allErrs = append(allErrs, ValidateEnvFrom(ctr.EnvFrom, path.Child("envFrom"))...) + allErrs = append(allErrs, ValidateVolumeMounts(ctr.VolumeMounts, volDevices, volumes, ctr, path.Child("volumeMounts"))...) + allErrs = append(allErrs, ValidateVolumeDevices(ctr.VolumeDevices, volMounts, volumes, path.Child("volumeDevices"))...) + allErrs = append(allErrs, validatePullPolicy(ctr.ImagePullPolicy, path.Child("imagePullPolicy"))...) + allErrs = append(allErrs, ValidateResourceRequirements(&ctr.Resources, podClaimNames, path.Child("resources"), opts)...) + allErrs = append(allErrs, ValidateSecurityContext(ctr.SecurityContext, path.Child("securityContext"))...) + return allErrs +} + +func validateHostUsers(spec *core.PodSpec, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + // Only make the following checks if hostUsers is false (otherwise, the container uses the + // same userns as the host, and so there isn't anything to check). + if spec.SecurityContext == nil || spec.SecurityContext.HostUsers == nil || *spec.SecurityContext.HostUsers == true { + return allErrs + } + + // For now only these volumes are supported: + // - configmap + // - secret + // - downwardAPI + // - emptyDir + // - projected + // So reject anything else. + for i, vol := range spec.Volumes { + switch { + case vol.EmptyDir != nil: + case vol.Secret != nil: + case vol.DownwardAPI != nil: + case vol.ConfigMap != nil: + case vol.Projected != nil: + default: + allErrs = append(allErrs, field.Forbidden(fldPath.Child("volumes").Index(i), "volume type not supported when `pod.Spec.HostUsers` is false")) + } + } + + // We decided to restrict the usage of userns with other host namespaces: + // https://github.com/kubernetes/kubernetes/pull/111090#discussion_r935994282 + // The tl;dr is: you can easily run into permission issues that seem unexpected, we don't + // know of any good use case and we can always enable them later. + + // Note we already validated above spec.SecurityContext is not nil. + if spec.SecurityContext.HostNetwork { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("hostNetwork"), "when `pod.Spec.HostUsers` is false")) + } + if spec.SecurityContext.HostPID { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("HostPID"), "when `pod.Spec.HostUsers` is false")) + } + if spec.SecurityContext.HostIPC { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("HostIPC"), "when `pod.Spec.HostUsers` is false")) + } + + return allErrs +} + +// validateContainers is called by pod spec and template validation to validate the list of regular containers. +func validateContainers(containers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.String, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { + allErrs := field.ErrorList{} + + if len(containers) == 0 { + return append(allErrs, field.Required(fldPath, "")) + } + + allNames := sets.String{} + for i, ctr := range containers { + path := fldPath.Index(i) + + // Apply validation common to all containers + allErrs = append(allErrs, validateContainerCommon(&ctr, volumes, podClaimNames, path, opts)...) + + // Container names must be unique within the list of regular containers. + // Collisions with init or ephemeral container names will be detected by the init or ephemeral + // container validation to prevent duplicate error messages. + if allNames.Has(ctr.Name) { + allErrs = append(allErrs, field.Duplicate(path.Child("name"), ctr.Name)) + } else { + allNames.Insert(ctr.Name) + } + + // These fields are only allowed for regular containers, so only check supported values here. + // Init and ephemeral container validation will return field.Forbidden() for these paths. + if ctr.Lifecycle != nil { + allErrs = append(allErrs, validateLifecycle(ctr.Lifecycle, path.Child("lifecycle"))...) + } + allErrs = append(allErrs, validateProbe(ctr.LivenessProbe, path.Child("livenessProbe"))...) + if ctr.LivenessProbe != nil && ctr.LivenessProbe.SuccessThreshold != 1 { + allErrs = append(allErrs, field.Invalid(path.Child("livenessProbe", "successThreshold"), ctr.LivenessProbe.SuccessThreshold, "must be 1")) + } + allErrs = append(allErrs, validateProbe(ctr.ReadinessProbe, path.Child("readinessProbe"))...) + if ctr.ReadinessProbe != nil && ctr.ReadinessProbe.TerminationGracePeriodSeconds != nil { + allErrs = append(allErrs, field.Invalid(path.Child("readinessProbe", "terminationGracePeriodSeconds"), ctr.ReadinessProbe.TerminationGracePeriodSeconds, "must not be set for readinessProbes")) + } + allErrs = append(allErrs, validateProbe(ctr.StartupProbe, path.Child("startupProbe"))...) + if ctr.StartupProbe != nil && ctr.StartupProbe.SuccessThreshold != 1 { + allErrs = append(allErrs, field.Invalid(path.Child("startupProbe", "successThreshold"), ctr.StartupProbe.SuccessThreshold, "must be 1")) + } + } + + // Port conflicts are checked across all containers + allErrs = append(allErrs, checkHostPortConflicts(containers, fldPath)...) + + return allErrs +} + +func validateRestartPolicy(restartPolicy *core.RestartPolicy, fldPath *field.Path) field.ErrorList { + allErrors := field.ErrorList{} + switch *restartPolicy { + case core.RestartPolicyAlways, core.RestartPolicyOnFailure, core.RestartPolicyNever: + break + case "": + allErrors = append(allErrors, field.Required(fldPath, "")) + default: + validValues := []string{string(core.RestartPolicyAlways), string(core.RestartPolicyOnFailure), string(core.RestartPolicyNever)} + allErrors = append(allErrors, field.NotSupported(fldPath, *restartPolicy, validValues)) + } + + return allErrors +} + +func ValidatePreemptionPolicy(preemptionPolicy *core.PreemptionPolicy, fldPath *field.Path) field.ErrorList { + allErrors := field.ErrorList{} + switch *preemptionPolicy { + case core.PreemptLowerPriority, core.PreemptNever: + case "": + allErrors = append(allErrors, field.Required(fldPath, "")) + default: + validValues := []string{string(core.PreemptLowerPriority), string(core.PreemptNever)} + allErrors = append(allErrors, field.NotSupported(fldPath, preemptionPolicy, validValues)) + } + return allErrors +} + +func validateDNSPolicy(dnsPolicy *core.DNSPolicy, fldPath *field.Path) field.ErrorList { + allErrors := field.ErrorList{} + switch *dnsPolicy { + case core.DNSClusterFirstWithHostNet, core.DNSClusterFirst, core.DNSDefault, core.DNSNone: + case "": + allErrors = append(allErrors, field.Required(fldPath, "")) + default: + validValues := []string{string(core.DNSClusterFirstWithHostNet), string(core.DNSClusterFirst), string(core.DNSDefault), string(core.DNSNone)} + allErrors = append(allErrors, field.NotSupported(fldPath, dnsPolicy, validValues)) + } + return allErrors +} + +var validFSGroupChangePolicies = sets.NewString(string(core.FSGroupChangeOnRootMismatch), string(core.FSGroupChangeAlways)) + +func validateFSGroupChangePolicy(fsGroupPolicy *core.PodFSGroupChangePolicy, fldPath *field.Path) field.ErrorList { + allErrors := field.ErrorList{} + if !validFSGroupChangePolicies.Has(string(*fsGroupPolicy)) { + allErrors = append(allErrors, field.NotSupported(fldPath, fsGroupPolicy, validFSGroupChangePolicies.List())) + } + return allErrors +} + +const ( + // Limits on various DNS parameters. These are derived from + // restrictions in Linux libc name resolution handling. + // Max number of DNS name servers. + MaxDNSNameservers = 3 + // Expanded max number of domains in the search path list. + MaxDNSSearchPathsExpanded = 32 + // Expanded max number of characters in the search path. + MaxDNSSearchListCharsExpanded = 2048 + // Max number of domains in the search path list. + MaxDNSSearchPathsLegacy = 6 + // Max number of characters in the search path list. + MaxDNSSearchListCharsLegacy = 256 +) + +func validateReadinessGates(readinessGates []core.PodReadinessGate, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + for i, value := range readinessGates { + allErrs = append(allErrs, ValidateQualifiedName(string(value.ConditionType), fldPath.Index(i).Child("conditionType"))...) + } + return allErrs +} + +func validateSchedulingGates(schedulingGates []core.PodSchedulingGate, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + // There should be no duplicates in the list of scheduling gates. + seen := sets.String{} + for i, schedulingGate := range schedulingGates { + if schedulingGate.Name == "" { + allErrs = append(allErrs, field.Required(fldPath.Index(i), "must not be empty")) + } + if seen.Has(schedulingGate.Name) { + allErrs = append(allErrs, field.Duplicate(fldPath.Index(i), schedulingGate.Name)) + } + seen.Insert(schedulingGate.Name) + } + return allErrs +} + +func validatePodDNSConfig(dnsConfig *core.PodDNSConfig, dnsPolicy *core.DNSPolicy, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { + allErrs := field.ErrorList{} + + // Validate DNSNone case. Must provide at least one DNS name server. + if dnsPolicy != nil && *dnsPolicy == core.DNSNone { + if dnsConfig == nil { + return append(allErrs, field.Required(fldPath, fmt.Sprintf("must provide `dnsConfig` when `dnsPolicy` is %s", core.DNSNone))) + } + if len(dnsConfig.Nameservers) == 0 { + return append(allErrs, field.Required(fldPath.Child("nameservers"), fmt.Sprintf("must provide at least one DNS nameserver when `dnsPolicy` is %s", core.DNSNone))) + } + } + + if dnsConfig != nil { + // Validate nameservers. + if len(dnsConfig.Nameservers) > MaxDNSNameservers { + allErrs = append(allErrs, field.Invalid(fldPath.Child("nameservers"), dnsConfig.Nameservers, fmt.Sprintf("must not have more than %v nameservers", MaxDNSNameservers))) + } + for i, ns := range dnsConfig.Nameservers { + if ip := netutils.ParseIPSloppy(ns); ip == nil { + allErrs = append(allErrs, field.Invalid(fldPath.Child("nameservers").Index(i), ns, "must be valid IP address")) + } + } + // Validate searches. + maxDNSSearchPaths, maxDNSSearchListChars := MaxDNSSearchPathsLegacy, MaxDNSSearchListCharsLegacy + if opts.AllowExpandedDNSConfig { + maxDNSSearchPaths, maxDNSSearchListChars = MaxDNSSearchPathsExpanded, MaxDNSSearchListCharsExpanded + } + if len(dnsConfig.Searches) > maxDNSSearchPaths { + allErrs = append(allErrs, field.Invalid(fldPath.Child("searches"), dnsConfig.Searches, fmt.Sprintf("must not have more than %v search paths", maxDNSSearchPaths))) + } + // Include the space between search paths. + if len(strings.Join(dnsConfig.Searches, " ")) > maxDNSSearchListChars { + allErrs = append(allErrs, field.Invalid(fldPath.Child("searches"), dnsConfig.Searches, fmt.Sprintf("must not have more than %v characters (including spaces) in the search list", maxDNSSearchListChars))) + } + for i, search := range dnsConfig.Searches { + // it is fine to have a trailing dot + search = strings.TrimSuffix(search, ".") + allErrs = append(allErrs, ValidateDNS1123Subdomain(search, fldPath.Child("searches").Index(i))...) + } + // Validate options. + for i, option := range dnsConfig.Options { + if len(option.Name) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("options").Index(i), "must not be empty")) + } + } + } + return allErrs +} + +func validateHostNetwork(hostNetwork bool, containers []core.Container, fldPath *field.Path) field.ErrorList { + allErrors := field.ErrorList{} + if hostNetwork { + for i, container := range containers { + portsPath := fldPath.Index(i).Child("ports") + for i, port := range container.Ports { + idxPath := portsPath.Index(i) + if port.HostPort != port.ContainerPort { + allErrors = append(allErrors, field.Invalid(idxPath.Child("containerPort"), port.ContainerPort, "must match `hostPort` when `hostNetwork` is true")) + } + } + } + } + return allErrors +} + +// validateImagePullSecrets checks to make sure the pull secrets are well +// formed. Right now, we only expect name to be set (it's the only field). If +// this ever changes and someone decides to set those fields, we'd like to +// know. +func validateImagePullSecrets(imagePullSecrets []core.LocalObjectReference, fldPath *field.Path) field.ErrorList { + allErrors := field.ErrorList{} + for i, currPullSecret := range imagePullSecrets { + idxPath := fldPath.Index(i) + strippedRef := core.LocalObjectReference{Name: currPullSecret.Name} + if !reflect.DeepEqual(strippedRef, currPullSecret) { + allErrors = append(allErrors, field.Invalid(idxPath, currPullSecret, "only name may be set")) + } + } + return allErrors +} + +// validateAffinity checks if given affinities are valid +func validateAffinity(affinity *core.Affinity, opts PodValidationOptions, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + if affinity != nil { + if affinity.NodeAffinity != nil { + allErrs = append(allErrs, validateNodeAffinity(affinity.NodeAffinity, fldPath.Child("nodeAffinity"))...) + } + if affinity.PodAffinity != nil { + allErrs = append(allErrs, validatePodAffinity(affinity.PodAffinity, opts.AllowInvalidLabelValueInSelector, fldPath.Child("podAffinity"))...) + } + if affinity.PodAntiAffinity != nil { + allErrs = append(allErrs, validatePodAntiAffinity(affinity.PodAntiAffinity, opts.AllowInvalidLabelValueInSelector, fldPath.Child("podAntiAffinity"))...) + } + } + + return allErrs +} + +func validateTaintEffect(effect *core.TaintEffect, allowEmpty bool, fldPath *field.Path) field.ErrorList { + if !allowEmpty && len(*effect) == 0 { + return field.ErrorList{field.Required(fldPath, "")} + } + + allErrors := field.ErrorList{} + switch *effect { + // TODO: Replace next line with subsequent commented-out line when implement TaintEffectNoScheduleNoAdmit. + case core.TaintEffectNoSchedule, core.TaintEffectPreferNoSchedule, core.TaintEffectNoExecute: + // case core.TaintEffectNoSchedule, core.TaintEffectPreferNoSchedule, core.TaintEffectNoScheduleNoAdmit, core.TaintEffectNoExecute: + default: + validValues := []string{ + string(core.TaintEffectNoSchedule), + string(core.TaintEffectPreferNoSchedule), + string(core.TaintEffectNoExecute), + // TODO: Uncomment this block when implement TaintEffectNoScheduleNoAdmit. + // string(core.TaintEffectNoScheduleNoAdmit), + } + allErrors = append(allErrors, field.NotSupported(fldPath, *effect, validValues)) + } + return allErrors +} + +// validateOnlyAddedTolerations validates updated pod tolerations. +func validateOnlyAddedTolerations(newTolerations []core.Toleration, oldTolerations []core.Toleration, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + for _, old := range oldTolerations { + found := false + oldTolerationClone := old.DeepCopy() + for _, newToleration := range newTolerations { + // assign to our clone before doing a deep equal so we can allow tolerationseconds to change. + oldTolerationClone.TolerationSeconds = newToleration.TolerationSeconds // +k8s:verify-mutation:reason=clone + if reflect.DeepEqual(*oldTolerationClone, newToleration) { + found = true + break + } + } + if !found { + allErrs = append(allErrs, field.Forbidden(fldPath, "existing toleration can not be modified except its tolerationSeconds")) + return allErrs + } + } + + allErrs = append(allErrs, ValidateTolerations(newTolerations, fldPath)...) + return allErrs +} + +func validateOnlyDeletedSchedulingGates(newGates, oldGates []core.PodSchedulingGate, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(newGates) == 0 { + return allErrs + } + + additionalGates := make(map[string]int) + for i, newGate := range newGates { + additionalGates[newGate.Name] = i + } + + for _, oldGate := range oldGates { + delete(additionalGates, oldGate.Name) + } + + for gate, i := range additionalGates { + allErrs = append(allErrs, field.Forbidden(fldPath.Index(i).Child("name"), fmt.Sprintf("only deletion is allowed, but found new scheduling gate '%s'", gate))) + } + + return allErrs +} + +func ValidateHostAliases(hostAliases []core.HostAlias, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + for _, hostAlias := range hostAliases { + if ip := netutils.ParseIPSloppy(hostAlias.IP); ip == nil { + allErrs = append(allErrs, field.Invalid(fldPath.Child("ip"), hostAlias.IP, "must be valid IP address")) + } + for _, hostname := range hostAlias.Hostnames { + allErrs = append(allErrs, ValidateDNS1123Subdomain(hostname, fldPath.Child("hostnames"))...) + } + } + return allErrs +} + +// ValidateTolerations tests if given tolerations have valid data. +func ValidateTolerations(tolerations []core.Toleration, fldPath *field.Path) field.ErrorList { + allErrors := field.ErrorList{} + for i, toleration := range tolerations { + idxPath := fldPath.Index(i) + // validate the toleration key + if len(toleration.Key) > 0 { + allErrors = append(allErrors, unversionedvalidation.ValidateLabelName(toleration.Key, idxPath.Child("key"))...) + } + + // empty toleration key with Exists operator and empty value means match all taints + if len(toleration.Key) == 0 && toleration.Operator != core.TolerationOpExists { + allErrors = append(allErrors, field.Invalid(idxPath.Child("operator"), toleration.Operator, + "operator must be Exists when `key` is empty, which means \"match all values and all keys\"")) + } + + if toleration.TolerationSeconds != nil && toleration.Effect != core.TaintEffectNoExecute { + allErrors = append(allErrors, field.Invalid(idxPath.Child("effect"), toleration.Effect, + "effect must be 'NoExecute' when `tolerationSeconds` is set")) + } + + // validate toleration operator and value + switch toleration.Operator { + // empty operator means Equal + case core.TolerationOpEqual, "": + if errs := validation.IsValidLabelValue(toleration.Value); len(errs) != 0 { + allErrors = append(allErrors, field.Invalid(idxPath.Child("operator"), toleration.Value, strings.Join(errs, ";"))) + } + case core.TolerationOpExists: + if len(toleration.Value) > 0 { + allErrors = append(allErrors, field.Invalid(idxPath.Child("operator"), toleration, "value must be empty when `operator` is 'Exists'")) + } + default: + validValues := []string{string(core.TolerationOpEqual), string(core.TolerationOpExists)} + allErrors = append(allErrors, field.NotSupported(idxPath.Child("operator"), toleration.Operator, validValues)) + } + + // validate toleration effect, empty toleration effect means match all taint effects + if len(toleration.Effect) > 0 { + allErrors = append(allErrors, validateTaintEffect(&toleration.Effect, true, idxPath.Child("effect"))...) + } + } + return allErrors +} + +// validateContainersOnlyForPod does additional validation for containers on a pod versus a pod template +// it only does additive validation of fields not covered in validateContainers and is not called for +// ephemeral containers which require a conversion to core.Container. +func validateContainersOnlyForPod(containers []core.Container, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + for i, ctr := range containers { + allErrs = append(allErrs, validateContainerOnlyForPod(&ctr, fldPath.Index(i))...) + } + return allErrs +} + +// validateContainerOnlyForPod does pod-only (i.e. not pod template) validation for a single container. +// This is called by validateContainersOnlyForPod and validateEphemeralContainers directly. +func validateContainerOnlyForPod(ctr *core.Container, path *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(ctr.Image) != len(strings.TrimSpace(ctr.Image)) { + allErrs = append(allErrs, field.Invalid(path.Child("image"), ctr.Image, "must not have leading or trailing whitespace")) + } + return allErrs +} + +// PodValidationOptions contains the different settings for pod validation +type PodValidationOptions struct { + // Allow pod spec to use hugepages in downward API + AllowDownwardAPIHugePages bool + // Allow invalid pod-deletion-cost annotation value for backward compatibility. + AllowInvalidPodDeletionCost bool + // Allow invalid label-value in LabelSelector + AllowInvalidLabelValueInSelector bool + // Allow pod spec to use non-integer multiple of huge page unit size + AllowIndivisibleHugePagesValues bool + // Allow more DNSSearchPaths and longer DNSSearchListChars + AllowExpandedDNSConfig bool +} + +// validatePodMetadataAndSpec tests if required fields in the pod.metadata and pod.spec are set, +// and is called by ValidatePodCreate and ValidatePodUpdate. +func validatePodMetadataAndSpec(pod *core.Pod, opts PodValidationOptions) field.ErrorList { + fldPath := field.NewPath("metadata") + allErrs := ValidateObjectMeta(&pod.ObjectMeta, true, ValidatePodName, fldPath) + allErrs = append(allErrs, ValidatePodSpecificAnnotations(pod.ObjectMeta.Annotations, &pod.Spec, fldPath.Child("annotations"), opts)...) + allErrs = append(allErrs, ValidatePodSpec(&pod.Spec, &pod.ObjectMeta, field.NewPath("spec"), opts)...) + + // we do additional validation only pertinent for pods and not pod templates + // this was done to preserve backwards compatibility + specPath := field.NewPath("spec") + + if pod.Spec.ServiceAccountName == "" { + for vi, volume := range pod.Spec.Volumes { + path := specPath.Child("volumes").Index(vi).Child("projected") + if volume.Projected != nil { + for si, source := range volume.Projected.Sources { + saPath := path.Child("sources").Index(si).Child("serviceAccountToken") + if source.ServiceAccountToken != nil { + allErrs = append(allErrs, field.Forbidden(saPath, "must not be specified when serviceAccountName is not set")) + } + } + } + } + } + + allErrs = append(allErrs, validateContainersOnlyForPod(pod.Spec.Containers, specPath.Child("containers"))...) + allErrs = append(allErrs, validateContainersOnlyForPod(pod.Spec.InitContainers, specPath.Child("initContainers"))...) + // validateContainersOnlyForPod() is checked for ephemeral containers by validateEphemeralContainers() + + return allErrs +} + +// validatePodIPs validates IPs in pod status +func validatePodIPs(pod *core.Pod) field.ErrorList { + allErrs := field.ErrorList{} + + podIPsField := field.NewPath("status", "podIPs") + + // all PodIPs must be valid IPs + for i, podIP := range pod.Status.PodIPs { + for _, msg := range validation.IsValidIP(podIP.IP) { + allErrs = append(allErrs, field.Invalid(podIPsField.Index(i), podIP.IP, msg)) + } + } + + // if we have more than one Pod.PodIP then + // - validate for dual stack + // - validate for duplication + if len(pod.Status.PodIPs) > 1 { + podIPs := make([]string, 0, len(pod.Status.PodIPs)) + for _, podIP := range pod.Status.PodIPs { + podIPs = append(podIPs, podIP.IP) + } + + dualStack, err := netutils.IsDualStackIPStrings(podIPs) + if err != nil { + allErrs = append(allErrs, field.InternalError(podIPsField, fmt.Errorf("failed to check for dual stack with error:%v", err))) + } + + // We only support one from each IP family (i.e. max two IPs in this list). + if !dualStack || len(podIPs) > 2 { + allErrs = append(allErrs, field.Invalid(podIPsField, pod.Status.PodIPs, "may specify no more than one IP for each IP family")) + } + + // There should be no duplicates in list of Pod.PodIPs + seen := sets.String{} // := make(map[string]int) + for i, podIP := range pod.Status.PodIPs { + if seen.Has(podIP.IP) { + allErrs = append(allErrs, field.Duplicate(podIPsField.Index(i), podIP)) + } + seen.Insert(podIP.IP) + } + } + + return allErrs +} + +// ValidatePodSpec tests that the specified PodSpec has valid data. +// This includes checking formatting and uniqueness. It also canonicalizes the +// structure by setting default values and implementing any backwards-compatibility +// tricks. +// The pod metadata is needed to validate generic ephemeral volumes. It is optional +// and should be left empty unless the spec is from a real pod object. +func ValidatePodSpec(spec *core.PodSpec, podMeta *metav1.ObjectMeta, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { + allErrs := field.ErrorList{} + + vols, vErrs := ValidateVolumes(spec.Volumes, podMeta, fldPath.Child("volumes"), opts) + allErrs = append(allErrs, vErrs...) + podClaimNames := gatherPodResourceClaimNames(spec.ResourceClaims) + allErrs = append(allErrs, validatePodResourceClaims(spec.ResourceClaims, fldPath.Child("resourceClaims"))...) + allErrs = append(allErrs, validateContainers(spec.Containers, vols, podClaimNames, fldPath.Child("containers"), opts)...) + allErrs = append(allErrs, validateInitContainers(spec.InitContainers, spec.Containers, vols, podClaimNames, fldPath.Child("initContainers"), opts)...) + allErrs = append(allErrs, validateEphemeralContainers(spec.EphemeralContainers, spec.Containers, spec.InitContainers, vols, podClaimNames, fldPath.Child("ephemeralContainers"), opts)...) + allErrs = append(allErrs, validateRestartPolicy(&spec.RestartPolicy, fldPath.Child("restartPolicy"))...) + allErrs = append(allErrs, validateDNSPolicy(&spec.DNSPolicy, fldPath.Child("dnsPolicy"))...) + allErrs = append(allErrs, unversionedvalidation.ValidateLabels(spec.NodeSelector, fldPath.Child("nodeSelector"))...) + allErrs = append(allErrs, ValidatePodSecurityContext(spec.SecurityContext, spec, fldPath, fldPath.Child("securityContext"), opts)...) + allErrs = append(allErrs, validateImagePullSecrets(spec.ImagePullSecrets, fldPath.Child("imagePullSecrets"))...) + allErrs = append(allErrs, validateAffinity(spec.Affinity, opts, fldPath.Child("affinity"))...) + allErrs = append(allErrs, validatePodDNSConfig(spec.DNSConfig, &spec.DNSPolicy, fldPath.Child("dnsConfig"), opts)...) + allErrs = append(allErrs, validateReadinessGates(spec.ReadinessGates, fldPath.Child("readinessGates"))...) + allErrs = append(allErrs, validateSchedulingGates(spec.SchedulingGates, fldPath.Child("schedulingGates"))...) + allErrs = append(allErrs, validateTopologySpreadConstraints(spec.TopologySpreadConstraints, fldPath.Child("topologySpreadConstraints"))...) + allErrs = append(allErrs, validateWindowsHostProcessPod(spec, fldPath)...) + allErrs = append(allErrs, validateHostUsers(spec, fldPath)...) + if len(spec.ServiceAccountName) > 0 { + for _, msg := range ValidateServiceAccountName(spec.ServiceAccountName, false) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("serviceAccountName"), spec.ServiceAccountName, msg)) + } + } + + if len(spec.NodeName) > 0 { + for _, msg := range ValidateNodeName(spec.NodeName, false) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("nodeName"), spec.NodeName, msg)) + } + } + + if spec.ActiveDeadlineSeconds != nil { + value := *spec.ActiveDeadlineSeconds + if value < 1 || value > math.MaxInt32 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("activeDeadlineSeconds"), value, validation.InclusiveRangeError(1, math.MaxInt32))) + } + } + + if len(spec.Hostname) > 0 { + allErrs = append(allErrs, ValidateDNS1123Label(spec.Hostname, fldPath.Child("hostname"))...) + } + + if len(spec.Subdomain) > 0 { + allErrs = append(allErrs, ValidateDNS1123Label(spec.Subdomain, fldPath.Child("subdomain"))...) + } + + if len(spec.Tolerations) > 0 { + allErrs = append(allErrs, ValidateTolerations(spec.Tolerations, fldPath.Child("tolerations"))...) + } + + if len(spec.HostAliases) > 0 { + allErrs = append(allErrs, ValidateHostAliases(spec.HostAliases, fldPath.Child("hostAliases"))...) + } + + if len(spec.PriorityClassName) > 0 { + for _, msg := range ValidatePriorityClassName(spec.PriorityClassName, false) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("priorityClassName"), spec.PriorityClassName, msg)) + } + } + + if spec.RuntimeClassName != nil { + allErrs = append(allErrs, ValidateRuntimeClassName(*spec.RuntimeClassName, fldPath.Child("runtimeClassName"))...) + } + + if spec.PreemptionPolicy != nil { + allErrs = append(allErrs, ValidatePreemptionPolicy(spec.PreemptionPolicy, fldPath.Child("preemptionPolicy"))...) + } + + if spec.Overhead != nil { + allErrs = append(allErrs, validateOverhead(spec.Overhead, fldPath.Child("overhead"), opts)...) + } + + if spec.OS != nil { + osErrs := validateOS(spec, fldPath.Child("os"), opts) + switch { + case len(osErrs) > 0: + allErrs = append(allErrs, osErrs...) + case spec.OS.Name == core.Linux: + allErrs = append(allErrs, validateLinux(spec, fldPath)...) + case spec.OS.Name == core.Windows: + allErrs = append(allErrs, validateWindows(spec, fldPath)...) + } + } + return allErrs +} + +func validateLinux(spec *core.PodSpec, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + securityContext := spec.SecurityContext + if securityContext != nil && securityContext.WindowsOptions != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("securityContext").Child("windowsOptions"), "windows options cannot be set for a linux pod")) + } + podshelper.VisitContainersWithPath(spec, fldPath, func(c *core.Container, cFldPath *field.Path) bool { + sc := c.SecurityContext + if sc != nil && sc.WindowsOptions != nil { + fldPath := cFldPath.Child("securityContext") + allErrs = append(allErrs, field.Forbidden(fldPath.Child("windowsOptions"), "windows options cannot be set for a linux pod")) + } + return true + }) + return allErrs +} + +func validateWindows(spec *core.PodSpec, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + securityContext := spec.SecurityContext + // validate Pod SecurityContext + if securityContext != nil { + if securityContext.SELinuxOptions != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("securityContext").Child("seLinuxOptions"), "cannot be set for a windows pod")) + } + if securityContext.HostUsers != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("hostUsers"), "cannot be set for a windows pod")) + } + if securityContext.HostPID { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("hostPID"), "cannot be set for a windows pod")) + } + if securityContext.HostIPC { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("hostIPC"), "cannot be set for a windows pod")) + } + if securityContext.SeccompProfile != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("securityContext").Child("seccompProfile"), "cannot be set for a windows pod")) + } + if securityContext.FSGroup != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("securityContext").Child("fsGroup"), "cannot be set for a windows pod")) + } + if securityContext.FSGroupChangePolicy != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("securityContext").Child("fsGroupChangePolicy"), "cannot be set for a windows pod")) + } + if len(securityContext.Sysctls) > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("securityContext").Child("sysctls"), "cannot be set for a windows pod")) + } + if securityContext.ShareProcessNamespace != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("shareProcessNamespace"), "cannot be set for a windows pod")) + } + if securityContext.RunAsUser != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("securityContext").Child("runAsUser"), "cannot be set for a windows pod")) + } + if securityContext.RunAsGroup != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("securityContext").Child("runAsGroup"), "cannot be set for a windows pod")) + } + if securityContext.SupplementalGroups != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("securityContext").Child("supplementalGroups"), "cannot be set for a windows pod")) + } + } + podshelper.VisitContainersWithPath(spec, fldPath, func(c *core.Container, cFldPath *field.Path) bool { + // validate container security context + sc := c.SecurityContext + // OS based podSecurityContext validation + // There is some naming overlap between Windows and Linux Security Contexts but all the Windows Specific options + // are set via securityContext.WindowsOptions which we validate below + // TODO: Think if we need to relax this restriction or some of the restrictions + if sc != nil { + fldPath := cFldPath.Child("securityContext") + if sc.SELinuxOptions != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("seLinuxOptions"), "cannot be set for a windows pod")) + } + if sc.SeccompProfile != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("seccompProfile"), "cannot be set for a windows pod")) + } + if sc.Capabilities != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("capabilities"), "cannot be set for a windows pod")) + } + if sc.ReadOnlyRootFilesystem != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("readOnlyRootFilesystem"), "cannot be set for a windows pod")) + } + if sc.Privileged != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("privileged"), "cannot be set for a windows pod")) + } + if sc.AllowPrivilegeEscalation != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("allowPrivilegeEscalation"), "cannot be set for a windows pod")) + } + if sc.ProcMount != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("procMount"), "cannot be set for a windows pod")) + } + if sc.RunAsUser != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("runAsUser"), "cannot be set for a windows pod")) + } + if sc.RunAsGroup != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("runAsGroup"), "cannot be set for a windows pod")) + } + } + return true + }) + return allErrs +} + +// ValidateNodeSelectorRequirement tests that the specified NodeSelectorRequirement fields has valid data +func ValidateNodeSelectorRequirement(rq core.NodeSelectorRequirement, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + switch rq.Operator { + case core.NodeSelectorOpIn, core.NodeSelectorOpNotIn: + if len(rq.Values) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("values"), "must be specified when `operator` is 'In' or 'NotIn'")) + } + case core.NodeSelectorOpExists, core.NodeSelectorOpDoesNotExist: + if len(rq.Values) > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("values"), "may not be specified when `operator` is 'Exists' or 'DoesNotExist'")) + } + + case core.NodeSelectorOpGt, core.NodeSelectorOpLt: + if len(rq.Values) != 1 { + allErrs = append(allErrs, field.Required(fldPath.Child("values"), "must be specified single value when `operator` is 'Lt' or 'Gt'")) + } + default: + allErrs = append(allErrs, field.Invalid(fldPath.Child("operator"), rq.Operator, "not a valid selector operator")) + } + + allErrs = append(allErrs, unversionedvalidation.ValidateLabelName(rq.Key, fldPath.Child("key"))...) + + return allErrs +} + +var nodeFieldSelectorValidators = map[string]func(string, bool) []string{ + metav1.ObjectNameField: ValidateNodeName, +} + +// ValidateNodeFieldSelectorRequirement tests that the specified NodeSelectorRequirement fields has valid data +func ValidateNodeFieldSelectorRequirement(req core.NodeSelectorRequirement, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + switch req.Operator { + case core.NodeSelectorOpIn, core.NodeSelectorOpNotIn: + if len(req.Values) != 1 { + allErrs = append(allErrs, field.Required(fldPath.Child("values"), + "must be only one value when `operator` is 'In' or 'NotIn' for node field selector")) + } + default: + allErrs = append(allErrs, field.Invalid(fldPath.Child("operator"), req.Operator, "not a valid selector operator")) + } + + if vf, found := nodeFieldSelectorValidators[req.Key]; !found { + allErrs = append(allErrs, field.Invalid(fldPath.Child("key"), req.Key, "not a valid field selector key")) + } else { + for i, v := range req.Values { + for _, msg := range vf(v, false) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("values").Index(i), v, msg)) + } + } + } + + return allErrs +} + +// ValidateNodeSelectorTerm tests that the specified node selector term has valid data +func ValidateNodeSelectorTerm(term core.NodeSelectorTerm, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + for j, req := range term.MatchExpressions { + allErrs = append(allErrs, ValidateNodeSelectorRequirement(req, fldPath.Child("matchExpressions").Index(j))...) + } + + for j, req := range term.MatchFields { + allErrs = append(allErrs, ValidateNodeFieldSelectorRequirement(req, fldPath.Child("matchFields").Index(j))...) + } + + return allErrs +} + +// ValidateNodeSelector tests that the specified nodeSelector fields has valid data +func ValidateNodeSelector(nodeSelector *core.NodeSelector, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + termFldPath := fldPath.Child("nodeSelectorTerms") + if len(nodeSelector.NodeSelectorTerms) == 0 { + return append(allErrs, field.Required(termFldPath, "must have at least one node selector term")) + } + + for i, term := range nodeSelector.NodeSelectorTerms { + allErrs = append(allErrs, ValidateNodeSelectorTerm(term, termFldPath.Index(i))...) + } + + return allErrs +} + +// validateTopologySelectorLabelRequirement tests that the specified TopologySelectorLabelRequirement fields has valid data, +// and constructs a set containing all of its Values. +func validateTopologySelectorLabelRequirement(rq core.TopologySelectorLabelRequirement, fldPath *field.Path) (sets.String, field.ErrorList) { + allErrs := field.ErrorList{} + valueSet := make(sets.String) + valuesPath := fldPath.Child("values") + if len(rq.Values) == 0 { + allErrs = append(allErrs, field.Required(valuesPath, "")) + } + + // Validate set property of Values field + for i, value := range rq.Values { + if valueSet.Has(value) { + allErrs = append(allErrs, field.Duplicate(valuesPath.Index(i), value)) + } + valueSet.Insert(value) + } + + allErrs = append(allErrs, unversionedvalidation.ValidateLabelName(rq.Key, fldPath.Child("key"))...) + + return valueSet, allErrs +} + +// ValidateTopologySelectorTerm tests that the specified topology selector term has valid data, +// and constructs a map representing the term in raw form. +func ValidateTopologySelectorTerm(term core.TopologySelectorTerm, fldPath *field.Path) (map[string]sets.String, field.ErrorList) { + allErrs := field.ErrorList{} + exprMap := make(map[string]sets.String) + exprPath := fldPath.Child("matchLabelExpressions") + + // Allow empty MatchLabelExpressions, in case this field becomes optional in the future. + for i, req := range term.MatchLabelExpressions { + idxPath := exprPath.Index(i) + valueSet, exprErrs := validateTopologySelectorLabelRequirement(req, idxPath) + allErrs = append(allErrs, exprErrs...) + + // Validate no duplicate keys exist. + if _, exists := exprMap[req.Key]; exists { + allErrs = append(allErrs, field.Duplicate(idxPath.Child("key"), req.Key)) + } + exprMap[req.Key] = valueSet + } + + return exprMap, allErrs +} + +// ValidateAvoidPodsInNodeAnnotations tests that the serialized AvoidPods in Node.Annotations has valid data +func ValidateAvoidPodsInNodeAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + v1Avoids, err := schedulinghelper.GetAvoidPodsFromNodeAnnotations(annotations) + if err != nil { + allErrs = append(allErrs, field.Invalid(fldPath.Child("AvoidPods"), core.PreferAvoidPodsAnnotationKey, err.Error())) + return allErrs + } + var avoids core.AvoidPods + if err := corev1.Convert_v1_AvoidPods_To_core_AvoidPods(&v1Avoids, &avoids, nil); err != nil { + allErrs = append(allErrs, field.Invalid(fldPath.Child("AvoidPods"), core.PreferAvoidPodsAnnotationKey, err.Error())) + return allErrs + } + + if len(avoids.PreferAvoidPods) != 0 { + for i, pa := range avoids.PreferAvoidPods { + idxPath := fldPath.Child(core.PreferAvoidPodsAnnotationKey).Index(i) + allErrs = append(allErrs, validatePreferAvoidPodsEntry(pa, idxPath)...) + } + } + + return allErrs +} + +// validatePreferAvoidPodsEntry tests if given PreferAvoidPodsEntry has valid data. +func validatePreferAvoidPodsEntry(avoidPodEntry core.PreferAvoidPodsEntry, fldPath *field.Path) field.ErrorList { + allErrors := field.ErrorList{} + if avoidPodEntry.PodSignature.PodController == nil { + allErrors = append(allErrors, field.Required(fldPath.Child("PodSignature"), "")) + } else { + if !*(avoidPodEntry.PodSignature.PodController.Controller) { + allErrors = append(allErrors, + field.Invalid(fldPath.Child("PodSignature").Child("PodController").Child("Controller"), + *(avoidPodEntry.PodSignature.PodController.Controller), "must point to a controller")) + } + } + return allErrors +} + +// ValidatePreferredSchedulingTerms tests that the specified SoftNodeAffinity fields has valid data +func ValidatePreferredSchedulingTerms(terms []core.PreferredSchedulingTerm, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + for i, term := range terms { + if term.Weight <= 0 || term.Weight > 100 { + allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("weight"), term.Weight, "must be in the range 1-100")) + } + + allErrs = append(allErrs, ValidateNodeSelectorTerm(term.Preference, fldPath.Index(i).Child("preference"))...) + } + return allErrs +} + +// validatePodAffinityTerm tests that the specified podAffinityTerm fields have valid data +func validatePodAffinityTerm(podAffinityTerm core.PodAffinityTerm, allowInvalidLabelValueInSelector bool, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + allErrs = append(allErrs, ValidatePodAffinityTermSelector(podAffinityTerm, allowInvalidLabelValueInSelector, fldPath)...) + for _, name := range podAffinityTerm.Namespaces { + for _, msg := range ValidateNamespaceName(name, false) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("namespace"), name, msg)) + } + } + if len(podAffinityTerm.TopologyKey) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("topologyKey"), "can not be empty")) + } + return append(allErrs, unversionedvalidation.ValidateLabelName(podAffinityTerm.TopologyKey, fldPath.Child("topologyKey"))...) +} + +// validatePodAffinityTerms tests that the specified podAffinityTerms fields have valid data +func validatePodAffinityTerms(podAffinityTerms []core.PodAffinityTerm, allowInvalidLabelValueInSelector bool, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + for i, podAffinityTerm := range podAffinityTerms { + allErrs = append(allErrs, validatePodAffinityTerm(podAffinityTerm, allowInvalidLabelValueInSelector, fldPath.Index(i))...) + } + return allErrs +} + +// validateWeightedPodAffinityTerms tests that the specified weightedPodAffinityTerms fields have valid data +func validateWeightedPodAffinityTerms(weightedPodAffinityTerms []core.WeightedPodAffinityTerm, allowInvalidLabelValueInSelector bool, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + for j, weightedTerm := range weightedPodAffinityTerms { + if weightedTerm.Weight <= 0 || weightedTerm.Weight > 100 { + allErrs = append(allErrs, field.Invalid(fldPath.Index(j).Child("weight"), weightedTerm.Weight, "must be in the range 1-100")) + } + allErrs = append(allErrs, validatePodAffinityTerm(weightedTerm.PodAffinityTerm, allowInvalidLabelValueInSelector, fldPath.Index(j).Child("podAffinityTerm"))...) + } + return allErrs +} + +// validatePodAntiAffinity tests that the specified podAntiAffinity fields have valid data +func validatePodAntiAffinity(podAntiAffinity *core.PodAntiAffinity, allowInvalidLabelValueInSelector bool, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + // TODO:Uncomment below code once RequiredDuringSchedulingRequiredDuringExecution is implemented. + // if podAntiAffinity.RequiredDuringSchedulingRequiredDuringExecution != nil { + // allErrs = append(allErrs, validatePodAffinityTerms(podAntiAffinity.RequiredDuringSchedulingRequiredDuringExecution, false, + // fldPath.Child("requiredDuringSchedulingRequiredDuringExecution"))...) + // } + if podAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution != nil { + allErrs = append(allErrs, validatePodAffinityTerms(podAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution, allowInvalidLabelValueInSelector, + fldPath.Child("requiredDuringSchedulingIgnoredDuringExecution"))...) + } + if podAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution != nil { + allErrs = append(allErrs, validateWeightedPodAffinityTerms(podAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution, allowInvalidLabelValueInSelector, + fldPath.Child("preferredDuringSchedulingIgnoredDuringExecution"))...) + } + return allErrs +} + +// validateNodeAffinity tests that the specified nodeAffinity fields have valid data +func validateNodeAffinity(na *core.NodeAffinity, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + // TODO: Uncomment the next three lines once RequiredDuringSchedulingRequiredDuringExecution is implemented. + // if na.RequiredDuringSchedulingRequiredDuringExecution != nil { + // allErrs = append(allErrs, ValidateNodeSelector(na.RequiredDuringSchedulingRequiredDuringExecution, fldPath.Child("requiredDuringSchedulingRequiredDuringExecution"))...) + // } + if na.RequiredDuringSchedulingIgnoredDuringExecution != nil { + allErrs = append(allErrs, ValidateNodeSelector(na.RequiredDuringSchedulingIgnoredDuringExecution, fldPath.Child("requiredDuringSchedulingIgnoredDuringExecution"))...) + } + if len(na.PreferredDuringSchedulingIgnoredDuringExecution) > 0 { + allErrs = append(allErrs, ValidatePreferredSchedulingTerms(na.PreferredDuringSchedulingIgnoredDuringExecution, fldPath.Child("preferredDuringSchedulingIgnoredDuringExecution"))...) + } + return allErrs +} + +// validatePodAffinity tests that the specified podAffinity fields have valid data +func validatePodAffinity(podAffinity *core.PodAffinity, allowInvalidLabelValueInSelector bool, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + // TODO:Uncomment below code once RequiredDuringSchedulingRequiredDuringExecution is implemented. + // if podAffinity.RequiredDuringSchedulingRequiredDuringExecution != nil { + // allErrs = append(allErrs, validatePodAffinityTerms(podAffinity.RequiredDuringSchedulingRequiredDuringExecution, false, + // fldPath.Child("requiredDuringSchedulingRequiredDuringExecution"))...) + // } + if podAffinity.RequiredDuringSchedulingIgnoredDuringExecution != nil { + allErrs = append(allErrs, validatePodAffinityTerms(podAffinity.RequiredDuringSchedulingIgnoredDuringExecution, allowInvalidLabelValueInSelector, + fldPath.Child("requiredDuringSchedulingIgnoredDuringExecution"))...) + } + if podAffinity.PreferredDuringSchedulingIgnoredDuringExecution != nil { + allErrs = append(allErrs, validateWeightedPodAffinityTerms(podAffinity.PreferredDuringSchedulingIgnoredDuringExecution, allowInvalidLabelValueInSelector, + fldPath.Child("preferredDuringSchedulingIgnoredDuringExecution"))...) + } + return allErrs +} + +func validateSeccompProfileField(sp *core.SeccompProfile, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if sp == nil { + return allErrs + } + + if err := validateSeccompProfileType(fldPath.Child("type"), sp.Type); err != nil { + allErrs = append(allErrs, err) + } + + if sp.Type == core.SeccompProfileTypeLocalhost { + if sp.LocalhostProfile == nil { + allErrs = append(allErrs, field.Required(fldPath.Child("localhostProfile"), "must be set when seccomp type is Localhost")) + } else { + allErrs = append(allErrs, validateLocalDescendingPath(*sp.LocalhostProfile, fldPath.Child("localhostProfile"))...) + } + } else { + if sp.LocalhostProfile != nil { + allErrs = append(allErrs, field.Invalid(fldPath.Child("localhostProfile"), sp, "can only be set when seccomp type is Localhost")) + } + } + + return allErrs +} + +func ValidateSeccompProfile(p string, fldPath *field.Path) field.ErrorList { + if p == core.SeccompProfileRuntimeDefault || p == core.DeprecatedSeccompProfileDockerDefault { + return nil + } + if p == v1.SeccompProfileNameUnconfined { + return nil + } + if strings.HasPrefix(p, v1.SeccompLocalhostProfileNamePrefix) { + return validateLocalDescendingPath(strings.TrimPrefix(p, v1.SeccompLocalhostProfileNamePrefix), fldPath) + } + return field.ErrorList{field.Invalid(fldPath, p, "must be a valid seccomp profile")} +} + +func ValidateSeccompPodAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if p, exists := annotations[core.SeccompPodAnnotationKey]; exists { + allErrs = append(allErrs, ValidateSeccompProfile(p, fldPath.Child(core.SeccompPodAnnotationKey))...) + } + for k, p := range annotations { + if strings.HasPrefix(k, core.SeccompContainerAnnotationKeyPrefix) { + allErrs = append(allErrs, ValidateSeccompProfile(p, fldPath.Child(k))...) + } + } + + return allErrs +} + +// ValidateSeccompProfileType tests that the argument is a valid SeccompProfileType. +func validateSeccompProfileType(fldPath *field.Path, seccompProfileType core.SeccompProfileType) *field.Error { + switch seccompProfileType { + case core.SeccompProfileTypeLocalhost, core.SeccompProfileTypeRuntimeDefault, core.SeccompProfileTypeUnconfined: + return nil + case "": + return field.Required(fldPath, "type is required when seccompProfile is set") + default: + return field.NotSupported(fldPath, seccompProfileType, []string{string(core.SeccompProfileTypeLocalhost), string(core.SeccompProfileTypeRuntimeDefault), string(core.SeccompProfileTypeUnconfined)}) + } +} + +func ValidateAppArmorPodAnnotations(annotations map[string]string, spec *core.PodSpec, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + for k, p := range annotations { + if !strings.HasPrefix(k, v1.AppArmorBetaContainerAnnotationKeyPrefix) { + continue + } + containerName := strings.TrimPrefix(k, v1.AppArmorBetaContainerAnnotationKeyPrefix) + if !podSpecHasContainer(spec, containerName) { + allErrs = append(allErrs, field.Invalid(fldPath.Key(k), containerName, "container not found")) + } + + if err := ValidateAppArmorProfileFormat(p); err != nil { + allErrs = append(allErrs, field.Invalid(fldPath.Key(k), p, err.Error())) + } + } + + return allErrs +} + +func ValidateAppArmorProfileFormat(profile string) error { + if profile == "" || profile == v1.AppArmorBetaProfileRuntimeDefault || profile == v1.AppArmorBetaProfileNameUnconfined { + return nil + } + if !strings.HasPrefix(profile, v1.AppArmorBetaProfileNamePrefix) { + return fmt.Errorf("invalid AppArmor profile name: %q", profile) + } + return nil +} + +func podSpecHasContainer(spec *core.PodSpec, containerName string) bool { + var hasContainer bool + podshelper.VisitContainersWithPath(spec, field.NewPath("spec"), func(c *core.Container, _ *field.Path) bool { + if c.Name == containerName { + hasContainer = true + return false + } + return true + }) + return hasContainer +} + +const ( + // a sysctl segment regex, concatenated with dots to form a sysctl name + SysctlSegmentFmt string = "[a-z0-9]([-_a-z0-9]*[a-z0-9])?" + + // a sysctl name regex with slash allowed + SysctlContainSlashFmt string = "(" + SysctlSegmentFmt + "[\\./])*" + SysctlSegmentFmt + + // the maximal length of a sysctl name + SysctlMaxLength int = 253 +) + +var sysctlContainSlashRegexp = regexp.MustCompile("^" + SysctlContainSlashFmt + "$") + +// IsValidSysctlName checks that the given string is a valid sysctl name, +// i.e. matches SysctlContainSlashFmt. +// More info: +// +// https://man7.org/linux/man-pages/man8/sysctl.8.html +// https://man7.org/linux/man-pages/man5/sysctl.d.5.html +func IsValidSysctlName(name string) bool { + if len(name) > SysctlMaxLength { + return false + } + return sysctlContainSlashRegexp.MatchString(name) +} + +func validateSysctls(sysctls []core.Sysctl, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + names := make(map[string]struct{}) + for i, s := range sysctls { + if len(s.Name) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Index(i).Child("name"), "")) + } else if !IsValidSysctlName(s.Name) { + allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("name"), s.Name, fmt.Sprintf("must have at most %d characters and match regex %s", SysctlMaxLength, sysctlContainSlashRegexp))) + } else if _, ok := names[s.Name]; ok { + allErrs = append(allErrs, field.Duplicate(fldPath.Index(i).Child("name"), s.Name)) + } + names[s.Name] = struct{}{} + } + return allErrs +} + +// ValidatePodSecurityContext test that the specified PodSecurityContext has valid data. +func ValidatePodSecurityContext(securityContext *core.PodSecurityContext, spec *core.PodSpec, specPath, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { + allErrs := field.ErrorList{} + + if securityContext != nil { + allErrs = append(allErrs, validateHostNetwork(securityContext.HostNetwork, spec.Containers, specPath.Child("containers"))...) + if securityContext.FSGroup != nil { + for _, msg := range validation.IsValidGroupID(*securityContext.FSGroup) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("fsGroup"), *(securityContext.FSGroup), msg)) + } + } + if securityContext.RunAsUser != nil { + for _, msg := range validation.IsValidUserID(*securityContext.RunAsUser) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("runAsUser"), *(securityContext.RunAsUser), msg)) + } + } + if securityContext.RunAsGroup != nil { + for _, msg := range validation.IsValidGroupID(*securityContext.RunAsGroup) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("runAsGroup"), *(securityContext.RunAsGroup), msg)) + } + } + for g, gid := range securityContext.SupplementalGroups { + for _, msg := range validation.IsValidGroupID(gid) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("supplementalGroups").Index(g), gid, msg)) + } + } + if securityContext.ShareProcessNamespace != nil && securityContext.HostPID && *securityContext.ShareProcessNamespace { + allErrs = append(allErrs, field.Invalid(fldPath.Child("shareProcessNamespace"), *securityContext.ShareProcessNamespace, "ShareProcessNamespace and HostPID cannot both be enabled")) + } + + if len(securityContext.Sysctls) != 0 { + allErrs = append(allErrs, validateSysctls(securityContext.Sysctls, fldPath.Child("sysctls"))...) + } + + if securityContext.FSGroupChangePolicy != nil { + allErrs = append(allErrs, validateFSGroupChangePolicy(securityContext.FSGroupChangePolicy, fldPath.Child("fsGroupChangePolicy"))...) + } + + allErrs = append(allErrs, validateSeccompProfileField(securityContext.SeccompProfile, fldPath.Child("seccompProfile"))...) + allErrs = append(allErrs, validateWindowsSecurityContextOptions(securityContext.WindowsOptions, fldPath.Child("windowsOptions"))...) + } + + return allErrs +} + +func ValidateContainerUpdates(newContainers, oldContainers []core.Container, fldPath *field.Path) (allErrs field.ErrorList, stop bool) { + allErrs = field.ErrorList{} + if len(newContainers) != len(oldContainers) { + // TODO: Pinpoint the specific container that causes the invalid error after we have strategic merge diff + allErrs = append(allErrs, field.Forbidden(fldPath, "pod updates may not add or remove containers")) + return allErrs, true + } + + // validate updated container images + for i, ctr := range newContainers { + if len(ctr.Image) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Index(i).Child("image"), "")) + } + // this is only called from ValidatePodUpdate so its safe to check leading/trailing whitespace. + if len(strings.TrimSpace(ctr.Image)) != len(ctr.Image) { + allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("image"), ctr.Image, "must not have leading or trailing whitespace")) + } + } + return allErrs, false +} + +// ValidatePodCreate validates a pod in the context of its initial create +func ValidatePodCreate(pod *core.Pod, opts PodValidationOptions) field.ErrorList { + allErrs := validatePodMetadataAndSpec(pod, opts) + + fldPath := field.NewPath("spec") + // EphemeralContainers can only be set on update using the ephemeralcontainers subresource + if len(pod.Spec.EphemeralContainers) > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("ephemeralContainers"), "cannot be set on create")) + } + // A Pod cannot be assigned a Node if there are remaining scheduling gates. + if pod.Spec.NodeName != "" && len(pod.Spec.SchedulingGates) != 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("nodeName"), "cannot be set until all schedulingGates have been cleared")) + } + allErrs = append(allErrs, validateSeccompAnnotationsAndFields(pod.ObjectMeta, &pod.Spec, fldPath)...) + + return allErrs +} + +// validateSeccompAnnotationsAndFields iterates through all containers and ensure that when both seccompProfile and seccomp annotations exist they match. +func validateSeccompAnnotationsAndFields(objectMeta metav1.ObjectMeta, podSpec *core.PodSpec, specPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + if podSpec.SecurityContext != nil && podSpec.SecurityContext.SeccompProfile != nil { + // If both seccomp annotations and fields are specified, the values must match. + if annotation, found := objectMeta.Annotations[v1.SeccompPodAnnotationKey]; found { + seccompPath := specPath.Child("securityContext").Child("seccompProfile") + err := validateSeccompAnnotationsAndFieldsMatch(annotation, podSpec.SecurityContext.SeccompProfile, seccompPath) + if err != nil { + allErrs = append(allErrs, err) + } + } + } + + podshelper.VisitContainersWithPath(podSpec, specPath, func(c *core.Container, cFldPath *field.Path) bool { + var field *core.SeccompProfile + if c.SecurityContext != nil { + field = c.SecurityContext.SeccompProfile + } + + if field == nil { + return true + } + + key := v1.SeccompContainerAnnotationKeyPrefix + c.Name + if annotation, found := objectMeta.Annotations[key]; found { + seccompPath := cFldPath.Child("securityContext").Child("seccompProfile") + err := validateSeccompAnnotationsAndFieldsMatch(annotation, field, seccompPath) + if err != nil { + allErrs = append(allErrs, err) + } + } + return true + }) + + return allErrs +} + +func validateSeccompAnnotationsAndFieldsMatch(annotationValue string, seccompField *core.SeccompProfile, fldPath *field.Path) *field.Error { + if seccompField == nil { + return nil + } + + switch seccompField.Type { + case core.SeccompProfileTypeUnconfined: + if annotationValue != v1.SeccompProfileNameUnconfined { + return field.Forbidden(fldPath.Child("type"), "seccomp type in annotation and field must match") + } + + case core.SeccompProfileTypeRuntimeDefault: + if annotationValue != v1.SeccompProfileRuntimeDefault && annotationValue != v1.DeprecatedSeccompProfileDockerDefault { + return field.Forbidden(fldPath.Child("type"), "seccomp type in annotation and field must match") + } + + case core.SeccompProfileTypeLocalhost: + if !strings.HasPrefix(annotationValue, v1.SeccompLocalhostProfileNamePrefix) { + return field.Forbidden(fldPath.Child("type"), "seccomp type in annotation and field must match") + } else if seccompField.LocalhostProfile == nil || strings.TrimPrefix(annotationValue, v1.SeccompLocalhostProfileNamePrefix) != *seccompField.LocalhostProfile { + return field.Forbidden(fldPath.Child("localhostProfile"), "seccomp profile in annotation and field must match") + } + } + + return nil +} + +// ValidatePodUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields +// that cannot be changed. +func ValidatePodUpdate(newPod, oldPod *core.Pod, opts PodValidationOptions) field.ErrorList { + fldPath := field.NewPath("metadata") + allErrs := ValidateObjectMetaUpdate(&newPod.ObjectMeta, &oldPod.ObjectMeta, fldPath) + allErrs = append(allErrs, validatePodMetadataAndSpec(newPod, opts)...) + allErrs = append(allErrs, ValidatePodSpecificAnnotationUpdates(newPod, oldPod, fldPath.Child("annotations"), opts)...) + specPath := field.NewPath("spec") + + // validate updateable fields: + // 1. spec.containers[*].image + // 2. spec.initContainers[*].image + // 3. spec.activeDeadlineSeconds + // 4. spec.terminationGracePeriodSeconds + // 5. spec.schedulingGates + + containerErrs, stop := ValidateContainerUpdates(newPod.Spec.Containers, oldPod.Spec.Containers, specPath.Child("containers")) + allErrs = append(allErrs, containerErrs...) + if stop { + return allErrs + } + containerErrs, stop = ValidateContainerUpdates(newPod.Spec.InitContainers, oldPod.Spec.InitContainers, specPath.Child("initContainers")) + allErrs = append(allErrs, containerErrs...) + if stop { + return allErrs + } + + // validate updated spec.activeDeadlineSeconds. two types of updates are allowed: + // 1. from nil to a positive value + // 2. from a positive value to a lesser, non-negative value + if newPod.Spec.ActiveDeadlineSeconds != nil { + newActiveDeadlineSeconds := *newPod.Spec.ActiveDeadlineSeconds + if newActiveDeadlineSeconds < 0 || newActiveDeadlineSeconds > math.MaxInt32 { + allErrs = append(allErrs, field.Invalid(specPath.Child("activeDeadlineSeconds"), newActiveDeadlineSeconds, validation.InclusiveRangeError(0, math.MaxInt32))) + return allErrs + } + if oldPod.Spec.ActiveDeadlineSeconds != nil { + oldActiveDeadlineSeconds := *oldPod.Spec.ActiveDeadlineSeconds + if oldActiveDeadlineSeconds < newActiveDeadlineSeconds { + allErrs = append(allErrs, field.Invalid(specPath.Child("activeDeadlineSeconds"), newActiveDeadlineSeconds, "must be less than or equal to previous value")) + return allErrs + } + } + } else if oldPod.Spec.ActiveDeadlineSeconds != nil { + allErrs = append(allErrs, field.Invalid(specPath.Child("activeDeadlineSeconds"), newPod.Spec.ActiveDeadlineSeconds, "must not update from a positive integer to nil value")) + } + + // Allow only additions to tolerations updates. + allErrs = append(allErrs, validateOnlyAddedTolerations(newPod.Spec.Tolerations, oldPod.Spec.Tolerations, specPath.Child("tolerations"))...) + + // Allow only deletions to schedulingGates updates. + allErrs = append(allErrs, validateOnlyDeletedSchedulingGates(newPod.Spec.SchedulingGates, oldPod.Spec.SchedulingGates, specPath.Child("schedulingGates"))...) + + // the last thing to check is pod spec equality. If the pod specs are equal, then we can simply return the errors we have + // so far and save the cost of a deep copy. + if apiequality.Semantic.DeepEqual(newPod.Spec, oldPod.Spec) { + return allErrs + } + + // handle updateable fields by munging those fields prior to deep equal comparison. + mungedPodSpec := *newPod.Spec.DeepCopy() + // munge spec.containers[*].image + var newContainers []core.Container + for ix, container := range mungedPodSpec.Containers { + container.Image = oldPod.Spec.Containers[ix].Image // +k8s:verify-mutation:reason=clone + newContainers = append(newContainers, container) + } + mungedPodSpec.Containers = newContainers + // munge spec.initContainers[*].image + var newInitContainers []core.Container + for ix, container := range mungedPodSpec.InitContainers { + container.Image = oldPod.Spec.InitContainers[ix].Image // +k8s:verify-mutation:reason=clone + newInitContainers = append(newInitContainers, container) + } + mungedPodSpec.InitContainers = newInitContainers + // munge spec.activeDeadlineSeconds + mungedPodSpec.ActiveDeadlineSeconds = nil + if oldPod.Spec.ActiveDeadlineSeconds != nil { + activeDeadlineSeconds := *oldPod.Spec.ActiveDeadlineSeconds + mungedPodSpec.ActiveDeadlineSeconds = &activeDeadlineSeconds + } + // munge spec.schedulingGates + mungedPodSpec.SchedulingGates = oldPod.Spec.SchedulingGates // +k8s:verify-mutation:reason=clone + // tolerations are checked before the deep copy, so munge those too + mungedPodSpec.Tolerations = oldPod.Spec.Tolerations // +k8s:verify-mutation:reason=clone + + // Relax validation of immutable fields to allow it to be set to 1 if it was previously negative. + if oldPod.Spec.TerminationGracePeriodSeconds != nil && *oldPod.Spec.TerminationGracePeriodSeconds < 0 && + mungedPodSpec.TerminationGracePeriodSeconds != nil && *mungedPodSpec.TerminationGracePeriodSeconds == 1 { + mungedPodSpec.TerminationGracePeriodSeconds = oldPod.Spec.TerminationGracePeriodSeconds // +k8s:verify-mutation:reason=clone + } + + if !apiequality.Semantic.DeepEqual(mungedPodSpec, oldPod.Spec) { + // This diff isn't perfect, but it's a helluva lot better an "I'm not going to tell you what the difference is". + // TODO: Pinpoint the specific field that causes the invalid error after we have strategic merge diff + specDiff := cmp.Diff(oldPod.Spec, mungedPodSpec) + allErrs = append(allErrs, field.Forbidden(specPath, fmt.Sprintf("pod updates may not change fields other than `spec.containers[*].image`, `spec.initContainers[*].image`, `spec.activeDeadlineSeconds`, `spec.tolerations` (only additions to existing tolerations) or `spec.terminationGracePeriodSeconds` (allow it to be set to 1 if it was previously negative)\n%v", specDiff))) + } + + return allErrs +} + +// ValidateContainerStateTransition test to if any illegal container state transitions are being attempted +func ValidateContainerStateTransition(newStatuses, oldStatuses []core.ContainerStatus, fldpath *field.Path, restartPolicy core.RestartPolicy) field.ErrorList { + allErrs := field.ErrorList{} + // If we should always restart, containers are allowed to leave the terminated state + if restartPolicy == core.RestartPolicyAlways { + return allErrs + } + for i, oldStatus := range oldStatuses { + // Skip any container that is not terminated + if oldStatus.State.Terminated == nil { + continue + } + // Skip any container that failed but is allowed to restart + if oldStatus.State.Terminated.ExitCode != 0 && restartPolicy == core.RestartPolicyOnFailure { + continue + } + for _, newStatus := range newStatuses { + if oldStatus.Name == newStatus.Name && newStatus.State.Terminated == nil { + allErrs = append(allErrs, field.Forbidden(fldpath.Index(i).Child("state"), "may not be transitioned to non-terminated state")) + } + } + } + return allErrs +} + +// ValidatePodStatusUpdate checks for changes to status that shouldn't occur in normal operation. +func ValidatePodStatusUpdate(newPod, oldPod *core.Pod, opts PodValidationOptions) field.ErrorList { + fldPath := field.NewPath("metadata") + allErrs := ValidateObjectMetaUpdate(&newPod.ObjectMeta, &oldPod.ObjectMeta, fldPath) + allErrs = append(allErrs, ValidatePodSpecificAnnotationUpdates(newPod, oldPod, fldPath.Child("annotations"), opts)...) + allErrs = append(allErrs, validatePodConditions(newPod.Status.Conditions, fldPath.Child("conditions"))...) + + fldPath = field.NewPath("status") + if newPod.Spec.NodeName != oldPod.Spec.NodeName { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("nodeName"), "may not be changed directly")) + } + + if newPod.Status.NominatedNodeName != oldPod.Status.NominatedNodeName && len(newPod.Status.NominatedNodeName) > 0 { + for _, msg := range ValidateNodeName(newPod.Status.NominatedNodeName, false) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("nominatedNodeName"), newPod.Status.NominatedNodeName, msg)) + } + } + + // If pod should not restart, make sure the status update does not transition + // any terminated containers to a non-terminated state. + allErrs = append(allErrs, ValidateContainerStateTransition(newPod.Status.ContainerStatuses, oldPod.Status.ContainerStatuses, fldPath.Child("containerStatuses"), oldPod.Spec.RestartPolicy)...) + allErrs = append(allErrs, ValidateContainerStateTransition(newPod.Status.InitContainerStatuses, oldPod.Status.InitContainerStatuses, fldPath.Child("initContainerStatuses"), oldPod.Spec.RestartPolicy)...) + // The kubelet will never restart ephemeral containers, so treat them like they have an implicit RestartPolicyNever. + allErrs = append(allErrs, ValidateContainerStateTransition(newPod.Status.EphemeralContainerStatuses, oldPod.Status.EphemeralContainerStatuses, fldPath.Child("ephemeralContainerStatuses"), core.RestartPolicyNever)...) + + if newIPErrs := validatePodIPs(newPod); len(newIPErrs) > 0 { + allErrs = append(allErrs, newIPErrs...) + } + + return allErrs +} + +// validatePodConditions tests if the custom pod conditions are valid. +func validatePodConditions(conditions []core.PodCondition, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + systemConditions := sets.NewString(string(core.PodScheduled), string(core.PodReady), string(core.PodInitialized)) + for i, condition := range conditions { + if systemConditions.Has(string(condition.Type)) { + continue + } + allErrs = append(allErrs, ValidateQualifiedName(string(condition.Type), fldPath.Index(i).Child("Type"))...) + } + return allErrs +} + +// ValidatePodEphemeralContainersUpdate tests that a user update to EphemeralContainers is valid. +// newPod and oldPod must only differ in their EphemeralContainers. +func ValidatePodEphemeralContainersUpdate(newPod, oldPod *core.Pod, opts PodValidationOptions) field.ErrorList { + // Part 1: Validate newPod's spec and updates to metadata + fldPath := field.NewPath("metadata") + allErrs := ValidateObjectMetaUpdate(&newPod.ObjectMeta, &oldPod.ObjectMeta, fldPath) + allErrs = append(allErrs, validatePodMetadataAndSpec(newPod, opts)...) + allErrs = append(allErrs, ValidatePodSpecificAnnotationUpdates(newPod, oldPod, fldPath.Child("annotations"), opts)...) + + // Part 2: Validate that the changes between oldPod.Spec.EphemeralContainers and + // newPod.Spec.EphemeralContainers are allowed. + // + // Existing EphemeralContainers may not be changed. Order isn't preserved by patch, so check each individually. + newContainerIndex := make(map[string]*core.EphemeralContainer) + specPath := field.NewPath("spec").Child("ephemeralContainers") + for i := range newPod.Spec.EphemeralContainers { + newContainerIndex[newPod.Spec.EphemeralContainers[i].Name] = &newPod.Spec.EphemeralContainers[i] + } + for _, old := range oldPod.Spec.EphemeralContainers { + if new, ok := newContainerIndex[old.Name]; !ok { + allErrs = append(allErrs, field.Forbidden(specPath, fmt.Sprintf("existing ephemeral containers %q may not be removed\n", old.Name))) + } else if !apiequality.Semantic.DeepEqual(old, *new) { + specDiff := cmp.Diff(old, *new) + allErrs = append(allErrs, field.Forbidden(specPath, fmt.Sprintf("existing ephemeral containers %q may not be changed\n%v", old.Name, specDiff))) + } + } + + return allErrs +} + +// ValidatePodBinding tests if required fields in the pod binding are legal. +func ValidatePodBinding(binding *core.Binding) field.ErrorList { + allErrs := field.ErrorList{} + + if len(binding.Target.Kind) != 0 && binding.Target.Kind != "Node" { + // TODO: When validation becomes versioned, this gets more complicated. + allErrs = append(allErrs, field.NotSupported(field.NewPath("target", "kind"), binding.Target.Kind, []string{"Node", ""})) + } + if len(binding.Target.Name) == 0 { + // TODO: When validation becomes versioned, this gets more complicated. + allErrs = append(allErrs, field.Required(field.NewPath("target", "name"), "")) + } + + return allErrs +} + +// ValidatePodTemplate tests if required fields in the pod template are set. +func ValidatePodTemplate(pod *core.PodTemplate, opts PodValidationOptions) field.ErrorList { + allErrs := ValidateObjectMeta(&pod.ObjectMeta, true, ValidatePodName, field.NewPath("metadata")) + allErrs = append(allErrs, ValidatePodTemplateSpec(&pod.Template, field.NewPath("template"), opts)...) + return allErrs +} + +// ValidatePodTemplateUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields +// that cannot be changed. +func ValidatePodTemplateUpdate(newPod, oldPod *core.PodTemplate, opts PodValidationOptions) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newPod.ObjectMeta, &oldPod.ObjectMeta, field.NewPath("metadata")) + allErrs = append(allErrs, ValidatePodTemplateSpec(&newPod.Template, field.NewPath("template"), opts)...) + return allErrs +} + +var supportedSessionAffinityType = sets.NewString(string(core.ServiceAffinityClientIP), string(core.ServiceAffinityNone)) +var supportedServiceType = sets.NewString(string(core.ServiceTypeClusterIP), string(core.ServiceTypeNodePort), + string(core.ServiceTypeLoadBalancer), string(core.ServiceTypeExternalName)) + +var supportedServiceInternalTrafficPolicy = sets.NewString(string(core.ServiceInternalTrafficPolicyCluster), string(core.ServiceExternalTrafficPolicyTypeLocal)) + +var supportedServiceIPFamily = sets.NewString(string(core.IPv4Protocol), string(core.IPv6Protocol)) +var supportedServiceIPFamilyPolicy = sets.NewString(string(core.IPFamilyPolicySingleStack), string(core.IPFamilyPolicyPreferDualStack), string(core.IPFamilyPolicyRequireDualStack)) + +// ValidateService tests if required fields/annotations of a Service are valid. +func ValidateService(service *core.Service) field.ErrorList { + allErrs := ValidateObjectMeta(&service.ObjectMeta, true, ValidateServiceName, field.NewPath("metadata")) + + specPath := field.NewPath("spec") + + if len(service.Spec.Ports) == 0 && !isHeadlessService(service) && service.Spec.Type != core.ServiceTypeExternalName { + allErrs = append(allErrs, field.Required(specPath.Child("ports"), "")) + } + switch service.Spec.Type { + case core.ServiceTypeLoadBalancer: + for ix := range service.Spec.Ports { + port := &service.Spec.Ports[ix] + // This is a workaround for broken cloud environments that + // over-open firewalls. Hopefully it can go away when more clouds + // understand containers better. + if port.Port == ports.KubeletPort { + portPath := specPath.Child("ports").Index(ix) + allErrs = append(allErrs, field.Invalid(portPath, port.Port, fmt.Sprintf("may not expose port %v externally since it is used by kubelet", ports.KubeletPort))) + } + } + if isHeadlessService(service) { + allErrs = append(allErrs, field.Invalid(specPath.Child("clusterIPs").Index(0), service.Spec.ClusterIPs[0], "may not be set to 'None' for LoadBalancer services")) + } + case core.ServiceTypeNodePort: + if isHeadlessService(service) { + allErrs = append(allErrs, field.Invalid(specPath.Child("clusterIPs").Index(0), service.Spec.ClusterIPs[0], "may not be set to 'None' for NodePort services")) + } + case core.ServiceTypeExternalName: + // must have len(.spec.ClusterIPs) == 0 // note: strategy sets ClusterIPs based on ClusterIP + if len(service.Spec.ClusterIPs) > 0 { + allErrs = append(allErrs, field.Forbidden(specPath.Child("clusterIPs"), "may not be set for ExternalName services")) + } + + // must have nil families and nil policy + if len(service.Spec.IPFamilies) > 0 { + allErrs = append(allErrs, field.Forbidden(specPath.Child("ipFamilies"), "may not be set for ExternalName services")) + } + if service.Spec.IPFamilyPolicy != nil { + allErrs = append(allErrs, field.Forbidden(specPath.Child("ipFamilyPolicy"), "may not be set for ExternalName services")) + } + + // The value (a CNAME) may have a trailing dot to denote it as fully qualified + cname := strings.TrimSuffix(service.Spec.ExternalName, ".") + if len(cname) > 0 { + allErrs = append(allErrs, ValidateDNS1123Subdomain(cname, specPath.Child("externalName"))...) + } else { + allErrs = append(allErrs, field.Required(specPath.Child("externalName"), "")) + } + } + + allPortNames := sets.String{} + portsPath := specPath.Child("ports") + for i := range service.Spec.Ports { + portPath := portsPath.Index(i) + allErrs = append(allErrs, validateServicePort(&service.Spec.Ports[i], len(service.Spec.Ports) > 1, isHeadlessService(service), &allPortNames, portPath)...) + } + + if service.Spec.Selector != nil { + allErrs = append(allErrs, unversionedvalidation.ValidateLabels(service.Spec.Selector, specPath.Child("selector"))...) + } + + if len(service.Spec.SessionAffinity) == 0 { + allErrs = append(allErrs, field.Required(specPath.Child("sessionAffinity"), "")) + } else if !supportedSessionAffinityType.Has(string(service.Spec.SessionAffinity)) { + allErrs = append(allErrs, field.NotSupported(specPath.Child("sessionAffinity"), service.Spec.SessionAffinity, supportedSessionAffinityType.List())) + } + + if service.Spec.SessionAffinity == core.ServiceAffinityClientIP { + allErrs = append(allErrs, validateClientIPAffinityConfig(service.Spec.SessionAffinityConfig, specPath.Child("sessionAffinityConfig"))...) + } else if service.Spec.SessionAffinity == core.ServiceAffinityNone { + if service.Spec.SessionAffinityConfig != nil { + allErrs = append(allErrs, field.Forbidden(specPath.Child("sessionAffinityConfig"), fmt.Sprintf("must not be set when session affinity is %s", string(core.ServiceAffinityNone)))) + } + } + + // dualstack <-> ClusterIPs <-> ipfamilies + allErrs = append(allErrs, ValidateServiceClusterIPsRelatedFields(service)...) + + ipPath := specPath.Child("externalIPs") + for i, ip := range service.Spec.ExternalIPs { + idxPath := ipPath.Index(i) + if msgs := validation.IsValidIP(ip); len(msgs) != 0 { + for i := range msgs { + allErrs = append(allErrs, field.Invalid(idxPath, ip, msgs[i])) + } + } else { + allErrs = append(allErrs, ValidateNonSpecialIP(ip, idxPath)...) + } + } + + if len(service.Spec.Type) == 0 { + allErrs = append(allErrs, field.Required(specPath.Child("type"), "")) + } else if !supportedServiceType.Has(string(service.Spec.Type)) { + allErrs = append(allErrs, field.NotSupported(specPath.Child("type"), service.Spec.Type, supportedServiceType.List())) + } + + if service.Spec.Type == core.ServiceTypeClusterIP { + portsPath := specPath.Child("ports") + for i := range service.Spec.Ports { + portPath := portsPath.Index(i) + if service.Spec.Ports[i].NodePort != 0 { + allErrs = append(allErrs, field.Forbidden(portPath.Child("nodePort"), "may not be used when `type` is 'ClusterIP'")) + } + } + } + + // Check for duplicate NodePorts, considering (protocol,port) pairs + portsPath = specPath.Child("ports") + nodePorts := make(map[core.ServicePort]bool) + for i := range service.Spec.Ports { + port := &service.Spec.Ports[i] + if port.NodePort == 0 { + continue + } + portPath := portsPath.Index(i) + var key core.ServicePort + key.Protocol = port.Protocol + key.NodePort = port.NodePort + _, found := nodePorts[key] + if found { + allErrs = append(allErrs, field.Duplicate(portPath.Child("nodePort"), port.NodePort)) + } + nodePorts[key] = true + } + + // Check for duplicate Ports, considering (protocol,port) pairs + portsPath = specPath.Child("ports") + ports := make(map[core.ServicePort]bool) + for i, port := range service.Spec.Ports { + portPath := portsPath.Index(i) + key := core.ServicePort{Protocol: port.Protocol, Port: port.Port} + _, found := ports[key] + if found { + allErrs = append(allErrs, field.Duplicate(portPath, key)) + } + ports[key] = true + } + + // Validate SourceRange field and annotation + _, ok := service.Annotations[core.AnnotationLoadBalancerSourceRangesKey] + if len(service.Spec.LoadBalancerSourceRanges) > 0 || ok { + var fieldPath *field.Path + var val string + if len(service.Spec.LoadBalancerSourceRanges) > 0 { + fieldPath = specPath.Child("LoadBalancerSourceRanges") + val = fmt.Sprintf("%v", service.Spec.LoadBalancerSourceRanges) + } else { + fieldPath = field.NewPath("metadata", "annotations").Key(core.AnnotationLoadBalancerSourceRangesKey) + val = service.Annotations[core.AnnotationLoadBalancerSourceRangesKey] + } + if service.Spec.Type != core.ServiceTypeLoadBalancer { + allErrs = append(allErrs, field.Forbidden(fieldPath, "may only be used when `type` is 'LoadBalancer'")) + } + _, err := apiservice.GetLoadBalancerSourceRanges(service) + if err != nil { + allErrs = append(allErrs, field.Invalid(fieldPath, val, "must be a list of IP ranges. For example, 10.240.0.0/24,10.250.0.0/24 ")) + } + } + + if service.Spec.AllocateLoadBalancerNodePorts != nil && service.Spec.Type != core.ServiceTypeLoadBalancer { + allErrs = append(allErrs, field.Forbidden(specPath.Child("allocateLoadBalancerNodePorts"), "may only be used when `type` is 'LoadBalancer'")) + } + + if service.Spec.Type == core.ServiceTypeLoadBalancer && service.Spec.AllocateLoadBalancerNodePorts == nil { + allErrs = append(allErrs, field.Required(field.NewPath("allocateLoadBalancerNodePorts"), "")) + } + + // validate LoadBalancerClass field + allErrs = append(allErrs, validateLoadBalancerClassField(nil, service)...) + + // external traffic policy fields + allErrs = append(allErrs, validateServiceExternalTrafficPolicy(service)...) + + // internal traffic policy field + allErrs = append(allErrs, validateServiceInternalTrafficFieldsValue(service)...) + + return allErrs +} + +func validateServicePort(sp *core.ServicePort, requireName, isHeadlessService bool, allNames *sets.String, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + if requireName && len(sp.Name) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("name"), "")) + } else if len(sp.Name) != 0 { + allErrs = append(allErrs, ValidateDNS1123Label(sp.Name, fldPath.Child("name"))...) + if allNames.Has(sp.Name) { + allErrs = append(allErrs, field.Duplicate(fldPath.Child("name"), sp.Name)) + } else { + allNames.Insert(sp.Name) + } + } + + for _, msg := range validation.IsValidPortNum(int(sp.Port)) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("port"), sp.Port, msg)) + } + + if len(sp.Protocol) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("protocol"), "")) + } else if !supportedPortProtocols.Has(string(sp.Protocol)) { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("protocol"), sp.Protocol, supportedPortProtocols.List())) + } + + allErrs = append(allErrs, ValidatePortNumOrName(sp.TargetPort, fldPath.Child("targetPort"))...) + + if sp.AppProtocol != nil { + allErrs = append(allErrs, ValidateQualifiedName(*sp.AppProtocol, fldPath.Child("appProtocol"))...) + } + + // in the v1 API, targetPorts on headless services were tolerated. + // once we have version-specific validation, we can reject this on newer API versions, but until then, we have to tolerate it for compatibility. + // + // if isHeadlessService { + // if sp.TargetPort.Type == intstr.String || (sp.TargetPort.Type == intstr.Int && sp.Port != sp.TargetPort.IntValue()) { + // allErrs = append(allErrs, field.Invalid(fldPath.Child("targetPort"), sp.TargetPort, "must be equal to the value of 'port' when clusterIP = None")) + // } + // } + + return allErrs +} + +func needsExternalTrafficPolicy(svc *core.Service) bool { + return svc.Spec.Type == core.ServiceTypeLoadBalancer || svc.Spec.Type == core.ServiceTypeNodePort +} + +var validExternalTrafficPolicies = sets.NewString( + string(core.ServiceExternalTrafficPolicyTypeCluster), + string(core.ServiceExternalTrafficPolicyTypeLocal)) + +func validateServiceExternalTrafficPolicy(service *core.Service) field.ErrorList { + allErrs := field.ErrorList{} + + fldPath := field.NewPath("spec") + + if !needsExternalTrafficPolicy(service) { + if service.Spec.ExternalTrafficPolicy != "" { + allErrs = append(allErrs, field.Invalid(fldPath.Child("externalTrafficPolicy"), service.Spec.ExternalTrafficPolicy, + "may only be set when `type` is 'NodePort' or 'LoadBalancer'")) + } + } else { + if service.Spec.ExternalTrafficPolicy == "" { + allErrs = append(allErrs, field.Required(fldPath.Child("externalTrafficPolicy"), "")) + } else if !validExternalTrafficPolicies.Has(string(service.Spec.ExternalTrafficPolicy)) { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("externalTrafficPolicy"), + service.Spec.ExternalTrafficPolicy, validExternalTrafficPolicies.List())) + } + } + + if !apiservice.NeedsHealthCheck(service) { + if service.Spec.HealthCheckNodePort != 0 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("healthCheckNodePort"), service.Spec.HealthCheckNodePort, + "may only be set when `type` is 'LoadBalancer' and `externalTrafficPolicy` is 'Local'")) + } + } else { + if service.Spec.HealthCheckNodePort == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("healthCheckNodePort"), "")) + } else { + for _, msg := range validation.IsValidPortNum(int(service.Spec.HealthCheckNodePort)) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("healthCheckNodePort"), service.Spec.HealthCheckNodePort, msg)) + } + } + } + + return allErrs +} + +func validateServiceExternalTrafficFieldsUpdate(before, after *core.Service) field.ErrorList { + allErrs := field.ErrorList{} + + if apiservice.NeedsHealthCheck(before) && apiservice.NeedsHealthCheck(after) { + if after.Spec.HealthCheckNodePort != before.Spec.HealthCheckNodePort { + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "healthCheckNodePort"), "field is immutable")) + } + } + + return allErrs +} + +// validateServiceInternalTrafficFieldsValue validates InternalTraffic related +// spec have legal value. +func validateServiceInternalTrafficFieldsValue(service *core.Service) field.ErrorList { + allErrs := field.ErrorList{} + + if service.Spec.InternalTrafficPolicy == nil { + // We do not forbid internalTrafficPolicy on other Service types because of historical reasons. + // We did not check that before it went beta and we don't want to invalidate existing stored objects. + if service.Spec.Type == core.ServiceTypeNodePort || + service.Spec.Type == core.ServiceTypeLoadBalancer || service.Spec.Type == core.ServiceTypeClusterIP { + allErrs = append(allErrs, field.Required(field.NewPath("spec").Child("internalTrafficPolicy"), "")) + } + } + + if service.Spec.InternalTrafficPolicy != nil && !supportedServiceInternalTrafficPolicy.Has(string(*service.Spec.InternalTrafficPolicy)) { + allErrs = append(allErrs, field.NotSupported(field.NewPath("spec").Child("internalTrafficPolicy"), *service.Spec.InternalTrafficPolicy, supportedServiceInternalTrafficPolicy.List())) + } + + return allErrs +} + +// ValidateServiceCreate validates Services as they are created. +func ValidateServiceCreate(service *core.Service) field.ErrorList { + return ValidateService(service) +} + +// ValidateServiceUpdate tests if required fields in the service are set during an update +func ValidateServiceUpdate(service, oldService *core.Service) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&service.ObjectMeta, &oldService.ObjectMeta, field.NewPath("metadata")) + + // User can upgrade (add another clusterIP or ipFamily) + // can downgrade (remove secondary clusterIP or ipFamily) + // but *CAN NOT* change primary/secondary clusterIP || ipFamily *UNLESS* + // they are changing from/to/ON ExternalName + + upgradeDowngradeClusterIPsErrs := validateUpgradeDowngradeClusterIPs(oldService, service) + allErrs = append(allErrs, upgradeDowngradeClusterIPsErrs...) + + upgradeDowngradeIPFamiliesErrs := validateUpgradeDowngradeIPFamilies(oldService, service) + allErrs = append(allErrs, upgradeDowngradeIPFamiliesErrs...) + + upgradeDowngradeLoadBalancerClassErrs := validateLoadBalancerClassField(oldService, service) + allErrs = append(allErrs, upgradeDowngradeLoadBalancerClassErrs...) + + allErrs = append(allErrs, validateServiceExternalTrafficFieldsUpdate(oldService, service)...) + + return append(allErrs, ValidateService(service)...) +} + +// ValidateServiceStatusUpdate tests if required fields in the Service are set when updating status. +func ValidateServiceStatusUpdate(service, oldService *core.Service) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&service.ObjectMeta, &oldService.ObjectMeta, field.NewPath("metadata")) + allErrs = append(allErrs, ValidateLoadBalancerStatus(&service.Status.LoadBalancer, field.NewPath("status", "loadBalancer"))...) + return allErrs +} + +// ValidateReplicationController tests if required fields in the replication controller are set. +func ValidateReplicationController(controller *core.ReplicationController, opts PodValidationOptions) field.ErrorList { + allErrs := ValidateObjectMeta(&controller.ObjectMeta, true, ValidateReplicationControllerName, field.NewPath("metadata")) + allErrs = append(allErrs, ValidateReplicationControllerSpec(&controller.Spec, field.NewPath("spec"), opts)...) + return allErrs +} + +// ValidateReplicationControllerUpdate tests if required fields in the replication controller are set. +func ValidateReplicationControllerUpdate(controller, oldController *core.ReplicationController, opts PodValidationOptions) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, field.NewPath("metadata")) + allErrs = append(allErrs, ValidateReplicationControllerSpec(&controller.Spec, field.NewPath("spec"), opts)...) + return allErrs +} + +// ValidateReplicationControllerStatusUpdate tests if required fields in the replication controller are set. +func ValidateReplicationControllerStatusUpdate(controller, oldController *core.ReplicationController) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, field.NewPath("metadata")) + allErrs = append(allErrs, ValidateReplicationControllerStatus(controller.Status, field.NewPath("status"))...) + return allErrs +} + +func ValidateReplicationControllerStatus(status core.ReplicationControllerStatus, statusPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + allErrs = append(allErrs, ValidateNonnegativeField(int64(status.Replicas), statusPath.Child("replicas"))...) + allErrs = append(allErrs, ValidateNonnegativeField(int64(status.FullyLabeledReplicas), statusPath.Child("fullyLabeledReplicas"))...) + allErrs = append(allErrs, ValidateNonnegativeField(int64(status.ReadyReplicas), statusPath.Child("readyReplicas"))...) + allErrs = append(allErrs, ValidateNonnegativeField(int64(status.AvailableReplicas), statusPath.Child("availableReplicas"))...) + allErrs = append(allErrs, ValidateNonnegativeField(int64(status.ObservedGeneration), statusPath.Child("observedGeneration"))...) + msg := "cannot be greater than status.replicas" + if status.FullyLabeledReplicas > status.Replicas { + allErrs = append(allErrs, field.Invalid(statusPath.Child("fullyLabeledReplicas"), status.FullyLabeledReplicas, msg)) + } + if status.ReadyReplicas > status.Replicas { + allErrs = append(allErrs, field.Invalid(statusPath.Child("readyReplicas"), status.ReadyReplicas, msg)) + } + if status.AvailableReplicas > status.Replicas { + allErrs = append(allErrs, field.Invalid(statusPath.Child("availableReplicas"), status.AvailableReplicas, msg)) + } + if status.AvailableReplicas > status.ReadyReplicas { + allErrs = append(allErrs, field.Invalid(statusPath.Child("availableReplicas"), status.AvailableReplicas, "cannot be greater than readyReplicas")) + } + return allErrs +} + +// Validates that the given selector is non-empty. +func ValidateNonEmptySelector(selectorMap map[string]string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + selector := labels.Set(selectorMap).AsSelector() + if selector.Empty() { + allErrs = append(allErrs, field.Required(fldPath, "")) + } + return allErrs +} + +// Validates the given template and ensures that it is in accordance with the desired selector and replicas. +func ValidatePodTemplateSpecForRC(template *core.PodTemplateSpec, selectorMap map[string]string, replicas int32, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { + allErrs := field.ErrorList{} + if template == nil { + allErrs = append(allErrs, field.Required(fldPath, "")) + } else { + selector := labels.Set(selectorMap).AsSelector() + if !selector.Empty() { + // Verify that the RC selector matches the labels in template. + labels := labels.Set(template.Labels) + if !selector.Matches(labels) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("metadata", "labels"), template.Labels, "`selector` does not match template `labels`")) + } + } + allErrs = append(allErrs, ValidatePodTemplateSpec(template, fldPath, opts)...) + if replicas > 1 { + allErrs = append(allErrs, ValidateReadOnlyPersistentDisks(template.Spec.Volumes, fldPath.Child("spec", "volumes"))...) + } + // RestartPolicy has already been first-order validated as per ValidatePodTemplateSpec(). + if template.Spec.RestartPolicy != core.RestartPolicyAlways { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("spec", "restartPolicy"), template.Spec.RestartPolicy, []string{string(core.RestartPolicyAlways)})) + } + if template.Spec.ActiveDeadlineSeconds != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("spec", "activeDeadlineSeconds"), "activeDeadlineSeconds in ReplicationController is not Supported")) + } + } + return allErrs +} + +// ValidateReplicationControllerSpec tests if required fields in the replication controller spec are set. +func ValidateReplicationControllerSpec(spec *core.ReplicationControllerSpec, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { + allErrs := field.ErrorList{} + allErrs = append(allErrs, ValidateNonnegativeField(int64(spec.MinReadySeconds), fldPath.Child("minReadySeconds"))...) + allErrs = append(allErrs, ValidateNonEmptySelector(spec.Selector, fldPath.Child("selector"))...) + allErrs = append(allErrs, ValidateNonnegativeField(int64(spec.Replicas), fldPath.Child("replicas"))...) + allErrs = append(allErrs, ValidatePodTemplateSpecForRC(spec.Template, spec.Selector, spec.Replicas, fldPath.Child("template"), opts)...) + return allErrs +} + +// ValidatePodTemplateSpec validates the spec of a pod template +func ValidatePodTemplateSpec(spec *core.PodTemplateSpec, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { + allErrs := field.ErrorList{} + allErrs = append(allErrs, unversionedvalidation.ValidateLabels(spec.Labels, fldPath.Child("labels"))...) + allErrs = append(allErrs, ValidateAnnotations(spec.Annotations, fldPath.Child("annotations"))...) + allErrs = append(allErrs, ValidatePodSpecificAnnotations(spec.Annotations, &spec.Spec, fldPath.Child("annotations"), opts)...) + allErrs = append(allErrs, ValidatePodSpec(&spec.Spec, nil, fldPath.Child("spec"), opts)...) + allErrs = append(allErrs, validateSeccompAnnotationsAndFields(spec.ObjectMeta, &spec.Spec, fldPath.Child("spec"))...) + + if len(spec.Spec.EphemeralContainers) > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("spec", "ephemeralContainers"), "ephemeral containers not allowed in pod template")) + } + + return allErrs +} + +func ValidateReadOnlyPersistentDisks(volumes []core.Volume, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + for i := range volumes { + vol := &volumes[i] + idxPath := fldPath.Index(i) + if vol.GCEPersistentDisk != nil { + if !vol.GCEPersistentDisk.ReadOnly { + allErrs = append(allErrs, field.Invalid(idxPath.Child("gcePersistentDisk", "readOnly"), false, "must be true for replicated pods > 1; GCE PD can only be mounted on multiple machines if it is read-only")) + } + } + // TODO: What to do for AWS? It doesn't support replicas + } + return allErrs +} + +// ValidateTaintsInNodeAnnotations tests that the serialized taints in Node.Annotations has valid data +func ValidateTaintsInNodeAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + taints, err := helper.GetTaintsFromNodeAnnotations(annotations) + if err != nil { + allErrs = append(allErrs, field.Invalid(fldPath, core.TaintsAnnotationKey, err.Error())) + return allErrs + } + + if len(taints) > 0 { + allErrs = append(allErrs, validateNodeTaints(taints, fldPath.Child(core.TaintsAnnotationKey))...) + } + + return allErrs +} + +// validateNodeTaints tests if given taints have valid data. +func validateNodeTaints(taints []core.Taint, fldPath *field.Path) field.ErrorList { + allErrors := field.ErrorList{} + + uniqueTaints := map[core.TaintEffect]sets.String{} + + for i, currTaint := range taints { + idxPath := fldPath.Index(i) + // validate the taint key + allErrors = append(allErrors, unversionedvalidation.ValidateLabelName(currTaint.Key, idxPath.Child("key"))...) + // validate the taint value + if errs := validation.IsValidLabelValue(currTaint.Value); len(errs) != 0 { + allErrors = append(allErrors, field.Invalid(idxPath.Child("value"), currTaint.Value, strings.Join(errs, ";"))) + } + // validate the taint effect + allErrors = append(allErrors, validateTaintEffect(&currTaint.Effect, false, idxPath.Child("effect"))...) + + // validate if taint is unique by + if len(uniqueTaints[currTaint.Effect]) > 0 && uniqueTaints[currTaint.Effect].Has(currTaint.Key) { + duplicatedError := field.Duplicate(idxPath, currTaint) + duplicatedError.Detail = "taints must be unique by key and effect pair" + allErrors = append(allErrors, duplicatedError) + continue + } + + // add taint to existingTaints for uniqueness check + if len(uniqueTaints[currTaint.Effect]) == 0 { + uniqueTaints[currTaint.Effect] = sets.String{} + } + uniqueTaints[currTaint.Effect].Insert(currTaint.Key) + } + return allErrors +} + +func ValidateNodeSpecificAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + if annotations[core.TaintsAnnotationKey] != "" { + allErrs = append(allErrs, ValidateTaintsInNodeAnnotations(annotations, fldPath)...) + } + + if annotations[core.PreferAvoidPodsAnnotationKey] != "" { + allErrs = append(allErrs, ValidateAvoidPodsInNodeAnnotations(annotations, fldPath)...) + } + return allErrs +} + +// ValidateNode tests if required fields in the node are set. +func ValidateNode(node *core.Node) field.ErrorList { + fldPath := field.NewPath("metadata") + allErrs := ValidateObjectMeta(&node.ObjectMeta, false, ValidateNodeName, fldPath) + allErrs = append(allErrs, ValidateNodeSpecificAnnotations(node.ObjectMeta.Annotations, fldPath.Child("annotations"))...) + if len(node.Spec.Taints) > 0 { + allErrs = append(allErrs, validateNodeTaints(node.Spec.Taints, fldPath.Child("taints"))...) + } + + // Only validate spec. + // All status fields are optional and can be updated later. + // That said, if specified, we need to ensure they are valid. + allErrs = append(allErrs, ValidateNodeResources(node)...) + + // validate PodCIDRS only if we need to + if len(node.Spec.PodCIDRs) > 0 { + podCIDRsField := field.NewPath("spec", "podCIDRs") + + // all PodCIDRs should be valid ones + for idx, value := range node.Spec.PodCIDRs { + if _, err := ValidateCIDR(value); err != nil { + allErrs = append(allErrs, field.Invalid(podCIDRsField.Index(idx), node.Spec.PodCIDRs, "must be valid CIDR")) + } + } + + // if more than PodCIDR then + // - validate for dual stack + // - validate for duplication + if len(node.Spec.PodCIDRs) > 1 { + dualStack, err := netutils.IsDualStackCIDRStrings(node.Spec.PodCIDRs) + if err != nil { + allErrs = append(allErrs, field.InternalError(podCIDRsField, fmt.Errorf("invalid PodCIDRs. failed to check with dual stack with error:%v", err))) + } + if !dualStack || len(node.Spec.PodCIDRs) > 2 { + allErrs = append(allErrs, field.Invalid(podCIDRsField, node.Spec.PodCIDRs, "may specify no more than one CIDR for each IP family")) + } + + // PodCIDRs must not contain duplicates + seen := sets.String{} + for i, value := range node.Spec.PodCIDRs { + if seen.Has(value) { + allErrs = append(allErrs, field.Duplicate(podCIDRsField.Index(i), value)) + } + seen.Insert(value) + } + } + } + + return allErrs +} + +// ValidateNodeResources is used to make sure a node has valid capacity and allocatable values. +func ValidateNodeResources(node *core.Node) field.ErrorList { + allErrs := field.ErrorList{} + + // Validate resource quantities in capacity. + for k, v := range node.Status.Capacity { + resPath := field.NewPath("status", "capacity", string(k)) + allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...) + } + + // Validate resource quantities in allocatable. + for k, v := range node.Status.Allocatable { + resPath := field.NewPath("status", "allocatable", string(k)) + allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...) + } + return allErrs +} + +// ValidateNodeUpdate tests to make sure a node update can be applied. Modifies oldNode. +func ValidateNodeUpdate(node, oldNode *core.Node) field.ErrorList { + fldPath := field.NewPath("metadata") + allErrs := ValidateObjectMetaUpdate(&node.ObjectMeta, &oldNode.ObjectMeta, fldPath) + allErrs = append(allErrs, ValidateNodeSpecificAnnotations(node.ObjectMeta.Annotations, fldPath.Child("annotations"))...) + + // TODO: Enable the code once we have better core object.status update model. Currently, + // anyone can update node status. + // if !apiequality.Semantic.DeepEqual(node.Status, core.NodeStatus{}) { + // allErrs = append(allErrs, field.Invalid("status", node.Status, "must be empty")) + // } + + allErrs = append(allErrs, ValidateNodeResources(node)...) + + // Validate no duplicate addresses in node status. + addresses := make(map[core.NodeAddress]bool) + for i, address := range node.Status.Addresses { + if _, ok := addresses[address]; ok { + allErrs = append(allErrs, field.Duplicate(field.NewPath("status", "addresses").Index(i), address)) + } + addresses[address] = true + } + + // Allow the controller manager to assign a CIDR to a node if it doesn't have one. + if len(oldNode.Spec.PodCIDRs) > 0 { + // compare the entire slice + if len(oldNode.Spec.PodCIDRs) != len(node.Spec.PodCIDRs) { + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "podCIDRs"), "node updates may not change podCIDR except from \"\" to valid")) + } else { + for idx, value := range oldNode.Spec.PodCIDRs { + if value != node.Spec.PodCIDRs[idx] { + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "podCIDRs"), "node updates may not change podCIDR except from \"\" to valid")) + } + } + } + } + + // Allow controller manager updating provider ID when not set + if len(oldNode.Spec.ProviderID) > 0 && oldNode.Spec.ProviderID != node.Spec.ProviderID { + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "providerID"), "node updates may not change providerID except from \"\" to valid")) + } + + if node.Spec.ConfigSource != nil { + allErrs = append(allErrs, validateNodeConfigSourceSpec(node.Spec.ConfigSource, field.NewPath("spec", "configSource"))...) + } + if node.Status.Config != nil { + allErrs = append(allErrs, validateNodeConfigStatus(node.Status.Config, field.NewPath("status", "config"))...) + } + + // update taints + if len(node.Spec.Taints) > 0 { + allErrs = append(allErrs, validateNodeTaints(node.Spec.Taints, fldPath.Child("taints"))...) + } + + if node.Spec.DoNotUseExternalID != oldNode.Spec.DoNotUseExternalID { + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "externalID"), "may not be updated")) + } + + // status and metadata are allowed change (barring restrictions above), so separately test spec field. + // spec only has a few fields, so check the ones we don't allow changing + // 1. PodCIDRs - immutable after first set - checked above + // 2. ProviderID - immutable after first set - checked above + // 3. Unschedulable - allowed to change + // 4. Taints - allowed to change + // 5. ConfigSource - allowed to change (and checked above) + // 6. DoNotUseExternalID - immutable - checked above + + return allErrs +} + +// validation specific to Node.Spec.ConfigSource +// The field ConfigSource is deprecated and will not be used. The validation is kept in place +// for the backward compatibility +func validateNodeConfigSourceSpec(source *core.NodeConfigSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + count := int(0) + if source.ConfigMap != nil { + count++ + allErrs = append(allErrs, validateConfigMapNodeConfigSourceSpec(source.ConfigMap, fldPath.Child("configMap"))...) + } + // add more subfields here in the future as they are added to NodeConfigSource + + // exactly one reference subfield must be non-nil + if count != 1 { + allErrs = append(allErrs, field.Invalid(fldPath, source, "exactly one reference subfield must be non-nil")) + } + return allErrs +} + +// validation specific to Node.Spec.ConfigSource.ConfigMap +// The field ConfigSource is deprecated and will not be used. The validation is kept in place +// for the backward compatibility +func validateConfigMapNodeConfigSourceSpec(source *core.ConfigMapNodeConfigSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + // uid and resourceVersion must not be set in spec + if string(source.UID) != "" { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("uid"), "uid must not be set in spec")) + } + if source.ResourceVersion != "" { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("resourceVersion"), "resourceVersion must not be set in spec")) + } + return append(allErrs, validateConfigMapNodeConfigSource(source, fldPath)...) +} + +// validation specififc to Node.Status.Config +func validateNodeConfigStatus(status *core.NodeConfigStatus, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if status.Assigned != nil { + allErrs = append(allErrs, validateNodeConfigSourceStatus(status.Assigned, fldPath.Child("assigned"))...) + } + if status.Active != nil { + allErrs = append(allErrs, validateNodeConfigSourceStatus(status.Active, fldPath.Child("active"))...) + } + if status.LastKnownGood != nil { + allErrs = append(allErrs, validateNodeConfigSourceStatus(status.LastKnownGood, fldPath.Child("lastKnownGood"))...) + } + return allErrs +} + +// validation specific to Node.Status.Config.(Active|Assigned|LastKnownGood) +func validateNodeConfigSourceStatus(source *core.NodeConfigSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + count := int(0) + if source.ConfigMap != nil { + count++ + allErrs = append(allErrs, validateConfigMapNodeConfigSourceStatus(source.ConfigMap, fldPath.Child("configMap"))...) + } + // add more subfields here in the future as they are added to NodeConfigSource + + // exactly one reference subfield must be non-nil + if count != 1 { + allErrs = append(allErrs, field.Invalid(fldPath, source, "exactly one reference subfield must be non-nil")) + } + return allErrs +} + +// validation specific to Node.Status.Config.(Active|Assigned|LastKnownGood).ConfigMap +func validateConfigMapNodeConfigSourceStatus(source *core.ConfigMapNodeConfigSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + // uid and resourceVersion must be set in status + if string(source.UID) == "" { + allErrs = append(allErrs, field.Required(fldPath.Child("uid"), "uid must be set in status")) + } + if source.ResourceVersion == "" { + allErrs = append(allErrs, field.Required(fldPath.Child("resourceVersion"), "resourceVersion must be set in status")) + } + return append(allErrs, validateConfigMapNodeConfigSource(source, fldPath)...) +} + +// common validation +func validateConfigMapNodeConfigSource(source *core.ConfigMapNodeConfigSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + // validate target configmap namespace + if source.Namespace == "" { + allErrs = append(allErrs, field.Required(fldPath.Child("namespace"), "namespace must be set")) + } else { + for _, msg := range ValidateNameFunc(ValidateNamespaceName)(source.Namespace, false) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("namespace"), source.Namespace, msg)) + } + } + // validate target configmap name + if source.Name == "" { + allErrs = append(allErrs, field.Required(fldPath.Child("name"), "name must be set")) + } else { + for _, msg := range ValidateNameFunc(ValidateConfigMapName)(source.Name, false) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), source.Name, msg)) + } + } + // validate kubeletConfigKey against rules for configMap key names + if source.KubeletConfigKey == "" { + allErrs = append(allErrs, field.Required(fldPath.Child("kubeletConfigKey"), "kubeletConfigKey must be set")) + } else { + for _, msg := range validation.IsConfigMapKey(source.KubeletConfigKey) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("kubeletConfigKey"), source.KubeletConfigKey, msg)) + } + } + return allErrs +} + +// Validate compute resource typename. +// Refer to docs/design/resources.md for more details. +func validateResourceName(value string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + for _, msg := range validation.IsQualifiedName(value) { + allErrs = append(allErrs, field.Invalid(fldPath, value, msg)) + } + if len(allErrs) != 0 { + return allErrs + } + + if len(strings.Split(value, "/")) == 1 { + if !helper.IsStandardResourceName(value) { + return append(allErrs, field.Invalid(fldPath, value, "must be a standard resource type or fully qualified")) + } + } + + return allErrs +} + +// Validate container resource name +// Refer to docs/design/resources.md for more details. +func validateContainerResourceName(value string, fldPath *field.Path) field.ErrorList { + allErrs := validateResourceName(value, fldPath) + + if len(strings.Split(value, "/")) == 1 { + if !helper.IsStandardContainerResourceName(value) { + return append(allErrs, field.Invalid(fldPath, value, "must be a standard resource for containers")) + } + } else if !helper.IsNativeResource(core.ResourceName(value)) { + if !helper.IsExtendedResourceName(core.ResourceName(value)) { + return append(allErrs, field.Invalid(fldPath, value, "doesn't follow extended resource name standard")) + } + } + return allErrs +} + +// Validate resource names that can go in a resource quota +// Refer to docs/design/resources.md for more details. +func ValidateResourceQuotaResourceName(value string, fldPath *field.Path) field.ErrorList { + allErrs := validateResourceName(value, fldPath) + + if len(strings.Split(value, "/")) == 1 { + if !helper.IsStandardQuotaResourceName(value) { + return append(allErrs, field.Invalid(fldPath, value, isInvalidQuotaResource)) + } + } + return allErrs +} + +// Validate limit range types +func validateLimitRangeTypeName(value string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + for _, msg := range validation.IsQualifiedName(value) { + allErrs = append(allErrs, field.Invalid(fldPath, value, msg)) + } + if len(allErrs) != 0 { + return allErrs + } + + if len(strings.Split(value, "/")) == 1 { + if !helper.IsStandardLimitRangeType(value) { + return append(allErrs, field.Invalid(fldPath, value, "must be a standard limit type or fully qualified")) + } + } + + return allErrs +} + +// Validate limit range resource name +// limit types (other than Pod/Container) could contain storage not just cpu or memory +func validateLimitRangeResourceName(limitType core.LimitType, value string, fldPath *field.Path) field.ErrorList { + switch limitType { + case core.LimitTypePod, core.LimitTypeContainer: + return validateContainerResourceName(value, fldPath) + default: + return validateResourceName(value, fldPath) + } +} + +// ValidateLimitRange tests if required fields in the LimitRange are set. +func ValidateLimitRange(limitRange *core.LimitRange) field.ErrorList { + allErrs := ValidateObjectMeta(&limitRange.ObjectMeta, true, ValidateLimitRangeName, field.NewPath("metadata")) + + // ensure resource names are properly qualified per docs/design/resources.md + limitTypeSet := map[core.LimitType]bool{} + fldPath := field.NewPath("spec", "limits") + for i := range limitRange.Spec.Limits { + idxPath := fldPath.Index(i) + limit := &limitRange.Spec.Limits[i] + allErrs = append(allErrs, validateLimitRangeTypeName(string(limit.Type), idxPath.Child("type"))...) + + _, found := limitTypeSet[limit.Type] + if found { + allErrs = append(allErrs, field.Duplicate(idxPath.Child("type"), limit.Type)) + } + limitTypeSet[limit.Type] = true + + keys := sets.String{} + min := map[string]resource.Quantity{} + max := map[string]resource.Quantity{} + defaults := map[string]resource.Quantity{} + defaultRequests := map[string]resource.Quantity{} + maxLimitRequestRatios := map[string]resource.Quantity{} + + for k, q := range limit.Max { + allErrs = append(allErrs, validateLimitRangeResourceName(limit.Type, string(k), idxPath.Child("max").Key(string(k)))...) + keys.Insert(string(k)) + max[string(k)] = q + } + for k, q := range limit.Min { + allErrs = append(allErrs, validateLimitRangeResourceName(limit.Type, string(k), idxPath.Child("min").Key(string(k)))...) + keys.Insert(string(k)) + min[string(k)] = q + } + + if limit.Type == core.LimitTypePod { + if len(limit.Default) > 0 { + allErrs = append(allErrs, field.Forbidden(idxPath.Child("default"), "may not be specified when `type` is 'Pod'")) + } + if len(limit.DefaultRequest) > 0 { + allErrs = append(allErrs, field.Forbidden(idxPath.Child("defaultRequest"), "may not be specified when `type` is 'Pod'")) + } + } else { + for k, q := range limit.Default { + allErrs = append(allErrs, validateLimitRangeResourceName(limit.Type, string(k), idxPath.Child("default").Key(string(k)))...) + keys.Insert(string(k)) + defaults[string(k)] = q + } + for k, q := range limit.DefaultRequest { + allErrs = append(allErrs, validateLimitRangeResourceName(limit.Type, string(k), idxPath.Child("defaultRequest").Key(string(k)))...) + keys.Insert(string(k)) + defaultRequests[string(k)] = q + } + } + + if limit.Type == core.LimitTypePersistentVolumeClaim { + _, minQuantityFound := limit.Min[core.ResourceStorage] + _, maxQuantityFound := limit.Max[core.ResourceStorage] + if !minQuantityFound && !maxQuantityFound { + allErrs = append(allErrs, field.Required(idxPath.Child("limits"), "either minimum or maximum storage value is required, but neither was provided")) + } + } + + for k, q := range limit.MaxLimitRequestRatio { + allErrs = append(allErrs, validateLimitRangeResourceName(limit.Type, string(k), idxPath.Child("maxLimitRequestRatio").Key(string(k)))...) + keys.Insert(string(k)) + maxLimitRequestRatios[string(k)] = q + } + + for k := range keys { + minQuantity, minQuantityFound := min[k] + maxQuantity, maxQuantityFound := max[k] + defaultQuantity, defaultQuantityFound := defaults[k] + defaultRequestQuantity, defaultRequestQuantityFound := defaultRequests[k] + maxRatio, maxRatioFound := maxLimitRequestRatios[k] + + if minQuantityFound && maxQuantityFound && minQuantity.Cmp(maxQuantity) > 0 { + allErrs = append(allErrs, field.Invalid(idxPath.Child("min").Key(string(k)), minQuantity, fmt.Sprintf("min value %s is greater than max value %s", minQuantity.String(), maxQuantity.String()))) + } + + if defaultRequestQuantityFound && minQuantityFound && minQuantity.Cmp(defaultRequestQuantity) > 0 { + allErrs = append(allErrs, field.Invalid(idxPath.Child("defaultRequest").Key(string(k)), defaultRequestQuantity, fmt.Sprintf("min value %s is greater than default request value %s", minQuantity.String(), defaultRequestQuantity.String()))) + } + + if defaultRequestQuantityFound && maxQuantityFound && defaultRequestQuantity.Cmp(maxQuantity) > 0 { + allErrs = append(allErrs, field.Invalid(idxPath.Child("defaultRequest").Key(string(k)), defaultRequestQuantity, fmt.Sprintf("default request value %s is greater than max value %s", defaultRequestQuantity.String(), maxQuantity.String()))) + } + + if defaultRequestQuantityFound && defaultQuantityFound && defaultRequestQuantity.Cmp(defaultQuantity) > 0 { + allErrs = append(allErrs, field.Invalid(idxPath.Child("defaultRequest").Key(string(k)), defaultRequestQuantity, fmt.Sprintf("default request value %s is greater than default limit value %s", defaultRequestQuantity.String(), defaultQuantity.String()))) + } + + if defaultQuantityFound && minQuantityFound && minQuantity.Cmp(defaultQuantity) > 0 { + allErrs = append(allErrs, field.Invalid(idxPath.Child("default").Key(string(k)), minQuantity, fmt.Sprintf("min value %s is greater than default value %s", minQuantity.String(), defaultQuantity.String()))) + } + + if defaultQuantityFound && maxQuantityFound && defaultQuantity.Cmp(maxQuantity) > 0 { + allErrs = append(allErrs, field.Invalid(idxPath.Child("default").Key(string(k)), maxQuantity, fmt.Sprintf("default value %s is greater than max value %s", defaultQuantity.String(), maxQuantity.String()))) + } + if maxRatioFound && maxRatio.Cmp(*resource.NewQuantity(1, resource.DecimalSI)) < 0 { + allErrs = append(allErrs, field.Invalid(idxPath.Child("maxLimitRequestRatio").Key(string(k)), maxRatio, fmt.Sprintf("ratio %s is less than 1", maxRatio.String()))) + } + if maxRatioFound && minQuantityFound && maxQuantityFound { + maxRatioValue := float64(maxRatio.Value()) + minQuantityValue := minQuantity.Value() + maxQuantityValue := maxQuantity.Value() + if maxRatio.Value() < resource.MaxMilliValue && minQuantityValue < resource.MaxMilliValue && maxQuantityValue < resource.MaxMilliValue { + maxRatioValue = float64(maxRatio.MilliValue()) / 1000 + minQuantityValue = minQuantity.MilliValue() + maxQuantityValue = maxQuantity.MilliValue() + } + maxRatioLimit := float64(maxQuantityValue) / float64(minQuantityValue) + if maxRatioValue > maxRatioLimit { + allErrs = append(allErrs, field.Invalid(idxPath.Child("maxLimitRequestRatio").Key(string(k)), maxRatio, fmt.Sprintf("ratio %s is greater than max/min = %f", maxRatio.String(), maxRatioLimit))) + } + } + + // for GPU, hugepages and other resources that are not allowed to overcommit, + // the default value and defaultRequest value must match if both are specified + if !helper.IsOvercommitAllowed(core.ResourceName(k)) && defaultQuantityFound && defaultRequestQuantityFound && defaultQuantity.Cmp(defaultRequestQuantity) != 0 { + allErrs = append(allErrs, field.Invalid(idxPath.Child("defaultRequest").Key(string(k)), defaultRequestQuantity, fmt.Sprintf("default value %s must equal to defaultRequest value %s in %s", defaultQuantity.String(), defaultRequestQuantity.String(), k))) + } + } + } + + return allErrs +} + +// ValidateServiceAccount tests if required fields in the ServiceAccount are set. +func ValidateServiceAccount(serviceAccount *core.ServiceAccount) field.ErrorList { + allErrs := ValidateObjectMeta(&serviceAccount.ObjectMeta, true, ValidateServiceAccountName, field.NewPath("metadata")) + return allErrs +} + +// ValidateServiceAccountUpdate tests if required fields in the ServiceAccount are set. +func ValidateServiceAccountUpdate(newServiceAccount, oldServiceAccount *core.ServiceAccount) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newServiceAccount.ObjectMeta, &oldServiceAccount.ObjectMeta, field.NewPath("metadata")) + allErrs = append(allErrs, ValidateServiceAccount(newServiceAccount)...) + return allErrs +} + +// ValidateSecret tests if required fields in the Secret are set. +func ValidateSecret(secret *core.Secret) field.ErrorList { + allErrs := ValidateObjectMeta(&secret.ObjectMeta, true, ValidateSecretName, field.NewPath("metadata")) + + dataPath := field.NewPath("data") + totalSize := 0 + for key, value := range secret.Data { + for _, msg := range validation.IsConfigMapKey(key) { + allErrs = append(allErrs, field.Invalid(dataPath.Key(key), key, msg)) + } + totalSize += len(value) + } + if totalSize > core.MaxSecretSize { + allErrs = append(allErrs, field.TooLong(dataPath, "", core.MaxSecretSize)) + } + + switch secret.Type { + case core.SecretTypeServiceAccountToken: + // Only require Annotations[kubernetes.io/service-account.name] + // Additional fields (like Annotations[kubernetes.io/service-account.uid] and Data[token]) might be contributed later by a controller loop + if value := secret.Annotations[core.ServiceAccountNameKey]; len(value) == 0 { + allErrs = append(allErrs, field.Required(field.NewPath("metadata", "annotations").Key(core.ServiceAccountNameKey), "")) + } + case core.SecretTypeOpaque, "": + // no-op + case core.SecretTypeDockercfg: + dockercfgBytes, exists := secret.Data[core.DockerConfigKey] + if !exists { + allErrs = append(allErrs, field.Required(dataPath.Key(core.DockerConfigKey), "")) + break + } + + // make sure that the content is well-formed json. + if err := json.Unmarshal(dockercfgBytes, &map[string]interface{}{}); err != nil { + allErrs = append(allErrs, field.Invalid(dataPath.Key(core.DockerConfigKey), "", err.Error())) + } + case core.SecretTypeDockerConfigJSON: + dockerConfigJSONBytes, exists := secret.Data[core.DockerConfigJSONKey] + if !exists { + allErrs = append(allErrs, field.Required(dataPath.Key(core.DockerConfigJSONKey), "")) + break + } + + // make sure that the content is well-formed json. + if err := json.Unmarshal(dockerConfigJSONBytes, &map[string]interface{}{}); err != nil { + allErrs = append(allErrs, field.Invalid(dataPath.Key(core.DockerConfigJSONKey), "", err.Error())) + } + case core.SecretTypeBasicAuth: + _, usernameFieldExists := secret.Data[core.BasicAuthUsernameKey] + _, passwordFieldExists := secret.Data[core.BasicAuthPasswordKey] + + // username or password might be empty, but the field must be present + if !usernameFieldExists && !passwordFieldExists { + allErrs = append(allErrs, field.Required(dataPath.Key(core.BasicAuthUsernameKey), "")) + allErrs = append(allErrs, field.Required(dataPath.Key(core.BasicAuthPasswordKey), "")) + break + } + case core.SecretTypeSSHAuth: + if len(secret.Data[core.SSHAuthPrivateKey]) == 0 { + allErrs = append(allErrs, field.Required(dataPath.Key(core.SSHAuthPrivateKey), "")) + break + } + + case core.SecretTypeTLS: + if _, exists := secret.Data[core.TLSCertKey]; !exists { + allErrs = append(allErrs, field.Required(dataPath.Key(core.TLSCertKey), "")) + } + if _, exists := secret.Data[core.TLSPrivateKeyKey]; !exists { + allErrs = append(allErrs, field.Required(dataPath.Key(core.TLSPrivateKeyKey), "")) + } + // TODO: Verify that the key matches the cert. + default: + // no-op + } + + return allErrs +} + +// ValidateSecretUpdate tests if required fields in the Secret are set. +func ValidateSecretUpdate(newSecret, oldSecret *core.Secret) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newSecret.ObjectMeta, &oldSecret.ObjectMeta, field.NewPath("metadata")) + + allErrs = append(allErrs, ValidateImmutableField(newSecret.Type, oldSecret.Type, field.NewPath("type"))...) + if oldSecret.Immutable != nil && *oldSecret.Immutable { + if newSecret.Immutable == nil || !*newSecret.Immutable { + allErrs = append(allErrs, field.Forbidden(field.NewPath("immutable"), "field is immutable when `immutable` is set")) + } + if !reflect.DeepEqual(newSecret.Data, oldSecret.Data) { + allErrs = append(allErrs, field.Forbidden(field.NewPath("data"), "field is immutable when `immutable` is set")) + } + // We don't validate StringData, as it was already converted back to Data + // before validation is happening. + } + + allErrs = append(allErrs, ValidateSecret(newSecret)...) + return allErrs +} + +// ValidateConfigMapName can be used to check whether the given ConfigMap name is valid. +// Prefix indicates this name will be used as part of generation, in which case +// trailing dashes are allowed. +var ValidateConfigMapName = apimachineryvalidation.NameIsDNSSubdomain + +// ValidateConfigMap tests whether required fields in the ConfigMap are set. +func ValidateConfigMap(cfg *core.ConfigMap) field.ErrorList { + allErrs := field.ErrorList{} + allErrs = append(allErrs, ValidateObjectMeta(&cfg.ObjectMeta, true, ValidateConfigMapName, field.NewPath("metadata"))...) + + totalSize := 0 + + for key, value := range cfg.Data { + for _, msg := range validation.IsConfigMapKey(key) { + allErrs = append(allErrs, field.Invalid(field.NewPath("data").Key(key), key, msg)) + } + // check if we have a duplicate key in the other bag + if _, isValue := cfg.BinaryData[key]; isValue { + msg := "duplicate of key present in binaryData" + allErrs = append(allErrs, field.Invalid(field.NewPath("data").Key(key), key, msg)) + } + totalSize += len(value) + } + for key, value := range cfg.BinaryData { + for _, msg := range validation.IsConfigMapKey(key) { + allErrs = append(allErrs, field.Invalid(field.NewPath("binaryData").Key(key), key, msg)) + } + totalSize += len(value) + } + if totalSize > core.MaxSecretSize { + // pass back "" to indicate that the error refers to the whole object. + allErrs = append(allErrs, field.TooLong(field.NewPath(""), cfg, core.MaxSecretSize)) + } + + return allErrs +} + +// ValidateConfigMapUpdate tests if required fields in the ConfigMap are set. +func ValidateConfigMapUpdate(newCfg, oldCfg *core.ConfigMap) field.ErrorList { + allErrs := field.ErrorList{} + allErrs = append(allErrs, ValidateObjectMetaUpdate(&newCfg.ObjectMeta, &oldCfg.ObjectMeta, field.NewPath("metadata"))...) + + if oldCfg.Immutable != nil && *oldCfg.Immutable { + if newCfg.Immutable == nil || !*newCfg.Immutable { + allErrs = append(allErrs, field.Forbidden(field.NewPath("immutable"), "field is immutable when `immutable` is set")) + } + if !reflect.DeepEqual(newCfg.Data, oldCfg.Data) { + allErrs = append(allErrs, field.Forbidden(field.NewPath("data"), "field is immutable when `immutable` is set")) + } + if !reflect.DeepEqual(newCfg.BinaryData, oldCfg.BinaryData) { + allErrs = append(allErrs, field.Forbidden(field.NewPath("binaryData"), "field is immutable when `immutable` is set")) + } + } + + allErrs = append(allErrs, ValidateConfigMap(newCfg)...) + return allErrs +} + +func validateBasicResource(quantity resource.Quantity, fldPath *field.Path) field.ErrorList { + if quantity.Value() < 0 { + return field.ErrorList{field.Invalid(fldPath, quantity.Value(), "must be a valid resource quantity")} + } + return field.ErrorList{} +} + +// Validates resource requirement spec. +func ValidateResourceRequirements(requirements *core.ResourceRequirements, podClaimNames sets.String, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { + allErrs := field.ErrorList{} + limPath := fldPath.Child("limits") + reqPath := fldPath.Child("requests") + limContainsCPUOrMemory := false + reqContainsCPUOrMemory := false + limContainsHugePages := false + reqContainsHugePages := false + supportedQoSComputeResources := sets.NewString(string(core.ResourceCPU), string(core.ResourceMemory)) + for resourceName, quantity := range requirements.Limits { + + fldPath := limPath.Key(string(resourceName)) + // Validate resource name. + allErrs = append(allErrs, validateContainerResourceName(string(resourceName), fldPath)...) + + // Validate resource quantity. + allErrs = append(allErrs, ValidateResourceQuantityValue(string(resourceName), quantity, fldPath)...) + + if helper.IsHugePageResourceName(resourceName) { + limContainsHugePages = true + if err := validateResourceQuantityHugePageValue(resourceName, quantity, opts); err != nil { + allErrs = append(allErrs, field.Invalid(fldPath, quantity.String(), err.Error())) + } + } + + if supportedQoSComputeResources.Has(string(resourceName)) { + limContainsCPUOrMemory = true + } + } + for resourceName, quantity := range requirements.Requests { + fldPath := reqPath.Key(string(resourceName)) + // Validate resource name. + allErrs = append(allErrs, validateContainerResourceName(string(resourceName), fldPath)...) + // Validate resource quantity. + allErrs = append(allErrs, ValidateResourceQuantityValue(string(resourceName), quantity, fldPath)...) + + // Check that request <= limit. + limitQuantity, exists := requirements.Limits[resourceName] + if exists { + // For non overcommitable resources, not only requests can't exceed limits, they also can't be lower, i.e. must be equal. + if quantity.Cmp(limitQuantity) != 0 && !helper.IsOvercommitAllowed(resourceName) { + allErrs = append(allErrs, field.Invalid(reqPath, quantity.String(), fmt.Sprintf("must be equal to %s limit", resourceName))) + } else if quantity.Cmp(limitQuantity) > 0 { + allErrs = append(allErrs, field.Invalid(reqPath, quantity.String(), fmt.Sprintf("must be less than or equal to %s limit", resourceName))) + } + } else if !helper.IsOvercommitAllowed(resourceName) { + allErrs = append(allErrs, field.Required(limPath, "Limit must be set for non overcommitable resources")) + } + if helper.IsHugePageResourceName(resourceName) { + reqContainsHugePages = true + if err := validateResourceQuantityHugePageValue(resourceName, quantity, opts); err != nil { + allErrs = append(allErrs, field.Invalid(fldPath, quantity.String(), err.Error())) + } + } + if supportedQoSComputeResources.Has(string(resourceName)) { + reqContainsCPUOrMemory = true + } + + } + if !limContainsCPUOrMemory && !reqContainsCPUOrMemory && (reqContainsHugePages || limContainsHugePages) { + allErrs = append(allErrs, field.Forbidden(fldPath, "HugePages require cpu or memory")) + } + + allErrs = append(allErrs, validateResourceClaimNames(requirements.Claims, podClaimNames, fldPath.Child("claims"))...) + + return allErrs +} + +// validateResourceClaimNames checks that the names in +// ResourceRequirements.Claims have a corresponding entry in +// PodSpec.ResourceClaims. +func validateResourceClaimNames(claims []core.ResourceClaim, podClaimNames sets.String, fldPath *field.Path) field.ErrorList { + var allErrs field.ErrorList + names := sets.String{} + for i, claim := range claims { + name := claim.Name + if name == "" { + allErrs = append(allErrs, field.Required(fldPath.Index(i), "")) + } else { + if names.Has(name) { + allErrs = append(allErrs, field.Duplicate(fldPath.Index(i), name)) + } else { + names.Insert(name) + } + if !podClaimNames.Has(name) { + // field.NotFound doesn't accept an + // explanation. Adding one here is more + // user-friendly. + error := field.NotFound(fldPath.Index(i), name) + error.Detail = "must be one of the names in pod.spec.resourceClaims" + if len(podClaimNames) == 0 { + error.Detail += " which is empty" + } else { + error.Detail += ": " + strings.Join(podClaimNames.List(), ", ") + } + allErrs = append(allErrs, error) + } + } + } + return allErrs +} + +func validateResourceQuantityHugePageValue(name core.ResourceName, quantity resource.Quantity, opts PodValidationOptions) error { + if !helper.IsHugePageResourceName(name) { + return nil + } + + if !opts.AllowIndivisibleHugePagesValues && !helper.IsHugePageResourceValueDivisible(name, quantity) { + return fmt.Errorf("%s is not positive integer multiple of %s", quantity.String(), name) + } + + return nil +} + +// validateResourceQuotaScopes ensures that each enumerated hard resource constraint is valid for set of scopes +func validateResourceQuotaScopes(resourceQuotaSpec *core.ResourceQuotaSpec, fld *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(resourceQuotaSpec.Scopes) == 0 { + return allErrs + } + hardLimits := sets.NewString() + for k := range resourceQuotaSpec.Hard { + hardLimits.Insert(string(k)) + } + fldPath := fld.Child("scopes") + scopeSet := sets.NewString() + for _, scope := range resourceQuotaSpec.Scopes { + if !helper.IsStandardResourceQuotaScope(string(scope)) { + allErrs = append(allErrs, field.Invalid(fldPath, resourceQuotaSpec.Scopes, "unsupported scope")) + } + for _, k := range hardLimits.List() { + if helper.IsStandardQuotaResourceName(k) && !helper.IsResourceQuotaScopeValidForResource(scope, k) { + allErrs = append(allErrs, field.Invalid(fldPath, resourceQuotaSpec.Scopes, "unsupported scope applied to resource")) + } + } + scopeSet.Insert(string(scope)) + } + invalidScopePairs := []sets.String{ + sets.NewString(string(core.ResourceQuotaScopeBestEffort), string(core.ResourceQuotaScopeNotBestEffort)), + sets.NewString(string(core.ResourceQuotaScopeTerminating), string(core.ResourceQuotaScopeNotTerminating)), + } + for _, invalidScopePair := range invalidScopePairs { + if scopeSet.HasAll(invalidScopePair.List()...) { + allErrs = append(allErrs, field.Invalid(fldPath, resourceQuotaSpec.Scopes, "conflicting scopes")) + } + } + return allErrs +} + +// validateScopedResourceSelectorRequirement tests that the match expressions has valid data +func validateScopedResourceSelectorRequirement(resourceQuotaSpec *core.ResourceQuotaSpec, fld *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + hardLimits := sets.NewString() + for k := range resourceQuotaSpec.Hard { + hardLimits.Insert(string(k)) + } + fldPath := fld.Child("matchExpressions") + scopeSet := sets.NewString() + for _, req := range resourceQuotaSpec.ScopeSelector.MatchExpressions { + if !helper.IsStandardResourceQuotaScope(string(req.ScopeName)) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("scopeName"), req.ScopeName, "unsupported scope")) + } + for _, k := range hardLimits.List() { + if helper.IsStandardQuotaResourceName(k) && !helper.IsResourceQuotaScopeValidForResource(req.ScopeName, k) { + allErrs = append(allErrs, field.Invalid(fldPath, resourceQuotaSpec.ScopeSelector, "unsupported scope applied to resource")) + } + } + switch req.ScopeName { + case core.ResourceQuotaScopeBestEffort, core.ResourceQuotaScopeNotBestEffort, core.ResourceQuotaScopeTerminating, core.ResourceQuotaScopeNotTerminating, core.ResourceQuotaScopeCrossNamespacePodAffinity: + if req.Operator != core.ScopeSelectorOpExists { + allErrs = append(allErrs, field.Invalid(fldPath.Child("operator"), req.Operator, + "must be 'Exist' when scope is any of ResourceQuotaScopeTerminating, ResourceQuotaScopeNotTerminating, ResourceQuotaScopeBestEffort, ResourceQuotaScopeNotBestEffort or ResourceQuotaScopeCrossNamespacePodAffinity")) + } + } + + switch req.Operator { + case core.ScopeSelectorOpIn, core.ScopeSelectorOpNotIn: + if len(req.Values) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("values"), + "must be at least one value when `operator` is 'In' or 'NotIn' for scope selector")) + } + case core.ScopeSelectorOpExists, core.ScopeSelectorOpDoesNotExist: + if len(req.Values) != 0 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("values"), req.Values, + "must be no value when `operator` is 'Exist' or 'DoesNotExist' for scope selector")) + } + default: + allErrs = append(allErrs, field.Invalid(fldPath.Child("operator"), req.Operator, "not a valid selector operator")) + } + scopeSet.Insert(string(req.ScopeName)) + } + invalidScopePairs := []sets.String{ + sets.NewString(string(core.ResourceQuotaScopeBestEffort), string(core.ResourceQuotaScopeNotBestEffort)), + sets.NewString(string(core.ResourceQuotaScopeTerminating), string(core.ResourceQuotaScopeNotTerminating)), + } + for _, invalidScopePair := range invalidScopePairs { + if scopeSet.HasAll(invalidScopePair.List()...) { + allErrs = append(allErrs, field.Invalid(fldPath, resourceQuotaSpec.Scopes, "conflicting scopes")) + } + } + + return allErrs +} + +// validateScopeSelector tests that the specified scope selector has valid data +func validateScopeSelector(resourceQuotaSpec *core.ResourceQuotaSpec, fld *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if resourceQuotaSpec.ScopeSelector == nil { + return allErrs + } + allErrs = append(allErrs, validateScopedResourceSelectorRequirement(resourceQuotaSpec, fld.Child("scopeSelector"))...) + return allErrs +} + +// ValidateResourceQuota tests if required fields in the ResourceQuota are set. +func ValidateResourceQuota(resourceQuota *core.ResourceQuota) field.ErrorList { + allErrs := ValidateObjectMeta(&resourceQuota.ObjectMeta, true, ValidateResourceQuotaName, field.NewPath("metadata")) + + allErrs = append(allErrs, ValidateResourceQuotaSpec(&resourceQuota.Spec, field.NewPath("spec"))...) + allErrs = append(allErrs, ValidateResourceQuotaStatus(&resourceQuota.Status, field.NewPath("status"))...) + + return allErrs +} + +func ValidateResourceQuotaStatus(status *core.ResourceQuotaStatus, fld *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + fldPath := fld.Child("hard") + for k, v := range status.Hard { + resPath := fldPath.Key(string(k)) + allErrs = append(allErrs, ValidateResourceQuotaResourceName(string(k), resPath)...) + allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...) + } + fldPath = fld.Child("used") + for k, v := range status.Used { + resPath := fldPath.Key(string(k)) + allErrs = append(allErrs, ValidateResourceQuotaResourceName(string(k), resPath)...) + allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...) + } + + return allErrs +} + +func ValidateResourceQuotaSpec(resourceQuotaSpec *core.ResourceQuotaSpec, fld *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + fldPath := fld.Child("hard") + for k, v := range resourceQuotaSpec.Hard { + resPath := fldPath.Key(string(k)) + allErrs = append(allErrs, ValidateResourceQuotaResourceName(string(k), resPath)...) + allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...) + } + + allErrs = append(allErrs, validateResourceQuotaScopes(resourceQuotaSpec, fld)...) + allErrs = append(allErrs, validateScopeSelector(resourceQuotaSpec, fld)...) + + return allErrs +} + +// ValidateResourceQuantityValue enforces that specified quantity is valid for specified resource +func ValidateResourceQuantityValue(resource string, value resource.Quantity, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + allErrs = append(allErrs, ValidateNonnegativeQuantity(value, fldPath)...) + if helper.IsIntegerResourceName(resource) { + if value.MilliValue()%int64(1000) != int64(0) { + allErrs = append(allErrs, field.Invalid(fldPath, value, isNotIntegerErrorMsg)) + } + } + return allErrs +} + +// ValidateResourceQuotaUpdate tests to see if the update is legal for an end user to make. +func ValidateResourceQuotaUpdate(newResourceQuota, oldResourceQuota *core.ResourceQuota) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newResourceQuota.ObjectMeta, &oldResourceQuota.ObjectMeta, field.NewPath("metadata")) + allErrs = append(allErrs, ValidateResourceQuotaSpec(&newResourceQuota.Spec, field.NewPath("spec"))...) + + // ensure scopes cannot change, and that resources are still valid for scope + fldPath := field.NewPath("spec", "scopes") + oldScopes := sets.NewString() + newScopes := sets.NewString() + for _, scope := range newResourceQuota.Spec.Scopes { + newScopes.Insert(string(scope)) + } + for _, scope := range oldResourceQuota.Spec.Scopes { + oldScopes.Insert(string(scope)) + } + if !oldScopes.Equal(newScopes) { + allErrs = append(allErrs, field.Invalid(fldPath, newResourceQuota.Spec.Scopes, fieldImmutableErrorMsg)) + } + + return allErrs +} + +// ValidateResourceQuotaStatusUpdate tests to see if the status update is legal for an end user to make. +func ValidateResourceQuotaStatusUpdate(newResourceQuota, oldResourceQuota *core.ResourceQuota) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newResourceQuota.ObjectMeta, &oldResourceQuota.ObjectMeta, field.NewPath("metadata")) + if len(newResourceQuota.ResourceVersion) == 0 { + allErrs = append(allErrs, field.Required(field.NewPath("resourceVersion"), "")) + } + fldPath := field.NewPath("status", "hard") + for k, v := range newResourceQuota.Status.Hard { + resPath := fldPath.Key(string(k)) + allErrs = append(allErrs, ValidateResourceQuotaResourceName(string(k), resPath)...) + allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...) + } + fldPath = field.NewPath("status", "used") + for k, v := range newResourceQuota.Status.Used { + resPath := fldPath.Key(string(k)) + allErrs = append(allErrs, ValidateResourceQuotaResourceName(string(k), resPath)...) + allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...) + } + return allErrs +} + +// ValidateNamespace tests if required fields are set. +func ValidateNamespace(namespace *core.Namespace) field.ErrorList { + allErrs := ValidateObjectMeta(&namespace.ObjectMeta, false, ValidateNamespaceName, field.NewPath("metadata")) + for i := range namespace.Spec.Finalizers { + allErrs = append(allErrs, validateFinalizerName(string(namespace.Spec.Finalizers[i]), field.NewPath("spec", "finalizers"))...) + } + return allErrs +} + +// Validate finalizer names +func validateFinalizerName(stringValue string, fldPath *field.Path) field.ErrorList { + allErrs := apimachineryvalidation.ValidateFinalizerName(stringValue, fldPath) + allErrs = append(allErrs, validateKubeFinalizerName(stringValue, fldPath)...) + return allErrs +} + +// validateKubeFinalizerName checks for "standard" names of legacy finalizer +func validateKubeFinalizerName(stringValue string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(strings.Split(stringValue, "/")) == 1 { + if !helper.IsStandardFinalizerName(stringValue) { + return append(allErrs, field.Invalid(fldPath, stringValue, "name is neither a standard finalizer name nor is it fully qualified")) + } + } + + return allErrs +} + +// ValidateNamespaceUpdate tests to make sure a namespace update can be applied. +func ValidateNamespaceUpdate(newNamespace *core.Namespace, oldNamespace *core.Namespace) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newNamespace.ObjectMeta, &oldNamespace.ObjectMeta, field.NewPath("metadata")) + return allErrs +} + +// ValidateNamespaceStatusUpdate tests to see if the update is legal for an end user to make. +func ValidateNamespaceStatusUpdate(newNamespace, oldNamespace *core.Namespace) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newNamespace.ObjectMeta, &oldNamespace.ObjectMeta, field.NewPath("metadata")) + if newNamespace.DeletionTimestamp.IsZero() { + if newNamespace.Status.Phase != core.NamespaceActive { + allErrs = append(allErrs, field.Invalid(field.NewPath("status", "Phase"), newNamespace.Status.Phase, "may only be 'Active' if `deletionTimestamp` is empty")) + } + } else { + if newNamespace.Status.Phase != core.NamespaceTerminating { + allErrs = append(allErrs, field.Invalid(field.NewPath("status", "Phase"), newNamespace.Status.Phase, "may only be 'Terminating' if `deletionTimestamp` is not empty")) + } + } + return allErrs +} + +// ValidateNamespaceFinalizeUpdate tests to see if the update is legal for an end user to make. +func ValidateNamespaceFinalizeUpdate(newNamespace, oldNamespace *core.Namespace) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newNamespace.ObjectMeta, &oldNamespace.ObjectMeta, field.NewPath("metadata")) + + fldPath := field.NewPath("spec", "finalizers") + for i := range newNamespace.Spec.Finalizers { + idxPath := fldPath.Index(i) + allErrs = append(allErrs, validateFinalizerName(string(newNamespace.Spec.Finalizers[i]), idxPath)...) + } + return allErrs +} + +// ValidateEndpoints validates Endpoints on create and update. +func ValidateEndpoints(endpoints *core.Endpoints) field.ErrorList { + allErrs := ValidateObjectMeta(&endpoints.ObjectMeta, true, ValidateEndpointsName, field.NewPath("metadata")) + allErrs = append(allErrs, ValidateEndpointsSpecificAnnotations(endpoints.Annotations, field.NewPath("annotations"))...) + allErrs = append(allErrs, validateEndpointSubsets(endpoints.Subsets, field.NewPath("subsets"))...) + return allErrs +} + +// ValidateEndpointsCreate validates Endpoints on create. +func ValidateEndpointsCreate(endpoints *core.Endpoints) field.ErrorList { + return ValidateEndpoints(endpoints) +} + +// ValidateEndpointsUpdate validates Endpoints on update. NodeName changes are +// allowed during update to accommodate the case where nodeIP or PodCIDR is +// reused. An existing endpoint ip will have a different nodeName if this +// happens. +func ValidateEndpointsUpdate(newEndpoints, oldEndpoints *core.Endpoints) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newEndpoints.ObjectMeta, &oldEndpoints.ObjectMeta, field.NewPath("metadata")) + allErrs = append(allErrs, ValidateEndpoints(newEndpoints)...) + return allErrs +} + +func validateEndpointSubsets(subsets []core.EndpointSubset, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + for i := range subsets { + ss := &subsets[i] + idxPath := fldPath.Index(i) + + // EndpointSubsets must include endpoint address. For headless service, we allow its endpoints not to have ports. + if len(ss.Addresses) == 0 && len(ss.NotReadyAddresses) == 0 { + // TODO: consider adding a RequiredOneOf() error for this and similar cases + allErrs = append(allErrs, field.Required(idxPath, "must specify `addresses` or `notReadyAddresses`")) + } + for addr := range ss.Addresses { + allErrs = append(allErrs, validateEndpointAddress(&ss.Addresses[addr], idxPath.Child("addresses").Index(addr))...) + } + for addr := range ss.NotReadyAddresses { + allErrs = append(allErrs, validateEndpointAddress(&ss.NotReadyAddresses[addr], idxPath.Child("notReadyAddresses").Index(addr))...) + } + for port := range ss.Ports { + allErrs = append(allErrs, validateEndpointPort(&ss.Ports[port], len(ss.Ports) > 1, idxPath.Child("ports").Index(port))...) + } + } + + return allErrs +} + +func validateEndpointAddress(address *core.EndpointAddress, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + for _, msg := range validation.IsValidIP(address.IP) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("ip"), address.IP, msg)) + } + if len(address.Hostname) > 0 { + allErrs = append(allErrs, ValidateDNS1123Label(address.Hostname, fldPath.Child("hostname"))...) + } + // During endpoint update, verify that NodeName is a DNS subdomain and transition rules allow the update + if address.NodeName != nil { + for _, msg := range ValidateNodeName(*address.NodeName, false) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("nodeName"), *address.NodeName, msg)) + } + } + allErrs = append(allErrs, ValidateNonSpecialIP(address.IP, fldPath.Child("ip"))...) + return allErrs +} + +// ValidateNonSpecialIP is used to validate Endpoints, EndpointSlices, and +// external IPs. Specifically, this disallows unspecified and loopback addresses +// are nonsensical and link-local addresses tend to be used for node-centric +// purposes (e.g. metadata service). +// +// IPv6 references +// - https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml +// - https://www.iana.org/assignments/ipv6-multicast-addresses/ipv6-multicast-addresses.xhtml +func ValidateNonSpecialIP(ipAddress string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + ip := netutils.ParseIPSloppy(ipAddress) + if ip == nil { + allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "must be a valid IP address")) + return allErrs + } + if ip.IsUnspecified() { + allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, fmt.Sprintf("may not be unspecified (%v)", ipAddress))) + } + if ip.IsLoopback() { + allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "may not be in the loopback range (127.0.0.0/8, ::1/128)")) + } + if ip.IsLinkLocalUnicast() { + allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "may not be in the link-local range (169.254.0.0/16, fe80::/10)")) + } + if ip.IsLinkLocalMulticast() { + allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "may not be in the link-local multicast range (224.0.0.0/24, ff02::/10)")) + } + return allErrs +} + +func validateEndpointPort(port *core.EndpointPort, requireName bool, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if requireName && len(port.Name) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("name"), "")) + } else if len(port.Name) != 0 { + allErrs = append(allErrs, ValidateDNS1123Label(port.Name, fldPath.Child("name"))...) + } + for _, msg := range validation.IsValidPortNum(int(port.Port)) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("port"), port.Port, msg)) + } + if len(port.Protocol) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("protocol"), "")) + } else if !supportedPortProtocols.Has(string(port.Protocol)) { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("protocol"), port.Protocol, supportedPortProtocols.List())) + } + if port.AppProtocol != nil { + allErrs = append(allErrs, ValidateQualifiedName(*port.AppProtocol, fldPath.Child("appProtocol"))...) + } + return allErrs +} + +// ValidateSecurityContext ensures the security context contains valid settings +func ValidateSecurityContext(sc *core.SecurityContext, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + // this should only be true for testing since SecurityContext is defaulted by the core + if sc == nil { + return allErrs + } + + if sc.Privileged != nil { + if *sc.Privileged && !capabilities.Get().AllowPrivileged { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("privileged"), "disallowed by cluster policy")) + } + } + + if sc.RunAsUser != nil { + for _, msg := range validation.IsValidUserID(*sc.RunAsUser) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("runAsUser"), *sc.RunAsUser, msg)) + } + } + + if sc.RunAsGroup != nil { + for _, msg := range validation.IsValidGroupID(*sc.RunAsGroup) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("runAsGroup"), *sc.RunAsGroup, msg)) + } + } + + if sc.ProcMount != nil { + if err := ValidateProcMountType(fldPath.Child("procMount"), *sc.ProcMount); err != nil { + allErrs = append(allErrs, err) + } + + } + allErrs = append(allErrs, validateSeccompProfileField(sc.SeccompProfile, fldPath.Child("seccompProfile"))...) + if sc.AllowPrivilegeEscalation != nil && !*sc.AllowPrivilegeEscalation { + if sc.Privileged != nil && *sc.Privileged { + allErrs = append(allErrs, field.Invalid(fldPath, sc, "cannot set `allowPrivilegeEscalation` to false and `privileged` to true")) + } + + if sc.Capabilities != nil { + for _, cap := range sc.Capabilities.Add { + if string(cap) == "CAP_SYS_ADMIN" { + allErrs = append(allErrs, field.Invalid(fldPath, sc, "cannot set `allowPrivilegeEscalation` to false and `capabilities.Add` CAP_SYS_ADMIN")) + } + } + } + } + + allErrs = append(allErrs, validateWindowsSecurityContextOptions(sc.WindowsOptions, fldPath.Child("windowsOptions"))...) + + return allErrs +} + +// maxGMSACredentialSpecLength is the max length, in bytes, for the actual contents +// of a GMSA cred spec. In general, those shouldn't be more than a few hundred bytes, +// so we want to give plenty of room here while still providing an upper bound. +// The runAsUserName field will be used to execute the given container's entrypoint, and +// it can be formatted as "DOMAIN/USER", where the DOMAIN is optional, maxRunAsUserNameDomainLength +// is the max character length for the user's DOMAIN, and maxRunAsUserNameUserLength +// is the max character length for the USER itself. Both the DOMAIN and USER have their +// own restrictions, and more information about them can be found here: +// https://support.microsoft.com/en-us/help/909264/naming-conventions-in-active-directory-for-computers-domains-sites-and +// https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/bb726984(v=technet.10) +const ( + maxGMSACredentialSpecLengthInKiB = 64 + maxGMSACredentialSpecLength = maxGMSACredentialSpecLengthInKiB * 1024 + maxRunAsUserNameDomainLength = 256 + maxRunAsUserNameUserLength = 104 +) + +var ( + // control characters are not permitted in the runAsUserName field. + ctrlRegex = regexp.MustCompile(`[[:cntrl:]]+`) + + // a valid NetBios Domain name cannot start with a dot, has at least 1 character, + // at most 15 characters, and it cannot the characters: \ / : * ? " < > | + validNetBiosRegex = regexp.MustCompile(`^[^\\/:\*\?"<>|\.][^\\/:\*\?"<>|]{0,14}$`) + + // a valid DNS name contains only alphanumeric characters, dots, and dashes. + dnsLabelFormat = `[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?` + dnsSubdomainFormat = fmt.Sprintf(`^%s(?:\.%s)*$`, dnsLabelFormat, dnsLabelFormat) + validWindowsUserDomainDNSRegex = regexp.MustCompile(dnsSubdomainFormat) + + // a username is invalid if it contains the characters: " / \ [ ] : ; | = , + * ? < > @ + // or it contains only dots or spaces. + invalidUserNameCharsRegex = regexp.MustCompile(`["/\\:;|=,\+\*\?<>@\[\]]`) + invalidUserNameDotsSpacesRegex = regexp.MustCompile(`^[\. ]+$`) +) + +func validateWindowsSecurityContextOptions(windowsOptions *core.WindowsSecurityContextOptions, fieldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + if windowsOptions == nil { + return allErrs + } + + if windowsOptions.GMSACredentialSpecName != nil { + // gmsaCredentialSpecName must be the name of a custom resource + for _, msg := range validation.IsDNS1123Subdomain(*windowsOptions.GMSACredentialSpecName) { + allErrs = append(allErrs, field.Invalid(fieldPath.Child("gmsaCredentialSpecName"), windowsOptions.GMSACredentialSpecName, msg)) + } + } + + if windowsOptions.GMSACredentialSpec != nil { + if l := len(*windowsOptions.GMSACredentialSpec); l == 0 { + allErrs = append(allErrs, field.Invalid(fieldPath.Child("gmsaCredentialSpec"), windowsOptions.GMSACredentialSpec, "gmsaCredentialSpec cannot be an empty string")) + } else if l > maxGMSACredentialSpecLength { + errMsg := fmt.Sprintf("gmsaCredentialSpec size must be under %d KiB", maxGMSACredentialSpecLengthInKiB) + allErrs = append(allErrs, field.Invalid(fieldPath.Child("gmsaCredentialSpec"), windowsOptions.GMSACredentialSpec, errMsg)) + } + } + + if windowsOptions.RunAsUserName != nil { + if l := len(*windowsOptions.RunAsUserName); l == 0 { + allErrs = append(allErrs, field.Invalid(fieldPath.Child("runAsUserName"), windowsOptions.RunAsUserName, "runAsUserName cannot be an empty string")) + } else if ctrlRegex.MatchString(*windowsOptions.RunAsUserName) { + errMsg := "runAsUserName cannot contain control characters" + allErrs = append(allErrs, field.Invalid(fieldPath.Child("runAsUserName"), windowsOptions.RunAsUserName, errMsg)) + } else if parts := strings.Split(*windowsOptions.RunAsUserName, "\\"); len(parts) > 2 { + errMsg := "runAsUserName cannot contain more than one backslash" + allErrs = append(allErrs, field.Invalid(fieldPath.Child("runAsUserName"), windowsOptions.RunAsUserName, errMsg)) + } else { + var ( + hasDomain = false + domain = "" + user string + ) + if len(parts) == 1 { + user = parts[0] + } else { + hasDomain = true + domain = parts[0] + user = parts[1] + } + + if len(domain) >= maxRunAsUserNameDomainLength { + errMsg := fmt.Sprintf("runAsUserName's Domain length must be under %d characters", maxRunAsUserNameDomainLength) + allErrs = append(allErrs, field.Invalid(fieldPath.Child("runAsUserName"), windowsOptions.RunAsUserName, errMsg)) + } + + if hasDomain && !(validNetBiosRegex.MatchString(domain) || validWindowsUserDomainDNSRegex.MatchString(domain)) { + errMsg := "runAsUserName's Domain doesn't match the NetBios nor the DNS format" + allErrs = append(allErrs, field.Invalid(fieldPath.Child("runAsUserName"), windowsOptions.RunAsUserName, errMsg)) + } + + if l := len(user); l == 0 { + errMsg := "runAsUserName's User cannot be empty" + allErrs = append(allErrs, field.Invalid(fieldPath.Child("runAsUserName"), windowsOptions.RunAsUserName, errMsg)) + } else if l > maxRunAsUserNameUserLength { + errMsg := fmt.Sprintf("runAsUserName's User length must not be longer than %d characters", maxRunAsUserNameUserLength) + allErrs = append(allErrs, field.Invalid(fieldPath.Child("runAsUserName"), windowsOptions.RunAsUserName, errMsg)) + } + + if invalidUserNameDotsSpacesRegex.MatchString(user) { + errMsg := `runAsUserName's User cannot contain only periods or spaces` + allErrs = append(allErrs, field.Invalid(fieldPath.Child("runAsUserName"), windowsOptions.RunAsUserName, errMsg)) + } + + if invalidUserNameCharsRegex.MatchString(user) { + errMsg := `runAsUserName's User cannot contain the following characters: "/\:;|=,+*?<>@[]` + allErrs = append(allErrs, field.Invalid(fieldPath.Child("runAsUserName"), windowsOptions.RunAsUserName, errMsg)) + } + } + } + + return allErrs +} + +func validateWindowsHostProcessPod(podSpec *core.PodSpec, fieldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + // Keep track of container and hostProcess container count for validate + containerCount := 0 + hostProcessContainerCount := 0 + + var podHostProcess *bool + if podSpec.SecurityContext != nil && podSpec.SecurityContext.WindowsOptions != nil { + podHostProcess = podSpec.SecurityContext.WindowsOptions.HostProcess + } + + hostNetwork := false + if podSpec.SecurityContext != nil { + hostNetwork = podSpec.SecurityContext.HostNetwork + } + + podshelper.VisitContainersWithPath(podSpec, fieldPath, func(c *core.Container, cFieldPath *field.Path) bool { + containerCount++ + + var containerHostProcess *bool = nil + if c.SecurityContext != nil && c.SecurityContext.WindowsOptions != nil { + containerHostProcess = c.SecurityContext.WindowsOptions.HostProcess + } + + if podHostProcess != nil && containerHostProcess != nil && *podHostProcess != *containerHostProcess { + errMsg := fmt.Sprintf("pod hostProcess value must be identical if both are specified, was %v", *podHostProcess) + allErrs = append(allErrs, field.Invalid(cFieldPath.Child("securityContext", "windowsOptions", "hostProcess"), *containerHostProcess, errMsg)) + } + + switch { + case containerHostProcess != nil && *containerHostProcess: + // Container explicitly sets hostProcess=true + hostProcessContainerCount++ + case containerHostProcess == nil && podHostProcess != nil && *podHostProcess: + // Container inherits hostProcess=true from pod settings + hostProcessContainerCount++ + } + + return true + }) + + if hostProcessContainerCount > 0 { + // At present, if a Windows Pods contains any HostProcess containers than all containers must be + // HostProcess containers (explicitly set or inherited). + if hostProcessContainerCount != containerCount { + errMsg := "If pod contains any hostProcess containers then all containers must be HostProcess containers" + allErrs = append(allErrs, field.Invalid(fieldPath, "", errMsg)) + } + + // At present Windows Pods which contain HostProcess containers must also set HostNetwork. + if !hostNetwork { + errMsg := "hostNetwork must be true if pod contains any hostProcess containers" + allErrs = append(allErrs, field.Invalid(fieldPath.Child("hostNetwork"), hostNetwork, errMsg)) + } + + if !capabilities.Get().AllowPrivileged { + errMsg := "hostProcess containers are disallowed by cluster policy" + allErrs = append(allErrs, field.Forbidden(fieldPath, errMsg)) + } + } + + return allErrs +} + +// validateOS validates the OS field within pod spec +func validateOS(podSpec *core.PodSpec, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { + allErrs := field.ErrorList{} + os := podSpec.OS + if os == nil { + return allErrs + } + if len(os.Name) == 0 { + return append(allErrs, field.Required(fldPath.Child("name"), "cannot be empty")) + } + osName := string(os.Name) + if !validOS.Has(osName) { + allErrs = append(allErrs, field.NotSupported(fldPath, osName, validOS.List())) + } + return allErrs +} + +func ValidatePodLogOptions(opts *core.PodLogOptions) field.ErrorList { + allErrs := field.ErrorList{} + if opts.TailLines != nil && *opts.TailLines < 0 { + allErrs = append(allErrs, field.Invalid(field.NewPath("tailLines"), *opts.TailLines, isNegativeErrorMsg)) + } + if opts.LimitBytes != nil && *opts.LimitBytes < 1 { + allErrs = append(allErrs, field.Invalid(field.NewPath("limitBytes"), *opts.LimitBytes, "must be greater than 0")) + } + switch { + case opts.SinceSeconds != nil && opts.SinceTime != nil: + allErrs = append(allErrs, field.Forbidden(field.NewPath(""), "at most one of `sinceTime` or `sinceSeconds` may be specified")) + case opts.SinceSeconds != nil: + if *opts.SinceSeconds < 1 { + allErrs = append(allErrs, field.Invalid(field.NewPath("sinceSeconds"), *opts.SinceSeconds, "must be greater than 0")) + } + } + return allErrs +} + +// ValidateLoadBalancerStatus validates required fields on a LoadBalancerStatus +func ValidateLoadBalancerStatus(status *core.LoadBalancerStatus, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + for i, ingress := range status.Ingress { + idxPath := fldPath.Child("ingress").Index(i) + if len(ingress.IP) > 0 { + if isIP := (netutils.ParseIPSloppy(ingress.IP) != nil); !isIP { + allErrs = append(allErrs, field.Invalid(idxPath.Child("ip"), ingress.IP, "must be a valid IP address")) + } + } + if len(ingress.Hostname) > 0 { + for _, msg := range validation.IsDNS1123Subdomain(ingress.Hostname) { + allErrs = append(allErrs, field.Invalid(idxPath.Child("hostname"), ingress.Hostname, msg)) + } + if isIP := (netutils.ParseIPSloppy(ingress.Hostname) != nil); isIP { + allErrs = append(allErrs, field.Invalid(idxPath.Child("hostname"), ingress.Hostname, "must be a DNS name, not an IP address")) + } + } + } + return allErrs +} + +// validateVolumeNodeAffinity tests that the PersistentVolume.NodeAffinity has valid data +// returns: +// - true if volumeNodeAffinity is set +// - errorList if there are validation errors +func validateVolumeNodeAffinity(nodeAffinity *core.VolumeNodeAffinity, fldPath *field.Path) (bool, field.ErrorList) { + allErrs := field.ErrorList{} + + if nodeAffinity == nil { + return false, allErrs + } + + if nodeAffinity.Required != nil { + allErrs = append(allErrs, ValidateNodeSelector(nodeAffinity.Required, fldPath.Child("required"))...) + } else { + allErrs = append(allErrs, field.Required(fldPath.Child("required"), "must specify required node constraints")) + } + + return true, allErrs +} + +// ValidateCIDR validates whether a CIDR matches the conventions expected by net.ParseCIDR +func ValidateCIDR(cidr string) (*net.IPNet, error) { + _, net, err := netutils.ParseCIDRSloppy(cidr) + if err != nil { + return nil, err + } + return net, nil +} + +func IsDecremented(update, old *int32) bool { + if update == nil && old != nil { + return true + } + if update == nil || old == nil { + return false + } + return *update < *old +} + +// ValidateProcMountType tests that the argument is a valid ProcMountType. +func ValidateProcMountType(fldPath *field.Path, procMountType core.ProcMountType) *field.Error { + switch procMountType { + case core.DefaultProcMount, core.UnmaskedProcMount: + return nil + default: + return field.NotSupported(fldPath, procMountType, []string{string(core.DefaultProcMount), string(core.UnmaskedProcMount)}) + } +} + +var ( + supportedScheduleActions = sets.NewString(string(core.DoNotSchedule), string(core.ScheduleAnyway)) +) + +// validateTopologySpreadConstraints validates given TopologySpreadConstraints. +func validateTopologySpreadConstraints(constraints []core.TopologySpreadConstraint, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + for i, constraint := range constraints { + subFldPath := fldPath.Index(i) + if err := ValidateMaxSkew(subFldPath.Child("maxSkew"), constraint.MaxSkew); err != nil { + allErrs = append(allErrs, err) + } + if err := ValidateTopologyKey(subFldPath.Child("topologyKey"), constraint.TopologyKey); err != nil { + allErrs = append(allErrs, err) + } + if err := ValidateWhenUnsatisfiable(subFldPath.Child("whenUnsatisfiable"), constraint.WhenUnsatisfiable); err != nil { + allErrs = append(allErrs, err) + } + // tuple {topologyKey, whenUnsatisfiable} denotes one kind of spread constraint + if err := ValidateSpreadConstraintNotRepeat(subFldPath.Child("{topologyKey, whenUnsatisfiable}"), constraint, constraints[i+1:]); err != nil { + allErrs = append(allErrs, err) + } + allErrs = append(allErrs, validateMinDomains(subFldPath.Child("minDomains"), constraint.MinDomains, constraint.WhenUnsatisfiable)...) + if err := validateNodeInclusionPolicy(subFldPath.Child("nodeAffinityPolicy"), constraint.NodeAffinityPolicy); err != nil { + allErrs = append(allErrs, err) + } + if err := validateNodeInclusionPolicy(subFldPath.Child("nodeTaintsPolicy"), constraint.NodeTaintsPolicy); err != nil { + allErrs = append(allErrs, err) + } + allErrs = append(allErrs, validateMatchLabelKeys(subFldPath.Child("matchLabelKeys"), constraint.MatchLabelKeys, constraint.LabelSelector)...) + } + + return allErrs +} + +// ValidateMaxSkew tests that the argument is a valid MaxSkew. +func ValidateMaxSkew(fldPath *field.Path, maxSkew int32) *field.Error { + if maxSkew <= 0 { + return field.Invalid(fldPath, maxSkew, isNotPositiveErrorMsg) + } + return nil +} + +// validateMinDomains tests that the argument is a valid MinDomains. +func validateMinDomains(fldPath *field.Path, minDomains *int32, action core.UnsatisfiableConstraintAction) field.ErrorList { + if minDomains == nil { + return nil + } + var allErrs field.ErrorList + if *minDomains <= 0 { + allErrs = append(allErrs, field.Invalid(fldPath, minDomains, isNotPositiveErrorMsg)) + } + // When MinDomains is non-nil, whenUnsatisfiable must be DoNotSchedule. + if action != core.DoNotSchedule { + allErrs = append(allErrs, field.Invalid(fldPath, minDomains, fmt.Sprintf("can only use minDomains if whenUnsatisfiable=%s, not %s", string(core.DoNotSchedule), string(action)))) + } + return allErrs +} + +// ValidateTopologyKey tests that the argument is a valid TopologyKey. +func ValidateTopologyKey(fldPath *field.Path, topologyKey string) *field.Error { + if len(topologyKey) == 0 { + return field.Required(fldPath, "can not be empty") + } + return nil +} + +// ValidateWhenUnsatisfiable tests that the argument is a valid UnsatisfiableConstraintAction. +func ValidateWhenUnsatisfiable(fldPath *field.Path, action core.UnsatisfiableConstraintAction) *field.Error { + if !supportedScheduleActions.Has(string(action)) { + return field.NotSupported(fldPath, action, supportedScheduleActions.List()) + } + return nil +} + +// ValidateSpreadConstraintNotRepeat tests that if `constraint` duplicates with `existingConstraintPairs` +// on TopologyKey and WhenUnsatisfiable fields. +func ValidateSpreadConstraintNotRepeat(fldPath *field.Path, constraint core.TopologySpreadConstraint, restingConstraints []core.TopologySpreadConstraint) *field.Error { + for _, restingConstraint := range restingConstraints { + if constraint.TopologyKey == restingConstraint.TopologyKey && + constraint.WhenUnsatisfiable == restingConstraint.WhenUnsatisfiable { + return field.Duplicate(fldPath, fmt.Sprintf("{%v, %v}", constraint.TopologyKey, constraint.WhenUnsatisfiable)) + } + } + return nil +} + +var ( + supportedPodTopologySpreadNodePolicies = sets.NewString(string(core.NodeInclusionPolicyIgnore), string(core.NodeInclusionPolicyHonor)) +) + +// validateNodeAffinityPolicy tests that the argument is a valid NodeInclusionPolicy. +func validateNodeInclusionPolicy(fldPath *field.Path, policy *core.NodeInclusionPolicy) *field.Error { + if policy == nil { + return nil + } + + if !supportedPodTopologySpreadNodePolicies.Has(string(*policy)) { + return field.NotSupported(fldPath, policy, supportedPodTopologySpreadNodePolicies.List()) + } + return nil +} + +// validateMatchLabelKeys tests that the elements are a valid label name and are not already included in labelSelector. +func validateMatchLabelKeys(fldPath *field.Path, matchLabelKeys []string, labelSelector *metav1.LabelSelector) field.ErrorList { + if len(matchLabelKeys) == 0 { + return nil + } + + labelSelectorKeys := sets.String{} + if labelSelector != nil { + for key := range labelSelector.MatchLabels { + labelSelectorKeys.Insert(key) + } + for _, matchExpression := range labelSelector.MatchExpressions { + labelSelectorKeys.Insert(matchExpression.Key) + } + } + + allErrs := field.ErrorList{} + for i, key := range matchLabelKeys { + allErrs = append(allErrs, unversionedvalidation.ValidateLabelName(key, fldPath.Index(i))...) + if labelSelectorKeys.Has(key) { + allErrs = append(allErrs, field.Invalid(fldPath.Index(i), key, "exists in both matchLabelKeys and labelSelector")) + } + } + + return allErrs +} + +// ValidateServiceClusterIPsRelatedFields validates .spec.ClusterIPs,, +// .spec.IPFamilies, .spec.ipFamilyPolicy. This is exported because it is used +// during IP init and allocation. +func ValidateServiceClusterIPsRelatedFields(service *core.Service) field.ErrorList { + // ClusterIP, ClusterIPs, IPFamilyPolicy and IPFamilies are validated prior (all must be unset) for ExternalName service + if service.Spec.Type == core.ServiceTypeExternalName { + return field.ErrorList{} + } + + allErrs := field.ErrorList{} + hasInvalidIPs := false + + specPath := field.NewPath("spec") + clusterIPsField := specPath.Child("clusterIPs") + ipFamiliesField := specPath.Child("ipFamilies") + ipFamilyPolicyField := specPath.Child("ipFamilyPolicy") + + // Make sure ClusterIP and ClusterIPs are synced. For most cases users can + // just manage one or the other and we'll handle the rest (see PrepareFor* + // in strategy). + if len(service.Spec.ClusterIP) != 0 { + // If ClusterIP is set, ClusterIPs[0] must match. + if len(service.Spec.ClusterIPs) == 0 { + allErrs = append(allErrs, field.Required(clusterIPsField, "")) + } else if service.Spec.ClusterIPs[0] != service.Spec.ClusterIP { + allErrs = append(allErrs, field.Invalid(clusterIPsField, service.Spec.ClusterIPs, "first value must match `clusterIP`")) + } + } else { // ClusterIP == "" + // If ClusterIP is not set, ClusterIPs must also be unset. + if len(service.Spec.ClusterIPs) != 0 { + allErrs = append(allErrs, field.Invalid(clusterIPsField, service.Spec.ClusterIPs, "must be empty when `clusterIP` is not specified")) + } + } + + // ipfamilies stand alone validation + // must be either IPv4 or IPv6 + seen := sets.String{} + for i, ipFamily := range service.Spec.IPFamilies { + if !supportedServiceIPFamily.Has(string(ipFamily)) { + allErrs = append(allErrs, field.NotSupported(ipFamiliesField.Index(i), ipFamily, supportedServiceIPFamily.List())) + } + // no duplicate check also ensures that ipfamilies is dualstacked, in any order + if seen.Has(string(ipFamily)) { + allErrs = append(allErrs, field.Duplicate(ipFamiliesField.Index(i), ipFamily)) + } + seen.Insert(string(ipFamily)) + } + + // IPFamilyPolicy stand alone validation + // note: nil is ok, defaulted in alloc check registry/core/service/* + if service.Spec.IPFamilyPolicy != nil { + // must have a supported value + if !supportedServiceIPFamilyPolicy.Has(string(*(service.Spec.IPFamilyPolicy))) { + allErrs = append(allErrs, field.NotSupported(ipFamilyPolicyField, service.Spec.IPFamilyPolicy, supportedServiceIPFamilyPolicy.List())) + } + } + + // clusterIPs stand alone validation + // valid ips with None and empty string handling + // duplication check is done as part of DualStackvalidation below + for i, clusterIP := range service.Spec.ClusterIPs { + // valid at first location only. if and only if len(clusterIPs) == 1 + if i == 0 && clusterIP == core.ClusterIPNone { + if len(service.Spec.ClusterIPs) > 1 { + hasInvalidIPs = true + allErrs = append(allErrs, field.Invalid(clusterIPsField, service.Spec.ClusterIPs, "'None' must be the first and only value")) + } + continue + } + + // is it valid ip? + errorMessages := validation.IsValidIP(clusterIP) + hasInvalidIPs = (len(errorMessages) != 0) || hasInvalidIPs + for _, msg := range errorMessages { + allErrs = append(allErrs, field.Invalid(clusterIPsField.Index(i), clusterIP, msg)) + } + } + + // max two + if len(service.Spec.ClusterIPs) > 2 { + allErrs = append(allErrs, field.Invalid(clusterIPsField, service.Spec.ClusterIPs, "may only hold up to 2 values")) + } + + // at this stage if there is an invalid ip or misplaced none/empty string + // it will skew the error messages (bad index || dualstackness of already bad ips). so we + // stop here if there are errors in clusterIPs validation + if hasInvalidIPs { + return allErrs + } + + // must be dual stacked ips if they are more than one ip + if len(service.Spec.ClusterIPs) > 1 /* meaning: it does not have a None or empty string */ { + dualStack, err := netutils.IsDualStackIPStrings(service.Spec.ClusterIPs) + if err != nil { // though we check for that earlier. safe > sorry + allErrs = append(allErrs, field.InternalError(clusterIPsField, fmt.Errorf("failed to check for dual stack with error:%v", err))) + } + + // We only support one from each IP family (i.e. max two IPs in this list). + if !dualStack { + allErrs = append(allErrs, field.Invalid(clusterIPsField, service.Spec.ClusterIPs, "may specify no more than one IP for each IP family")) + } + } + + // match clusterIPs to their families, if they were provided + if !isHeadlessService(service) && len(service.Spec.ClusterIPs) > 0 && len(service.Spec.IPFamilies) > 0 { + for i, ip := range service.Spec.ClusterIPs { + if i > (len(service.Spec.IPFamilies) - 1) { + break // no more families to check + } + + // 4=>6 + if service.Spec.IPFamilies[i] == core.IPv4Protocol && netutils.IsIPv6String(ip) { + allErrs = append(allErrs, field.Invalid(clusterIPsField.Index(i), ip, fmt.Sprintf("expected an IPv4 value as indicated by `ipFamilies[%v]`", i))) + } + // 6=>4 + if service.Spec.IPFamilies[i] == core.IPv6Protocol && !netutils.IsIPv6String(ip) { + allErrs = append(allErrs, field.Invalid(clusterIPsField.Index(i), ip, fmt.Sprintf("expected an IPv6 value as indicated by `ipFamilies[%v]`", i))) + } + } + } + + return allErrs +} + +// specific validation for clusterIPs in cases of user upgrading or downgrading to/from dualstack +func validateUpgradeDowngradeClusterIPs(oldService, service *core.Service) field.ErrorList { + allErrs := make(field.ErrorList, 0) + + // bail out early for ExternalName + if service.Spec.Type == core.ServiceTypeExternalName || oldService.Spec.Type == core.ServiceTypeExternalName { + return allErrs + } + newIsHeadless := isHeadlessService(service) + oldIsHeadless := isHeadlessService(oldService) + + if oldIsHeadless && newIsHeadless { + return allErrs + } + + switch { + // no change in ClusterIP lengths + // compare each + case len(oldService.Spec.ClusterIPs) == len(service.Spec.ClusterIPs): + for i, ip := range oldService.Spec.ClusterIPs { + if ip != service.Spec.ClusterIPs[i] { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "clusterIPs").Index(i), service.Spec.ClusterIPs, "may not change once set")) + } + } + + // something has been released (downgraded) + case len(oldService.Spec.ClusterIPs) > len(service.Spec.ClusterIPs): + // primary ClusterIP has been released + if len(service.Spec.ClusterIPs) == 0 { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "clusterIPs").Index(0), service.Spec.ClusterIPs, "primary clusterIP can not be unset")) + } + + // test if primary clusterIP has changed + if len(oldService.Spec.ClusterIPs) > 0 && + len(service.Spec.ClusterIPs) > 0 && + service.Spec.ClusterIPs[0] != oldService.Spec.ClusterIPs[0] { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "clusterIPs").Index(0), service.Spec.ClusterIPs, "may not change once set")) + } + + // test if secondary ClusterIP has been released. has this service been downgraded correctly? + // user *must* set IPFamilyPolicy == SingleStack + if len(service.Spec.ClusterIPs) == 1 { + if service.Spec.IPFamilyPolicy == nil || *(service.Spec.IPFamilyPolicy) != core.IPFamilyPolicySingleStack { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "ipFamilyPolicy"), service.Spec.IPFamilyPolicy, "must be set to 'SingleStack' when releasing the secondary clusterIP")) + } + } + case len(oldService.Spec.ClusterIPs) < len(service.Spec.ClusterIPs): + // something has been added (upgraded) + // test if primary clusterIP has changed + if len(oldService.Spec.ClusterIPs) > 0 && + service.Spec.ClusterIPs[0] != oldService.Spec.ClusterIPs[0] { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "clusterIPs").Index(0), service.Spec.ClusterIPs, "may not change once set")) + } + // we don't check for Policy == RequireDualStack here since, Validation/Creation func takes care of it + } + return allErrs +} + +// specific validation for ipFamilies in cases of user upgrading or downgrading to/from dualstack +func validateUpgradeDowngradeIPFamilies(oldService, service *core.Service) field.ErrorList { + allErrs := make(field.ErrorList, 0) + // bail out early for ExternalName + if service.Spec.Type == core.ServiceTypeExternalName || oldService.Spec.Type == core.ServiceTypeExternalName { + return allErrs + } + + oldIsHeadless := isHeadlessService(oldService) + newIsHeadless := isHeadlessService(service) + + // if changed to/from headless, then bail out + if newIsHeadless != oldIsHeadless { + return allErrs + } + // headless can change families + if newIsHeadless { + return allErrs + } + + switch { + case len(oldService.Spec.IPFamilies) == len(service.Spec.IPFamilies): + // no change in ClusterIP lengths + // compare each + + for i, ip := range oldService.Spec.IPFamilies { + if ip != service.Spec.IPFamilies[i] { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "ipFamilies").Index(0), service.Spec.IPFamilies, "may not change once set")) + } + } + + case len(oldService.Spec.IPFamilies) > len(service.Spec.IPFamilies): + // something has been released (downgraded) + + // test if primary ipfamily has been released + if len(service.Spec.ClusterIPs) == 0 { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "ipFamilies").Index(0), service.Spec.IPFamilies, "primary ipFamily can not be unset")) + } + + // test if primary ipFamily has changed + if len(service.Spec.IPFamilies) > 0 && + service.Spec.IPFamilies[0] != oldService.Spec.IPFamilies[0] { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "ipFamilies").Index(0), service.Spec.ClusterIPs, "may not change once set")) + } + + // test if secondary IPFamily has been released. has this service been downgraded correctly? + // user *must* set IPFamilyPolicy == SingleStack + if len(service.Spec.IPFamilies) == 1 { + if service.Spec.IPFamilyPolicy == nil || *(service.Spec.IPFamilyPolicy) != core.IPFamilyPolicySingleStack { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "ipFamilyPolicy"), service.Spec.IPFamilyPolicy, "must be set to 'SingleStack' when releasing the secondary ipFamily")) + } + } + case len(oldService.Spec.IPFamilies) < len(service.Spec.IPFamilies): + // something has been added (upgraded) + + // test if primary ipFamily has changed + if len(oldService.Spec.IPFamilies) > 0 && + len(service.Spec.IPFamilies) > 0 && + service.Spec.IPFamilies[0] != oldService.Spec.IPFamilies[0] { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "ipFamilies").Index(0), service.Spec.ClusterIPs, "may not change once set")) + } + // we don't check for Policy == RequireDualStack here since, Validation/Creation func takes care of it + } + return allErrs +} + +func isHeadlessService(service *core.Service) bool { + return service != nil && + len(service.Spec.ClusterIPs) == 1 && + service.Spec.ClusterIPs[0] == core.ClusterIPNone +} + +// validateLoadBalancerClassField validation for loadBalancerClass +func validateLoadBalancerClassField(oldService, service *core.Service) field.ErrorList { + allErrs := make(field.ErrorList, 0) + if oldService != nil { + // validate update op + if isTypeLoadBalancer(oldService) && isTypeLoadBalancer(service) { + // old and new are both LoadBalancer + if !sameLoadBalancerClass(oldService, service) { + // can't change loadBalancerClass + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "loadBalancerClass"), service.Spec.LoadBalancerClass, "may not change once set")) + } + } + } + + if isTypeLoadBalancer(service) { + // check LoadBalancerClass format + if service.Spec.LoadBalancerClass != nil { + allErrs = append(allErrs, ValidateQualifiedName(*service.Spec.LoadBalancerClass, field.NewPath("spec", "loadBalancerClass"))...) + } + } else { + // check if LoadBalancerClass set for non LoadBalancer type of service + if service.Spec.LoadBalancerClass != nil { + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "loadBalancerClass"), "may only be used when `type` is 'LoadBalancer'")) + } + } + return allErrs +} + +// isTypeLoadBalancer tests service type is loadBalancer or not +func isTypeLoadBalancer(service *core.Service) bool { + return service.Spec.Type == core.ServiceTypeLoadBalancer +} + +// sameLoadBalancerClass check two services have the same loadBalancerClass or not +func sameLoadBalancerClass(oldService, service *core.Service) bool { + if oldService.Spec.LoadBalancerClass == nil && service.Spec.LoadBalancerClass == nil { + return true + } + if oldService.Spec.LoadBalancerClass == nil || service.Spec.LoadBalancerClass == nil { + return false + } + return *oldService.Spec.LoadBalancerClass == *service.Spec.LoadBalancerClass +} + +func ValidatePodAffinityTermSelector(podAffinityTerm core.PodAffinityTerm, allowInvalidLabelValueInSelector bool, fldPath *field.Path) field.ErrorList { + var allErrs field.ErrorList + labelSelectorValidationOptions := unversionedvalidation.LabelSelectorValidationOptions{AllowInvalidLabelValueInSelector: allowInvalidLabelValueInSelector} + allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(podAffinityTerm.LabelSelector, labelSelectorValidationOptions, fldPath.Child("labelSelector"))...) + allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(podAffinityTerm.NamespaceSelector, labelSelectorValidationOptions, fldPath.Child("namespaceSelector"))...) + return allErrs +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/core/zz_generated.deepcopy.go b/vendor/k8s.io/kubernetes/pkg/apis/core/zz_generated.deepcopy.go new file mode 100644 index 000000000..857843371 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/core/zz_generated.deepcopy.go @@ -0,0 +1,6153 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package core + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + types "k8s.io/apimachinery/pkg/types" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AWSElasticBlockStoreVolumeSource) DeepCopyInto(out *AWSElasticBlockStoreVolumeSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSElasticBlockStoreVolumeSource. +func (in *AWSElasticBlockStoreVolumeSource) DeepCopy() *AWSElasticBlockStoreVolumeSource { + if in == nil { + return nil + } + out := new(AWSElasticBlockStoreVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Affinity) DeepCopyInto(out *Affinity) { + *out = *in + if in.NodeAffinity != nil { + in, out := &in.NodeAffinity, &out.NodeAffinity + *out = new(NodeAffinity) + (*in).DeepCopyInto(*out) + } + if in.PodAffinity != nil { + in, out := &in.PodAffinity, &out.PodAffinity + *out = new(PodAffinity) + (*in).DeepCopyInto(*out) + } + if in.PodAntiAffinity != nil { + in, out := &in.PodAntiAffinity, &out.PodAntiAffinity + *out = new(PodAntiAffinity) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Affinity. +func (in *Affinity) DeepCopy() *Affinity { + if in == nil { + return nil + } + out := new(Affinity) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AttachedVolume) DeepCopyInto(out *AttachedVolume) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AttachedVolume. +func (in *AttachedVolume) DeepCopy() *AttachedVolume { + if in == nil { + return nil + } + out := new(AttachedVolume) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AvoidPods) DeepCopyInto(out *AvoidPods) { + *out = *in + if in.PreferAvoidPods != nil { + in, out := &in.PreferAvoidPods, &out.PreferAvoidPods + *out = make([]PreferAvoidPodsEntry, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AvoidPods. +func (in *AvoidPods) DeepCopy() *AvoidPods { + if in == nil { + return nil + } + out := new(AvoidPods) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureDiskVolumeSource) DeepCopyInto(out *AzureDiskVolumeSource) { + *out = *in + if in.CachingMode != nil { + in, out := &in.CachingMode, &out.CachingMode + *out = new(AzureDataDiskCachingMode) + **out = **in + } + if in.FSType != nil { + in, out := &in.FSType, &out.FSType + *out = new(string) + **out = **in + } + if in.ReadOnly != nil { + in, out := &in.ReadOnly, &out.ReadOnly + *out = new(bool) + **out = **in + } + if in.Kind != nil { + in, out := &in.Kind, &out.Kind + *out = new(AzureDataDiskKind) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureDiskVolumeSource. +func (in *AzureDiskVolumeSource) DeepCopy() *AzureDiskVolumeSource { + if in == nil { + return nil + } + out := new(AzureDiskVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureFilePersistentVolumeSource) DeepCopyInto(out *AzureFilePersistentVolumeSource) { + *out = *in + if in.SecretNamespace != nil { + in, out := &in.SecretNamespace, &out.SecretNamespace + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureFilePersistentVolumeSource. +func (in *AzureFilePersistentVolumeSource) DeepCopy() *AzureFilePersistentVolumeSource { + if in == nil { + return nil + } + out := new(AzureFilePersistentVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureFileVolumeSource) DeepCopyInto(out *AzureFileVolumeSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureFileVolumeSource. +func (in *AzureFileVolumeSource) DeepCopy() *AzureFileVolumeSource { + if in == nil { + return nil + } + out := new(AzureFileVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Binding) DeepCopyInto(out *Binding) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Target = in.Target + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Binding. +func (in *Binding) DeepCopy() *Binding { + if in == nil { + return nil + } + out := new(Binding) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Binding) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CSIPersistentVolumeSource) DeepCopyInto(out *CSIPersistentVolumeSource) { + *out = *in + if in.VolumeAttributes != nil { + in, out := &in.VolumeAttributes, &out.VolumeAttributes + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.ControllerPublishSecretRef != nil { + in, out := &in.ControllerPublishSecretRef, &out.ControllerPublishSecretRef + *out = new(SecretReference) + **out = **in + } + if in.NodeStageSecretRef != nil { + in, out := &in.NodeStageSecretRef, &out.NodeStageSecretRef + *out = new(SecretReference) + **out = **in + } + if in.NodePublishSecretRef != nil { + in, out := &in.NodePublishSecretRef, &out.NodePublishSecretRef + *out = new(SecretReference) + **out = **in + } + if in.ControllerExpandSecretRef != nil { + in, out := &in.ControllerExpandSecretRef, &out.ControllerExpandSecretRef + *out = new(SecretReference) + **out = **in + } + if in.NodeExpandSecretRef != nil { + in, out := &in.NodeExpandSecretRef, &out.NodeExpandSecretRef + *out = new(SecretReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIPersistentVolumeSource. +func (in *CSIPersistentVolumeSource) DeepCopy() *CSIPersistentVolumeSource { + if in == nil { + return nil + } + out := new(CSIPersistentVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CSIVolumeSource) DeepCopyInto(out *CSIVolumeSource) { + *out = *in + if in.ReadOnly != nil { + in, out := &in.ReadOnly, &out.ReadOnly + *out = new(bool) + **out = **in + } + if in.FSType != nil { + in, out := &in.FSType, &out.FSType + *out = new(string) + **out = **in + } + if in.VolumeAttributes != nil { + in, out := &in.VolumeAttributes, &out.VolumeAttributes + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.NodePublishSecretRef != nil { + in, out := &in.NodePublishSecretRef, &out.NodePublishSecretRef + *out = new(LocalObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIVolumeSource. +func (in *CSIVolumeSource) DeepCopy() *CSIVolumeSource { + if in == nil { + return nil + } + out := new(CSIVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Capabilities) DeepCopyInto(out *Capabilities) { + *out = *in + if in.Add != nil { + in, out := &in.Add, &out.Add + *out = make([]Capability, len(*in)) + copy(*out, *in) + } + if in.Drop != nil { + in, out := &in.Drop, &out.Drop + *out = make([]Capability, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Capabilities. +func (in *Capabilities) DeepCopy() *Capabilities { + if in == nil { + return nil + } + out := new(Capabilities) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CephFSPersistentVolumeSource) DeepCopyInto(out *CephFSPersistentVolumeSource) { + *out = *in + if in.Monitors != nil { + in, out := &in.Monitors, &out.Monitors + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(SecretReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CephFSPersistentVolumeSource. +func (in *CephFSPersistentVolumeSource) DeepCopy() *CephFSPersistentVolumeSource { + if in == nil { + return nil + } + out := new(CephFSPersistentVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CephFSVolumeSource) DeepCopyInto(out *CephFSVolumeSource) { + *out = *in + if in.Monitors != nil { + in, out := &in.Monitors, &out.Monitors + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(LocalObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CephFSVolumeSource. +func (in *CephFSVolumeSource) DeepCopy() *CephFSVolumeSource { + if in == nil { + return nil + } + out := new(CephFSVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CinderPersistentVolumeSource) DeepCopyInto(out *CinderPersistentVolumeSource) { + *out = *in + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(SecretReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CinderPersistentVolumeSource. +func (in *CinderPersistentVolumeSource) DeepCopy() *CinderPersistentVolumeSource { + if in == nil { + return nil + } + out := new(CinderPersistentVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CinderVolumeSource) DeepCopyInto(out *CinderVolumeSource) { + *out = *in + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(LocalObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CinderVolumeSource. +func (in *CinderVolumeSource) DeepCopy() *CinderVolumeSource { + if in == nil { + return nil + } + out := new(CinderVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClaimSource) DeepCopyInto(out *ClaimSource) { + *out = *in + if in.ResourceClaimName != nil { + in, out := &in.ResourceClaimName, &out.ResourceClaimName + *out = new(string) + **out = **in + } + if in.ResourceClaimTemplateName != nil { + in, out := &in.ResourceClaimTemplateName, &out.ResourceClaimTemplateName + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClaimSource. +func (in *ClaimSource) DeepCopy() *ClaimSource { + if in == nil { + return nil + } + out := new(ClaimSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClientIPConfig) DeepCopyInto(out *ClientIPConfig) { + *out = *in + if in.TimeoutSeconds != nil { + in, out := &in.TimeoutSeconds, &out.TimeoutSeconds + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientIPConfig. +func (in *ClientIPConfig) DeepCopy() *ClientIPConfig { + if in == nil { + return nil + } + out := new(ClientIPConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ComponentCondition) DeepCopyInto(out *ComponentCondition) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComponentCondition. +func (in *ComponentCondition) DeepCopy() *ComponentCondition { + if in == nil { + return nil + } + out := new(ComponentCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ComponentStatus) DeepCopyInto(out *ComponentStatus) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]ComponentCondition, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComponentStatus. +func (in *ComponentStatus) DeepCopy() *ComponentStatus { + if in == nil { + return nil + } + out := new(ComponentStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ComponentStatus) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ComponentStatusList) DeepCopyInto(out *ComponentStatusList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ComponentStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComponentStatusList. +func (in *ComponentStatusList) DeepCopy() *ComponentStatusList { + if in == nil { + return nil + } + out := new(ComponentStatusList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ComponentStatusList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigMap) DeepCopyInto(out *ConfigMap) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.Immutable != nil { + in, out := &in.Immutable, &out.Immutable + *out = new(bool) + **out = **in + } + if in.Data != nil { + in, out := &in.Data, &out.Data + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.BinaryData != nil { + in, out := &in.BinaryData, &out.BinaryData + *out = make(map[string][]byte, len(*in)) + for key, val := range *in { + var outVal []byte + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = make([]byte, len(*in)) + copy(*out, *in) + } + (*out)[key] = outVal + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigMap. +func (in *ConfigMap) DeepCopy() *ConfigMap { + if in == nil { + return nil + } + out := new(ConfigMap) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ConfigMap) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigMapEnvSource) DeepCopyInto(out *ConfigMapEnvSource) { + *out = *in + out.LocalObjectReference = in.LocalObjectReference + if in.Optional != nil { + in, out := &in.Optional, &out.Optional + *out = new(bool) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigMapEnvSource. +func (in *ConfigMapEnvSource) DeepCopy() *ConfigMapEnvSource { + if in == nil { + return nil + } + out := new(ConfigMapEnvSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigMapKeySelector) DeepCopyInto(out *ConfigMapKeySelector) { + *out = *in + out.LocalObjectReference = in.LocalObjectReference + if in.Optional != nil { + in, out := &in.Optional, &out.Optional + *out = new(bool) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigMapKeySelector. +func (in *ConfigMapKeySelector) DeepCopy() *ConfigMapKeySelector { + if in == nil { + return nil + } + out := new(ConfigMapKeySelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigMapList) DeepCopyInto(out *ConfigMapList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ConfigMap, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigMapList. +func (in *ConfigMapList) DeepCopy() *ConfigMapList { + if in == nil { + return nil + } + out := new(ConfigMapList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ConfigMapList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigMapNodeConfigSource) DeepCopyInto(out *ConfigMapNodeConfigSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigMapNodeConfigSource. +func (in *ConfigMapNodeConfigSource) DeepCopy() *ConfigMapNodeConfigSource { + if in == nil { + return nil + } + out := new(ConfigMapNodeConfigSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigMapProjection) DeepCopyInto(out *ConfigMapProjection) { + *out = *in + out.LocalObjectReference = in.LocalObjectReference + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]KeyToPath, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Optional != nil { + in, out := &in.Optional, &out.Optional + *out = new(bool) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigMapProjection. +func (in *ConfigMapProjection) DeepCopy() *ConfigMapProjection { + if in == nil { + return nil + } + out := new(ConfigMapProjection) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigMapVolumeSource) DeepCopyInto(out *ConfigMapVolumeSource) { + *out = *in + out.LocalObjectReference = in.LocalObjectReference + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]KeyToPath, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.DefaultMode != nil { + in, out := &in.DefaultMode, &out.DefaultMode + *out = new(int32) + **out = **in + } + if in.Optional != nil { + in, out := &in.Optional, &out.Optional + *out = new(bool) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigMapVolumeSource. +func (in *ConfigMapVolumeSource) DeepCopy() *ConfigMapVolumeSource { + if in == nil { + return nil + } + out := new(ConfigMapVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Container) DeepCopyInto(out *Container) { + *out = *in + if in.Command != nil { + in, out := &in.Command, &out.Command + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Args != nil { + in, out := &in.Args, &out.Args + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Ports != nil { + in, out := &in.Ports, &out.Ports + *out = make([]ContainerPort, len(*in)) + copy(*out, *in) + } + if in.EnvFrom != nil { + in, out := &in.EnvFrom, &out.EnvFrom + *out = make([]EnvFromSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Env != nil { + in, out := &in.Env, &out.Env + *out = make([]EnvVar, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.Resources.DeepCopyInto(&out.Resources) + if in.VolumeMounts != nil { + in, out := &in.VolumeMounts, &out.VolumeMounts + *out = make([]VolumeMount, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.VolumeDevices != nil { + in, out := &in.VolumeDevices, &out.VolumeDevices + *out = make([]VolumeDevice, len(*in)) + copy(*out, *in) + } + if in.LivenessProbe != nil { + in, out := &in.LivenessProbe, &out.LivenessProbe + *out = new(Probe) + (*in).DeepCopyInto(*out) + } + if in.ReadinessProbe != nil { + in, out := &in.ReadinessProbe, &out.ReadinessProbe + *out = new(Probe) + (*in).DeepCopyInto(*out) + } + if in.StartupProbe != nil { + in, out := &in.StartupProbe, &out.StartupProbe + *out = new(Probe) + (*in).DeepCopyInto(*out) + } + if in.Lifecycle != nil { + in, out := &in.Lifecycle, &out.Lifecycle + *out = new(Lifecycle) + (*in).DeepCopyInto(*out) + } + if in.SecurityContext != nil { + in, out := &in.SecurityContext, &out.SecurityContext + *out = new(SecurityContext) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Container. +func (in *Container) DeepCopy() *Container { + if in == nil { + return nil + } + out := new(Container) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerImage) DeepCopyInto(out *ContainerImage) { + *out = *in + if in.Names != nil { + in, out := &in.Names, &out.Names + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerImage. +func (in *ContainerImage) DeepCopy() *ContainerImage { + if in == nil { + return nil + } + out := new(ContainerImage) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerPort) DeepCopyInto(out *ContainerPort) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerPort. +func (in *ContainerPort) DeepCopy() *ContainerPort { + if in == nil { + return nil + } + out := new(ContainerPort) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerState) DeepCopyInto(out *ContainerState) { + *out = *in + if in.Waiting != nil { + in, out := &in.Waiting, &out.Waiting + *out = new(ContainerStateWaiting) + **out = **in + } + if in.Running != nil { + in, out := &in.Running, &out.Running + *out = new(ContainerStateRunning) + (*in).DeepCopyInto(*out) + } + if in.Terminated != nil { + in, out := &in.Terminated, &out.Terminated + *out = new(ContainerStateTerminated) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerState. +func (in *ContainerState) DeepCopy() *ContainerState { + if in == nil { + return nil + } + out := new(ContainerState) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerStateRunning) DeepCopyInto(out *ContainerStateRunning) { + *out = *in + in.StartedAt.DeepCopyInto(&out.StartedAt) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerStateRunning. +func (in *ContainerStateRunning) DeepCopy() *ContainerStateRunning { + if in == nil { + return nil + } + out := new(ContainerStateRunning) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerStateTerminated) DeepCopyInto(out *ContainerStateTerminated) { + *out = *in + in.StartedAt.DeepCopyInto(&out.StartedAt) + in.FinishedAt.DeepCopyInto(&out.FinishedAt) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerStateTerminated. +func (in *ContainerStateTerminated) DeepCopy() *ContainerStateTerminated { + if in == nil { + return nil + } + out := new(ContainerStateTerminated) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerStateWaiting) DeepCopyInto(out *ContainerStateWaiting) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerStateWaiting. +func (in *ContainerStateWaiting) DeepCopy() *ContainerStateWaiting { + if in == nil { + return nil + } + out := new(ContainerStateWaiting) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerStatus) DeepCopyInto(out *ContainerStatus) { + *out = *in + in.State.DeepCopyInto(&out.State) + in.LastTerminationState.DeepCopyInto(&out.LastTerminationState) + if in.Started != nil { + in, out := &in.Started, &out.Started + *out = new(bool) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerStatus. +func (in *ContainerStatus) DeepCopy() *ContainerStatus { + if in == nil { + return nil + } + out := new(ContainerStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DaemonEndpoint) DeepCopyInto(out *DaemonEndpoint) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DaemonEndpoint. +func (in *DaemonEndpoint) DeepCopy() *DaemonEndpoint { + if in == nil { + return nil + } + out := new(DaemonEndpoint) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DownwardAPIProjection) DeepCopyInto(out *DownwardAPIProjection) { + *out = *in + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]DownwardAPIVolumeFile, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DownwardAPIProjection. +func (in *DownwardAPIProjection) DeepCopy() *DownwardAPIProjection { + if in == nil { + return nil + } + out := new(DownwardAPIProjection) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DownwardAPIVolumeFile) DeepCopyInto(out *DownwardAPIVolumeFile) { + *out = *in + if in.FieldRef != nil { + in, out := &in.FieldRef, &out.FieldRef + *out = new(ObjectFieldSelector) + **out = **in + } + if in.ResourceFieldRef != nil { + in, out := &in.ResourceFieldRef, &out.ResourceFieldRef + *out = new(ResourceFieldSelector) + (*in).DeepCopyInto(*out) + } + if in.Mode != nil { + in, out := &in.Mode, &out.Mode + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DownwardAPIVolumeFile. +func (in *DownwardAPIVolumeFile) DeepCopy() *DownwardAPIVolumeFile { + if in == nil { + return nil + } + out := new(DownwardAPIVolumeFile) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DownwardAPIVolumeSource) DeepCopyInto(out *DownwardAPIVolumeSource) { + *out = *in + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]DownwardAPIVolumeFile, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.DefaultMode != nil { + in, out := &in.DefaultMode, &out.DefaultMode + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DownwardAPIVolumeSource. +func (in *DownwardAPIVolumeSource) DeepCopy() *DownwardAPIVolumeSource { + if in == nil { + return nil + } + out := new(DownwardAPIVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EmptyDirVolumeSource) DeepCopyInto(out *EmptyDirVolumeSource) { + *out = *in + if in.SizeLimit != nil { + in, out := &in.SizeLimit, &out.SizeLimit + x := (*in).DeepCopy() + *out = &x + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EmptyDirVolumeSource. +func (in *EmptyDirVolumeSource) DeepCopy() *EmptyDirVolumeSource { + if in == nil { + return nil + } + out := new(EmptyDirVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EndpointAddress) DeepCopyInto(out *EndpointAddress) { + *out = *in + if in.NodeName != nil { + in, out := &in.NodeName, &out.NodeName + *out = new(string) + **out = **in + } + if in.TargetRef != nil { + in, out := &in.TargetRef, &out.TargetRef + *out = new(ObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EndpointAddress. +func (in *EndpointAddress) DeepCopy() *EndpointAddress { + if in == nil { + return nil + } + out := new(EndpointAddress) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EndpointPort) DeepCopyInto(out *EndpointPort) { + *out = *in + if in.AppProtocol != nil { + in, out := &in.AppProtocol, &out.AppProtocol + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EndpointPort. +func (in *EndpointPort) DeepCopy() *EndpointPort { + if in == nil { + return nil + } + out := new(EndpointPort) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EndpointSubset) DeepCopyInto(out *EndpointSubset) { + *out = *in + if in.Addresses != nil { + in, out := &in.Addresses, &out.Addresses + *out = make([]EndpointAddress, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.NotReadyAddresses != nil { + in, out := &in.NotReadyAddresses, &out.NotReadyAddresses + *out = make([]EndpointAddress, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Ports != nil { + in, out := &in.Ports, &out.Ports + *out = make([]EndpointPort, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EndpointSubset. +func (in *EndpointSubset) DeepCopy() *EndpointSubset { + if in == nil { + return nil + } + out := new(EndpointSubset) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Endpoints) DeepCopyInto(out *Endpoints) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.Subsets != nil { + in, out := &in.Subsets, &out.Subsets + *out = make([]EndpointSubset, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Endpoints. +func (in *Endpoints) DeepCopy() *Endpoints { + if in == nil { + return nil + } + out := new(Endpoints) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Endpoints) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EndpointsList) DeepCopyInto(out *EndpointsList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Endpoints, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EndpointsList. +func (in *EndpointsList) DeepCopy() *EndpointsList { + if in == nil { + return nil + } + out := new(EndpointsList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *EndpointsList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EnvFromSource) DeepCopyInto(out *EnvFromSource) { + *out = *in + if in.ConfigMapRef != nil { + in, out := &in.ConfigMapRef, &out.ConfigMapRef + *out = new(ConfigMapEnvSource) + (*in).DeepCopyInto(*out) + } + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(SecretEnvSource) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvFromSource. +func (in *EnvFromSource) DeepCopy() *EnvFromSource { + if in == nil { + return nil + } + out := new(EnvFromSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EnvVar) DeepCopyInto(out *EnvVar) { + *out = *in + if in.ValueFrom != nil { + in, out := &in.ValueFrom, &out.ValueFrom + *out = new(EnvVarSource) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvVar. +func (in *EnvVar) DeepCopy() *EnvVar { + if in == nil { + return nil + } + out := new(EnvVar) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EnvVarSource) DeepCopyInto(out *EnvVarSource) { + *out = *in + if in.FieldRef != nil { + in, out := &in.FieldRef, &out.FieldRef + *out = new(ObjectFieldSelector) + **out = **in + } + if in.ResourceFieldRef != nil { + in, out := &in.ResourceFieldRef, &out.ResourceFieldRef + *out = new(ResourceFieldSelector) + (*in).DeepCopyInto(*out) + } + if in.ConfigMapKeyRef != nil { + in, out := &in.ConfigMapKeyRef, &out.ConfigMapKeyRef + *out = new(ConfigMapKeySelector) + (*in).DeepCopyInto(*out) + } + if in.SecretKeyRef != nil { + in, out := &in.SecretKeyRef, &out.SecretKeyRef + *out = new(SecretKeySelector) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvVarSource. +func (in *EnvVarSource) DeepCopy() *EnvVarSource { + if in == nil { + return nil + } + out := new(EnvVarSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EphemeralContainer) DeepCopyInto(out *EphemeralContainer) { + *out = *in + in.EphemeralContainerCommon.DeepCopyInto(&out.EphemeralContainerCommon) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EphemeralContainer. +func (in *EphemeralContainer) DeepCopy() *EphemeralContainer { + if in == nil { + return nil + } + out := new(EphemeralContainer) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EphemeralContainerCommon) DeepCopyInto(out *EphemeralContainerCommon) { + *out = *in + if in.Command != nil { + in, out := &in.Command, &out.Command + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Args != nil { + in, out := &in.Args, &out.Args + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Ports != nil { + in, out := &in.Ports, &out.Ports + *out = make([]ContainerPort, len(*in)) + copy(*out, *in) + } + if in.EnvFrom != nil { + in, out := &in.EnvFrom, &out.EnvFrom + *out = make([]EnvFromSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Env != nil { + in, out := &in.Env, &out.Env + *out = make([]EnvVar, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.Resources.DeepCopyInto(&out.Resources) + if in.VolumeMounts != nil { + in, out := &in.VolumeMounts, &out.VolumeMounts + *out = make([]VolumeMount, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.VolumeDevices != nil { + in, out := &in.VolumeDevices, &out.VolumeDevices + *out = make([]VolumeDevice, len(*in)) + copy(*out, *in) + } + if in.LivenessProbe != nil { + in, out := &in.LivenessProbe, &out.LivenessProbe + *out = new(Probe) + (*in).DeepCopyInto(*out) + } + if in.ReadinessProbe != nil { + in, out := &in.ReadinessProbe, &out.ReadinessProbe + *out = new(Probe) + (*in).DeepCopyInto(*out) + } + if in.StartupProbe != nil { + in, out := &in.StartupProbe, &out.StartupProbe + *out = new(Probe) + (*in).DeepCopyInto(*out) + } + if in.Lifecycle != nil { + in, out := &in.Lifecycle, &out.Lifecycle + *out = new(Lifecycle) + (*in).DeepCopyInto(*out) + } + if in.SecurityContext != nil { + in, out := &in.SecurityContext, &out.SecurityContext + *out = new(SecurityContext) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EphemeralContainerCommon. +func (in *EphemeralContainerCommon) DeepCopy() *EphemeralContainerCommon { + if in == nil { + return nil + } + out := new(EphemeralContainerCommon) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EphemeralVolumeSource) DeepCopyInto(out *EphemeralVolumeSource) { + *out = *in + if in.VolumeClaimTemplate != nil { + in, out := &in.VolumeClaimTemplate, &out.VolumeClaimTemplate + *out = new(PersistentVolumeClaimTemplate) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EphemeralVolumeSource. +func (in *EphemeralVolumeSource) DeepCopy() *EphemeralVolumeSource { + if in == nil { + return nil + } + out := new(EphemeralVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Event) DeepCopyInto(out *Event) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.InvolvedObject = in.InvolvedObject + out.Source = in.Source + in.FirstTimestamp.DeepCopyInto(&out.FirstTimestamp) + in.LastTimestamp.DeepCopyInto(&out.LastTimestamp) + in.EventTime.DeepCopyInto(&out.EventTime) + if in.Series != nil { + in, out := &in.Series, &out.Series + *out = new(EventSeries) + (*in).DeepCopyInto(*out) + } + if in.Related != nil { + in, out := &in.Related, &out.Related + *out = new(ObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Event. +func (in *Event) DeepCopy() *Event { + if in == nil { + return nil + } + out := new(Event) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Event) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EventList) DeepCopyInto(out *EventList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Event, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventList. +func (in *EventList) DeepCopy() *EventList { + if in == nil { + return nil + } + out := new(EventList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *EventList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EventSeries) DeepCopyInto(out *EventSeries) { + *out = *in + in.LastObservedTime.DeepCopyInto(&out.LastObservedTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventSeries. +func (in *EventSeries) DeepCopy() *EventSeries { + if in == nil { + return nil + } + out := new(EventSeries) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EventSource) DeepCopyInto(out *EventSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventSource. +func (in *EventSource) DeepCopy() *EventSource { + if in == nil { + return nil + } + out := new(EventSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExecAction) DeepCopyInto(out *ExecAction) { + *out = *in + if in.Command != nil { + in, out := &in.Command, &out.Command + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecAction. +func (in *ExecAction) DeepCopy() *ExecAction { + if in == nil { + return nil + } + out := new(ExecAction) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FCVolumeSource) DeepCopyInto(out *FCVolumeSource) { + *out = *in + if in.TargetWWNs != nil { + in, out := &in.TargetWWNs, &out.TargetWWNs + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Lun != nil { + in, out := &in.Lun, &out.Lun + *out = new(int32) + **out = **in + } + if in.WWIDs != nil { + in, out := &in.WWIDs, &out.WWIDs + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FCVolumeSource. +func (in *FCVolumeSource) DeepCopy() *FCVolumeSource { + if in == nil { + return nil + } + out := new(FCVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FlexPersistentVolumeSource) DeepCopyInto(out *FlexPersistentVolumeSource) { + *out = *in + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(SecretReference) + **out = **in + } + if in.Options != nil { + in, out := &in.Options, &out.Options + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlexPersistentVolumeSource. +func (in *FlexPersistentVolumeSource) DeepCopy() *FlexPersistentVolumeSource { + if in == nil { + return nil + } + out := new(FlexPersistentVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FlexVolumeSource) DeepCopyInto(out *FlexVolumeSource) { + *out = *in + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(LocalObjectReference) + **out = **in + } + if in.Options != nil { + in, out := &in.Options, &out.Options + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlexVolumeSource. +func (in *FlexVolumeSource) DeepCopy() *FlexVolumeSource { + if in == nil { + return nil + } + out := new(FlexVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FlockerVolumeSource) DeepCopyInto(out *FlockerVolumeSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlockerVolumeSource. +func (in *FlockerVolumeSource) DeepCopy() *FlockerVolumeSource { + if in == nil { + return nil + } + out := new(FlockerVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GCEPersistentDiskVolumeSource) DeepCopyInto(out *GCEPersistentDiskVolumeSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GCEPersistentDiskVolumeSource. +func (in *GCEPersistentDiskVolumeSource) DeepCopy() *GCEPersistentDiskVolumeSource { + if in == nil { + return nil + } + out := new(GCEPersistentDiskVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GRPCAction) DeepCopyInto(out *GRPCAction) { + *out = *in + if in.Service != nil { + in, out := &in.Service, &out.Service + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GRPCAction. +func (in *GRPCAction) DeepCopy() *GRPCAction { + if in == nil { + return nil + } + out := new(GRPCAction) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GitRepoVolumeSource) DeepCopyInto(out *GitRepoVolumeSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitRepoVolumeSource. +func (in *GitRepoVolumeSource) DeepCopy() *GitRepoVolumeSource { + if in == nil { + return nil + } + out := new(GitRepoVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GlusterfsPersistentVolumeSource) DeepCopyInto(out *GlusterfsPersistentVolumeSource) { + *out = *in + if in.EndpointsNamespace != nil { + in, out := &in.EndpointsNamespace, &out.EndpointsNamespace + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GlusterfsPersistentVolumeSource. +func (in *GlusterfsPersistentVolumeSource) DeepCopy() *GlusterfsPersistentVolumeSource { + if in == nil { + return nil + } + out := new(GlusterfsPersistentVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GlusterfsVolumeSource) DeepCopyInto(out *GlusterfsVolumeSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GlusterfsVolumeSource. +func (in *GlusterfsVolumeSource) DeepCopy() *GlusterfsVolumeSource { + if in == nil { + return nil + } + out := new(GlusterfsVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPGetAction) DeepCopyInto(out *HTTPGetAction) { + *out = *in + out.Port = in.Port + if in.HTTPHeaders != nil { + in, out := &in.HTTPHeaders, &out.HTTPHeaders + *out = make([]HTTPHeader, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPGetAction. +func (in *HTTPGetAction) DeepCopy() *HTTPGetAction { + if in == nil { + return nil + } + out := new(HTTPGetAction) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPHeader) DeepCopyInto(out *HTTPHeader) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPHeader. +func (in *HTTPHeader) DeepCopy() *HTTPHeader { + if in == nil { + return nil + } + out := new(HTTPHeader) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HostAlias) DeepCopyInto(out *HostAlias) { + *out = *in + if in.Hostnames != nil { + in, out := &in.Hostnames, &out.Hostnames + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostAlias. +func (in *HostAlias) DeepCopy() *HostAlias { + if in == nil { + return nil + } + out := new(HostAlias) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HostPathVolumeSource) DeepCopyInto(out *HostPathVolumeSource) { + *out = *in + if in.Type != nil { + in, out := &in.Type, &out.Type + *out = new(HostPathType) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostPathVolumeSource. +func (in *HostPathVolumeSource) DeepCopy() *HostPathVolumeSource { + if in == nil { + return nil + } + out := new(HostPathVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ISCSIPersistentVolumeSource) DeepCopyInto(out *ISCSIPersistentVolumeSource) { + *out = *in + if in.Portals != nil { + in, out := &in.Portals, &out.Portals + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(SecretReference) + **out = **in + } + if in.InitiatorName != nil { + in, out := &in.InitiatorName, &out.InitiatorName + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ISCSIPersistentVolumeSource. +func (in *ISCSIPersistentVolumeSource) DeepCopy() *ISCSIPersistentVolumeSource { + if in == nil { + return nil + } + out := new(ISCSIPersistentVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ISCSIVolumeSource) DeepCopyInto(out *ISCSIVolumeSource) { + *out = *in + if in.Portals != nil { + in, out := &in.Portals, &out.Portals + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(LocalObjectReference) + **out = **in + } + if in.InitiatorName != nil { + in, out := &in.InitiatorName, &out.InitiatorName + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ISCSIVolumeSource. +func (in *ISCSIVolumeSource) DeepCopy() *ISCSIVolumeSource { + if in == nil { + return nil + } + out := new(ISCSIVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KeyToPath) DeepCopyInto(out *KeyToPath) { + *out = *in + if in.Mode != nil { + in, out := &in.Mode, &out.Mode + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyToPath. +func (in *KeyToPath) DeepCopy() *KeyToPath { + if in == nil { + return nil + } + out := new(KeyToPath) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Lifecycle) DeepCopyInto(out *Lifecycle) { + *out = *in + if in.PostStart != nil { + in, out := &in.PostStart, &out.PostStart + *out = new(LifecycleHandler) + (*in).DeepCopyInto(*out) + } + if in.PreStop != nil { + in, out := &in.PreStop, &out.PreStop + *out = new(LifecycleHandler) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Lifecycle. +func (in *Lifecycle) DeepCopy() *Lifecycle { + if in == nil { + return nil + } + out := new(Lifecycle) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LifecycleHandler) DeepCopyInto(out *LifecycleHandler) { + *out = *in + if in.Exec != nil { + in, out := &in.Exec, &out.Exec + *out = new(ExecAction) + (*in).DeepCopyInto(*out) + } + if in.HTTPGet != nil { + in, out := &in.HTTPGet, &out.HTTPGet + *out = new(HTTPGetAction) + (*in).DeepCopyInto(*out) + } + if in.TCPSocket != nil { + in, out := &in.TCPSocket, &out.TCPSocket + *out = new(TCPSocketAction) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LifecycleHandler. +func (in *LifecycleHandler) DeepCopy() *LifecycleHandler { + if in == nil { + return nil + } + out := new(LifecycleHandler) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LimitRange) DeepCopyInto(out *LimitRange) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LimitRange. +func (in *LimitRange) DeepCopy() *LimitRange { + if in == nil { + return nil + } + out := new(LimitRange) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *LimitRange) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LimitRangeItem) DeepCopyInto(out *LimitRangeItem) { + *out = *in + if in.Max != nil { + in, out := &in.Max, &out.Max + *out = make(ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + if in.Min != nil { + in, out := &in.Min, &out.Min + *out = make(ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + if in.Default != nil { + in, out := &in.Default, &out.Default + *out = make(ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + if in.DefaultRequest != nil { + in, out := &in.DefaultRequest, &out.DefaultRequest + *out = make(ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + if in.MaxLimitRequestRatio != nil { + in, out := &in.MaxLimitRequestRatio, &out.MaxLimitRequestRatio + *out = make(ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LimitRangeItem. +func (in *LimitRangeItem) DeepCopy() *LimitRangeItem { + if in == nil { + return nil + } + out := new(LimitRangeItem) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LimitRangeList) DeepCopyInto(out *LimitRangeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]LimitRange, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LimitRangeList. +func (in *LimitRangeList) DeepCopy() *LimitRangeList { + if in == nil { + return nil + } + out := new(LimitRangeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *LimitRangeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LimitRangeSpec) DeepCopyInto(out *LimitRangeSpec) { + *out = *in + if in.Limits != nil { + in, out := &in.Limits, &out.Limits + *out = make([]LimitRangeItem, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LimitRangeSpec. +func (in *LimitRangeSpec) DeepCopy() *LimitRangeSpec { + if in == nil { + return nil + } + out := new(LimitRangeSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *List) DeepCopyInto(out *List) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]runtime.Object, len(*in)) + for i := range *in { + if (*in)[i] != nil { + (*out)[i] = (*in)[i].DeepCopyObject() + } + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new List. +func (in *List) DeepCopy() *List { + if in == nil { + return nil + } + out := new(List) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *List) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LoadBalancerIngress) DeepCopyInto(out *LoadBalancerIngress) { + *out = *in + if in.Ports != nil { + in, out := &in.Ports, &out.Ports + *out = make([]PortStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoadBalancerIngress. +func (in *LoadBalancerIngress) DeepCopy() *LoadBalancerIngress { + if in == nil { + return nil + } + out := new(LoadBalancerIngress) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LoadBalancerStatus) DeepCopyInto(out *LoadBalancerStatus) { + *out = *in + if in.Ingress != nil { + in, out := &in.Ingress, &out.Ingress + *out = make([]LoadBalancerIngress, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoadBalancerStatus. +func (in *LoadBalancerStatus) DeepCopy() *LoadBalancerStatus { + if in == nil { + return nil + } + out := new(LoadBalancerStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LocalObjectReference) DeepCopyInto(out *LocalObjectReference) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LocalObjectReference. +func (in *LocalObjectReference) DeepCopy() *LocalObjectReference { + if in == nil { + return nil + } + out := new(LocalObjectReference) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LocalVolumeSource) DeepCopyInto(out *LocalVolumeSource) { + *out = *in + if in.FSType != nil { + in, out := &in.FSType, &out.FSType + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LocalVolumeSource. +func (in *LocalVolumeSource) DeepCopy() *LocalVolumeSource { + if in == nil { + return nil + } + out := new(LocalVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NFSVolumeSource) DeepCopyInto(out *NFSVolumeSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NFSVolumeSource. +func (in *NFSVolumeSource) DeepCopy() *NFSVolumeSource { + if in == nil { + return nil + } + out := new(NFSVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Namespace) DeepCopyInto(out *Namespace) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Namespace. +func (in *Namespace) DeepCopy() *Namespace { + if in == nil { + return nil + } + out := new(Namespace) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Namespace) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NamespaceCondition) DeepCopyInto(out *NamespaceCondition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NamespaceCondition. +func (in *NamespaceCondition) DeepCopy() *NamespaceCondition { + if in == nil { + return nil + } + out := new(NamespaceCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NamespaceList) DeepCopyInto(out *NamespaceList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Namespace, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NamespaceList. +func (in *NamespaceList) DeepCopy() *NamespaceList { + if in == nil { + return nil + } + out := new(NamespaceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NamespaceList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NamespaceSpec) DeepCopyInto(out *NamespaceSpec) { + *out = *in + if in.Finalizers != nil { + in, out := &in.Finalizers, &out.Finalizers + *out = make([]FinalizerName, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NamespaceSpec. +func (in *NamespaceSpec) DeepCopy() *NamespaceSpec { + if in == nil { + return nil + } + out := new(NamespaceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NamespaceStatus) DeepCopyInto(out *NamespaceStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]NamespaceCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NamespaceStatus. +func (in *NamespaceStatus) DeepCopy() *NamespaceStatus { + if in == nil { + return nil + } + out := new(NamespaceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Node) DeepCopyInto(out *Node) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Node. +func (in *Node) DeepCopy() *Node { + if in == nil { + return nil + } + out := new(Node) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Node) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeAddress) DeepCopyInto(out *NodeAddress) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeAddress. +func (in *NodeAddress) DeepCopy() *NodeAddress { + if in == nil { + return nil + } + out := new(NodeAddress) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeAffinity) DeepCopyInto(out *NodeAffinity) { + *out = *in + if in.RequiredDuringSchedulingIgnoredDuringExecution != nil { + in, out := &in.RequiredDuringSchedulingIgnoredDuringExecution, &out.RequiredDuringSchedulingIgnoredDuringExecution + *out = new(NodeSelector) + (*in).DeepCopyInto(*out) + } + if in.PreferredDuringSchedulingIgnoredDuringExecution != nil { + in, out := &in.PreferredDuringSchedulingIgnoredDuringExecution, &out.PreferredDuringSchedulingIgnoredDuringExecution + *out = make([]PreferredSchedulingTerm, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeAffinity. +func (in *NodeAffinity) DeepCopy() *NodeAffinity { + if in == nil { + return nil + } + out := new(NodeAffinity) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeCondition) DeepCopyInto(out *NodeCondition) { + *out = *in + in.LastHeartbeatTime.DeepCopyInto(&out.LastHeartbeatTime) + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeCondition. +func (in *NodeCondition) DeepCopy() *NodeCondition { + if in == nil { + return nil + } + out := new(NodeCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeConfigSource) DeepCopyInto(out *NodeConfigSource) { + *out = *in + if in.ConfigMap != nil { + in, out := &in.ConfigMap, &out.ConfigMap + *out = new(ConfigMapNodeConfigSource) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeConfigSource. +func (in *NodeConfigSource) DeepCopy() *NodeConfigSource { + if in == nil { + return nil + } + out := new(NodeConfigSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeConfigStatus) DeepCopyInto(out *NodeConfigStatus) { + *out = *in + if in.Assigned != nil { + in, out := &in.Assigned, &out.Assigned + *out = new(NodeConfigSource) + (*in).DeepCopyInto(*out) + } + if in.Active != nil { + in, out := &in.Active, &out.Active + *out = new(NodeConfigSource) + (*in).DeepCopyInto(*out) + } + if in.LastKnownGood != nil { + in, out := &in.LastKnownGood, &out.LastKnownGood + *out = new(NodeConfigSource) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeConfigStatus. +func (in *NodeConfigStatus) DeepCopy() *NodeConfigStatus { + if in == nil { + return nil + } + out := new(NodeConfigStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeDaemonEndpoints) DeepCopyInto(out *NodeDaemonEndpoints) { + *out = *in + out.KubeletEndpoint = in.KubeletEndpoint + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeDaemonEndpoints. +func (in *NodeDaemonEndpoints) DeepCopy() *NodeDaemonEndpoints { + if in == nil { + return nil + } + out := new(NodeDaemonEndpoints) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeList) DeepCopyInto(out *NodeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Node, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeList. +func (in *NodeList) DeepCopy() *NodeList { + if in == nil { + return nil + } + out := new(NodeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeProxyOptions) DeepCopyInto(out *NodeProxyOptions) { + *out = *in + out.TypeMeta = in.TypeMeta + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeProxyOptions. +func (in *NodeProxyOptions) DeepCopy() *NodeProxyOptions { + if in == nil { + return nil + } + out := new(NodeProxyOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodeProxyOptions) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeResources) DeepCopyInto(out *NodeResources) { + *out = *in + if in.Capacity != nil { + in, out := &in.Capacity, &out.Capacity + *out = make(ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeResources. +func (in *NodeResources) DeepCopy() *NodeResources { + if in == nil { + return nil + } + out := new(NodeResources) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeSelector) DeepCopyInto(out *NodeSelector) { + *out = *in + if in.NodeSelectorTerms != nil { + in, out := &in.NodeSelectorTerms, &out.NodeSelectorTerms + *out = make([]NodeSelectorTerm, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeSelector. +func (in *NodeSelector) DeepCopy() *NodeSelector { + if in == nil { + return nil + } + out := new(NodeSelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeSelectorRequirement) DeepCopyInto(out *NodeSelectorRequirement) { + *out = *in + if in.Values != nil { + in, out := &in.Values, &out.Values + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeSelectorRequirement. +func (in *NodeSelectorRequirement) DeepCopy() *NodeSelectorRequirement { + if in == nil { + return nil + } + out := new(NodeSelectorRequirement) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeSelectorTerm) DeepCopyInto(out *NodeSelectorTerm) { + *out = *in + if in.MatchExpressions != nil { + in, out := &in.MatchExpressions, &out.MatchExpressions + *out = make([]NodeSelectorRequirement, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.MatchFields != nil { + in, out := &in.MatchFields, &out.MatchFields + *out = make([]NodeSelectorRequirement, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeSelectorTerm. +func (in *NodeSelectorTerm) DeepCopy() *NodeSelectorTerm { + if in == nil { + return nil + } + out := new(NodeSelectorTerm) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeSpec) DeepCopyInto(out *NodeSpec) { + *out = *in + if in.PodCIDRs != nil { + in, out := &in.PodCIDRs, &out.PodCIDRs + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Taints != nil { + in, out := &in.Taints, &out.Taints + *out = make([]Taint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ConfigSource != nil { + in, out := &in.ConfigSource, &out.ConfigSource + *out = new(NodeConfigSource) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeSpec. +func (in *NodeSpec) DeepCopy() *NodeSpec { + if in == nil { + return nil + } + out := new(NodeSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeStatus) DeepCopyInto(out *NodeStatus) { + *out = *in + if in.Capacity != nil { + in, out := &in.Capacity, &out.Capacity + *out = make(ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + if in.Allocatable != nil { + in, out := &in.Allocatable, &out.Allocatable + *out = make(ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]NodeCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Addresses != nil { + in, out := &in.Addresses, &out.Addresses + *out = make([]NodeAddress, len(*in)) + copy(*out, *in) + } + out.DaemonEndpoints = in.DaemonEndpoints + out.NodeInfo = in.NodeInfo + if in.Images != nil { + in, out := &in.Images, &out.Images + *out = make([]ContainerImage, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.VolumesInUse != nil { + in, out := &in.VolumesInUse, &out.VolumesInUse + *out = make([]UniqueVolumeName, len(*in)) + copy(*out, *in) + } + if in.VolumesAttached != nil { + in, out := &in.VolumesAttached, &out.VolumesAttached + *out = make([]AttachedVolume, len(*in)) + copy(*out, *in) + } + if in.Config != nil { + in, out := &in.Config, &out.Config + *out = new(NodeConfigStatus) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeStatus. +func (in *NodeStatus) DeepCopy() *NodeStatus { + if in == nil { + return nil + } + out := new(NodeStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeSystemInfo) DeepCopyInto(out *NodeSystemInfo) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeSystemInfo. +func (in *NodeSystemInfo) DeepCopy() *NodeSystemInfo { + if in == nil { + return nil + } + out := new(NodeSystemInfo) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ObjectFieldSelector) DeepCopyInto(out *ObjectFieldSelector) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectFieldSelector. +func (in *ObjectFieldSelector) DeepCopy() *ObjectFieldSelector { + if in == nil { + return nil + } + out := new(ObjectFieldSelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ObjectReference) DeepCopyInto(out *ObjectReference) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectReference. +func (in *ObjectReference) DeepCopy() *ObjectReference { + if in == nil { + return nil + } + out := new(ObjectReference) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ObjectReference) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PersistentVolume) DeepCopyInto(out *PersistentVolume) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PersistentVolume. +func (in *PersistentVolume) DeepCopy() *PersistentVolume { + if in == nil { + return nil + } + out := new(PersistentVolume) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PersistentVolume) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PersistentVolumeClaim) DeepCopyInto(out *PersistentVolumeClaim) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PersistentVolumeClaim. +func (in *PersistentVolumeClaim) DeepCopy() *PersistentVolumeClaim { + if in == nil { + return nil + } + out := new(PersistentVolumeClaim) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PersistentVolumeClaim) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PersistentVolumeClaimCondition) DeepCopyInto(out *PersistentVolumeClaimCondition) { + *out = *in + in.LastProbeTime.DeepCopyInto(&out.LastProbeTime) + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PersistentVolumeClaimCondition. +func (in *PersistentVolumeClaimCondition) DeepCopy() *PersistentVolumeClaimCondition { + if in == nil { + return nil + } + out := new(PersistentVolumeClaimCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PersistentVolumeClaimList) DeepCopyInto(out *PersistentVolumeClaimList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]PersistentVolumeClaim, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PersistentVolumeClaimList. +func (in *PersistentVolumeClaimList) DeepCopy() *PersistentVolumeClaimList { + if in == nil { + return nil + } + out := new(PersistentVolumeClaimList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PersistentVolumeClaimList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PersistentVolumeClaimSpec) DeepCopyInto(out *PersistentVolumeClaimSpec) { + *out = *in + if in.AccessModes != nil { + in, out := &in.AccessModes, &out.AccessModes + *out = make([]PersistentVolumeAccessMode, len(*in)) + copy(*out, *in) + } + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + in.Resources.DeepCopyInto(&out.Resources) + if in.StorageClassName != nil { + in, out := &in.StorageClassName, &out.StorageClassName + *out = new(string) + **out = **in + } + if in.VolumeMode != nil { + in, out := &in.VolumeMode, &out.VolumeMode + *out = new(PersistentVolumeMode) + **out = **in + } + if in.DataSource != nil { + in, out := &in.DataSource, &out.DataSource + *out = new(TypedLocalObjectReference) + (*in).DeepCopyInto(*out) + } + if in.DataSourceRef != nil { + in, out := &in.DataSourceRef, &out.DataSourceRef + *out = new(TypedObjectReference) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PersistentVolumeClaimSpec. +func (in *PersistentVolumeClaimSpec) DeepCopy() *PersistentVolumeClaimSpec { + if in == nil { + return nil + } + out := new(PersistentVolumeClaimSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PersistentVolumeClaimStatus) DeepCopyInto(out *PersistentVolumeClaimStatus) { + *out = *in + if in.AccessModes != nil { + in, out := &in.AccessModes, &out.AccessModes + *out = make([]PersistentVolumeAccessMode, len(*in)) + copy(*out, *in) + } + if in.Capacity != nil { + in, out := &in.Capacity, &out.Capacity + *out = make(ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]PersistentVolumeClaimCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.AllocatedResources != nil { + in, out := &in.AllocatedResources, &out.AllocatedResources + *out = make(ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + if in.ResizeStatus != nil { + in, out := &in.ResizeStatus, &out.ResizeStatus + *out = new(PersistentVolumeClaimResizeStatus) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PersistentVolumeClaimStatus. +func (in *PersistentVolumeClaimStatus) DeepCopy() *PersistentVolumeClaimStatus { + if in == nil { + return nil + } + out := new(PersistentVolumeClaimStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PersistentVolumeClaimTemplate) DeepCopyInto(out *PersistentVolumeClaimTemplate) { + *out = *in + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PersistentVolumeClaimTemplate. +func (in *PersistentVolumeClaimTemplate) DeepCopy() *PersistentVolumeClaimTemplate { + if in == nil { + return nil + } + out := new(PersistentVolumeClaimTemplate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PersistentVolumeClaimVolumeSource) DeepCopyInto(out *PersistentVolumeClaimVolumeSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PersistentVolumeClaimVolumeSource. +func (in *PersistentVolumeClaimVolumeSource) DeepCopy() *PersistentVolumeClaimVolumeSource { + if in == nil { + return nil + } + out := new(PersistentVolumeClaimVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PersistentVolumeList) DeepCopyInto(out *PersistentVolumeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]PersistentVolume, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PersistentVolumeList. +func (in *PersistentVolumeList) DeepCopy() *PersistentVolumeList { + if in == nil { + return nil + } + out := new(PersistentVolumeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PersistentVolumeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PersistentVolumeSource) DeepCopyInto(out *PersistentVolumeSource) { + *out = *in + if in.GCEPersistentDisk != nil { + in, out := &in.GCEPersistentDisk, &out.GCEPersistentDisk + *out = new(GCEPersistentDiskVolumeSource) + **out = **in + } + if in.AWSElasticBlockStore != nil { + in, out := &in.AWSElasticBlockStore, &out.AWSElasticBlockStore + *out = new(AWSElasticBlockStoreVolumeSource) + **out = **in + } + if in.HostPath != nil { + in, out := &in.HostPath, &out.HostPath + *out = new(HostPathVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.Glusterfs != nil { + in, out := &in.Glusterfs, &out.Glusterfs + *out = new(GlusterfsPersistentVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.NFS != nil { + in, out := &in.NFS, &out.NFS + *out = new(NFSVolumeSource) + **out = **in + } + if in.RBD != nil { + in, out := &in.RBD, &out.RBD + *out = new(RBDPersistentVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.Quobyte != nil { + in, out := &in.Quobyte, &out.Quobyte + *out = new(QuobyteVolumeSource) + **out = **in + } + if in.ISCSI != nil { + in, out := &in.ISCSI, &out.ISCSI + *out = new(ISCSIPersistentVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.FlexVolume != nil { + in, out := &in.FlexVolume, &out.FlexVolume + *out = new(FlexPersistentVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.Cinder != nil { + in, out := &in.Cinder, &out.Cinder + *out = new(CinderPersistentVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.CephFS != nil { + in, out := &in.CephFS, &out.CephFS + *out = new(CephFSPersistentVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.FC != nil { + in, out := &in.FC, &out.FC + *out = new(FCVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.Flocker != nil { + in, out := &in.Flocker, &out.Flocker + *out = new(FlockerVolumeSource) + **out = **in + } + if in.AzureFile != nil { + in, out := &in.AzureFile, &out.AzureFile + *out = new(AzureFilePersistentVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.VsphereVolume != nil { + in, out := &in.VsphereVolume, &out.VsphereVolume + *out = new(VsphereVirtualDiskVolumeSource) + **out = **in + } + if in.AzureDisk != nil { + in, out := &in.AzureDisk, &out.AzureDisk + *out = new(AzureDiskVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.PhotonPersistentDisk != nil { + in, out := &in.PhotonPersistentDisk, &out.PhotonPersistentDisk + *out = new(PhotonPersistentDiskVolumeSource) + **out = **in + } + if in.PortworxVolume != nil { + in, out := &in.PortworxVolume, &out.PortworxVolume + *out = new(PortworxVolumeSource) + **out = **in + } + if in.ScaleIO != nil { + in, out := &in.ScaleIO, &out.ScaleIO + *out = new(ScaleIOPersistentVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.Local != nil { + in, out := &in.Local, &out.Local + *out = new(LocalVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.StorageOS != nil { + in, out := &in.StorageOS, &out.StorageOS + *out = new(StorageOSPersistentVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.CSI != nil { + in, out := &in.CSI, &out.CSI + *out = new(CSIPersistentVolumeSource) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PersistentVolumeSource. +func (in *PersistentVolumeSource) DeepCopy() *PersistentVolumeSource { + if in == nil { + return nil + } + out := new(PersistentVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PersistentVolumeSpec) DeepCopyInto(out *PersistentVolumeSpec) { + *out = *in + if in.Capacity != nil { + in, out := &in.Capacity, &out.Capacity + *out = make(ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + in.PersistentVolumeSource.DeepCopyInto(&out.PersistentVolumeSource) + if in.AccessModes != nil { + in, out := &in.AccessModes, &out.AccessModes + *out = make([]PersistentVolumeAccessMode, len(*in)) + copy(*out, *in) + } + if in.ClaimRef != nil { + in, out := &in.ClaimRef, &out.ClaimRef + *out = new(ObjectReference) + **out = **in + } + if in.MountOptions != nil { + in, out := &in.MountOptions, &out.MountOptions + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.VolumeMode != nil { + in, out := &in.VolumeMode, &out.VolumeMode + *out = new(PersistentVolumeMode) + **out = **in + } + if in.NodeAffinity != nil { + in, out := &in.NodeAffinity, &out.NodeAffinity + *out = new(VolumeNodeAffinity) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PersistentVolumeSpec. +func (in *PersistentVolumeSpec) DeepCopy() *PersistentVolumeSpec { + if in == nil { + return nil + } + out := new(PersistentVolumeSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PersistentVolumeStatus) DeepCopyInto(out *PersistentVolumeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PersistentVolumeStatus. +func (in *PersistentVolumeStatus) DeepCopy() *PersistentVolumeStatus { + if in == nil { + return nil + } + out := new(PersistentVolumeStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PhotonPersistentDiskVolumeSource) DeepCopyInto(out *PhotonPersistentDiskVolumeSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PhotonPersistentDiskVolumeSource. +func (in *PhotonPersistentDiskVolumeSource) DeepCopy() *PhotonPersistentDiskVolumeSource { + if in == nil { + return nil + } + out := new(PhotonPersistentDiskVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Pod) DeepCopyInto(out *Pod) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Pod. +func (in *Pod) DeepCopy() *Pod { + if in == nil { + return nil + } + out := new(Pod) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Pod) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodAffinity) DeepCopyInto(out *PodAffinity) { + *out = *in + if in.RequiredDuringSchedulingIgnoredDuringExecution != nil { + in, out := &in.RequiredDuringSchedulingIgnoredDuringExecution, &out.RequiredDuringSchedulingIgnoredDuringExecution + *out = make([]PodAffinityTerm, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.PreferredDuringSchedulingIgnoredDuringExecution != nil { + in, out := &in.PreferredDuringSchedulingIgnoredDuringExecution, &out.PreferredDuringSchedulingIgnoredDuringExecution + *out = make([]WeightedPodAffinityTerm, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodAffinity. +func (in *PodAffinity) DeepCopy() *PodAffinity { + if in == nil { + return nil + } + out := new(PodAffinity) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodAffinityTerm) DeepCopyInto(out *PodAffinityTerm) { + *out = *in + if in.LabelSelector != nil { + in, out := &in.LabelSelector, &out.LabelSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + if in.Namespaces != nil { + in, out := &in.Namespaces, &out.Namespaces + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.NamespaceSelector != nil { + in, out := &in.NamespaceSelector, &out.NamespaceSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodAffinityTerm. +func (in *PodAffinityTerm) DeepCopy() *PodAffinityTerm { + if in == nil { + return nil + } + out := new(PodAffinityTerm) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodAntiAffinity) DeepCopyInto(out *PodAntiAffinity) { + *out = *in + if in.RequiredDuringSchedulingIgnoredDuringExecution != nil { + in, out := &in.RequiredDuringSchedulingIgnoredDuringExecution, &out.RequiredDuringSchedulingIgnoredDuringExecution + *out = make([]PodAffinityTerm, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.PreferredDuringSchedulingIgnoredDuringExecution != nil { + in, out := &in.PreferredDuringSchedulingIgnoredDuringExecution, &out.PreferredDuringSchedulingIgnoredDuringExecution + *out = make([]WeightedPodAffinityTerm, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodAntiAffinity. +func (in *PodAntiAffinity) DeepCopy() *PodAntiAffinity { + if in == nil { + return nil + } + out := new(PodAntiAffinity) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodAttachOptions) DeepCopyInto(out *PodAttachOptions) { + *out = *in + out.TypeMeta = in.TypeMeta + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodAttachOptions. +func (in *PodAttachOptions) DeepCopy() *PodAttachOptions { + if in == nil { + return nil + } + out := new(PodAttachOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PodAttachOptions) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodCondition) DeepCopyInto(out *PodCondition) { + *out = *in + in.LastProbeTime.DeepCopyInto(&out.LastProbeTime) + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodCondition. +func (in *PodCondition) DeepCopy() *PodCondition { + if in == nil { + return nil + } + out := new(PodCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodDNSConfig) DeepCopyInto(out *PodDNSConfig) { + *out = *in + if in.Nameservers != nil { + in, out := &in.Nameservers, &out.Nameservers + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Searches != nil { + in, out := &in.Searches, &out.Searches + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Options != nil { + in, out := &in.Options, &out.Options + *out = make([]PodDNSConfigOption, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodDNSConfig. +func (in *PodDNSConfig) DeepCopy() *PodDNSConfig { + if in == nil { + return nil + } + out := new(PodDNSConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodDNSConfigOption) DeepCopyInto(out *PodDNSConfigOption) { + *out = *in + if in.Value != nil { + in, out := &in.Value, &out.Value + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodDNSConfigOption. +func (in *PodDNSConfigOption) DeepCopy() *PodDNSConfigOption { + if in == nil { + return nil + } + out := new(PodDNSConfigOption) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodExecOptions) DeepCopyInto(out *PodExecOptions) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.Command != nil { + in, out := &in.Command, &out.Command + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodExecOptions. +func (in *PodExecOptions) DeepCopy() *PodExecOptions { + if in == nil { + return nil + } + out := new(PodExecOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PodExecOptions) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodIP) DeepCopyInto(out *PodIP) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodIP. +func (in *PodIP) DeepCopy() *PodIP { + if in == nil { + return nil + } + out := new(PodIP) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodList) DeepCopyInto(out *PodList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Pod, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodList. +func (in *PodList) DeepCopy() *PodList { + if in == nil { + return nil + } + out := new(PodList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PodList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodLogOptions) DeepCopyInto(out *PodLogOptions) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.SinceSeconds != nil { + in, out := &in.SinceSeconds, &out.SinceSeconds + *out = new(int64) + **out = **in + } + if in.SinceTime != nil { + in, out := &in.SinceTime, &out.SinceTime + *out = (*in).DeepCopy() + } + if in.TailLines != nil { + in, out := &in.TailLines, &out.TailLines + *out = new(int64) + **out = **in + } + if in.LimitBytes != nil { + in, out := &in.LimitBytes, &out.LimitBytes + *out = new(int64) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodLogOptions. +func (in *PodLogOptions) DeepCopy() *PodLogOptions { + if in == nil { + return nil + } + out := new(PodLogOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PodLogOptions) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodOS) DeepCopyInto(out *PodOS) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodOS. +func (in *PodOS) DeepCopy() *PodOS { + if in == nil { + return nil + } + out := new(PodOS) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodPortForwardOptions) DeepCopyInto(out *PodPortForwardOptions) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.Ports != nil { + in, out := &in.Ports, &out.Ports + *out = make([]int32, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodPortForwardOptions. +func (in *PodPortForwardOptions) DeepCopy() *PodPortForwardOptions { + if in == nil { + return nil + } + out := new(PodPortForwardOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PodPortForwardOptions) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodProxyOptions) DeepCopyInto(out *PodProxyOptions) { + *out = *in + out.TypeMeta = in.TypeMeta + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodProxyOptions. +func (in *PodProxyOptions) DeepCopy() *PodProxyOptions { + if in == nil { + return nil + } + out := new(PodProxyOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PodProxyOptions) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodReadinessGate) DeepCopyInto(out *PodReadinessGate) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodReadinessGate. +func (in *PodReadinessGate) DeepCopy() *PodReadinessGate { + if in == nil { + return nil + } + out := new(PodReadinessGate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodResourceClaim) DeepCopyInto(out *PodResourceClaim) { + *out = *in + in.Source.DeepCopyInto(&out.Source) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodResourceClaim. +func (in *PodResourceClaim) DeepCopy() *PodResourceClaim { + if in == nil { + return nil + } + out := new(PodResourceClaim) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodSchedulingGate) DeepCopyInto(out *PodSchedulingGate) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodSchedulingGate. +func (in *PodSchedulingGate) DeepCopy() *PodSchedulingGate { + if in == nil { + return nil + } + out := new(PodSchedulingGate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodSecurityContext) DeepCopyInto(out *PodSecurityContext) { + *out = *in + if in.ShareProcessNamespace != nil { + in, out := &in.ShareProcessNamespace, &out.ShareProcessNamespace + *out = new(bool) + **out = **in + } + if in.HostUsers != nil { + in, out := &in.HostUsers, &out.HostUsers + *out = new(bool) + **out = **in + } + if in.SELinuxOptions != nil { + in, out := &in.SELinuxOptions, &out.SELinuxOptions + *out = new(SELinuxOptions) + **out = **in + } + if in.WindowsOptions != nil { + in, out := &in.WindowsOptions, &out.WindowsOptions + *out = new(WindowsSecurityContextOptions) + (*in).DeepCopyInto(*out) + } + if in.RunAsUser != nil { + in, out := &in.RunAsUser, &out.RunAsUser + *out = new(int64) + **out = **in + } + if in.RunAsGroup != nil { + in, out := &in.RunAsGroup, &out.RunAsGroup + *out = new(int64) + **out = **in + } + if in.RunAsNonRoot != nil { + in, out := &in.RunAsNonRoot, &out.RunAsNonRoot + *out = new(bool) + **out = **in + } + if in.SupplementalGroups != nil { + in, out := &in.SupplementalGroups, &out.SupplementalGroups + *out = make([]int64, len(*in)) + copy(*out, *in) + } + if in.FSGroup != nil { + in, out := &in.FSGroup, &out.FSGroup + *out = new(int64) + **out = **in + } + if in.FSGroupChangePolicy != nil { + in, out := &in.FSGroupChangePolicy, &out.FSGroupChangePolicy + *out = new(PodFSGroupChangePolicy) + **out = **in + } + if in.Sysctls != nil { + in, out := &in.Sysctls, &out.Sysctls + *out = make([]Sysctl, len(*in)) + copy(*out, *in) + } + if in.SeccompProfile != nil { + in, out := &in.SeccompProfile, &out.SeccompProfile + *out = new(SeccompProfile) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodSecurityContext. +func (in *PodSecurityContext) DeepCopy() *PodSecurityContext { + if in == nil { + return nil + } + out := new(PodSecurityContext) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodSignature) DeepCopyInto(out *PodSignature) { + *out = *in + if in.PodController != nil { + in, out := &in.PodController, &out.PodController + *out = new(v1.OwnerReference) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodSignature. +func (in *PodSignature) DeepCopy() *PodSignature { + if in == nil { + return nil + } + out := new(PodSignature) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodSpec) DeepCopyInto(out *PodSpec) { + *out = *in + if in.Volumes != nil { + in, out := &in.Volumes, &out.Volumes + *out = make([]Volume, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.InitContainers != nil { + in, out := &in.InitContainers, &out.InitContainers + *out = make([]Container, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Containers != nil { + in, out := &in.Containers, &out.Containers + *out = make([]Container, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.EphemeralContainers != nil { + in, out := &in.EphemeralContainers, &out.EphemeralContainers + *out = make([]EphemeralContainer, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.TerminationGracePeriodSeconds != nil { + in, out := &in.TerminationGracePeriodSeconds, &out.TerminationGracePeriodSeconds + *out = new(int64) + **out = **in + } + if in.ActiveDeadlineSeconds != nil { + in, out := &in.ActiveDeadlineSeconds, &out.ActiveDeadlineSeconds + *out = new(int64) + **out = **in + } + if in.NodeSelector != nil { + in, out := &in.NodeSelector, &out.NodeSelector + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.AutomountServiceAccountToken != nil { + in, out := &in.AutomountServiceAccountToken, &out.AutomountServiceAccountToken + *out = new(bool) + **out = **in + } + if in.SecurityContext != nil { + in, out := &in.SecurityContext, &out.SecurityContext + *out = new(PodSecurityContext) + (*in).DeepCopyInto(*out) + } + if in.ImagePullSecrets != nil { + in, out := &in.ImagePullSecrets, &out.ImagePullSecrets + *out = make([]LocalObjectReference, len(*in)) + copy(*out, *in) + } + if in.SetHostnameAsFQDN != nil { + in, out := &in.SetHostnameAsFQDN, &out.SetHostnameAsFQDN + *out = new(bool) + **out = **in + } + if in.Affinity != nil { + in, out := &in.Affinity, &out.Affinity + *out = new(Affinity) + (*in).DeepCopyInto(*out) + } + if in.Tolerations != nil { + in, out := &in.Tolerations, &out.Tolerations + *out = make([]Toleration, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.HostAliases != nil { + in, out := &in.HostAliases, &out.HostAliases + *out = make([]HostAlias, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Priority != nil { + in, out := &in.Priority, &out.Priority + *out = new(int32) + **out = **in + } + if in.PreemptionPolicy != nil { + in, out := &in.PreemptionPolicy, &out.PreemptionPolicy + *out = new(PreemptionPolicy) + **out = **in + } + if in.DNSConfig != nil { + in, out := &in.DNSConfig, &out.DNSConfig + *out = new(PodDNSConfig) + (*in).DeepCopyInto(*out) + } + if in.ReadinessGates != nil { + in, out := &in.ReadinessGates, &out.ReadinessGates + *out = make([]PodReadinessGate, len(*in)) + copy(*out, *in) + } + if in.RuntimeClassName != nil { + in, out := &in.RuntimeClassName, &out.RuntimeClassName + *out = new(string) + **out = **in + } + if in.Overhead != nil { + in, out := &in.Overhead, &out.Overhead + *out = make(ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + if in.EnableServiceLinks != nil { + in, out := &in.EnableServiceLinks, &out.EnableServiceLinks + *out = new(bool) + **out = **in + } + if in.TopologySpreadConstraints != nil { + in, out := &in.TopologySpreadConstraints, &out.TopologySpreadConstraints + *out = make([]TopologySpreadConstraint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.OS != nil { + in, out := &in.OS, &out.OS + *out = new(PodOS) + **out = **in + } + if in.SchedulingGates != nil { + in, out := &in.SchedulingGates, &out.SchedulingGates + *out = make([]PodSchedulingGate, len(*in)) + copy(*out, *in) + } + if in.ResourceClaims != nil { + in, out := &in.ResourceClaims, &out.ResourceClaims + *out = make([]PodResourceClaim, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodSpec. +func (in *PodSpec) DeepCopy() *PodSpec { + if in == nil { + return nil + } + out := new(PodSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodStatus) DeepCopyInto(out *PodStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]PodCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.PodIPs != nil { + in, out := &in.PodIPs, &out.PodIPs + *out = make([]PodIP, len(*in)) + copy(*out, *in) + } + if in.StartTime != nil { + in, out := &in.StartTime, &out.StartTime + *out = (*in).DeepCopy() + } + if in.InitContainerStatuses != nil { + in, out := &in.InitContainerStatuses, &out.InitContainerStatuses + *out = make([]ContainerStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ContainerStatuses != nil { + in, out := &in.ContainerStatuses, &out.ContainerStatuses + *out = make([]ContainerStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.EphemeralContainerStatuses != nil { + in, out := &in.EphemeralContainerStatuses, &out.EphemeralContainerStatuses + *out = make([]ContainerStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodStatus. +func (in *PodStatus) DeepCopy() *PodStatus { + if in == nil { + return nil + } + out := new(PodStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodStatusResult) DeepCopyInto(out *PodStatusResult) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodStatusResult. +func (in *PodStatusResult) DeepCopy() *PodStatusResult { + if in == nil { + return nil + } + out := new(PodStatusResult) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PodStatusResult) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodTemplate) DeepCopyInto(out *PodTemplate) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Template.DeepCopyInto(&out.Template) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodTemplate. +func (in *PodTemplate) DeepCopy() *PodTemplate { + if in == nil { + return nil + } + out := new(PodTemplate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PodTemplate) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodTemplateList) DeepCopyInto(out *PodTemplateList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]PodTemplate, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodTemplateList. +func (in *PodTemplateList) DeepCopy() *PodTemplateList { + if in == nil { + return nil + } + out := new(PodTemplateList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PodTemplateList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodTemplateSpec) DeepCopyInto(out *PodTemplateSpec) { + *out = *in + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodTemplateSpec. +func (in *PodTemplateSpec) DeepCopy() *PodTemplateSpec { + if in == nil { + return nil + } + out := new(PodTemplateSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PortStatus) DeepCopyInto(out *PortStatus) { + *out = *in + if in.Error != nil { + in, out := &in.Error, &out.Error + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortStatus. +func (in *PortStatus) DeepCopy() *PortStatus { + if in == nil { + return nil + } + out := new(PortStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PortworxVolumeSource) DeepCopyInto(out *PortworxVolumeSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortworxVolumeSource. +func (in *PortworxVolumeSource) DeepCopy() *PortworxVolumeSource { + if in == nil { + return nil + } + out := new(PortworxVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Preconditions) DeepCopyInto(out *Preconditions) { + *out = *in + if in.UID != nil { + in, out := &in.UID, &out.UID + *out = new(types.UID) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Preconditions. +func (in *Preconditions) DeepCopy() *Preconditions { + if in == nil { + return nil + } + out := new(Preconditions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PreferAvoidPodsEntry) DeepCopyInto(out *PreferAvoidPodsEntry) { + *out = *in + in.PodSignature.DeepCopyInto(&out.PodSignature) + in.EvictionTime.DeepCopyInto(&out.EvictionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PreferAvoidPodsEntry. +func (in *PreferAvoidPodsEntry) DeepCopy() *PreferAvoidPodsEntry { + if in == nil { + return nil + } + out := new(PreferAvoidPodsEntry) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PreferredSchedulingTerm) DeepCopyInto(out *PreferredSchedulingTerm) { + *out = *in + in.Preference.DeepCopyInto(&out.Preference) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PreferredSchedulingTerm. +func (in *PreferredSchedulingTerm) DeepCopy() *PreferredSchedulingTerm { + if in == nil { + return nil + } + out := new(PreferredSchedulingTerm) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Probe) DeepCopyInto(out *Probe) { + *out = *in + in.ProbeHandler.DeepCopyInto(&out.ProbeHandler) + if in.TerminationGracePeriodSeconds != nil { + in, out := &in.TerminationGracePeriodSeconds, &out.TerminationGracePeriodSeconds + *out = new(int64) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Probe. +func (in *Probe) DeepCopy() *Probe { + if in == nil { + return nil + } + out := new(Probe) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProbeHandler) DeepCopyInto(out *ProbeHandler) { + *out = *in + if in.Exec != nil { + in, out := &in.Exec, &out.Exec + *out = new(ExecAction) + (*in).DeepCopyInto(*out) + } + if in.HTTPGet != nil { + in, out := &in.HTTPGet, &out.HTTPGet + *out = new(HTTPGetAction) + (*in).DeepCopyInto(*out) + } + if in.TCPSocket != nil { + in, out := &in.TCPSocket, &out.TCPSocket + *out = new(TCPSocketAction) + **out = **in + } + if in.GRPC != nil { + in, out := &in.GRPC, &out.GRPC + *out = new(GRPCAction) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProbeHandler. +func (in *ProbeHandler) DeepCopy() *ProbeHandler { + if in == nil { + return nil + } + out := new(ProbeHandler) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProjectedVolumeSource) DeepCopyInto(out *ProjectedVolumeSource) { + *out = *in + if in.Sources != nil { + in, out := &in.Sources, &out.Sources + *out = make([]VolumeProjection, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.DefaultMode != nil { + in, out := &in.DefaultMode, &out.DefaultMode + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectedVolumeSource. +func (in *ProjectedVolumeSource) DeepCopy() *ProjectedVolumeSource { + if in == nil { + return nil + } + out := new(ProjectedVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *QuobyteVolumeSource) DeepCopyInto(out *QuobyteVolumeSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new QuobyteVolumeSource. +func (in *QuobyteVolumeSource) DeepCopy() *QuobyteVolumeSource { + if in == nil { + return nil + } + out := new(QuobyteVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RBDPersistentVolumeSource) DeepCopyInto(out *RBDPersistentVolumeSource) { + *out = *in + if in.CephMonitors != nil { + in, out := &in.CephMonitors, &out.CephMonitors + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(SecretReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RBDPersistentVolumeSource. +func (in *RBDPersistentVolumeSource) DeepCopy() *RBDPersistentVolumeSource { + if in == nil { + return nil + } + out := new(RBDPersistentVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RBDVolumeSource) DeepCopyInto(out *RBDVolumeSource) { + *out = *in + if in.CephMonitors != nil { + in, out := &in.CephMonitors, &out.CephMonitors + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(LocalObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RBDVolumeSource. +func (in *RBDVolumeSource) DeepCopy() *RBDVolumeSource { + if in == nil { + return nil + } + out := new(RBDVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RangeAllocation) DeepCopyInto(out *RangeAllocation) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.Data != nil { + in, out := &in.Data, &out.Data + *out = make([]byte, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RangeAllocation. +func (in *RangeAllocation) DeepCopy() *RangeAllocation { + if in == nil { + return nil + } + out := new(RangeAllocation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RangeAllocation) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReplicationController) DeepCopyInto(out *ReplicationController) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplicationController. +func (in *ReplicationController) DeepCopy() *ReplicationController { + if in == nil { + return nil + } + out := new(ReplicationController) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ReplicationController) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReplicationControllerCondition) DeepCopyInto(out *ReplicationControllerCondition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplicationControllerCondition. +func (in *ReplicationControllerCondition) DeepCopy() *ReplicationControllerCondition { + if in == nil { + return nil + } + out := new(ReplicationControllerCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReplicationControllerList) DeepCopyInto(out *ReplicationControllerList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ReplicationController, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplicationControllerList. +func (in *ReplicationControllerList) DeepCopy() *ReplicationControllerList { + if in == nil { + return nil + } + out := new(ReplicationControllerList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ReplicationControllerList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReplicationControllerSpec) DeepCopyInto(out *ReplicationControllerSpec) { + *out = *in + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Template != nil { + in, out := &in.Template, &out.Template + *out = new(PodTemplateSpec) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplicationControllerSpec. +func (in *ReplicationControllerSpec) DeepCopy() *ReplicationControllerSpec { + if in == nil { + return nil + } + out := new(ReplicationControllerSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReplicationControllerStatus) DeepCopyInto(out *ReplicationControllerStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]ReplicationControllerCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplicationControllerStatus. +func (in *ReplicationControllerStatus) DeepCopy() *ReplicationControllerStatus { + if in == nil { + return nil + } + out := new(ReplicationControllerStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceClaim) DeepCopyInto(out *ResourceClaim) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceClaim. +func (in *ResourceClaim) DeepCopy() *ResourceClaim { + if in == nil { + return nil + } + out := new(ResourceClaim) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceFieldSelector) DeepCopyInto(out *ResourceFieldSelector) { + *out = *in + out.Divisor = in.Divisor.DeepCopy() + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceFieldSelector. +func (in *ResourceFieldSelector) DeepCopy() *ResourceFieldSelector { + if in == nil { + return nil + } + out := new(ResourceFieldSelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in ResourceList) DeepCopyInto(out *ResourceList) { + { + in := &in + *out = make(ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceList. +func (in ResourceList) DeepCopy() ResourceList { + if in == nil { + return nil + } + out := new(ResourceList) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceQuota) DeepCopyInto(out *ResourceQuota) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceQuota. +func (in *ResourceQuota) DeepCopy() *ResourceQuota { + if in == nil { + return nil + } + out := new(ResourceQuota) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ResourceQuota) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceQuotaList) DeepCopyInto(out *ResourceQuotaList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ResourceQuota, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceQuotaList. +func (in *ResourceQuotaList) DeepCopy() *ResourceQuotaList { + if in == nil { + return nil + } + out := new(ResourceQuotaList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ResourceQuotaList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceQuotaSpec) DeepCopyInto(out *ResourceQuotaSpec) { + *out = *in + if in.Hard != nil { + in, out := &in.Hard, &out.Hard + *out = make(ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + if in.Scopes != nil { + in, out := &in.Scopes, &out.Scopes + *out = make([]ResourceQuotaScope, len(*in)) + copy(*out, *in) + } + if in.ScopeSelector != nil { + in, out := &in.ScopeSelector, &out.ScopeSelector + *out = new(ScopeSelector) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceQuotaSpec. +func (in *ResourceQuotaSpec) DeepCopy() *ResourceQuotaSpec { + if in == nil { + return nil + } + out := new(ResourceQuotaSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceQuotaStatus) DeepCopyInto(out *ResourceQuotaStatus) { + *out = *in + if in.Hard != nil { + in, out := &in.Hard, &out.Hard + *out = make(ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + if in.Used != nil { + in, out := &in.Used, &out.Used + *out = make(ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceQuotaStatus. +func (in *ResourceQuotaStatus) DeepCopy() *ResourceQuotaStatus { + if in == nil { + return nil + } + out := new(ResourceQuotaStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceRequirements) DeepCopyInto(out *ResourceRequirements) { + *out = *in + if in.Limits != nil { + in, out := &in.Limits, &out.Limits + *out = make(ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + if in.Requests != nil { + in, out := &in.Requests, &out.Requests + *out = make(ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + if in.Claims != nil { + in, out := &in.Claims, &out.Claims + *out = make([]ResourceClaim, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceRequirements. +func (in *ResourceRequirements) DeepCopy() *ResourceRequirements { + if in == nil { + return nil + } + out := new(ResourceRequirements) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SELinuxOptions) DeepCopyInto(out *SELinuxOptions) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SELinuxOptions. +func (in *SELinuxOptions) DeepCopy() *SELinuxOptions { + if in == nil { + return nil + } + out := new(SELinuxOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ScaleIOPersistentVolumeSource) DeepCopyInto(out *ScaleIOPersistentVolumeSource) { + *out = *in + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(SecretReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScaleIOPersistentVolumeSource. +func (in *ScaleIOPersistentVolumeSource) DeepCopy() *ScaleIOPersistentVolumeSource { + if in == nil { + return nil + } + out := new(ScaleIOPersistentVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ScaleIOVolumeSource) DeepCopyInto(out *ScaleIOVolumeSource) { + *out = *in + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(LocalObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScaleIOVolumeSource. +func (in *ScaleIOVolumeSource) DeepCopy() *ScaleIOVolumeSource { + if in == nil { + return nil + } + out := new(ScaleIOVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ScopeSelector) DeepCopyInto(out *ScopeSelector) { + *out = *in + if in.MatchExpressions != nil { + in, out := &in.MatchExpressions, &out.MatchExpressions + *out = make([]ScopedResourceSelectorRequirement, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScopeSelector. +func (in *ScopeSelector) DeepCopy() *ScopeSelector { + if in == nil { + return nil + } + out := new(ScopeSelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ScopedResourceSelectorRequirement) DeepCopyInto(out *ScopedResourceSelectorRequirement) { + *out = *in + if in.Values != nil { + in, out := &in.Values, &out.Values + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScopedResourceSelectorRequirement. +func (in *ScopedResourceSelectorRequirement) DeepCopy() *ScopedResourceSelectorRequirement { + if in == nil { + return nil + } + out := new(ScopedResourceSelectorRequirement) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SeccompProfile) DeepCopyInto(out *SeccompProfile) { + *out = *in + if in.LocalhostProfile != nil { + in, out := &in.LocalhostProfile, &out.LocalhostProfile + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SeccompProfile. +func (in *SeccompProfile) DeepCopy() *SeccompProfile { + if in == nil { + return nil + } + out := new(SeccompProfile) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Secret) DeepCopyInto(out *Secret) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.Immutable != nil { + in, out := &in.Immutable, &out.Immutable + *out = new(bool) + **out = **in + } + if in.Data != nil { + in, out := &in.Data, &out.Data + *out = make(map[string][]byte, len(*in)) + for key, val := range *in { + var outVal []byte + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = make([]byte, len(*in)) + copy(*out, *in) + } + (*out)[key] = outVal + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Secret. +func (in *Secret) DeepCopy() *Secret { + if in == nil { + return nil + } + out := new(Secret) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Secret) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecretEnvSource) DeepCopyInto(out *SecretEnvSource) { + *out = *in + out.LocalObjectReference = in.LocalObjectReference + if in.Optional != nil { + in, out := &in.Optional, &out.Optional + *out = new(bool) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretEnvSource. +func (in *SecretEnvSource) DeepCopy() *SecretEnvSource { + if in == nil { + return nil + } + out := new(SecretEnvSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecretKeySelector) DeepCopyInto(out *SecretKeySelector) { + *out = *in + out.LocalObjectReference = in.LocalObjectReference + if in.Optional != nil { + in, out := &in.Optional, &out.Optional + *out = new(bool) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretKeySelector. +func (in *SecretKeySelector) DeepCopy() *SecretKeySelector { + if in == nil { + return nil + } + out := new(SecretKeySelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecretList) DeepCopyInto(out *SecretList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Secret, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretList. +func (in *SecretList) DeepCopy() *SecretList { + if in == nil { + return nil + } + out := new(SecretList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SecretList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecretProjection) DeepCopyInto(out *SecretProjection) { + *out = *in + out.LocalObjectReference = in.LocalObjectReference + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]KeyToPath, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Optional != nil { + in, out := &in.Optional, &out.Optional + *out = new(bool) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretProjection. +func (in *SecretProjection) DeepCopy() *SecretProjection { + if in == nil { + return nil + } + out := new(SecretProjection) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecretReference) DeepCopyInto(out *SecretReference) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretReference. +func (in *SecretReference) DeepCopy() *SecretReference { + if in == nil { + return nil + } + out := new(SecretReference) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecretVolumeSource) DeepCopyInto(out *SecretVolumeSource) { + *out = *in + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]KeyToPath, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.DefaultMode != nil { + in, out := &in.DefaultMode, &out.DefaultMode + *out = new(int32) + **out = **in + } + if in.Optional != nil { + in, out := &in.Optional, &out.Optional + *out = new(bool) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretVolumeSource. +func (in *SecretVolumeSource) DeepCopy() *SecretVolumeSource { + if in == nil { + return nil + } + out := new(SecretVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecurityContext) DeepCopyInto(out *SecurityContext) { + *out = *in + if in.Capabilities != nil { + in, out := &in.Capabilities, &out.Capabilities + *out = new(Capabilities) + (*in).DeepCopyInto(*out) + } + if in.Privileged != nil { + in, out := &in.Privileged, &out.Privileged + *out = new(bool) + **out = **in + } + if in.SELinuxOptions != nil { + in, out := &in.SELinuxOptions, &out.SELinuxOptions + *out = new(SELinuxOptions) + **out = **in + } + if in.WindowsOptions != nil { + in, out := &in.WindowsOptions, &out.WindowsOptions + *out = new(WindowsSecurityContextOptions) + (*in).DeepCopyInto(*out) + } + if in.RunAsUser != nil { + in, out := &in.RunAsUser, &out.RunAsUser + *out = new(int64) + **out = **in + } + if in.RunAsGroup != nil { + in, out := &in.RunAsGroup, &out.RunAsGroup + *out = new(int64) + **out = **in + } + if in.RunAsNonRoot != nil { + in, out := &in.RunAsNonRoot, &out.RunAsNonRoot + *out = new(bool) + **out = **in + } + if in.ReadOnlyRootFilesystem != nil { + in, out := &in.ReadOnlyRootFilesystem, &out.ReadOnlyRootFilesystem + *out = new(bool) + **out = **in + } + if in.AllowPrivilegeEscalation != nil { + in, out := &in.AllowPrivilegeEscalation, &out.AllowPrivilegeEscalation + *out = new(bool) + **out = **in + } + if in.ProcMount != nil { + in, out := &in.ProcMount, &out.ProcMount + *out = new(ProcMountType) + **out = **in + } + if in.SeccompProfile != nil { + in, out := &in.SeccompProfile, &out.SeccompProfile + *out = new(SeccompProfile) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityContext. +func (in *SecurityContext) DeepCopy() *SecurityContext { + if in == nil { + return nil + } + out := new(SecurityContext) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SerializedReference) DeepCopyInto(out *SerializedReference) { + *out = *in + out.TypeMeta = in.TypeMeta + out.Reference = in.Reference + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SerializedReference. +func (in *SerializedReference) DeepCopy() *SerializedReference { + if in == nil { + return nil + } + out := new(SerializedReference) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SerializedReference) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Service) DeepCopyInto(out *Service) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Service. +func (in *Service) DeepCopy() *Service { + if in == nil { + return nil + } + out := new(Service) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Service) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceAccount) DeepCopyInto(out *ServiceAccount) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.Secrets != nil { + in, out := &in.Secrets, &out.Secrets + *out = make([]ObjectReference, len(*in)) + copy(*out, *in) + } + if in.ImagePullSecrets != nil { + in, out := &in.ImagePullSecrets, &out.ImagePullSecrets + *out = make([]LocalObjectReference, len(*in)) + copy(*out, *in) + } + if in.AutomountServiceAccountToken != nil { + in, out := &in.AutomountServiceAccountToken, &out.AutomountServiceAccountToken + *out = new(bool) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceAccount. +func (in *ServiceAccount) DeepCopy() *ServiceAccount { + if in == nil { + return nil + } + out := new(ServiceAccount) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ServiceAccount) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceAccountList) DeepCopyInto(out *ServiceAccountList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ServiceAccount, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceAccountList. +func (in *ServiceAccountList) DeepCopy() *ServiceAccountList { + if in == nil { + return nil + } + out := new(ServiceAccountList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ServiceAccountList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceAccountTokenProjection) DeepCopyInto(out *ServiceAccountTokenProjection) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceAccountTokenProjection. +func (in *ServiceAccountTokenProjection) DeepCopy() *ServiceAccountTokenProjection { + if in == nil { + return nil + } + out := new(ServiceAccountTokenProjection) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceList) DeepCopyInto(out *ServiceList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Service, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceList. +func (in *ServiceList) DeepCopy() *ServiceList { + if in == nil { + return nil + } + out := new(ServiceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ServiceList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServicePort) DeepCopyInto(out *ServicePort) { + *out = *in + if in.AppProtocol != nil { + in, out := &in.AppProtocol, &out.AppProtocol + *out = new(string) + **out = **in + } + out.TargetPort = in.TargetPort + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServicePort. +func (in *ServicePort) DeepCopy() *ServicePort { + if in == nil { + return nil + } + out := new(ServicePort) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceProxyOptions) DeepCopyInto(out *ServiceProxyOptions) { + *out = *in + out.TypeMeta = in.TypeMeta + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceProxyOptions. +func (in *ServiceProxyOptions) DeepCopy() *ServiceProxyOptions { + if in == nil { + return nil + } + out := new(ServiceProxyOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ServiceProxyOptions) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceSpec) DeepCopyInto(out *ServiceSpec) { + *out = *in + if in.Ports != nil { + in, out := &in.Ports, &out.Ports + *out = make([]ServicePort, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.ClusterIPs != nil { + in, out := &in.ClusterIPs, &out.ClusterIPs + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.IPFamilies != nil { + in, out := &in.IPFamilies, &out.IPFamilies + *out = make([]IPFamily, len(*in)) + copy(*out, *in) + } + if in.IPFamilyPolicy != nil { + in, out := &in.IPFamilyPolicy, &out.IPFamilyPolicy + *out = new(IPFamilyPolicy) + **out = **in + } + if in.ExternalIPs != nil { + in, out := &in.ExternalIPs, &out.ExternalIPs + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.SessionAffinityConfig != nil { + in, out := &in.SessionAffinityConfig, &out.SessionAffinityConfig + *out = new(SessionAffinityConfig) + (*in).DeepCopyInto(*out) + } + if in.LoadBalancerSourceRanges != nil { + in, out := &in.LoadBalancerSourceRanges, &out.LoadBalancerSourceRanges + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.AllocateLoadBalancerNodePorts != nil { + in, out := &in.AllocateLoadBalancerNodePorts, &out.AllocateLoadBalancerNodePorts + *out = new(bool) + **out = **in + } + if in.LoadBalancerClass != nil { + in, out := &in.LoadBalancerClass, &out.LoadBalancerClass + *out = new(string) + **out = **in + } + if in.InternalTrafficPolicy != nil { + in, out := &in.InternalTrafficPolicy, &out.InternalTrafficPolicy + *out = new(ServiceInternalTrafficPolicyType) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceSpec. +func (in *ServiceSpec) DeepCopy() *ServiceSpec { + if in == nil { + return nil + } + out := new(ServiceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceStatus) DeepCopyInto(out *ServiceStatus) { + *out = *in + in.LoadBalancer.DeepCopyInto(&out.LoadBalancer) + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceStatus. +func (in *ServiceStatus) DeepCopy() *ServiceStatus { + if in == nil { + return nil + } + out := new(ServiceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SessionAffinityConfig) DeepCopyInto(out *SessionAffinityConfig) { + *out = *in + if in.ClientIP != nil { + in, out := &in.ClientIP, &out.ClientIP + *out = new(ClientIPConfig) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SessionAffinityConfig. +func (in *SessionAffinityConfig) DeepCopy() *SessionAffinityConfig { + if in == nil { + return nil + } + out := new(SessionAffinityConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StorageOSPersistentVolumeSource) DeepCopyInto(out *StorageOSPersistentVolumeSource) { + *out = *in + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(ObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StorageOSPersistentVolumeSource. +func (in *StorageOSPersistentVolumeSource) DeepCopy() *StorageOSPersistentVolumeSource { + if in == nil { + return nil + } + out := new(StorageOSPersistentVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StorageOSVolumeSource) DeepCopyInto(out *StorageOSVolumeSource) { + *out = *in + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(LocalObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StorageOSVolumeSource. +func (in *StorageOSVolumeSource) DeepCopy() *StorageOSVolumeSource { + if in == nil { + return nil + } + out := new(StorageOSVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Sysctl) DeepCopyInto(out *Sysctl) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Sysctl. +func (in *Sysctl) DeepCopy() *Sysctl { + if in == nil { + return nil + } + out := new(Sysctl) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TCPSocketAction) DeepCopyInto(out *TCPSocketAction) { + *out = *in + out.Port = in.Port + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TCPSocketAction. +func (in *TCPSocketAction) DeepCopy() *TCPSocketAction { + if in == nil { + return nil + } + out := new(TCPSocketAction) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Taint) DeepCopyInto(out *Taint) { + *out = *in + if in.TimeAdded != nil { + in, out := &in.TimeAdded, &out.TimeAdded + *out = (*in).DeepCopy() + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Taint. +func (in *Taint) DeepCopy() *Taint { + if in == nil { + return nil + } + out := new(Taint) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Toleration) DeepCopyInto(out *Toleration) { + *out = *in + if in.TolerationSeconds != nil { + in, out := &in.TolerationSeconds, &out.TolerationSeconds + *out = new(int64) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Toleration. +func (in *Toleration) DeepCopy() *Toleration { + if in == nil { + return nil + } + out := new(Toleration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TopologySelectorLabelRequirement) DeepCopyInto(out *TopologySelectorLabelRequirement) { + *out = *in + if in.Values != nil { + in, out := &in.Values, &out.Values + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TopologySelectorLabelRequirement. +func (in *TopologySelectorLabelRequirement) DeepCopy() *TopologySelectorLabelRequirement { + if in == nil { + return nil + } + out := new(TopologySelectorLabelRequirement) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TopologySelectorTerm) DeepCopyInto(out *TopologySelectorTerm) { + *out = *in + if in.MatchLabelExpressions != nil { + in, out := &in.MatchLabelExpressions, &out.MatchLabelExpressions + *out = make([]TopologySelectorLabelRequirement, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TopologySelectorTerm. +func (in *TopologySelectorTerm) DeepCopy() *TopologySelectorTerm { + if in == nil { + return nil + } + out := new(TopologySelectorTerm) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TopologySpreadConstraint) DeepCopyInto(out *TopologySpreadConstraint) { + *out = *in + if in.LabelSelector != nil { + in, out := &in.LabelSelector, &out.LabelSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + if in.MinDomains != nil { + in, out := &in.MinDomains, &out.MinDomains + *out = new(int32) + **out = **in + } + if in.NodeAffinityPolicy != nil { + in, out := &in.NodeAffinityPolicy, &out.NodeAffinityPolicy + *out = new(NodeInclusionPolicy) + **out = **in + } + if in.NodeTaintsPolicy != nil { + in, out := &in.NodeTaintsPolicy, &out.NodeTaintsPolicy + *out = new(NodeInclusionPolicy) + **out = **in + } + if in.MatchLabelKeys != nil { + in, out := &in.MatchLabelKeys, &out.MatchLabelKeys + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TopologySpreadConstraint. +func (in *TopologySpreadConstraint) DeepCopy() *TopologySpreadConstraint { + if in == nil { + return nil + } + out := new(TopologySpreadConstraint) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TypedLocalObjectReference) DeepCopyInto(out *TypedLocalObjectReference) { + *out = *in + if in.APIGroup != nil { + in, out := &in.APIGroup, &out.APIGroup + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TypedLocalObjectReference. +func (in *TypedLocalObjectReference) DeepCopy() *TypedLocalObjectReference { + if in == nil { + return nil + } + out := new(TypedLocalObjectReference) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TypedObjectReference) DeepCopyInto(out *TypedObjectReference) { + *out = *in + if in.APIGroup != nil { + in, out := &in.APIGroup, &out.APIGroup + *out = new(string) + **out = **in + } + if in.Namespace != nil { + in, out := &in.Namespace, &out.Namespace + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TypedObjectReference. +func (in *TypedObjectReference) DeepCopy() *TypedObjectReference { + if in == nil { + return nil + } + out := new(TypedObjectReference) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Volume) DeepCopyInto(out *Volume) { + *out = *in + in.VolumeSource.DeepCopyInto(&out.VolumeSource) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Volume. +func (in *Volume) DeepCopy() *Volume { + if in == nil { + return nil + } + out := new(Volume) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeDevice) DeepCopyInto(out *VolumeDevice) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeDevice. +func (in *VolumeDevice) DeepCopy() *VolumeDevice { + if in == nil { + return nil + } + out := new(VolumeDevice) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeMount) DeepCopyInto(out *VolumeMount) { + *out = *in + if in.MountPropagation != nil { + in, out := &in.MountPropagation, &out.MountPropagation + *out = new(MountPropagationMode) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeMount. +func (in *VolumeMount) DeepCopy() *VolumeMount { + if in == nil { + return nil + } + out := new(VolumeMount) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeNodeAffinity) DeepCopyInto(out *VolumeNodeAffinity) { + *out = *in + if in.Required != nil { + in, out := &in.Required, &out.Required + *out = new(NodeSelector) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeNodeAffinity. +func (in *VolumeNodeAffinity) DeepCopy() *VolumeNodeAffinity { + if in == nil { + return nil + } + out := new(VolumeNodeAffinity) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeProjection) DeepCopyInto(out *VolumeProjection) { + *out = *in + if in.Secret != nil { + in, out := &in.Secret, &out.Secret + *out = new(SecretProjection) + (*in).DeepCopyInto(*out) + } + if in.DownwardAPI != nil { + in, out := &in.DownwardAPI, &out.DownwardAPI + *out = new(DownwardAPIProjection) + (*in).DeepCopyInto(*out) + } + if in.ConfigMap != nil { + in, out := &in.ConfigMap, &out.ConfigMap + *out = new(ConfigMapProjection) + (*in).DeepCopyInto(*out) + } + if in.ServiceAccountToken != nil { + in, out := &in.ServiceAccountToken, &out.ServiceAccountToken + *out = new(ServiceAccountTokenProjection) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeProjection. +func (in *VolumeProjection) DeepCopy() *VolumeProjection { + if in == nil { + return nil + } + out := new(VolumeProjection) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeSource) DeepCopyInto(out *VolumeSource) { + *out = *in + if in.HostPath != nil { + in, out := &in.HostPath, &out.HostPath + *out = new(HostPathVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.EmptyDir != nil { + in, out := &in.EmptyDir, &out.EmptyDir + *out = new(EmptyDirVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.GCEPersistentDisk != nil { + in, out := &in.GCEPersistentDisk, &out.GCEPersistentDisk + *out = new(GCEPersistentDiskVolumeSource) + **out = **in + } + if in.AWSElasticBlockStore != nil { + in, out := &in.AWSElasticBlockStore, &out.AWSElasticBlockStore + *out = new(AWSElasticBlockStoreVolumeSource) + **out = **in + } + if in.GitRepo != nil { + in, out := &in.GitRepo, &out.GitRepo + *out = new(GitRepoVolumeSource) + **out = **in + } + if in.Secret != nil { + in, out := &in.Secret, &out.Secret + *out = new(SecretVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.NFS != nil { + in, out := &in.NFS, &out.NFS + *out = new(NFSVolumeSource) + **out = **in + } + if in.ISCSI != nil { + in, out := &in.ISCSI, &out.ISCSI + *out = new(ISCSIVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.Glusterfs != nil { + in, out := &in.Glusterfs, &out.Glusterfs + *out = new(GlusterfsVolumeSource) + **out = **in + } + if in.PersistentVolumeClaim != nil { + in, out := &in.PersistentVolumeClaim, &out.PersistentVolumeClaim + *out = new(PersistentVolumeClaimVolumeSource) + **out = **in + } + if in.RBD != nil { + in, out := &in.RBD, &out.RBD + *out = new(RBDVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.Quobyte != nil { + in, out := &in.Quobyte, &out.Quobyte + *out = new(QuobyteVolumeSource) + **out = **in + } + if in.FlexVolume != nil { + in, out := &in.FlexVolume, &out.FlexVolume + *out = new(FlexVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.Cinder != nil { + in, out := &in.Cinder, &out.Cinder + *out = new(CinderVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.CephFS != nil { + in, out := &in.CephFS, &out.CephFS + *out = new(CephFSVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.Flocker != nil { + in, out := &in.Flocker, &out.Flocker + *out = new(FlockerVolumeSource) + **out = **in + } + if in.DownwardAPI != nil { + in, out := &in.DownwardAPI, &out.DownwardAPI + *out = new(DownwardAPIVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.FC != nil { + in, out := &in.FC, &out.FC + *out = new(FCVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.AzureFile != nil { + in, out := &in.AzureFile, &out.AzureFile + *out = new(AzureFileVolumeSource) + **out = **in + } + if in.ConfigMap != nil { + in, out := &in.ConfigMap, &out.ConfigMap + *out = new(ConfigMapVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.VsphereVolume != nil { + in, out := &in.VsphereVolume, &out.VsphereVolume + *out = new(VsphereVirtualDiskVolumeSource) + **out = **in + } + if in.AzureDisk != nil { + in, out := &in.AzureDisk, &out.AzureDisk + *out = new(AzureDiskVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.PhotonPersistentDisk != nil { + in, out := &in.PhotonPersistentDisk, &out.PhotonPersistentDisk + *out = new(PhotonPersistentDiskVolumeSource) + **out = **in + } + if in.Projected != nil { + in, out := &in.Projected, &out.Projected + *out = new(ProjectedVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.PortworxVolume != nil { + in, out := &in.PortworxVolume, &out.PortworxVolume + *out = new(PortworxVolumeSource) + **out = **in + } + if in.ScaleIO != nil { + in, out := &in.ScaleIO, &out.ScaleIO + *out = new(ScaleIOVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.StorageOS != nil { + in, out := &in.StorageOS, &out.StorageOS + *out = new(StorageOSVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.CSI != nil { + in, out := &in.CSI, &out.CSI + *out = new(CSIVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.Ephemeral != nil { + in, out := &in.Ephemeral, &out.Ephemeral + *out = new(EphemeralVolumeSource) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeSource. +func (in *VolumeSource) DeepCopy() *VolumeSource { + if in == nil { + return nil + } + out := new(VolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VsphereVirtualDiskVolumeSource) DeepCopyInto(out *VsphereVirtualDiskVolumeSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VsphereVirtualDiskVolumeSource. +func (in *VsphereVirtualDiskVolumeSource) DeepCopy() *VsphereVirtualDiskVolumeSource { + if in == nil { + return nil + } + out := new(VsphereVirtualDiskVolumeSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WeightedPodAffinityTerm) DeepCopyInto(out *WeightedPodAffinityTerm) { + *out = *in + in.PodAffinityTerm.DeepCopyInto(&out.PodAffinityTerm) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WeightedPodAffinityTerm. +func (in *WeightedPodAffinityTerm) DeepCopy() *WeightedPodAffinityTerm { + if in == nil { + return nil + } + out := new(WeightedPodAffinityTerm) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WindowsSecurityContextOptions) DeepCopyInto(out *WindowsSecurityContextOptions) { + *out = *in + if in.GMSACredentialSpecName != nil { + in, out := &in.GMSACredentialSpecName, &out.GMSACredentialSpecName + *out = new(string) + **out = **in + } + if in.GMSACredentialSpec != nil { + in, out := &in.GMSACredentialSpec, &out.GMSACredentialSpec + *out = new(string) + **out = **in + } + if in.RunAsUserName != nil { + in, out := &in.RunAsUserName, &out.RunAsUserName + *out = new(string) + **out = **in + } + if in.HostProcess != nil { + in, out := &in.HostProcess, &out.HostProcess + *out = new(bool) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WindowsSecurityContextOptions. +func (in *WindowsSecurityContextOptions) DeepCopy() *WindowsSecurityContextOptions { + if in == nil { + return nil + } + out := new(WindowsSecurityContextOptions) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/k8s.io/kubernetes/pkg/capabilities/capabilities.go b/vendor/k8s.io/kubernetes/pkg/capabilities/capabilities.go new file mode 100644 index 000000000..eac7560ad --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/capabilities/capabilities.go @@ -0,0 +1,94 @@ +/* +Copyright 2014 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 capabilities + +import ( + "sync" +) + +// Capabilities defines the set of capabilities available within the system. +// For now these are global. Eventually they may be per-user +type Capabilities struct { + AllowPrivileged bool + + // Pod sources from which to allow privileged capabilities like host networking, sharing the host + // IPC namespace, and sharing the host PID namespace. + PrivilegedSources PrivilegedSources + + // PerConnectionBandwidthLimitBytesPerSec limits the throughput of each connection (currently only used for proxy, exec, attach) + PerConnectionBandwidthLimitBytesPerSec int64 +} + +// PrivilegedSources defines the pod sources allowed to make privileged requests for certain types +// of capabilities like host networking, sharing the host IPC namespace, and sharing the host PID namespace. +type PrivilegedSources struct { + // List of pod sources for which using host network is allowed. + HostNetworkSources []string + + // List of pod sources for which using host pid namespace is allowed. + HostPIDSources []string + + // List of pod sources for which using host ipc is allowed. + HostIPCSources []string +} + +var capInstance struct { + once sync.Once + lock sync.Mutex + capabilities *Capabilities +} + +// Initialize the capability set. This can only be done once per binary, subsequent calls are ignored. +func Initialize(c Capabilities) { + // Only do this once + capInstance.once.Do(func() { + capInstance.capabilities = &c + }) +} + +// Setup the capability set. It wraps Initialize for improving usability. +func Setup(allowPrivileged bool, perConnectionBytesPerSec int64) { + Initialize(Capabilities{ + AllowPrivileged: allowPrivileged, + PerConnectionBandwidthLimitBytesPerSec: perConnectionBytesPerSec, + }) +} + +// SetForTests sets capabilities for tests. Convenience method for testing. This should only be called from tests. +func SetForTests(c Capabilities) { + capInstance.lock.Lock() + defer capInstance.lock.Unlock() + capInstance.capabilities = &c +} + +// Get returns a read-only copy of the system capabilities. +func Get() Capabilities { + capInstance.lock.Lock() + defer capInstance.lock.Unlock() + // This check prevents clobbering of capabilities that might've been set via SetForTests + if capInstance.capabilities == nil { + Initialize(Capabilities{ + AllowPrivileged: false, + PrivilegedSources: PrivilegedSources{ + HostNetworkSources: []string{}, + HostPIDSources: []string{}, + HostIPCSources: []string{}, + }, + }) + } + return *capInstance.capabilities +} diff --git a/vendor/k8s.io/kubernetes/pkg/capabilities/doc.go b/vendor/k8s.io/kubernetes/pkg/capabilities/doc.go new file mode 100644 index 000000000..e8d3aa3e5 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/capabilities/doc.go @@ -0,0 +1,18 @@ +/* +Copyright 2014 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 capabilities manages system level capabilities +package capabilities // import "k8s.io/kubernetes/pkg/capabilities" diff --git a/vendor/k8s.io/kubernetes/pkg/cluster/ports/doc.go b/vendor/k8s.io/kubernetes/pkg/cluster/ports/doc.go new file mode 100644 index 000000000..0810294e0 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/cluster/ports/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2014 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 ports defines ports used by various pieces of the kubernetes +// infrastructure. +package ports // import "k8s.io/kubernetes/pkg/cluster/ports" diff --git a/vendor/k8s.io/kubernetes/pkg/cluster/ports/ports.go b/vendor/k8s.io/kubernetes/pkg/cluster/ports/ports.go new file mode 100644 index 000000000..10ded2ad7 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/cluster/ports/ports.go @@ -0,0 +1,46 @@ +/* +Copyright 2014 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 ports + +// In this file, we can see all default port of cluster. +// It's also an important documentation for us. So don't remove them easily. +const ( + // ProxyStatusPort is the default port for the proxy metrics server. + // May be overridden by a flag at startup. + ProxyStatusPort = 10249 + // KubeletPort is the default port for the kubelet server on each host machine. + // May be overridden by a flag at startup. + KubeletPort = 10250 + // KubeletReadOnlyPort exposes basic read-only services from the kubelet. + // May be overridden by a flag at startup. + // This is necessary for heapster to collect monitoring stats from the kubelet + // until heapster can transition to using the SSL endpoint. + // TODO(roberthbailey): Remove this once we have a better solution for heapster. + KubeletReadOnlyPort = 10255 + // KubeletHealthzPort exposes a healthz endpoint from the kubelet. + // May be overridden by a flag at startup. + KubeletHealthzPort = 10248 + // ProxyHealthzPort is the default port for the proxy healthz server. + // May be overridden by a flag at startup. + ProxyHealthzPort = 10256 + // KubeControllerManagerPort is the default port for the controller manager status server. + // May be overridden by a flag at startup. + KubeControllerManagerPort = 10257 + // CloudControllerManagerPort is the default port for the cloud controller manager server. + // This value may be overridden by a flag at startup. + CloudControllerManagerPort = 10258 +) diff --git a/vendor/k8s.io/kubernetes/pkg/features/OWNERS b/vendor/k8s.io/kubernetes/pkg/features/OWNERS new file mode 100644 index 000000000..3e1dd9f08 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/features/OWNERS @@ -0,0 +1,4 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +approvers: + - feature-approvers diff --git a/vendor/k8s.io/kubernetes/pkg/features/kube_features.go b/vendor/k8s.io/kubernetes/pkg/features/kube_features.go new file mode 100644 index 000000000..8847b8309 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/features/kube_features.go @@ -0,0 +1,1190 @@ +/* +Copyright 2017 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 features + +import ( + "k8s.io/apimachinery/pkg/util/runtime" + genericfeatures "k8s.io/apiserver/pkg/features" + utilfeature "k8s.io/apiserver/pkg/util/feature" + "k8s.io/component-base/featuregate" +) + +const ( + // Every feature gate should add method here following this template: + // + // // owner: @username + // // kep: https://kep.k8s.io/NNN + // // alpha: v1.X + // MyFeature featuregate.Feature = "MyFeature" + // + // Feature gates should be listed in alphabetical, case-sensitive + // (upper before any lower case character) order. This reduces the risk + // of code conflicts because changes are more likely to be scattered + // across the file. + + // owner: @ttakahashi21 @mkimuram + // kep: https://kep.k8s.io/3294 + // alpha: v1.26 + // + // Enable usage of Provision of PVCs from snapshots in other namespaces + CrossNamespaceVolumeDataSource featuregate.Feature = "CrossNamespaceVolumeDataSource" + + // owner: @bswartz + // alpha: v1.18 + // beta: v1.24 + // + // Enables usage of any object for volume data source in PVCs + AnyVolumeDataSource featuregate.Feature = "AnyVolumeDataSource" + + // owner: @nabokihms + // alpha: v1.26 + // + // Enables API to get self subject attributes after authentication. + APISelfSubjectReview featuregate.Feature = "APISelfSubjectReview" + + // owner: @tallclair + // beta: v1.4 + AppArmor featuregate.Feature = "AppArmor" + + // owner: @szuecs + // alpha: v1.12 + // + // Enable nodes to change CPUCFSQuotaPeriod + CPUCFSQuotaPeriod featuregate.Feature = "CustomCPUCFSQuotaPeriod" + + // owner: @ConnorDoyle, @fromanirh (only for GA graduation) + // alpha: v1.8 + // beta: v1.10 + // GA: v1.26 + // + // Alternative container-level CPU affinity policies. + CPUManager featuregate.Feature = "CPUManager" + + // owner: @fromanirh + // alpha: v1.23 + // beta: see below. + // + // Allow fine-tuning of cpumanager policies, experimental, alpha-quality options + // Per https://groups.google.com/g/kubernetes-sig-architecture/c/Nxsc7pfe5rw/m/vF2djJh0BAAJ + // We want to avoid a proliferation of feature gates. This feature gate: + // - will guard *a group* of cpumanager options whose quality level is alpha. + // - will never graduate to beta or stable. + // See https://groups.google.com/g/kubernetes-sig-architecture/c/Nxsc7pfe5rw/m/vF2djJh0BAAJ + // for details about the removal of this feature gate. + CPUManagerPolicyAlphaOptions featuregate.Feature = "CPUManagerPolicyAlphaOptions" + + // owner: @fromanirh + // beta: v1.23 + // beta: see below. + // + // Allow fine-tuning of cpumanager policies, experimental, beta-quality options + // Per https://groups.google.com/g/kubernetes-sig-architecture/c/Nxsc7pfe5rw/m/vF2djJh0BAAJ + // We want to avoid a proliferation of feature gates. This feature gate: + // - will guard *a group* of cpumanager options whose quality level is beta. + // - is thus *introduced* as beta + // - will never graduate to stable. + // See https://groups.google.com/g/kubernetes-sig-architecture/c/Nxsc7pfe5rw/m/vF2djJh0BAAJ + // for details about the removal of this feature gate. + CPUManagerPolicyBetaOptions featuregate.Feature = "CPUManagerPolicyBetaOptions" + + // owner: @fromanirh + // alpha: v1.22 + // beta: v1.23 + // + // Allow the usage of options to fine-tune the cpumanager policies. + CPUManagerPolicyOptions featuregate.Feature = "CPUManagerPolicyOptions" + + // owner: @pohly + // alpha: v1.14 + // beta: v1.16 + // GA: v1.25 + // + // Enables CSI Inline volumes support for pods + CSIInlineVolume featuregate.Feature = "CSIInlineVolume" + + // owner: @davidz627 + // alpha: v1.14 + // beta: v1.17 + // + // Enables the in-tree storage to CSI Plugin migration feature. + CSIMigration featuregate.Feature = "CSIMigration" + + // owner: @leakingtapan + // alpha: v1.14 + // beta: v1.17 + // GA: v1.25 + // + // Enables the AWS EBS in-tree driver to AWS EBS CSI Driver migration feature. + CSIMigrationAWS featuregate.Feature = "CSIMigrationAWS" + + // owner: @andyzhangx + // alpha: v1.15 + // beta: v1.19 + // GA: v1.24 + // + // Enables the Azure Disk in-tree driver to Azure Disk Driver migration feature. + CSIMigrationAzureDisk featuregate.Feature = "CSIMigrationAzureDisk" + + // owner: @andyzhangx + // alpha: v1.15 + // beta: v1.21 + // GA: v1.26 + // + // Enables the Azure File in-tree driver to Azure File Driver migration feature. + CSIMigrationAzureFile featuregate.Feature = "CSIMigrationAzureFile" + + // owner: @davidz627 + // alpha: v1.14 + // beta: v1.17 + // GA: 1.25 + // + // Enables the GCE PD in-tree driver to GCE CSI Driver migration feature. + CSIMigrationGCE featuregate.Feature = "CSIMigrationGCE" + + // owner: @trierra + // alpha: v1.23 + // + // Enables the Portworx in-tree driver to Portworx migration feature. + CSIMigrationPortworx featuregate.Feature = "CSIMigrationPortworx" + + // owner: @humblec + // alpha: v1.23 + // + // Enables the RBD in-tree driver to RBD CSI Driver migration feature. + CSIMigrationRBD featuregate.Feature = "CSIMigrationRBD" + + // owner: @divyenpatel + // beta: v1.19 (requires: vSphere vCenter/ESXi Version: 7.0u2, HW Version: VM version 15) + // GA: 1.26 + // Enables the vSphere in-tree driver to vSphere CSI Driver migration feature. + CSIMigrationvSphere featuregate.Feature = "CSIMigrationvSphere" + + // owner: @humblec, @zhucan + // kep: https://kep.k8s.io/3171 + // alpha: v1.25 + // + // Enables SecretRef field in CSI NodeExpandVolume request. + CSINodeExpandSecret featuregate.Feature = "CSINodeExpandSecret" + + // owner: @pohly + // alpha: v1.19 + // beta: v1.21 + // GA: v1.24 + // + // Enables tracking of available storage capacity that CSI drivers provide. + CSIStorageCapacity featuregate.Feature = "CSIStorageCapacity" + + // owner: @fengzixu + // alpha: v1.21 + // + // Enables kubelet to detect CSI volume condition and send the event of the abnormal volume to the corresponding pod that is using it. + CSIVolumeHealth featuregate.Feature = "CSIVolumeHealth" + + // owner: @adrianreber + // kep: https://kep.k8s.io/2008 + // alpha: v1.25 + // + // Enables container Checkpoint support in the kubelet + ContainerCheckpoint featuregate.Feature = "ContainerCheckpoint" + + // owner: @bhcleek @wzshiming + // GA: v1.25 + // + // Normalize HttpGet URL and Header passing for lifecycle handlers with probers. + ConsistentHTTPGetHandlers featuregate.Feature = "ConsistentHTTPGetHandlers" + + // owner: @jiahuif + // alpha: v1.21 + // beta: v1.22 + // GA: v1.24 + // + // Enables Leader Migration for kube-controller-manager and cloud-controller-manager + ControllerManagerLeaderMigration featuregate.Feature = "ControllerManagerLeaderMigration" + + // owner: @deejross, @soltysh + // kep: https://kep.k8s.io/3140 + // alpha: v1.24 + // beta: v1.25 + // + // Enables support for time zones in CronJobs. + CronJobTimeZone featuregate.Feature = "CronJobTimeZone" + + // owner: @smarterclayton + // alpha: v1.21 + // beta: v1.22 + // GA: v1.25 + // DaemonSets allow workloads to maintain availability during update per node + DaemonSetUpdateSurge featuregate.Feature = "DaemonSetUpdateSurge" + + // owner: @gnufied, @verult, @bertinatto + // alpha: v1.22 + // beta: v1.23 + // GA: v1.26 + // If supported by the CSI driver, delegates the role of applying FSGroup to + // the driver by passing FSGroup through the NodeStageVolume and + // NodePublishVolume calls. + DelegateFSGroupToCSIDriver featuregate.Feature = "DelegateFSGroupToCSIDriver" + + // owner: @jiayingz, @swatisehgal (for GA graduation) + // alpha: v1.8 + // beta: v1.10 + // GA: v1.26 + // + // Enables support for Device Plugins + DevicePlugins featuregate.Feature = "DevicePlugins" + + // owner: @RenaudWasTaken @dashpole + // alpha: v1.19 + // beta: v1.20 + // ga: v1.25 + // + // Disables Accelerator Metrics Collected by Kubelet + DisableAcceleratorUsageMetrics featuregate.Feature = "DisableAcceleratorUsageMetrics" + + // owner: @andrewsykim + // alpha: v1.22 + // + // Disable any functionality in kube-apiserver, kube-controller-manager and kubelet related to the `--cloud-provider` component flag. + DisableCloudProviders featuregate.Feature = "DisableCloudProviders" + + // owner: @andrewsykim + // alpha: v1.23 + // + // Disable in-tree functionality in kubelet to authenticate to cloud provider container registries for image pull credentials. + DisableKubeletCloudCredentialProviders featuregate.Feature = "DisableKubeletCloudCredentialProviders" + + // owner: @derekwaynecarr + // alpha: v1.20 + // beta: v1.21 (off by default until 1.22) + // + // Enables usage of hugepages- in downward API. + DownwardAPIHugePages featuregate.Feature = "DownwardAPIHugePages" + + // owner: @pohly + // kep: http://kep.k8s.io/3063 + // alpha: v1.26 + // + // Enables support for resources with custom parameters and a lifecycle + // that is independent of a Pod. + DynamicResourceAllocation featuregate.Feature = "DynamicResourceAllocation" + + // owner: @andrewsykim + // kep: https://kep.k8s.io/1672 + // alpha: v1.20 + // beta: v1.22 + // GA: v1.26 + // + // Enable Terminating condition in Endpoint Slices. + EndpointSliceTerminatingCondition featuregate.Feature = "EndpointSliceTerminatingCondition" + + // owner: @verb + // alpha: v1.16 + // beta: v1.23 + // GA: v1.25 + // + // Allows running an ephemeral container in pod namespaces to troubleshoot a running pod. + EphemeralContainers featuregate.Feature = "EphemeralContainers" + + // owner: @harche + // kep: http://kep.k8s.io/3386 + // alpha: v1.25 + // + // Allows using event-driven PLEG (pod lifecycle event generator) through kubelet + // which avoids frequent relisting of containers which helps optimize performance. + EventedPLEG featuregate.Feature = "EventedPLEG" + + // owner: @andrewsykim @SergeyKanzhelev + // GA: v1.20 + // + // Ensure kubelet respects exec probe timeouts. Feature gate exists in-case existing workloads + // may depend on old behavior where exec probe timeouts were ignored. + // Lock to default and remove after v1.22 based on user feedback that should be reflected in KEP #1972 update + ExecProbeTimeout featuregate.Feature = "ExecProbeTimeout" + + // owner: @gnufied + // alpha: v1.14 + // beta: v1.16 + // GA: 1.24 + // Ability to expand CSI volumes + ExpandCSIVolumes featuregate.Feature = "ExpandCSIVolumes" + + // owner: @mlmhl @gnufied + // beta: v1.15 + // GA: 1.24 + // Ability to expand persistent volumes' file system without unmounting volumes. + ExpandInUsePersistentVolumes featuregate.Feature = "ExpandInUsePersistentVolumes" + + // owner: @gnufied + // beta: v1.11 + // GA: 1.24 + // Ability to Expand persistent volumes + ExpandPersistentVolumes featuregate.Feature = "ExpandPersistentVolumes" + + // owner: @gjkim42 + // kep: https://kep.k8s.io/2595 + // alpha: v1.22 + // beta: v1.26 + // + // Enables apiserver and kubelet to allow up to 32 DNSSearchPaths and up to 2048 DNSSearchListChars. + ExpandedDNSConfig featuregate.Feature = "ExpandedDNSConfig" + + // owner: @pweil- + // alpha: v1.5 + // + // Default userns=host for containers that are using other host namespaces, host mounts, the pod + // contains a privileged container, or specific non-namespaced capabilities (MKNOD, SYS_MODULE, + // SYS_TIME). This should only be enabled if user namespace remapping is enabled in the docker daemon. + ExperimentalHostUserNamespaceDefaultingGate featuregate.Feature = "ExperimentalHostUserNamespaceDefaulting" + + // owner: @yuzhiquan, @bowei, @PxyUp, @SergeyKanzhelev + // kep: https://kep.k8s.io/2727 + // alpha: v1.23 + // beta: v1.24 + // + // Enables GRPC probe method for {Liveness,Readiness,Startup}Probe. + GRPCContainerProbe featuregate.Feature = "GRPCContainerProbe" + + // owner: @bobbypage + // alpha: v1.20 + // beta: v1.21 + // Adds support for kubelet to detect node shutdown and gracefully terminate pods prior to the node being shutdown. + GracefulNodeShutdown featuregate.Feature = "GracefulNodeShutdown" + + // owner: @wzshiming + // alpha: v1.23 + // beta: v1.24 + // Make the kubelet use shutdown configuration based on pod priority values for graceful shutdown. + GracefulNodeShutdownBasedOnPodPriority featuregate.Feature = "GracefulNodeShutdownBasedOnPodPriority" + + // owner: @arjunrn @mwielgus @josephburnett + // alpha: v1.20 + // + // Add support for the HPA to scale based on metrics from individual containers + // in target pods + HPAContainerMetrics featuregate.Feature = "HPAContainerMetrics" + + // owner: @dxist + // alpha: v1.16 + // + // Enables support of HPA scaling to zero pods when an object or custom metric is configured. + HPAScaleToZero featuregate.Feature = "HPAScaleToZero" + + // owner: @deepakkinni @xing-yang + // kep: https://kep.k8s.io/2680 + // alpha: v1.23 + // + // Honor Persistent Volume Reclaim Policy when it is "Delete" irrespective of PV-PVC + // deletion ordering. + HonorPVReclaimPolicy featuregate.Feature = "HonorPVReclaimPolicy" + + // owner: @ravig + // alpha: v1.23 + // beta: v1.24 + // GA: v1.25 + // IdentifyPodOS allows user to specify OS on which they'd like the Pod run. The user should still set the nodeSelector + // with appropriate `kubernetes.io/os` label for scheduler to identify appropriate node for the pod to run. + IdentifyPodOS featuregate.Feature = "IdentifyPodOS" + + // owner: @leakingtapan + // alpha: v1.21 + // + // Disables the AWS EBS in-tree driver. + InTreePluginAWSUnregister featuregate.Feature = "InTreePluginAWSUnregister" + + // owner: @andyzhangx + // alpha: v1.21 + // + // Disables the Azure Disk in-tree driver. + InTreePluginAzureDiskUnregister featuregate.Feature = "InTreePluginAzureDiskUnregister" + + // owner: @andyzhangx + // alpha: v1.21 + // + // Disables the Azure File in-tree driver. + InTreePluginAzureFileUnregister featuregate.Feature = "InTreePluginAzureFileUnregister" + + // owner: @Jiawei0227 + // alpha: v1.21 + // + // Disables the GCE PD in-tree driver. + InTreePluginGCEUnregister featuregate.Feature = "InTreePluginGCEUnregister" + + // owner: @adisky + // alpha: v1.21 + // + // Disables the OpenStack Cinder in-tree driver. + InTreePluginOpenStackUnregister featuregate.Feature = "InTreePluginOpenStackUnregister" + + // owner: @trierra + // alpha: v1.23 + // + // Disables the Portworx in-tree driver. + InTreePluginPortworxUnregister featuregate.Feature = "InTreePluginPortworxUnregister" + + // owner: @humblec + // alpha: v1.23 + // + // Disables the RBD in-tree driver. + InTreePluginRBDUnregister featuregate.Feature = "InTreePluginRBDUnregister" + + // owner: @divyenpatel + // alpha: v1.21 + // + // Disables the vSphere in-tree driver. + InTreePluginvSphereUnregister featuregate.Feature = "InTreePluginvSphereUnregister" + + // owner: @danwinship + // kep: https://kep.k8s.io/3178 + // alpha: v1.25 + // + // Causes kubelet to no longer create legacy IPTables rules + IPTablesOwnershipCleanup featuregate.Feature = "IPTablesOwnershipCleanup" + + // owner: @mimowo + // kep: https://kep.k8s.io/3329 + // alpha: v1.25 + // beta: v1.26 + // + // Allow users to specify handling of pod failures based on container exit codes + // and pod conditions. + JobPodFailurePolicy featuregate.Feature = "JobPodFailurePolicy" + + // owner: @ahg + // beta: v1.23 + // + // Allow updating node scheduling directives in the pod template of jobs. Specifically, + // node affinity, selector and tolerations. This is allowed only for suspended jobs + // that have never been unsuspended before. + JobMutableNodeSchedulingDirectives featuregate.Feature = "JobMutableNodeSchedulingDirectives" + + // owner: @alculquicondor + // alpha: v1.23 + // beta: v1.24 + // + // Track the number of pods with Ready condition in the Job status. + JobReadyPods featuregate.Feature = "JobReadyPods" + + // owner: @alculquicondor + // alpha: v1.22 + // beta: v1.23 + // stable: v1.26 + // + // Track Job completion without relying on Pod remaining in the cluster + // indefinitely. Pod finalizers, in addition to a field in the Job status + // allow the Job controller to keep track of Pods that it didn't account for + // yet. + JobTrackingWithFinalizers featuregate.Feature = "JobTrackingWithFinalizers" + + // owner: @andrewsykim @adisky @ndixita + // alpha: v1.20 + // beta: v1.24 + // GA: v1.26 + // + // Enable kubelet exec plugins for image pull credentials. + KubeletCredentialProviders featuregate.Feature = "KubeletCredentialProviders" + + // owner: @AkihiroSuda + // alpha: v1.22 + // + // Enables support for running kubelet in a user namespace. + // The user namespace has to be created before running kubelet. + // All the node components such as CRI need to be running in the same user namespace. + KubeletInUserNamespace featuregate.Feature = "KubeletInUserNamespace" + + // owner: @dashpole + // alpha: v1.13 + // beta: v1.15 + // + // Enables the kubelet's pod resources grpc endpoint + KubeletPodResources featuregate.Feature = "KubeletPodResources" + + // owner: @fromanirh + // alpha: v1.21 + // beta: v1.23 + // Enable POD resources API to return allocatable resources + KubeletPodResourcesGetAllocatable featuregate.Feature = "KubeletPodResourcesGetAllocatable" + + // owner: @sallyom + // kep: https://kep.k8s.io/2832 + // alpha: v1.25 + // + // Add support for distributed tracing in the kubelet + KubeletTracing featuregate.Feature = "KubeletTracing" + + // owner: @zshihang + // kep: https://kep.k8s.io/2800 + // beta: v1.24 + // + // Stop auto-generation of secret-based service account tokens. + LegacyServiceAccountTokenNoAutoGeneration featuregate.Feature = "LegacyServiceAccountTokenNoAutoGeneration" + + // owner: @zshihang + // kep: http://kep.k8s.io/2800 + // alpha: v1.25 + // + // Enables tracking of secret-based service account tokens usage. + LegacyServiceAccountTokenTracking featuregate.Feature = "LegacyServiceAccountTokenTracking" + + // owner: @jinxu + // beta: v1.10 + // stable: v1.25 + // + // Support local ephemeral storage types for local storage capacity isolation feature. + LocalStorageCapacityIsolation featuregate.Feature = "LocalStorageCapacityIsolation" + + // owner: @RobertKrawitz + // alpha: v1.15 + // + // Allow use of filesystems for ephemeral storage monitoring. + // Only applies if LocalStorageCapacityIsolation is set. + LocalStorageCapacityIsolationFSQuotaMonitoring featuregate.Feature = "LocalStorageCapacityIsolationFSQuotaMonitoring" + + // owner: @damemi + // alpha: v1.21 + // beta: v1.22 + // + // Enables scaling down replicas via logarithmic comparison of creation/ready timestamps + LogarithmicScaleDown featuregate.Feature = "LogarithmicScaleDown" + + // owner: @denkensk + // kep: https://kep.k8s.io/3243 + // alpha: v1.25 + // + // Enable MatchLabelKeys in PodTopologySpread. + MatchLabelKeysInPodTopologySpread featuregate.Feature = "MatchLabelKeysInPodTopologySpread" + + // owner: @krmayankk + // alpha: v1.24 + // + // Enables maxUnavailable for StatefulSet + MaxUnavailableStatefulSet featuregate.Feature = "MaxUnavailableStatefulSet" + + // owner: @cynepco3hahue(alukiano) @cezaryzukowski @k-wiatrzyk + // alpha: v1.21 + // beta: v1.22 + // Allows setting memory affinity for a container based on NUMA topology + MemoryManager featuregate.Feature = "MemoryManager" + + // owner: @xiaoxubeii + // kep: https://kep.k8s.io/2570 + // alpha: v1.22 + // + // Enables kubelet to support memory QoS with cgroups v2. + MemoryQoS featuregate.Feature = "MemoryQoS" + + // owner: @sanposhiho + // kep: https://kep.k8s.io/3022 + // alpha: v1.24 + // beta: v1.25 + // + // Enable MinDomains in Pod Topology Spread. + MinDomainsInPodTopologySpread featuregate.Feature = "MinDomainsInPodTopologySpread" + + // owner: @danwinship + // kep: http://kep.k8s.io/3453 + // alpha: v1.26 + // + // Enables new performance-improving code in kube-proxy iptables mode + MinimizeIPTablesRestore featuregate.Feature = "MinimizeIPTablesRestore" + + // owner: @janosi @bridgetkromhout + // kep: https://kep.k8s.io/1435 + // alpha: v1.20 + // beta: v1.24 + // ga: v1.26 + // + // Enables the usage of different protocols in the same Service with type=LoadBalancer + MixedProtocolLBService featuregate.Feature = "MixedProtocolLBService" + + // owner: @sarveshr7 + // kep: https://kep.k8s.io/2593 + // alpha: v1.25 + // + // Enables the MultiCIDR Range allocator. + MultiCIDRRangeAllocator featuregate.Feature = "MultiCIDRRangeAllocator" + + // owner: @rikatz + // kep: https://kep.k8s.io/2079 + // alpha: v1.21 + // beta: v1.22 + // ga: v1.25 + // + // Enables the endPort field in NetworkPolicy to enable a Port Range behavior in Network Policies. + NetworkPolicyEndPort featuregate.Feature = "NetworkPolicyEndPort" + + // owner: @rikatz + // kep: https://kep.k8s.io/2943 + // alpha: v1.24 + // + // Enables NetworkPolicy status subresource + NetworkPolicyStatus featuregate.Feature = "NetworkPolicyStatus" + + // owner: @xing-yang @sonasingh46 + // kep: https://kep.k8s.io/2268 + // alpha: v1.24 + // beta: v1.26 + // + // Allow pods to failover to a different node in case of non graceful node shutdown + NodeOutOfServiceVolumeDetach featuregate.Feature = "NodeOutOfServiceVolumeDetach" + + // owner: @ehashman + // alpha: v1.22 + // + // Permits kubelet to run with swap enabled + NodeSwap featuregate.Feature = "NodeSwap" + + // owner: @mortent, @atiratree, @ravig + // kep: http://kep.k8s.io/3018 + // alpha: v1.26 + // + // Enables PDBUnhealthyPodEvictionPolicy for PodDisruptionBudgets + PDBUnhealthyPodEvictionPolicy featuregate.Feature = "PDBUnhealthyPodEvictionPolicy" + + // owner: @haircommander + // kep: https://kep.k8s.io/2364 + // alpha: v1.23 + // + // Configures the Kubelet to use the CRI to populate pod and container stats, instead of supplimenting with stats from cAdvisor. + // Requires the CRI implementation supports supplying the required stats. + PodAndContainerStatsFromCRI featuregate.Feature = "PodAndContainerStatsFromCRI" + + // owner: @ahg-g + // alpha: v1.21 + // beta: v1.22 + // + // Enables controlling pod ranking on replicaset scale-down. + PodDeletionCost featuregate.Feature = "PodDeletionCost" + + // owner: @mimowo + // kep: https://kep.k8s.io/3329 + // alpha: v1.25 + // beta: v1.26 + // + // Enables support for appending a dedicated pod condition indicating that + // the pod is being deleted due to a disruption. + PodDisruptionConditions featuregate.Feature = "PodDisruptionConditions" + + // owner: @ddebroy + // alpha: v1.25 + // + // Enables reporting of PodHasNetwork condition in pod status after pod + // sandbox creation and network configuration completes successfully + PodHasNetworkCondition featuregate.Feature = "PodHasNetworkCondition" + + // owner: @Huang-Wei + // kep: https://kep.k8s.io/3521 + // alpha: v1.26 + // + // Enable users to specify when a Pod is ready for scheduling. + PodSchedulingReadiness featuregate.Feature = "PodSchedulingReadiness" + + // owner: @liggitt, @tallclair, sig-auth + // alpha: v1.22 + // beta: v1.23 + // ga: v1.25 + // + // Enables the PodSecurity admission plugin + PodSecurity featuregate.Feature = "PodSecurity" + + // owner: @ehashman + // alpha: v1.21 + // beta: v1.22 + // + // Allows user to override pod-level terminationGracePeriod for probes + ProbeTerminationGracePeriod featuregate.Feature = "ProbeTerminationGracePeriod" + + // owner: @jessfraz + // alpha: v1.12 + // + // Enables control over ProcMountType for containers. + ProcMountType featuregate.Feature = "ProcMountType" + + // owner: @andrewsykim + // kep: https://kep.k8s.io/1669 + // alpha: v1.22 + // beta: v1.26 + // + // Enable kube-proxy to handle terminating ednpoints when externalTrafficPolicy=Local + ProxyTerminatingEndpoints featuregate.Feature = "ProxyTerminatingEndpoints" + + // owner: @sjenning + // alpha: v1.11 + // + // Allows resource reservations at the QoS level preventing pods at lower QoS levels from + // bursting into resources requested at higher QoS levels (memory only for now) + QOSReserved featuregate.Feature = "QOSReserved" + + // owner: @chrishenzie + // alpha: v1.22 + // + // Enables usage of the ReadWriteOncePod PersistentVolume access mode. + ReadWriteOncePod featuregate.Feature = "ReadWriteOncePod" + + // owner: @gnufied + // kep: https://kep.k8s.io/1790 + // alpha: v1.23 + // + // Allow users to recover from volume expansion failure + RecoverVolumeExpansionFailure featuregate.Feature = "RecoverVolumeExpansionFailure" + + // owner: @RomanBednar + // kep: https://kep.k8s.io/3333 + // alpha: v1.25 + // + // Allow assigning StorageClass to unbound PVCs retroactively + RetroactiveDefaultStorageClass featuregate.Feature = "RetroactiveDefaultStorageClass" + + // owner: @mikedanese + // alpha: v1.7 + // beta: v1.12 + // + // Gets a server certificate for the kubelet from the Certificate Signing + // Request API instead of generating one self signed and auto rotates the + // certificate as expiration approaches. + RotateKubeletServerCertificate featuregate.Feature = "RotateKubeletServerCertificate" + + // owner: @saschagrunert + // kep: https://kep.k8s.io/2413 + // alpha: v1.22 + // beta: v1.25 + // + // Enables the use of `RuntimeDefault` as the default seccomp profile for all workloads. + SeccompDefault featuregate.Feature = "SeccompDefault" + + // owner: @maplain @andrewsykim + // kep: https://kep.k8s.io/2086 + // alpha: v1.21 + // beta: v1.22 + // GA: v1.26 + // + // Enables node-local routing for Service internal traffic + ServiceInternalTrafficPolicy featuregate.Feature = "ServiceInternalTrafficPolicy" + + // owner: @aojea + // kep: https://kep.k8s.io/3070 + // alpha: v1.24 + // beta: v1.25 + // ga: v1.26 + // + // Subdivide the ClusterIP range for dynamic and static IP allocation. + ServiceIPStaticSubrange featuregate.Feature = "ServiceIPStaticSubrange" + + // owner: @derekwaynecarr + // alpha: v1.20 + // beta: v1.22 + // + // Enables kubelet support to size memory backed volumes + SizeMemoryBackedVolumes featuregate.Feature = "SizeMemoryBackedVolumes" + + // owner: @mattcary + // alpha: v1.22 + // + // Enables policies controlling deletion of PVCs created by a StatefulSet. + StatefulSetAutoDeletePVC featuregate.Feature = "StatefulSetAutoDeletePVC" + + // owner: @ravig + // kep: https://kep.k8s.io/2607 + // alpha: v1.22 + // beta: v1.23 + // GA: v1.25 + // StatefulSetMinReadySeconds allows minReadySeconds to be respected by StatefulSet controller + StatefulSetMinReadySeconds featuregate.Feature = "StatefulSetMinReadySeconds" + + // owner: @psch + // alpha: v1.26 + // + // Enables a StatefulSet to start from an arbitrary non zero ordinal + StatefulSetStartOrdinal featuregate.Feature = "StatefulSetStartOrdinal" + + // owner: @robscott + // kep: https://kep.k8s.io/2433 + // alpha: v1.21 + // beta: v1.23 + // + // Enables topology aware hints for EndpointSlices + TopologyAwareHints featuregate.Feature = "TopologyAwareHints" + + // owner: @lmdaly + // alpha: v1.16 + // beta: v1.18 + // + // Enable resource managers to make NUMA aligned decisions + TopologyManager featuregate.Feature = "TopologyManager" + + // owner: @PiotrProkop + // kep: https://kep.k8s.io/3545 + // alpha: v1.26 + // + // Allow fine-tuning of topology manager policies with alpha options. + // This feature gate: + // - will guard *a group* of topology manager options whose quality level is alpha. + // - will never graduate to beta or stable. + TopologyManagerPolicyAlphaOptions featuregate.Feature = "TopologyManagerPolicyAlphaOptions" + + // owner: @PiotrProkop + // kep: https://kep.k8s.io/3545 + // alpha: v1.26 + // + // Allow fine-tuning of topology manager policies with beta options. + // This feature gate: + // - will guard *a group* of topology manager options whose quality level is beta. + // - is thus *introduced* as beta + // - will never graduate to stable. + TopologyManagerPolicyBetaOptions featuregate.Feature = "TopologyManagerPolicyBetaOptions" + + // owner: @PiotrProkop + // kep: https://kep.k8s.io/3545 + // alpha: v1.26 + // + // Allow the usage of options to fine-tune the topology manager policies. + TopologyManagerPolicyOptions featuregate.Feature = "TopologyManagerPolicyOptions" + + // owner: @rata, @giuseppe + // kep: https://kep.k8s.io/127 + // alpha: v1.25 + // + // Enables user namespace support for stateless pods. + UserNamespacesStatelessPodsSupport featuregate.Feature = "UserNamespacesStatelessPodsSupport" + + // owner: @cofyc + // alpha: v1.21 + VolumeCapacityPriority featuregate.Feature = "VolumeCapacityPriority" + + // owner: @ksubrmnn + // alpha: v1.14 + // + // Allows kube-proxy to create DSR loadbalancers for Windows + WinDSR featuregate.Feature = "WinDSR" + + // owner: @ksubrmnn + // alpha: v1.14 + // beta: v1.20 + // + // Allows kube-proxy to run in Overlay mode for Windows + WinOverlay featuregate.Feature = "WinOverlay" + + // owner: @marosset + // kep: https://kep.k8s.io/3503 + // alpha: v1.26 + // + // Enables support for joining Windows containers to a hosts' network namespace. + WindowsHostNetwork featuregate.Feature = "WindowsHostNetwork" + + // owner: @marosset + // alpha: v1.22 + // beta: v1.23 + // GA: v1.26 + // + // Enables support for 'HostProcess' containers on Windows nodes. + WindowsHostProcessContainers featuregate.Feature = "WindowsHostProcessContainers" + + // owner: @kerthcet + // kep: https://kep.k8s.io/3094 + // alpha: v1.25 + // beta: v1.26 + // + // Allow users to specify whether to take nodeAffinity/nodeTaint into consideration when + // calculating pod topology spread skew. + NodeInclusionPolicyInPodTopologySpread featuregate.Feature = "NodeInclusionPolicyInPodTopologySpread" + + // owner: @jsafrane + // kep: https://kep.k8s.io/1710 + // alpha: v1.25 + // Speed up container startup by mounting volumes with the correct SELinux label + // instead of changing each file on the volumes recursively. + // Initial implementation focused on ReadWriteOncePod volumes. + SELinuxMountReadWriteOncePod featuregate.Feature = "SELinuxMountReadWriteOncePod" +) + +func init() { + runtime.Must(utilfeature.DefaultMutableFeatureGate.Add(defaultKubernetesFeatureGates)) +} + +// defaultKubernetesFeatureGates consists of all known Kubernetes-specific feature keys. +// To add a new feature, define a key for it above and add it here. The features will be +// available throughout Kubernetes binaries. +// +// Entries are separated from each other with blank lines to avoid sweeping gofmt changes +// when adding or removing one entry. +var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{ + CrossNamespaceVolumeDataSource: {Default: false, PreRelease: featuregate.Alpha}, + + AnyVolumeDataSource: {Default: true, PreRelease: featuregate.Beta}, // on by default in 1.24 + + APISelfSubjectReview: {Default: false, PreRelease: featuregate.Alpha}, + + AppArmor: {Default: true, PreRelease: featuregate.Beta}, + + CPUCFSQuotaPeriod: {Default: false, PreRelease: featuregate.Alpha}, + + CPUManager: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // GA in 1.26 + + CPUManagerPolicyAlphaOptions: {Default: false, PreRelease: featuregate.Alpha}, + + CPUManagerPolicyBetaOptions: {Default: true, PreRelease: featuregate.Beta}, + + CPUManagerPolicyOptions: {Default: true, PreRelease: featuregate.Beta}, + + CSIInlineVolume: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.27 + + CSIMigration: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.27 + + CSIMigrationAWS: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.27 + + CSIMigrationAzureDisk: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.26 + + CSIMigrationAzureFile: {Default: true, PreRelease: featuregate.GA}, // remove in 1.28 + + CSIMigrationGCE: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.27 + + CSIMigrationPortworx: {Default: false, PreRelease: featuregate.Beta}, // Off by default (requires Portworx CSI driver) + + CSIMigrationRBD: {Default: false, PreRelease: featuregate.Alpha}, // Off by default (requires RBD CSI driver) + + CSIMigrationvSphere: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.28 + + CSINodeExpandSecret: {Default: false, PreRelease: featuregate.Alpha}, + + CSIStorageCapacity: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.26 + + CSIVolumeHealth: {Default: false, PreRelease: featuregate.Alpha}, + + ContainerCheckpoint: {Default: false, PreRelease: featuregate.Alpha}, + + ConsistentHTTPGetHandlers: {Default: true, PreRelease: featuregate.GA}, + + ControllerManagerLeaderMigration: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.26 + + CronJobTimeZone: {Default: true, PreRelease: featuregate.Beta}, + + DaemonSetUpdateSurge: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.27 + + DelegateFSGroupToCSIDriver: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.28 + + DevicePlugins: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // GA in 1.26 + + DisableAcceleratorUsageMetrics: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, + + DisableCloudProviders: {Default: false, PreRelease: featuregate.Alpha}, + + DisableKubeletCloudCredentialProviders: {Default: false, PreRelease: featuregate.Alpha}, + + DownwardAPIHugePages: {Default: true, PreRelease: featuregate.Beta}, // on by default in 1.22 + + EndpointSliceTerminatingCondition: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in v1.28 + + DynamicResourceAllocation: {Default: false, PreRelease: featuregate.Alpha}, + + EphemeralContainers: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.27 + + EventedPLEG: {Default: false, PreRelease: featuregate.Alpha}, + + ExecProbeTimeout: {Default: true, PreRelease: featuregate.GA}, // lock to default and remove after v1.22 based on KEP #1972 update + + ExpandCSIVolumes: {Default: true, PreRelease: featuregate.GA}, // remove in 1.26 + + ExpandInUsePersistentVolumes: {Default: true, PreRelease: featuregate.GA}, // remove in 1.26 + + ExpandPersistentVolumes: {Default: true, PreRelease: featuregate.GA}, // remove in 1.26 + + ExpandedDNSConfig: {Default: true, PreRelease: featuregate.Beta}, + + ExperimentalHostUserNamespaceDefaultingGate: {Default: false, PreRelease: featuregate.Beta}, + + GRPCContainerProbe: {Default: true, PreRelease: featuregate.Beta}, + + GracefulNodeShutdown: {Default: true, PreRelease: featuregate.Beta}, + + GracefulNodeShutdownBasedOnPodPriority: {Default: true, PreRelease: featuregate.Beta}, + + HPAContainerMetrics: {Default: false, PreRelease: featuregate.Alpha}, + + HonorPVReclaimPolicy: {Default: false, PreRelease: featuregate.Alpha}, + + IdentifyPodOS: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.27 + + InTreePluginAWSUnregister: {Default: false, PreRelease: featuregate.Alpha}, + + InTreePluginAzureDiskUnregister: {Default: false, PreRelease: featuregate.Alpha}, + + InTreePluginAzureFileUnregister: {Default: false, PreRelease: featuregate.Alpha}, + + InTreePluginGCEUnregister: {Default: false, PreRelease: featuregate.Alpha}, + + InTreePluginOpenStackUnregister: {Default: false, PreRelease: featuregate.Alpha}, + + InTreePluginPortworxUnregister: {Default: false, PreRelease: featuregate.Alpha}, + + InTreePluginRBDUnregister: {Default: false, PreRelease: featuregate.Alpha}, + + InTreePluginvSphereUnregister: {Default: false, PreRelease: featuregate.Alpha}, + + IPTablesOwnershipCleanup: {Default: false, PreRelease: featuregate.Alpha}, + + JobPodFailurePolicy: {Default: true, PreRelease: featuregate.Beta}, + + JobMutableNodeSchedulingDirectives: {Default: true, PreRelease: featuregate.Beta}, + + JobReadyPods: {Default: true, PreRelease: featuregate.Beta}, + + JobTrackingWithFinalizers: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.28 + + KubeletCredentialProviders: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.28 + + KubeletInUserNamespace: {Default: false, PreRelease: featuregate.Alpha}, + + KubeletPodResources: {Default: true, PreRelease: featuregate.Beta}, + + KubeletPodResourcesGetAllocatable: {Default: true, PreRelease: featuregate.Beta}, + + KubeletTracing: {Default: false, PreRelease: featuregate.Alpha}, + + LegacyServiceAccountTokenNoAutoGeneration: {Default: true, PreRelease: featuregate.GA}, + + LegacyServiceAccountTokenTracking: {Default: false, PreRelease: featuregate.Alpha}, + + LocalStorageCapacityIsolation: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.27 + + LocalStorageCapacityIsolationFSQuotaMonitoring: {Default: false, PreRelease: featuregate.Alpha}, + + LogarithmicScaleDown: {Default: true, PreRelease: featuregate.Beta}, + + MatchLabelKeysInPodTopologySpread: {Default: false, PreRelease: featuregate.Alpha}, + + MaxUnavailableStatefulSet: {Default: false, PreRelease: featuregate.Alpha}, + + MemoryManager: {Default: true, PreRelease: featuregate.Beta}, + + MemoryQoS: {Default: false, PreRelease: featuregate.Alpha}, + + MinDomainsInPodTopologySpread: {Default: false, PreRelease: featuregate.Beta}, + + MinimizeIPTablesRestore: {Default: false, PreRelease: featuregate.Alpha}, + + MixedProtocolLBService: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.28 + + MultiCIDRRangeAllocator: {Default: false, PreRelease: featuregate.Alpha}, + + NetworkPolicyEndPort: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.27 + + NetworkPolicyStatus: {Default: false, PreRelease: featuregate.Alpha}, + + NodeOutOfServiceVolumeDetach: {Default: true, PreRelease: featuregate.Beta}, + + NodeSwap: {Default: false, PreRelease: featuregate.Alpha}, + + PDBUnhealthyPodEvictionPolicy: {Default: false, PreRelease: featuregate.Alpha}, + + PodAndContainerStatsFromCRI: {Default: false, PreRelease: featuregate.Alpha}, + + PodDeletionCost: {Default: true, PreRelease: featuregate.Beta}, + + PodDisruptionConditions: {Default: true, PreRelease: featuregate.Beta}, + + PodHasNetworkCondition: {Default: false, PreRelease: featuregate.Alpha}, + + PodSchedulingReadiness: {Default: false, PreRelease: featuregate.Alpha}, + + PodSecurity: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, + + ProbeTerminationGracePeriod: {Default: true, PreRelease: featuregate.Beta}, // Default to true in beta 1.25 + + ProcMountType: {Default: false, PreRelease: featuregate.Alpha}, + + ProxyTerminatingEndpoints: {Default: true, PreRelease: featuregate.Beta}, + + QOSReserved: {Default: false, PreRelease: featuregate.Alpha}, + + ReadWriteOncePod: {Default: false, PreRelease: featuregate.Alpha}, + + RecoverVolumeExpansionFailure: {Default: false, PreRelease: featuregate.Alpha}, + + RetroactiveDefaultStorageClass: {Default: true, PreRelease: featuregate.Beta}, + + RotateKubeletServerCertificate: {Default: true, PreRelease: featuregate.Beta}, + + SeccompDefault: {Default: true, PreRelease: featuregate.Beta}, + + ServiceIPStaticSubrange: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.28 + + ServiceInternalTrafficPolicy: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.28 + + SizeMemoryBackedVolumes: {Default: true, PreRelease: featuregate.Beta}, + + StatefulSetAutoDeletePVC: {Default: false, PreRelease: featuregate.Alpha}, + + StatefulSetMinReadySeconds: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.27 + + StatefulSetStartOrdinal: {Default: false, PreRelease: featuregate.Alpha}, + + TopologyAwareHints: {Default: true, PreRelease: featuregate.Beta}, + + TopologyManager: {Default: true, PreRelease: featuregate.Beta}, + + TopologyManagerPolicyAlphaOptions: {Default: false, PreRelease: featuregate.Alpha}, + + TopologyManagerPolicyBetaOptions: {Default: false, PreRelease: featuregate.Beta}, + + TopologyManagerPolicyOptions: {Default: false, PreRelease: featuregate.Alpha}, + + VolumeCapacityPriority: {Default: false, PreRelease: featuregate.Alpha}, + + UserNamespacesStatelessPodsSupport: {Default: false, PreRelease: featuregate.Alpha}, + + WinDSR: {Default: false, PreRelease: featuregate.Alpha}, + + WinOverlay: {Default: true, PreRelease: featuregate.Beta}, + + WindowsHostNetwork: {Default: true, PreRelease: featuregate.Alpha}, + + WindowsHostProcessContainers: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.28 + + NodeInclusionPolicyInPodTopologySpread: {Default: true, PreRelease: featuregate.Beta}, + + SELinuxMountReadWriteOncePod: {Default: false, PreRelease: featuregate.Alpha}, + + // inherited features from generic apiserver, relisted here to get a conflict if it is changed + // unintentionally on either side: + + genericfeatures.AggregatedDiscoveryEndpoint: {Default: false, PreRelease: featuregate.Alpha}, + + genericfeatures.APIListChunking: {Default: true, PreRelease: featuregate.Beta}, + + genericfeatures.APIPriorityAndFairness: {Default: true, PreRelease: featuregate.Beta}, + + genericfeatures.APIResponseCompression: {Default: true, PreRelease: featuregate.Beta}, + + genericfeatures.AdvancedAuditing: {Default: true, PreRelease: featuregate.GA}, + + genericfeatures.ValidatingAdmissionPolicy: {Default: false, PreRelease: featuregate.Alpha}, + + genericfeatures.CustomResourceValidationExpressions: {Default: true, PreRelease: featuregate.Beta}, + + genericfeatures.DryRun: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.28 + + genericfeatures.OpenAPIEnums: {Default: true, PreRelease: featuregate.Beta}, + + genericfeatures.OpenAPIV3: {Default: true, PreRelease: featuregate.Beta}, + + genericfeatures.ServerSideApply: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.29 + + genericfeatures.ServerSideFieldValidation: {Default: true, PreRelease: featuregate.Beta}, + + // features that enable backwards compatibility but are scheduled to be removed + // ... + HPAScaleToZero: {Default: false, PreRelease: featuregate.Alpha}, +} diff --git a/vendor/k8s.io/kubernetes/pkg/fieldpath/doc.go b/vendor/k8s.io/kubernetes/pkg/fieldpath/doc.go new file mode 100644 index 000000000..400d001e7 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/fieldpath/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2015 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 fieldpath supplies methods for extracting fields from objects +// given a path to a field. +package fieldpath // import "k8s.io/kubernetes/pkg/fieldpath" diff --git a/vendor/k8s.io/kubernetes/pkg/fieldpath/fieldpath.go b/vendor/k8s.io/kubernetes/pkg/fieldpath/fieldpath.go new file mode 100644 index 000000000..20fa8eaaa --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/fieldpath/fieldpath.go @@ -0,0 +1,110 @@ +/* +Copyright 2015 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 fieldpath + +import ( + "fmt" + "strings" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/validation" +) + +// FormatMap formats map[string]string to a string. +func FormatMap(m map[string]string) (fmtStr string) { + // output with keys in sorted order to provide stable output + keys := sets.NewString() + for key := range m { + keys.Insert(key) + } + for _, key := range keys.List() { + fmtStr += fmt.Sprintf("%v=%q\n", key, m[key]) + } + fmtStr = strings.TrimSuffix(fmtStr, "\n") + + return +} + +// ExtractFieldPathAsString extracts the field from the given object +// and returns it as a string. The object must be a pointer to an +// API type. +func ExtractFieldPathAsString(obj interface{}, fieldPath string) (string, error) { + accessor, err := meta.Accessor(obj) + if err != nil { + return "", err + } + + if path, subscript, ok := SplitMaybeSubscriptedPath(fieldPath); ok { + switch path { + case "metadata.annotations": + if errs := validation.IsQualifiedName(strings.ToLower(subscript)); len(errs) != 0 { + return "", fmt.Errorf("invalid key subscript in %s: %s", fieldPath, strings.Join(errs, ";")) + } + return accessor.GetAnnotations()[subscript], nil + case "metadata.labels": + if errs := validation.IsQualifiedName(subscript); len(errs) != 0 { + return "", fmt.Errorf("invalid key subscript in %s: %s", fieldPath, strings.Join(errs, ";")) + } + return accessor.GetLabels()[subscript], nil + default: + return "", fmt.Errorf("fieldPath %q does not support subscript", fieldPath) + } + } + + switch fieldPath { + case "metadata.annotations": + return FormatMap(accessor.GetAnnotations()), nil + case "metadata.labels": + return FormatMap(accessor.GetLabels()), nil + case "metadata.name": + return accessor.GetName(), nil + case "metadata.namespace": + return accessor.GetNamespace(), nil + case "metadata.uid": + return string(accessor.GetUID()), nil + } + + return "", fmt.Errorf("unsupported fieldPath: %v", fieldPath) +} + +// SplitMaybeSubscriptedPath checks whether the specified fieldPath is +// subscripted, and +// - if yes, this function splits the fieldPath into path and subscript, and +// returns (path, subscript, true). +// - if no, this function returns (fieldPath, "", false). +// +// Example inputs and outputs: +// +// "metadata.annotations['myKey']" --> ("metadata.annotations", "myKey", true) +// "metadata.annotations['a[b]c']" --> ("metadata.annotations", "a[b]c", true) +// "metadata.labels['']" --> ("metadata.labels", "", true) +// "metadata.labels" --> ("metadata.labels", "", false) +func SplitMaybeSubscriptedPath(fieldPath string) (string, string, bool) { + if !strings.HasSuffix(fieldPath, "']") { + return fieldPath, "", false + } + s := strings.TrimSuffix(fieldPath, "']") + parts := strings.SplitN(s, "['", 2) + if len(parts) < 2 { + return fieldPath, "", false + } + if len(parts[0]) == 0 { + return fieldPath, "", false + } + return parts[0], parts[1], true +} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/server/metrics/metrics.go b/vendor/k8s.io/kubernetes/pkg/kubelet/server/metrics/metrics.go new file mode 100644 index 000000000..e9a2b5fca --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/server/metrics/metrics.go @@ -0,0 +1,101 @@ +/* +Copyright 2019 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 metrics + +import ( + "sync" + "time" + + "k8s.io/component-base/metrics" + "k8s.io/component-base/metrics/legacyregistry" +) + +const ( + kubeletSubsystem = "kubelet" +) + +var ( + // HTTPRequests tracks the number of the http requests received since the server started. + HTTPRequests = metrics.NewCounterVec( + &metrics.CounterOpts{ + Subsystem: kubeletSubsystem, + Name: "http_requests_total", + Help: "Number of the http requests received since the server started", + StabilityLevel: metrics.ALPHA, + }, + // server_type aims to differentiate the readonly server and the readwrite server. + // long_running marks whether the request is long-running or not. + // Currently, long-running requests include exec/attach/portforward/debug. + []string{"method", "path", "server_type", "long_running"}, + ) + // HTTPRequestsDuration tracks the duration in seconds to serve http requests. + HTTPRequestsDuration = metrics.NewHistogramVec( + &metrics.HistogramOpts{ + Subsystem: kubeletSubsystem, + Name: "http_requests_duration_seconds", + Help: "Duration in seconds to serve http requests", + // Use DefBuckets for now, will customize the buckets if necessary. + Buckets: metrics.DefBuckets, + StabilityLevel: metrics.ALPHA, + }, + []string{"method", "path", "server_type", "long_running"}, + ) + // HTTPInflightRequests tracks the number of the inflight http requests. + HTTPInflightRequests = metrics.NewGaugeVec( + &metrics.GaugeOpts{ + Subsystem: kubeletSubsystem, + Name: "http_inflight_requests", + Help: "Number of the inflight http requests", + StabilityLevel: metrics.ALPHA, + }, + []string{"method", "path", "server_type", "long_running"}, + ) + // VolumeStatCalDuration tracks the duration in seconds to calculate volume stats. + // this metric is mainly for comparison between fsquota monitoring and `du` for disk usage. + VolumeStatCalDuration = metrics.NewHistogramVec( + &metrics.HistogramOpts{ + Subsystem: kubeletSubsystem, + Name: "volume_metric_collection_duration_seconds", + Help: "Duration in seconds to calculate volume stats", + Buckets: metrics.DefBuckets, + StabilityLevel: metrics.ALPHA, + }, + []string{"metric_source"}, + ) +) + +var registerMetrics sync.Once + +// Register all metrics. +func Register() { + registerMetrics.Do(func() { + legacyregistry.MustRegister(HTTPRequests) + legacyregistry.MustRegister(HTTPRequestsDuration) + legacyregistry.MustRegister(HTTPInflightRequests) + legacyregistry.MustRegister(VolumeStatCalDuration) + }) +} + +// SinceInSeconds gets the time since the specified start in seconds. +func SinceInSeconds(start time.Time) float64 { + return time.Since(start).Seconds() +} + +// CollectVolumeStatCalDuration collects the duration in seconds to calculate volume stats. +func CollectVolumeStatCalDuration(metricSource string, start time.Time) { + VolumeStatCalDuration.WithLabelValues(metricSource).Observe(SinceInSeconds(start)) +} diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/util/endpoints.go b/vendor/k8s.io/kubernetes/pkg/proxy/util/endpoints.go new file mode 100644 index 000000000..d5e08e4c1 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/proxy/util/endpoints.go @@ -0,0 +1,64 @@ +/* +Copyright 2017 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 util + +import ( + "net" + "strconv" + + "k8s.io/klog/v2" + netutils "k8s.io/utils/net" +) + +// IPPart returns just the IP part of an IP or IP:port or endpoint string. If the IP +// part is an IPv6 address enclosed in brackets (e.g. "[fd00:1::5]:9999"), +// then the brackets are stripped as well. +func IPPart(s string) string { + if ip := netutils.ParseIPSloppy(s); ip != nil { + // IP address without port + return s + } + // Must be IP:port + host, _, err := net.SplitHostPort(s) + if err != nil { + klog.ErrorS(err, "Failed to parse host-port", "input", s) + return "" + } + // Check if host string is a valid IP address + ip := netutils.ParseIPSloppy(host) + if ip == nil { + klog.ErrorS(nil, "Failed to parse IP", "input", host) + return "" + } + return ip.String() +} + +// PortPart returns just the port part of an endpoint string. +func PortPart(s string) (int, error) { + // Must be IP:port + _, port, err := net.SplitHostPort(s) + if err != nil { + klog.ErrorS(err, "Failed to parse host-port", "input", s) + return -1, err + } + portNumber, err := strconv.Atoi(port) + if err != nil { + klog.ErrorS(err, "Failed to parse port", "input", port) + return -1, err + } + return portNumber, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/util/network.go b/vendor/k8s.io/kubernetes/pkg/proxy/util/network.go new file mode 100644 index 000000000..9d46da039 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/proxy/util/network.go @@ -0,0 +1,39 @@ +/* +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 util + +import ( + "net" +) + +// NetworkInterfacer defines an interface for several net library functions. Production +// code will forward to net library functions, and unit tests will override the methods +// for testing purposes. +type NetworkInterfacer interface { + InterfaceAddrs() ([]net.Addr, error) +} + +// RealNetwork implements the NetworkInterfacer interface for production code, just +// wrapping the underlying net library function calls. +type RealNetwork struct{} + +// InterfaceAddrs wraps net.InterfaceAddrs(), it's a part of NetworkInterfacer interface. +func (RealNetwork) InterfaceAddrs() ([]net.Addr, error) { + return net.InterfaceAddrs() +} + +var _ NetworkInterfacer = &RealNetwork{} diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/util/utils.go b/vendor/k8s.io/kubernetes/pkg/proxy/util/utils.go new file mode 100644 index 000000000..92ef46580 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/proxy/util/utils.go @@ -0,0 +1,598 @@ +/* +Copyright 2017 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 util + +import ( + "bytes" + "context" + "errors" + "fmt" + "net" + "net/http" + "strconv" + "strings" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + utilrand "k8s.io/apimachinery/pkg/util/rand" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/client-go/tools/events" + utilsysctl "k8s.io/component-helpers/node/util/sysctl" + helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" + netutils "k8s.io/utils/net" + + "k8s.io/klog/v2" +) + +const ( + // IPv4ZeroCIDR is the CIDR block for the whole IPv4 address space + IPv4ZeroCIDR = "0.0.0.0/0" + + // IPv6ZeroCIDR is the CIDR block for the whole IPv6 address space + IPv6ZeroCIDR = "::/0" +) + +var ( + // ErrAddressNotAllowed indicates the address is not allowed + ErrAddressNotAllowed = errors.New("address not allowed") + + // ErrNoAddresses indicates there are no addresses for the hostname + ErrNoAddresses = errors.New("no addresses for hostname") +) + +// isValidEndpoint checks that the given host / port pair are valid endpoint +func isValidEndpoint(host string, port int) bool { + return host != "" && port > 0 +} + +// BuildPortsToEndpointsMap builds a map of portname -> all ip:ports for that +// portname. Explode Endpoints.Subsets[*] into this structure. +func BuildPortsToEndpointsMap(endpoints *v1.Endpoints) map[string][]string { + portsToEndpoints := map[string][]string{} + for i := range endpoints.Subsets { + ss := &endpoints.Subsets[i] + for i := range ss.Ports { + port := &ss.Ports[i] + for i := range ss.Addresses { + addr := &ss.Addresses[i] + if isValidEndpoint(addr.IP, int(port.Port)) { + portsToEndpoints[port.Name] = append(portsToEndpoints[port.Name], net.JoinHostPort(addr.IP, strconv.Itoa(int(port.Port)))) + } + } + } + } + return portsToEndpoints +} + +// ContainsIPv4Loopback returns true if the input is empty or one of the CIDR contains an IPv4 loopback address. +func ContainsIPv4Loopback(cidrStrings []string) bool { + if len(cidrStrings) == 0 { + return true + } + // RFC 5735 127.0.0.0/8 - This block is assigned for use as the Internet host loopback address + ipv4LoopbackStart := netutils.ParseIPSloppy("127.0.0.0") + for _, cidr := range cidrStrings { + if IsZeroCIDR(cidr) { + return true + } + + ip, ipnet, err := netutils.ParseCIDRSloppy(cidr) + if err != nil { + continue + } + + if netutils.IsIPv6CIDR(ipnet) { + continue + } + + if ip.IsLoopback() { + return true + } + if ipnet.Contains(ipv4LoopbackStart) { + return true + } + } + return false +} + +// IsZeroCIDR checks whether the input CIDR string is either +// the IPv4 or IPv6 zero CIDR +func IsZeroCIDR(cidr string) bool { + if cidr == IPv4ZeroCIDR || cidr == IPv6ZeroCIDR { + return true + } + return false +} + +// IsLoopBack checks if a given IP address is a loopback address. +func IsLoopBack(ip string) bool { + netIP := netutils.ParseIPSloppy(ip) + if netIP != nil { + return netIP.IsLoopback() + } + return false +} + +// IsProxyableIP checks if a given IP address is permitted to be proxied +func IsProxyableIP(ip string) error { + netIP := netutils.ParseIPSloppy(ip) + if netIP == nil { + return ErrAddressNotAllowed + } + return isProxyableIP(netIP) +} + +func isProxyableIP(ip net.IP) error { + if !ip.IsGlobalUnicast() { + return ErrAddressNotAllowed + } + return nil +} + +// Resolver is an interface for net.Resolver +type Resolver interface { + LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error) +} + +// IsProxyableHostname checks if the IP addresses for a given hostname are permitted to be proxied +func IsProxyableHostname(ctx context.Context, resolv Resolver, hostname string) error { + resp, err := resolv.LookupIPAddr(ctx, hostname) + if err != nil { + return err + } + + if len(resp) == 0 { + return ErrNoAddresses + } + + for _, host := range resp { + if err := isProxyableIP(host.IP); err != nil { + return err + } + } + return nil +} + +// IsAllowedHost checks if the given IP host address is in a network in the denied list. +func IsAllowedHost(host net.IP, denied []*net.IPNet) error { + for _, ipNet := range denied { + if ipNet.Contains(host) { + return ErrAddressNotAllowed + } + } + return nil +} + +// GetLocalAddrs returns a list of all network addresses on the local system +func GetLocalAddrs() ([]net.IP, error) { + var localAddrs []net.IP + + addrs, err := net.InterfaceAddrs() + if err != nil { + return nil, err + } + + for _, addr := range addrs { + ip, _, err := netutils.ParseCIDRSloppy(addr.String()) + if err != nil { + return nil, err + } + + localAddrs = append(localAddrs, ip) + } + + return localAddrs, nil +} + +// GetLocalAddrSet return a local IPSet. +// If failed to get local addr, will assume no local ips. +func GetLocalAddrSet() netutils.IPSet { + localAddrs, err := GetLocalAddrs() + if err != nil { + klog.ErrorS(err, "Failed to get local addresses assuming no local IPs") + } else if len(localAddrs) == 0 { + klog.InfoS("No local addresses were found") + } + + localAddrSet := netutils.IPSet{} + localAddrSet.Insert(localAddrs...) + return localAddrSet +} + +// ShouldSkipService checks if a given service should skip proxying +func ShouldSkipService(service *v1.Service) bool { + // if ClusterIP is "None" or empty, skip proxying + if !helper.IsServiceIPSet(service) { + klog.V(3).InfoS("Skipping service due to cluster IP", "service", klog.KObj(service), "clusterIP", service.Spec.ClusterIP) + return true + } + // Even if ClusterIP is set, ServiceTypeExternalName services don't get proxied + if service.Spec.Type == v1.ServiceTypeExternalName { + klog.V(3).InfoS("Skipping service due to Type=ExternalName", "service", klog.KObj(service)) + return true + } + return false +} + +// GetNodeAddresses return all matched node IP addresses based on given cidr slice. +// Some callers, e.g. IPVS proxier, need concrete IPs, not ranges, which is why this exists. +// NetworkInterfacer is injected for test purpose. +// We expect the cidrs passed in is already validated. +// Given an empty input `[]`, it will return `0.0.0.0/0` and `::/0` directly. +// If multiple cidrs is given, it will return the minimal IP sets, e.g. given input `[1.2.0.0/16, 0.0.0.0/0]`, it will +// only return `0.0.0.0/0`. +// NOTE: GetNodeAddresses only accepts CIDRs, if you want concrete IPs, e.g. 1.2.3.4, then the input should be 1.2.3.4/32. +func GetNodeAddresses(cidrs []string, nw NetworkInterfacer) (sets.String, error) { + uniqueAddressList := sets.NewString() + if len(cidrs) == 0 { + uniqueAddressList.Insert(IPv4ZeroCIDR) + uniqueAddressList.Insert(IPv6ZeroCIDR) + return uniqueAddressList, nil + } + // First round of iteration to pick out `0.0.0.0/0` or `::/0` for the sake of excluding non-zero IPs. + for _, cidr := range cidrs { + if IsZeroCIDR(cidr) { + uniqueAddressList.Insert(cidr) + } + } + + addrs, err := nw.InterfaceAddrs() + if err != nil { + return nil, fmt.Errorf("error listing all interfaceAddrs from host, error: %v", err) + } + + // Second round of iteration to parse IPs based on cidr. + for _, cidr := range cidrs { + if IsZeroCIDR(cidr) { + continue + } + + _, ipNet, _ := netutils.ParseCIDRSloppy(cidr) + for _, addr := range addrs { + var ip net.IP + // nw.InterfaceAddrs may return net.IPAddr or net.IPNet on windows, and it will return net.IPNet on linux. + switch v := addr.(type) { + case *net.IPAddr: + ip = v.IP + case *net.IPNet: + ip = v.IP + default: + continue + } + + if ipNet.Contains(ip) { + if netutils.IsIPv6(ip) && !uniqueAddressList.Has(IPv6ZeroCIDR) { + uniqueAddressList.Insert(ip.String()) + } + if !netutils.IsIPv6(ip) && !uniqueAddressList.Has(IPv4ZeroCIDR) { + uniqueAddressList.Insert(ip.String()) + } + } + } + } + + if uniqueAddressList.Len() == 0 { + return nil, fmt.Errorf("no addresses found for cidrs %v", cidrs) + } + + return uniqueAddressList, nil +} + +// AddressSet validates the addresses in the slice using the "isValid" function. +// Addresses that pass the validation are returned as a string Set. +func AddressSet(isValid func(ip net.IP) bool, addrs []net.Addr) sets.String { + ips := sets.NewString() + for _, a := range addrs { + var ip net.IP + switch v := a.(type) { + case *net.IPAddr: + ip = v.IP + case *net.IPNet: + ip = v.IP + default: + continue + } + if isValid(ip) { + ips.Insert(ip.String()) + } + } + return ips +} + +// LogAndEmitIncorrectIPVersionEvent logs and emits incorrect IP version event. +func LogAndEmitIncorrectIPVersionEvent(recorder events.EventRecorder, fieldName, fieldValue, svcNamespace, svcName string, svcUID types.UID) { + errMsg := fmt.Sprintf("%s in %s has incorrect IP version", fieldValue, fieldName) + klog.ErrorS(nil, "Incorrect IP version", "service", klog.KRef(svcNamespace, svcName), "field", fieldName, "value", fieldValue) + if recorder != nil { + recorder.Eventf( + &v1.ObjectReference{ + Kind: "Service", + Name: svcName, + Namespace: svcNamespace, + UID: svcUID, + }, nil, v1.EventTypeWarning, "KubeProxyIncorrectIPVersion", "GatherEndpoints", errMsg) + } +} + +// MapIPsByIPFamily maps a slice of IPs to their respective IP families (v4 or v6) +func MapIPsByIPFamily(ipStrings []string) map[v1.IPFamily][]string { + ipFamilyMap := map[v1.IPFamily][]string{} + for _, ip := range ipStrings { + // Handle only the valid IPs + if ipFamily, err := getIPFamilyFromIP(ip); err == nil { + ipFamilyMap[ipFamily] = append(ipFamilyMap[ipFamily], ip) + } else { + // this function is called in multiple places. All of which + // have sanitized data. Except the case of ExternalIPs which is + // not validated by api-server. Specifically empty strings + // validation. Which yields into a lot of bad error logs. + // check for empty string + if len(strings.TrimSpace(ip)) != 0 { + klog.ErrorS(nil, "Skipping invalid IP", "ip", ip) + + } + } + } + return ipFamilyMap +} + +// MapCIDRsByIPFamily maps a slice of IPs to their respective IP families (v4 or v6) +func MapCIDRsByIPFamily(cidrStrings []string) map[v1.IPFamily][]string { + ipFamilyMap := map[v1.IPFamily][]string{} + for _, cidr := range cidrStrings { + // Handle only the valid CIDRs + if ipFamily, err := getIPFamilyFromCIDR(cidr); err == nil { + ipFamilyMap[ipFamily] = append(ipFamilyMap[ipFamily], cidr) + } else { + klog.ErrorS(nil, "Skipping invalid CIDR", "cidr", cidr) + } + } + return ipFamilyMap +} + +func getIPFamilyFromIP(ipStr string) (v1.IPFamily, error) { + netIP := netutils.ParseIPSloppy(ipStr) + if netIP == nil { + return "", ErrAddressNotAllowed + } + + if netutils.IsIPv6(netIP) { + return v1.IPv6Protocol, nil + } + return v1.IPv4Protocol, nil +} + +func getIPFamilyFromCIDR(cidrStr string) (v1.IPFamily, error) { + _, netCIDR, err := netutils.ParseCIDRSloppy(cidrStr) + if err != nil { + return "", ErrAddressNotAllowed + } + if netutils.IsIPv6CIDR(netCIDR) { + return v1.IPv6Protocol, nil + } + return v1.IPv4Protocol, nil +} + +// OtherIPFamily returns the other ip family +func OtherIPFamily(ipFamily v1.IPFamily) v1.IPFamily { + if ipFamily == v1.IPv6Protocol { + return v1.IPv4Protocol + } + + return v1.IPv6Protocol +} + +// AppendPortIfNeeded appends the given port to IP address unless it is already in +// "ipv4:port" or "[ipv6]:port" format. +func AppendPortIfNeeded(addr string, port int32) string { + // Return if address is already in "ipv4:port" or "[ipv6]:port" format. + if _, _, err := net.SplitHostPort(addr); err == nil { + return addr + } + + // Simply return for invalid case. This should be caught by validation instead. + ip := netutils.ParseIPSloppy(addr) + if ip == nil { + return addr + } + + // Append port to address. + if ip.To4() != nil { + return fmt.Sprintf("%s:%d", addr, port) + } + return fmt.Sprintf("[%s]:%d", addr, port) +} + +// ShuffleStrings copies strings from the specified slice into a copy in random +// order. It returns a new slice. +func ShuffleStrings(s []string) []string { + if s == nil { + return nil + } + shuffled := make([]string, len(s)) + perm := utilrand.Perm(len(s)) + for i, j := range perm { + shuffled[j] = s[i] + } + return shuffled +} + +// EnsureSysctl sets a kernel sysctl to a given numeric value. +func EnsureSysctl(sysctl utilsysctl.Interface, name string, newVal int) error { + if oldVal, _ := sysctl.GetSysctl(name); oldVal != newVal { + if err := sysctl.SetSysctl(name, newVal); err != nil { + return fmt.Errorf("can't set sysctl %s to %d: %v", name, newVal, err) + } + klog.V(1).InfoS("Changed sysctl", "name", name, "before", oldVal, "after", newVal) + } + return nil +} + +// DialContext is a dial function matching the signature of net.Dialer.DialContext. +type DialContext = func(context.Context, string, string) (net.Conn, error) + +// FilteredDialOptions configures how a DialContext is wrapped by NewFilteredDialContext. +type FilteredDialOptions struct { + // DialHostIPDenylist restricts hosts from being dialed. + DialHostCIDRDenylist []*net.IPNet + // AllowLocalLoopback controls connections to local loopback hosts (as defined by + // IsProxyableIP). + AllowLocalLoopback bool +} + +// NewFilteredDialContext returns a DialContext function that filters connections based on a FilteredDialOptions. +func NewFilteredDialContext(wrapped DialContext, resolv Resolver, opts *FilteredDialOptions) DialContext { + if wrapped == nil { + wrapped = http.DefaultTransport.(*http.Transport).DialContext + } + if opts == nil { + // Do no filtering + return wrapped + } + if resolv == nil { + resolv = net.DefaultResolver + } + if len(opts.DialHostCIDRDenylist) == 0 && opts.AllowLocalLoopback { + // Do no filtering. + return wrapped + } + return func(ctx context.Context, network, address string) (net.Conn, error) { + // DialContext is given host:port. LookupIPAddress expects host. + addressToResolve, _, err := net.SplitHostPort(address) + if err != nil { + addressToResolve = address + } + + resp, err := resolv.LookupIPAddr(ctx, addressToResolve) + if err != nil { + return nil, err + } + + if len(resp) == 0 { + return nil, ErrNoAddresses + } + + for _, host := range resp { + if !opts.AllowLocalLoopback { + if err := isProxyableIP(host.IP); err != nil { + return nil, err + } + } + if opts.DialHostCIDRDenylist != nil { + if err := IsAllowedHost(host.IP, opts.DialHostCIDRDenylist); err != nil { + return nil, err + } + } + } + return wrapped(ctx, network, address) + } +} + +// GetClusterIPByFamily returns a service clusterip by family +func GetClusterIPByFamily(ipFamily v1.IPFamily, service *v1.Service) string { + // allowing skew + if len(service.Spec.IPFamilies) == 0 { + if len(service.Spec.ClusterIP) == 0 || service.Spec.ClusterIP == v1.ClusterIPNone { + return "" + } + + IsIPv6Family := (ipFamily == v1.IPv6Protocol) + if IsIPv6Family == netutils.IsIPv6String(service.Spec.ClusterIP) { + return service.Spec.ClusterIP + } + + return "" + } + + for idx, family := range service.Spec.IPFamilies { + if family == ipFamily { + if idx < len(service.Spec.ClusterIPs) { + return service.Spec.ClusterIPs[idx] + } + } + } + + return "" +} + +type LineBuffer struct { + b bytes.Buffer + lines int +} + +// Write takes a list of arguments, each a string or []string, joins all the +// individual strings with spaces, terminates with newline, and writes to buf. +// Any other argument type will panic. +func (buf *LineBuffer) Write(args ...interface{}) { + for i, arg := range args { + if i > 0 { + buf.b.WriteByte(' ') + } + switch x := arg.(type) { + case string: + buf.b.WriteString(x) + case []string: + for j, s := range x { + if j > 0 { + buf.b.WriteByte(' ') + } + buf.b.WriteString(s) + } + default: + panic(fmt.Sprintf("unknown argument type: %T", x)) + } + } + buf.b.WriteByte('\n') + buf.lines++ +} + +// WriteBytes writes bytes to buffer, and terminates with newline. +func (buf *LineBuffer) WriteBytes(bytes []byte) { + buf.b.Write(bytes) + buf.b.WriteByte('\n') + buf.lines++ +} + +// Reset clears buf +func (buf *LineBuffer) Reset() { + buf.b.Reset() + buf.lines = 0 +} + +// Bytes returns the contents of buf as a []byte +func (buf *LineBuffer) Bytes() []byte { + return buf.b.Bytes() +} + +// Lines returns the number of lines in buf. Note that more precisely, this returns the +// number of times Write() or WriteBytes() was called; it assumes that you never wrote +// any newlines to the buffer yourself. +func (buf *LineBuffer) Lines() int { + return buf.lines +} + +// RevertPorts is closing ports in replacementPortsMap but not in originalPortsMap. In other words, it only +// closes the ports opened in this sync. +func RevertPorts(replacementPortsMap, originalPortsMap map[netutils.LocalPort]netutils.Closeable) { + for k, v := range replacementPortsMap { + // Only close newly opened local ports - leave ones that were open before this update + if originalPortsMap[k] == nil { + klog.V(2).InfoS("Closing local port", "port", k.String()) + v.Close() + } + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/OWNERS b/vendor/k8s.io/kubernetes/pkg/scheduler/OWNERS new file mode 100644 index 000000000..19c02ee0b --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/OWNERS @@ -0,0 +1,8 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +approvers: + - sig-scheduling-maintainers +reviewers: + - sig-scheduling +labels: + - sig/scheduling diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/OWNERS b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/OWNERS new file mode 100644 index 000000000..3023c572e --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/OWNERS @@ -0,0 +1,11 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +approvers: + - api-approvers +reviewers: + - api-reviewers + - sig-scheduling-api-reviewers + - sig-scheduling-api-approvers +labels: + - kind/api-change + - sig/scheduling diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/doc.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/doc.go new file mode 100644 index 000000000..896eaa83b --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/doc.go @@ -0,0 +1,20 @@ +/* +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. +*/ + +// +k8s:deepcopy-gen=package +// +groupName=kubescheduler.config.k8s.io + +package config // import "k8s.io/kubernetes/pkg/scheduler/apis/config" diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/latest/latest.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/latest/latest.go new file mode 100644 index 000000000..49c196c8a --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/latest/latest.go @@ -0,0 +1,43 @@ +/* +Copyright 2021 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 latest + +import ( + "k8s.io/component-base/config/v1alpha1" + v1 "k8s.io/kube-scheduler/config/v1" + "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/kubernetes/pkg/scheduler/apis/config/scheme" +) + +// Default creates a default configuration of the latest versioned type. +// This function needs to be updated whenever we bump the scheduler's component config version. +func Default() (*config.KubeSchedulerConfiguration, error) { + versionedCfg := v1.KubeSchedulerConfiguration{} + versionedCfg.DebuggingConfiguration = *v1alpha1.NewRecommendedDebuggingConfiguration() + + scheme.Scheme.Default(&versionedCfg) + cfg := config.KubeSchedulerConfiguration{} + if err := scheme.Scheme.Convert(&versionedCfg, &cfg, nil); err != nil { + return nil, err + } + // We don't set this field in pkg/scheduler/apis/config/{version}/conversion.go + // because the field will be cleared later by API machinery during + // conversion. See KubeSchedulerConfiguration internal type definition for + // more details. + cfg.TypeMeta.APIVersion = v1.SchemeGroupVersion.String() + return &cfg, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/register.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/register.go new file mode 100644 index 000000000..457556e10 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/register.go @@ -0,0 +1,50 @@ +/* +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 config + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// GroupName is the group name used in this package +const GroupName = "kubescheduler.config.k8s.io" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal} + +var ( + // SchemeBuilder is the scheme builder with scheme init functions to run for this API package + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + // AddToScheme is a global function that registers this API group & version to a scheme + AddToScheme = SchemeBuilder.AddToScheme +) + +// addKnownTypes registers known types to the given scheme +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &KubeSchedulerConfiguration{}, + &DefaultPreemptionArgs{}, + &InterPodAffinityArgs{}, + &NodeResourcesFitArgs{}, + &PodTopologySpreadArgs{}, + &VolumeBindingArgs{}, + &NodeResourcesBalancedAllocationArgs{}, + &NodeAffinityArgs{}, + ) + return nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/scheme/scheme.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/scheme/scheme.go new file mode 100644 index 000000000..375b49b56 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/scheme/scheme.go @@ -0,0 +1,52 @@ +/* +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 scheme + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + config "k8s.io/kubernetes/pkg/scheduler/apis/config" + configv1 "k8s.io/kubernetes/pkg/scheduler/apis/config/v1" + configv1beta2 "k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2" + configv1beta3 "k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3" +) + +var ( + // Scheme is the runtime.Scheme to which all kubescheduler api types are registered. + Scheme = runtime.NewScheme() + + // Codecs provides access to encoding and decoding for the scheme. + Codecs = serializer.NewCodecFactory(Scheme, serializer.EnableStrict) +) + +func init() { + AddToScheme(Scheme) +} + +// AddToScheme builds the kubescheduler scheme using all known versions of the kubescheduler api. +func AddToScheme(scheme *runtime.Scheme) { + utilruntime.Must(config.AddToScheme(scheme)) + utilruntime.Must(configv1beta2.AddToScheme(scheme)) + utilruntime.Must(configv1beta3.AddToScheme(scheme)) + utilruntime.Must(configv1.AddToScheme(scheme)) + utilruntime.Must(scheme.SetVersionPriority( + configv1.SchemeGroupVersion, + configv1beta3.SchemeGroupVersion, + configv1beta2.SchemeGroupVersion, + )) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/types.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/types.go new file mode 100644 index 000000000..8db4e35c9 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/types.go @@ -0,0 +1,338 @@ +/* +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 config + +import ( + "math" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/sets" + componentbaseconfig "k8s.io/component-base/config" +) + +const ( + // SchedulerPolicyConfigMapKey defines the key of the element in the + // scheduler's policy ConfigMap that contains scheduler's policy config. + SchedulerPolicyConfigMapKey = "policy.cfg" + + // DefaultKubeSchedulerPort is the default port for the scheduler status server. + // May be overridden by a flag at startup. + DefaultKubeSchedulerPort = 10259 +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// KubeSchedulerConfiguration configures a scheduler +type KubeSchedulerConfiguration struct { + // TypeMeta contains the API version and kind. In kube-scheduler, after + // conversion from the versioned KubeSchedulerConfiguration type to this + // internal type, we set the APIVersion field to the scheme group/version of + // the type we converted from. This is done in cmd/kube-scheduler in two + // places: (1) when loading config from a file, (2) generating the default + // config. Based on the versioned type set in this field, we make decisions; + // for example (1) during validation to check for usage of removed plugins, + // (2) writing config to a file, (3) initialising the scheduler. + metav1.TypeMeta + + // Parallelism defines the amount of parallelism in algorithms for scheduling a Pods. Must be greater than 0. Defaults to 16 + Parallelism int32 + + // LeaderElection defines the configuration of leader election client. + LeaderElection componentbaseconfig.LeaderElectionConfiguration + + // ClientConnection specifies the kubeconfig file and client connection + // settings for the proxy server to use when communicating with the apiserver. + ClientConnection componentbaseconfig.ClientConnectionConfiguration + // HealthzBindAddress is the IP address and port for the health check server to serve on. + HealthzBindAddress string + // MetricsBindAddress is the IP address and port for the metrics server to serve on. + MetricsBindAddress string + + // DebuggingConfiguration holds configuration for Debugging related features + // TODO: We might wanna make this a substruct like Debugging componentbaseconfig.DebuggingConfiguration + componentbaseconfig.DebuggingConfiguration + + // PercentageOfNodesToScore is the percentage of all nodes that once found feasible + // for running a pod, the scheduler stops its search for more feasible nodes in + // the cluster. This helps improve scheduler's performance. Scheduler always tries to find + // at least "minFeasibleNodesToFind" feasible nodes no matter what the value of this flag is. + // Example: if the cluster size is 500 nodes and the value of this flag is 30, + // then scheduler stops finding further feasible nodes once it finds 150 feasible ones. + // When the value is 0, default percentage (5%--50% based on the size of the cluster) of the + // nodes will be scored. It is overridden by profile level PercentageOfNodesToScore. + PercentageOfNodesToScore *int32 + + // PodInitialBackoffSeconds is the initial backoff for unschedulable pods. + // If specified, it must be greater than 0. If this value is null, the default value (1s) + // will be used. + PodInitialBackoffSeconds int64 + + // PodMaxBackoffSeconds is the max backoff for unschedulable pods. + // If specified, it must be greater than or equal to podInitialBackoffSeconds. If this value is null, + // the default value (10s) will be used. + PodMaxBackoffSeconds int64 + + // Profiles are scheduling profiles that kube-scheduler supports. Pods can + // choose to be scheduled under a particular profile by setting its associated + // scheduler name. Pods that don't specify any scheduler name are scheduled + // with the "default-scheduler" profile, if present here. + Profiles []KubeSchedulerProfile + + // Extenders are the list of scheduler extenders, each holding the values of how to communicate + // with the extender. These extenders are shared by all scheduler profiles. + Extenders []Extender +} + +// KubeSchedulerProfile is a scheduling profile. +type KubeSchedulerProfile struct { + // SchedulerName is the name of the scheduler associated to this profile. + // If SchedulerName matches with the pod's "spec.schedulerName", then the pod + // is scheduled with this profile. + SchedulerName string + + // PercentageOfNodesToScore is the percentage of all nodes that once found feasible + // for running a pod, the scheduler stops its search for more feasible nodes in + // the cluster. This helps improve scheduler's performance. Scheduler always tries to find + // at least "minFeasibleNodesToFind" feasible nodes no matter what the value of this flag is. + // Example: if the cluster size is 500 nodes and the value of this flag is 30, + // then scheduler stops finding further feasible nodes once it finds 150 feasible ones. + // When the value is 0, default percentage (5%--50% based on the size of the cluster) of the + // nodes will be scored. It will override global PercentageOfNodesToScore. If it is empty, + // global PercentageOfNodesToScore will be used. + PercentageOfNodesToScore *int32 + + // Plugins specify the set of plugins that should be enabled or disabled. + // Enabled plugins are the ones that should be enabled in addition to the + // default plugins. Disabled plugins are any of the default plugins that + // should be disabled. + // When no enabled or disabled plugin is specified for an extension point, + // default plugins for that extension point will be used if there is any. + // If a QueueSort plugin is specified, the same QueueSort Plugin and + // PluginConfig must be specified for all profiles. + Plugins *Plugins + + // PluginConfig is an optional set of custom plugin arguments for each plugin. + // Omitting config args for a plugin is equivalent to using the default config + // for that plugin. + PluginConfig []PluginConfig +} + +// Plugins include multiple extension points. When specified, the list of plugins for +// a particular extension point are the only ones enabled. If an extension point is +// omitted from the config, then the default set of plugins is used for that extension point. +// Enabled plugins are called in the order specified here, after default plugins. If they need to +// be invoked before default plugins, default plugins must be disabled and re-enabled here in desired order. +type Plugins struct { + // PreEnqueue is a list of plugins that should be invoked before adding pods to the scheduling queue. + PreEnqueue PluginSet + + // QueueSort is a list of plugins that should be invoked when sorting pods in the scheduling queue. + QueueSort PluginSet + + // PreFilter is a list of plugins that should be invoked at "PreFilter" extension point of the scheduling framework. + PreFilter PluginSet + + // Filter is a list of plugins that should be invoked when filtering out nodes that cannot run the Pod. + Filter PluginSet + + // PostFilter is a list of plugins that are invoked after filtering phase, but only when no feasible nodes were found for the pod. + PostFilter PluginSet + + // PreScore is a list of plugins that are invoked before scoring. + PreScore PluginSet + + // Score is a list of plugins that should be invoked when ranking nodes that have passed the filtering phase. + Score PluginSet + + // Reserve is a list of plugins invoked when reserving/unreserving resources + // after a node is assigned to run the pod. + Reserve PluginSet + + // Permit is a list of plugins that control binding of a Pod. These plugins can prevent or delay binding of a Pod. + Permit PluginSet + + // PreBind is a list of plugins that should be invoked before a pod is bound. + PreBind PluginSet + + // Bind is a list of plugins that should be invoked at "Bind" extension point of the scheduling framework. + // The scheduler call these plugins in order. Scheduler skips the rest of these plugins as soon as one returns success. + Bind PluginSet + + // PostBind is a list of plugins that should be invoked after a pod is successfully bound. + PostBind PluginSet + + // MultiPoint is a simplified config field for enabling plugins for all valid extension points + MultiPoint PluginSet +} + +// PluginSet specifies enabled and disabled plugins for an extension point. +// If an array is empty, missing, or nil, default plugins at that extension point will be used. +type PluginSet struct { + // Enabled specifies plugins that should be enabled in addition to default plugins. + // These are called after default plugins and in the same order specified here. + Enabled []Plugin + // Disabled specifies default plugins that should be disabled. + // When all default plugins need to be disabled, an array containing only one "*" should be provided. + Disabled []Plugin +} + +// Plugin specifies a plugin name and its weight when applicable. Weight is used only for Score plugins. +type Plugin struct { + // Name defines the name of plugin + Name string + // Weight defines the weight of plugin, only used for Score plugins. + Weight int32 +} + +// PluginConfig specifies arguments that should be passed to a plugin at the time of initialization. +// A plugin that is invoked at multiple extension points is initialized once. Args can have arbitrary structure. +// It is up to the plugin to process these Args. +type PluginConfig struct { + // Name defines the name of plugin being configured + Name string + // Args defines the arguments passed to the plugins at the time of initialization. Args can have arbitrary structure. + Args runtime.Object +} + +/* + * NOTE: The following variables and methods are intentionally left out of the staging mirror. + */ +const ( + // DefaultPercentageOfNodesToScore defines the percentage of nodes of all nodes + // that once found feasible, the scheduler stops looking for more nodes. + // A value of 0 means adaptive, meaning the scheduler figures out a proper default. + DefaultPercentageOfNodesToScore = 0 + + // MaxCustomPriorityScore is the max score UtilizationShapePoint expects. + MaxCustomPriorityScore int64 = 10 + + // MaxTotalScore is the maximum total score. + MaxTotalScore int64 = math.MaxInt64 + + // MaxWeight defines the max weight value allowed for custom PriorityPolicy + MaxWeight = MaxTotalScore / MaxCustomPriorityScore +) + +// Names returns the list of enabled plugin names. +func (p *Plugins) Names() []string { + if p == nil { + return nil + } + extensions := []PluginSet{ + p.PreEnqueue, + p.PreFilter, + p.Filter, + p.PostFilter, + p.Reserve, + p.PreScore, + p.Score, + p.PreBind, + p.Bind, + p.PostBind, + p.Permit, + p.QueueSort, + } + n := sets.NewString() + for _, e := range extensions { + for _, pg := range e.Enabled { + n.Insert(pg.Name) + } + } + return n.List() +} + +// Extender holds the parameters used to communicate with the extender. If a verb is unspecified/empty, +// it is assumed that the extender chose not to provide that extension. +type Extender struct { + // URLPrefix at which the extender is available + URLPrefix string + // Verb for the filter call, empty if not supported. This verb is appended to the URLPrefix when issuing the filter call to extender. + FilterVerb string + // Verb for the preempt call, empty if not supported. This verb is appended to the URLPrefix when issuing the preempt call to extender. + PreemptVerb string + // Verb for the prioritize call, empty if not supported. This verb is appended to the URLPrefix when issuing the prioritize call to extender. + PrioritizeVerb string + // The numeric multiplier for the node scores that the prioritize call generates. + // The weight should be a positive integer + Weight int64 + // Verb for the bind call, empty if not supported. This verb is appended to the URLPrefix when issuing the bind call to extender. + // If this method is implemented by the extender, it is the extender's responsibility to bind the pod to apiserver. Only one extender + // can implement this function. + BindVerb string + // EnableHTTPS specifies whether https should be used to communicate with the extender + EnableHTTPS bool + // TLSConfig specifies the transport layer security config + TLSConfig *ExtenderTLSConfig + // HTTPTimeout specifies the timeout duration for a call to the extender. Filter timeout fails the scheduling of the pod. Prioritize + // timeout is ignored, k8s/other extenders priorities are used to select the node. + HTTPTimeout metav1.Duration + // NodeCacheCapable specifies that the extender is capable of caching node information, + // so the scheduler should only send minimal information about the eligible nodes + // assuming that the extender already cached full details of all nodes in the cluster + NodeCacheCapable bool + // ManagedResources is a list of extended resources that are managed by + // this extender. + // - A pod will be sent to the extender on the Filter, Prioritize and Bind + // (if the extender is the binder) phases iff the pod requests at least + // one of the extended resources in this list. If empty or unspecified, + // all pods will be sent to this extender. + // - If IgnoredByScheduler is set to true for a resource, kube-scheduler + // will skip checking the resource in predicates. + // +optional + ManagedResources []ExtenderManagedResource + // Ignorable specifies if the extender is ignorable, i.e. scheduling should not + // fail when the extender returns an error or is not reachable. + Ignorable bool +} + +// ExtenderManagedResource describes the arguments of extended resources +// managed by an extender. +type ExtenderManagedResource struct { + // Name is the extended resource name. + Name string + // IgnoredByScheduler indicates whether kube-scheduler should ignore this + // resource when applying predicates. + IgnoredByScheduler bool +} + +// ExtenderTLSConfig contains settings to enable TLS with extender +type ExtenderTLSConfig struct { + // Server should be accessed without verifying the TLS certificate. For testing only. + Insecure bool + // ServerName is passed to the server for SNI and is used in the client to check server + // certificates against. If ServerName is empty, the hostname used to contact the + // server is used. + ServerName string + + // Server requires TLS client certificate authentication + CertFile string + // Server requires TLS client certificate authentication + KeyFile string + // Trusted root certificates for server + CAFile string + + // CertData holds PEM-encoded bytes (typically read from a client certificate file). + // CertData takes precedence over CertFile + CertData []byte + // KeyData holds PEM-encoded bytes (typically read from a client certificate key file). + // KeyData takes precedence over KeyFile + KeyData []byte `datapolicy:"security-key"` + // CAData holds PEM-encoded bytes (typically read from a root certificates bundle). + // CAData takes precedence over CAFile + CAData []byte +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/types_pluginargs.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/types_pluginargs.go new file mode 100644 index 000000000..31bb8df02 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/types_pluginargs.go @@ -0,0 +1,214 @@ +/* +Copyright 2020 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 config + +import ( + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// DefaultPreemptionArgs holds arguments used to configure the +// DefaultPreemption plugin. +type DefaultPreemptionArgs struct { + metav1.TypeMeta + + // MinCandidateNodesPercentage is the minimum number of candidates to + // shortlist when dry running preemption as a percentage of number of nodes. + // Must be in the range [0, 100]. Defaults to 10% of the cluster size if + // unspecified. + MinCandidateNodesPercentage int32 + // MinCandidateNodesAbsolute is the absolute minimum number of candidates to + // shortlist. The likely number of candidates enumerated for dry running + // preemption is given by the formula: + // numCandidates = max(numNodes * minCandidateNodesPercentage, minCandidateNodesAbsolute) + // We say "likely" because there are other factors such as PDB violations + // that play a role in the number of candidates shortlisted. Must be at least + // 0 nodes. Defaults to 100 nodes if unspecified. + MinCandidateNodesAbsolute int32 +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// InterPodAffinityArgs holds arguments used to configure the InterPodAffinity plugin. +type InterPodAffinityArgs struct { + metav1.TypeMeta + + // HardPodAffinityWeight is the scoring weight for existing pods with a + // matching hard affinity to the incoming pod. + HardPodAffinityWeight int32 +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// NodeResourcesFitArgs holds arguments used to configure the NodeResourcesFit plugin. +type NodeResourcesFitArgs struct { + metav1.TypeMeta + + // IgnoredResources is the list of resources that NodeResources fit filter + // should ignore. + IgnoredResources []string + // IgnoredResourceGroups defines the list of resource groups that NodeResources fit filter should ignore. + // e.g. if group is ["example.com"], it will ignore all resource names that begin + // with "example.com", such as "example.com/aaa" and "example.com/bbb". + // A resource group name can't contain '/'. + IgnoredResourceGroups []string + + // ScoringStrategy selects the node resource scoring strategy. + ScoringStrategy *ScoringStrategy +} + +// PodTopologySpreadConstraintsDefaulting defines how to set default constraints +// for the PodTopologySpread plugin. +type PodTopologySpreadConstraintsDefaulting string + +const ( + // SystemDefaulting instructs to use the kubernetes defined default. + SystemDefaulting PodTopologySpreadConstraintsDefaulting = "System" + // ListDefaulting instructs to use the config provided default. + ListDefaulting PodTopologySpreadConstraintsDefaulting = "List" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// PodTopologySpreadArgs holds arguments used to configure the PodTopologySpread plugin. +type PodTopologySpreadArgs struct { + metav1.TypeMeta + + // DefaultConstraints defines topology spread constraints to be applied to + // Pods that don't define any in `pod.spec.topologySpreadConstraints`. + // `.defaultConstraints[*].labelSelectors` must be empty, as they are + // deduced from the Pod's membership to Services, ReplicationControllers, + // ReplicaSets or StatefulSets. + // When not empty, .defaultingType must be "List". + DefaultConstraints []v1.TopologySpreadConstraint + + // DefaultingType determines how .defaultConstraints are deduced. Can be one + // of "System" or "List". + // + // - "System": Use kubernetes defined constraints that spread Pods among + // Nodes and Zones. + // - "List": Use constraints defined in .defaultConstraints. + // + // Defaults to "System". + // +optional + DefaultingType PodTopologySpreadConstraintsDefaulting +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// NodeResourcesBalancedAllocationArgs holds arguments used to configure NodeResourcesBalancedAllocation plugin. +type NodeResourcesBalancedAllocationArgs struct { + metav1.TypeMeta + + // Resources to be considered when scoring. + // The default resource set includes "cpu" and "memory", only valid weight is 1. + Resources []ResourceSpec +} + +// UtilizationShapePoint represents a single point of a priority function shape. +type UtilizationShapePoint struct { + // Utilization (x axis). Valid values are 0 to 100. Fully utilized node maps to 100. + Utilization int32 + // Score assigned to a given utilization (y axis). Valid values are 0 to 10. + Score int32 +} + +// ResourceSpec represents single resource. +type ResourceSpec struct { + // Name of the resource. + Name string + // Weight of the resource. + Weight int64 +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// VolumeBindingArgs holds arguments used to configure the VolumeBinding plugin. +type VolumeBindingArgs struct { + metav1.TypeMeta + + // BindTimeoutSeconds is the timeout in seconds in volume binding operation. + // Value must be non-negative integer. The value zero indicates no waiting. + // If this value is nil, the default value will be used. + BindTimeoutSeconds int64 + + // Shape specifies the points defining the score function shape, which is + // used to score nodes based on the utilization of statically provisioned + // PVs. The utilization is calculated by dividing the total requested + // storage of the pod by the total capacity of feasible PVs on each node. + // Each point contains utilization (ranges from 0 to 100) and its + // associated score (ranges from 0 to 10). You can turn the priority by + // specifying different scores for different utilization numbers. + // The default shape points are: + // 1) 0 for 0 utilization + // 2) 10 for 100 utilization + // All points must be sorted in increasing order by utilization. + // +featureGate=VolumeCapacityPriority + // +optional + Shape []UtilizationShapePoint +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// NodeAffinityArgs holds arguments to configure the NodeAffinity plugin. +type NodeAffinityArgs struct { + metav1.TypeMeta + + // AddedAffinity is applied to all Pods additionally to the NodeAffinity + // specified in the PodSpec. That is, Nodes need to satisfy AddedAffinity + // AND .spec.NodeAffinity. AddedAffinity is empty by default (all Nodes + // match). + // When AddedAffinity is used, some Pods with affinity requirements that match + // a specific Node (such as Daemonset Pods) might remain unschedulable. + AddedAffinity *v1.NodeAffinity +} + +// ScoringStrategyType the type of scoring strategy used in NodeResourcesFit plugin. +type ScoringStrategyType string + +const ( + // LeastAllocated strategy prioritizes nodes with least allocated resources. + LeastAllocated ScoringStrategyType = "LeastAllocated" + // MostAllocated strategy prioritizes nodes with most allocated resources. + MostAllocated ScoringStrategyType = "MostAllocated" + // RequestedToCapacityRatio strategy allows specifying a custom shape function + // to score nodes based on the request to capacity ratio. + RequestedToCapacityRatio ScoringStrategyType = "RequestedToCapacityRatio" +) + +// ScoringStrategy define ScoringStrategyType for node resource plugin +type ScoringStrategy struct { + // Type selects which strategy to run. + Type ScoringStrategyType + + // Resources to consider when scoring. + // The default resource set includes "cpu" and "memory" with an equal weight. + // Allowed weights go from 1 to 100. + // Weight defaults to 1 if not specified or explicitly set to 0. + Resources []ResourceSpec + + // Arguments specific to RequestedToCapacityRatio strategy. + RequestedToCapacityRatio *RequestedToCapacityRatioParam +} + +// RequestedToCapacityRatioParam define RequestedToCapacityRatio parameters +type RequestedToCapacityRatioParam struct { + // Shape is a list of points defining the scoring function shape. + Shape []UtilizationShapePoint +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/conversion.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/conversion.go new file mode 100644 index 000000000..18115f93f --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/conversion.go @@ -0,0 +1,107 @@ +/* +Copyright 2022 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 v1 + +import ( + "fmt" + "sync" + + "k8s.io/apimachinery/pkg/conversion" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + v1 "k8s.io/kube-scheduler/config/v1" + "k8s.io/kubernetes/pkg/scheduler/apis/config" +) + +var ( + // pluginArgConversionScheme is a scheme with internal and v1 registered, + // used for defaulting/converting typed PluginConfig Args. + // Access via getPluginArgConversionScheme() + pluginArgConversionScheme *runtime.Scheme + initPluginArgConversionScheme sync.Once +) + +func GetPluginArgConversionScheme() *runtime.Scheme { + initPluginArgConversionScheme.Do(func() { + // set up the scheme used for plugin arg conversion + pluginArgConversionScheme = runtime.NewScheme() + utilruntime.Must(AddToScheme(pluginArgConversionScheme)) + utilruntime.Must(config.AddToScheme(pluginArgConversionScheme)) + }) + return pluginArgConversionScheme +} + +func Convert_v1_KubeSchedulerConfiguration_To_config_KubeSchedulerConfiguration(in *v1.KubeSchedulerConfiguration, out *config.KubeSchedulerConfiguration, s conversion.Scope) error { + if err := autoConvert_v1_KubeSchedulerConfiguration_To_config_KubeSchedulerConfiguration(in, out, s); err != nil { + return err + } + return convertToInternalPluginConfigArgs(out) +} + +// convertToInternalPluginConfigArgs converts PluginConfig#Args into internal +// types using a scheme, after applying defaults. +func convertToInternalPluginConfigArgs(out *config.KubeSchedulerConfiguration) error { + scheme := GetPluginArgConversionScheme() + for i := range out.Profiles { + prof := &out.Profiles[i] + for j := range prof.PluginConfig { + args := prof.PluginConfig[j].Args + if args == nil { + continue + } + if _, isUnknown := args.(*runtime.Unknown); isUnknown { + continue + } + internalArgs, err := scheme.ConvertToVersion(args, config.SchemeGroupVersion) + if err != nil { + return fmt.Errorf("converting .Profiles[%d].PluginConfig[%d].Args into internal type: %w", i, j, err) + } + prof.PluginConfig[j].Args = internalArgs + } + } + return nil +} + +func Convert_config_KubeSchedulerConfiguration_To_v1_KubeSchedulerConfiguration(in *config.KubeSchedulerConfiguration, out *v1.KubeSchedulerConfiguration, s conversion.Scope) error { + if err := autoConvert_config_KubeSchedulerConfiguration_To_v1_KubeSchedulerConfiguration(in, out, s); err != nil { + return err + } + return convertToExternalPluginConfigArgs(out) +} + +// convertToExternalPluginConfigArgs converts PluginConfig#Args into +// external (versioned) types using a scheme. +func convertToExternalPluginConfigArgs(out *v1.KubeSchedulerConfiguration) error { + scheme := GetPluginArgConversionScheme() + for i := range out.Profiles { + for j := range out.Profiles[i].PluginConfig { + args := out.Profiles[i].PluginConfig[j].Args + if args.Object == nil { + continue + } + if _, isUnknown := args.Object.(*runtime.Unknown); isUnknown { + continue + } + externalArgs, err := scheme.ConvertToVersion(args.Object, SchemeGroupVersion) + if err != nil { + return err + } + out.Profiles[i].PluginConfig[j].Args.Object = externalArgs + } + } + return nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/default_plugins.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/default_plugins.go new file mode 100644 index 000000000..3fc8c1bdf --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/default_plugins.go @@ -0,0 +1,162 @@ +/* +Copyright 2022 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 v1 + +import ( + "k8s.io/apimachinery/pkg/util/sets" + utilfeature "k8s.io/apiserver/pkg/util/feature" + "k8s.io/klog/v2" + v1 "k8s.io/kube-scheduler/config/v1" + "k8s.io/kubernetes/pkg/features" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" + "k8s.io/utils/pointer" +) + +// getDefaultPlugins returns the default set of plugins. +func getDefaultPlugins() *v1.Plugins { + plugins := &v1.Plugins{ + MultiPoint: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: names.PrioritySort}, + {Name: names.NodeUnschedulable}, + {Name: names.NodeName}, + {Name: names.TaintToleration, Weight: pointer.Int32(3)}, + {Name: names.NodeAffinity, Weight: pointer.Int32(2)}, + {Name: names.NodePorts}, + {Name: names.NodeResourcesFit, Weight: pointer.Int32(1)}, + {Name: names.VolumeRestrictions}, + {Name: names.EBSLimits}, + {Name: names.GCEPDLimits}, + {Name: names.NodeVolumeLimits}, + {Name: names.AzureDiskLimits}, + {Name: names.VolumeBinding}, + {Name: names.VolumeZone}, + {Name: names.PodTopologySpread, Weight: pointer.Int32(2)}, + {Name: names.InterPodAffinity, Weight: pointer.Int32(2)}, + {Name: names.DefaultPreemption}, + {Name: names.NodeResourcesBalancedAllocation, Weight: pointer.Int32(1)}, + {Name: names.ImageLocality, Weight: pointer.Int32(1)}, + {Name: names.DefaultBinder}, + }, + }, + } + applyFeatureGates(plugins) + + return plugins +} + +func applyFeatureGates(config *v1.Plugins) { + if utilfeature.DefaultFeatureGate.Enabled(features.PodSchedulingReadiness) { + config.MultiPoint.Enabled = append(config.MultiPoint.Enabled, v1.Plugin{Name: names.SchedulingGates}) + } + if utilfeature.DefaultFeatureGate.Enabled(features.DynamicResourceAllocation) { + // This plugin should come before DefaultPreemption because if + // there is a problem with a Pod and PostFilter gets called to + // resolve the problem, it is better to first deallocate an + // idle ResourceClaim than it is to evict some Pod that might + // be doing useful work. + for i := range config.MultiPoint.Enabled { + if config.MultiPoint.Enabled[i].Name == names.DefaultPreemption { + extended := make([]v1.Plugin, 0, len(config.MultiPoint.Enabled)+1) + extended = append(extended, config.MultiPoint.Enabled[:i]...) + extended = append(extended, v1.Plugin{Name: names.DynamicResources}) + extended = append(extended, config.MultiPoint.Enabled[i:]...) + config.MultiPoint.Enabled = extended + break + } + } + } +} + +// mergePlugins merges the custom set into the given default one, handling disabled sets. +func mergePlugins(defaultPlugins, customPlugins *v1.Plugins) *v1.Plugins { + if customPlugins == nil { + return defaultPlugins + } + + defaultPlugins.MultiPoint = mergePluginSet(defaultPlugins.MultiPoint, customPlugins.MultiPoint) + defaultPlugins.PreEnqueue = mergePluginSet(defaultPlugins.PreEnqueue, customPlugins.PreEnqueue) + defaultPlugins.QueueSort = mergePluginSet(defaultPlugins.QueueSort, customPlugins.QueueSort) + defaultPlugins.PreFilter = mergePluginSet(defaultPlugins.PreFilter, customPlugins.PreFilter) + defaultPlugins.Filter = mergePluginSet(defaultPlugins.Filter, customPlugins.Filter) + defaultPlugins.PostFilter = mergePluginSet(defaultPlugins.PostFilter, customPlugins.PostFilter) + defaultPlugins.PreScore = mergePluginSet(defaultPlugins.PreScore, customPlugins.PreScore) + defaultPlugins.Score = mergePluginSet(defaultPlugins.Score, customPlugins.Score) + defaultPlugins.Reserve = mergePluginSet(defaultPlugins.Reserve, customPlugins.Reserve) + defaultPlugins.Permit = mergePluginSet(defaultPlugins.Permit, customPlugins.Permit) + defaultPlugins.PreBind = mergePluginSet(defaultPlugins.PreBind, customPlugins.PreBind) + defaultPlugins.Bind = mergePluginSet(defaultPlugins.Bind, customPlugins.Bind) + defaultPlugins.PostBind = mergePluginSet(defaultPlugins.PostBind, customPlugins.PostBind) + return defaultPlugins +} + +type pluginIndex struct { + index int + plugin v1.Plugin +} + +func mergePluginSet(defaultPluginSet, customPluginSet v1.PluginSet) v1.PluginSet { + disabledPlugins := sets.NewString() + enabledCustomPlugins := make(map[string]pluginIndex) + // replacedPluginIndex is a set of index of plugins, which have replaced the default plugins. + replacedPluginIndex := sets.NewInt() + var disabled []v1.Plugin + for _, disabledPlugin := range customPluginSet.Disabled { + // if the user is manually disabling any (or all, with "*") default plugins for an extension point, + // we need to track that so that the MultiPoint extension logic in the framework can know to skip + // inserting unspecified default plugins to this point. + disabled = append(disabled, v1.Plugin{Name: disabledPlugin.Name}) + disabledPlugins.Insert(disabledPlugin.Name) + } + + // With MultiPoint, we may now have some disabledPlugins in the default registry + // For example, we enable PluginX with Filter+Score through MultiPoint but disable its Score plugin by default. + for _, disabledPlugin := range defaultPluginSet.Disabled { + disabled = append(disabled, v1.Plugin{Name: disabledPlugin.Name}) + disabledPlugins.Insert(disabledPlugin.Name) + } + + for index, enabledPlugin := range customPluginSet.Enabled { + enabledCustomPlugins[enabledPlugin.Name] = pluginIndex{index, enabledPlugin} + } + var enabledPlugins []v1.Plugin + if !disabledPlugins.Has("*") { + for _, defaultEnabledPlugin := range defaultPluginSet.Enabled { + if disabledPlugins.Has(defaultEnabledPlugin.Name) { + continue + } + // The default plugin is explicitly re-configured, update the default plugin accordingly. + if customPlugin, ok := enabledCustomPlugins[defaultEnabledPlugin.Name]; ok { + klog.InfoS("Default plugin is explicitly re-configured; overriding", "plugin", defaultEnabledPlugin.Name) + // Update the default plugin in place to preserve order. + defaultEnabledPlugin = customPlugin.plugin + replacedPluginIndex.Insert(customPlugin.index) + } + enabledPlugins = append(enabledPlugins, defaultEnabledPlugin) + } + } + + // Append all the custom plugins which haven't replaced any default plugins. + // Note: duplicated custom plugins will still be appended here. + // If so, the instantiation of scheduler framework will detect it and abort. + for index, plugin := range customPluginSet.Enabled { + if !replacedPluginIndex.Has(index) { + enabledPlugins = append(enabledPlugins, plugin) + } + } + return v1.PluginSet{Enabled: enabledPlugins, Disabled: disabled} +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/defaults.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/defaults.go new file mode 100644 index 000000000..8e86712fa --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/defaults.go @@ -0,0 +1,242 @@ +/* +Copyright 2022 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 v1 + +import ( + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apiserver/pkg/util/feature" + componentbaseconfigv1alpha1 "k8s.io/component-base/config/v1alpha1" + configv1 "k8s.io/kube-scheduler/config/v1" + "k8s.io/kubernetes/pkg/features" + "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/utils/pointer" +) + +var defaultResourceSpec = []configv1.ResourceSpec{ + {Name: string(v1.ResourceCPU), Weight: 1}, + {Name: string(v1.ResourceMemory), Weight: 1}, +} + +func addDefaultingFuncs(scheme *runtime.Scheme) error { + return RegisterDefaults(scheme) +} + +func pluginsNames(p *configv1.Plugins) []string { + if p == nil { + return nil + } + extensions := []configv1.PluginSet{ + p.MultiPoint, + p.PreFilter, + p.Filter, + p.PostFilter, + p.Reserve, + p.PreScore, + p.Score, + p.PreBind, + p.Bind, + p.PostBind, + p.Permit, + p.PreEnqueue, + p.QueueSort, + } + n := sets.NewString() + for _, e := range extensions { + for _, pg := range e.Enabled { + n.Insert(pg.Name) + } + } + return n.List() +} + +func setDefaults_KubeSchedulerProfile(prof *configv1.KubeSchedulerProfile) { + // Set default plugins. + prof.Plugins = mergePlugins(getDefaultPlugins(), prof.Plugins) + // Set default plugin configs. + scheme := GetPluginArgConversionScheme() + existingConfigs := sets.NewString() + for j := range prof.PluginConfig { + existingConfigs.Insert(prof.PluginConfig[j].Name) + args := prof.PluginConfig[j].Args.Object + if _, isUnknown := args.(*runtime.Unknown); isUnknown { + continue + } + scheme.Default(args) + } + + // Append default configs for plugins that didn't have one explicitly set. + for _, name := range pluginsNames(prof.Plugins) { + if existingConfigs.Has(name) { + continue + } + gvk := configv1.SchemeGroupVersion.WithKind(name + "Args") + args, err := scheme.New(gvk) + if err != nil { + // This plugin is out-of-tree or doesn't require configuration. + continue + } + scheme.Default(args) + args.GetObjectKind().SetGroupVersionKind(gvk) + prof.PluginConfig = append(prof.PluginConfig, configv1.PluginConfig{ + Name: name, + Args: runtime.RawExtension{Object: args}, + }) + } +} + +// SetDefaults_KubeSchedulerConfiguration sets additional defaults +func SetDefaults_KubeSchedulerConfiguration(obj *configv1.KubeSchedulerConfiguration) { + if obj.Parallelism == nil { + obj.Parallelism = pointer.Int32(16) + } + + if len(obj.Profiles) == 0 { + obj.Profiles = append(obj.Profiles, configv1.KubeSchedulerProfile{}) + } + // Only apply a default scheduler name when there is a single profile. + // Validation will ensure that every profile has a non-empty unique name. + if len(obj.Profiles) == 1 && obj.Profiles[0].SchedulerName == nil { + obj.Profiles[0].SchedulerName = pointer.String(v1.DefaultSchedulerName) + } + + // Add the default set of plugins and apply the configuration. + for i := range obj.Profiles { + prof := &obj.Profiles[i] + setDefaults_KubeSchedulerProfile(prof) + } + + if obj.PercentageOfNodesToScore == nil { + obj.PercentageOfNodesToScore = pointer.Int32(config.DefaultPercentageOfNodesToScore) + } + + if len(obj.LeaderElection.ResourceLock) == 0 { + // Use lease-based leader election to reduce cost. + // We migrated for EndpointsLease lock in 1.17 and starting in 1.20 we + // migrated to Lease lock. + obj.LeaderElection.ResourceLock = "leases" + } + if len(obj.LeaderElection.ResourceNamespace) == 0 { + obj.LeaderElection.ResourceNamespace = configv1.SchedulerDefaultLockObjectNamespace + } + if len(obj.LeaderElection.ResourceName) == 0 { + obj.LeaderElection.ResourceName = configv1.SchedulerDefaultLockObjectName + } + + if len(obj.ClientConnection.ContentType) == 0 { + obj.ClientConnection.ContentType = "application/vnd.kubernetes.protobuf" + } + // Scheduler has an opinion about QPS/Burst, setting specific defaults for itself, instead of generic settings. + if obj.ClientConnection.QPS == 0.0 { + obj.ClientConnection.QPS = 50.0 + } + if obj.ClientConnection.Burst == 0 { + obj.ClientConnection.Burst = 100 + } + + // Use the default LeaderElectionConfiguration options + componentbaseconfigv1alpha1.RecommendedDefaultLeaderElectionConfiguration(&obj.LeaderElection) + + if obj.PodInitialBackoffSeconds == nil { + obj.PodInitialBackoffSeconds = pointer.Int64(1) + } + + if obj.PodMaxBackoffSeconds == nil { + obj.PodMaxBackoffSeconds = pointer.Int64(10) + } + + // Enable profiling by default in the scheduler + if obj.EnableProfiling == nil { + obj.EnableProfiling = pointer.Bool(true) + } + + // Enable contention profiling by default if profiling is enabled + if *obj.EnableProfiling && obj.EnableContentionProfiling == nil { + obj.EnableContentionProfiling = pointer.Bool(true) + } +} + +func SetDefaults_DefaultPreemptionArgs(obj *configv1.DefaultPreemptionArgs) { + if obj.MinCandidateNodesPercentage == nil { + obj.MinCandidateNodesPercentage = pointer.Int32(10) + } + if obj.MinCandidateNodesAbsolute == nil { + obj.MinCandidateNodesAbsolute = pointer.Int32(100) + } +} + +func SetDefaults_InterPodAffinityArgs(obj *configv1.InterPodAffinityArgs) { + if obj.HardPodAffinityWeight == nil { + obj.HardPodAffinityWeight = pointer.Int32(1) + } +} + +func SetDefaults_VolumeBindingArgs(obj *configv1.VolumeBindingArgs) { + if obj.BindTimeoutSeconds == nil { + obj.BindTimeoutSeconds = pointer.Int64(600) + } + if len(obj.Shape) == 0 && feature.DefaultFeatureGate.Enabled(features.VolumeCapacityPriority) { + obj.Shape = []configv1.UtilizationShapePoint{ + { + Utilization: 0, + Score: 0, + }, + { + Utilization: 100, + Score: int32(config.MaxCustomPriorityScore), + }, + } + } +} + +func SetDefaults_NodeResourcesBalancedAllocationArgs(obj *configv1.NodeResourcesBalancedAllocationArgs) { + if len(obj.Resources) == 0 { + obj.Resources = defaultResourceSpec + return + } + // If the weight is not set or it is explicitly set to 0, then apply the default weight(1) instead. + for i := range obj.Resources { + if obj.Resources[i].Weight == 0 { + obj.Resources[i].Weight = 1 + } + } +} + +func SetDefaults_PodTopologySpreadArgs(obj *configv1.PodTopologySpreadArgs) { + if obj.DefaultingType == "" { + obj.DefaultingType = configv1.SystemDefaulting + } +} + +func SetDefaults_NodeResourcesFitArgs(obj *configv1.NodeResourcesFitArgs) { + if obj.ScoringStrategy == nil { + obj.ScoringStrategy = &configv1.ScoringStrategy{ + Type: configv1.ScoringStrategyType(config.LeastAllocated), + Resources: defaultResourceSpec, + } + } + if len(obj.ScoringStrategy.Resources) == 0 { + // If no resources specified, use the default set. + obj.ScoringStrategy.Resources = append(obj.ScoringStrategy.Resources, defaultResourceSpec...) + } + for i := range obj.ScoringStrategy.Resources { + if obj.ScoringStrategy.Resources[i].Weight == 0 { + obj.ScoringStrategy.Resources[i].Weight = 1 + } + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/doc.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/doc.go new file mode 100644 index 000000000..7fa215827 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/doc.go @@ -0,0 +1,24 @@ +/* +Copyright 2022 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. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:conversion-gen=k8s.io/kubernetes/pkg/scheduler/apis/config +// +k8s:conversion-gen-external-types=k8s.io/kube-scheduler/config/v1 +// +k8s:defaulter-gen=TypeMeta +// +k8s:defaulter-gen-input=k8s.io/kube-scheduler/config/v1 +// +groupName=kubescheduler.config.k8s.io + +package v1 // import "k8s.io/kubernetes/pkg/scheduler/apis/config/v1" diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/register.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/register.go new file mode 100644 index 000000000..9a32736c8 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/register.go @@ -0,0 +1,42 @@ +/* +Copyright 2022 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 v1 + +import ( + v1 "k8s.io/kube-scheduler/config/v1" +) + +// GroupName is the group name used in this package +const GroupName = v1.GroupName + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = v1.SchemeGroupVersion + +var ( + // localSchemeBuilder extends the SchemeBuilder instance with the external types. In this package, + // defaulting and conversion init funcs are registered as well. + localSchemeBuilder = &v1.SchemeBuilder + // AddToScheme is a global function that registers this API group & version to a scheme + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addDefaultingFuncs) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/zz_generated.conversion.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/zz_generated.conversion.go new file mode 100644 index 000000000..d9dbc31ad --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/zz_generated.conversion.go @@ -0,0 +1,944 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by conversion-gen. DO NOT EDIT. + +package v1 + +import ( + unsafe "unsafe" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + v1alpha1 "k8s.io/component-base/config/v1alpha1" + v1 "k8s.io/kube-scheduler/config/v1" + config "k8s.io/kubernetes/pkg/scheduler/apis/config" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*v1.DefaultPreemptionArgs)(nil), (*config.DefaultPreemptionArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_DefaultPreemptionArgs_To_config_DefaultPreemptionArgs(a.(*v1.DefaultPreemptionArgs), b.(*config.DefaultPreemptionArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.DefaultPreemptionArgs)(nil), (*v1.DefaultPreemptionArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_DefaultPreemptionArgs_To_v1_DefaultPreemptionArgs(a.(*config.DefaultPreemptionArgs), b.(*v1.DefaultPreemptionArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.Extender)(nil), (*config.Extender)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Extender_To_config_Extender(a.(*v1.Extender), b.(*config.Extender), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.Extender)(nil), (*v1.Extender)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_Extender_To_v1_Extender(a.(*config.Extender), b.(*v1.Extender), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ExtenderManagedResource)(nil), (*config.ExtenderManagedResource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ExtenderManagedResource_To_config_ExtenderManagedResource(a.(*v1.ExtenderManagedResource), b.(*config.ExtenderManagedResource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.ExtenderManagedResource)(nil), (*v1.ExtenderManagedResource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_ExtenderManagedResource_To_v1_ExtenderManagedResource(a.(*config.ExtenderManagedResource), b.(*v1.ExtenderManagedResource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ExtenderTLSConfig)(nil), (*config.ExtenderTLSConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ExtenderTLSConfig_To_config_ExtenderTLSConfig(a.(*v1.ExtenderTLSConfig), b.(*config.ExtenderTLSConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.ExtenderTLSConfig)(nil), (*v1.ExtenderTLSConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_ExtenderTLSConfig_To_v1_ExtenderTLSConfig(a.(*config.ExtenderTLSConfig), b.(*v1.ExtenderTLSConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.InterPodAffinityArgs)(nil), (*config.InterPodAffinityArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_InterPodAffinityArgs_To_config_InterPodAffinityArgs(a.(*v1.InterPodAffinityArgs), b.(*config.InterPodAffinityArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.InterPodAffinityArgs)(nil), (*v1.InterPodAffinityArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_InterPodAffinityArgs_To_v1_InterPodAffinityArgs(a.(*config.InterPodAffinityArgs), b.(*v1.InterPodAffinityArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.KubeSchedulerProfile)(nil), (*config.KubeSchedulerProfile)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_KubeSchedulerProfile_To_config_KubeSchedulerProfile(a.(*v1.KubeSchedulerProfile), b.(*config.KubeSchedulerProfile), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.KubeSchedulerProfile)(nil), (*v1.KubeSchedulerProfile)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_KubeSchedulerProfile_To_v1_KubeSchedulerProfile(a.(*config.KubeSchedulerProfile), b.(*v1.KubeSchedulerProfile), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NodeAffinityArgs)(nil), (*config.NodeAffinityArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeAffinityArgs_To_config_NodeAffinityArgs(a.(*v1.NodeAffinityArgs), b.(*config.NodeAffinityArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.NodeAffinityArgs)(nil), (*v1.NodeAffinityArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_NodeAffinityArgs_To_v1_NodeAffinityArgs(a.(*config.NodeAffinityArgs), b.(*v1.NodeAffinityArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NodeResourcesBalancedAllocationArgs)(nil), (*config.NodeResourcesBalancedAllocationArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeResourcesBalancedAllocationArgs_To_config_NodeResourcesBalancedAllocationArgs(a.(*v1.NodeResourcesBalancedAllocationArgs), b.(*config.NodeResourcesBalancedAllocationArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.NodeResourcesBalancedAllocationArgs)(nil), (*v1.NodeResourcesBalancedAllocationArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_NodeResourcesBalancedAllocationArgs_To_v1_NodeResourcesBalancedAllocationArgs(a.(*config.NodeResourcesBalancedAllocationArgs), b.(*v1.NodeResourcesBalancedAllocationArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NodeResourcesFitArgs)(nil), (*config.NodeResourcesFitArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs(a.(*v1.NodeResourcesFitArgs), b.(*config.NodeResourcesFitArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.NodeResourcesFitArgs)(nil), (*v1.NodeResourcesFitArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_NodeResourcesFitArgs_To_v1_NodeResourcesFitArgs(a.(*config.NodeResourcesFitArgs), b.(*v1.NodeResourcesFitArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.Plugin)(nil), (*config.Plugin)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Plugin_To_config_Plugin(a.(*v1.Plugin), b.(*config.Plugin), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.Plugin)(nil), (*v1.Plugin)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_Plugin_To_v1_Plugin(a.(*config.Plugin), b.(*v1.Plugin), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PluginConfig)(nil), (*config.PluginConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PluginConfig_To_config_PluginConfig(a.(*v1.PluginConfig), b.(*config.PluginConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.PluginConfig)(nil), (*v1.PluginConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_PluginConfig_To_v1_PluginConfig(a.(*config.PluginConfig), b.(*v1.PluginConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PluginSet)(nil), (*config.PluginSet)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PluginSet_To_config_PluginSet(a.(*v1.PluginSet), b.(*config.PluginSet), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.PluginSet)(nil), (*v1.PluginSet)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_PluginSet_To_v1_PluginSet(a.(*config.PluginSet), b.(*v1.PluginSet), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.Plugins)(nil), (*config.Plugins)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Plugins_To_config_Plugins(a.(*v1.Plugins), b.(*config.Plugins), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.Plugins)(nil), (*v1.Plugins)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_Plugins_To_v1_Plugins(a.(*config.Plugins), b.(*v1.Plugins), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodTopologySpreadArgs)(nil), (*config.PodTopologySpreadArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodTopologySpreadArgs_To_config_PodTopologySpreadArgs(a.(*v1.PodTopologySpreadArgs), b.(*config.PodTopologySpreadArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.PodTopologySpreadArgs)(nil), (*v1.PodTopologySpreadArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_PodTopologySpreadArgs_To_v1_PodTopologySpreadArgs(a.(*config.PodTopologySpreadArgs), b.(*v1.PodTopologySpreadArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.RequestedToCapacityRatioParam)(nil), (*config.RequestedToCapacityRatioParam)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(a.(*v1.RequestedToCapacityRatioParam), b.(*config.RequestedToCapacityRatioParam), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.RequestedToCapacityRatioParam)(nil), (*v1.RequestedToCapacityRatioParam)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_RequestedToCapacityRatioParam_To_v1_RequestedToCapacityRatioParam(a.(*config.RequestedToCapacityRatioParam), b.(*v1.RequestedToCapacityRatioParam), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ResourceSpec)(nil), (*config.ResourceSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ResourceSpec_To_config_ResourceSpec(a.(*v1.ResourceSpec), b.(*config.ResourceSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.ResourceSpec)(nil), (*v1.ResourceSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_ResourceSpec_To_v1_ResourceSpec(a.(*config.ResourceSpec), b.(*v1.ResourceSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ScoringStrategy)(nil), (*config.ScoringStrategy)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ScoringStrategy_To_config_ScoringStrategy(a.(*v1.ScoringStrategy), b.(*config.ScoringStrategy), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.ScoringStrategy)(nil), (*v1.ScoringStrategy)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_ScoringStrategy_To_v1_ScoringStrategy(a.(*config.ScoringStrategy), b.(*v1.ScoringStrategy), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.UtilizationShapePoint)(nil), (*config.UtilizationShapePoint)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_UtilizationShapePoint_To_config_UtilizationShapePoint(a.(*v1.UtilizationShapePoint), b.(*config.UtilizationShapePoint), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.UtilizationShapePoint)(nil), (*v1.UtilizationShapePoint)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_UtilizationShapePoint_To_v1_UtilizationShapePoint(a.(*config.UtilizationShapePoint), b.(*v1.UtilizationShapePoint), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.VolumeBindingArgs)(nil), (*config.VolumeBindingArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_VolumeBindingArgs_To_config_VolumeBindingArgs(a.(*v1.VolumeBindingArgs), b.(*config.VolumeBindingArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.VolumeBindingArgs)(nil), (*v1.VolumeBindingArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_VolumeBindingArgs_To_v1_VolumeBindingArgs(a.(*config.VolumeBindingArgs), b.(*v1.VolumeBindingArgs), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*config.KubeSchedulerConfiguration)(nil), (*v1.KubeSchedulerConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_KubeSchedulerConfiguration_To_v1_KubeSchedulerConfiguration(a.(*config.KubeSchedulerConfiguration), b.(*v1.KubeSchedulerConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1.KubeSchedulerConfiguration)(nil), (*config.KubeSchedulerConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_KubeSchedulerConfiguration_To_config_KubeSchedulerConfiguration(a.(*v1.KubeSchedulerConfiguration), b.(*config.KubeSchedulerConfiguration), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v1_DefaultPreemptionArgs_To_config_DefaultPreemptionArgs(in *v1.DefaultPreemptionArgs, out *config.DefaultPreemptionArgs, s conversion.Scope) error { + if err := metav1.Convert_Pointer_int32_To_int32(&in.MinCandidateNodesPercentage, &out.MinCandidateNodesPercentage, s); err != nil { + return err + } + if err := metav1.Convert_Pointer_int32_To_int32(&in.MinCandidateNodesAbsolute, &out.MinCandidateNodesAbsolute, s); err != nil { + return err + } + return nil +} + +// Convert_v1_DefaultPreemptionArgs_To_config_DefaultPreemptionArgs is an autogenerated conversion function. +func Convert_v1_DefaultPreemptionArgs_To_config_DefaultPreemptionArgs(in *v1.DefaultPreemptionArgs, out *config.DefaultPreemptionArgs, s conversion.Scope) error { + return autoConvert_v1_DefaultPreemptionArgs_To_config_DefaultPreemptionArgs(in, out, s) +} + +func autoConvert_config_DefaultPreemptionArgs_To_v1_DefaultPreemptionArgs(in *config.DefaultPreemptionArgs, out *v1.DefaultPreemptionArgs, s conversion.Scope) error { + if err := metav1.Convert_int32_To_Pointer_int32(&in.MinCandidateNodesPercentage, &out.MinCandidateNodesPercentage, s); err != nil { + return err + } + if err := metav1.Convert_int32_To_Pointer_int32(&in.MinCandidateNodesAbsolute, &out.MinCandidateNodesAbsolute, s); err != nil { + return err + } + return nil +} + +// Convert_config_DefaultPreemptionArgs_To_v1_DefaultPreemptionArgs is an autogenerated conversion function. +func Convert_config_DefaultPreemptionArgs_To_v1_DefaultPreemptionArgs(in *config.DefaultPreemptionArgs, out *v1.DefaultPreemptionArgs, s conversion.Scope) error { + return autoConvert_config_DefaultPreemptionArgs_To_v1_DefaultPreemptionArgs(in, out, s) +} + +func autoConvert_v1_Extender_To_config_Extender(in *v1.Extender, out *config.Extender, s conversion.Scope) error { + out.URLPrefix = in.URLPrefix + out.FilterVerb = in.FilterVerb + out.PreemptVerb = in.PreemptVerb + out.PrioritizeVerb = in.PrioritizeVerb + out.Weight = in.Weight + out.BindVerb = in.BindVerb + out.EnableHTTPS = in.EnableHTTPS + out.TLSConfig = (*config.ExtenderTLSConfig)(unsafe.Pointer(in.TLSConfig)) + out.HTTPTimeout = in.HTTPTimeout + out.NodeCacheCapable = in.NodeCacheCapable + out.ManagedResources = *(*[]config.ExtenderManagedResource)(unsafe.Pointer(&in.ManagedResources)) + out.Ignorable = in.Ignorable + return nil +} + +// Convert_v1_Extender_To_config_Extender is an autogenerated conversion function. +func Convert_v1_Extender_To_config_Extender(in *v1.Extender, out *config.Extender, s conversion.Scope) error { + return autoConvert_v1_Extender_To_config_Extender(in, out, s) +} + +func autoConvert_config_Extender_To_v1_Extender(in *config.Extender, out *v1.Extender, s conversion.Scope) error { + out.URLPrefix = in.URLPrefix + out.FilterVerb = in.FilterVerb + out.PreemptVerb = in.PreemptVerb + out.PrioritizeVerb = in.PrioritizeVerb + out.Weight = in.Weight + out.BindVerb = in.BindVerb + out.EnableHTTPS = in.EnableHTTPS + out.TLSConfig = (*v1.ExtenderTLSConfig)(unsafe.Pointer(in.TLSConfig)) + out.HTTPTimeout = in.HTTPTimeout + out.NodeCacheCapable = in.NodeCacheCapable + out.ManagedResources = *(*[]v1.ExtenderManagedResource)(unsafe.Pointer(&in.ManagedResources)) + out.Ignorable = in.Ignorable + return nil +} + +// Convert_config_Extender_To_v1_Extender is an autogenerated conversion function. +func Convert_config_Extender_To_v1_Extender(in *config.Extender, out *v1.Extender, s conversion.Scope) error { + return autoConvert_config_Extender_To_v1_Extender(in, out, s) +} + +func autoConvert_v1_ExtenderManagedResource_To_config_ExtenderManagedResource(in *v1.ExtenderManagedResource, out *config.ExtenderManagedResource, s conversion.Scope) error { + out.Name = in.Name + out.IgnoredByScheduler = in.IgnoredByScheduler + return nil +} + +// Convert_v1_ExtenderManagedResource_To_config_ExtenderManagedResource is an autogenerated conversion function. +func Convert_v1_ExtenderManagedResource_To_config_ExtenderManagedResource(in *v1.ExtenderManagedResource, out *config.ExtenderManagedResource, s conversion.Scope) error { + return autoConvert_v1_ExtenderManagedResource_To_config_ExtenderManagedResource(in, out, s) +} + +func autoConvert_config_ExtenderManagedResource_To_v1_ExtenderManagedResource(in *config.ExtenderManagedResource, out *v1.ExtenderManagedResource, s conversion.Scope) error { + out.Name = in.Name + out.IgnoredByScheduler = in.IgnoredByScheduler + return nil +} + +// Convert_config_ExtenderManagedResource_To_v1_ExtenderManagedResource is an autogenerated conversion function. +func Convert_config_ExtenderManagedResource_To_v1_ExtenderManagedResource(in *config.ExtenderManagedResource, out *v1.ExtenderManagedResource, s conversion.Scope) error { + return autoConvert_config_ExtenderManagedResource_To_v1_ExtenderManagedResource(in, out, s) +} + +func autoConvert_v1_ExtenderTLSConfig_To_config_ExtenderTLSConfig(in *v1.ExtenderTLSConfig, out *config.ExtenderTLSConfig, s conversion.Scope) error { + out.Insecure = in.Insecure + out.ServerName = in.ServerName + out.CertFile = in.CertFile + out.KeyFile = in.KeyFile + out.CAFile = in.CAFile + out.CertData = *(*[]byte)(unsafe.Pointer(&in.CertData)) + out.KeyData = *(*[]byte)(unsafe.Pointer(&in.KeyData)) + out.CAData = *(*[]byte)(unsafe.Pointer(&in.CAData)) + return nil +} + +// Convert_v1_ExtenderTLSConfig_To_config_ExtenderTLSConfig is an autogenerated conversion function. +func Convert_v1_ExtenderTLSConfig_To_config_ExtenderTLSConfig(in *v1.ExtenderTLSConfig, out *config.ExtenderTLSConfig, s conversion.Scope) error { + return autoConvert_v1_ExtenderTLSConfig_To_config_ExtenderTLSConfig(in, out, s) +} + +func autoConvert_config_ExtenderTLSConfig_To_v1_ExtenderTLSConfig(in *config.ExtenderTLSConfig, out *v1.ExtenderTLSConfig, s conversion.Scope) error { + out.Insecure = in.Insecure + out.ServerName = in.ServerName + out.CertFile = in.CertFile + out.KeyFile = in.KeyFile + out.CAFile = in.CAFile + out.CertData = *(*[]byte)(unsafe.Pointer(&in.CertData)) + out.KeyData = *(*[]byte)(unsafe.Pointer(&in.KeyData)) + out.CAData = *(*[]byte)(unsafe.Pointer(&in.CAData)) + return nil +} + +// Convert_config_ExtenderTLSConfig_To_v1_ExtenderTLSConfig is an autogenerated conversion function. +func Convert_config_ExtenderTLSConfig_To_v1_ExtenderTLSConfig(in *config.ExtenderTLSConfig, out *v1.ExtenderTLSConfig, s conversion.Scope) error { + return autoConvert_config_ExtenderTLSConfig_To_v1_ExtenderTLSConfig(in, out, s) +} + +func autoConvert_v1_InterPodAffinityArgs_To_config_InterPodAffinityArgs(in *v1.InterPodAffinityArgs, out *config.InterPodAffinityArgs, s conversion.Scope) error { + if err := metav1.Convert_Pointer_int32_To_int32(&in.HardPodAffinityWeight, &out.HardPodAffinityWeight, s); err != nil { + return err + } + return nil +} + +// Convert_v1_InterPodAffinityArgs_To_config_InterPodAffinityArgs is an autogenerated conversion function. +func Convert_v1_InterPodAffinityArgs_To_config_InterPodAffinityArgs(in *v1.InterPodAffinityArgs, out *config.InterPodAffinityArgs, s conversion.Scope) error { + return autoConvert_v1_InterPodAffinityArgs_To_config_InterPodAffinityArgs(in, out, s) +} + +func autoConvert_config_InterPodAffinityArgs_To_v1_InterPodAffinityArgs(in *config.InterPodAffinityArgs, out *v1.InterPodAffinityArgs, s conversion.Scope) error { + if err := metav1.Convert_int32_To_Pointer_int32(&in.HardPodAffinityWeight, &out.HardPodAffinityWeight, s); err != nil { + return err + } + return nil +} + +// Convert_config_InterPodAffinityArgs_To_v1_InterPodAffinityArgs is an autogenerated conversion function. +func Convert_config_InterPodAffinityArgs_To_v1_InterPodAffinityArgs(in *config.InterPodAffinityArgs, out *v1.InterPodAffinityArgs, s conversion.Scope) error { + return autoConvert_config_InterPodAffinityArgs_To_v1_InterPodAffinityArgs(in, out, s) +} + +func autoConvert_v1_KubeSchedulerConfiguration_To_config_KubeSchedulerConfiguration(in *v1.KubeSchedulerConfiguration, out *config.KubeSchedulerConfiguration, s conversion.Scope) error { + if err := metav1.Convert_Pointer_int32_To_int32(&in.Parallelism, &out.Parallelism, s); err != nil { + return err + } + if err := v1alpha1.Convert_v1alpha1_LeaderElectionConfiguration_To_config_LeaderElectionConfiguration(&in.LeaderElection, &out.LeaderElection, s); err != nil { + return err + } + if err := v1alpha1.Convert_v1alpha1_ClientConnectionConfiguration_To_config_ClientConnectionConfiguration(&in.ClientConnection, &out.ClientConnection, s); err != nil { + return err + } + if err := v1alpha1.Convert_v1alpha1_DebuggingConfiguration_To_config_DebuggingConfiguration(&in.DebuggingConfiguration, &out.DebuggingConfiguration, s); err != nil { + return err + } + out.PercentageOfNodesToScore = (*int32)(unsafe.Pointer(in.PercentageOfNodesToScore)) + if err := metav1.Convert_Pointer_int64_To_int64(&in.PodInitialBackoffSeconds, &out.PodInitialBackoffSeconds, s); err != nil { + return err + } + if err := metav1.Convert_Pointer_int64_To_int64(&in.PodMaxBackoffSeconds, &out.PodMaxBackoffSeconds, s); err != nil { + return err + } + if in.Profiles != nil { + in, out := &in.Profiles, &out.Profiles + *out = make([]config.KubeSchedulerProfile, len(*in)) + for i := range *in { + if err := Convert_v1_KubeSchedulerProfile_To_config_KubeSchedulerProfile(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Profiles = nil + } + out.Extenders = *(*[]config.Extender)(unsafe.Pointer(&in.Extenders)) + return nil +} + +func autoConvert_config_KubeSchedulerConfiguration_To_v1_KubeSchedulerConfiguration(in *config.KubeSchedulerConfiguration, out *v1.KubeSchedulerConfiguration, s conversion.Scope) error { + if err := metav1.Convert_int32_To_Pointer_int32(&in.Parallelism, &out.Parallelism, s); err != nil { + return err + } + if err := v1alpha1.Convert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfiguration(&in.LeaderElection, &out.LeaderElection, s); err != nil { + return err + } + if err := v1alpha1.Convert_config_ClientConnectionConfiguration_To_v1alpha1_ClientConnectionConfiguration(&in.ClientConnection, &out.ClientConnection, s); err != nil { + return err + } + // WARNING: in.HealthzBindAddress requires manual conversion: does not exist in peer-type + // WARNING: in.MetricsBindAddress requires manual conversion: does not exist in peer-type + if err := v1alpha1.Convert_config_DebuggingConfiguration_To_v1alpha1_DebuggingConfiguration(&in.DebuggingConfiguration, &out.DebuggingConfiguration, s); err != nil { + return err + } + out.PercentageOfNodesToScore = (*int32)(unsafe.Pointer(in.PercentageOfNodesToScore)) + if err := metav1.Convert_int64_To_Pointer_int64(&in.PodInitialBackoffSeconds, &out.PodInitialBackoffSeconds, s); err != nil { + return err + } + if err := metav1.Convert_int64_To_Pointer_int64(&in.PodMaxBackoffSeconds, &out.PodMaxBackoffSeconds, s); err != nil { + return err + } + if in.Profiles != nil { + in, out := &in.Profiles, &out.Profiles + *out = make([]v1.KubeSchedulerProfile, len(*in)) + for i := range *in { + if err := Convert_config_KubeSchedulerProfile_To_v1_KubeSchedulerProfile(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Profiles = nil + } + out.Extenders = *(*[]v1.Extender)(unsafe.Pointer(&in.Extenders)) + return nil +} + +func autoConvert_v1_KubeSchedulerProfile_To_config_KubeSchedulerProfile(in *v1.KubeSchedulerProfile, out *config.KubeSchedulerProfile, s conversion.Scope) error { + if err := metav1.Convert_Pointer_string_To_string(&in.SchedulerName, &out.SchedulerName, s); err != nil { + return err + } + out.PercentageOfNodesToScore = (*int32)(unsafe.Pointer(in.PercentageOfNodesToScore)) + if in.Plugins != nil { + in, out := &in.Plugins, &out.Plugins + *out = new(config.Plugins) + if err := Convert_v1_Plugins_To_config_Plugins(*in, *out, s); err != nil { + return err + } + } else { + out.Plugins = nil + } + if in.PluginConfig != nil { + in, out := &in.PluginConfig, &out.PluginConfig + *out = make([]config.PluginConfig, len(*in)) + for i := range *in { + if err := Convert_v1_PluginConfig_To_config_PluginConfig(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.PluginConfig = nil + } + return nil +} + +// Convert_v1_KubeSchedulerProfile_To_config_KubeSchedulerProfile is an autogenerated conversion function. +func Convert_v1_KubeSchedulerProfile_To_config_KubeSchedulerProfile(in *v1.KubeSchedulerProfile, out *config.KubeSchedulerProfile, s conversion.Scope) error { + return autoConvert_v1_KubeSchedulerProfile_To_config_KubeSchedulerProfile(in, out, s) +} + +func autoConvert_config_KubeSchedulerProfile_To_v1_KubeSchedulerProfile(in *config.KubeSchedulerProfile, out *v1.KubeSchedulerProfile, s conversion.Scope) error { + if err := metav1.Convert_string_To_Pointer_string(&in.SchedulerName, &out.SchedulerName, s); err != nil { + return err + } + out.PercentageOfNodesToScore = (*int32)(unsafe.Pointer(in.PercentageOfNodesToScore)) + if in.Plugins != nil { + in, out := &in.Plugins, &out.Plugins + *out = new(v1.Plugins) + if err := Convert_config_Plugins_To_v1_Plugins(*in, *out, s); err != nil { + return err + } + } else { + out.Plugins = nil + } + if in.PluginConfig != nil { + in, out := &in.PluginConfig, &out.PluginConfig + *out = make([]v1.PluginConfig, len(*in)) + for i := range *in { + if err := Convert_config_PluginConfig_To_v1_PluginConfig(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.PluginConfig = nil + } + return nil +} + +// Convert_config_KubeSchedulerProfile_To_v1_KubeSchedulerProfile is an autogenerated conversion function. +func Convert_config_KubeSchedulerProfile_To_v1_KubeSchedulerProfile(in *config.KubeSchedulerProfile, out *v1.KubeSchedulerProfile, s conversion.Scope) error { + return autoConvert_config_KubeSchedulerProfile_To_v1_KubeSchedulerProfile(in, out, s) +} + +func autoConvert_v1_NodeAffinityArgs_To_config_NodeAffinityArgs(in *v1.NodeAffinityArgs, out *config.NodeAffinityArgs, s conversion.Scope) error { + out.AddedAffinity = (*corev1.NodeAffinity)(unsafe.Pointer(in.AddedAffinity)) + return nil +} + +// Convert_v1_NodeAffinityArgs_To_config_NodeAffinityArgs is an autogenerated conversion function. +func Convert_v1_NodeAffinityArgs_To_config_NodeAffinityArgs(in *v1.NodeAffinityArgs, out *config.NodeAffinityArgs, s conversion.Scope) error { + return autoConvert_v1_NodeAffinityArgs_To_config_NodeAffinityArgs(in, out, s) +} + +func autoConvert_config_NodeAffinityArgs_To_v1_NodeAffinityArgs(in *config.NodeAffinityArgs, out *v1.NodeAffinityArgs, s conversion.Scope) error { + out.AddedAffinity = (*corev1.NodeAffinity)(unsafe.Pointer(in.AddedAffinity)) + return nil +} + +// Convert_config_NodeAffinityArgs_To_v1_NodeAffinityArgs is an autogenerated conversion function. +func Convert_config_NodeAffinityArgs_To_v1_NodeAffinityArgs(in *config.NodeAffinityArgs, out *v1.NodeAffinityArgs, s conversion.Scope) error { + return autoConvert_config_NodeAffinityArgs_To_v1_NodeAffinityArgs(in, out, s) +} + +func autoConvert_v1_NodeResourcesBalancedAllocationArgs_To_config_NodeResourcesBalancedAllocationArgs(in *v1.NodeResourcesBalancedAllocationArgs, out *config.NodeResourcesBalancedAllocationArgs, s conversion.Scope) error { + out.Resources = *(*[]config.ResourceSpec)(unsafe.Pointer(&in.Resources)) + return nil +} + +// Convert_v1_NodeResourcesBalancedAllocationArgs_To_config_NodeResourcesBalancedAllocationArgs is an autogenerated conversion function. +func Convert_v1_NodeResourcesBalancedAllocationArgs_To_config_NodeResourcesBalancedAllocationArgs(in *v1.NodeResourcesBalancedAllocationArgs, out *config.NodeResourcesBalancedAllocationArgs, s conversion.Scope) error { + return autoConvert_v1_NodeResourcesBalancedAllocationArgs_To_config_NodeResourcesBalancedAllocationArgs(in, out, s) +} + +func autoConvert_config_NodeResourcesBalancedAllocationArgs_To_v1_NodeResourcesBalancedAllocationArgs(in *config.NodeResourcesBalancedAllocationArgs, out *v1.NodeResourcesBalancedAllocationArgs, s conversion.Scope) error { + out.Resources = *(*[]v1.ResourceSpec)(unsafe.Pointer(&in.Resources)) + return nil +} + +// Convert_config_NodeResourcesBalancedAllocationArgs_To_v1_NodeResourcesBalancedAllocationArgs is an autogenerated conversion function. +func Convert_config_NodeResourcesBalancedAllocationArgs_To_v1_NodeResourcesBalancedAllocationArgs(in *config.NodeResourcesBalancedAllocationArgs, out *v1.NodeResourcesBalancedAllocationArgs, s conversion.Scope) error { + return autoConvert_config_NodeResourcesBalancedAllocationArgs_To_v1_NodeResourcesBalancedAllocationArgs(in, out, s) +} + +func autoConvert_v1_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs(in *v1.NodeResourcesFitArgs, out *config.NodeResourcesFitArgs, s conversion.Scope) error { + out.IgnoredResources = *(*[]string)(unsafe.Pointer(&in.IgnoredResources)) + out.IgnoredResourceGroups = *(*[]string)(unsafe.Pointer(&in.IgnoredResourceGroups)) + out.ScoringStrategy = (*config.ScoringStrategy)(unsafe.Pointer(in.ScoringStrategy)) + return nil +} + +// Convert_v1_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs is an autogenerated conversion function. +func Convert_v1_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs(in *v1.NodeResourcesFitArgs, out *config.NodeResourcesFitArgs, s conversion.Scope) error { + return autoConvert_v1_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs(in, out, s) +} + +func autoConvert_config_NodeResourcesFitArgs_To_v1_NodeResourcesFitArgs(in *config.NodeResourcesFitArgs, out *v1.NodeResourcesFitArgs, s conversion.Scope) error { + out.IgnoredResources = *(*[]string)(unsafe.Pointer(&in.IgnoredResources)) + out.IgnoredResourceGroups = *(*[]string)(unsafe.Pointer(&in.IgnoredResourceGroups)) + out.ScoringStrategy = (*v1.ScoringStrategy)(unsafe.Pointer(in.ScoringStrategy)) + return nil +} + +// Convert_config_NodeResourcesFitArgs_To_v1_NodeResourcesFitArgs is an autogenerated conversion function. +func Convert_config_NodeResourcesFitArgs_To_v1_NodeResourcesFitArgs(in *config.NodeResourcesFitArgs, out *v1.NodeResourcesFitArgs, s conversion.Scope) error { + return autoConvert_config_NodeResourcesFitArgs_To_v1_NodeResourcesFitArgs(in, out, s) +} + +func autoConvert_v1_Plugin_To_config_Plugin(in *v1.Plugin, out *config.Plugin, s conversion.Scope) error { + out.Name = in.Name + if err := metav1.Convert_Pointer_int32_To_int32(&in.Weight, &out.Weight, s); err != nil { + return err + } + return nil +} + +// Convert_v1_Plugin_To_config_Plugin is an autogenerated conversion function. +func Convert_v1_Plugin_To_config_Plugin(in *v1.Plugin, out *config.Plugin, s conversion.Scope) error { + return autoConvert_v1_Plugin_To_config_Plugin(in, out, s) +} + +func autoConvert_config_Plugin_To_v1_Plugin(in *config.Plugin, out *v1.Plugin, s conversion.Scope) error { + out.Name = in.Name + if err := metav1.Convert_int32_To_Pointer_int32(&in.Weight, &out.Weight, s); err != nil { + return err + } + return nil +} + +// Convert_config_Plugin_To_v1_Plugin is an autogenerated conversion function. +func Convert_config_Plugin_To_v1_Plugin(in *config.Plugin, out *v1.Plugin, s conversion.Scope) error { + return autoConvert_config_Plugin_To_v1_Plugin(in, out, s) +} + +func autoConvert_v1_PluginConfig_To_config_PluginConfig(in *v1.PluginConfig, out *config.PluginConfig, s conversion.Scope) error { + out.Name = in.Name + if err := runtime.Convert_runtime_RawExtension_To_runtime_Object(&in.Args, &out.Args, s); err != nil { + return err + } + return nil +} + +// Convert_v1_PluginConfig_To_config_PluginConfig is an autogenerated conversion function. +func Convert_v1_PluginConfig_To_config_PluginConfig(in *v1.PluginConfig, out *config.PluginConfig, s conversion.Scope) error { + return autoConvert_v1_PluginConfig_To_config_PluginConfig(in, out, s) +} + +func autoConvert_config_PluginConfig_To_v1_PluginConfig(in *config.PluginConfig, out *v1.PluginConfig, s conversion.Scope) error { + out.Name = in.Name + if err := runtime.Convert_runtime_Object_To_runtime_RawExtension(&in.Args, &out.Args, s); err != nil { + return err + } + return nil +} + +// Convert_config_PluginConfig_To_v1_PluginConfig is an autogenerated conversion function. +func Convert_config_PluginConfig_To_v1_PluginConfig(in *config.PluginConfig, out *v1.PluginConfig, s conversion.Scope) error { + return autoConvert_config_PluginConfig_To_v1_PluginConfig(in, out, s) +} + +func autoConvert_v1_PluginSet_To_config_PluginSet(in *v1.PluginSet, out *config.PluginSet, s conversion.Scope) error { + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = make([]config.Plugin, len(*in)) + for i := range *in { + if err := Convert_v1_Plugin_To_config_Plugin(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Enabled = nil + } + if in.Disabled != nil { + in, out := &in.Disabled, &out.Disabled + *out = make([]config.Plugin, len(*in)) + for i := range *in { + if err := Convert_v1_Plugin_To_config_Plugin(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Disabled = nil + } + return nil +} + +// Convert_v1_PluginSet_To_config_PluginSet is an autogenerated conversion function. +func Convert_v1_PluginSet_To_config_PluginSet(in *v1.PluginSet, out *config.PluginSet, s conversion.Scope) error { + return autoConvert_v1_PluginSet_To_config_PluginSet(in, out, s) +} + +func autoConvert_config_PluginSet_To_v1_PluginSet(in *config.PluginSet, out *v1.PluginSet, s conversion.Scope) error { + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = make([]v1.Plugin, len(*in)) + for i := range *in { + if err := Convert_config_Plugin_To_v1_Plugin(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Enabled = nil + } + if in.Disabled != nil { + in, out := &in.Disabled, &out.Disabled + *out = make([]v1.Plugin, len(*in)) + for i := range *in { + if err := Convert_config_Plugin_To_v1_Plugin(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Disabled = nil + } + return nil +} + +// Convert_config_PluginSet_To_v1_PluginSet is an autogenerated conversion function. +func Convert_config_PluginSet_To_v1_PluginSet(in *config.PluginSet, out *v1.PluginSet, s conversion.Scope) error { + return autoConvert_config_PluginSet_To_v1_PluginSet(in, out, s) +} + +func autoConvert_v1_Plugins_To_config_Plugins(in *v1.Plugins, out *config.Plugins, s conversion.Scope) error { + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.PreEnqueue, &out.PreEnqueue, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.QueueSort, &out.QueueSort, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.PreFilter, &out.PreFilter, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.Filter, &out.Filter, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.PostFilter, &out.PostFilter, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.PreScore, &out.PreScore, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.Score, &out.Score, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.Reserve, &out.Reserve, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.Permit, &out.Permit, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.PreBind, &out.PreBind, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.Bind, &out.Bind, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.PostBind, &out.PostBind, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.MultiPoint, &out.MultiPoint, s); err != nil { + return err + } + return nil +} + +// Convert_v1_Plugins_To_config_Plugins is an autogenerated conversion function. +func Convert_v1_Plugins_To_config_Plugins(in *v1.Plugins, out *config.Plugins, s conversion.Scope) error { + return autoConvert_v1_Plugins_To_config_Plugins(in, out, s) +} + +func autoConvert_config_Plugins_To_v1_Plugins(in *config.Plugins, out *v1.Plugins, s conversion.Scope) error { + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.PreEnqueue, &out.PreEnqueue, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.QueueSort, &out.QueueSort, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.PreFilter, &out.PreFilter, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.Filter, &out.Filter, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.PostFilter, &out.PostFilter, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.PreScore, &out.PreScore, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.Score, &out.Score, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.Reserve, &out.Reserve, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.Permit, &out.Permit, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.PreBind, &out.PreBind, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.Bind, &out.Bind, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.PostBind, &out.PostBind, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.MultiPoint, &out.MultiPoint, s); err != nil { + return err + } + return nil +} + +// Convert_config_Plugins_To_v1_Plugins is an autogenerated conversion function. +func Convert_config_Plugins_To_v1_Plugins(in *config.Plugins, out *v1.Plugins, s conversion.Scope) error { + return autoConvert_config_Plugins_To_v1_Plugins(in, out, s) +} + +func autoConvert_v1_PodTopologySpreadArgs_To_config_PodTopologySpreadArgs(in *v1.PodTopologySpreadArgs, out *config.PodTopologySpreadArgs, s conversion.Scope) error { + out.DefaultConstraints = *(*[]corev1.TopologySpreadConstraint)(unsafe.Pointer(&in.DefaultConstraints)) + out.DefaultingType = config.PodTopologySpreadConstraintsDefaulting(in.DefaultingType) + return nil +} + +// Convert_v1_PodTopologySpreadArgs_To_config_PodTopologySpreadArgs is an autogenerated conversion function. +func Convert_v1_PodTopologySpreadArgs_To_config_PodTopologySpreadArgs(in *v1.PodTopologySpreadArgs, out *config.PodTopologySpreadArgs, s conversion.Scope) error { + return autoConvert_v1_PodTopologySpreadArgs_To_config_PodTopologySpreadArgs(in, out, s) +} + +func autoConvert_config_PodTopologySpreadArgs_To_v1_PodTopologySpreadArgs(in *config.PodTopologySpreadArgs, out *v1.PodTopologySpreadArgs, s conversion.Scope) error { + out.DefaultConstraints = *(*[]corev1.TopologySpreadConstraint)(unsafe.Pointer(&in.DefaultConstraints)) + out.DefaultingType = v1.PodTopologySpreadConstraintsDefaulting(in.DefaultingType) + return nil +} + +// Convert_config_PodTopologySpreadArgs_To_v1_PodTopologySpreadArgs is an autogenerated conversion function. +func Convert_config_PodTopologySpreadArgs_To_v1_PodTopologySpreadArgs(in *config.PodTopologySpreadArgs, out *v1.PodTopologySpreadArgs, s conversion.Scope) error { + return autoConvert_config_PodTopologySpreadArgs_To_v1_PodTopologySpreadArgs(in, out, s) +} + +func autoConvert_v1_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(in *v1.RequestedToCapacityRatioParam, out *config.RequestedToCapacityRatioParam, s conversion.Scope) error { + out.Shape = *(*[]config.UtilizationShapePoint)(unsafe.Pointer(&in.Shape)) + return nil +} + +// Convert_v1_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam is an autogenerated conversion function. +func Convert_v1_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(in *v1.RequestedToCapacityRatioParam, out *config.RequestedToCapacityRatioParam, s conversion.Scope) error { + return autoConvert_v1_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(in, out, s) +} + +func autoConvert_config_RequestedToCapacityRatioParam_To_v1_RequestedToCapacityRatioParam(in *config.RequestedToCapacityRatioParam, out *v1.RequestedToCapacityRatioParam, s conversion.Scope) error { + out.Shape = *(*[]v1.UtilizationShapePoint)(unsafe.Pointer(&in.Shape)) + return nil +} + +// Convert_config_RequestedToCapacityRatioParam_To_v1_RequestedToCapacityRatioParam is an autogenerated conversion function. +func Convert_config_RequestedToCapacityRatioParam_To_v1_RequestedToCapacityRatioParam(in *config.RequestedToCapacityRatioParam, out *v1.RequestedToCapacityRatioParam, s conversion.Scope) error { + return autoConvert_config_RequestedToCapacityRatioParam_To_v1_RequestedToCapacityRatioParam(in, out, s) +} + +func autoConvert_v1_ResourceSpec_To_config_ResourceSpec(in *v1.ResourceSpec, out *config.ResourceSpec, s conversion.Scope) error { + out.Name = in.Name + out.Weight = in.Weight + return nil +} + +// Convert_v1_ResourceSpec_To_config_ResourceSpec is an autogenerated conversion function. +func Convert_v1_ResourceSpec_To_config_ResourceSpec(in *v1.ResourceSpec, out *config.ResourceSpec, s conversion.Scope) error { + return autoConvert_v1_ResourceSpec_To_config_ResourceSpec(in, out, s) +} + +func autoConvert_config_ResourceSpec_To_v1_ResourceSpec(in *config.ResourceSpec, out *v1.ResourceSpec, s conversion.Scope) error { + out.Name = in.Name + out.Weight = in.Weight + return nil +} + +// Convert_config_ResourceSpec_To_v1_ResourceSpec is an autogenerated conversion function. +func Convert_config_ResourceSpec_To_v1_ResourceSpec(in *config.ResourceSpec, out *v1.ResourceSpec, s conversion.Scope) error { + return autoConvert_config_ResourceSpec_To_v1_ResourceSpec(in, out, s) +} + +func autoConvert_v1_ScoringStrategy_To_config_ScoringStrategy(in *v1.ScoringStrategy, out *config.ScoringStrategy, s conversion.Scope) error { + out.Type = config.ScoringStrategyType(in.Type) + out.Resources = *(*[]config.ResourceSpec)(unsafe.Pointer(&in.Resources)) + out.RequestedToCapacityRatio = (*config.RequestedToCapacityRatioParam)(unsafe.Pointer(in.RequestedToCapacityRatio)) + return nil +} + +// Convert_v1_ScoringStrategy_To_config_ScoringStrategy is an autogenerated conversion function. +func Convert_v1_ScoringStrategy_To_config_ScoringStrategy(in *v1.ScoringStrategy, out *config.ScoringStrategy, s conversion.Scope) error { + return autoConvert_v1_ScoringStrategy_To_config_ScoringStrategy(in, out, s) +} + +func autoConvert_config_ScoringStrategy_To_v1_ScoringStrategy(in *config.ScoringStrategy, out *v1.ScoringStrategy, s conversion.Scope) error { + out.Type = v1.ScoringStrategyType(in.Type) + out.Resources = *(*[]v1.ResourceSpec)(unsafe.Pointer(&in.Resources)) + out.RequestedToCapacityRatio = (*v1.RequestedToCapacityRatioParam)(unsafe.Pointer(in.RequestedToCapacityRatio)) + return nil +} + +// Convert_config_ScoringStrategy_To_v1_ScoringStrategy is an autogenerated conversion function. +func Convert_config_ScoringStrategy_To_v1_ScoringStrategy(in *config.ScoringStrategy, out *v1.ScoringStrategy, s conversion.Scope) error { + return autoConvert_config_ScoringStrategy_To_v1_ScoringStrategy(in, out, s) +} + +func autoConvert_v1_UtilizationShapePoint_To_config_UtilizationShapePoint(in *v1.UtilizationShapePoint, out *config.UtilizationShapePoint, s conversion.Scope) error { + out.Utilization = in.Utilization + out.Score = in.Score + return nil +} + +// Convert_v1_UtilizationShapePoint_To_config_UtilizationShapePoint is an autogenerated conversion function. +func Convert_v1_UtilizationShapePoint_To_config_UtilizationShapePoint(in *v1.UtilizationShapePoint, out *config.UtilizationShapePoint, s conversion.Scope) error { + return autoConvert_v1_UtilizationShapePoint_To_config_UtilizationShapePoint(in, out, s) +} + +func autoConvert_config_UtilizationShapePoint_To_v1_UtilizationShapePoint(in *config.UtilizationShapePoint, out *v1.UtilizationShapePoint, s conversion.Scope) error { + out.Utilization = in.Utilization + out.Score = in.Score + return nil +} + +// Convert_config_UtilizationShapePoint_To_v1_UtilizationShapePoint is an autogenerated conversion function. +func Convert_config_UtilizationShapePoint_To_v1_UtilizationShapePoint(in *config.UtilizationShapePoint, out *v1.UtilizationShapePoint, s conversion.Scope) error { + return autoConvert_config_UtilizationShapePoint_To_v1_UtilizationShapePoint(in, out, s) +} + +func autoConvert_v1_VolumeBindingArgs_To_config_VolumeBindingArgs(in *v1.VolumeBindingArgs, out *config.VolumeBindingArgs, s conversion.Scope) error { + if err := metav1.Convert_Pointer_int64_To_int64(&in.BindTimeoutSeconds, &out.BindTimeoutSeconds, s); err != nil { + return err + } + out.Shape = *(*[]config.UtilizationShapePoint)(unsafe.Pointer(&in.Shape)) + return nil +} + +// Convert_v1_VolumeBindingArgs_To_config_VolumeBindingArgs is an autogenerated conversion function. +func Convert_v1_VolumeBindingArgs_To_config_VolumeBindingArgs(in *v1.VolumeBindingArgs, out *config.VolumeBindingArgs, s conversion.Scope) error { + return autoConvert_v1_VolumeBindingArgs_To_config_VolumeBindingArgs(in, out, s) +} + +func autoConvert_config_VolumeBindingArgs_To_v1_VolumeBindingArgs(in *config.VolumeBindingArgs, out *v1.VolumeBindingArgs, s conversion.Scope) error { + if err := metav1.Convert_int64_To_Pointer_int64(&in.BindTimeoutSeconds, &out.BindTimeoutSeconds, s); err != nil { + return err + } + out.Shape = *(*[]v1.UtilizationShapePoint)(unsafe.Pointer(&in.Shape)) + return nil +} + +// Convert_config_VolumeBindingArgs_To_v1_VolumeBindingArgs is an autogenerated conversion function. +func Convert_config_VolumeBindingArgs_To_v1_VolumeBindingArgs(in *config.VolumeBindingArgs, out *v1.VolumeBindingArgs, s conversion.Scope) error { + return autoConvert_config_VolumeBindingArgs_To_v1_VolumeBindingArgs(in, out, s) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/zz_generated.deepcopy.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/zz_generated.deepcopy.go new file mode 100644 index 000000000..87181b430 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/zz_generated.deepcopy.go @@ -0,0 +1,22 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/zz_generated.defaults.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/zz_generated.defaults.go new file mode 100644 index 000000000..ac93d735c --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1/zz_generated.defaults.go @@ -0,0 +1,73 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" + v1 "k8s.io/kube-scheduler/config/v1" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + scheme.AddTypeDefaultingFunc(&v1.DefaultPreemptionArgs{}, func(obj interface{}) { SetObjectDefaults_DefaultPreemptionArgs(obj.(*v1.DefaultPreemptionArgs)) }) + scheme.AddTypeDefaultingFunc(&v1.InterPodAffinityArgs{}, func(obj interface{}) { SetObjectDefaults_InterPodAffinityArgs(obj.(*v1.InterPodAffinityArgs)) }) + scheme.AddTypeDefaultingFunc(&v1.KubeSchedulerConfiguration{}, func(obj interface{}) { + SetObjectDefaults_KubeSchedulerConfiguration(obj.(*v1.KubeSchedulerConfiguration)) + }) + scheme.AddTypeDefaultingFunc(&v1.NodeResourcesBalancedAllocationArgs{}, func(obj interface{}) { + SetObjectDefaults_NodeResourcesBalancedAllocationArgs(obj.(*v1.NodeResourcesBalancedAllocationArgs)) + }) + scheme.AddTypeDefaultingFunc(&v1.NodeResourcesFitArgs{}, func(obj interface{}) { SetObjectDefaults_NodeResourcesFitArgs(obj.(*v1.NodeResourcesFitArgs)) }) + scheme.AddTypeDefaultingFunc(&v1.PodTopologySpreadArgs{}, func(obj interface{}) { SetObjectDefaults_PodTopologySpreadArgs(obj.(*v1.PodTopologySpreadArgs)) }) + scheme.AddTypeDefaultingFunc(&v1.VolumeBindingArgs{}, func(obj interface{}) { SetObjectDefaults_VolumeBindingArgs(obj.(*v1.VolumeBindingArgs)) }) + return nil +} + +func SetObjectDefaults_DefaultPreemptionArgs(in *v1.DefaultPreemptionArgs) { + SetDefaults_DefaultPreemptionArgs(in) +} + +func SetObjectDefaults_InterPodAffinityArgs(in *v1.InterPodAffinityArgs) { + SetDefaults_InterPodAffinityArgs(in) +} + +func SetObjectDefaults_KubeSchedulerConfiguration(in *v1.KubeSchedulerConfiguration) { + SetDefaults_KubeSchedulerConfiguration(in) +} + +func SetObjectDefaults_NodeResourcesBalancedAllocationArgs(in *v1.NodeResourcesBalancedAllocationArgs) { + SetDefaults_NodeResourcesBalancedAllocationArgs(in) +} + +func SetObjectDefaults_NodeResourcesFitArgs(in *v1.NodeResourcesFitArgs) { + SetDefaults_NodeResourcesFitArgs(in) +} + +func SetObjectDefaults_PodTopologySpreadArgs(in *v1.PodTopologySpreadArgs) { + SetDefaults_PodTopologySpreadArgs(in) +} + +func SetObjectDefaults_VolumeBindingArgs(in *v1.VolumeBindingArgs) { + SetDefaults_VolumeBindingArgs(in) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/conversion.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/conversion.go new file mode 100644 index 000000000..c0d89d75e --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/conversion.go @@ -0,0 +1,117 @@ +/* +Copyright 2021 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 v1beta2 + +import ( + "fmt" + "sync" + + "k8s.io/apimachinery/pkg/conversion" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/kube-scheduler/config/v1beta2" + "k8s.io/kubernetes/pkg/scheduler/apis/config" +) + +var ( + // pluginArgConversionScheme is a scheme with internal and v1beta2 registered, + // used for defaulting/converting typed PluginConfig Args. + // Access via getPluginArgConversionScheme() + pluginArgConversionScheme *runtime.Scheme + initPluginArgConversionScheme sync.Once +) + +func GetPluginArgConversionScheme() *runtime.Scheme { + initPluginArgConversionScheme.Do(func() { + // set up the scheme used for plugin arg conversion + pluginArgConversionScheme = runtime.NewScheme() + utilruntime.Must(AddToScheme(pluginArgConversionScheme)) + utilruntime.Must(config.AddToScheme(pluginArgConversionScheme)) + }) + return pluginArgConversionScheme +} + +func Convert_v1beta2_KubeSchedulerConfiguration_To_config_KubeSchedulerConfiguration(in *v1beta2.KubeSchedulerConfiguration, out *config.KubeSchedulerConfiguration, s conversion.Scope) error { + if err := autoConvert_v1beta2_KubeSchedulerConfiguration_To_config_KubeSchedulerConfiguration(in, out, s); err != nil { + return err + } + return convertToInternalPluginConfigArgs(out) +} + +// convertToInternalPluginConfigArgs converts PluginConfig#Args into internal +// types using a scheme, after applying defaults. +func convertToInternalPluginConfigArgs(out *config.KubeSchedulerConfiguration) error { + scheme := GetPluginArgConversionScheme() + for i := range out.Profiles { + prof := &out.Profiles[i] + for j := range prof.PluginConfig { + args := prof.PluginConfig[j].Args + if args == nil { + continue + } + if _, isUnknown := args.(*runtime.Unknown); isUnknown { + continue + } + internalArgs, err := scheme.ConvertToVersion(args, config.SchemeGroupVersion) + if err != nil { + return fmt.Errorf("converting .Profiles[%d].PluginConfig[%d].Args into internal type: %w", i, j, err) + } + prof.PluginConfig[j].Args = internalArgs + } + } + return nil +} + +func Convert_config_KubeSchedulerConfiguration_To_v1beta2_KubeSchedulerConfiguration(in *config.KubeSchedulerConfiguration, out *v1beta2.KubeSchedulerConfiguration, s conversion.Scope) error { + if err := autoConvert_config_KubeSchedulerConfiguration_To_v1beta2_KubeSchedulerConfiguration(in, out, s); err != nil { + return err + } + return convertToExternalPluginConfigArgs(out) +} + +// convertToExternalPluginConfigArgs converts PluginConfig#Args into +// external (versioned) types using a scheme. +func convertToExternalPluginConfigArgs(out *v1beta2.KubeSchedulerConfiguration) error { + scheme := GetPluginArgConversionScheme() + for i := range out.Profiles { + for j := range out.Profiles[i].PluginConfig { + args := out.Profiles[i].PluginConfig[j].Args + if args.Object == nil { + continue + } + if _, isUnknown := args.Object.(*runtime.Unknown); isUnknown { + continue + } + externalArgs, err := scheme.ConvertToVersion(args.Object, SchemeGroupVersion) + if err != nil { + return err + } + out.Profiles[i].PluginConfig[j].Args.Object = externalArgs + } + } + return nil +} + +// Convert_config_KubeSchedulerProfile_To_v1beta2_KubeSchedulerProfile uses auto coversion by +// ignoring per profile PercentageOfNodesToScore. +func Convert_config_KubeSchedulerProfile_To_v1beta2_KubeSchedulerProfile(in *config.KubeSchedulerProfile, out *v1beta2.KubeSchedulerProfile, s conversion.Scope) error { + return autoConvert_config_KubeSchedulerProfile_To_v1beta2_KubeSchedulerProfile(in, out, s) +} + +func Convert_config_Plugins_To_v1beta2_Plugins(in *config.Plugins, out *v1beta2.Plugins, s conversion.Scope) error { + return autoConvert_config_Plugins_To_v1beta2_Plugins(in, out, s) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/default_plugins.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/default_plugins.go new file mode 100644 index 000000000..37341a423 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/default_plugins.go @@ -0,0 +1,186 @@ +/* +Copyright 2021 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 v1beta2 + +import ( + "k8s.io/apimachinery/pkg/util/sets" + utilfeature "k8s.io/apiserver/pkg/util/feature" + "k8s.io/klog/v2" + "k8s.io/kube-scheduler/config/v1beta2" + "k8s.io/kubernetes/pkg/features" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" + "k8s.io/utils/pointer" +) + +// getDefaultPlugins returns the default set of plugins. +func getDefaultPlugins() *v1beta2.Plugins { + plugins := &v1beta2.Plugins{ + QueueSort: v1beta2.PluginSet{ + Enabled: []v1beta2.Plugin{ + {Name: names.PrioritySort}, + }, + }, + PreFilter: v1beta2.PluginSet{ + Enabled: []v1beta2.Plugin{ + {Name: names.NodeResourcesFit}, + {Name: names.NodePorts}, + {Name: names.VolumeRestrictions}, + {Name: names.PodTopologySpread}, + {Name: names.InterPodAffinity}, + {Name: names.VolumeBinding}, + {Name: names.NodeAffinity}, + }, + }, + Filter: v1beta2.PluginSet{ + Enabled: []v1beta2.Plugin{ + {Name: names.NodeUnschedulable}, + {Name: names.NodeName}, + {Name: names.TaintToleration}, + {Name: names.NodeAffinity}, + {Name: names.NodePorts}, + {Name: names.NodeResourcesFit}, + {Name: names.VolumeRestrictions}, + {Name: names.EBSLimits}, + {Name: names.GCEPDLimits}, + {Name: names.NodeVolumeLimits}, + {Name: names.AzureDiskLimits}, + {Name: names.VolumeBinding}, + {Name: names.VolumeZone}, + {Name: names.PodTopologySpread}, + {Name: names.InterPodAffinity}, + }, + }, + PostFilter: v1beta2.PluginSet{ + Enabled: []v1beta2.Plugin{ + {Name: names.DefaultPreemption}, + }, + }, + PreScore: v1beta2.PluginSet{ + Enabled: []v1beta2.Plugin{ + {Name: names.InterPodAffinity}, + {Name: names.PodTopologySpread}, + {Name: names.TaintToleration}, + {Name: names.NodeAffinity}, + }, + }, + Score: v1beta2.PluginSet{ + Enabled: []v1beta2.Plugin{ + {Name: names.NodeResourcesBalancedAllocation, Weight: pointer.Int32(1)}, + {Name: names.ImageLocality, Weight: pointer.Int32(1)}, + {Name: names.InterPodAffinity, Weight: pointer.Int32(1)}, + {Name: names.NodeResourcesFit, Weight: pointer.Int32(1)}, + {Name: names.NodeAffinity, Weight: pointer.Int32(1)}, + // Weight is doubled because: + // - This is a score coming from user preference. + // - It makes its signal comparable to NodeResourcesFit.LeastAllocated. + {Name: names.PodTopologySpread, Weight: pointer.Int32(2)}, + {Name: names.TaintToleration, Weight: pointer.Int32(1)}, + }, + }, + Reserve: v1beta2.PluginSet{ + Enabled: []v1beta2.Plugin{ + {Name: names.VolumeBinding}, + }, + }, + PreBind: v1beta2.PluginSet{ + Enabled: []v1beta2.Plugin{ + {Name: names.VolumeBinding}, + }, + }, + Bind: v1beta2.PluginSet{ + Enabled: []v1beta2.Plugin{ + {Name: names.DefaultBinder}, + }, + }, + } + applyFeatureGates(plugins) + + return plugins +} + +func applyFeatureGates(config *v1beta2.Plugins) { + if utilfeature.DefaultFeatureGate.Enabled(features.VolumeCapacityPriority) { + config.Score.Enabled = append(config.Score.Enabled, v1beta2.Plugin{Name: names.VolumeBinding, Weight: pointer.Int32(1)}) + } + if utilfeature.DefaultFeatureGate.Enabled(features.PodSchedulingReadiness) { + config.PreEnqueue.Enabled = append(config.PreEnqueue.Enabled, v1beta2.Plugin{Name: names.SchedulingGates}) + } +} + +// mergePlugins merges the custom set into the given default one, handling disabled sets. +func mergePlugins(defaultPlugins, customPlugins *v1beta2.Plugins) *v1beta2.Plugins { + if customPlugins == nil { + return defaultPlugins + } + + defaultPlugins.QueueSort = mergePluginSet(defaultPlugins.QueueSort, customPlugins.QueueSort) + defaultPlugins.PreFilter = mergePluginSet(defaultPlugins.PreFilter, customPlugins.PreFilter) + defaultPlugins.Filter = mergePluginSet(defaultPlugins.Filter, customPlugins.Filter) + defaultPlugins.PostFilter = mergePluginSet(defaultPlugins.PostFilter, customPlugins.PostFilter) + defaultPlugins.PreScore = mergePluginSet(defaultPlugins.PreScore, customPlugins.PreScore) + defaultPlugins.Score = mergePluginSet(defaultPlugins.Score, customPlugins.Score) + defaultPlugins.Reserve = mergePluginSet(defaultPlugins.Reserve, customPlugins.Reserve) + defaultPlugins.Permit = mergePluginSet(defaultPlugins.Permit, customPlugins.Permit) + defaultPlugins.PreBind = mergePluginSet(defaultPlugins.PreBind, customPlugins.PreBind) + defaultPlugins.Bind = mergePluginSet(defaultPlugins.Bind, customPlugins.Bind) + defaultPlugins.PostBind = mergePluginSet(defaultPlugins.PostBind, customPlugins.PostBind) + return defaultPlugins +} + +type pluginIndex struct { + index int + plugin v1beta2.Plugin +} + +func mergePluginSet(defaultPluginSet, customPluginSet v1beta2.PluginSet) v1beta2.PluginSet { + disabledPlugins := sets.NewString() + enabledCustomPlugins := make(map[string]pluginIndex) + // replacedPluginIndex is a set of index of plugins, which have replaced the default plugins. + replacedPluginIndex := sets.NewInt() + for _, disabledPlugin := range customPluginSet.Disabled { + disabledPlugins.Insert(disabledPlugin.Name) + } + for index, enabledPlugin := range customPluginSet.Enabled { + enabledCustomPlugins[enabledPlugin.Name] = pluginIndex{index, enabledPlugin} + } + var enabledPlugins []v1beta2.Plugin + if !disabledPlugins.Has("*") { + for _, defaultEnabledPlugin := range defaultPluginSet.Enabled { + if disabledPlugins.Has(defaultEnabledPlugin.Name) { + continue + } + // The default plugin is explicitly re-configured, update the default plugin accordingly. + if customPlugin, ok := enabledCustomPlugins[defaultEnabledPlugin.Name]; ok { + klog.InfoS("Default plugin is explicitly re-configured; overriding", "plugin", defaultEnabledPlugin.Name) + // Update the default plugin in place to preserve order. + defaultEnabledPlugin = customPlugin.plugin + replacedPluginIndex.Insert(customPlugin.index) + } + enabledPlugins = append(enabledPlugins, defaultEnabledPlugin) + } + } + + // Append all the custom plugins which haven't replaced any default plugins. + // Note: duplicated custom plugins will still be appended here. + // If so, the instantiation of scheduler framework will detect it and abort. + for index, plugin := range customPluginSet.Enabled { + if !replacedPluginIndex.Has(index) { + enabledPlugins = append(enabledPlugins, plugin) + } + } + return v1beta2.PluginSet{Enabled: enabledPlugins} +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/defaults.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/defaults.go new file mode 100644 index 000000000..1bf120806 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/defaults.go @@ -0,0 +1,241 @@ +/* +Copyright 2021 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 v1beta2 + +import ( + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apiserver/pkg/util/feature" + componentbaseconfigv1alpha1 "k8s.io/component-base/config/v1alpha1" + "k8s.io/kube-scheduler/config/v1beta2" + "k8s.io/kubernetes/pkg/features" + "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/utils/pointer" +) + +var defaultResourceSpec = []v1beta2.ResourceSpec{ + {Name: string(v1.ResourceCPU), Weight: 1}, + {Name: string(v1.ResourceMemory), Weight: 1}, +} + +func addDefaultingFuncs(scheme *runtime.Scheme) error { + return RegisterDefaults(scheme) +} + +func pluginsNames(p *v1beta2.Plugins) []string { + if p == nil { + return nil + } + extensions := []v1beta2.PluginSet{ + p.PreFilter, + p.Filter, + p.PostFilter, + p.Reserve, + p.PreScore, + p.Score, + p.PreBind, + p.Bind, + p.PostBind, + p.Permit, + p.QueueSort, + } + n := sets.NewString() + for _, e := range extensions { + for _, pg := range e.Enabled { + n.Insert(pg.Name) + } + } + return n.List() +} + +func setDefaults_KubeSchedulerProfile(prof *v1beta2.KubeSchedulerProfile) { + // Set default plugins. + prof.Plugins = mergePlugins(getDefaultPlugins(), prof.Plugins) + + // Set default plugin configs. + scheme := GetPluginArgConversionScheme() + existingConfigs := sets.NewString() + for j := range prof.PluginConfig { + existingConfigs.Insert(prof.PluginConfig[j].Name) + args := prof.PluginConfig[j].Args.Object + if _, isUnknown := args.(*runtime.Unknown); isUnknown { + continue + } + scheme.Default(args) + } + + // Append default configs for plugins that didn't have one explicitly set. + for _, name := range pluginsNames(prof.Plugins) { + if existingConfigs.Has(name) { + continue + } + gvk := v1beta2.SchemeGroupVersion.WithKind(name + "Args") + args, err := scheme.New(gvk) + if err != nil { + // This plugin is out-of-tree or doesn't require configuration. + continue + } + scheme.Default(args) + args.GetObjectKind().SetGroupVersionKind(gvk) + prof.PluginConfig = append(prof.PluginConfig, v1beta2.PluginConfig{ + Name: name, + Args: runtime.RawExtension{Object: args}, + }) + } +} + +// SetDefaults_KubeSchedulerConfiguration sets additional defaults +func SetDefaults_KubeSchedulerConfiguration(obj *v1beta2.KubeSchedulerConfiguration) { + if obj.Parallelism == nil { + obj.Parallelism = pointer.Int32(16) + } + + if len(obj.Profiles) == 0 { + obj.Profiles = append(obj.Profiles, v1beta2.KubeSchedulerProfile{}) + } + // Only apply a default scheduler name when there is a single profile. + // Validation will ensure that every profile has a non-empty unique name. + if len(obj.Profiles) == 1 && obj.Profiles[0].SchedulerName == nil { + obj.Profiles[0].SchedulerName = pointer.String(v1.DefaultSchedulerName) + } + + // Add the default set of plugins and apply the configuration. + for i := range obj.Profiles { + prof := &obj.Profiles[i] + setDefaults_KubeSchedulerProfile(prof) + } + + if obj.PercentageOfNodesToScore == nil { + obj.PercentageOfNodesToScore = pointer.Int32(config.DefaultPercentageOfNodesToScore) + } + + if len(obj.LeaderElection.ResourceLock) == 0 { + // Use lease-based leader election to reduce cost. + // We migrated for EndpointsLease lock in 1.17 and starting in 1.20 we + // migrated to Lease lock. + obj.LeaderElection.ResourceLock = "leases" + } + if len(obj.LeaderElection.ResourceNamespace) == 0 { + obj.LeaderElection.ResourceNamespace = v1beta2.SchedulerDefaultLockObjectNamespace + } + if len(obj.LeaderElection.ResourceName) == 0 { + obj.LeaderElection.ResourceName = v1beta2.SchedulerDefaultLockObjectName + } + + if len(obj.ClientConnection.ContentType) == 0 { + obj.ClientConnection.ContentType = "application/vnd.kubernetes.protobuf" + } + // Scheduler has an opinion about QPS/Burst, setting specific defaults for itself, instead of generic settings. + if obj.ClientConnection.QPS == 0.0 { + obj.ClientConnection.QPS = 50.0 + } + if obj.ClientConnection.Burst == 0 { + obj.ClientConnection.Burst = 100 + } + + // Use the default LeaderElectionConfiguration options + componentbaseconfigv1alpha1.RecommendedDefaultLeaderElectionConfiguration(&obj.LeaderElection) + + if obj.PodInitialBackoffSeconds == nil { + obj.PodInitialBackoffSeconds = pointer.Int64(1) + } + + if obj.PodMaxBackoffSeconds == nil { + obj.PodMaxBackoffSeconds = pointer.Int64(10) + } + + // Enable profiling by default in the scheduler + if obj.EnableProfiling == nil { + obj.EnableProfiling = pointer.Bool(true) + } + + // Enable contention profiling by default if profiling is enabled + if *obj.EnableProfiling && obj.EnableContentionProfiling == nil { + obj.EnableContentionProfiling = pointer.Bool(true) + } +} + +func SetDefaults_DefaultPreemptionArgs(obj *v1beta2.DefaultPreemptionArgs) { + if obj.MinCandidateNodesPercentage == nil { + obj.MinCandidateNodesPercentage = pointer.Int32(10) + } + if obj.MinCandidateNodesAbsolute == nil { + obj.MinCandidateNodesAbsolute = pointer.Int32(100) + } +} + +func SetDefaults_InterPodAffinityArgs(obj *v1beta2.InterPodAffinityArgs) { + if obj.HardPodAffinityWeight == nil { + obj.HardPodAffinityWeight = pointer.Int32(1) + } +} + +func SetDefaults_VolumeBindingArgs(obj *v1beta2.VolumeBindingArgs) { + if obj.BindTimeoutSeconds == nil { + obj.BindTimeoutSeconds = pointer.Int64(600) + } + if len(obj.Shape) == 0 && feature.DefaultFeatureGate.Enabled(features.VolumeCapacityPriority) { + obj.Shape = []v1beta2.UtilizationShapePoint{ + { + Utilization: 0, + Score: 0, + }, + { + Utilization: 100, + Score: int32(config.MaxCustomPriorityScore), + }, + } + } +} + +func SetDefaults_NodeResourcesBalancedAllocationArgs(obj *v1beta2.NodeResourcesBalancedAllocationArgs) { + if len(obj.Resources) == 0 { + obj.Resources = defaultResourceSpec + return + } + // If the weight is not set or it is explicitly set to 0, then apply the default weight(1) instead. + for i := range obj.Resources { + if obj.Resources[i].Weight == 0 { + obj.Resources[i].Weight = 1 + } + } +} + +func SetDefaults_PodTopologySpreadArgs(obj *v1beta2.PodTopologySpreadArgs) { + if obj.DefaultingType == "" { + obj.DefaultingType = v1beta2.SystemDefaulting + } +} + +func SetDefaults_NodeResourcesFitArgs(obj *v1beta2.NodeResourcesFitArgs) { + if obj.ScoringStrategy == nil { + obj.ScoringStrategy = &v1beta2.ScoringStrategy{ + Type: v1beta2.ScoringStrategyType(config.LeastAllocated), + Resources: defaultResourceSpec, + } + } + if len(obj.ScoringStrategy.Resources) == 0 { + // If no resources specified, use the default set. + obj.ScoringStrategy.Resources = append(obj.ScoringStrategy.Resources, defaultResourceSpec...) + } + for i := range obj.ScoringStrategy.Resources { + if obj.ScoringStrategy.Resources[i].Weight == 0 { + obj.ScoringStrategy.Resources[i].Weight = 1 + } + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/doc.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/doc.go new file mode 100644 index 000000000..0c8b9e17e --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/doc.go @@ -0,0 +1,24 @@ +/* +Copyright 2021 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. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:conversion-gen=k8s.io/kubernetes/pkg/scheduler/apis/config +// +k8s:conversion-gen-external-types=k8s.io/kube-scheduler/config/v1beta2 +// +k8s:defaulter-gen=TypeMeta +// +k8s:defaulter-gen-input=k8s.io/kube-scheduler/config/v1beta2 +// +groupName=kubescheduler.config.k8s.io + +package v1beta2 // import "k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2" diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/register.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/register.go new file mode 100644 index 000000000..b8ca76de5 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/register.go @@ -0,0 +1,42 @@ +/* +Copyright 2021 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 v1beta2 + +import ( + "k8s.io/kube-scheduler/config/v1beta2" +) + +// GroupName is the group name used in this package +const GroupName = v1beta2.GroupName + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = v1beta2.SchemeGroupVersion + +var ( + // localSchemeBuilder extends the SchemeBuilder instance with the external types. In this package, + // defaulting and conversion init funcs are registered as well. + localSchemeBuilder = &v1beta2.SchemeBuilder + // AddToScheme is a global function that registers this API group & version to a scheme + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addDefaultingFuncs) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/zz_generated.conversion.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/zz_generated.conversion.go new file mode 100644 index 000000000..642729e38 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/zz_generated.conversion.go @@ -0,0 +1,943 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by conversion-gen. DO NOT EDIT. + +package v1beta2 + +import ( + unsafe "unsafe" + + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + v1alpha1 "k8s.io/component-base/config/v1alpha1" + v1beta2 "k8s.io/kube-scheduler/config/v1beta2" + config "k8s.io/kubernetes/pkg/scheduler/apis/config" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*v1beta2.DefaultPreemptionArgs)(nil), (*config.DefaultPreemptionArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_DefaultPreemptionArgs_To_config_DefaultPreemptionArgs(a.(*v1beta2.DefaultPreemptionArgs), b.(*config.DefaultPreemptionArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.DefaultPreemptionArgs)(nil), (*v1beta2.DefaultPreemptionArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_DefaultPreemptionArgs_To_v1beta2_DefaultPreemptionArgs(a.(*config.DefaultPreemptionArgs), b.(*v1beta2.DefaultPreemptionArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta2.Extender)(nil), (*config.Extender)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_Extender_To_config_Extender(a.(*v1beta2.Extender), b.(*config.Extender), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.Extender)(nil), (*v1beta2.Extender)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_Extender_To_v1beta2_Extender(a.(*config.Extender), b.(*v1beta2.Extender), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta2.ExtenderManagedResource)(nil), (*config.ExtenderManagedResource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_ExtenderManagedResource_To_config_ExtenderManagedResource(a.(*v1beta2.ExtenderManagedResource), b.(*config.ExtenderManagedResource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.ExtenderManagedResource)(nil), (*v1beta2.ExtenderManagedResource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_ExtenderManagedResource_To_v1beta2_ExtenderManagedResource(a.(*config.ExtenderManagedResource), b.(*v1beta2.ExtenderManagedResource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta2.ExtenderTLSConfig)(nil), (*config.ExtenderTLSConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_ExtenderTLSConfig_To_config_ExtenderTLSConfig(a.(*v1beta2.ExtenderTLSConfig), b.(*config.ExtenderTLSConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.ExtenderTLSConfig)(nil), (*v1beta2.ExtenderTLSConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_ExtenderTLSConfig_To_v1beta2_ExtenderTLSConfig(a.(*config.ExtenderTLSConfig), b.(*v1beta2.ExtenderTLSConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta2.InterPodAffinityArgs)(nil), (*config.InterPodAffinityArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_InterPodAffinityArgs_To_config_InterPodAffinityArgs(a.(*v1beta2.InterPodAffinityArgs), b.(*config.InterPodAffinityArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.InterPodAffinityArgs)(nil), (*v1beta2.InterPodAffinityArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_InterPodAffinityArgs_To_v1beta2_InterPodAffinityArgs(a.(*config.InterPodAffinityArgs), b.(*v1beta2.InterPodAffinityArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta2.KubeSchedulerProfile)(nil), (*config.KubeSchedulerProfile)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_KubeSchedulerProfile_To_config_KubeSchedulerProfile(a.(*v1beta2.KubeSchedulerProfile), b.(*config.KubeSchedulerProfile), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta2.NodeAffinityArgs)(nil), (*config.NodeAffinityArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_NodeAffinityArgs_To_config_NodeAffinityArgs(a.(*v1beta2.NodeAffinityArgs), b.(*config.NodeAffinityArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.NodeAffinityArgs)(nil), (*v1beta2.NodeAffinityArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_NodeAffinityArgs_To_v1beta2_NodeAffinityArgs(a.(*config.NodeAffinityArgs), b.(*v1beta2.NodeAffinityArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta2.NodeResourcesBalancedAllocationArgs)(nil), (*config.NodeResourcesBalancedAllocationArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_NodeResourcesBalancedAllocationArgs_To_config_NodeResourcesBalancedAllocationArgs(a.(*v1beta2.NodeResourcesBalancedAllocationArgs), b.(*config.NodeResourcesBalancedAllocationArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.NodeResourcesBalancedAllocationArgs)(nil), (*v1beta2.NodeResourcesBalancedAllocationArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_NodeResourcesBalancedAllocationArgs_To_v1beta2_NodeResourcesBalancedAllocationArgs(a.(*config.NodeResourcesBalancedAllocationArgs), b.(*v1beta2.NodeResourcesBalancedAllocationArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta2.NodeResourcesFitArgs)(nil), (*config.NodeResourcesFitArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs(a.(*v1beta2.NodeResourcesFitArgs), b.(*config.NodeResourcesFitArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.NodeResourcesFitArgs)(nil), (*v1beta2.NodeResourcesFitArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_NodeResourcesFitArgs_To_v1beta2_NodeResourcesFitArgs(a.(*config.NodeResourcesFitArgs), b.(*v1beta2.NodeResourcesFitArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta2.Plugin)(nil), (*config.Plugin)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_Plugin_To_config_Plugin(a.(*v1beta2.Plugin), b.(*config.Plugin), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.Plugin)(nil), (*v1beta2.Plugin)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_Plugin_To_v1beta2_Plugin(a.(*config.Plugin), b.(*v1beta2.Plugin), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta2.PluginConfig)(nil), (*config.PluginConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_PluginConfig_To_config_PluginConfig(a.(*v1beta2.PluginConfig), b.(*config.PluginConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.PluginConfig)(nil), (*v1beta2.PluginConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_PluginConfig_To_v1beta2_PluginConfig(a.(*config.PluginConfig), b.(*v1beta2.PluginConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta2.PluginSet)(nil), (*config.PluginSet)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_PluginSet_To_config_PluginSet(a.(*v1beta2.PluginSet), b.(*config.PluginSet), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.PluginSet)(nil), (*v1beta2.PluginSet)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_PluginSet_To_v1beta2_PluginSet(a.(*config.PluginSet), b.(*v1beta2.PluginSet), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta2.Plugins)(nil), (*config.Plugins)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_Plugins_To_config_Plugins(a.(*v1beta2.Plugins), b.(*config.Plugins), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta2.PodTopologySpreadArgs)(nil), (*config.PodTopologySpreadArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_PodTopologySpreadArgs_To_config_PodTopologySpreadArgs(a.(*v1beta2.PodTopologySpreadArgs), b.(*config.PodTopologySpreadArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.PodTopologySpreadArgs)(nil), (*v1beta2.PodTopologySpreadArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_PodTopologySpreadArgs_To_v1beta2_PodTopologySpreadArgs(a.(*config.PodTopologySpreadArgs), b.(*v1beta2.PodTopologySpreadArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta2.RequestedToCapacityRatioParam)(nil), (*config.RequestedToCapacityRatioParam)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(a.(*v1beta2.RequestedToCapacityRatioParam), b.(*config.RequestedToCapacityRatioParam), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.RequestedToCapacityRatioParam)(nil), (*v1beta2.RequestedToCapacityRatioParam)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_RequestedToCapacityRatioParam_To_v1beta2_RequestedToCapacityRatioParam(a.(*config.RequestedToCapacityRatioParam), b.(*v1beta2.RequestedToCapacityRatioParam), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta2.ResourceSpec)(nil), (*config.ResourceSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_ResourceSpec_To_config_ResourceSpec(a.(*v1beta2.ResourceSpec), b.(*config.ResourceSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.ResourceSpec)(nil), (*v1beta2.ResourceSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_ResourceSpec_To_v1beta2_ResourceSpec(a.(*config.ResourceSpec), b.(*v1beta2.ResourceSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta2.ScoringStrategy)(nil), (*config.ScoringStrategy)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_ScoringStrategy_To_config_ScoringStrategy(a.(*v1beta2.ScoringStrategy), b.(*config.ScoringStrategy), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.ScoringStrategy)(nil), (*v1beta2.ScoringStrategy)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_ScoringStrategy_To_v1beta2_ScoringStrategy(a.(*config.ScoringStrategy), b.(*v1beta2.ScoringStrategy), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta2.UtilizationShapePoint)(nil), (*config.UtilizationShapePoint)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_UtilizationShapePoint_To_config_UtilizationShapePoint(a.(*v1beta2.UtilizationShapePoint), b.(*config.UtilizationShapePoint), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.UtilizationShapePoint)(nil), (*v1beta2.UtilizationShapePoint)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_UtilizationShapePoint_To_v1beta2_UtilizationShapePoint(a.(*config.UtilizationShapePoint), b.(*v1beta2.UtilizationShapePoint), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta2.VolumeBindingArgs)(nil), (*config.VolumeBindingArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_VolumeBindingArgs_To_config_VolumeBindingArgs(a.(*v1beta2.VolumeBindingArgs), b.(*config.VolumeBindingArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.VolumeBindingArgs)(nil), (*v1beta2.VolumeBindingArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_VolumeBindingArgs_To_v1beta2_VolumeBindingArgs(a.(*config.VolumeBindingArgs), b.(*v1beta2.VolumeBindingArgs), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*config.KubeSchedulerConfiguration)(nil), (*v1beta2.KubeSchedulerConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_KubeSchedulerConfiguration_To_v1beta2_KubeSchedulerConfiguration(a.(*config.KubeSchedulerConfiguration), b.(*v1beta2.KubeSchedulerConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*config.KubeSchedulerProfile)(nil), (*v1beta2.KubeSchedulerProfile)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_KubeSchedulerProfile_To_v1beta2_KubeSchedulerProfile(a.(*config.KubeSchedulerProfile), b.(*v1beta2.KubeSchedulerProfile), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*config.Plugins)(nil), (*v1beta2.Plugins)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_Plugins_To_v1beta2_Plugins(a.(*config.Plugins), b.(*v1beta2.Plugins), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1beta2.KubeSchedulerConfiguration)(nil), (*config.KubeSchedulerConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_KubeSchedulerConfiguration_To_config_KubeSchedulerConfiguration(a.(*v1beta2.KubeSchedulerConfiguration), b.(*config.KubeSchedulerConfiguration), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v1beta2_DefaultPreemptionArgs_To_config_DefaultPreemptionArgs(in *v1beta2.DefaultPreemptionArgs, out *config.DefaultPreemptionArgs, s conversion.Scope) error { + if err := v1.Convert_Pointer_int32_To_int32(&in.MinCandidateNodesPercentage, &out.MinCandidateNodesPercentage, s); err != nil { + return err + } + if err := v1.Convert_Pointer_int32_To_int32(&in.MinCandidateNodesAbsolute, &out.MinCandidateNodesAbsolute, s); err != nil { + return err + } + return nil +} + +// Convert_v1beta2_DefaultPreemptionArgs_To_config_DefaultPreemptionArgs is an autogenerated conversion function. +func Convert_v1beta2_DefaultPreemptionArgs_To_config_DefaultPreemptionArgs(in *v1beta2.DefaultPreemptionArgs, out *config.DefaultPreemptionArgs, s conversion.Scope) error { + return autoConvert_v1beta2_DefaultPreemptionArgs_To_config_DefaultPreemptionArgs(in, out, s) +} + +func autoConvert_config_DefaultPreemptionArgs_To_v1beta2_DefaultPreemptionArgs(in *config.DefaultPreemptionArgs, out *v1beta2.DefaultPreemptionArgs, s conversion.Scope) error { + if err := v1.Convert_int32_To_Pointer_int32(&in.MinCandidateNodesPercentage, &out.MinCandidateNodesPercentage, s); err != nil { + return err + } + if err := v1.Convert_int32_To_Pointer_int32(&in.MinCandidateNodesAbsolute, &out.MinCandidateNodesAbsolute, s); err != nil { + return err + } + return nil +} + +// Convert_config_DefaultPreemptionArgs_To_v1beta2_DefaultPreemptionArgs is an autogenerated conversion function. +func Convert_config_DefaultPreemptionArgs_To_v1beta2_DefaultPreemptionArgs(in *config.DefaultPreemptionArgs, out *v1beta2.DefaultPreemptionArgs, s conversion.Scope) error { + return autoConvert_config_DefaultPreemptionArgs_To_v1beta2_DefaultPreemptionArgs(in, out, s) +} + +func autoConvert_v1beta2_Extender_To_config_Extender(in *v1beta2.Extender, out *config.Extender, s conversion.Scope) error { + out.URLPrefix = in.URLPrefix + out.FilterVerb = in.FilterVerb + out.PreemptVerb = in.PreemptVerb + out.PrioritizeVerb = in.PrioritizeVerb + out.Weight = in.Weight + out.BindVerb = in.BindVerb + out.EnableHTTPS = in.EnableHTTPS + out.TLSConfig = (*config.ExtenderTLSConfig)(unsafe.Pointer(in.TLSConfig)) + out.HTTPTimeout = in.HTTPTimeout + out.NodeCacheCapable = in.NodeCacheCapable + out.ManagedResources = *(*[]config.ExtenderManagedResource)(unsafe.Pointer(&in.ManagedResources)) + out.Ignorable = in.Ignorable + return nil +} + +// Convert_v1beta2_Extender_To_config_Extender is an autogenerated conversion function. +func Convert_v1beta2_Extender_To_config_Extender(in *v1beta2.Extender, out *config.Extender, s conversion.Scope) error { + return autoConvert_v1beta2_Extender_To_config_Extender(in, out, s) +} + +func autoConvert_config_Extender_To_v1beta2_Extender(in *config.Extender, out *v1beta2.Extender, s conversion.Scope) error { + out.URLPrefix = in.URLPrefix + out.FilterVerb = in.FilterVerb + out.PreemptVerb = in.PreemptVerb + out.PrioritizeVerb = in.PrioritizeVerb + out.Weight = in.Weight + out.BindVerb = in.BindVerb + out.EnableHTTPS = in.EnableHTTPS + out.TLSConfig = (*v1beta2.ExtenderTLSConfig)(unsafe.Pointer(in.TLSConfig)) + out.HTTPTimeout = in.HTTPTimeout + out.NodeCacheCapable = in.NodeCacheCapable + out.ManagedResources = *(*[]v1beta2.ExtenderManagedResource)(unsafe.Pointer(&in.ManagedResources)) + out.Ignorable = in.Ignorable + return nil +} + +// Convert_config_Extender_To_v1beta2_Extender is an autogenerated conversion function. +func Convert_config_Extender_To_v1beta2_Extender(in *config.Extender, out *v1beta2.Extender, s conversion.Scope) error { + return autoConvert_config_Extender_To_v1beta2_Extender(in, out, s) +} + +func autoConvert_v1beta2_ExtenderManagedResource_To_config_ExtenderManagedResource(in *v1beta2.ExtenderManagedResource, out *config.ExtenderManagedResource, s conversion.Scope) error { + out.Name = in.Name + out.IgnoredByScheduler = in.IgnoredByScheduler + return nil +} + +// Convert_v1beta2_ExtenderManagedResource_To_config_ExtenderManagedResource is an autogenerated conversion function. +func Convert_v1beta2_ExtenderManagedResource_To_config_ExtenderManagedResource(in *v1beta2.ExtenderManagedResource, out *config.ExtenderManagedResource, s conversion.Scope) error { + return autoConvert_v1beta2_ExtenderManagedResource_To_config_ExtenderManagedResource(in, out, s) +} + +func autoConvert_config_ExtenderManagedResource_To_v1beta2_ExtenderManagedResource(in *config.ExtenderManagedResource, out *v1beta2.ExtenderManagedResource, s conversion.Scope) error { + out.Name = in.Name + out.IgnoredByScheduler = in.IgnoredByScheduler + return nil +} + +// Convert_config_ExtenderManagedResource_To_v1beta2_ExtenderManagedResource is an autogenerated conversion function. +func Convert_config_ExtenderManagedResource_To_v1beta2_ExtenderManagedResource(in *config.ExtenderManagedResource, out *v1beta2.ExtenderManagedResource, s conversion.Scope) error { + return autoConvert_config_ExtenderManagedResource_To_v1beta2_ExtenderManagedResource(in, out, s) +} + +func autoConvert_v1beta2_ExtenderTLSConfig_To_config_ExtenderTLSConfig(in *v1beta2.ExtenderTLSConfig, out *config.ExtenderTLSConfig, s conversion.Scope) error { + out.Insecure = in.Insecure + out.ServerName = in.ServerName + out.CertFile = in.CertFile + out.KeyFile = in.KeyFile + out.CAFile = in.CAFile + out.CertData = *(*[]byte)(unsafe.Pointer(&in.CertData)) + out.KeyData = *(*[]byte)(unsafe.Pointer(&in.KeyData)) + out.CAData = *(*[]byte)(unsafe.Pointer(&in.CAData)) + return nil +} + +// Convert_v1beta2_ExtenderTLSConfig_To_config_ExtenderTLSConfig is an autogenerated conversion function. +func Convert_v1beta2_ExtenderTLSConfig_To_config_ExtenderTLSConfig(in *v1beta2.ExtenderTLSConfig, out *config.ExtenderTLSConfig, s conversion.Scope) error { + return autoConvert_v1beta2_ExtenderTLSConfig_To_config_ExtenderTLSConfig(in, out, s) +} + +func autoConvert_config_ExtenderTLSConfig_To_v1beta2_ExtenderTLSConfig(in *config.ExtenderTLSConfig, out *v1beta2.ExtenderTLSConfig, s conversion.Scope) error { + out.Insecure = in.Insecure + out.ServerName = in.ServerName + out.CertFile = in.CertFile + out.KeyFile = in.KeyFile + out.CAFile = in.CAFile + out.CertData = *(*[]byte)(unsafe.Pointer(&in.CertData)) + out.KeyData = *(*[]byte)(unsafe.Pointer(&in.KeyData)) + out.CAData = *(*[]byte)(unsafe.Pointer(&in.CAData)) + return nil +} + +// Convert_config_ExtenderTLSConfig_To_v1beta2_ExtenderTLSConfig is an autogenerated conversion function. +func Convert_config_ExtenderTLSConfig_To_v1beta2_ExtenderTLSConfig(in *config.ExtenderTLSConfig, out *v1beta2.ExtenderTLSConfig, s conversion.Scope) error { + return autoConvert_config_ExtenderTLSConfig_To_v1beta2_ExtenderTLSConfig(in, out, s) +} + +func autoConvert_v1beta2_InterPodAffinityArgs_To_config_InterPodAffinityArgs(in *v1beta2.InterPodAffinityArgs, out *config.InterPodAffinityArgs, s conversion.Scope) error { + if err := v1.Convert_Pointer_int32_To_int32(&in.HardPodAffinityWeight, &out.HardPodAffinityWeight, s); err != nil { + return err + } + return nil +} + +// Convert_v1beta2_InterPodAffinityArgs_To_config_InterPodAffinityArgs is an autogenerated conversion function. +func Convert_v1beta2_InterPodAffinityArgs_To_config_InterPodAffinityArgs(in *v1beta2.InterPodAffinityArgs, out *config.InterPodAffinityArgs, s conversion.Scope) error { + return autoConvert_v1beta2_InterPodAffinityArgs_To_config_InterPodAffinityArgs(in, out, s) +} + +func autoConvert_config_InterPodAffinityArgs_To_v1beta2_InterPodAffinityArgs(in *config.InterPodAffinityArgs, out *v1beta2.InterPodAffinityArgs, s conversion.Scope) error { + if err := v1.Convert_int32_To_Pointer_int32(&in.HardPodAffinityWeight, &out.HardPodAffinityWeight, s); err != nil { + return err + } + return nil +} + +// Convert_config_InterPodAffinityArgs_To_v1beta2_InterPodAffinityArgs is an autogenerated conversion function. +func Convert_config_InterPodAffinityArgs_To_v1beta2_InterPodAffinityArgs(in *config.InterPodAffinityArgs, out *v1beta2.InterPodAffinityArgs, s conversion.Scope) error { + return autoConvert_config_InterPodAffinityArgs_To_v1beta2_InterPodAffinityArgs(in, out, s) +} + +func autoConvert_v1beta2_KubeSchedulerConfiguration_To_config_KubeSchedulerConfiguration(in *v1beta2.KubeSchedulerConfiguration, out *config.KubeSchedulerConfiguration, s conversion.Scope) error { + if err := v1.Convert_Pointer_int32_To_int32(&in.Parallelism, &out.Parallelism, s); err != nil { + return err + } + if err := v1alpha1.Convert_v1alpha1_LeaderElectionConfiguration_To_config_LeaderElectionConfiguration(&in.LeaderElection, &out.LeaderElection, s); err != nil { + return err + } + if err := v1alpha1.Convert_v1alpha1_ClientConnectionConfiguration_To_config_ClientConnectionConfiguration(&in.ClientConnection, &out.ClientConnection, s); err != nil { + return err + } + if err := v1.Convert_Pointer_string_To_string(&in.HealthzBindAddress, &out.HealthzBindAddress, s); err != nil { + return err + } + if err := v1.Convert_Pointer_string_To_string(&in.MetricsBindAddress, &out.MetricsBindAddress, s); err != nil { + return err + } + if err := v1alpha1.Convert_v1alpha1_DebuggingConfiguration_To_config_DebuggingConfiguration(&in.DebuggingConfiguration, &out.DebuggingConfiguration, s); err != nil { + return err + } + out.PercentageOfNodesToScore = (*int32)(unsafe.Pointer(in.PercentageOfNodesToScore)) + if err := v1.Convert_Pointer_int64_To_int64(&in.PodInitialBackoffSeconds, &out.PodInitialBackoffSeconds, s); err != nil { + return err + } + if err := v1.Convert_Pointer_int64_To_int64(&in.PodMaxBackoffSeconds, &out.PodMaxBackoffSeconds, s); err != nil { + return err + } + if in.Profiles != nil { + in, out := &in.Profiles, &out.Profiles + *out = make([]config.KubeSchedulerProfile, len(*in)) + for i := range *in { + if err := Convert_v1beta2_KubeSchedulerProfile_To_config_KubeSchedulerProfile(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Profiles = nil + } + out.Extenders = *(*[]config.Extender)(unsafe.Pointer(&in.Extenders)) + return nil +} + +func autoConvert_config_KubeSchedulerConfiguration_To_v1beta2_KubeSchedulerConfiguration(in *config.KubeSchedulerConfiguration, out *v1beta2.KubeSchedulerConfiguration, s conversion.Scope) error { + if err := v1.Convert_int32_To_Pointer_int32(&in.Parallelism, &out.Parallelism, s); err != nil { + return err + } + if err := v1alpha1.Convert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfiguration(&in.LeaderElection, &out.LeaderElection, s); err != nil { + return err + } + if err := v1alpha1.Convert_config_ClientConnectionConfiguration_To_v1alpha1_ClientConnectionConfiguration(&in.ClientConnection, &out.ClientConnection, s); err != nil { + return err + } + if err := v1.Convert_string_To_Pointer_string(&in.HealthzBindAddress, &out.HealthzBindAddress, s); err != nil { + return err + } + if err := v1.Convert_string_To_Pointer_string(&in.MetricsBindAddress, &out.MetricsBindAddress, s); err != nil { + return err + } + if err := v1alpha1.Convert_config_DebuggingConfiguration_To_v1alpha1_DebuggingConfiguration(&in.DebuggingConfiguration, &out.DebuggingConfiguration, s); err != nil { + return err + } + out.PercentageOfNodesToScore = (*int32)(unsafe.Pointer(in.PercentageOfNodesToScore)) + if err := v1.Convert_int64_To_Pointer_int64(&in.PodInitialBackoffSeconds, &out.PodInitialBackoffSeconds, s); err != nil { + return err + } + if err := v1.Convert_int64_To_Pointer_int64(&in.PodMaxBackoffSeconds, &out.PodMaxBackoffSeconds, s); err != nil { + return err + } + if in.Profiles != nil { + in, out := &in.Profiles, &out.Profiles + *out = make([]v1beta2.KubeSchedulerProfile, len(*in)) + for i := range *in { + if err := Convert_config_KubeSchedulerProfile_To_v1beta2_KubeSchedulerProfile(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Profiles = nil + } + out.Extenders = *(*[]v1beta2.Extender)(unsafe.Pointer(&in.Extenders)) + return nil +} + +func autoConvert_v1beta2_KubeSchedulerProfile_To_config_KubeSchedulerProfile(in *v1beta2.KubeSchedulerProfile, out *config.KubeSchedulerProfile, s conversion.Scope) error { + if err := v1.Convert_Pointer_string_To_string(&in.SchedulerName, &out.SchedulerName, s); err != nil { + return err + } + if in.Plugins != nil { + in, out := &in.Plugins, &out.Plugins + *out = new(config.Plugins) + if err := Convert_v1beta2_Plugins_To_config_Plugins(*in, *out, s); err != nil { + return err + } + } else { + out.Plugins = nil + } + if in.PluginConfig != nil { + in, out := &in.PluginConfig, &out.PluginConfig + *out = make([]config.PluginConfig, len(*in)) + for i := range *in { + if err := Convert_v1beta2_PluginConfig_To_config_PluginConfig(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.PluginConfig = nil + } + return nil +} + +// Convert_v1beta2_KubeSchedulerProfile_To_config_KubeSchedulerProfile is an autogenerated conversion function. +func Convert_v1beta2_KubeSchedulerProfile_To_config_KubeSchedulerProfile(in *v1beta2.KubeSchedulerProfile, out *config.KubeSchedulerProfile, s conversion.Scope) error { + return autoConvert_v1beta2_KubeSchedulerProfile_To_config_KubeSchedulerProfile(in, out, s) +} + +func autoConvert_config_KubeSchedulerProfile_To_v1beta2_KubeSchedulerProfile(in *config.KubeSchedulerProfile, out *v1beta2.KubeSchedulerProfile, s conversion.Scope) error { + if err := v1.Convert_string_To_Pointer_string(&in.SchedulerName, &out.SchedulerName, s); err != nil { + return err + } + // WARNING: in.PercentageOfNodesToScore requires manual conversion: does not exist in peer-type + if in.Plugins != nil { + in, out := &in.Plugins, &out.Plugins + *out = new(v1beta2.Plugins) + if err := Convert_config_Plugins_To_v1beta2_Plugins(*in, *out, s); err != nil { + return err + } + } else { + out.Plugins = nil + } + if in.PluginConfig != nil { + in, out := &in.PluginConfig, &out.PluginConfig + *out = make([]v1beta2.PluginConfig, len(*in)) + for i := range *in { + if err := Convert_config_PluginConfig_To_v1beta2_PluginConfig(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.PluginConfig = nil + } + return nil +} + +func autoConvert_v1beta2_NodeAffinityArgs_To_config_NodeAffinityArgs(in *v1beta2.NodeAffinityArgs, out *config.NodeAffinityArgs, s conversion.Scope) error { + out.AddedAffinity = (*corev1.NodeAffinity)(unsafe.Pointer(in.AddedAffinity)) + return nil +} + +// Convert_v1beta2_NodeAffinityArgs_To_config_NodeAffinityArgs is an autogenerated conversion function. +func Convert_v1beta2_NodeAffinityArgs_To_config_NodeAffinityArgs(in *v1beta2.NodeAffinityArgs, out *config.NodeAffinityArgs, s conversion.Scope) error { + return autoConvert_v1beta2_NodeAffinityArgs_To_config_NodeAffinityArgs(in, out, s) +} + +func autoConvert_config_NodeAffinityArgs_To_v1beta2_NodeAffinityArgs(in *config.NodeAffinityArgs, out *v1beta2.NodeAffinityArgs, s conversion.Scope) error { + out.AddedAffinity = (*corev1.NodeAffinity)(unsafe.Pointer(in.AddedAffinity)) + return nil +} + +// Convert_config_NodeAffinityArgs_To_v1beta2_NodeAffinityArgs is an autogenerated conversion function. +func Convert_config_NodeAffinityArgs_To_v1beta2_NodeAffinityArgs(in *config.NodeAffinityArgs, out *v1beta2.NodeAffinityArgs, s conversion.Scope) error { + return autoConvert_config_NodeAffinityArgs_To_v1beta2_NodeAffinityArgs(in, out, s) +} + +func autoConvert_v1beta2_NodeResourcesBalancedAllocationArgs_To_config_NodeResourcesBalancedAllocationArgs(in *v1beta2.NodeResourcesBalancedAllocationArgs, out *config.NodeResourcesBalancedAllocationArgs, s conversion.Scope) error { + out.Resources = *(*[]config.ResourceSpec)(unsafe.Pointer(&in.Resources)) + return nil +} + +// Convert_v1beta2_NodeResourcesBalancedAllocationArgs_To_config_NodeResourcesBalancedAllocationArgs is an autogenerated conversion function. +func Convert_v1beta2_NodeResourcesBalancedAllocationArgs_To_config_NodeResourcesBalancedAllocationArgs(in *v1beta2.NodeResourcesBalancedAllocationArgs, out *config.NodeResourcesBalancedAllocationArgs, s conversion.Scope) error { + return autoConvert_v1beta2_NodeResourcesBalancedAllocationArgs_To_config_NodeResourcesBalancedAllocationArgs(in, out, s) +} + +func autoConvert_config_NodeResourcesBalancedAllocationArgs_To_v1beta2_NodeResourcesBalancedAllocationArgs(in *config.NodeResourcesBalancedAllocationArgs, out *v1beta2.NodeResourcesBalancedAllocationArgs, s conversion.Scope) error { + out.Resources = *(*[]v1beta2.ResourceSpec)(unsafe.Pointer(&in.Resources)) + return nil +} + +// Convert_config_NodeResourcesBalancedAllocationArgs_To_v1beta2_NodeResourcesBalancedAllocationArgs is an autogenerated conversion function. +func Convert_config_NodeResourcesBalancedAllocationArgs_To_v1beta2_NodeResourcesBalancedAllocationArgs(in *config.NodeResourcesBalancedAllocationArgs, out *v1beta2.NodeResourcesBalancedAllocationArgs, s conversion.Scope) error { + return autoConvert_config_NodeResourcesBalancedAllocationArgs_To_v1beta2_NodeResourcesBalancedAllocationArgs(in, out, s) +} + +func autoConvert_v1beta2_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs(in *v1beta2.NodeResourcesFitArgs, out *config.NodeResourcesFitArgs, s conversion.Scope) error { + out.IgnoredResources = *(*[]string)(unsafe.Pointer(&in.IgnoredResources)) + out.IgnoredResourceGroups = *(*[]string)(unsafe.Pointer(&in.IgnoredResourceGroups)) + out.ScoringStrategy = (*config.ScoringStrategy)(unsafe.Pointer(in.ScoringStrategy)) + return nil +} + +// Convert_v1beta2_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs is an autogenerated conversion function. +func Convert_v1beta2_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs(in *v1beta2.NodeResourcesFitArgs, out *config.NodeResourcesFitArgs, s conversion.Scope) error { + return autoConvert_v1beta2_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs(in, out, s) +} + +func autoConvert_config_NodeResourcesFitArgs_To_v1beta2_NodeResourcesFitArgs(in *config.NodeResourcesFitArgs, out *v1beta2.NodeResourcesFitArgs, s conversion.Scope) error { + out.IgnoredResources = *(*[]string)(unsafe.Pointer(&in.IgnoredResources)) + out.IgnoredResourceGroups = *(*[]string)(unsafe.Pointer(&in.IgnoredResourceGroups)) + out.ScoringStrategy = (*v1beta2.ScoringStrategy)(unsafe.Pointer(in.ScoringStrategy)) + return nil +} + +// Convert_config_NodeResourcesFitArgs_To_v1beta2_NodeResourcesFitArgs is an autogenerated conversion function. +func Convert_config_NodeResourcesFitArgs_To_v1beta2_NodeResourcesFitArgs(in *config.NodeResourcesFitArgs, out *v1beta2.NodeResourcesFitArgs, s conversion.Scope) error { + return autoConvert_config_NodeResourcesFitArgs_To_v1beta2_NodeResourcesFitArgs(in, out, s) +} + +func autoConvert_v1beta2_Plugin_To_config_Plugin(in *v1beta2.Plugin, out *config.Plugin, s conversion.Scope) error { + out.Name = in.Name + if err := v1.Convert_Pointer_int32_To_int32(&in.Weight, &out.Weight, s); err != nil { + return err + } + return nil +} + +// Convert_v1beta2_Plugin_To_config_Plugin is an autogenerated conversion function. +func Convert_v1beta2_Plugin_To_config_Plugin(in *v1beta2.Plugin, out *config.Plugin, s conversion.Scope) error { + return autoConvert_v1beta2_Plugin_To_config_Plugin(in, out, s) +} + +func autoConvert_config_Plugin_To_v1beta2_Plugin(in *config.Plugin, out *v1beta2.Plugin, s conversion.Scope) error { + out.Name = in.Name + if err := v1.Convert_int32_To_Pointer_int32(&in.Weight, &out.Weight, s); err != nil { + return err + } + return nil +} + +// Convert_config_Plugin_To_v1beta2_Plugin is an autogenerated conversion function. +func Convert_config_Plugin_To_v1beta2_Plugin(in *config.Plugin, out *v1beta2.Plugin, s conversion.Scope) error { + return autoConvert_config_Plugin_To_v1beta2_Plugin(in, out, s) +} + +func autoConvert_v1beta2_PluginConfig_To_config_PluginConfig(in *v1beta2.PluginConfig, out *config.PluginConfig, s conversion.Scope) error { + out.Name = in.Name + if err := runtime.Convert_runtime_RawExtension_To_runtime_Object(&in.Args, &out.Args, s); err != nil { + return err + } + return nil +} + +// Convert_v1beta2_PluginConfig_To_config_PluginConfig is an autogenerated conversion function. +func Convert_v1beta2_PluginConfig_To_config_PluginConfig(in *v1beta2.PluginConfig, out *config.PluginConfig, s conversion.Scope) error { + return autoConvert_v1beta2_PluginConfig_To_config_PluginConfig(in, out, s) +} + +func autoConvert_config_PluginConfig_To_v1beta2_PluginConfig(in *config.PluginConfig, out *v1beta2.PluginConfig, s conversion.Scope) error { + out.Name = in.Name + if err := runtime.Convert_runtime_Object_To_runtime_RawExtension(&in.Args, &out.Args, s); err != nil { + return err + } + return nil +} + +// Convert_config_PluginConfig_To_v1beta2_PluginConfig is an autogenerated conversion function. +func Convert_config_PluginConfig_To_v1beta2_PluginConfig(in *config.PluginConfig, out *v1beta2.PluginConfig, s conversion.Scope) error { + return autoConvert_config_PluginConfig_To_v1beta2_PluginConfig(in, out, s) +} + +func autoConvert_v1beta2_PluginSet_To_config_PluginSet(in *v1beta2.PluginSet, out *config.PluginSet, s conversion.Scope) error { + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = make([]config.Plugin, len(*in)) + for i := range *in { + if err := Convert_v1beta2_Plugin_To_config_Plugin(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Enabled = nil + } + if in.Disabled != nil { + in, out := &in.Disabled, &out.Disabled + *out = make([]config.Plugin, len(*in)) + for i := range *in { + if err := Convert_v1beta2_Plugin_To_config_Plugin(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Disabled = nil + } + return nil +} + +// Convert_v1beta2_PluginSet_To_config_PluginSet is an autogenerated conversion function. +func Convert_v1beta2_PluginSet_To_config_PluginSet(in *v1beta2.PluginSet, out *config.PluginSet, s conversion.Scope) error { + return autoConvert_v1beta2_PluginSet_To_config_PluginSet(in, out, s) +} + +func autoConvert_config_PluginSet_To_v1beta2_PluginSet(in *config.PluginSet, out *v1beta2.PluginSet, s conversion.Scope) error { + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = make([]v1beta2.Plugin, len(*in)) + for i := range *in { + if err := Convert_config_Plugin_To_v1beta2_Plugin(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Enabled = nil + } + if in.Disabled != nil { + in, out := &in.Disabled, &out.Disabled + *out = make([]v1beta2.Plugin, len(*in)) + for i := range *in { + if err := Convert_config_Plugin_To_v1beta2_Plugin(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Disabled = nil + } + return nil +} + +// Convert_config_PluginSet_To_v1beta2_PluginSet is an autogenerated conversion function. +func Convert_config_PluginSet_To_v1beta2_PluginSet(in *config.PluginSet, out *v1beta2.PluginSet, s conversion.Scope) error { + return autoConvert_config_PluginSet_To_v1beta2_PluginSet(in, out, s) +} + +func autoConvert_v1beta2_Plugins_To_config_Plugins(in *v1beta2.Plugins, out *config.Plugins, s conversion.Scope) error { + if err := Convert_v1beta2_PluginSet_To_config_PluginSet(&in.PreEnqueue, &out.PreEnqueue, s); err != nil { + return err + } + if err := Convert_v1beta2_PluginSet_To_config_PluginSet(&in.QueueSort, &out.QueueSort, s); err != nil { + return err + } + if err := Convert_v1beta2_PluginSet_To_config_PluginSet(&in.PreFilter, &out.PreFilter, s); err != nil { + return err + } + if err := Convert_v1beta2_PluginSet_To_config_PluginSet(&in.Filter, &out.Filter, s); err != nil { + return err + } + if err := Convert_v1beta2_PluginSet_To_config_PluginSet(&in.PostFilter, &out.PostFilter, s); err != nil { + return err + } + if err := Convert_v1beta2_PluginSet_To_config_PluginSet(&in.PreScore, &out.PreScore, s); err != nil { + return err + } + if err := Convert_v1beta2_PluginSet_To_config_PluginSet(&in.Score, &out.Score, s); err != nil { + return err + } + if err := Convert_v1beta2_PluginSet_To_config_PluginSet(&in.Reserve, &out.Reserve, s); err != nil { + return err + } + if err := Convert_v1beta2_PluginSet_To_config_PluginSet(&in.Permit, &out.Permit, s); err != nil { + return err + } + if err := Convert_v1beta2_PluginSet_To_config_PluginSet(&in.PreBind, &out.PreBind, s); err != nil { + return err + } + if err := Convert_v1beta2_PluginSet_To_config_PluginSet(&in.Bind, &out.Bind, s); err != nil { + return err + } + if err := Convert_v1beta2_PluginSet_To_config_PluginSet(&in.PostBind, &out.PostBind, s); err != nil { + return err + } + if err := Convert_v1beta2_PluginSet_To_config_PluginSet(&in.MultiPoint, &out.MultiPoint, s); err != nil { + return err + } + return nil +} + +// Convert_v1beta2_Plugins_To_config_Plugins is an autogenerated conversion function. +func Convert_v1beta2_Plugins_To_config_Plugins(in *v1beta2.Plugins, out *config.Plugins, s conversion.Scope) error { + return autoConvert_v1beta2_Plugins_To_config_Plugins(in, out, s) +} + +func autoConvert_config_Plugins_To_v1beta2_Plugins(in *config.Plugins, out *v1beta2.Plugins, s conversion.Scope) error { + if err := Convert_config_PluginSet_To_v1beta2_PluginSet(&in.PreEnqueue, &out.PreEnqueue, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta2_PluginSet(&in.QueueSort, &out.QueueSort, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta2_PluginSet(&in.PreFilter, &out.PreFilter, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta2_PluginSet(&in.Filter, &out.Filter, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta2_PluginSet(&in.PostFilter, &out.PostFilter, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta2_PluginSet(&in.PreScore, &out.PreScore, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta2_PluginSet(&in.Score, &out.Score, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta2_PluginSet(&in.Reserve, &out.Reserve, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta2_PluginSet(&in.Permit, &out.Permit, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta2_PluginSet(&in.PreBind, &out.PreBind, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta2_PluginSet(&in.Bind, &out.Bind, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta2_PluginSet(&in.PostBind, &out.PostBind, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta2_PluginSet(&in.MultiPoint, &out.MultiPoint, s); err != nil { + return err + } + return nil +} + +func autoConvert_v1beta2_PodTopologySpreadArgs_To_config_PodTopologySpreadArgs(in *v1beta2.PodTopologySpreadArgs, out *config.PodTopologySpreadArgs, s conversion.Scope) error { + out.DefaultConstraints = *(*[]corev1.TopologySpreadConstraint)(unsafe.Pointer(&in.DefaultConstraints)) + out.DefaultingType = config.PodTopologySpreadConstraintsDefaulting(in.DefaultingType) + return nil +} + +// Convert_v1beta2_PodTopologySpreadArgs_To_config_PodTopologySpreadArgs is an autogenerated conversion function. +func Convert_v1beta2_PodTopologySpreadArgs_To_config_PodTopologySpreadArgs(in *v1beta2.PodTopologySpreadArgs, out *config.PodTopologySpreadArgs, s conversion.Scope) error { + return autoConvert_v1beta2_PodTopologySpreadArgs_To_config_PodTopologySpreadArgs(in, out, s) +} + +func autoConvert_config_PodTopologySpreadArgs_To_v1beta2_PodTopologySpreadArgs(in *config.PodTopologySpreadArgs, out *v1beta2.PodTopologySpreadArgs, s conversion.Scope) error { + out.DefaultConstraints = *(*[]corev1.TopologySpreadConstraint)(unsafe.Pointer(&in.DefaultConstraints)) + out.DefaultingType = v1beta2.PodTopologySpreadConstraintsDefaulting(in.DefaultingType) + return nil +} + +// Convert_config_PodTopologySpreadArgs_To_v1beta2_PodTopologySpreadArgs is an autogenerated conversion function. +func Convert_config_PodTopologySpreadArgs_To_v1beta2_PodTopologySpreadArgs(in *config.PodTopologySpreadArgs, out *v1beta2.PodTopologySpreadArgs, s conversion.Scope) error { + return autoConvert_config_PodTopologySpreadArgs_To_v1beta2_PodTopologySpreadArgs(in, out, s) +} + +func autoConvert_v1beta2_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(in *v1beta2.RequestedToCapacityRatioParam, out *config.RequestedToCapacityRatioParam, s conversion.Scope) error { + out.Shape = *(*[]config.UtilizationShapePoint)(unsafe.Pointer(&in.Shape)) + return nil +} + +// Convert_v1beta2_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam is an autogenerated conversion function. +func Convert_v1beta2_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(in *v1beta2.RequestedToCapacityRatioParam, out *config.RequestedToCapacityRatioParam, s conversion.Scope) error { + return autoConvert_v1beta2_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(in, out, s) +} + +func autoConvert_config_RequestedToCapacityRatioParam_To_v1beta2_RequestedToCapacityRatioParam(in *config.RequestedToCapacityRatioParam, out *v1beta2.RequestedToCapacityRatioParam, s conversion.Scope) error { + out.Shape = *(*[]v1beta2.UtilizationShapePoint)(unsafe.Pointer(&in.Shape)) + return nil +} + +// Convert_config_RequestedToCapacityRatioParam_To_v1beta2_RequestedToCapacityRatioParam is an autogenerated conversion function. +func Convert_config_RequestedToCapacityRatioParam_To_v1beta2_RequestedToCapacityRatioParam(in *config.RequestedToCapacityRatioParam, out *v1beta2.RequestedToCapacityRatioParam, s conversion.Scope) error { + return autoConvert_config_RequestedToCapacityRatioParam_To_v1beta2_RequestedToCapacityRatioParam(in, out, s) +} + +func autoConvert_v1beta2_ResourceSpec_To_config_ResourceSpec(in *v1beta2.ResourceSpec, out *config.ResourceSpec, s conversion.Scope) error { + out.Name = in.Name + out.Weight = in.Weight + return nil +} + +// Convert_v1beta2_ResourceSpec_To_config_ResourceSpec is an autogenerated conversion function. +func Convert_v1beta2_ResourceSpec_To_config_ResourceSpec(in *v1beta2.ResourceSpec, out *config.ResourceSpec, s conversion.Scope) error { + return autoConvert_v1beta2_ResourceSpec_To_config_ResourceSpec(in, out, s) +} + +func autoConvert_config_ResourceSpec_To_v1beta2_ResourceSpec(in *config.ResourceSpec, out *v1beta2.ResourceSpec, s conversion.Scope) error { + out.Name = in.Name + out.Weight = in.Weight + return nil +} + +// Convert_config_ResourceSpec_To_v1beta2_ResourceSpec is an autogenerated conversion function. +func Convert_config_ResourceSpec_To_v1beta2_ResourceSpec(in *config.ResourceSpec, out *v1beta2.ResourceSpec, s conversion.Scope) error { + return autoConvert_config_ResourceSpec_To_v1beta2_ResourceSpec(in, out, s) +} + +func autoConvert_v1beta2_ScoringStrategy_To_config_ScoringStrategy(in *v1beta2.ScoringStrategy, out *config.ScoringStrategy, s conversion.Scope) error { + out.Type = config.ScoringStrategyType(in.Type) + out.Resources = *(*[]config.ResourceSpec)(unsafe.Pointer(&in.Resources)) + out.RequestedToCapacityRatio = (*config.RequestedToCapacityRatioParam)(unsafe.Pointer(in.RequestedToCapacityRatio)) + return nil +} + +// Convert_v1beta2_ScoringStrategy_To_config_ScoringStrategy is an autogenerated conversion function. +func Convert_v1beta2_ScoringStrategy_To_config_ScoringStrategy(in *v1beta2.ScoringStrategy, out *config.ScoringStrategy, s conversion.Scope) error { + return autoConvert_v1beta2_ScoringStrategy_To_config_ScoringStrategy(in, out, s) +} + +func autoConvert_config_ScoringStrategy_To_v1beta2_ScoringStrategy(in *config.ScoringStrategy, out *v1beta2.ScoringStrategy, s conversion.Scope) error { + out.Type = v1beta2.ScoringStrategyType(in.Type) + out.Resources = *(*[]v1beta2.ResourceSpec)(unsafe.Pointer(&in.Resources)) + out.RequestedToCapacityRatio = (*v1beta2.RequestedToCapacityRatioParam)(unsafe.Pointer(in.RequestedToCapacityRatio)) + return nil +} + +// Convert_config_ScoringStrategy_To_v1beta2_ScoringStrategy is an autogenerated conversion function. +func Convert_config_ScoringStrategy_To_v1beta2_ScoringStrategy(in *config.ScoringStrategy, out *v1beta2.ScoringStrategy, s conversion.Scope) error { + return autoConvert_config_ScoringStrategy_To_v1beta2_ScoringStrategy(in, out, s) +} + +func autoConvert_v1beta2_UtilizationShapePoint_To_config_UtilizationShapePoint(in *v1beta2.UtilizationShapePoint, out *config.UtilizationShapePoint, s conversion.Scope) error { + out.Utilization = in.Utilization + out.Score = in.Score + return nil +} + +// Convert_v1beta2_UtilizationShapePoint_To_config_UtilizationShapePoint is an autogenerated conversion function. +func Convert_v1beta2_UtilizationShapePoint_To_config_UtilizationShapePoint(in *v1beta2.UtilizationShapePoint, out *config.UtilizationShapePoint, s conversion.Scope) error { + return autoConvert_v1beta2_UtilizationShapePoint_To_config_UtilizationShapePoint(in, out, s) +} + +func autoConvert_config_UtilizationShapePoint_To_v1beta2_UtilizationShapePoint(in *config.UtilizationShapePoint, out *v1beta2.UtilizationShapePoint, s conversion.Scope) error { + out.Utilization = in.Utilization + out.Score = in.Score + return nil +} + +// Convert_config_UtilizationShapePoint_To_v1beta2_UtilizationShapePoint is an autogenerated conversion function. +func Convert_config_UtilizationShapePoint_To_v1beta2_UtilizationShapePoint(in *config.UtilizationShapePoint, out *v1beta2.UtilizationShapePoint, s conversion.Scope) error { + return autoConvert_config_UtilizationShapePoint_To_v1beta2_UtilizationShapePoint(in, out, s) +} + +func autoConvert_v1beta2_VolumeBindingArgs_To_config_VolumeBindingArgs(in *v1beta2.VolumeBindingArgs, out *config.VolumeBindingArgs, s conversion.Scope) error { + if err := v1.Convert_Pointer_int64_To_int64(&in.BindTimeoutSeconds, &out.BindTimeoutSeconds, s); err != nil { + return err + } + out.Shape = *(*[]config.UtilizationShapePoint)(unsafe.Pointer(&in.Shape)) + return nil +} + +// Convert_v1beta2_VolumeBindingArgs_To_config_VolumeBindingArgs is an autogenerated conversion function. +func Convert_v1beta2_VolumeBindingArgs_To_config_VolumeBindingArgs(in *v1beta2.VolumeBindingArgs, out *config.VolumeBindingArgs, s conversion.Scope) error { + return autoConvert_v1beta2_VolumeBindingArgs_To_config_VolumeBindingArgs(in, out, s) +} + +func autoConvert_config_VolumeBindingArgs_To_v1beta2_VolumeBindingArgs(in *config.VolumeBindingArgs, out *v1beta2.VolumeBindingArgs, s conversion.Scope) error { + if err := v1.Convert_int64_To_Pointer_int64(&in.BindTimeoutSeconds, &out.BindTimeoutSeconds, s); err != nil { + return err + } + out.Shape = *(*[]v1beta2.UtilizationShapePoint)(unsafe.Pointer(&in.Shape)) + return nil +} + +// Convert_config_VolumeBindingArgs_To_v1beta2_VolumeBindingArgs is an autogenerated conversion function. +func Convert_config_VolumeBindingArgs_To_v1beta2_VolumeBindingArgs(in *config.VolumeBindingArgs, out *v1beta2.VolumeBindingArgs, s conversion.Scope) error { + return autoConvert_config_VolumeBindingArgs_To_v1beta2_VolumeBindingArgs(in, out, s) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/zz_generated.deepcopy.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/zz_generated.deepcopy.go new file mode 100644 index 000000000..e38909ba4 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/zz_generated.deepcopy.go @@ -0,0 +1,22 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1beta2 diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/zz_generated.defaults.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/zz_generated.defaults.go new file mode 100644 index 000000000..359ee6437 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2/zz_generated.defaults.go @@ -0,0 +1,73 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1beta2 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" + v1beta2 "k8s.io/kube-scheduler/config/v1beta2" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + scheme.AddTypeDefaultingFunc(&v1beta2.DefaultPreemptionArgs{}, func(obj interface{}) { SetObjectDefaults_DefaultPreemptionArgs(obj.(*v1beta2.DefaultPreemptionArgs)) }) + scheme.AddTypeDefaultingFunc(&v1beta2.InterPodAffinityArgs{}, func(obj interface{}) { SetObjectDefaults_InterPodAffinityArgs(obj.(*v1beta2.InterPodAffinityArgs)) }) + scheme.AddTypeDefaultingFunc(&v1beta2.KubeSchedulerConfiguration{}, func(obj interface{}) { + SetObjectDefaults_KubeSchedulerConfiguration(obj.(*v1beta2.KubeSchedulerConfiguration)) + }) + scheme.AddTypeDefaultingFunc(&v1beta2.NodeResourcesBalancedAllocationArgs{}, func(obj interface{}) { + SetObjectDefaults_NodeResourcesBalancedAllocationArgs(obj.(*v1beta2.NodeResourcesBalancedAllocationArgs)) + }) + scheme.AddTypeDefaultingFunc(&v1beta2.NodeResourcesFitArgs{}, func(obj interface{}) { SetObjectDefaults_NodeResourcesFitArgs(obj.(*v1beta2.NodeResourcesFitArgs)) }) + scheme.AddTypeDefaultingFunc(&v1beta2.PodTopologySpreadArgs{}, func(obj interface{}) { SetObjectDefaults_PodTopologySpreadArgs(obj.(*v1beta2.PodTopologySpreadArgs)) }) + scheme.AddTypeDefaultingFunc(&v1beta2.VolumeBindingArgs{}, func(obj interface{}) { SetObjectDefaults_VolumeBindingArgs(obj.(*v1beta2.VolumeBindingArgs)) }) + return nil +} + +func SetObjectDefaults_DefaultPreemptionArgs(in *v1beta2.DefaultPreemptionArgs) { + SetDefaults_DefaultPreemptionArgs(in) +} + +func SetObjectDefaults_InterPodAffinityArgs(in *v1beta2.InterPodAffinityArgs) { + SetDefaults_InterPodAffinityArgs(in) +} + +func SetObjectDefaults_KubeSchedulerConfiguration(in *v1beta2.KubeSchedulerConfiguration) { + SetDefaults_KubeSchedulerConfiguration(in) +} + +func SetObjectDefaults_NodeResourcesBalancedAllocationArgs(in *v1beta2.NodeResourcesBalancedAllocationArgs) { + SetDefaults_NodeResourcesBalancedAllocationArgs(in) +} + +func SetObjectDefaults_NodeResourcesFitArgs(in *v1beta2.NodeResourcesFitArgs) { + SetDefaults_NodeResourcesFitArgs(in) +} + +func SetObjectDefaults_PodTopologySpreadArgs(in *v1beta2.PodTopologySpreadArgs) { + SetDefaults_PodTopologySpreadArgs(in) +} + +func SetObjectDefaults_VolumeBindingArgs(in *v1beta2.VolumeBindingArgs) { + SetDefaults_VolumeBindingArgs(in) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/conversion.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/conversion.go new file mode 100644 index 000000000..bbb8ff4f2 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/conversion.go @@ -0,0 +1,118 @@ +/* +Copyright 2021 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 v1beta3 + +import ( + "fmt" + "sync" + + "k8s.io/apimachinery/pkg/conversion" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/kube-scheduler/config/v1beta3" + "k8s.io/kubernetes/pkg/scheduler/apis/config" +) + +var ( + // pluginArgConversionScheme is a scheme with internal and v1beta3 registered, + // used for defaulting/converting typed PluginConfig Args. + // Access via getPluginArgConversionScheme() + pluginArgConversionScheme *runtime.Scheme + initPluginArgConversionScheme sync.Once +) + +func GetPluginArgConversionScheme() *runtime.Scheme { + initPluginArgConversionScheme.Do(func() { + // set up the scheme used for plugin arg conversion + pluginArgConversionScheme = runtime.NewScheme() + utilruntime.Must(AddToScheme(pluginArgConversionScheme)) + utilruntime.Must(config.AddToScheme(pluginArgConversionScheme)) + }) + return pluginArgConversionScheme +} + +func Convert_v1beta3_KubeSchedulerConfiguration_To_config_KubeSchedulerConfiguration(in *v1beta3.KubeSchedulerConfiguration, out *config.KubeSchedulerConfiguration, s conversion.Scope) error { + if err := autoConvert_v1beta3_KubeSchedulerConfiguration_To_config_KubeSchedulerConfiguration(in, out, s); err != nil { + return err + } + return convertToInternalPluginConfigArgs(out) +} + +// convertToInternalPluginConfigArgs converts PluginConfig#Args into internal +// types using a scheme, after applying defaults. +func convertToInternalPluginConfigArgs(out *config.KubeSchedulerConfiguration) error { + scheme := GetPluginArgConversionScheme() + for i := range out.Profiles { + prof := &out.Profiles[i] + for j := range prof.PluginConfig { + args := prof.PluginConfig[j].Args + if args == nil { + continue + } + if _, isUnknown := args.(*runtime.Unknown); isUnknown { + continue + } + internalArgs, err := scheme.ConvertToVersion(args, config.SchemeGroupVersion) + if err != nil { + return fmt.Errorf("converting .Profiles[%d].PluginConfig[%d].Args into internal type: %w", i, j, err) + } + prof.PluginConfig[j].Args = internalArgs + } + } + return nil +} + +func Convert_config_KubeSchedulerConfiguration_To_v1beta3_KubeSchedulerConfiguration(in *config.KubeSchedulerConfiguration, out *v1beta3.KubeSchedulerConfiguration, s conversion.Scope) error { + if err := autoConvert_config_KubeSchedulerConfiguration_To_v1beta3_KubeSchedulerConfiguration(in, out, s); err != nil { + return err + } + return convertToExternalPluginConfigArgs(out) +} + +// convertToExternalPluginConfigArgs converts PluginConfig#Args into +// external (versioned) types using a scheme. +func convertToExternalPluginConfigArgs(out *v1beta3.KubeSchedulerConfiguration) error { + scheme := GetPluginArgConversionScheme() + for i := range out.Profiles { + for j := range out.Profiles[i].PluginConfig { + args := out.Profiles[i].PluginConfig[j].Args + if args.Object == nil { + continue + } + if _, isUnknown := args.Object.(*runtime.Unknown); isUnknown { + continue + } + externalArgs, err := scheme.ConvertToVersion(args.Object, SchemeGroupVersion) + if err != nil { + return err + } + out.Profiles[i].PluginConfig[j].Args.Object = externalArgs + } + } + return nil +} + +// Convert_config_KubeSchedulerProfile_To_v1beta3_KubeSchedulerProfile called auto coversion by +// ignoring per profile PercentageOfNodesToScore. +func Convert_config_KubeSchedulerProfile_To_v1beta3_KubeSchedulerProfile(in *config.KubeSchedulerProfile, out *v1beta3.KubeSchedulerProfile, s conversion.Scope) error { + return autoConvert_config_KubeSchedulerProfile_To_v1beta3_KubeSchedulerProfile(in, out, s) +} + +// Convert_config_Plugins_To_v1beta3_Plugins is an autogenerated conversion function. +func Convert_config_Plugins_To_v1beta3_Plugins(in *config.Plugins, out *v1beta3.Plugins, s conversion.Scope) error { + return autoConvert_config_Plugins_To_v1beta3_Plugins(in, out, s) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/default_plugins.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/default_plugins.go new file mode 100644 index 000000000..13d479fec --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/default_plugins.go @@ -0,0 +1,144 @@ +/* +Copyright 2021 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 v1beta3 + +import ( + "k8s.io/apimachinery/pkg/util/sets" + utilfeature "k8s.io/apiserver/pkg/util/feature" + "k8s.io/klog/v2" + "k8s.io/kube-scheduler/config/v1beta3" + "k8s.io/kubernetes/pkg/features" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" + "k8s.io/utils/pointer" +) + +// getDefaultPlugins returns the default set of plugins. +func getDefaultPlugins() *v1beta3.Plugins { + plugins := &v1beta3.Plugins{ + MultiPoint: v1beta3.PluginSet{ + Enabled: []v1beta3.Plugin{ + {Name: names.PrioritySort}, + {Name: names.NodeUnschedulable}, + {Name: names.NodeName}, + {Name: names.TaintToleration, Weight: pointer.Int32(3)}, + {Name: names.NodeAffinity, Weight: pointer.Int32(2)}, + {Name: names.NodePorts}, + {Name: names.NodeResourcesFit, Weight: pointer.Int32(1)}, + {Name: names.VolumeRestrictions}, + {Name: names.EBSLimits}, + {Name: names.GCEPDLimits}, + {Name: names.NodeVolumeLimits}, + {Name: names.AzureDiskLimits}, + {Name: names.VolumeBinding}, + {Name: names.VolumeZone}, + {Name: names.PodTopologySpread, Weight: pointer.Int32(2)}, + {Name: names.InterPodAffinity, Weight: pointer.Int32(2)}, + {Name: names.DefaultPreemption}, + {Name: names.NodeResourcesBalancedAllocation, Weight: pointer.Int32(1)}, + {Name: names.ImageLocality, Weight: pointer.Int32(1)}, + {Name: names.DefaultBinder}, + }, + }, + } + applyFeatureGates(plugins) + + return plugins +} + +func applyFeatureGates(config *v1beta3.Plugins) { + if utilfeature.DefaultFeatureGate.Enabled(features.PodSchedulingReadiness) { + config.MultiPoint.Enabled = append(config.MultiPoint.Enabled, v1beta3.Plugin{Name: names.SchedulingGates}) + } +} + +// mergePlugins merges the custom set into the given default one, handling disabled sets. +func mergePlugins(defaultPlugins, customPlugins *v1beta3.Plugins) *v1beta3.Plugins { + if customPlugins == nil { + return defaultPlugins + } + + defaultPlugins.MultiPoint = mergePluginSet(defaultPlugins.MultiPoint, customPlugins.MultiPoint) + defaultPlugins.QueueSort = mergePluginSet(defaultPlugins.QueueSort, customPlugins.QueueSort) + defaultPlugins.PreFilter = mergePluginSet(defaultPlugins.PreFilter, customPlugins.PreFilter) + defaultPlugins.Filter = mergePluginSet(defaultPlugins.Filter, customPlugins.Filter) + defaultPlugins.PostFilter = mergePluginSet(defaultPlugins.PostFilter, customPlugins.PostFilter) + defaultPlugins.PreScore = mergePluginSet(defaultPlugins.PreScore, customPlugins.PreScore) + defaultPlugins.Score = mergePluginSet(defaultPlugins.Score, customPlugins.Score) + defaultPlugins.Reserve = mergePluginSet(defaultPlugins.Reserve, customPlugins.Reserve) + defaultPlugins.Permit = mergePluginSet(defaultPlugins.Permit, customPlugins.Permit) + defaultPlugins.PreBind = mergePluginSet(defaultPlugins.PreBind, customPlugins.PreBind) + defaultPlugins.Bind = mergePluginSet(defaultPlugins.Bind, customPlugins.Bind) + defaultPlugins.PostBind = mergePluginSet(defaultPlugins.PostBind, customPlugins.PostBind) + return defaultPlugins +} + +type pluginIndex struct { + index int + plugin v1beta3.Plugin +} + +func mergePluginSet(defaultPluginSet, customPluginSet v1beta3.PluginSet) v1beta3.PluginSet { + disabledPlugins := sets.NewString() + enabledCustomPlugins := make(map[string]pluginIndex) + // replacedPluginIndex is a set of index of plugins, which have replaced the default plugins. + replacedPluginIndex := sets.NewInt() + var disabled []v1beta3.Plugin + for _, disabledPlugin := range customPluginSet.Disabled { + // if the user is manually disabling any (or all, with "*") default plugins for an extension point, + // we need to track that so that the MultiPoint extension logic in the framework can know to skip + // inserting unspecified default plugins to this point. + disabled = append(disabled, v1beta3.Plugin{Name: disabledPlugin.Name}) + disabledPlugins.Insert(disabledPlugin.Name) + } + + // With MultiPoint, we may now have some disabledPlugins in the default registry + // For example, we enable PluginX with Filter+Score through MultiPoint but disable its Score plugin by default. + for _, disabledPlugin := range defaultPluginSet.Disabled { + disabled = append(disabled, v1beta3.Plugin{Name: disabledPlugin.Name}) + disabledPlugins.Insert(disabledPlugin.Name) + } + + for index, enabledPlugin := range customPluginSet.Enabled { + enabledCustomPlugins[enabledPlugin.Name] = pluginIndex{index, enabledPlugin} + } + var enabledPlugins []v1beta3.Plugin + if !disabledPlugins.Has("*") { + for _, defaultEnabledPlugin := range defaultPluginSet.Enabled { + if disabledPlugins.Has(defaultEnabledPlugin.Name) { + continue + } + // The default plugin is explicitly re-configured, update the default plugin accordingly. + if customPlugin, ok := enabledCustomPlugins[defaultEnabledPlugin.Name]; ok { + klog.InfoS("Default plugin is explicitly re-configured; overriding", "plugin", defaultEnabledPlugin.Name) + // Update the default plugin in place to preserve order. + defaultEnabledPlugin = customPlugin.plugin + replacedPluginIndex.Insert(customPlugin.index) + } + enabledPlugins = append(enabledPlugins, defaultEnabledPlugin) + } + } + + // Append all the custom plugins which haven't replaced any default plugins. + // Note: duplicated custom plugins will still be appended here. + // If so, the instantiation of scheduler framework will detect it and abort. + for index, plugin := range customPluginSet.Enabled { + if !replacedPluginIndex.Has(index) { + enabledPlugins = append(enabledPlugins, plugin) + } + } + return v1beta3.PluginSet{Enabled: enabledPlugins, Disabled: disabled} +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/defaults.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/defaults.go new file mode 100644 index 000000000..b3816d36a --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/defaults.go @@ -0,0 +1,242 @@ +/* +Copyright 2021 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 v1beta3 + +import ( + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apiserver/pkg/util/feature" + componentbaseconfigv1alpha1 "k8s.io/component-base/config/v1alpha1" + "k8s.io/kube-scheduler/config/v1beta3" + "k8s.io/kubernetes/pkg/features" + "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/utils/pointer" +) + +var defaultResourceSpec = []v1beta3.ResourceSpec{ + {Name: string(v1.ResourceCPU), Weight: 1}, + {Name: string(v1.ResourceMemory), Weight: 1}, +} + +func addDefaultingFuncs(scheme *runtime.Scheme) error { + return RegisterDefaults(scheme) +} + +func pluginsNames(p *v1beta3.Plugins) []string { + if p == nil { + return nil + } + extensions := []v1beta3.PluginSet{ + p.MultiPoint, + p.PreFilter, + p.Filter, + p.PostFilter, + p.Reserve, + p.PreScore, + p.Score, + p.PreBind, + p.Bind, + p.PostBind, + p.Permit, + p.QueueSort, + } + n := sets.NewString() + for _, e := range extensions { + for _, pg := range e.Enabled { + n.Insert(pg.Name) + } + } + return n.List() +} + +func setDefaults_KubeSchedulerProfile(prof *v1beta3.KubeSchedulerProfile) { + // Set default plugins. + prof.Plugins = mergePlugins(getDefaultPlugins(), prof.Plugins) + // Set default plugin configs. + scheme := GetPluginArgConversionScheme() + existingConfigs := sets.NewString() + for j := range prof.PluginConfig { + existingConfigs.Insert(prof.PluginConfig[j].Name) + args := prof.PluginConfig[j].Args.Object + if _, isUnknown := args.(*runtime.Unknown); isUnknown { + continue + } + scheme.Default(args) + } + + // Append default configs for plugins that didn't have one explicitly set. + for _, name := range pluginsNames(prof.Plugins) { + if existingConfigs.Has(name) { + continue + } + gvk := v1beta3.SchemeGroupVersion.WithKind(name + "Args") + args, err := scheme.New(gvk) + if err != nil { + // This plugin is out-of-tree or doesn't require configuration. + continue + } + scheme.Default(args) + args.GetObjectKind().SetGroupVersionKind(gvk) + prof.PluginConfig = append(prof.PluginConfig, v1beta3.PluginConfig{ + Name: name, + Args: runtime.RawExtension{Object: args}, + }) + } +} + +// SetDefaults_KubeSchedulerConfiguration sets additional defaults +func SetDefaults_KubeSchedulerConfiguration(obj *v1beta3.KubeSchedulerConfiguration) { + if obj.Parallelism == nil { + obj.Parallelism = pointer.Int32(16) + } + + if len(obj.Profiles) == 0 { + obj.Profiles = append(obj.Profiles, v1beta3.KubeSchedulerProfile{}) + } + // Only apply a default scheduler name when there is a single profile. + // Validation will ensure that every profile has a non-empty unique name. + if len(obj.Profiles) == 1 && obj.Profiles[0].SchedulerName == nil { + obj.Profiles[0].SchedulerName = pointer.String(v1.DefaultSchedulerName) + } + + // Add the default set of plugins and apply the configuration. + for i := range obj.Profiles { + prof := &obj.Profiles[i] + setDefaults_KubeSchedulerProfile(prof) + } + + if obj.PercentageOfNodesToScore == nil { + percentageOfNodesToScore := int32(config.DefaultPercentageOfNodesToScore) + obj.PercentageOfNodesToScore = &percentageOfNodesToScore + } + + if len(obj.LeaderElection.ResourceLock) == 0 { + // Use lease-based leader election to reduce cost. + // We migrated for EndpointsLease lock in 1.17 and starting in 1.20 we + // migrated to Lease lock. + obj.LeaderElection.ResourceLock = "leases" + } + if len(obj.LeaderElection.ResourceNamespace) == 0 { + obj.LeaderElection.ResourceNamespace = v1beta3.SchedulerDefaultLockObjectNamespace + } + if len(obj.LeaderElection.ResourceName) == 0 { + obj.LeaderElection.ResourceName = v1beta3.SchedulerDefaultLockObjectName + } + + if len(obj.ClientConnection.ContentType) == 0 { + obj.ClientConnection.ContentType = "application/vnd.kubernetes.protobuf" + } + // Scheduler has an opinion about QPS/Burst, setting specific defaults for itself, instead of generic settings. + if obj.ClientConnection.QPS == 0.0 { + obj.ClientConnection.QPS = 50.0 + } + if obj.ClientConnection.Burst == 0 { + obj.ClientConnection.Burst = 100 + } + + // Use the default LeaderElectionConfiguration options + componentbaseconfigv1alpha1.RecommendedDefaultLeaderElectionConfiguration(&obj.LeaderElection) + + if obj.PodInitialBackoffSeconds == nil { + obj.PodInitialBackoffSeconds = pointer.Int64(1) + } + + if obj.PodMaxBackoffSeconds == nil { + obj.PodMaxBackoffSeconds = pointer.Int64(10) + } + + // Enable profiling by default in the scheduler + if obj.EnableProfiling == nil { + obj.EnableProfiling = pointer.Bool(true) + } + + // Enable contention profiling by default if profiling is enabled + if *obj.EnableProfiling && obj.EnableContentionProfiling == nil { + obj.EnableContentionProfiling = pointer.Bool(true) + } +} + +func SetDefaults_DefaultPreemptionArgs(obj *v1beta3.DefaultPreemptionArgs) { + if obj.MinCandidateNodesPercentage == nil { + obj.MinCandidateNodesPercentage = pointer.Int32(10) + } + if obj.MinCandidateNodesAbsolute == nil { + obj.MinCandidateNodesAbsolute = pointer.Int32(100) + } +} + +func SetDefaults_InterPodAffinityArgs(obj *v1beta3.InterPodAffinityArgs) { + if obj.HardPodAffinityWeight == nil { + obj.HardPodAffinityWeight = pointer.Int32(1) + } +} + +func SetDefaults_VolumeBindingArgs(obj *v1beta3.VolumeBindingArgs) { + if obj.BindTimeoutSeconds == nil { + obj.BindTimeoutSeconds = pointer.Int64(600) + } + if len(obj.Shape) == 0 && feature.DefaultFeatureGate.Enabled(features.VolumeCapacityPriority) { + obj.Shape = []v1beta3.UtilizationShapePoint{ + { + Utilization: 0, + Score: 0, + }, + { + Utilization: 100, + Score: int32(config.MaxCustomPriorityScore), + }, + } + } +} + +func SetDefaults_NodeResourcesBalancedAllocationArgs(obj *v1beta3.NodeResourcesBalancedAllocationArgs) { + if len(obj.Resources) == 0 { + obj.Resources = defaultResourceSpec + return + } + // If the weight is not set or it is explicitly set to 0, then apply the default weight(1) instead. + for i := range obj.Resources { + if obj.Resources[i].Weight == 0 { + obj.Resources[i].Weight = 1 + } + } +} + +func SetDefaults_PodTopologySpreadArgs(obj *v1beta3.PodTopologySpreadArgs) { + if obj.DefaultingType == "" { + obj.DefaultingType = v1beta3.SystemDefaulting + } +} + +func SetDefaults_NodeResourcesFitArgs(obj *v1beta3.NodeResourcesFitArgs) { + if obj.ScoringStrategy == nil { + obj.ScoringStrategy = &v1beta3.ScoringStrategy{ + Type: v1beta3.ScoringStrategyType(config.LeastAllocated), + Resources: defaultResourceSpec, + } + } + if len(obj.ScoringStrategy.Resources) == 0 { + // If no resources specified, use the default set. + obj.ScoringStrategy.Resources = append(obj.ScoringStrategy.Resources, defaultResourceSpec...) + } + for i := range obj.ScoringStrategy.Resources { + if obj.ScoringStrategy.Resources[i].Weight == 0 { + obj.ScoringStrategy.Resources[i].Weight = 1 + } + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/doc.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/doc.go new file mode 100644 index 000000000..e9976588f --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/doc.go @@ -0,0 +1,24 @@ +/* +Copyright 2021 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. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:conversion-gen=k8s.io/kubernetes/pkg/scheduler/apis/config +// +k8s:conversion-gen-external-types=k8s.io/kube-scheduler/config/v1beta3 +// +k8s:defaulter-gen=TypeMeta +// +k8s:defaulter-gen-input=k8s.io/kube-scheduler/config/v1beta3 +// +groupName=kubescheduler.config.k8s.io + +package v1beta3 // import "k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3" diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/register.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/register.go new file mode 100644 index 000000000..2af0952e6 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/register.go @@ -0,0 +1,42 @@ +/* +Copyright 2021 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 v1beta3 + +import ( + "k8s.io/kube-scheduler/config/v1beta3" +) + +// GroupName is the group name used in this package +const GroupName = v1beta3.GroupName + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = v1beta3.SchemeGroupVersion + +var ( + // localSchemeBuilder extends the SchemeBuilder instance with the external types. In this package, + // defaulting and conversion init funcs are registered as well. + localSchemeBuilder = &v1beta3.SchemeBuilder + // AddToScheme is a global function that registers this API group & version to a scheme + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addDefaultingFuncs) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/zz_generated.conversion.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/zz_generated.conversion.go new file mode 100644 index 000000000..1e8fd12ba --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/zz_generated.conversion.go @@ -0,0 +1,933 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by conversion-gen. DO NOT EDIT. + +package v1beta3 + +import ( + unsafe "unsafe" + + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + v1alpha1 "k8s.io/component-base/config/v1alpha1" + v1beta3 "k8s.io/kube-scheduler/config/v1beta3" + config "k8s.io/kubernetes/pkg/scheduler/apis/config" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*v1beta3.DefaultPreemptionArgs)(nil), (*config.DefaultPreemptionArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta3_DefaultPreemptionArgs_To_config_DefaultPreemptionArgs(a.(*v1beta3.DefaultPreemptionArgs), b.(*config.DefaultPreemptionArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.DefaultPreemptionArgs)(nil), (*v1beta3.DefaultPreemptionArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_DefaultPreemptionArgs_To_v1beta3_DefaultPreemptionArgs(a.(*config.DefaultPreemptionArgs), b.(*v1beta3.DefaultPreemptionArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta3.Extender)(nil), (*config.Extender)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta3_Extender_To_config_Extender(a.(*v1beta3.Extender), b.(*config.Extender), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.Extender)(nil), (*v1beta3.Extender)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_Extender_To_v1beta3_Extender(a.(*config.Extender), b.(*v1beta3.Extender), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta3.ExtenderManagedResource)(nil), (*config.ExtenderManagedResource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta3_ExtenderManagedResource_To_config_ExtenderManagedResource(a.(*v1beta3.ExtenderManagedResource), b.(*config.ExtenderManagedResource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.ExtenderManagedResource)(nil), (*v1beta3.ExtenderManagedResource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_ExtenderManagedResource_To_v1beta3_ExtenderManagedResource(a.(*config.ExtenderManagedResource), b.(*v1beta3.ExtenderManagedResource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta3.ExtenderTLSConfig)(nil), (*config.ExtenderTLSConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta3_ExtenderTLSConfig_To_config_ExtenderTLSConfig(a.(*v1beta3.ExtenderTLSConfig), b.(*config.ExtenderTLSConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.ExtenderTLSConfig)(nil), (*v1beta3.ExtenderTLSConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_ExtenderTLSConfig_To_v1beta3_ExtenderTLSConfig(a.(*config.ExtenderTLSConfig), b.(*v1beta3.ExtenderTLSConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta3.InterPodAffinityArgs)(nil), (*config.InterPodAffinityArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta3_InterPodAffinityArgs_To_config_InterPodAffinityArgs(a.(*v1beta3.InterPodAffinityArgs), b.(*config.InterPodAffinityArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.InterPodAffinityArgs)(nil), (*v1beta3.InterPodAffinityArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_InterPodAffinityArgs_To_v1beta3_InterPodAffinityArgs(a.(*config.InterPodAffinityArgs), b.(*v1beta3.InterPodAffinityArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta3.KubeSchedulerProfile)(nil), (*config.KubeSchedulerProfile)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta3_KubeSchedulerProfile_To_config_KubeSchedulerProfile(a.(*v1beta3.KubeSchedulerProfile), b.(*config.KubeSchedulerProfile), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta3.NodeAffinityArgs)(nil), (*config.NodeAffinityArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta3_NodeAffinityArgs_To_config_NodeAffinityArgs(a.(*v1beta3.NodeAffinityArgs), b.(*config.NodeAffinityArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.NodeAffinityArgs)(nil), (*v1beta3.NodeAffinityArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_NodeAffinityArgs_To_v1beta3_NodeAffinityArgs(a.(*config.NodeAffinityArgs), b.(*v1beta3.NodeAffinityArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta3.NodeResourcesBalancedAllocationArgs)(nil), (*config.NodeResourcesBalancedAllocationArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta3_NodeResourcesBalancedAllocationArgs_To_config_NodeResourcesBalancedAllocationArgs(a.(*v1beta3.NodeResourcesBalancedAllocationArgs), b.(*config.NodeResourcesBalancedAllocationArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.NodeResourcesBalancedAllocationArgs)(nil), (*v1beta3.NodeResourcesBalancedAllocationArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_NodeResourcesBalancedAllocationArgs_To_v1beta3_NodeResourcesBalancedAllocationArgs(a.(*config.NodeResourcesBalancedAllocationArgs), b.(*v1beta3.NodeResourcesBalancedAllocationArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta3.NodeResourcesFitArgs)(nil), (*config.NodeResourcesFitArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta3_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs(a.(*v1beta3.NodeResourcesFitArgs), b.(*config.NodeResourcesFitArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.NodeResourcesFitArgs)(nil), (*v1beta3.NodeResourcesFitArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_NodeResourcesFitArgs_To_v1beta3_NodeResourcesFitArgs(a.(*config.NodeResourcesFitArgs), b.(*v1beta3.NodeResourcesFitArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta3.Plugin)(nil), (*config.Plugin)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta3_Plugin_To_config_Plugin(a.(*v1beta3.Plugin), b.(*config.Plugin), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.Plugin)(nil), (*v1beta3.Plugin)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_Plugin_To_v1beta3_Plugin(a.(*config.Plugin), b.(*v1beta3.Plugin), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta3.PluginConfig)(nil), (*config.PluginConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta3_PluginConfig_To_config_PluginConfig(a.(*v1beta3.PluginConfig), b.(*config.PluginConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.PluginConfig)(nil), (*v1beta3.PluginConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_PluginConfig_To_v1beta3_PluginConfig(a.(*config.PluginConfig), b.(*v1beta3.PluginConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta3.PluginSet)(nil), (*config.PluginSet)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta3_PluginSet_To_config_PluginSet(a.(*v1beta3.PluginSet), b.(*config.PluginSet), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.PluginSet)(nil), (*v1beta3.PluginSet)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_PluginSet_To_v1beta3_PluginSet(a.(*config.PluginSet), b.(*v1beta3.PluginSet), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta3.Plugins)(nil), (*config.Plugins)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta3_Plugins_To_config_Plugins(a.(*v1beta3.Plugins), b.(*config.Plugins), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta3.PodTopologySpreadArgs)(nil), (*config.PodTopologySpreadArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta3_PodTopologySpreadArgs_To_config_PodTopologySpreadArgs(a.(*v1beta3.PodTopologySpreadArgs), b.(*config.PodTopologySpreadArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.PodTopologySpreadArgs)(nil), (*v1beta3.PodTopologySpreadArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_PodTopologySpreadArgs_To_v1beta3_PodTopologySpreadArgs(a.(*config.PodTopologySpreadArgs), b.(*v1beta3.PodTopologySpreadArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta3.RequestedToCapacityRatioParam)(nil), (*config.RequestedToCapacityRatioParam)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta3_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(a.(*v1beta3.RequestedToCapacityRatioParam), b.(*config.RequestedToCapacityRatioParam), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.RequestedToCapacityRatioParam)(nil), (*v1beta3.RequestedToCapacityRatioParam)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_RequestedToCapacityRatioParam_To_v1beta3_RequestedToCapacityRatioParam(a.(*config.RequestedToCapacityRatioParam), b.(*v1beta3.RequestedToCapacityRatioParam), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta3.ResourceSpec)(nil), (*config.ResourceSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta3_ResourceSpec_To_config_ResourceSpec(a.(*v1beta3.ResourceSpec), b.(*config.ResourceSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.ResourceSpec)(nil), (*v1beta3.ResourceSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_ResourceSpec_To_v1beta3_ResourceSpec(a.(*config.ResourceSpec), b.(*v1beta3.ResourceSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta3.ScoringStrategy)(nil), (*config.ScoringStrategy)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta3_ScoringStrategy_To_config_ScoringStrategy(a.(*v1beta3.ScoringStrategy), b.(*config.ScoringStrategy), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.ScoringStrategy)(nil), (*v1beta3.ScoringStrategy)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_ScoringStrategy_To_v1beta3_ScoringStrategy(a.(*config.ScoringStrategy), b.(*v1beta3.ScoringStrategy), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta3.UtilizationShapePoint)(nil), (*config.UtilizationShapePoint)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta3_UtilizationShapePoint_To_config_UtilizationShapePoint(a.(*v1beta3.UtilizationShapePoint), b.(*config.UtilizationShapePoint), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.UtilizationShapePoint)(nil), (*v1beta3.UtilizationShapePoint)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_UtilizationShapePoint_To_v1beta3_UtilizationShapePoint(a.(*config.UtilizationShapePoint), b.(*v1beta3.UtilizationShapePoint), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta3.VolumeBindingArgs)(nil), (*config.VolumeBindingArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta3_VolumeBindingArgs_To_config_VolumeBindingArgs(a.(*v1beta3.VolumeBindingArgs), b.(*config.VolumeBindingArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.VolumeBindingArgs)(nil), (*v1beta3.VolumeBindingArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_VolumeBindingArgs_To_v1beta3_VolumeBindingArgs(a.(*config.VolumeBindingArgs), b.(*v1beta3.VolumeBindingArgs), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*config.KubeSchedulerConfiguration)(nil), (*v1beta3.KubeSchedulerConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_KubeSchedulerConfiguration_To_v1beta3_KubeSchedulerConfiguration(a.(*config.KubeSchedulerConfiguration), b.(*v1beta3.KubeSchedulerConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*config.KubeSchedulerProfile)(nil), (*v1beta3.KubeSchedulerProfile)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_KubeSchedulerProfile_To_v1beta3_KubeSchedulerProfile(a.(*config.KubeSchedulerProfile), b.(*v1beta3.KubeSchedulerProfile), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*config.Plugins)(nil), (*v1beta3.Plugins)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_Plugins_To_v1beta3_Plugins(a.(*config.Plugins), b.(*v1beta3.Plugins), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1beta3.KubeSchedulerConfiguration)(nil), (*config.KubeSchedulerConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta3_KubeSchedulerConfiguration_To_config_KubeSchedulerConfiguration(a.(*v1beta3.KubeSchedulerConfiguration), b.(*config.KubeSchedulerConfiguration), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v1beta3_DefaultPreemptionArgs_To_config_DefaultPreemptionArgs(in *v1beta3.DefaultPreemptionArgs, out *config.DefaultPreemptionArgs, s conversion.Scope) error { + if err := v1.Convert_Pointer_int32_To_int32(&in.MinCandidateNodesPercentage, &out.MinCandidateNodesPercentage, s); err != nil { + return err + } + if err := v1.Convert_Pointer_int32_To_int32(&in.MinCandidateNodesAbsolute, &out.MinCandidateNodesAbsolute, s); err != nil { + return err + } + return nil +} + +// Convert_v1beta3_DefaultPreemptionArgs_To_config_DefaultPreemptionArgs is an autogenerated conversion function. +func Convert_v1beta3_DefaultPreemptionArgs_To_config_DefaultPreemptionArgs(in *v1beta3.DefaultPreemptionArgs, out *config.DefaultPreemptionArgs, s conversion.Scope) error { + return autoConvert_v1beta3_DefaultPreemptionArgs_To_config_DefaultPreemptionArgs(in, out, s) +} + +func autoConvert_config_DefaultPreemptionArgs_To_v1beta3_DefaultPreemptionArgs(in *config.DefaultPreemptionArgs, out *v1beta3.DefaultPreemptionArgs, s conversion.Scope) error { + if err := v1.Convert_int32_To_Pointer_int32(&in.MinCandidateNodesPercentage, &out.MinCandidateNodesPercentage, s); err != nil { + return err + } + if err := v1.Convert_int32_To_Pointer_int32(&in.MinCandidateNodesAbsolute, &out.MinCandidateNodesAbsolute, s); err != nil { + return err + } + return nil +} + +// Convert_config_DefaultPreemptionArgs_To_v1beta3_DefaultPreemptionArgs is an autogenerated conversion function. +func Convert_config_DefaultPreemptionArgs_To_v1beta3_DefaultPreemptionArgs(in *config.DefaultPreemptionArgs, out *v1beta3.DefaultPreemptionArgs, s conversion.Scope) error { + return autoConvert_config_DefaultPreemptionArgs_To_v1beta3_DefaultPreemptionArgs(in, out, s) +} + +func autoConvert_v1beta3_Extender_To_config_Extender(in *v1beta3.Extender, out *config.Extender, s conversion.Scope) error { + out.URLPrefix = in.URLPrefix + out.FilterVerb = in.FilterVerb + out.PreemptVerb = in.PreemptVerb + out.PrioritizeVerb = in.PrioritizeVerb + out.Weight = in.Weight + out.BindVerb = in.BindVerb + out.EnableHTTPS = in.EnableHTTPS + out.TLSConfig = (*config.ExtenderTLSConfig)(unsafe.Pointer(in.TLSConfig)) + out.HTTPTimeout = in.HTTPTimeout + out.NodeCacheCapable = in.NodeCacheCapable + out.ManagedResources = *(*[]config.ExtenderManagedResource)(unsafe.Pointer(&in.ManagedResources)) + out.Ignorable = in.Ignorable + return nil +} + +// Convert_v1beta3_Extender_To_config_Extender is an autogenerated conversion function. +func Convert_v1beta3_Extender_To_config_Extender(in *v1beta3.Extender, out *config.Extender, s conversion.Scope) error { + return autoConvert_v1beta3_Extender_To_config_Extender(in, out, s) +} + +func autoConvert_config_Extender_To_v1beta3_Extender(in *config.Extender, out *v1beta3.Extender, s conversion.Scope) error { + out.URLPrefix = in.URLPrefix + out.FilterVerb = in.FilterVerb + out.PreemptVerb = in.PreemptVerb + out.PrioritizeVerb = in.PrioritizeVerb + out.Weight = in.Weight + out.BindVerb = in.BindVerb + out.EnableHTTPS = in.EnableHTTPS + out.TLSConfig = (*v1beta3.ExtenderTLSConfig)(unsafe.Pointer(in.TLSConfig)) + out.HTTPTimeout = in.HTTPTimeout + out.NodeCacheCapable = in.NodeCacheCapable + out.ManagedResources = *(*[]v1beta3.ExtenderManagedResource)(unsafe.Pointer(&in.ManagedResources)) + out.Ignorable = in.Ignorable + return nil +} + +// Convert_config_Extender_To_v1beta3_Extender is an autogenerated conversion function. +func Convert_config_Extender_To_v1beta3_Extender(in *config.Extender, out *v1beta3.Extender, s conversion.Scope) error { + return autoConvert_config_Extender_To_v1beta3_Extender(in, out, s) +} + +func autoConvert_v1beta3_ExtenderManagedResource_To_config_ExtenderManagedResource(in *v1beta3.ExtenderManagedResource, out *config.ExtenderManagedResource, s conversion.Scope) error { + out.Name = in.Name + out.IgnoredByScheduler = in.IgnoredByScheduler + return nil +} + +// Convert_v1beta3_ExtenderManagedResource_To_config_ExtenderManagedResource is an autogenerated conversion function. +func Convert_v1beta3_ExtenderManagedResource_To_config_ExtenderManagedResource(in *v1beta3.ExtenderManagedResource, out *config.ExtenderManagedResource, s conversion.Scope) error { + return autoConvert_v1beta3_ExtenderManagedResource_To_config_ExtenderManagedResource(in, out, s) +} + +func autoConvert_config_ExtenderManagedResource_To_v1beta3_ExtenderManagedResource(in *config.ExtenderManagedResource, out *v1beta3.ExtenderManagedResource, s conversion.Scope) error { + out.Name = in.Name + out.IgnoredByScheduler = in.IgnoredByScheduler + return nil +} + +// Convert_config_ExtenderManagedResource_To_v1beta3_ExtenderManagedResource is an autogenerated conversion function. +func Convert_config_ExtenderManagedResource_To_v1beta3_ExtenderManagedResource(in *config.ExtenderManagedResource, out *v1beta3.ExtenderManagedResource, s conversion.Scope) error { + return autoConvert_config_ExtenderManagedResource_To_v1beta3_ExtenderManagedResource(in, out, s) +} + +func autoConvert_v1beta3_ExtenderTLSConfig_To_config_ExtenderTLSConfig(in *v1beta3.ExtenderTLSConfig, out *config.ExtenderTLSConfig, s conversion.Scope) error { + out.Insecure = in.Insecure + out.ServerName = in.ServerName + out.CertFile = in.CertFile + out.KeyFile = in.KeyFile + out.CAFile = in.CAFile + out.CertData = *(*[]byte)(unsafe.Pointer(&in.CertData)) + out.KeyData = *(*[]byte)(unsafe.Pointer(&in.KeyData)) + out.CAData = *(*[]byte)(unsafe.Pointer(&in.CAData)) + return nil +} + +// Convert_v1beta3_ExtenderTLSConfig_To_config_ExtenderTLSConfig is an autogenerated conversion function. +func Convert_v1beta3_ExtenderTLSConfig_To_config_ExtenderTLSConfig(in *v1beta3.ExtenderTLSConfig, out *config.ExtenderTLSConfig, s conversion.Scope) error { + return autoConvert_v1beta3_ExtenderTLSConfig_To_config_ExtenderTLSConfig(in, out, s) +} + +func autoConvert_config_ExtenderTLSConfig_To_v1beta3_ExtenderTLSConfig(in *config.ExtenderTLSConfig, out *v1beta3.ExtenderTLSConfig, s conversion.Scope) error { + out.Insecure = in.Insecure + out.ServerName = in.ServerName + out.CertFile = in.CertFile + out.KeyFile = in.KeyFile + out.CAFile = in.CAFile + out.CertData = *(*[]byte)(unsafe.Pointer(&in.CertData)) + out.KeyData = *(*[]byte)(unsafe.Pointer(&in.KeyData)) + out.CAData = *(*[]byte)(unsafe.Pointer(&in.CAData)) + return nil +} + +// Convert_config_ExtenderTLSConfig_To_v1beta3_ExtenderTLSConfig is an autogenerated conversion function. +func Convert_config_ExtenderTLSConfig_To_v1beta3_ExtenderTLSConfig(in *config.ExtenderTLSConfig, out *v1beta3.ExtenderTLSConfig, s conversion.Scope) error { + return autoConvert_config_ExtenderTLSConfig_To_v1beta3_ExtenderTLSConfig(in, out, s) +} + +func autoConvert_v1beta3_InterPodAffinityArgs_To_config_InterPodAffinityArgs(in *v1beta3.InterPodAffinityArgs, out *config.InterPodAffinityArgs, s conversion.Scope) error { + if err := v1.Convert_Pointer_int32_To_int32(&in.HardPodAffinityWeight, &out.HardPodAffinityWeight, s); err != nil { + return err + } + return nil +} + +// Convert_v1beta3_InterPodAffinityArgs_To_config_InterPodAffinityArgs is an autogenerated conversion function. +func Convert_v1beta3_InterPodAffinityArgs_To_config_InterPodAffinityArgs(in *v1beta3.InterPodAffinityArgs, out *config.InterPodAffinityArgs, s conversion.Scope) error { + return autoConvert_v1beta3_InterPodAffinityArgs_To_config_InterPodAffinityArgs(in, out, s) +} + +func autoConvert_config_InterPodAffinityArgs_To_v1beta3_InterPodAffinityArgs(in *config.InterPodAffinityArgs, out *v1beta3.InterPodAffinityArgs, s conversion.Scope) error { + if err := v1.Convert_int32_To_Pointer_int32(&in.HardPodAffinityWeight, &out.HardPodAffinityWeight, s); err != nil { + return err + } + return nil +} + +// Convert_config_InterPodAffinityArgs_To_v1beta3_InterPodAffinityArgs is an autogenerated conversion function. +func Convert_config_InterPodAffinityArgs_To_v1beta3_InterPodAffinityArgs(in *config.InterPodAffinityArgs, out *v1beta3.InterPodAffinityArgs, s conversion.Scope) error { + return autoConvert_config_InterPodAffinityArgs_To_v1beta3_InterPodAffinityArgs(in, out, s) +} + +func autoConvert_v1beta3_KubeSchedulerConfiguration_To_config_KubeSchedulerConfiguration(in *v1beta3.KubeSchedulerConfiguration, out *config.KubeSchedulerConfiguration, s conversion.Scope) error { + if err := v1.Convert_Pointer_int32_To_int32(&in.Parallelism, &out.Parallelism, s); err != nil { + return err + } + if err := v1alpha1.Convert_v1alpha1_LeaderElectionConfiguration_To_config_LeaderElectionConfiguration(&in.LeaderElection, &out.LeaderElection, s); err != nil { + return err + } + if err := v1alpha1.Convert_v1alpha1_ClientConnectionConfiguration_To_config_ClientConnectionConfiguration(&in.ClientConnection, &out.ClientConnection, s); err != nil { + return err + } + if err := v1alpha1.Convert_v1alpha1_DebuggingConfiguration_To_config_DebuggingConfiguration(&in.DebuggingConfiguration, &out.DebuggingConfiguration, s); err != nil { + return err + } + out.PercentageOfNodesToScore = (*int32)(unsafe.Pointer(in.PercentageOfNodesToScore)) + if err := v1.Convert_Pointer_int64_To_int64(&in.PodInitialBackoffSeconds, &out.PodInitialBackoffSeconds, s); err != nil { + return err + } + if err := v1.Convert_Pointer_int64_To_int64(&in.PodMaxBackoffSeconds, &out.PodMaxBackoffSeconds, s); err != nil { + return err + } + if in.Profiles != nil { + in, out := &in.Profiles, &out.Profiles + *out = make([]config.KubeSchedulerProfile, len(*in)) + for i := range *in { + if err := Convert_v1beta3_KubeSchedulerProfile_To_config_KubeSchedulerProfile(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Profiles = nil + } + out.Extenders = *(*[]config.Extender)(unsafe.Pointer(&in.Extenders)) + return nil +} + +func autoConvert_config_KubeSchedulerConfiguration_To_v1beta3_KubeSchedulerConfiguration(in *config.KubeSchedulerConfiguration, out *v1beta3.KubeSchedulerConfiguration, s conversion.Scope) error { + if err := v1.Convert_int32_To_Pointer_int32(&in.Parallelism, &out.Parallelism, s); err != nil { + return err + } + if err := v1alpha1.Convert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfiguration(&in.LeaderElection, &out.LeaderElection, s); err != nil { + return err + } + if err := v1alpha1.Convert_config_ClientConnectionConfiguration_To_v1alpha1_ClientConnectionConfiguration(&in.ClientConnection, &out.ClientConnection, s); err != nil { + return err + } + // WARNING: in.HealthzBindAddress requires manual conversion: does not exist in peer-type + // WARNING: in.MetricsBindAddress requires manual conversion: does not exist in peer-type + if err := v1alpha1.Convert_config_DebuggingConfiguration_To_v1alpha1_DebuggingConfiguration(&in.DebuggingConfiguration, &out.DebuggingConfiguration, s); err != nil { + return err + } + out.PercentageOfNodesToScore = (*int32)(unsafe.Pointer(in.PercentageOfNodesToScore)) + if err := v1.Convert_int64_To_Pointer_int64(&in.PodInitialBackoffSeconds, &out.PodInitialBackoffSeconds, s); err != nil { + return err + } + if err := v1.Convert_int64_To_Pointer_int64(&in.PodMaxBackoffSeconds, &out.PodMaxBackoffSeconds, s); err != nil { + return err + } + if in.Profiles != nil { + in, out := &in.Profiles, &out.Profiles + *out = make([]v1beta3.KubeSchedulerProfile, len(*in)) + for i := range *in { + if err := Convert_config_KubeSchedulerProfile_To_v1beta3_KubeSchedulerProfile(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Profiles = nil + } + out.Extenders = *(*[]v1beta3.Extender)(unsafe.Pointer(&in.Extenders)) + return nil +} + +func autoConvert_v1beta3_KubeSchedulerProfile_To_config_KubeSchedulerProfile(in *v1beta3.KubeSchedulerProfile, out *config.KubeSchedulerProfile, s conversion.Scope) error { + if err := v1.Convert_Pointer_string_To_string(&in.SchedulerName, &out.SchedulerName, s); err != nil { + return err + } + if in.Plugins != nil { + in, out := &in.Plugins, &out.Plugins + *out = new(config.Plugins) + if err := Convert_v1beta3_Plugins_To_config_Plugins(*in, *out, s); err != nil { + return err + } + } else { + out.Plugins = nil + } + if in.PluginConfig != nil { + in, out := &in.PluginConfig, &out.PluginConfig + *out = make([]config.PluginConfig, len(*in)) + for i := range *in { + if err := Convert_v1beta3_PluginConfig_To_config_PluginConfig(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.PluginConfig = nil + } + return nil +} + +// Convert_v1beta3_KubeSchedulerProfile_To_config_KubeSchedulerProfile is an autogenerated conversion function. +func Convert_v1beta3_KubeSchedulerProfile_To_config_KubeSchedulerProfile(in *v1beta3.KubeSchedulerProfile, out *config.KubeSchedulerProfile, s conversion.Scope) error { + return autoConvert_v1beta3_KubeSchedulerProfile_To_config_KubeSchedulerProfile(in, out, s) +} + +func autoConvert_config_KubeSchedulerProfile_To_v1beta3_KubeSchedulerProfile(in *config.KubeSchedulerProfile, out *v1beta3.KubeSchedulerProfile, s conversion.Scope) error { + if err := v1.Convert_string_To_Pointer_string(&in.SchedulerName, &out.SchedulerName, s); err != nil { + return err + } + // WARNING: in.PercentageOfNodesToScore requires manual conversion: does not exist in peer-type + if in.Plugins != nil { + in, out := &in.Plugins, &out.Plugins + *out = new(v1beta3.Plugins) + if err := Convert_config_Plugins_To_v1beta3_Plugins(*in, *out, s); err != nil { + return err + } + } else { + out.Plugins = nil + } + if in.PluginConfig != nil { + in, out := &in.PluginConfig, &out.PluginConfig + *out = make([]v1beta3.PluginConfig, len(*in)) + for i := range *in { + if err := Convert_config_PluginConfig_To_v1beta3_PluginConfig(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.PluginConfig = nil + } + return nil +} + +func autoConvert_v1beta3_NodeAffinityArgs_To_config_NodeAffinityArgs(in *v1beta3.NodeAffinityArgs, out *config.NodeAffinityArgs, s conversion.Scope) error { + out.AddedAffinity = (*corev1.NodeAffinity)(unsafe.Pointer(in.AddedAffinity)) + return nil +} + +// Convert_v1beta3_NodeAffinityArgs_To_config_NodeAffinityArgs is an autogenerated conversion function. +func Convert_v1beta3_NodeAffinityArgs_To_config_NodeAffinityArgs(in *v1beta3.NodeAffinityArgs, out *config.NodeAffinityArgs, s conversion.Scope) error { + return autoConvert_v1beta3_NodeAffinityArgs_To_config_NodeAffinityArgs(in, out, s) +} + +func autoConvert_config_NodeAffinityArgs_To_v1beta3_NodeAffinityArgs(in *config.NodeAffinityArgs, out *v1beta3.NodeAffinityArgs, s conversion.Scope) error { + out.AddedAffinity = (*corev1.NodeAffinity)(unsafe.Pointer(in.AddedAffinity)) + return nil +} + +// Convert_config_NodeAffinityArgs_To_v1beta3_NodeAffinityArgs is an autogenerated conversion function. +func Convert_config_NodeAffinityArgs_To_v1beta3_NodeAffinityArgs(in *config.NodeAffinityArgs, out *v1beta3.NodeAffinityArgs, s conversion.Scope) error { + return autoConvert_config_NodeAffinityArgs_To_v1beta3_NodeAffinityArgs(in, out, s) +} + +func autoConvert_v1beta3_NodeResourcesBalancedAllocationArgs_To_config_NodeResourcesBalancedAllocationArgs(in *v1beta3.NodeResourcesBalancedAllocationArgs, out *config.NodeResourcesBalancedAllocationArgs, s conversion.Scope) error { + out.Resources = *(*[]config.ResourceSpec)(unsafe.Pointer(&in.Resources)) + return nil +} + +// Convert_v1beta3_NodeResourcesBalancedAllocationArgs_To_config_NodeResourcesBalancedAllocationArgs is an autogenerated conversion function. +func Convert_v1beta3_NodeResourcesBalancedAllocationArgs_To_config_NodeResourcesBalancedAllocationArgs(in *v1beta3.NodeResourcesBalancedAllocationArgs, out *config.NodeResourcesBalancedAllocationArgs, s conversion.Scope) error { + return autoConvert_v1beta3_NodeResourcesBalancedAllocationArgs_To_config_NodeResourcesBalancedAllocationArgs(in, out, s) +} + +func autoConvert_config_NodeResourcesBalancedAllocationArgs_To_v1beta3_NodeResourcesBalancedAllocationArgs(in *config.NodeResourcesBalancedAllocationArgs, out *v1beta3.NodeResourcesBalancedAllocationArgs, s conversion.Scope) error { + out.Resources = *(*[]v1beta3.ResourceSpec)(unsafe.Pointer(&in.Resources)) + return nil +} + +// Convert_config_NodeResourcesBalancedAllocationArgs_To_v1beta3_NodeResourcesBalancedAllocationArgs is an autogenerated conversion function. +func Convert_config_NodeResourcesBalancedAllocationArgs_To_v1beta3_NodeResourcesBalancedAllocationArgs(in *config.NodeResourcesBalancedAllocationArgs, out *v1beta3.NodeResourcesBalancedAllocationArgs, s conversion.Scope) error { + return autoConvert_config_NodeResourcesBalancedAllocationArgs_To_v1beta3_NodeResourcesBalancedAllocationArgs(in, out, s) +} + +func autoConvert_v1beta3_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs(in *v1beta3.NodeResourcesFitArgs, out *config.NodeResourcesFitArgs, s conversion.Scope) error { + out.IgnoredResources = *(*[]string)(unsafe.Pointer(&in.IgnoredResources)) + out.IgnoredResourceGroups = *(*[]string)(unsafe.Pointer(&in.IgnoredResourceGroups)) + out.ScoringStrategy = (*config.ScoringStrategy)(unsafe.Pointer(in.ScoringStrategy)) + return nil +} + +// Convert_v1beta3_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs is an autogenerated conversion function. +func Convert_v1beta3_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs(in *v1beta3.NodeResourcesFitArgs, out *config.NodeResourcesFitArgs, s conversion.Scope) error { + return autoConvert_v1beta3_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs(in, out, s) +} + +func autoConvert_config_NodeResourcesFitArgs_To_v1beta3_NodeResourcesFitArgs(in *config.NodeResourcesFitArgs, out *v1beta3.NodeResourcesFitArgs, s conversion.Scope) error { + out.IgnoredResources = *(*[]string)(unsafe.Pointer(&in.IgnoredResources)) + out.IgnoredResourceGroups = *(*[]string)(unsafe.Pointer(&in.IgnoredResourceGroups)) + out.ScoringStrategy = (*v1beta3.ScoringStrategy)(unsafe.Pointer(in.ScoringStrategy)) + return nil +} + +// Convert_config_NodeResourcesFitArgs_To_v1beta3_NodeResourcesFitArgs is an autogenerated conversion function. +func Convert_config_NodeResourcesFitArgs_To_v1beta3_NodeResourcesFitArgs(in *config.NodeResourcesFitArgs, out *v1beta3.NodeResourcesFitArgs, s conversion.Scope) error { + return autoConvert_config_NodeResourcesFitArgs_To_v1beta3_NodeResourcesFitArgs(in, out, s) +} + +func autoConvert_v1beta3_Plugin_To_config_Plugin(in *v1beta3.Plugin, out *config.Plugin, s conversion.Scope) error { + out.Name = in.Name + if err := v1.Convert_Pointer_int32_To_int32(&in.Weight, &out.Weight, s); err != nil { + return err + } + return nil +} + +// Convert_v1beta3_Plugin_To_config_Plugin is an autogenerated conversion function. +func Convert_v1beta3_Plugin_To_config_Plugin(in *v1beta3.Plugin, out *config.Plugin, s conversion.Scope) error { + return autoConvert_v1beta3_Plugin_To_config_Plugin(in, out, s) +} + +func autoConvert_config_Plugin_To_v1beta3_Plugin(in *config.Plugin, out *v1beta3.Plugin, s conversion.Scope) error { + out.Name = in.Name + if err := v1.Convert_int32_To_Pointer_int32(&in.Weight, &out.Weight, s); err != nil { + return err + } + return nil +} + +// Convert_config_Plugin_To_v1beta3_Plugin is an autogenerated conversion function. +func Convert_config_Plugin_To_v1beta3_Plugin(in *config.Plugin, out *v1beta3.Plugin, s conversion.Scope) error { + return autoConvert_config_Plugin_To_v1beta3_Plugin(in, out, s) +} + +func autoConvert_v1beta3_PluginConfig_To_config_PluginConfig(in *v1beta3.PluginConfig, out *config.PluginConfig, s conversion.Scope) error { + out.Name = in.Name + if err := runtime.Convert_runtime_RawExtension_To_runtime_Object(&in.Args, &out.Args, s); err != nil { + return err + } + return nil +} + +// Convert_v1beta3_PluginConfig_To_config_PluginConfig is an autogenerated conversion function. +func Convert_v1beta3_PluginConfig_To_config_PluginConfig(in *v1beta3.PluginConfig, out *config.PluginConfig, s conversion.Scope) error { + return autoConvert_v1beta3_PluginConfig_To_config_PluginConfig(in, out, s) +} + +func autoConvert_config_PluginConfig_To_v1beta3_PluginConfig(in *config.PluginConfig, out *v1beta3.PluginConfig, s conversion.Scope) error { + out.Name = in.Name + if err := runtime.Convert_runtime_Object_To_runtime_RawExtension(&in.Args, &out.Args, s); err != nil { + return err + } + return nil +} + +// Convert_config_PluginConfig_To_v1beta3_PluginConfig is an autogenerated conversion function. +func Convert_config_PluginConfig_To_v1beta3_PluginConfig(in *config.PluginConfig, out *v1beta3.PluginConfig, s conversion.Scope) error { + return autoConvert_config_PluginConfig_To_v1beta3_PluginConfig(in, out, s) +} + +func autoConvert_v1beta3_PluginSet_To_config_PluginSet(in *v1beta3.PluginSet, out *config.PluginSet, s conversion.Scope) error { + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = make([]config.Plugin, len(*in)) + for i := range *in { + if err := Convert_v1beta3_Plugin_To_config_Plugin(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Enabled = nil + } + if in.Disabled != nil { + in, out := &in.Disabled, &out.Disabled + *out = make([]config.Plugin, len(*in)) + for i := range *in { + if err := Convert_v1beta3_Plugin_To_config_Plugin(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Disabled = nil + } + return nil +} + +// Convert_v1beta3_PluginSet_To_config_PluginSet is an autogenerated conversion function. +func Convert_v1beta3_PluginSet_To_config_PluginSet(in *v1beta3.PluginSet, out *config.PluginSet, s conversion.Scope) error { + return autoConvert_v1beta3_PluginSet_To_config_PluginSet(in, out, s) +} + +func autoConvert_config_PluginSet_To_v1beta3_PluginSet(in *config.PluginSet, out *v1beta3.PluginSet, s conversion.Scope) error { + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = make([]v1beta3.Plugin, len(*in)) + for i := range *in { + if err := Convert_config_Plugin_To_v1beta3_Plugin(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Enabled = nil + } + if in.Disabled != nil { + in, out := &in.Disabled, &out.Disabled + *out = make([]v1beta3.Plugin, len(*in)) + for i := range *in { + if err := Convert_config_Plugin_To_v1beta3_Plugin(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Disabled = nil + } + return nil +} + +// Convert_config_PluginSet_To_v1beta3_PluginSet is an autogenerated conversion function. +func Convert_config_PluginSet_To_v1beta3_PluginSet(in *config.PluginSet, out *v1beta3.PluginSet, s conversion.Scope) error { + return autoConvert_config_PluginSet_To_v1beta3_PluginSet(in, out, s) +} + +func autoConvert_v1beta3_Plugins_To_config_Plugins(in *v1beta3.Plugins, out *config.Plugins, s conversion.Scope) error { + if err := Convert_v1beta3_PluginSet_To_config_PluginSet(&in.PreEnqueue, &out.PreEnqueue, s); err != nil { + return err + } + if err := Convert_v1beta3_PluginSet_To_config_PluginSet(&in.QueueSort, &out.QueueSort, s); err != nil { + return err + } + if err := Convert_v1beta3_PluginSet_To_config_PluginSet(&in.PreFilter, &out.PreFilter, s); err != nil { + return err + } + if err := Convert_v1beta3_PluginSet_To_config_PluginSet(&in.Filter, &out.Filter, s); err != nil { + return err + } + if err := Convert_v1beta3_PluginSet_To_config_PluginSet(&in.PostFilter, &out.PostFilter, s); err != nil { + return err + } + if err := Convert_v1beta3_PluginSet_To_config_PluginSet(&in.PreScore, &out.PreScore, s); err != nil { + return err + } + if err := Convert_v1beta3_PluginSet_To_config_PluginSet(&in.Score, &out.Score, s); err != nil { + return err + } + if err := Convert_v1beta3_PluginSet_To_config_PluginSet(&in.Reserve, &out.Reserve, s); err != nil { + return err + } + if err := Convert_v1beta3_PluginSet_To_config_PluginSet(&in.Permit, &out.Permit, s); err != nil { + return err + } + if err := Convert_v1beta3_PluginSet_To_config_PluginSet(&in.PreBind, &out.PreBind, s); err != nil { + return err + } + if err := Convert_v1beta3_PluginSet_To_config_PluginSet(&in.Bind, &out.Bind, s); err != nil { + return err + } + if err := Convert_v1beta3_PluginSet_To_config_PluginSet(&in.PostBind, &out.PostBind, s); err != nil { + return err + } + if err := Convert_v1beta3_PluginSet_To_config_PluginSet(&in.MultiPoint, &out.MultiPoint, s); err != nil { + return err + } + return nil +} + +// Convert_v1beta3_Plugins_To_config_Plugins is an autogenerated conversion function. +func Convert_v1beta3_Plugins_To_config_Plugins(in *v1beta3.Plugins, out *config.Plugins, s conversion.Scope) error { + return autoConvert_v1beta3_Plugins_To_config_Plugins(in, out, s) +} + +func autoConvert_config_Plugins_To_v1beta3_Plugins(in *config.Plugins, out *v1beta3.Plugins, s conversion.Scope) error { + if err := Convert_config_PluginSet_To_v1beta3_PluginSet(&in.PreEnqueue, &out.PreEnqueue, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta3_PluginSet(&in.QueueSort, &out.QueueSort, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta3_PluginSet(&in.PreFilter, &out.PreFilter, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta3_PluginSet(&in.Filter, &out.Filter, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta3_PluginSet(&in.PostFilter, &out.PostFilter, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta3_PluginSet(&in.PreScore, &out.PreScore, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta3_PluginSet(&in.Score, &out.Score, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta3_PluginSet(&in.Reserve, &out.Reserve, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta3_PluginSet(&in.Permit, &out.Permit, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta3_PluginSet(&in.PreBind, &out.PreBind, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta3_PluginSet(&in.Bind, &out.Bind, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta3_PluginSet(&in.PostBind, &out.PostBind, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1beta3_PluginSet(&in.MultiPoint, &out.MultiPoint, s); err != nil { + return err + } + return nil +} + +func autoConvert_v1beta3_PodTopologySpreadArgs_To_config_PodTopologySpreadArgs(in *v1beta3.PodTopologySpreadArgs, out *config.PodTopologySpreadArgs, s conversion.Scope) error { + out.DefaultConstraints = *(*[]corev1.TopologySpreadConstraint)(unsafe.Pointer(&in.DefaultConstraints)) + out.DefaultingType = config.PodTopologySpreadConstraintsDefaulting(in.DefaultingType) + return nil +} + +// Convert_v1beta3_PodTopologySpreadArgs_To_config_PodTopologySpreadArgs is an autogenerated conversion function. +func Convert_v1beta3_PodTopologySpreadArgs_To_config_PodTopologySpreadArgs(in *v1beta3.PodTopologySpreadArgs, out *config.PodTopologySpreadArgs, s conversion.Scope) error { + return autoConvert_v1beta3_PodTopologySpreadArgs_To_config_PodTopologySpreadArgs(in, out, s) +} + +func autoConvert_config_PodTopologySpreadArgs_To_v1beta3_PodTopologySpreadArgs(in *config.PodTopologySpreadArgs, out *v1beta3.PodTopologySpreadArgs, s conversion.Scope) error { + out.DefaultConstraints = *(*[]corev1.TopologySpreadConstraint)(unsafe.Pointer(&in.DefaultConstraints)) + out.DefaultingType = v1beta3.PodTopologySpreadConstraintsDefaulting(in.DefaultingType) + return nil +} + +// Convert_config_PodTopologySpreadArgs_To_v1beta3_PodTopologySpreadArgs is an autogenerated conversion function. +func Convert_config_PodTopologySpreadArgs_To_v1beta3_PodTopologySpreadArgs(in *config.PodTopologySpreadArgs, out *v1beta3.PodTopologySpreadArgs, s conversion.Scope) error { + return autoConvert_config_PodTopologySpreadArgs_To_v1beta3_PodTopologySpreadArgs(in, out, s) +} + +func autoConvert_v1beta3_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(in *v1beta3.RequestedToCapacityRatioParam, out *config.RequestedToCapacityRatioParam, s conversion.Scope) error { + out.Shape = *(*[]config.UtilizationShapePoint)(unsafe.Pointer(&in.Shape)) + return nil +} + +// Convert_v1beta3_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam is an autogenerated conversion function. +func Convert_v1beta3_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(in *v1beta3.RequestedToCapacityRatioParam, out *config.RequestedToCapacityRatioParam, s conversion.Scope) error { + return autoConvert_v1beta3_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(in, out, s) +} + +func autoConvert_config_RequestedToCapacityRatioParam_To_v1beta3_RequestedToCapacityRatioParam(in *config.RequestedToCapacityRatioParam, out *v1beta3.RequestedToCapacityRatioParam, s conversion.Scope) error { + out.Shape = *(*[]v1beta3.UtilizationShapePoint)(unsafe.Pointer(&in.Shape)) + return nil +} + +// Convert_config_RequestedToCapacityRatioParam_To_v1beta3_RequestedToCapacityRatioParam is an autogenerated conversion function. +func Convert_config_RequestedToCapacityRatioParam_To_v1beta3_RequestedToCapacityRatioParam(in *config.RequestedToCapacityRatioParam, out *v1beta3.RequestedToCapacityRatioParam, s conversion.Scope) error { + return autoConvert_config_RequestedToCapacityRatioParam_To_v1beta3_RequestedToCapacityRatioParam(in, out, s) +} + +func autoConvert_v1beta3_ResourceSpec_To_config_ResourceSpec(in *v1beta3.ResourceSpec, out *config.ResourceSpec, s conversion.Scope) error { + out.Name = in.Name + out.Weight = in.Weight + return nil +} + +// Convert_v1beta3_ResourceSpec_To_config_ResourceSpec is an autogenerated conversion function. +func Convert_v1beta3_ResourceSpec_To_config_ResourceSpec(in *v1beta3.ResourceSpec, out *config.ResourceSpec, s conversion.Scope) error { + return autoConvert_v1beta3_ResourceSpec_To_config_ResourceSpec(in, out, s) +} + +func autoConvert_config_ResourceSpec_To_v1beta3_ResourceSpec(in *config.ResourceSpec, out *v1beta3.ResourceSpec, s conversion.Scope) error { + out.Name = in.Name + out.Weight = in.Weight + return nil +} + +// Convert_config_ResourceSpec_To_v1beta3_ResourceSpec is an autogenerated conversion function. +func Convert_config_ResourceSpec_To_v1beta3_ResourceSpec(in *config.ResourceSpec, out *v1beta3.ResourceSpec, s conversion.Scope) error { + return autoConvert_config_ResourceSpec_To_v1beta3_ResourceSpec(in, out, s) +} + +func autoConvert_v1beta3_ScoringStrategy_To_config_ScoringStrategy(in *v1beta3.ScoringStrategy, out *config.ScoringStrategy, s conversion.Scope) error { + out.Type = config.ScoringStrategyType(in.Type) + out.Resources = *(*[]config.ResourceSpec)(unsafe.Pointer(&in.Resources)) + out.RequestedToCapacityRatio = (*config.RequestedToCapacityRatioParam)(unsafe.Pointer(in.RequestedToCapacityRatio)) + return nil +} + +// Convert_v1beta3_ScoringStrategy_To_config_ScoringStrategy is an autogenerated conversion function. +func Convert_v1beta3_ScoringStrategy_To_config_ScoringStrategy(in *v1beta3.ScoringStrategy, out *config.ScoringStrategy, s conversion.Scope) error { + return autoConvert_v1beta3_ScoringStrategy_To_config_ScoringStrategy(in, out, s) +} + +func autoConvert_config_ScoringStrategy_To_v1beta3_ScoringStrategy(in *config.ScoringStrategy, out *v1beta3.ScoringStrategy, s conversion.Scope) error { + out.Type = v1beta3.ScoringStrategyType(in.Type) + out.Resources = *(*[]v1beta3.ResourceSpec)(unsafe.Pointer(&in.Resources)) + out.RequestedToCapacityRatio = (*v1beta3.RequestedToCapacityRatioParam)(unsafe.Pointer(in.RequestedToCapacityRatio)) + return nil +} + +// Convert_config_ScoringStrategy_To_v1beta3_ScoringStrategy is an autogenerated conversion function. +func Convert_config_ScoringStrategy_To_v1beta3_ScoringStrategy(in *config.ScoringStrategy, out *v1beta3.ScoringStrategy, s conversion.Scope) error { + return autoConvert_config_ScoringStrategy_To_v1beta3_ScoringStrategy(in, out, s) +} + +func autoConvert_v1beta3_UtilizationShapePoint_To_config_UtilizationShapePoint(in *v1beta3.UtilizationShapePoint, out *config.UtilizationShapePoint, s conversion.Scope) error { + out.Utilization = in.Utilization + out.Score = in.Score + return nil +} + +// Convert_v1beta3_UtilizationShapePoint_To_config_UtilizationShapePoint is an autogenerated conversion function. +func Convert_v1beta3_UtilizationShapePoint_To_config_UtilizationShapePoint(in *v1beta3.UtilizationShapePoint, out *config.UtilizationShapePoint, s conversion.Scope) error { + return autoConvert_v1beta3_UtilizationShapePoint_To_config_UtilizationShapePoint(in, out, s) +} + +func autoConvert_config_UtilizationShapePoint_To_v1beta3_UtilizationShapePoint(in *config.UtilizationShapePoint, out *v1beta3.UtilizationShapePoint, s conversion.Scope) error { + out.Utilization = in.Utilization + out.Score = in.Score + return nil +} + +// Convert_config_UtilizationShapePoint_To_v1beta3_UtilizationShapePoint is an autogenerated conversion function. +func Convert_config_UtilizationShapePoint_To_v1beta3_UtilizationShapePoint(in *config.UtilizationShapePoint, out *v1beta3.UtilizationShapePoint, s conversion.Scope) error { + return autoConvert_config_UtilizationShapePoint_To_v1beta3_UtilizationShapePoint(in, out, s) +} + +func autoConvert_v1beta3_VolumeBindingArgs_To_config_VolumeBindingArgs(in *v1beta3.VolumeBindingArgs, out *config.VolumeBindingArgs, s conversion.Scope) error { + if err := v1.Convert_Pointer_int64_To_int64(&in.BindTimeoutSeconds, &out.BindTimeoutSeconds, s); err != nil { + return err + } + out.Shape = *(*[]config.UtilizationShapePoint)(unsafe.Pointer(&in.Shape)) + return nil +} + +// Convert_v1beta3_VolumeBindingArgs_To_config_VolumeBindingArgs is an autogenerated conversion function. +func Convert_v1beta3_VolumeBindingArgs_To_config_VolumeBindingArgs(in *v1beta3.VolumeBindingArgs, out *config.VolumeBindingArgs, s conversion.Scope) error { + return autoConvert_v1beta3_VolumeBindingArgs_To_config_VolumeBindingArgs(in, out, s) +} + +func autoConvert_config_VolumeBindingArgs_To_v1beta3_VolumeBindingArgs(in *config.VolumeBindingArgs, out *v1beta3.VolumeBindingArgs, s conversion.Scope) error { + if err := v1.Convert_int64_To_Pointer_int64(&in.BindTimeoutSeconds, &out.BindTimeoutSeconds, s); err != nil { + return err + } + out.Shape = *(*[]v1beta3.UtilizationShapePoint)(unsafe.Pointer(&in.Shape)) + return nil +} + +// Convert_config_VolumeBindingArgs_To_v1beta3_VolumeBindingArgs is an autogenerated conversion function. +func Convert_config_VolumeBindingArgs_To_v1beta3_VolumeBindingArgs(in *config.VolumeBindingArgs, out *v1beta3.VolumeBindingArgs, s conversion.Scope) error { + return autoConvert_config_VolumeBindingArgs_To_v1beta3_VolumeBindingArgs(in, out, s) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/zz_generated.deepcopy.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/zz_generated.deepcopy.go new file mode 100644 index 000000000..e735e37db --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/zz_generated.deepcopy.go @@ -0,0 +1,22 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1beta3 diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/zz_generated.defaults.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/zz_generated.defaults.go new file mode 100644 index 000000000..3c28679f6 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3/zz_generated.defaults.go @@ -0,0 +1,73 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1beta3 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" + v1beta3 "k8s.io/kube-scheduler/config/v1beta3" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + scheme.AddTypeDefaultingFunc(&v1beta3.DefaultPreemptionArgs{}, func(obj interface{}) { SetObjectDefaults_DefaultPreemptionArgs(obj.(*v1beta3.DefaultPreemptionArgs)) }) + scheme.AddTypeDefaultingFunc(&v1beta3.InterPodAffinityArgs{}, func(obj interface{}) { SetObjectDefaults_InterPodAffinityArgs(obj.(*v1beta3.InterPodAffinityArgs)) }) + scheme.AddTypeDefaultingFunc(&v1beta3.KubeSchedulerConfiguration{}, func(obj interface{}) { + SetObjectDefaults_KubeSchedulerConfiguration(obj.(*v1beta3.KubeSchedulerConfiguration)) + }) + scheme.AddTypeDefaultingFunc(&v1beta3.NodeResourcesBalancedAllocationArgs{}, func(obj interface{}) { + SetObjectDefaults_NodeResourcesBalancedAllocationArgs(obj.(*v1beta3.NodeResourcesBalancedAllocationArgs)) + }) + scheme.AddTypeDefaultingFunc(&v1beta3.NodeResourcesFitArgs{}, func(obj interface{}) { SetObjectDefaults_NodeResourcesFitArgs(obj.(*v1beta3.NodeResourcesFitArgs)) }) + scheme.AddTypeDefaultingFunc(&v1beta3.PodTopologySpreadArgs{}, func(obj interface{}) { SetObjectDefaults_PodTopologySpreadArgs(obj.(*v1beta3.PodTopologySpreadArgs)) }) + scheme.AddTypeDefaultingFunc(&v1beta3.VolumeBindingArgs{}, func(obj interface{}) { SetObjectDefaults_VolumeBindingArgs(obj.(*v1beta3.VolumeBindingArgs)) }) + return nil +} + +func SetObjectDefaults_DefaultPreemptionArgs(in *v1beta3.DefaultPreemptionArgs) { + SetDefaults_DefaultPreemptionArgs(in) +} + +func SetObjectDefaults_InterPodAffinityArgs(in *v1beta3.InterPodAffinityArgs) { + SetDefaults_InterPodAffinityArgs(in) +} + +func SetObjectDefaults_KubeSchedulerConfiguration(in *v1beta3.KubeSchedulerConfiguration) { + SetDefaults_KubeSchedulerConfiguration(in) +} + +func SetObjectDefaults_NodeResourcesBalancedAllocationArgs(in *v1beta3.NodeResourcesBalancedAllocationArgs) { + SetDefaults_NodeResourcesBalancedAllocationArgs(in) +} + +func SetObjectDefaults_NodeResourcesFitArgs(in *v1beta3.NodeResourcesFitArgs) { + SetDefaults_NodeResourcesFitArgs(in) +} + +func SetObjectDefaults_PodTopologySpreadArgs(in *v1beta3.PodTopologySpreadArgs) { + SetDefaults_PodTopologySpreadArgs(in) +} + +func SetObjectDefaults_VolumeBindingArgs(in *v1beta3.VolumeBindingArgs) { + SetDefaults_VolumeBindingArgs(in) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/validation/validation.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/validation/validation.go new file mode 100644 index 000000000..1dcfc699e --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/validation/validation.go @@ -0,0 +1,334 @@ +/* +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 validation + +import ( + "fmt" + "net" + "reflect" + "strconv" + "strings" + + "github.com/google/go-cmp/cmp" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/validation" + "k8s.io/apimachinery/pkg/util/validation/field" + componentbasevalidation "k8s.io/component-base/config/validation" + v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" + "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2" + "k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3" +) + +// ValidateKubeSchedulerConfiguration ensures validation of the KubeSchedulerConfiguration struct +func ValidateKubeSchedulerConfiguration(cc *config.KubeSchedulerConfiguration) utilerrors.Aggregate { + var errs []error + errs = append(errs, componentbasevalidation.ValidateClientConnectionConfiguration(&cc.ClientConnection, field.NewPath("clientConnection")).ToAggregate()) + errs = append(errs, componentbasevalidation.ValidateLeaderElectionConfiguration(&cc.LeaderElection, field.NewPath("leaderElection")).ToAggregate()) + profilesPath := field.NewPath("profiles") + if cc.Parallelism <= 0 { + errs = append(errs, field.Invalid(field.NewPath("parallelism"), cc.Parallelism, "should be an integer value greater than zero")) + } + + if len(cc.Profiles) == 0 { + errs = append(errs, field.Required(profilesPath, "")) + } else { + existingProfiles := make(map[string]int, len(cc.Profiles)) + for i := range cc.Profiles { + profile := &cc.Profiles[i] + path := profilesPath.Index(i) + errs = append(errs, validateKubeSchedulerProfile(path, cc.APIVersion, profile)...) + if idx, ok := existingProfiles[profile.SchedulerName]; ok { + errs = append(errs, field.Duplicate(path.Child("schedulerName"), profilesPath.Index(idx).Child("schedulerName"))) + } + existingProfiles[profile.SchedulerName] = i + } + errs = append(errs, validateCommonQueueSort(profilesPath, cc.Profiles)...) + } + if len(cc.HealthzBindAddress) > 0 { + host, port, err := splitHostIntPort(cc.HealthzBindAddress) + if err != nil { + errs = append(errs, field.Invalid(field.NewPath("healthzBindAddress"), cc.HealthzBindAddress, err.Error())) + } else { + if errMsgs := validation.IsValidIP(host); errMsgs != nil { + errs = append(errs, field.Invalid(field.NewPath("healthzBindAddress"), cc.HealthzBindAddress, strings.Join(errMsgs, ","))) + } + if port != 0 { + errs = append(errs, field.Invalid(field.NewPath("healthzBindAddress"), cc.HealthzBindAddress, "must be empty or with an explicit 0 port")) + } + } + } + if len(cc.MetricsBindAddress) > 0 { + host, port, err := splitHostIntPort(cc.MetricsBindAddress) + if err != nil { + errs = append(errs, field.Invalid(field.NewPath("metricsBindAddress"), cc.MetricsBindAddress, err.Error())) + } else { + if errMsgs := validation.IsValidIP(host); errMsgs != nil { + errs = append(errs, field.Invalid(field.NewPath("metricsBindAddress"), cc.MetricsBindAddress, strings.Join(errMsgs, ","))) + } + if port != 0 { + errs = append(errs, field.Invalid(field.NewPath("metricsBindAddress"), cc.MetricsBindAddress, "must be empty or with an explicit 0 port")) + } + } + } + + errs = append(errs, validatePercentageOfNodesToScore(field.NewPath("percentageOfNodesToScore"), cc.PercentageOfNodesToScore)) + + if cc.PodInitialBackoffSeconds <= 0 { + errs = append(errs, field.Invalid(field.NewPath("podInitialBackoffSeconds"), + cc.PodInitialBackoffSeconds, "must be greater than 0")) + } + if cc.PodMaxBackoffSeconds < cc.PodInitialBackoffSeconds { + errs = append(errs, field.Invalid(field.NewPath("podMaxBackoffSeconds"), + cc.PodMaxBackoffSeconds, "must be greater than or equal to PodInitialBackoffSeconds")) + } + + errs = append(errs, validateExtenders(field.NewPath("extenders"), cc.Extenders)...) + return utilerrors.Flatten(utilerrors.NewAggregate(errs)) +} + +func splitHostIntPort(s string) (string, int, error) { + host, port, err := net.SplitHostPort(s) + if err != nil { + return "", 0, err + } + portInt, err := strconv.Atoi(port) + if err != nil { + return "", 0, err + } + return host, portInt, err +} + +func validatePercentageOfNodesToScore(path *field.Path, percentageOfNodesToScore *int32) error { + if percentageOfNodesToScore != nil { + if *percentageOfNodesToScore < 0 || *percentageOfNodesToScore > 100 { + return field.Invalid(path, *percentageOfNodesToScore, "not in valid range [0-100]") + } + } + return nil +} + +type invalidPlugins struct { + schemeGroupVersion string + plugins []string +} + +// invalidPluginsByVersion maintains a list of removed/deprecated plugins in each version. +// Remember to add an entry to that list when creating a new component config +// version (even if the list of invalid plugins is empty). +var invalidPluginsByVersion = []invalidPlugins{ + { + schemeGroupVersion: v1beta2.SchemeGroupVersion.String(), + plugins: []string{}, + }, + { + schemeGroupVersion: v1beta3.SchemeGroupVersion.String(), + plugins: []string{}, + }, + { + schemeGroupVersion: v1.SchemeGroupVersion.String(), + plugins: []string{"SelectorSpread"}, + }, +} + +// isPluginInvalid checks if a given plugin was removed/deprecated in the given component +// config version or earlier. +func isPluginInvalid(apiVersion string, name string) (bool, string) { + for _, dp := range invalidPluginsByVersion { + for _, plugin := range dp.plugins { + if name == plugin { + return true, dp.schemeGroupVersion + } + } + if apiVersion == dp.schemeGroupVersion { + break + } + } + return false, "" +} + +func validatePluginSetForInvalidPlugins(path *field.Path, apiVersion string, ps config.PluginSet) []error { + var errs []error + for i, plugin := range ps.Enabled { + if invalid, invalidVersion := isPluginInvalid(apiVersion, plugin.Name); invalid { + errs = append(errs, field.Invalid(path.Child("enabled").Index(i), plugin.Name, fmt.Sprintf("was invalid in version %q (KubeSchedulerConfiguration is version %q)", invalidVersion, apiVersion))) + } + } + return errs +} + +func validateKubeSchedulerProfile(path *field.Path, apiVersion string, profile *config.KubeSchedulerProfile) []error { + var errs []error + if len(profile.SchedulerName) == 0 { + errs = append(errs, field.Required(path.Child("schedulerName"), "")) + } + errs = append(errs, validatePercentageOfNodesToScore(path.Child("percentageOfNodesToScore"), profile.PercentageOfNodesToScore)) + errs = append(errs, validatePluginConfig(path, apiVersion, profile)...) + return errs +} + +func validatePluginConfig(path *field.Path, apiVersion string, profile *config.KubeSchedulerProfile) []error { + var errs []error + m := map[string]interface{}{ + "DefaultPreemption": ValidateDefaultPreemptionArgs, + "InterPodAffinity": ValidateInterPodAffinityArgs, + "NodeAffinity": ValidateNodeAffinityArgs, + "NodeResourcesBalancedAllocation": ValidateNodeResourcesBalancedAllocationArgs, + "NodeResourcesFitArgs": ValidateNodeResourcesFitArgs, + "PodTopologySpread": ValidatePodTopologySpreadArgs, + "VolumeBinding": ValidateVolumeBindingArgs, + } + + if profile.Plugins != nil { + stagesToPluginSet := map[string]config.PluginSet{ + "preEnqueue": profile.Plugins.PreEnqueue, + "queueSort": profile.Plugins.QueueSort, + "preFilter": profile.Plugins.PreFilter, + "filter": profile.Plugins.Filter, + "postFilter": profile.Plugins.PostFilter, + "preScore": profile.Plugins.PreScore, + "score": profile.Plugins.Score, + "reserve": profile.Plugins.Reserve, + "permit": profile.Plugins.Permit, + "preBind": profile.Plugins.PreBind, + "bind": profile.Plugins.Bind, + "postBind": profile.Plugins.PostBind, + } + + pluginsPath := path.Child("plugins") + for s, p := range stagesToPluginSet { + errs = append(errs, validatePluginSetForInvalidPlugins( + pluginsPath.Child(s), apiVersion, p)...) + } + } + + seenPluginConfig := make(sets.String) + + for i := range profile.PluginConfig { + pluginConfigPath := path.Child("pluginConfig").Index(i) + name := profile.PluginConfig[i].Name + args := profile.PluginConfig[i].Args + if seenPluginConfig.Has(name) { + errs = append(errs, field.Duplicate(pluginConfigPath, name)) + } else { + seenPluginConfig.Insert(name) + } + if invalid, invalidVersion := isPluginInvalid(apiVersion, name); invalid { + errs = append(errs, field.Invalid(pluginConfigPath, name, fmt.Sprintf("was invalid in version %q (KubeSchedulerConfiguration is version %q)", invalidVersion, apiVersion))) + } else if validateFunc, ok := m[name]; ok { + // type mismatch, no need to validate the `args`. + if reflect.TypeOf(args) != reflect.ValueOf(validateFunc).Type().In(1) { + errs = append(errs, field.Invalid(pluginConfigPath.Child("args"), args, "has to match plugin args")) + } else { + in := []reflect.Value{reflect.ValueOf(pluginConfigPath.Child("args")), reflect.ValueOf(args)} + res := reflect.ValueOf(validateFunc).Call(in) + // It's possible that validation function return a Aggregate, just append here and it will be flattened at the end of CC validation. + if res[0].Interface() != nil { + errs = append(errs, res[0].Interface().(error)) + } + } + } + } + return errs +} + +func validateCommonQueueSort(path *field.Path, profiles []config.KubeSchedulerProfile) []error { + var errs []error + var canon config.PluginSet + var queueSortName string + var queueSortArgs runtime.Object + if profiles[0].Plugins != nil { + canon = profiles[0].Plugins.QueueSort + if len(profiles[0].Plugins.QueueSort.Enabled) != 0 { + queueSortName = profiles[0].Plugins.QueueSort.Enabled[0].Name + } + length := len(profiles[0].Plugins.QueueSort.Enabled) + if length > 1 { + errs = append(errs, field.Invalid(path.Index(0).Child("plugins", "queueSort", "Enabled"), length, "only one queue sort plugin can be enabled")) + } + } + for _, cfg := range profiles[0].PluginConfig { + if len(queueSortName) > 0 && cfg.Name == queueSortName { + queueSortArgs = cfg.Args + } + } + for i := 1; i < len(profiles); i++ { + var curr config.PluginSet + if profiles[i].Plugins != nil { + curr = profiles[i].Plugins.QueueSort + } + if !cmp.Equal(canon, curr) { + errs = append(errs, field.Invalid(path.Index(i).Child("plugins", "queueSort"), curr, "has to match for all profiles")) + } + for _, cfg := range profiles[i].PluginConfig { + if cfg.Name == queueSortName && !cmp.Equal(queueSortArgs, cfg.Args) { + errs = append(errs, field.Invalid(path.Index(i).Child("pluginConfig", "args"), cfg.Args, "has to match for all profiles")) + } + } + } + return errs +} + +// validateExtenders validates the configured extenders for the Scheduler +func validateExtenders(fldPath *field.Path, extenders []config.Extender) []error { + var errs []error + binders := 0 + extenderManagedResources := sets.NewString() + for i, extender := range extenders { + path := fldPath.Index(i) + if len(extender.PrioritizeVerb) > 0 && extender.Weight <= 0 { + errs = append(errs, field.Invalid(path.Child("weight"), + extender.Weight, "must have a positive weight applied to it")) + } + if extender.BindVerb != "" { + binders++ + } + for j, resource := range extender.ManagedResources { + managedResourcesPath := path.Child("managedResources").Index(j) + validationErrors := validateExtendedResourceName(managedResourcesPath.Child("name"), v1.ResourceName(resource.Name)) + errs = append(errs, validationErrors...) + if extenderManagedResources.Has(resource.Name) { + errs = append(errs, field.Invalid(managedResourcesPath.Child("name"), + resource.Name, "duplicate extender managed resource name")) + } + extenderManagedResources.Insert(resource.Name) + } + } + if binders > 1 { + errs = append(errs, field.Invalid(fldPath, fmt.Sprintf("found %d extenders implementing bind", binders), "only one extender can implement bind")) + } + return errs +} + +// validateExtendedResourceName checks whether the specified name is a valid +// extended resource name. +func validateExtendedResourceName(path *field.Path, name v1.ResourceName) []error { + var validationErrors []error + for _, msg := range validation.IsQualifiedName(string(name)) { + validationErrors = append(validationErrors, field.Invalid(path, name, msg)) + } + if len(validationErrors) != 0 { + return validationErrors + } + if !v1helper.IsExtendedResourceName(name) { + validationErrors = append(validationErrors, field.Invalid(path, string(name), "is an invalid extended resource name")) + } + return validationErrors +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/validation/validation_pluginargs.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/validation/validation_pluginargs.go new file mode 100644 index 000000000..325a6bc67 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/validation/validation_pluginargs.go @@ -0,0 +1,328 @@ +/* +Copyright 2020 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 validation + +import ( + "fmt" + "strings" + + v1 "k8s.io/api/core/v1" + metav1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation" + "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/validation/field" + utilfeature "k8s.io/apiserver/pkg/util/feature" + "k8s.io/component-helpers/scheduling/corev1/nodeaffinity" + "k8s.io/kubernetes/pkg/features" + "k8s.io/kubernetes/pkg/scheduler/apis/config" +) + +var supportedScoringStrategyTypes = sets.NewString( + string(config.LeastAllocated), + string(config.MostAllocated), + string(config.RequestedToCapacityRatio), +) + +// ValidateDefaultPreemptionArgs validates that DefaultPreemptionArgs are correct. +func ValidateDefaultPreemptionArgs(path *field.Path, args *config.DefaultPreemptionArgs) error { + var allErrs field.ErrorList + percentagePath := path.Child("minCandidateNodesPercentage") + absolutePath := path.Child("minCandidateNodesAbsolute") + if err := validateMinCandidateNodesPercentage(args.MinCandidateNodesPercentage, percentagePath); err != nil { + allErrs = append(allErrs, err) + } + if err := validateMinCandidateNodesAbsolute(args.MinCandidateNodesAbsolute, absolutePath); err != nil { + allErrs = append(allErrs, err) + } + if args.MinCandidateNodesPercentage == 0 && args.MinCandidateNodesAbsolute == 0 { + allErrs = append(allErrs, + field.Invalid(percentagePath, args.MinCandidateNodesPercentage, "cannot be zero at the same time as minCandidateNodesAbsolute"), + field.Invalid(absolutePath, args.MinCandidateNodesAbsolute, "cannot be zero at the same time as minCandidateNodesPercentage")) + } + return allErrs.ToAggregate() +} + +// validateMinCandidateNodesPercentage validates that +// minCandidateNodesPercentage is within the allowed range. +func validateMinCandidateNodesPercentage(minCandidateNodesPercentage int32, p *field.Path) *field.Error { + if minCandidateNodesPercentage < 0 || minCandidateNodesPercentage > 100 { + return field.Invalid(p, minCandidateNodesPercentage, "not in valid range [0, 100]") + } + return nil +} + +// validateMinCandidateNodesAbsolute validates that minCandidateNodesAbsolute +// is within the allowed range. +func validateMinCandidateNodesAbsolute(minCandidateNodesAbsolute int32, p *field.Path) *field.Error { + if minCandidateNodesAbsolute < 0 { + return field.Invalid(p, minCandidateNodesAbsolute, "not in valid range [0, inf)") + } + return nil +} + +// ValidateInterPodAffinityArgs validates that InterPodAffinityArgs are correct. +func ValidateInterPodAffinityArgs(path *field.Path, args *config.InterPodAffinityArgs) error { + return validateHardPodAffinityWeight(path.Child("hardPodAffinityWeight"), args.HardPodAffinityWeight) +} + +// validateHardPodAffinityWeight validates that weight is within allowed range. +func validateHardPodAffinityWeight(path *field.Path, w int32) error { + const ( + minHardPodAffinityWeight = 0 + maxHardPodAffinityWeight = 100 + ) + + if w < minHardPodAffinityWeight || w > maxHardPodAffinityWeight { + msg := fmt.Sprintf("not in valid range [%d, %d]", minHardPodAffinityWeight, maxHardPodAffinityWeight) + return field.Invalid(path, w, msg) + } + return nil +} + +// ValidatePodTopologySpreadArgs validates that PodTopologySpreadArgs are correct. +// It replicates the validation from pkg/apis/core/validation.validateTopologySpreadConstraints +// with an additional check for .labelSelector to be nil. +func ValidatePodTopologySpreadArgs(path *field.Path, args *config.PodTopologySpreadArgs) error { + var allErrs field.ErrorList + if err := validateDefaultingType(path.Child("defaultingType"), args.DefaultingType, args.DefaultConstraints); err != nil { + allErrs = append(allErrs, err) + } + + defaultConstraintsPath := path.Child("defaultConstraints") + for i, c := range args.DefaultConstraints { + p := defaultConstraintsPath.Index(i) + if c.MaxSkew <= 0 { + f := p.Child("maxSkew") + allErrs = append(allErrs, field.Invalid(f, c.MaxSkew, "not in valid range (0, inf)")) + } + allErrs = append(allErrs, validateTopologyKey(p.Child("topologyKey"), c.TopologyKey)...) + if err := validateWhenUnsatisfiable(p.Child("whenUnsatisfiable"), c.WhenUnsatisfiable); err != nil { + allErrs = append(allErrs, err) + } + if c.LabelSelector != nil { + f := field.Forbidden(p.Child("labelSelector"), "constraint must not define a selector, as they deduced for each pod") + allErrs = append(allErrs, f) + } + if err := validateConstraintNotRepeat(defaultConstraintsPath, args.DefaultConstraints, i); err != nil { + allErrs = append(allErrs, err) + } + } + if len(allErrs) == 0 { + return nil + } + return allErrs.ToAggregate() +} + +func validateDefaultingType(p *field.Path, v config.PodTopologySpreadConstraintsDefaulting, constraints []v1.TopologySpreadConstraint) *field.Error { + if v != config.SystemDefaulting && v != config.ListDefaulting { + return field.NotSupported(p, v, []string{string(config.SystemDefaulting), string(config.ListDefaulting)}) + } + if v == config.SystemDefaulting && len(constraints) > 0 { + return field.Invalid(p, v, "when .defaultConstraints are not empty") + } + return nil +} + +func validateTopologyKey(p *field.Path, v string) field.ErrorList { + var allErrs field.ErrorList + if len(v) == 0 { + allErrs = append(allErrs, field.Required(p, "can not be empty")) + } else { + allErrs = append(allErrs, metav1validation.ValidateLabelName(v, p)...) + } + return allErrs +} + +func validateWhenUnsatisfiable(p *field.Path, v v1.UnsatisfiableConstraintAction) *field.Error { + supportedScheduleActions := sets.NewString(string(v1.DoNotSchedule), string(v1.ScheduleAnyway)) + + if len(v) == 0 { + return field.Required(p, "can not be empty") + } + if !supportedScheduleActions.Has(string(v)) { + return field.NotSupported(p, v, supportedScheduleActions.List()) + } + return nil +} + +func validateConstraintNotRepeat(path *field.Path, constraints []v1.TopologySpreadConstraint, idx int) *field.Error { + c := &constraints[idx] + for i := range constraints[:idx] { + other := &constraints[i] + if c.TopologyKey == other.TopologyKey && c.WhenUnsatisfiable == other.WhenUnsatisfiable { + return field.Duplicate(path.Index(idx), fmt.Sprintf("{%v, %v}", c.TopologyKey, c.WhenUnsatisfiable)) + } + } + return nil +} + +func validateFunctionShape(shape []config.UtilizationShapePoint, path *field.Path) field.ErrorList { + const ( + minUtilization = 0 + maxUtilization = 100 + minScore = 0 + maxScore = int32(config.MaxCustomPriorityScore) + ) + + var allErrs field.ErrorList + + if len(shape) == 0 { + allErrs = append(allErrs, field.Required(path, "at least one point must be specified")) + return allErrs + } + + for i := 1; i < len(shape); i++ { + if shape[i-1].Utilization >= shape[i].Utilization { + allErrs = append(allErrs, field.Invalid(path.Index(i).Child("utilization"), shape[i].Utilization, "utilization values must be sorted in increasing order")) + break + } + } + + for i, point := range shape { + if point.Utilization < minUtilization || point.Utilization > maxUtilization { + msg := fmt.Sprintf("not in valid range [%d, %d]", minUtilization, maxUtilization) + allErrs = append(allErrs, field.Invalid(path.Index(i).Child("utilization"), point.Utilization, msg)) + } + + if point.Score < minScore || point.Score > maxScore { + msg := fmt.Sprintf("not in valid range [%d, %d]", minScore, maxScore) + allErrs = append(allErrs, field.Invalid(path.Index(i).Child("score"), point.Score, msg)) + } + } + + return allErrs +} + +func validateResources(resources []config.ResourceSpec, p *field.Path) field.ErrorList { + var allErrs field.ErrorList + for i, resource := range resources { + if resource.Weight <= 0 || resource.Weight > 100 { + msg := fmt.Sprintf("resource weight of %v not in valid range (0, 100]", resource.Name) + allErrs = append(allErrs, field.Invalid(p.Index(i).Child("weight"), resource.Weight, msg)) + } + } + return allErrs +} + +// ValidateNodeResourcesBalancedAllocationArgs validates that NodeResourcesBalancedAllocationArgs are set correctly. +func ValidateNodeResourcesBalancedAllocationArgs(path *field.Path, args *config.NodeResourcesBalancedAllocationArgs) error { + var allErrs field.ErrorList + seenResources := sets.NewString() + for i, resource := range args.Resources { + if seenResources.Has(resource.Name) { + allErrs = append(allErrs, field.Duplicate(path.Child("resources").Index(i).Child("name"), resource.Name)) + } else { + seenResources.Insert(resource.Name) + } + if resource.Weight != 1 { + allErrs = append(allErrs, field.Invalid(path.Child("resources").Index(i).Child("weight"), resource.Weight, "must be 1")) + } + } + return allErrs.ToAggregate() +} + +// ValidateNodeAffinityArgs validates that NodeAffinityArgs are correct. +func ValidateNodeAffinityArgs(path *field.Path, args *config.NodeAffinityArgs) error { + if args.AddedAffinity == nil { + return nil + } + affinity := args.AddedAffinity + var errs []error + if ns := affinity.RequiredDuringSchedulingIgnoredDuringExecution; ns != nil { + _, err := nodeaffinity.NewNodeSelector(ns, field.WithPath(path.Child("addedAffinity", "requiredDuringSchedulingIgnoredDuringExecution"))) + if err != nil { + errs = append(errs, err) + } + } + // TODO: Add validation for requiredDuringSchedulingRequiredDuringExecution when it gets added to the API. + if terms := affinity.PreferredDuringSchedulingIgnoredDuringExecution; len(terms) != 0 { + _, err := nodeaffinity.NewPreferredSchedulingTerms(terms, field.WithPath(path.Child("addedAffinity", "preferredDuringSchedulingIgnoredDuringExecution"))) + if err != nil { + errs = append(errs, err) + } + } + return errors.Flatten(errors.NewAggregate(errs)) +} + +// VolumeBindingArgsValidationOptions contains the different settings for validation. +type VolumeBindingArgsValidationOptions struct { + AllowVolumeCapacityPriority bool +} + +// ValidateVolumeBindingArgs validates that VolumeBindingArgs are set correctly. +func ValidateVolumeBindingArgs(path *field.Path, args *config.VolumeBindingArgs) error { + return ValidateVolumeBindingArgsWithOptions(path, args, VolumeBindingArgsValidationOptions{ + AllowVolumeCapacityPriority: utilfeature.DefaultFeatureGate.Enabled(features.VolumeCapacityPriority), + }) +} + +// ValidateVolumeBindingArgs validates that VolumeBindingArgs with scheduler features. +func ValidateVolumeBindingArgsWithOptions(path *field.Path, args *config.VolumeBindingArgs, opts VolumeBindingArgsValidationOptions) error { + var allErrs field.ErrorList + + if args.BindTimeoutSeconds < 0 { + allErrs = append(allErrs, field.Invalid(path.Child("bindTimeoutSeconds"), args.BindTimeoutSeconds, "invalid BindTimeoutSeconds, should not be a negative value")) + } + + if opts.AllowVolumeCapacityPriority { + allErrs = append(allErrs, validateFunctionShape(args.Shape, path.Child("shape"))...) + } else if args.Shape != nil { + // When the feature is off, return an error if the config is not nil. + // This prevents unexpected configuration from taking effect when the + // feature turns on in the future. + allErrs = append(allErrs, field.Invalid(path.Child("shape"), args.Shape, "unexpected field `shape`, remove it or turn on the feature gate VolumeCapacityPriority")) + } + return allErrs.ToAggregate() +} + +func ValidateNodeResourcesFitArgs(path *field.Path, args *config.NodeResourcesFitArgs) error { + var allErrs field.ErrorList + resPath := path.Child("ignoredResources") + for i, res := range args.IgnoredResources { + path := resPath.Index(i) + if errs := metav1validation.ValidateLabelName(res, path); len(errs) != 0 { + allErrs = append(allErrs, errs...) + } + } + + groupPath := path.Child("ignoredResourceGroups") + for i, group := range args.IgnoredResourceGroups { + path := groupPath.Index(i) + if strings.Contains(group, "/") { + allErrs = append(allErrs, field.Invalid(path, group, "resource group name can't contain '/'")) + } + if errs := metav1validation.ValidateLabelName(group, path); len(errs) != 0 { + allErrs = append(allErrs, errs...) + } + } + + strategyPath := path.Child("scoringStrategy") + if args.ScoringStrategy != nil { + if !supportedScoringStrategyTypes.Has(string(args.ScoringStrategy.Type)) { + allErrs = append(allErrs, field.NotSupported(strategyPath.Child("type"), args.ScoringStrategy.Type, supportedScoringStrategyTypes.List())) + } + allErrs = append(allErrs, validateResources(args.ScoringStrategy.Resources, strategyPath.Child("resources"))...) + if args.ScoringStrategy.RequestedToCapacityRatio != nil { + allErrs = append(allErrs, validateFunctionShape(args.ScoringStrategy.RequestedToCapacityRatio.Shape, strategyPath.Child("shape"))...) + } + } + + if len(allErrs) == 0 { + return nil + } + return allErrs.ToAggregate() +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/zz_generated.deepcopy.go b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/zz_generated.deepcopy.go new file mode 100644 index 000000000..f5baa6221 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/apis/config/zz_generated.deepcopy.go @@ -0,0 +1,562 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package config + +import ( + v1 "k8s.io/api/core/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DefaultPreemptionArgs) DeepCopyInto(out *DefaultPreemptionArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DefaultPreemptionArgs. +func (in *DefaultPreemptionArgs) DeepCopy() *DefaultPreemptionArgs { + if in == nil { + return nil + } + out := new(DefaultPreemptionArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DefaultPreemptionArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Extender) DeepCopyInto(out *Extender) { + *out = *in + if in.TLSConfig != nil { + in, out := &in.TLSConfig, &out.TLSConfig + *out = new(ExtenderTLSConfig) + (*in).DeepCopyInto(*out) + } + out.HTTPTimeout = in.HTTPTimeout + if in.ManagedResources != nil { + in, out := &in.ManagedResources, &out.ManagedResources + *out = make([]ExtenderManagedResource, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Extender. +func (in *Extender) DeepCopy() *Extender { + if in == nil { + return nil + } + out := new(Extender) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExtenderManagedResource) DeepCopyInto(out *ExtenderManagedResource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderManagedResource. +func (in *ExtenderManagedResource) DeepCopy() *ExtenderManagedResource { + if in == nil { + return nil + } + out := new(ExtenderManagedResource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExtenderTLSConfig) DeepCopyInto(out *ExtenderTLSConfig) { + *out = *in + if in.CertData != nil { + in, out := &in.CertData, &out.CertData + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.KeyData != nil { + in, out := &in.KeyData, &out.KeyData + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.CAData != nil { + in, out := &in.CAData, &out.CAData + *out = make([]byte, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderTLSConfig. +func (in *ExtenderTLSConfig) DeepCopy() *ExtenderTLSConfig { + if in == nil { + return nil + } + out := new(ExtenderTLSConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InterPodAffinityArgs) DeepCopyInto(out *InterPodAffinityArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InterPodAffinityArgs. +func (in *InterPodAffinityArgs) DeepCopy() *InterPodAffinityArgs { + if in == nil { + return nil + } + out := new(InterPodAffinityArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *InterPodAffinityArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubeSchedulerConfiguration) DeepCopyInto(out *KubeSchedulerConfiguration) { + *out = *in + out.TypeMeta = in.TypeMeta + out.LeaderElection = in.LeaderElection + out.ClientConnection = in.ClientConnection + out.DebuggingConfiguration = in.DebuggingConfiguration + if in.PercentageOfNodesToScore != nil { + in, out := &in.PercentageOfNodesToScore, &out.PercentageOfNodesToScore + *out = new(int32) + **out = **in + } + if in.Profiles != nil { + in, out := &in.Profiles, &out.Profiles + *out = make([]KubeSchedulerProfile, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Extenders != nil { + in, out := &in.Extenders, &out.Extenders + *out = make([]Extender, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeSchedulerConfiguration. +func (in *KubeSchedulerConfiguration) DeepCopy() *KubeSchedulerConfiguration { + if in == nil { + return nil + } + out := new(KubeSchedulerConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KubeSchedulerConfiguration) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubeSchedulerProfile) DeepCopyInto(out *KubeSchedulerProfile) { + *out = *in + if in.PercentageOfNodesToScore != nil { + in, out := &in.PercentageOfNodesToScore, &out.PercentageOfNodesToScore + *out = new(int32) + **out = **in + } + if in.Plugins != nil { + in, out := &in.Plugins, &out.Plugins + *out = new(Plugins) + (*in).DeepCopyInto(*out) + } + if in.PluginConfig != nil { + in, out := &in.PluginConfig, &out.PluginConfig + *out = make([]PluginConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeSchedulerProfile. +func (in *KubeSchedulerProfile) DeepCopy() *KubeSchedulerProfile { + if in == nil { + return nil + } + out := new(KubeSchedulerProfile) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeAffinityArgs) DeepCopyInto(out *NodeAffinityArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.AddedAffinity != nil { + in, out := &in.AddedAffinity, &out.AddedAffinity + *out = new(v1.NodeAffinity) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeAffinityArgs. +func (in *NodeAffinityArgs) DeepCopy() *NodeAffinityArgs { + if in == nil { + return nil + } + out := new(NodeAffinityArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodeAffinityArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeResourcesBalancedAllocationArgs) DeepCopyInto(out *NodeResourcesBalancedAllocationArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make([]ResourceSpec, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeResourcesBalancedAllocationArgs. +func (in *NodeResourcesBalancedAllocationArgs) DeepCopy() *NodeResourcesBalancedAllocationArgs { + if in == nil { + return nil + } + out := new(NodeResourcesBalancedAllocationArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodeResourcesBalancedAllocationArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeResourcesFitArgs) DeepCopyInto(out *NodeResourcesFitArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.IgnoredResources != nil { + in, out := &in.IgnoredResources, &out.IgnoredResources + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.IgnoredResourceGroups != nil { + in, out := &in.IgnoredResourceGroups, &out.IgnoredResourceGroups + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.ScoringStrategy != nil { + in, out := &in.ScoringStrategy, &out.ScoringStrategy + *out = new(ScoringStrategy) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeResourcesFitArgs. +func (in *NodeResourcesFitArgs) DeepCopy() *NodeResourcesFitArgs { + if in == nil { + return nil + } + out := new(NodeResourcesFitArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodeResourcesFitArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Plugin) DeepCopyInto(out *Plugin) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Plugin. +func (in *Plugin) DeepCopy() *Plugin { + if in == nil { + return nil + } + out := new(Plugin) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginConfig) DeepCopyInto(out *PluginConfig) { + *out = *in + if in.Args != nil { + out.Args = in.Args.DeepCopyObject() + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginConfig. +func (in *PluginConfig) DeepCopy() *PluginConfig { + if in == nil { + return nil + } + out := new(PluginConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginSet) DeepCopyInto(out *PluginSet) { + *out = *in + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = make([]Plugin, len(*in)) + copy(*out, *in) + } + if in.Disabled != nil { + in, out := &in.Disabled, &out.Disabled + *out = make([]Plugin, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginSet. +func (in *PluginSet) DeepCopy() *PluginSet { + if in == nil { + return nil + } + out := new(PluginSet) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Plugins) DeepCopyInto(out *Plugins) { + *out = *in + in.PreEnqueue.DeepCopyInto(&out.PreEnqueue) + in.QueueSort.DeepCopyInto(&out.QueueSort) + in.PreFilter.DeepCopyInto(&out.PreFilter) + in.Filter.DeepCopyInto(&out.Filter) + in.PostFilter.DeepCopyInto(&out.PostFilter) + in.PreScore.DeepCopyInto(&out.PreScore) + in.Score.DeepCopyInto(&out.Score) + in.Reserve.DeepCopyInto(&out.Reserve) + in.Permit.DeepCopyInto(&out.Permit) + in.PreBind.DeepCopyInto(&out.PreBind) + in.Bind.DeepCopyInto(&out.Bind) + in.PostBind.DeepCopyInto(&out.PostBind) + in.MultiPoint.DeepCopyInto(&out.MultiPoint) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Plugins. +func (in *Plugins) DeepCopy() *Plugins { + if in == nil { + return nil + } + out := new(Plugins) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodTopologySpreadArgs) DeepCopyInto(out *PodTopologySpreadArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.DefaultConstraints != nil { + in, out := &in.DefaultConstraints, &out.DefaultConstraints + *out = make([]v1.TopologySpreadConstraint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodTopologySpreadArgs. +func (in *PodTopologySpreadArgs) DeepCopy() *PodTopologySpreadArgs { + if in == nil { + return nil + } + out := new(PodTopologySpreadArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PodTopologySpreadArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RequestedToCapacityRatioParam) DeepCopyInto(out *RequestedToCapacityRatioParam) { + *out = *in + if in.Shape != nil { + in, out := &in.Shape, &out.Shape + *out = make([]UtilizationShapePoint, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RequestedToCapacityRatioParam. +func (in *RequestedToCapacityRatioParam) DeepCopy() *RequestedToCapacityRatioParam { + if in == nil { + return nil + } + out := new(RequestedToCapacityRatioParam) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceSpec) DeepCopyInto(out *ResourceSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceSpec. +func (in *ResourceSpec) DeepCopy() *ResourceSpec { + if in == nil { + return nil + } + out := new(ResourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ScoringStrategy) DeepCopyInto(out *ScoringStrategy) { + *out = *in + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make([]ResourceSpec, len(*in)) + copy(*out, *in) + } + if in.RequestedToCapacityRatio != nil { + in, out := &in.RequestedToCapacityRatio, &out.RequestedToCapacityRatio + *out = new(RequestedToCapacityRatioParam) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScoringStrategy. +func (in *ScoringStrategy) DeepCopy() *ScoringStrategy { + if in == nil { + return nil + } + out := new(ScoringStrategy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UtilizationShapePoint) DeepCopyInto(out *UtilizationShapePoint) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UtilizationShapePoint. +func (in *UtilizationShapePoint) DeepCopy() *UtilizationShapePoint { + if in == nil { + return nil + } + out := new(UtilizationShapePoint) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeBindingArgs) DeepCopyInto(out *VolumeBindingArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.Shape != nil { + in, out := &in.Shape, &out.Shape + *out = make([]UtilizationShapePoint, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeBindingArgs. +func (in *VolumeBindingArgs) DeepCopy() *VolumeBindingArgs { + if in == nil { + return nil + } + out := new(VolumeBindingArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VolumeBindingArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/eventhandlers.go b/vendor/k8s.io/kubernetes/pkg/scheduler/eventhandlers.go new file mode 100644 index 000000000..9f7b2b53d --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/eventhandlers.go @@ -0,0 +1,543 @@ +/* +Copyright 2019 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 scheduler + +import ( + "fmt" + "reflect" + "strings" + + v1 "k8s.io/api/core/v1" + storagev1 "k8s.io/api/storage/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + utilfeature "k8s.io/apiserver/pkg/util/feature" + "k8s.io/client-go/dynamic/dynamicinformer" + "k8s.io/client-go/informers" + "k8s.io/client-go/tools/cache" + corev1helpers "k8s.io/component-helpers/scheduling/corev1" + corev1nodeaffinity "k8s.io/component-helpers/scheduling/corev1/nodeaffinity" + "k8s.io/klog/v2" + "k8s.io/kubernetes/pkg/features" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeaffinity" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodename" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeports" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources" + "k8s.io/kubernetes/pkg/scheduler/internal/queue" + "k8s.io/kubernetes/pkg/scheduler/profile" +) + +func (sched *Scheduler) onStorageClassAdd(obj interface{}) { + sc, ok := obj.(*storagev1.StorageClass) + if !ok { + klog.ErrorS(nil, "Cannot convert to *storagev1.StorageClass", "obj", obj) + return + } + + // CheckVolumeBindingPred fails if pod has unbound immediate PVCs. If these + // PVCs have specified StorageClass name, creating StorageClass objects + // with late binding will cause predicates to pass, so we need to move pods + // to active queue. + // We don't need to invalidate cached results because results will not be + // cached for pod that has unbound immediate PVCs. + if sc.VolumeBindingMode != nil && *sc.VolumeBindingMode == storagev1.VolumeBindingWaitForFirstConsumer { + sched.SchedulingQueue.MoveAllToActiveOrBackoffQueue(queue.StorageClassAdd, nil) + } +} + +func (sched *Scheduler) addNodeToCache(obj interface{}) { + node, ok := obj.(*v1.Node) + if !ok { + klog.ErrorS(nil, "Cannot convert to *v1.Node", "obj", obj) + return + } + + nodeInfo := sched.Cache.AddNode(node) + klog.V(3).InfoS("Add event for node", "node", klog.KObj(node)) + sched.SchedulingQueue.MoveAllToActiveOrBackoffQueue(queue.NodeAdd, preCheckForNode(nodeInfo)) +} + +func (sched *Scheduler) updateNodeInCache(oldObj, newObj interface{}) { + oldNode, ok := oldObj.(*v1.Node) + if !ok { + klog.ErrorS(nil, "Cannot convert oldObj to *v1.Node", "oldObj", oldObj) + return + } + newNode, ok := newObj.(*v1.Node) + if !ok { + klog.ErrorS(nil, "Cannot convert newObj to *v1.Node", "newObj", newObj) + return + } + + nodeInfo := sched.Cache.UpdateNode(oldNode, newNode) + // Only requeue unschedulable pods if the node became more schedulable. + if event := nodeSchedulingPropertiesChange(newNode, oldNode); event != nil { + sched.SchedulingQueue.MoveAllToActiveOrBackoffQueue(*event, preCheckForNode(nodeInfo)) + } +} + +func (sched *Scheduler) deleteNodeFromCache(obj interface{}) { + var node *v1.Node + switch t := obj.(type) { + case *v1.Node: + node = t + case cache.DeletedFinalStateUnknown: + var ok bool + node, ok = t.Obj.(*v1.Node) + if !ok { + klog.ErrorS(nil, "Cannot convert to *v1.Node", "obj", t.Obj) + return + } + default: + klog.ErrorS(nil, "Cannot convert to *v1.Node", "obj", t) + return + } + klog.V(3).InfoS("Delete event for node", "node", klog.KObj(node)) + if err := sched.Cache.RemoveNode(node); err != nil { + klog.ErrorS(err, "Scheduler cache RemoveNode failed") + } +} + +func (sched *Scheduler) addPodToSchedulingQueue(obj interface{}) { + pod := obj.(*v1.Pod) + klog.V(3).InfoS("Add event for unscheduled pod", "pod", klog.KObj(pod)) + if err := sched.SchedulingQueue.Add(pod); err != nil { + utilruntime.HandleError(fmt.Errorf("unable to queue %T: %v", obj, err)) + } +} + +func (sched *Scheduler) updatePodInSchedulingQueue(oldObj, newObj interface{}) { + oldPod, newPod := oldObj.(*v1.Pod), newObj.(*v1.Pod) + // Bypass update event that carries identical objects; otherwise, a duplicated + // Pod may go through scheduling and cause unexpected behavior (see #96071). + if oldPod.ResourceVersion == newPod.ResourceVersion { + return + } + + isAssumed, err := sched.Cache.IsAssumedPod(newPod) + if err != nil { + utilruntime.HandleError(fmt.Errorf("failed to check whether pod %s/%s is assumed: %v", newPod.Namespace, newPod.Name, err)) + } + if isAssumed { + return + } + + if err := sched.SchedulingQueue.Update(oldPod, newPod); err != nil { + utilruntime.HandleError(fmt.Errorf("unable to update %T: %v", newObj, err)) + } +} + +func (sched *Scheduler) deletePodFromSchedulingQueue(obj interface{}) { + var pod *v1.Pod + switch t := obj.(type) { + case *v1.Pod: + pod = obj.(*v1.Pod) + case cache.DeletedFinalStateUnknown: + var ok bool + pod, ok = t.Obj.(*v1.Pod) + if !ok { + utilruntime.HandleError(fmt.Errorf("unable to convert object %T to *v1.Pod in %T", obj, sched)) + return + } + default: + utilruntime.HandleError(fmt.Errorf("unable to handle object in %T: %T", sched, obj)) + return + } + klog.V(3).InfoS("Delete event for unscheduled pod", "pod", klog.KObj(pod)) + if err := sched.SchedulingQueue.Delete(pod); err != nil { + utilruntime.HandleError(fmt.Errorf("unable to dequeue %T: %v", obj, err)) + } + fwk, err := sched.frameworkForPod(pod) + if err != nil { + // This shouldn't happen, because we only accept for scheduling the pods + // which specify a scheduler name that matches one of the profiles. + klog.ErrorS(err, "Unable to get profile", "pod", klog.KObj(pod)) + return + } + // If a waiting pod is rejected, it indicates it's previously assumed and we're + // removing it from the scheduler cache. In this case, signal a AssignedPodDelete + // event to immediately retry some unscheduled Pods. + if fwk.RejectWaitingPod(pod.UID) { + sched.SchedulingQueue.MoveAllToActiveOrBackoffQueue(queue.AssignedPodDelete, nil) + } +} + +func (sched *Scheduler) addPodToCache(obj interface{}) { + pod, ok := obj.(*v1.Pod) + if !ok { + klog.ErrorS(nil, "Cannot convert to *v1.Pod", "obj", obj) + return + } + klog.V(3).InfoS("Add event for scheduled pod", "pod", klog.KObj(pod)) + + if err := sched.Cache.AddPod(pod); err != nil { + klog.ErrorS(err, "Scheduler cache AddPod failed", "pod", klog.KObj(pod)) + } + + sched.SchedulingQueue.AssignedPodAdded(pod) +} + +func (sched *Scheduler) updatePodInCache(oldObj, newObj interface{}) { + oldPod, ok := oldObj.(*v1.Pod) + if !ok { + klog.ErrorS(nil, "Cannot convert oldObj to *v1.Pod", "oldObj", oldObj) + return + } + newPod, ok := newObj.(*v1.Pod) + if !ok { + klog.ErrorS(nil, "Cannot convert newObj to *v1.Pod", "newObj", newObj) + return + } + klog.V(4).InfoS("Update event for scheduled pod", "pod", klog.KObj(oldPod)) + + if err := sched.Cache.UpdatePod(oldPod, newPod); err != nil { + klog.ErrorS(err, "Scheduler cache UpdatePod failed", "pod", klog.KObj(oldPod)) + } + + sched.SchedulingQueue.AssignedPodUpdated(newPod) +} + +func (sched *Scheduler) deletePodFromCache(obj interface{}) { + var pod *v1.Pod + switch t := obj.(type) { + case *v1.Pod: + pod = t + case cache.DeletedFinalStateUnknown: + var ok bool + pod, ok = t.Obj.(*v1.Pod) + if !ok { + klog.ErrorS(nil, "Cannot convert to *v1.Pod", "obj", t.Obj) + return + } + default: + klog.ErrorS(nil, "Cannot convert to *v1.Pod", "obj", t) + return + } + klog.V(3).InfoS("Delete event for scheduled pod", "pod", klog.KObj(pod)) + if err := sched.Cache.RemovePod(pod); err != nil { + klog.ErrorS(err, "Scheduler cache RemovePod failed", "pod", klog.KObj(pod)) + } + + sched.SchedulingQueue.MoveAllToActiveOrBackoffQueue(queue.AssignedPodDelete, nil) +} + +// assignedPod selects pods that are assigned (scheduled and running). +func assignedPod(pod *v1.Pod) bool { + return len(pod.Spec.NodeName) != 0 +} + +// responsibleForPod returns true if the pod has asked to be scheduled by the given scheduler. +func responsibleForPod(pod *v1.Pod, profiles profile.Map) bool { + return profiles.HandlesSchedulerName(pod.Spec.SchedulerName) +} + +// addAllEventHandlers is a helper function used in tests and in Scheduler +// to add event handlers for various informers. +func addAllEventHandlers( + sched *Scheduler, + informerFactory informers.SharedInformerFactory, + dynInformerFactory dynamicinformer.DynamicSharedInformerFactory, + gvkMap map[framework.GVK]framework.ActionType, +) { + // scheduled pod cache + informerFactory.Core().V1().Pods().Informer().AddEventHandler( + cache.FilteringResourceEventHandler{ + FilterFunc: func(obj interface{}) bool { + switch t := obj.(type) { + case *v1.Pod: + return assignedPod(t) + case cache.DeletedFinalStateUnknown: + if _, ok := t.Obj.(*v1.Pod); ok { + // The carried object may be stale, so we don't use it to check if + // it's assigned or not. Attempting to cleanup anyways. + return true + } + utilruntime.HandleError(fmt.Errorf("unable to convert object %T to *v1.Pod in %T", obj, sched)) + return false + default: + utilruntime.HandleError(fmt.Errorf("unable to handle object in %T: %T", sched, obj)) + return false + } + }, + Handler: cache.ResourceEventHandlerFuncs{ + AddFunc: sched.addPodToCache, + UpdateFunc: sched.updatePodInCache, + DeleteFunc: sched.deletePodFromCache, + }, + }, + ) + // unscheduled pod queue + informerFactory.Core().V1().Pods().Informer().AddEventHandler( + cache.FilteringResourceEventHandler{ + FilterFunc: func(obj interface{}) bool { + switch t := obj.(type) { + case *v1.Pod: + return !assignedPod(t) && responsibleForPod(t, sched.Profiles) + case cache.DeletedFinalStateUnknown: + if pod, ok := t.Obj.(*v1.Pod); ok { + // The carried object may be stale, so we don't use it to check if + // it's assigned or not. + return responsibleForPod(pod, sched.Profiles) + } + utilruntime.HandleError(fmt.Errorf("unable to convert object %T to *v1.Pod in %T", obj, sched)) + return false + default: + utilruntime.HandleError(fmt.Errorf("unable to handle object in %T: %T", sched, obj)) + return false + } + }, + Handler: cache.ResourceEventHandlerFuncs{ + AddFunc: sched.addPodToSchedulingQueue, + UpdateFunc: sched.updatePodInSchedulingQueue, + DeleteFunc: sched.deletePodFromSchedulingQueue, + }, + }, + ) + + informerFactory.Core().V1().Nodes().Informer().AddEventHandler( + cache.ResourceEventHandlerFuncs{ + AddFunc: sched.addNodeToCache, + UpdateFunc: sched.updateNodeInCache, + DeleteFunc: sched.deleteNodeFromCache, + }, + ) + + buildEvtResHandler := func(at framework.ActionType, gvk framework.GVK, shortGVK string) cache.ResourceEventHandlerFuncs { + funcs := cache.ResourceEventHandlerFuncs{} + if at&framework.Add != 0 { + evt := framework.ClusterEvent{Resource: gvk, ActionType: framework.Add, Label: fmt.Sprintf("%vAdd", shortGVK)} + funcs.AddFunc = func(_ interface{}) { + sched.SchedulingQueue.MoveAllToActiveOrBackoffQueue(evt, nil) + } + } + if at&framework.Update != 0 { + evt := framework.ClusterEvent{Resource: gvk, ActionType: framework.Update, Label: fmt.Sprintf("%vUpdate", shortGVK)} + funcs.UpdateFunc = func(_, _ interface{}) { + sched.SchedulingQueue.MoveAllToActiveOrBackoffQueue(evt, nil) + } + } + if at&framework.Delete != 0 { + evt := framework.ClusterEvent{Resource: gvk, ActionType: framework.Delete, Label: fmt.Sprintf("%vDelete", shortGVK)} + funcs.DeleteFunc = func(_ interface{}) { + sched.SchedulingQueue.MoveAllToActiveOrBackoffQueue(evt, nil) + } + } + return funcs + } + + for gvk, at := range gvkMap { + switch gvk { + case framework.Node, framework.Pod: + // Do nothing. + case framework.CSINode: + informerFactory.Storage().V1().CSINodes().Informer().AddEventHandler( + buildEvtResHandler(at, framework.CSINode, "CSINode"), + ) + case framework.CSIDriver: + informerFactory.Storage().V1().CSIDrivers().Informer().AddEventHandler( + buildEvtResHandler(at, framework.CSIDriver, "CSIDriver"), + ) + case framework.CSIStorageCapacity: + informerFactory.Storage().V1().CSIStorageCapacities().Informer().AddEventHandler( + buildEvtResHandler(at, framework.CSIStorageCapacity, "CSIStorageCapacity"), + ) + case framework.PersistentVolume: + // MaxPDVolumeCountPredicate: since it relies on the counts of PV. + // + // PvAdd: Pods created when there are no PVs available will be stuck in + // unschedulable queue. But unbound PVs created for static provisioning and + // delay binding storage class are skipped in PV controller dynamic + // provisioning and binding process, will not trigger events to schedule pod + // again. So we need to move pods to active queue on PV add for this + // scenario. + // + // PvUpdate: Scheduler.bindVolumesWorker may fail to update assumed pod volume + // bindings due to conflicts if PVs are updated by PV controller or other + // parties, then scheduler will add pod back to unschedulable queue. We + // need to move pods to active queue on PV update for this scenario. + informerFactory.Core().V1().PersistentVolumes().Informer().AddEventHandler( + buildEvtResHandler(at, framework.PersistentVolume, "Pv"), + ) + case framework.PersistentVolumeClaim: + // MaxPDVolumeCountPredicate: add/update PVC will affect counts of PV when it is bound. + informerFactory.Core().V1().PersistentVolumeClaims().Informer().AddEventHandler( + buildEvtResHandler(at, framework.PersistentVolumeClaim, "Pvc"), + ) + case framework.PodScheduling: + if utilfeature.DefaultFeatureGate.Enabled(features.DynamicResourceAllocation) { + _, _ = informerFactory.Resource().V1alpha1().PodSchedulings().Informer().AddEventHandler( + buildEvtResHandler(at, framework.PodScheduling, "PodScheduling"), + ) + } + case framework.ResourceClaim: + if utilfeature.DefaultFeatureGate.Enabled(features.DynamicResourceAllocation) { + _, _ = informerFactory.Resource().V1alpha1().ResourceClaims().Informer().AddEventHandler( + buildEvtResHandler(at, framework.ResourceClaim, "ResourceClaim"), + ) + } + case framework.StorageClass: + if at&framework.Add != 0 { + informerFactory.Storage().V1().StorageClasses().Informer().AddEventHandler( + cache.ResourceEventHandlerFuncs{ + AddFunc: sched.onStorageClassAdd, + }, + ) + } + if at&framework.Update != 0 { + informerFactory.Storage().V1().StorageClasses().Informer().AddEventHandler( + cache.ResourceEventHandlerFuncs{ + UpdateFunc: func(_, _ interface{}) { + sched.SchedulingQueue.MoveAllToActiveOrBackoffQueue(queue.StorageClassUpdate, nil) + }, + }, + ) + } + default: + // Tests may not instantiate dynInformerFactory. + if dynInformerFactory == nil { + continue + } + // GVK is expected to be at least 3-folded, separated by dots. + // .. + // Valid examples: + // - foos.v1.example.com + // - bars.v1beta1.a.b.c + // Invalid examples: + // - foos.v1 (2 sections) + // - foo.v1.example.com (the first section should be plural) + if strings.Count(string(gvk), ".") < 2 { + klog.ErrorS(nil, "incorrect event registration", "gvk", gvk) + continue + } + // Fall back to try dynamic informers. + gvr, _ := schema.ParseResourceArg(string(gvk)) + dynInformer := dynInformerFactory.ForResource(*gvr).Informer() + dynInformer.AddEventHandler( + buildEvtResHandler(at, gvk, strings.Title(gvr.Resource)), + ) + } + } +} + +func nodeSchedulingPropertiesChange(newNode *v1.Node, oldNode *v1.Node) *framework.ClusterEvent { + if nodeSpecUnschedulableChanged(newNode, oldNode) { + return &queue.NodeSpecUnschedulableChange + } + if nodeAllocatableChanged(newNode, oldNode) { + return &queue.NodeAllocatableChange + } + if nodeLabelsChanged(newNode, oldNode) { + return &queue.NodeLabelChange + } + if nodeTaintsChanged(newNode, oldNode) { + return &queue.NodeTaintChange + } + if nodeConditionsChanged(newNode, oldNode) { + return &queue.NodeConditionChange + } + + return nil +} + +func nodeAllocatableChanged(newNode *v1.Node, oldNode *v1.Node) bool { + return !reflect.DeepEqual(oldNode.Status.Allocatable, newNode.Status.Allocatable) +} + +func nodeLabelsChanged(newNode *v1.Node, oldNode *v1.Node) bool { + return !reflect.DeepEqual(oldNode.GetLabels(), newNode.GetLabels()) +} + +func nodeTaintsChanged(newNode *v1.Node, oldNode *v1.Node) bool { + return !reflect.DeepEqual(newNode.Spec.Taints, oldNode.Spec.Taints) +} + +func nodeConditionsChanged(newNode *v1.Node, oldNode *v1.Node) bool { + strip := func(conditions []v1.NodeCondition) map[v1.NodeConditionType]v1.ConditionStatus { + conditionStatuses := make(map[v1.NodeConditionType]v1.ConditionStatus, len(conditions)) + for i := range conditions { + conditionStatuses[conditions[i].Type] = conditions[i].Status + } + return conditionStatuses + } + return !reflect.DeepEqual(strip(oldNode.Status.Conditions), strip(newNode.Status.Conditions)) +} + +func nodeSpecUnschedulableChanged(newNode *v1.Node, oldNode *v1.Node) bool { + return newNode.Spec.Unschedulable != oldNode.Spec.Unschedulable && !newNode.Spec.Unschedulable +} + +func preCheckForNode(nodeInfo *framework.NodeInfo) queue.PreEnqueueCheck { + // Note: the following checks doesn't take preemption into considerations, in very rare + // cases (e.g., node resizing), "pod" may still fail a check but preemption helps. We deliberately + // chose to ignore those cases as unschedulable pods will be re-queued eventually. + return func(pod *v1.Pod) bool { + admissionResults := AdmissionCheck(pod, nodeInfo, false) + if len(admissionResults) != 0 { + return false + } + _, isUntolerated := corev1helpers.FindMatchingUntoleratedTaint(nodeInfo.Node().Spec.Taints, pod.Spec.Tolerations, func(t *v1.Taint) bool { + return t.Effect == v1.TaintEffectNoSchedule + }) + return !isUntolerated + } +} + +// AdmissionCheck calls the filtering logic of noderesources/nodeport/nodeAffinity/nodename +// and returns the failure reasons. It's used in kubelet(pkg/kubelet/lifecycle/predicate.go) and scheduler. +// It returns the first failure if `includeAllFailures` is set to false; otherwise +// returns all failures. +func AdmissionCheck(pod *v1.Pod, nodeInfo *framework.NodeInfo, includeAllFailures bool) []AdmissionResult { + var admissionResults []AdmissionResult + insufficientResources := noderesources.Fits(pod, nodeInfo) + if len(insufficientResources) != 0 { + for i := range insufficientResources { + admissionResults = append(admissionResults, AdmissionResult{InsufficientResource: &insufficientResources[i]}) + } + if !includeAllFailures { + return admissionResults + } + } + + if matches, _ := corev1nodeaffinity.GetRequiredNodeAffinity(pod).Match(nodeInfo.Node()); !matches { + admissionResults = append(admissionResults, AdmissionResult{Name: nodeaffinity.Name, Reason: nodeaffinity.ErrReasonPod}) + if !includeAllFailures { + return admissionResults + } + } + if !nodename.Fits(pod, nodeInfo) { + admissionResults = append(admissionResults, AdmissionResult{Name: nodename.Name, Reason: nodename.ErrReason}) + if !includeAllFailures { + return admissionResults + } + } + if !nodeports.Fits(pod, nodeInfo) { + admissionResults = append(admissionResults, AdmissionResult{Name: nodeports.Name, Reason: nodeports.ErrReason}) + if !includeAllFailures { + return admissionResults + } + } + return admissionResults +} + +// AdmissionResult describes the reason why Scheduler can't admit the pod. +// If the reason is a resource fit one, then AdmissionResult.InsufficientResource includes the details. +type AdmissionResult struct { + Name string + Reason string + InsufficientResource *noderesources.InsufficientResource +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/extender.go b/vendor/k8s.io/kubernetes/pkg/scheduler/extender.go new file mode 100644 index 000000000..8350e04c9 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/extender.go @@ -0,0 +1,444 @@ +/* +Copyright 2015 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 scheduler + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "strings" + "time" + + v1 "k8s.io/api/core/v1" + utilnet "k8s.io/apimachinery/pkg/util/net" + "k8s.io/apimachinery/pkg/util/sets" + restclient "k8s.io/client-go/rest" + extenderv1 "k8s.io/kube-scheduler/extender/v1" + schedulerapi "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/kubernetes/pkg/scheduler/framework" +) + +const ( + // DefaultExtenderTimeout defines the default extender timeout in second. + DefaultExtenderTimeout = 5 * time.Second +) + +// HTTPExtender implements the Extender interface. +type HTTPExtender struct { + extenderURL string + preemptVerb string + filterVerb string + prioritizeVerb string + bindVerb string + weight int64 + client *http.Client + nodeCacheCapable bool + managedResources sets.String + ignorable bool +} + +func makeTransport(config *schedulerapi.Extender) (http.RoundTripper, error) { + var cfg restclient.Config + if config.TLSConfig != nil { + cfg.TLSClientConfig.Insecure = config.TLSConfig.Insecure + cfg.TLSClientConfig.ServerName = config.TLSConfig.ServerName + cfg.TLSClientConfig.CertFile = config.TLSConfig.CertFile + cfg.TLSClientConfig.KeyFile = config.TLSConfig.KeyFile + cfg.TLSClientConfig.CAFile = config.TLSConfig.CAFile + cfg.TLSClientConfig.CertData = config.TLSConfig.CertData + cfg.TLSClientConfig.KeyData = config.TLSConfig.KeyData + cfg.TLSClientConfig.CAData = config.TLSConfig.CAData + } + if config.EnableHTTPS { + hasCA := len(cfg.CAFile) > 0 || len(cfg.CAData) > 0 + if !hasCA { + cfg.Insecure = true + } + } + tlsConfig, err := restclient.TLSConfigFor(&cfg) + if err != nil { + return nil, err + } + if tlsConfig != nil { + return utilnet.SetTransportDefaults(&http.Transport{ + TLSClientConfig: tlsConfig, + }), nil + } + return utilnet.SetTransportDefaults(&http.Transport{}), nil +} + +// NewHTTPExtender creates an HTTPExtender object. +func NewHTTPExtender(config *schedulerapi.Extender) (framework.Extender, error) { + if config.HTTPTimeout.Duration.Nanoseconds() == 0 { + config.HTTPTimeout.Duration = time.Duration(DefaultExtenderTimeout) + } + + transport, err := makeTransport(config) + if err != nil { + return nil, err + } + client := &http.Client{ + Transport: transport, + Timeout: config.HTTPTimeout.Duration, + } + managedResources := sets.NewString() + for _, r := range config.ManagedResources { + managedResources.Insert(string(r.Name)) + } + return &HTTPExtender{ + extenderURL: config.URLPrefix, + preemptVerb: config.PreemptVerb, + filterVerb: config.FilterVerb, + prioritizeVerb: config.PrioritizeVerb, + bindVerb: config.BindVerb, + weight: config.Weight, + client: client, + nodeCacheCapable: config.NodeCacheCapable, + managedResources: managedResources, + ignorable: config.Ignorable, + }, nil +} + +// Name returns extenderURL to identify the extender. +func (h *HTTPExtender) Name() string { + return h.extenderURL +} + +// IsIgnorable returns true indicates scheduling should not fail when this extender +// is unavailable +func (h *HTTPExtender) IsIgnorable() bool { + return h.ignorable +} + +// SupportsPreemption returns true if an extender supports preemption. +// An extender should have preempt verb defined and enabled its own node cache. +func (h *HTTPExtender) SupportsPreemption() bool { + return len(h.preemptVerb) > 0 +} + +// ProcessPreemption returns filtered candidate nodes and victims after running preemption logic in extender. +func (h *HTTPExtender) ProcessPreemption( + pod *v1.Pod, + nodeNameToVictims map[string]*extenderv1.Victims, + nodeInfos framework.NodeInfoLister, +) (map[string]*extenderv1.Victims, error) { + var ( + result extenderv1.ExtenderPreemptionResult + args *extenderv1.ExtenderPreemptionArgs + ) + + if !h.SupportsPreemption() { + return nil, fmt.Errorf("preempt verb is not defined for extender %v but run into ProcessPreemption", h.extenderURL) + } + + if h.nodeCacheCapable { + // If extender has cached node info, pass NodeNameToMetaVictims in args. + nodeNameToMetaVictims := convertToMetaVictims(nodeNameToVictims) + args = &extenderv1.ExtenderPreemptionArgs{ + Pod: pod, + NodeNameToMetaVictims: nodeNameToMetaVictims, + } + } else { + args = &extenderv1.ExtenderPreemptionArgs{ + Pod: pod, + NodeNameToVictims: nodeNameToVictims, + } + } + + if err := h.send(h.preemptVerb, args, &result); err != nil { + return nil, err + } + + // Extender will always return NodeNameToMetaVictims. + // So let's convert it to NodeNameToVictims by using . + newNodeNameToVictims, err := h.convertToVictims(result.NodeNameToMetaVictims, nodeInfos) + if err != nil { + return nil, err + } + // Do not override . + return newNodeNameToVictims, nil +} + +// convertToVictims converts "nodeNameToMetaVictims" from object identifiers, +// such as UIDs and names, to object pointers. +func (h *HTTPExtender) convertToVictims( + nodeNameToMetaVictims map[string]*extenderv1.MetaVictims, + nodeInfos framework.NodeInfoLister, +) (map[string]*extenderv1.Victims, error) { + nodeNameToVictims := map[string]*extenderv1.Victims{} + for nodeName, metaVictims := range nodeNameToMetaVictims { + nodeInfo, err := nodeInfos.Get(nodeName) + if err != nil { + return nil, err + } + victims := &extenderv1.Victims{ + Pods: []*v1.Pod{}, + NumPDBViolations: metaVictims.NumPDBViolations, + } + for _, metaPod := range metaVictims.Pods { + pod, err := h.convertPodUIDToPod(metaPod, nodeInfo) + if err != nil { + return nil, err + } + victims.Pods = append(victims.Pods, pod) + } + nodeNameToVictims[nodeName] = victims + } + return nodeNameToVictims, nil +} + +// convertPodUIDToPod returns v1.Pod object for given MetaPod and node info. +// The v1.Pod object is restored by nodeInfo.Pods(). +// It returns an error if there's cache inconsistency between default scheduler +// and extender, i.e. when the pod is not found in nodeInfo.Pods. +func (h *HTTPExtender) convertPodUIDToPod( + metaPod *extenderv1.MetaPod, + nodeInfo *framework.NodeInfo) (*v1.Pod, error) { + for _, p := range nodeInfo.Pods { + if string(p.Pod.UID) == metaPod.UID { + return p.Pod, nil + } + } + return nil, fmt.Errorf("extender: %v claims to preempt pod (UID: %v) on node: %v, but the pod is not found on that node", + h.extenderURL, metaPod, nodeInfo.Node().Name) +} + +// convertToMetaVictims converts from struct type to meta types. +func convertToMetaVictims( + nodeNameToVictims map[string]*extenderv1.Victims, +) map[string]*extenderv1.MetaVictims { + nodeNameToMetaVictims := map[string]*extenderv1.MetaVictims{} + for node, victims := range nodeNameToVictims { + metaVictims := &extenderv1.MetaVictims{ + Pods: []*extenderv1.MetaPod{}, + NumPDBViolations: victims.NumPDBViolations, + } + for _, pod := range victims.Pods { + metaPod := &extenderv1.MetaPod{ + UID: string(pod.UID), + } + metaVictims.Pods = append(metaVictims.Pods, metaPod) + } + nodeNameToMetaVictims[node] = metaVictims + } + return nodeNameToMetaVictims +} + +// Filter based on extender implemented predicate functions. The filtered list is +// expected to be a subset of the supplied list; otherwise the function returns an error. +// The failedNodes and failedAndUnresolvableNodes optionally contains the list +// of failed nodes and failure reasons, except nodes in the latter are +// unresolvable. +func (h *HTTPExtender) Filter( + pod *v1.Pod, + nodes []*v1.Node, +) (filteredList []*v1.Node, failedNodes, failedAndUnresolvableNodes extenderv1.FailedNodesMap, err error) { + var ( + result extenderv1.ExtenderFilterResult + nodeList *v1.NodeList + nodeNames *[]string + nodeResult []*v1.Node + args *extenderv1.ExtenderArgs + ) + fromNodeName := make(map[string]*v1.Node) + for _, n := range nodes { + fromNodeName[n.Name] = n + } + + if h.filterVerb == "" { + return nodes, extenderv1.FailedNodesMap{}, extenderv1.FailedNodesMap{}, nil + } + + if h.nodeCacheCapable { + nodeNameSlice := make([]string, 0, len(nodes)) + for _, node := range nodes { + nodeNameSlice = append(nodeNameSlice, node.Name) + } + nodeNames = &nodeNameSlice + } else { + nodeList = &v1.NodeList{} + for _, node := range nodes { + nodeList.Items = append(nodeList.Items, *node) + } + } + + args = &extenderv1.ExtenderArgs{ + Pod: pod, + Nodes: nodeList, + NodeNames: nodeNames, + } + + if err := h.send(h.filterVerb, args, &result); err != nil { + return nil, nil, nil, err + } + if result.Error != "" { + return nil, nil, nil, fmt.Errorf(result.Error) + } + + if h.nodeCacheCapable && result.NodeNames != nil { + nodeResult = make([]*v1.Node, len(*result.NodeNames)) + for i, nodeName := range *result.NodeNames { + if n, ok := fromNodeName[nodeName]; ok { + nodeResult[i] = n + } else { + return nil, nil, nil, fmt.Errorf( + "extender %q claims a filtered node %q which is not found in the input node list", + h.extenderURL, nodeName) + } + } + } else if result.Nodes != nil { + nodeResult = make([]*v1.Node, len(result.Nodes.Items)) + for i := range result.Nodes.Items { + nodeResult[i] = &result.Nodes.Items[i] + } + } + + return nodeResult, result.FailedNodes, result.FailedAndUnresolvableNodes, nil +} + +// Prioritize based on extender implemented priority functions. Weight*priority is added +// up for each such priority function. The returned score is added to the score computed +// by Kubernetes scheduler. The total score is used to do the host selection. +func (h *HTTPExtender) Prioritize(pod *v1.Pod, nodes []*v1.Node) (*extenderv1.HostPriorityList, int64, error) { + var ( + result extenderv1.HostPriorityList + nodeList *v1.NodeList + nodeNames *[]string + args *extenderv1.ExtenderArgs + ) + + if h.prioritizeVerb == "" { + result := extenderv1.HostPriorityList{} + for _, node := range nodes { + result = append(result, extenderv1.HostPriority{Host: node.Name, Score: 0}) + } + return &result, 0, nil + } + + if h.nodeCacheCapable { + nodeNameSlice := make([]string, 0, len(nodes)) + for _, node := range nodes { + nodeNameSlice = append(nodeNameSlice, node.Name) + } + nodeNames = &nodeNameSlice + } else { + nodeList = &v1.NodeList{} + for _, node := range nodes { + nodeList.Items = append(nodeList.Items, *node) + } + } + + args = &extenderv1.ExtenderArgs{ + Pod: pod, + Nodes: nodeList, + NodeNames: nodeNames, + } + + if err := h.send(h.prioritizeVerb, args, &result); err != nil { + return nil, 0, err + } + return &result, h.weight, nil +} + +// Bind delegates the action of binding a pod to a node to the extender. +func (h *HTTPExtender) Bind(binding *v1.Binding) error { + var result extenderv1.ExtenderBindingResult + if !h.IsBinder() { + // This shouldn't happen as this extender wouldn't have become a Binder. + return fmt.Errorf("unexpected empty bindVerb in extender") + } + req := &extenderv1.ExtenderBindingArgs{ + PodName: binding.Name, + PodNamespace: binding.Namespace, + PodUID: binding.UID, + Node: binding.Target.Name, + } + if err := h.send(h.bindVerb, req, &result); err != nil { + return err + } + if result.Error != "" { + return fmt.Errorf(result.Error) + } + return nil +} + +// IsBinder returns whether this extender is configured for the Bind method. +func (h *HTTPExtender) IsBinder() bool { + return h.bindVerb != "" +} + +// Helper function to send messages to the extender +func (h *HTTPExtender) send(action string, args interface{}, result interface{}) error { + out, err := json.Marshal(args) + if err != nil { + return err + } + + url := strings.TrimRight(h.extenderURL, "/") + "/" + action + + req, err := http.NewRequest("POST", url, bytes.NewReader(out)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := h.client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("failed %v with extender at URL %v, code %v", action, url, resp.StatusCode) + } + + return json.NewDecoder(resp.Body).Decode(result) +} + +// IsInterested returns true if at least one extended resource requested by +// this pod is managed by this extender. +func (h *HTTPExtender) IsInterested(pod *v1.Pod) bool { + if h.managedResources.Len() == 0 { + return true + } + if h.hasManagedResources(pod.Spec.Containers) { + return true + } + if h.hasManagedResources(pod.Spec.InitContainers) { + return true + } + return false +} + +func (h *HTTPExtender) hasManagedResources(containers []v1.Container) bool { + for i := range containers { + container := &containers[i] + for resourceName := range container.Resources.Requests { + if h.managedResources.Has(string(resourceName)) { + return true + } + } + for resourceName := range container.Resources.Limits { + if h.managedResources.Has(string(resourceName)) { + return true + } + } + } + return false +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/cycle_state.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/cycle_state.go new file mode 100644 index 000000000..7f4a13512 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/cycle_state.go @@ -0,0 +1,110 @@ +/* +Copyright 2019 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 framework + +import ( + "errors" + "sync" +) + +var ( + // ErrNotFound is the not found error message. + ErrNotFound = errors.New("not found") +) + +// StateData is a generic type for arbitrary data stored in CycleState. +type StateData interface { + // Clone is an interface to make a copy of StateData. For performance reasons, + // clone should make shallow copies for members (e.g., slices or maps) that are not + // impacted by PreFilter's optional AddPod/RemovePod methods. + Clone() StateData +} + +// StateKey is the type of keys stored in CycleState. +type StateKey string + +// CycleState provides a mechanism for plugins to store and retrieve arbitrary data. +// StateData stored by one plugin can be read, altered, or deleted by another plugin. +// CycleState does not provide any data protection, as all plugins are assumed to be +// trusted. +// Note: CycleState uses a sync.Map to back the storage. It's aimed to optimize for the "write once and read many times" scenarios. +// It is the recommended pattern used in all in-tree plugins - plugin-specific state is written once in PreFilter/PreScore and afterwards read many times in Filter/Score. +type CycleState struct { + // storage is keyed with StateKey, and valued with StateData. + storage sync.Map + // if recordPluginMetrics is true, PluginExecutionDuration will be recorded for this cycle. + recordPluginMetrics bool +} + +// NewCycleState initializes a new CycleState and returns its pointer. +func NewCycleState() *CycleState { + return &CycleState{} +} + +// ShouldRecordPluginMetrics returns whether PluginExecutionDuration metrics should be recorded. +func (c *CycleState) ShouldRecordPluginMetrics() bool { + if c == nil { + return false + } + return c.recordPluginMetrics +} + +// SetRecordPluginMetrics sets recordPluginMetrics to the given value. +func (c *CycleState) SetRecordPluginMetrics(flag bool) { + if c == nil { + return + } + c.recordPluginMetrics = flag +} + +// Clone creates a copy of CycleState and returns its pointer. Clone returns +// nil if the context being cloned is nil. +func (c *CycleState) Clone() *CycleState { + if c == nil { + return nil + } + copy := NewCycleState() + c.storage.Range(func(k, v interface{}) bool { + copy.storage.Store(k, v.(StateData).Clone()) + return true + }) + copy.recordPluginMetrics = c.recordPluginMetrics + + return copy +} + +// Read retrieves data with the given "key" from CycleState. If the key is not +// present an error is returned. +// This function is thread safe by using sync.Map. +func (c *CycleState) Read(key StateKey) (StateData, error) { + if v, ok := c.storage.Load(key); ok { + return v.(StateData), nil + } + return nil, ErrNotFound +} + +// Write stores the given "val" in CycleState with the given "key". +// This function is thread safe by using sync.Map. +func (c *CycleState) Write(key StateKey, val StateData) { + c.storage.Store(key, val) +} + +// Delete deletes data with the given key from CycleState. +// This function is thread safe by using sync.Map. +func (c *CycleState) Delete(key StateKey) { + c.storage.Delete(key) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/extender.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/extender.go new file mode 100644 index 000000000..d47c89bf1 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/extender.go @@ -0,0 +1,72 @@ +/* +Copyright 2020 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 framework + +import ( + v1 "k8s.io/api/core/v1" + extenderv1 "k8s.io/kube-scheduler/extender/v1" +) + +// Extender is an interface for external processes to influence scheduling +// decisions made by Kubernetes. This is typically needed for resources not directly +// managed by Kubernetes. +type Extender interface { + // Name returns a unique name that identifies the extender. + Name() string + + // Filter based on extender-implemented predicate functions. The filtered list is + // expected to be a subset of the supplied list. + // The failedNodes and failedAndUnresolvableNodes optionally contains the list + // of failed nodes and failure reasons, except nodes in the latter are + // unresolvable. + Filter(pod *v1.Pod, nodes []*v1.Node) (filteredNodes []*v1.Node, failedNodesMap extenderv1.FailedNodesMap, failedAndUnresolvable extenderv1.FailedNodesMap, err error) + + // Prioritize based on extender-implemented priority functions. The returned scores & weight + // are used to compute the weighted score for an extender. The weighted scores are added to + // the scores computed by Kubernetes scheduler. The total scores are used to do the host selection. + Prioritize(pod *v1.Pod, nodes []*v1.Node) (hostPriorities *extenderv1.HostPriorityList, weight int64, err error) + + // Bind delegates the action of binding a pod to a node to the extender. + Bind(binding *v1.Binding) error + + // IsBinder returns whether this extender is configured for the Bind method. + IsBinder() bool + + // IsInterested returns true if at least one extended resource requested by + // this pod is managed by this extender. + IsInterested(pod *v1.Pod) bool + + // ProcessPreemption returns nodes with their victim pods processed by extender based on + // given: + // 1. Pod to schedule + // 2. Candidate nodes and victim pods (nodeNameToVictims) generated by previous scheduling process. + // The possible changes made by extender may include: + // 1. Subset of given candidate nodes after preemption phase of extender. + // 2. A different set of victim pod for every given candidate node after preemption phase of extender. + ProcessPreemption( + pod *v1.Pod, + nodeNameToVictims map[string]*extenderv1.Victims, + nodeInfos NodeInfoLister, + ) (map[string]*extenderv1.Victims, error) + + // SupportsPreemption returns if the scheduler extender support preemption or not. + SupportsPreemption() bool + + // IsIgnorable returns true indicates scheduling should not fail when this extender + // is unavailable. This gives scheduler ability to fail fast and tolerate non-critical extenders as well. + IsIgnorable() bool +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/interface.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/interface.go new file mode 100644 index 000000000..9f9b5fd16 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/interface.go @@ -0,0 +1,768 @@ +/* +Copyright 2019 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. +*/ + +// This file defines the scheduling framework plugin interfaces. + +package framework + +import ( + "context" + "errors" + "math" + "strings" + "sync" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/client-go/informers" + clientset "k8s.io/client-go/kubernetes" + restclient "k8s.io/client-go/rest" + "k8s.io/client-go/tools/events" + "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/kubernetes/pkg/scheduler/framework/parallelize" +) + +// NodeScoreList declares a list of nodes and their scores. +type NodeScoreList []NodeScore + +// NodeScore is a struct with node name and score. +type NodeScore struct { + Name string + Score int64 +} + +// NodeToStatusMap declares map from node name to its status. +type NodeToStatusMap map[string]*Status + +// NodePluginScores is a struct with node name and scores for that node. +type NodePluginScores struct { + // Name is node name. + Name string + // Scores is scores from plugins and extenders. + Scores []PluginScore + // TotalScore is the total score in Scores. + TotalScore int64 +} + +// PluginScore is a struct with plugin/extender name and score. +type PluginScore struct { + // Name is the name of plugin or extender. + Name string + Score int64 +} + +// Code is the Status code/type which is returned from plugins. +type Code int + +// These are predefined codes used in a Status. +const ( + // Success means that plugin ran correctly and found pod schedulable. + // NOTE: A nil status is also considered as "Success". + Success Code = iota + // Error is used for internal plugin errors, unexpected input, etc. + Error + // Unschedulable is used when a plugin finds a pod unschedulable. The scheduler might attempt to + // preempt other pods to get this pod scheduled. Use UnschedulableAndUnresolvable to make the + // scheduler skip preemption. + // The accompanying status message should explain why the pod is unschedulable. + Unschedulable + // UnschedulableAndUnresolvable is used when a plugin finds a pod unschedulable and + // preemption would not change anything. Plugins should return Unschedulable if it is possible + // that the pod can get scheduled with preemption. + // The accompanying status message should explain why the pod is unschedulable. + UnschedulableAndUnresolvable + // Wait is used when a Permit plugin finds a pod scheduling should wait. + Wait + // Skip is used when a Bind plugin chooses to skip binding. + Skip +) + +// This list should be exactly the same as the codes iota defined above in the same order. +var codes = []string{"Success", "Error", "Unschedulable", "UnschedulableAndUnresolvable", "Wait", "Skip"} + +// statusPrecedence defines a map from status to its precedence, larger value means higher precedent. +var statusPrecedence = map[Code]int{ + Error: 3, + UnschedulableAndUnresolvable: 2, + Unschedulable: 1, + // Any other statuses we know today, `Skip` or `Wait`, will take precedence over `Success`. + Success: -1, +} + +func (c Code) String() string { + return codes[c] +} + +const ( + // MaxNodeScore is the maximum score a Score plugin is expected to return. + MaxNodeScore int64 = 100 + + // MinNodeScore is the minimum score a Score plugin is expected to return. + MinNodeScore int64 = 0 + + // MaxTotalScore is the maximum total score. + MaxTotalScore int64 = math.MaxInt64 +) + +// PodsToActivateKey is a reserved state key for stashing pods. +// If the stashed pods are present in unschedulablePods or backoffQ,they will be +// activated (i.e., moved to activeQ) in two phases: +// - end of a scheduling cycle if it succeeds (will be cleared from `PodsToActivate` if activated) +// - end of a binding cycle if it succeeds +var PodsToActivateKey StateKey = "kubernetes.io/pods-to-activate" + +// PodsToActivate stores pods to be activated. +type PodsToActivate struct { + sync.Mutex + // Map is keyed with namespaced pod name, and valued with the pod. + Map map[string]*v1.Pod +} + +// Clone just returns the same state. +func (s *PodsToActivate) Clone() StateData { + return s +} + +// NewPodsToActivate instantiates a PodsToActivate object. +func NewPodsToActivate() *PodsToActivate { + return &PodsToActivate{Map: make(map[string]*v1.Pod)} +} + +// Status indicates the result of running a plugin. It consists of a code, a +// message, (optionally) an error, and a plugin name it fails by. +// When the status code is not Success, the reasons should explain why. +// And, when code is Success, all the other fields should be empty. +// NOTE: A nil Status is also considered as Success. +type Status struct { + code Code + reasons []string + err error + // failedPlugin is an optional field that records the plugin name a Pod failed by. + // It's set by the framework when code is Error, Unschedulable or UnschedulableAndUnresolvable. + failedPlugin string +} + +// Code returns code of the Status. +func (s *Status) Code() Code { + if s == nil { + return Success + } + return s.code +} + +// Message returns a concatenated message on reasons of the Status. +func (s *Status) Message() string { + if s == nil { + return "" + } + return strings.Join(s.reasons, ", ") +} + +// SetFailedPlugin sets the given plugin name to s.failedPlugin. +func (s *Status) SetFailedPlugin(plugin string) { + s.failedPlugin = plugin +} + +// WithFailedPlugin sets the given plugin name to s.failedPlugin, +// and returns the given status object. +func (s *Status) WithFailedPlugin(plugin string) *Status { + s.SetFailedPlugin(plugin) + return s +} + +// FailedPlugin returns the failed plugin name. +func (s *Status) FailedPlugin() string { + return s.failedPlugin +} + +// Reasons returns reasons of the Status. +func (s *Status) Reasons() []string { + return s.reasons +} + +// AppendReason appends given reason to the Status. +func (s *Status) AppendReason(reason string) { + s.reasons = append(s.reasons, reason) +} + +// IsSuccess returns true if and only if "Status" is nil or Code is "Success". +func (s *Status) IsSuccess() bool { + return s.Code() == Success +} + +// IsWait returns true if and only if "Status" is non-nil and its Code is "Wait". +func (s *Status) IsWait() bool { + return s.Code() == Wait +} + +// IsSkip returns true if and only if "Status" is non-nil and its Code is "Skip". +func (s *Status) IsSkip() bool { + return s.Code() == Skip +} + +// IsUnschedulable returns true if "Status" is Unschedulable (Unschedulable or UnschedulableAndUnresolvable). +func (s *Status) IsUnschedulable() bool { + code := s.Code() + return code == Unschedulable || code == UnschedulableAndUnresolvable +} + +// AsError returns nil if the status is a success, a wait or a skip; otherwise returns an "error" object +// with a concatenated message on reasons of the Status. +func (s *Status) AsError() error { + if s.IsSuccess() || s.IsWait() || s.IsSkip() { + return nil + } + if s.err != nil { + return s.err + } + return errors.New(s.Message()) +} + +// Equal checks equality of two statuses. This is useful for testing with +// cmp.Equal. +func (s *Status) Equal(x *Status) bool { + if s == nil || x == nil { + return s.IsSuccess() && x.IsSuccess() + } + if s.code != x.code { + return false + } + if s.code == Error { + return cmp.Equal(s.err, x.err, cmpopts.EquateErrors()) + } + return cmp.Equal(s.reasons, x.reasons) +} + +// NewStatus makes a Status out of the given arguments and returns its pointer. +func NewStatus(code Code, reasons ...string) *Status { + s := &Status{ + code: code, + reasons: reasons, + } + if code == Error { + s.err = errors.New(s.Message()) + } + return s +} + +// AsStatus wraps an error in a Status. +func AsStatus(err error) *Status { + if err == nil { + return nil + } + return &Status{ + code: Error, + reasons: []string{err.Error()}, + err: err, + } +} + +// PluginToStatus maps plugin name to status. Currently used to identify which Filter plugin +// returned which status. +type PluginToStatus map[string]*Status + +// Merge merges the statuses in the map into one. The resulting status code have the following +// precedence: Error, UnschedulableAndUnresolvable, Unschedulable. +func (p PluginToStatus) Merge() *Status { + if len(p) == 0 { + return nil + } + + finalStatus := NewStatus(Success) + for _, s := range p { + if s.Code() == Error { + finalStatus.err = s.AsError() + } + if statusPrecedence[s.Code()] > statusPrecedence[finalStatus.code] { + finalStatus.code = s.Code() + // Same as code, we keep the most relevant failedPlugin in the returned Status. + finalStatus.failedPlugin = s.FailedPlugin() + } + + for _, r := range s.reasons { + finalStatus.AppendReason(r) + } + } + + return finalStatus +} + +// WaitingPod represents a pod currently waiting in the permit phase. +type WaitingPod interface { + // GetPod returns a reference to the waiting pod. + GetPod() *v1.Pod + // GetPendingPlugins returns a list of pending Permit plugin's name. + GetPendingPlugins() []string + // Allow declares the waiting pod is allowed to be scheduled by the plugin named as "pluginName". + // If this is the last remaining plugin to allow, then a success signal is delivered + // to unblock the pod. + Allow(pluginName string) + // Reject declares the waiting pod unschedulable. + Reject(pluginName, msg string) +} + +// Plugin is the parent type for all the scheduling framework plugins. +type Plugin interface { + Name() string +} + +// PreEnqueuePlugin is an interface that must be implemented by "PreEnqueue" plugins. +// These plugins are called prior to adding Pods to activeQ. +// Note: an preEnqueue plugin is expected to be lightweight and efficient, so it's not expected to +// involve expensive calls like accessing external endpoints; otherwise it'd block other +// Pods' enqueuing in event handlers. +type PreEnqueuePlugin interface { + Plugin + // PreEnqueue is called prior to adding Pods to activeQ. + PreEnqueue(ctx context.Context, p *v1.Pod) *Status +} + +// LessFunc is the function to sort pod info +type LessFunc func(podInfo1, podInfo2 *QueuedPodInfo) bool + +// QueueSortPlugin is an interface that must be implemented by "QueueSort" plugins. +// These plugins are used to sort pods in the scheduling queue. Only one queue sort +// plugin may be enabled at a time. +type QueueSortPlugin interface { + Plugin + // Less are used to sort pods in the scheduling queue. + Less(*QueuedPodInfo, *QueuedPodInfo) bool +} + +// EnqueueExtensions is an optional interface that plugins can implement to efficiently +// move unschedulable Pods in internal scheduling queues. Plugins +// that fail pod scheduling (e.g., Filter plugins) are expected to implement this interface. +type EnqueueExtensions interface { + // EventsToRegister returns a series of possible events that may cause a Pod + // failed by this plugin schedulable. + // The events will be registered when instantiating the internal scheduling queue, + // and leveraged to build event handlers dynamically. + // Note: the returned list needs to be static (not depend on configuration parameters); + // otherwise it would lead to undefined behavior. + EventsToRegister() []ClusterEvent +} + +// PreFilterExtensions is an interface that is included in plugins that allow specifying +// callbacks to make incremental updates to its supposedly pre-calculated +// state. +type PreFilterExtensions interface { + // AddPod is called by the framework while trying to evaluate the impact + // of adding podToAdd to the node while scheduling podToSchedule. + AddPod(ctx context.Context, state *CycleState, podToSchedule *v1.Pod, podInfoToAdd *PodInfo, nodeInfo *NodeInfo) *Status + // RemovePod is called by the framework while trying to evaluate the impact + // of removing podToRemove from the node while scheduling podToSchedule. + RemovePod(ctx context.Context, state *CycleState, podToSchedule *v1.Pod, podInfoToRemove *PodInfo, nodeInfo *NodeInfo) *Status +} + +// PreFilterPlugin is an interface that must be implemented by "PreFilter" plugins. +// These plugins are called at the beginning of the scheduling cycle. +type PreFilterPlugin interface { + Plugin + // PreFilter is called at the beginning of the scheduling cycle. All PreFilter + // plugins must return success or the pod will be rejected. PreFilter could optionally + // return a PreFilterResult to influence which nodes to evaluate downstream. This is useful + // for cases where it is possible to determine the subset of nodes to process in O(1) time. + PreFilter(ctx context.Context, state *CycleState, p *v1.Pod) (*PreFilterResult, *Status) + // PreFilterExtensions returns a PreFilterExtensions interface if the plugin implements one, + // or nil if it does not. A Pre-filter plugin can provide extensions to incrementally + // modify its pre-processed info. The framework guarantees that the extensions + // AddPod/RemovePod will only be called after PreFilter, possibly on a cloned + // CycleState, and may call those functions more than once before calling + // Filter again on a specific node. + PreFilterExtensions() PreFilterExtensions +} + +// FilterPlugin is an interface for Filter plugins. These plugins are called at the +// filter extension point for filtering out hosts that cannot run a pod. +// This concept used to be called 'predicate' in the original scheduler. +// These plugins should return "Success", "Unschedulable" or "Error" in Status.code. +// However, the scheduler accepts other valid codes as well. +// Anything other than "Success" will lead to exclusion of the given host from +// running the pod. +type FilterPlugin interface { + Plugin + // Filter is called by the scheduling framework. + // All FilterPlugins should return "Success" to declare that + // the given node fits the pod. If Filter doesn't return "Success", + // it will return "Unschedulable", "UnschedulableAndUnresolvable" or "Error". + // For the node being evaluated, Filter plugins should look at the passed + // nodeInfo reference for this particular node's information (e.g., pods + // considered to be running on the node) instead of looking it up in the + // NodeInfoSnapshot because we don't guarantee that they will be the same. + // For example, during preemption, we may pass a copy of the original + // nodeInfo object that has some pods removed from it to evaluate the + // possibility of preempting them to schedule the target pod. + Filter(ctx context.Context, state *CycleState, pod *v1.Pod, nodeInfo *NodeInfo) *Status +} + +// PostFilterPlugin is an interface for "PostFilter" plugins. These plugins are called +// after a pod cannot be scheduled. +type PostFilterPlugin interface { + Plugin + // PostFilter is called by the scheduling framework. + // A PostFilter plugin should return one of the following statuses: + // - Unschedulable: the plugin gets executed successfully but the pod cannot be made schedulable. + // - Success: the plugin gets executed successfully and the pod can be made schedulable. + // - Error: the plugin aborts due to some internal error. + // + // Informational plugins should be configured ahead of other ones, and always return Unschedulable status. + // Optionally, a non-nil PostFilterResult may be returned along with a Success status. For example, + // a preemption plugin may choose to return nominatedNodeName, so that framework can reuse that to update the + // preemptor pod's .spec.status.nominatedNodeName field. + PostFilter(ctx context.Context, state *CycleState, pod *v1.Pod, filteredNodeStatusMap NodeToStatusMap) (*PostFilterResult, *Status) +} + +// PreScorePlugin is an interface for "PreScore" plugin. PreScore is an +// informational extension point. Plugins will be called with a list of nodes +// that passed the filtering phase. A plugin may use this data to update internal +// state or to generate logs/metrics. +type PreScorePlugin interface { + Plugin + // PreScore is called by the scheduling framework after a list of nodes + // passed the filtering phase. All prescore plugins must return success or + // the pod will be rejected + PreScore(ctx context.Context, state *CycleState, pod *v1.Pod, nodes []*v1.Node) *Status +} + +// ScoreExtensions is an interface for Score extended functionality. +type ScoreExtensions interface { + // NormalizeScore is called for all node scores produced by the same plugin's "Score" + // method. A successful run of NormalizeScore will update the scores list and return + // a success status. + NormalizeScore(ctx context.Context, state *CycleState, p *v1.Pod, scores NodeScoreList) *Status +} + +// ScorePlugin is an interface that must be implemented by "Score" plugins to rank +// nodes that passed the filtering phase. +type ScorePlugin interface { + Plugin + // Score is called on each filtered node. It must return success and an integer + // indicating the rank of the node. All scoring plugins must return success or + // the pod will be rejected. + Score(ctx context.Context, state *CycleState, p *v1.Pod, nodeName string) (int64, *Status) + + // ScoreExtensions returns a ScoreExtensions interface if it implements one, or nil if does not. + ScoreExtensions() ScoreExtensions +} + +// ReservePlugin is an interface for plugins with Reserve and Unreserve +// methods. These are meant to update the state of the plugin. This concept +// used to be called 'assume' in the original scheduler. These plugins should +// return only Success or Error in Status.code. However, the scheduler accepts +// other valid codes as well. Anything other than Success will lead to +// rejection of the pod. +type ReservePlugin interface { + Plugin + // Reserve is called by the scheduling framework when the scheduler cache is + // updated. If this method returns a failed Status, the scheduler will call + // the Unreserve method for all enabled ReservePlugins. + Reserve(ctx context.Context, state *CycleState, p *v1.Pod, nodeName string) *Status + // Unreserve is called by the scheduling framework when a reserved pod was + // rejected, an error occurred during reservation of subsequent plugins, or + // in a later phase. The Unreserve method implementation must be idempotent + // and may be called by the scheduler even if the corresponding Reserve + // method for the same plugin was not called. + Unreserve(ctx context.Context, state *CycleState, p *v1.Pod, nodeName string) +} + +// PreBindPlugin is an interface that must be implemented by "PreBind" plugins. +// These plugins are called before a pod being scheduled. +type PreBindPlugin interface { + Plugin + // PreBind is called before binding a pod. All prebind plugins must return + // success or the pod will be rejected and won't be sent for binding. + PreBind(ctx context.Context, state *CycleState, p *v1.Pod, nodeName string) *Status +} + +// PostBindPlugin is an interface that must be implemented by "PostBind" plugins. +// These plugins are called after a pod is successfully bound to a node. +type PostBindPlugin interface { + Plugin + // PostBind is called after a pod is successfully bound. These plugins are + // informational. A common application of this extension point is for cleaning + // up. If a plugin needs to clean-up its state after a pod is scheduled and + // bound, PostBind is the extension point that it should register. + PostBind(ctx context.Context, state *CycleState, p *v1.Pod, nodeName string) +} + +// PermitPlugin is an interface that must be implemented by "Permit" plugins. +// These plugins are called before a pod is bound to a node. +type PermitPlugin interface { + Plugin + // Permit is called before binding a pod (and before prebind plugins). Permit + // plugins are used to prevent or delay the binding of a Pod. A permit plugin + // must return success or wait with timeout duration, or the pod will be rejected. + // The pod will also be rejected if the wait timeout or the pod is rejected while + // waiting. Note that if the plugin returns "wait", the framework will wait only + // after running the remaining plugins given that no other plugin rejects the pod. + Permit(ctx context.Context, state *CycleState, p *v1.Pod, nodeName string) (*Status, time.Duration) +} + +// BindPlugin is an interface that must be implemented by "Bind" plugins. Bind +// plugins are used to bind a pod to a Node. +type BindPlugin interface { + Plugin + // Bind plugins will not be called until all pre-bind plugins have completed. Each + // bind plugin is called in the configured order. A bind plugin may choose whether + // or not to handle the given Pod. If a bind plugin chooses to handle a Pod, the + // remaining bind plugins are skipped. When a bind plugin does not handle a pod, + // it must return Skip in its Status code. If a bind plugin returns an Error, the + // pod is rejected and will not be bound. + Bind(ctx context.Context, state *CycleState, p *v1.Pod, nodeName string) *Status +} + +// Framework manages the set of plugins in use by the scheduling framework. +// Configured plugins are called at specified points in a scheduling context. +type Framework interface { + Handle + + // PreEnqueuePlugins returns the registered preEnqueue plugins. + PreEnqueuePlugins() []PreEnqueuePlugin + + // QueueSortFunc returns the function to sort pods in scheduling queue + QueueSortFunc() LessFunc + + // RunPreFilterPlugins runs the set of configured PreFilter plugins. It returns + // *Status and its code is set to non-success if any of the plugins returns + // anything but Success. If a non-success status is returned, then the scheduling + // cycle is aborted. + // It also returns a PreFilterResult, which may influence what or how many nodes to + // evaluate downstream. + RunPreFilterPlugins(ctx context.Context, state *CycleState, pod *v1.Pod) (*PreFilterResult, *Status) + + // RunPostFilterPlugins runs the set of configured PostFilter plugins. + // PostFilter plugins can either be informational, in which case should be configured + // to execute first and return Unschedulable status, or ones that try to change the + // cluster state to make the pod potentially schedulable in a future scheduling cycle. + RunPostFilterPlugins(ctx context.Context, state *CycleState, pod *v1.Pod, filteredNodeStatusMap NodeToStatusMap) (*PostFilterResult, *Status) + + // RunPreBindPlugins runs the set of configured PreBind plugins. It returns + // *Status and its code is set to non-success if any of the plugins returns + // anything but Success. If the Status code is "Unschedulable", it is + // considered as a scheduling check failure, otherwise, it is considered as an + // internal error. In either case the pod is not going to be bound. + RunPreBindPlugins(ctx context.Context, state *CycleState, pod *v1.Pod, nodeName string) *Status + + // RunPostBindPlugins runs the set of configured PostBind plugins. + RunPostBindPlugins(ctx context.Context, state *CycleState, pod *v1.Pod, nodeName string) + + // RunReservePluginsReserve runs the Reserve method of the set of + // configured Reserve plugins. If any of these calls returns an error, it + // does not continue running the remaining ones and returns the error. In + // such case, pod will not be scheduled. + RunReservePluginsReserve(ctx context.Context, state *CycleState, pod *v1.Pod, nodeName string) *Status + + // RunReservePluginsUnreserve runs the Unreserve method of the set of + // configured Reserve plugins. + RunReservePluginsUnreserve(ctx context.Context, state *CycleState, pod *v1.Pod, nodeName string) + + // RunPermitPlugins runs the set of configured Permit plugins. If any of these + // plugins returns a status other than "Success" or "Wait", it does not continue + // running the remaining plugins and returns an error. Otherwise, if any of the + // plugins returns "Wait", then this function will create and add waiting pod + // to a map of currently waiting pods and return status with "Wait" code. + // Pod will remain waiting pod for the minimum duration returned by the Permit plugins. + RunPermitPlugins(ctx context.Context, state *CycleState, pod *v1.Pod, nodeName string) *Status + + // WaitOnPermit will block, if the pod is a waiting pod, until the waiting pod is rejected or allowed. + WaitOnPermit(ctx context.Context, pod *v1.Pod) *Status + + // RunBindPlugins runs the set of configured Bind plugins. A Bind plugin may choose + // whether or not to handle the given Pod. If a Bind plugin chooses to skip the + // binding, it should return code=5("skip") status. Otherwise, it should return "Error" + // or "Success". If none of the plugins handled binding, RunBindPlugins returns + // code=5("skip") status. + RunBindPlugins(ctx context.Context, state *CycleState, pod *v1.Pod, nodeName string) *Status + + // HasFilterPlugins returns true if at least one Filter plugin is defined. + HasFilterPlugins() bool + + // HasPostFilterPlugins returns true if at least one PostFilter plugin is defined. + HasPostFilterPlugins() bool + + // HasScorePlugins returns true if at least one Score plugin is defined. + HasScorePlugins() bool + + // ListPlugins returns a map of extension point name to list of configured Plugins. + ListPlugins() *config.Plugins + + // ProfileName returns the profile name associated to a profile. + ProfileName() string + + // PercentageOfNodesToScore returns percentageOfNodesToScore associated to a profile. + PercentageOfNodesToScore() *int32 + + // SetPodNominator sets the PodNominator + SetPodNominator(nominator PodNominator) +} + +// Handle provides data and some tools that plugins can use. It is +// passed to the plugin factories at the time of plugin initialization. Plugins +// must store and use this handle to call framework functions. +type Handle interface { + // PodNominator abstracts operations to maintain nominated Pods. + PodNominator + // PluginsRunner abstracts operations to run some plugins. + PluginsRunner + // SnapshotSharedLister returns listers from the latest NodeInfo Snapshot. The snapshot + // is taken at the beginning of a scheduling cycle and remains unchanged until + // a pod finishes "Permit" point. There is no guarantee that the information + // remains unchanged in the binding phase of scheduling, so plugins in the binding + // cycle (pre-bind/bind/post-bind/un-reserve plugin) should not use it, + // otherwise a concurrent read/write error might occur, they should use scheduler + // cache instead. + SnapshotSharedLister() SharedLister + + // IterateOverWaitingPods acquires a read lock and iterates over the WaitingPods map. + IterateOverWaitingPods(callback func(WaitingPod)) + + // GetWaitingPod returns a waiting pod given its UID. + GetWaitingPod(uid types.UID) WaitingPod + + // RejectWaitingPod rejects a waiting pod given its UID. + // The return value indicates if the pod is waiting or not. + RejectWaitingPod(uid types.UID) bool + + // ClientSet returns a kubernetes clientSet. + ClientSet() clientset.Interface + + // KubeConfig returns the raw kube config. + KubeConfig() *restclient.Config + + // EventRecorder returns an event recorder. + EventRecorder() events.EventRecorder + + SharedInformerFactory() informers.SharedInformerFactory + + // RunFilterPluginsWithNominatedPods runs the set of configured filter plugins for nominated pod on the given node. + RunFilterPluginsWithNominatedPods(ctx context.Context, state *CycleState, pod *v1.Pod, info *NodeInfo) *Status + + // Extenders returns registered scheduler extenders. + Extenders() []Extender + + // Parallelizer returns a parallelizer holding parallelism for scheduler. + Parallelizer() parallelize.Parallelizer +} + +// PreFilterResult wraps needed info for scheduler framework to act upon PreFilter phase. +type PreFilterResult struct { + // The set of nodes that should be considered downstream; if nil then + // all nodes are eligible. + NodeNames sets.String +} + +func (p *PreFilterResult) AllNodes() bool { + return p == nil || p.NodeNames == nil +} + +func (p *PreFilterResult) Merge(in *PreFilterResult) *PreFilterResult { + if p.AllNodes() && in.AllNodes() { + return nil + } + + r := PreFilterResult{} + if p.AllNodes() { + r.NodeNames = in.NodeNames.Clone() + return &r + } + if in.AllNodes() { + r.NodeNames = p.NodeNames.Clone() + return &r + } + + r.NodeNames = p.NodeNames.Intersection(in.NodeNames) + return &r +} + +type NominatingMode int + +const ( + ModeNoop NominatingMode = iota + ModeOverride +) + +type NominatingInfo struct { + NominatedNodeName string + NominatingMode NominatingMode +} + +// PostFilterResult wraps needed info for scheduler framework to act upon PostFilter phase. +type PostFilterResult struct { + *NominatingInfo +} + +func NewPostFilterResultWithNominatedNode(name string) *PostFilterResult { + return &PostFilterResult{ + NominatingInfo: &NominatingInfo{ + NominatedNodeName: name, + NominatingMode: ModeOverride, + }, + } +} + +func (ni *NominatingInfo) Mode() NominatingMode { + if ni == nil { + return ModeNoop + } + return ni.NominatingMode +} + +// PodNominator abstracts operations to maintain nominated Pods. +type PodNominator interface { + // AddNominatedPod adds the given pod to the nominator or + // updates it if it already exists. + AddNominatedPod(pod *PodInfo, nominatingInfo *NominatingInfo) + // DeleteNominatedPodIfExists deletes nominatedPod from internal cache. It's a no-op if it doesn't exist. + DeleteNominatedPodIfExists(pod *v1.Pod) + // UpdateNominatedPod updates the with . + UpdateNominatedPod(oldPod *v1.Pod, newPodInfo *PodInfo) + // NominatedPodsForNode returns nominatedPods on the given node. + NominatedPodsForNode(nodeName string) []*PodInfo +} + +// PluginsRunner abstracts operations to run some plugins. +// This is used by preemption PostFilter plugins when evaluating the feasibility of +// scheduling the pod on nodes when certain running pods get evicted. +type PluginsRunner interface { + // RunPreScorePlugins runs the set of configured PreScore plugins. If any + // of these plugins returns any status other than "Success", the given pod is rejected. + RunPreScorePlugins(context.Context, *CycleState, *v1.Pod, []*v1.Node) *Status + // RunScorePlugins runs the set of configured scoring plugins. + // It returns a list that stores scores from each plugin and total score for each Node. + // It also returns *Status, which is set to non-success if any of the plugins returns + // a non-success status. + RunScorePlugins(context.Context, *CycleState, *v1.Pod, []*v1.Node) ([]NodePluginScores, *Status) + // RunFilterPlugins runs the set of configured Filter plugins for pod on + // the given node. Note that for the node being evaluated, the passed nodeInfo + // reference could be different from the one in NodeInfoSnapshot map (e.g., pods + // considered to be running on the node could be different). For example, during + // preemption, we may pass a copy of the original nodeInfo object that has some pods + // removed from it to evaluate the possibility of preempting them to + // schedule the target pod. + RunFilterPlugins(context.Context, *CycleState, *v1.Pod, *NodeInfo) PluginToStatus + // RunPreFilterExtensionAddPod calls the AddPod interface for the set of configured + // PreFilter plugins. It returns directly if any of the plugins return any + // status other than Success. + RunPreFilterExtensionAddPod(ctx context.Context, state *CycleState, podToSchedule *v1.Pod, podInfoToAdd *PodInfo, nodeInfo *NodeInfo) *Status + // RunPreFilterExtensionRemovePod calls the RemovePod interface for the set of configured + // PreFilter plugins. It returns directly if any of the plugins return any + // status other than Success. + RunPreFilterExtensionRemovePod(ctx context.Context, state *CycleState, podToSchedule *v1.Pod, podInfoToRemove *PodInfo, nodeInfo *NodeInfo) *Status +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/listers.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/listers.go new file mode 100644 index 000000000..4701bc522 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/listers.go @@ -0,0 +1,42 @@ +/* +Copyright 2019 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 framework + +// NodeInfoLister interface represents anything that can list/get NodeInfo objects from node name. +type NodeInfoLister interface { + // List returns the list of NodeInfos. + List() ([]*NodeInfo, error) + // HavePodsWithAffinityList returns the list of NodeInfos of nodes with pods with affinity terms. + HavePodsWithAffinityList() ([]*NodeInfo, error) + // HavePodsWithRequiredAntiAffinityList returns the list of NodeInfos of nodes with pods with required anti-affinity terms. + HavePodsWithRequiredAntiAffinityList() ([]*NodeInfo, error) + // Get returns the NodeInfo of the given node name. + Get(nodeName string) (*NodeInfo, error) +} + +// StorageInfoLister interface represents anything that handles storage-related operations and resources. +type StorageInfoLister interface { + // IsPVCUsedByPods returns true/false on whether the PVC is used by one or more scheduled pods, + // keyed in the format "namespace/name". + IsPVCUsedByPods(key string) bool +} + +// SharedLister groups scheduler-specific listers. +type SharedLister interface { + NodeInfos() NodeInfoLister + StorageInfos() StorageInfoLister +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/parallelize/error_channel.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/parallelize/error_channel.go new file mode 100644 index 000000000..2eff825ba --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/parallelize/error_channel.go @@ -0,0 +1,59 @@ +/* +Copyright 2019 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 parallelize + +import "context" + +// ErrorChannel supports non-blocking send and receive operation to capture error. +// A maximum of one error is kept in the channel and the rest of the errors sent +// are ignored, unless the existing error is received and the channel becomes empty +// again. +type ErrorChannel struct { + errCh chan error +} + +// SendError sends an error without blocking the sender. +func (e *ErrorChannel) SendError(err error) { + select { + case e.errCh <- err: + default: + } +} + +// SendErrorWithCancel sends an error without blocking the sender and calls +// cancel function. +func (e *ErrorChannel) SendErrorWithCancel(err error, cancel context.CancelFunc) { + e.SendError(err) + cancel() +} + +// ReceiveError receives an error from channel without blocking on the receiver. +func (e *ErrorChannel) ReceiveError() error { + select { + case err := <-e.errCh: + return err + default: + return nil + } +} + +// NewErrorChannel returns a new ErrorChannel. +func NewErrorChannel() *ErrorChannel { + return &ErrorChannel{ + errCh: make(chan error, 1), + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/parallelize/parallelism.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/parallelize/parallelism.go new file mode 100644 index 000000000..94441b97d --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/parallelize/parallelism.go @@ -0,0 +1,65 @@ +/* +Copyright 2020 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 parallelize + +import ( + "context" + "math" + + "k8s.io/client-go/util/workqueue" + "k8s.io/kubernetes/pkg/scheduler/metrics" +) + +// DefaultParallelism is the default parallelism used in scheduler. +const DefaultParallelism int = 16 + +// Parallelizer holds the parallelism for scheduler. +type Parallelizer struct { + parallelism int +} + +// NewParallelizer returns an object holding the parallelism. +func NewParallelizer(p int) Parallelizer { + return Parallelizer{parallelism: p} +} + +// chunkSizeFor returns a chunk size for the given number of items to use for +// parallel work. The size aims to produce good CPU utilization. +// returns max(1, min(sqrt(n), n/Parallelism)) +func chunkSizeFor(n, parallelism int) int { + s := int(math.Sqrt(float64(n))) + + if r := n/parallelism + 1; s > r { + s = r + } else if s < 1 { + s = 1 + } + return s +} + +// Until is a wrapper around workqueue.ParallelizeUntil to use in scheduling algorithms. +// A given operation will be a label that is recorded in the goroutine metric. +func (p Parallelizer) Until(ctx context.Context, pieces int, doWorkPiece workqueue.DoWorkPieceFunc, operation string) { + goroutinesMetric := metrics.Goroutines.WithLabelValues(operation) + withMetrics := func(piece int) { + goroutinesMetric.Inc() + doWorkPiece(piece) + goroutinesMetric.Dec() + } + + workqueue.ParallelizeUntil(ctx, p.parallelism, pieces, withMetrics, workqueue.WithChunkSize(chunkSizeFor(pieces, p.parallelism))) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/README.md b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/README.md new file mode 100644 index 000000000..6fba8bb84 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/README.md @@ -0,0 +1,3 @@ +# Scheduler Framework Plugins + +Moved [here](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-scheduling/scheduler_framework_plugins.md). diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultbinder/default_binder.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultbinder/default_binder.go new file mode 100644 index 000000000..e695e320d --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultbinder/default_binder.go @@ -0,0 +1,62 @@ +/* +Copyright 2020 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 defaultbinder + +import ( + "context" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog/v2" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" +) + +// Name of the plugin used in the plugin registry and configurations. +const Name = names.DefaultBinder + +// DefaultBinder binds pods to nodes using a k8s client. +type DefaultBinder struct { + handle framework.Handle +} + +var _ framework.BindPlugin = &DefaultBinder{} + +// New creates a DefaultBinder. +func New(_ runtime.Object, handle framework.Handle) (framework.Plugin, error) { + return &DefaultBinder{handle: handle}, nil +} + +// Name returns the name of the plugin. +func (b DefaultBinder) Name() string { + return Name +} + +// Bind binds pods to nodes using the k8s client. +func (b DefaultBinder) Bind(ctx context.Context, state *framework.CycleState, p *v1.Pod, nodeName string) *framework.Status { + klog.V(3).InfoS("Attempting to bind pod to node", "pod", klog.KObj(p), "node", klog.KRef("", nodeName)) + binding := &v1.Binding{ + ObjectMeta: metav1.ObjectMeta{Namespace: p.Namespace, Name: p.Name, UID: p.UID}, + Target: v1.ObjectReference{Kind: "Node", Name: nodeName}, + } + err := b.handle.ClientSet().CoreV1().Pods(binding.Namespace).Bind(ctx, binding, metav1.CreateOptions{}) + if err != nil { + return framework.AsStatus(err) + } + return nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultpreemption/default_preemption.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultpreemption/default_preemption.go new file mode 100644 index 000000000..91fc9ef9e --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultpreemption/default_preemption.go @@ -0,0 +1,317 @@ +/* +Copyright 2020 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 defaultpreemption + +import ( + "context" + "fmt" + "math/rand" + "sort" + + v1 "k8s.io/api/core/v1" + policy "k8s.io/api/policy/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/informers" + corelisters "k8s.io/client-go/listers/core/v1" + policylisters "k8s.io/client-go/listers/policy/v1" + corev1helpers "k8s.io/component-helpers/scheduling/corev1" + "k8s.io/klog/v2" + extenderv1 "k8s.io/kube-scheduler/extender/v1" + "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/kubernetes/pkg/scheduler/apis/config/validation" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" + "k8s.io/kubernetes/pkg/scheduler/framework/preemption" + "k8s.io/kubernetes/pkg/scheduler/metrics" + "k8s.io/kubernetes/pkg/scheduler/util" +) + +// Name of the plugin used in the plugin registry and configurations. +const Name = names.DefaultPreemption + +// DefaultPreemption is a PostFilter plugin implements the preemption logic. +type DefaultPreemption struct { + fh framework.Handle + args config.DefaultPreemptionArgs + podLister corelisters.PodLister + pdbLister policylisters.PodDisruptionBudgetLister +} + +var _ framework.PostFilterPlugin = &DefaultPreemption{} + +// Name returns name of the plugin. It is used in logs, etc. +func (pl *DefaultPreemption) Name() string { + return Name +} + +// New initializes a new plugin and returns it. +func New(dpArgs runtime.Object, fh framework.Handle, fts feature.Features) (framework.Plugin, error) { + args, ok := dpArgs.(*config.DefaultPreemptionArgs) + if !ok { + return nil, fmt.Errorf("got args of type %T, want *DefaultPreemptionArgs", dpArgs) + } + if err := validation.ValidateDefaultPreemptionArgs(nil, args); err != nil { + return nil, err + } + pl := DefaultPreemption{ + fh: fh, + args: *args, + podLister: fh.SharedInformerFactory().Core().V1().Pods().Lister(), + pdbLister: getPDBLister(fh.SharedInformerFactory()), + } + return &pl, nil +} + +// PostFilter invoked at the postFilter extension point. +func (pl *DefaultPreemption) PostFilter(ctx context.Context, state *framework.CycleState, pod *v1.Pod, m framework.NodeToStatusMap) (*framework.PostFilterResult, *framework.Status) { + defer func() { + metrics.PreemptionAttempts.Inc() + }() + + pe := preemption.Evaluator{ + PluginName: names.DefaultPreemption, + Handler: pl.fh, + PodLister: pl.podLister, + PdbLister: pl.pdbLister, + State: state, + Interface: pl, + } + + result, status := pe.Preempt(ctx, pod, m) + if status.Message() != "" { + return result, framework.NewStatus(status.Code(), "preemption: "+status.Message()) + } + return result, status +} + +// calculateNumCandidates returns the number of candidates the FindCandidates +// method must produce from dry running based on the constraints given by +// and . The number of +// candidates returned will never be greater than . +func (pl *DefaultPreemption) calculateNumCandidates(numNodes int32) int32 { + n := (numNodes * pl.args.MinCandidateNodesPercentage) / 100 + if n < pl.args.MinCandidateNodesAbsolute { + n = pl.args.MinCandidateNodesAbsolute + } + if n > numNodes { + n = numNodes + } + return n +} + +// GetOffsetAndNumCandidates chooses a random offset and calculates the number +// of candidates that should be shortlisted for dry running preemption. +func (pl *DefaultPreemption) GetOffsetAndNumCandidates(numNodes int32) (int32, int32) { + return rand.Int31n(numNodes), pl.calculateNumCandidates(numNodes) +} + +// This function is not applicable for out-of-tree preemption plugins that exercise +// different preemption candidates on the same nominated node. +func (pl *DefaultPreemption) CandidatesToVictimsMap(candidates []preemption.Candidate) map[string]*extenderv1.Victims { + m := make(map[string]*extenderv1.Victims) + for _, c := range candidates { + m[c.Name()] = c.Victims() + } + return m +} + +// SelectVictimsOnNode finds minimum set of pods on the given node that should be preempted in order to make enough room +// for "pod" to be scheduled. +func (pl *DefaultPreemption) SelectVictimsOnNode( + ctx context.Context, + state *framework.CycleState, + pod *v1.Pod, + nodeInfo *framework.NodeInfo, + pdbs []*policy.PodDisruptionBudget) ([]*v1.Pod, int, *framework.Status) { + var potentialVictims []*framework.PodInfo + removePod := func(rpi *framework.PodInfo) error { + if err := nodeInfo.RemovePod(rpi.Pod); err != nil { + return err + } + status := pl.fh.RunPreFilterExtensionRemovePod(ctx, state, pod, rpi, nodeInfo) + if !status.IsSuccess() { + return status.AsError() + } + return nil + } + addPod := func(api *framework.PodInfo) error { + nodeInfo.AddPodInfo(api) + status := pl.fh.RunPreFilterExtensionAddPod(ctx, state, pod, api, nodeInfo) + if !status.IsSuccess() { + return status.AsError() + } + return nil + } + // As the first step, remove all the lower priority pods from the node and + // check if the given pod can be scheduled. + podPriority := corev1helpers.PodPriority(pod) + for _, pi := range nodeInfo.Pods { + if corev1helpers.PodPriority(pi.Pod) < podPriority { + potentialVictims = append(potentialVictims, pi) + if err := removePod(pi); err != nil { + return nil, 0, framework.AsStatus(err) + } + } + } + + // No potential victims are found, and so we don't need to evaluate the node again since its state didn't change. + if len(potentialVictims) == 0 { + message := fmt.Sprintf("No preemption victims found for incoming pod") + return nil, 0, framework.NewStatus(framework.UnschedulableAndUnresolvable, message) + } + + // If the new pod does not fit after removing all the lower priority pods, + // we are almost done and this node is not suitable for preemption. The only + // condition that we could check is if the "pod" is failing to schedule due to + // inter-pod affinity to one or more victims, but we have decided not to + // support this case for performance reasons. Having affinity to lower + // priority pods is not a recommended configuration anyway. + if status := pl.fh.RunFilterPluginsWithNominatedPods(ctx, state, pod, nodeInfo); !status.IsSuccess() { + return nil, 0, status + } + var victims []*v1.Pod + numViolatingVictim := 0 + sort.Slice(potentialVictims, func(i, j int) bool { return util.MoreImportantPod(potentialVictims[i].Pod, potentialVictims[j].Pod) }) + // Try to reprieve as many pods as possible. We first try to reprieve the PDB + // violating victims and then other non-violating ones. In both cases, we start + // from the highest priority victims. + violatingVictims, nonViolatingVictims := filterPodsWithPDBViolation(potentialVictims, pdbs) + reprievePod := func(pi *framework.PodInfo) (bool, error) { + if err := addPod(pi); err != nil { + return false, err + } + status := pl.fh.RunFilterPluginsWithNominatedPods(ctx, state, pod, nodeInfo) + fits := status.IsSuccess() + if !fits { + if err := removePod(pi); err != nil { + return false, err + } + rpi := pi.Pod + victims = append(victims, rpi) + klog.V(5).InfoS("Pod is a potential preemption victim on node", "pod", klog.KObj(rpi), "node", klog.KObj(nodeInfo.Node())) + } + return fits, nil + } + for _, p := range violatingVictims { + if fits, err := reprievePod(p); err != nil { + return nil, 0, framework.AsStatus(err) + } else if !fits { + numViolatingVictim++ + } + } + // Now we try to reprieve non-violating victims. + for _, p := range nonViolatingVictims { + if _, err := reprievePod(p); err != nil { + return nil, 0, framework.AsStatus(err) + } + } + return victims, numViolatingVictim, framework.NewStatus(framework.Success) +} + +// PodEligibleToPreemptOthers returns one bool and one string. The bool +// indicates whether this pod should be considered for preempting other pods or +// not. The string includes the reason if this pod isn't eligible. +// If this pod has a preemptionPolicy of Never or has already preempted other +// pods and those are in their graceful termination period, it shouldn't be +// considered for preemption. +// We look at the node that is nominated for this pod and as long as there are +// terminating pods on the node, we don't consider this for preempting more pods. +func (pl *DefaultPreemption) PodEligibleToPreemptOthers(pod *v1.Pod, nominatedNodeStatus *framework.Status) (bool, string) { + if pod.Spec.PreemptionPolicy != nil && *pod.Spec.PreemptionPolicy == v1.PreemptNever { + return false, fmt.Sprint("not eligible due to preemptionPolicy=Never.") + } + nodeInfos := pl.fh.SnapshotSharedLister().NodeInfos() + nomNodeName := pod.Status.NominatedNodeName + if len(nomNodeName) > 0 { + // If the pod's nominated node is considered as UnschedulableAndUnresolvable by the filters, + // then the pod should be considered for preempting again. + if nominatedNodeStatus.Code() == framework.UnschedulableAndUnresolvable { + return true, "" + } + + if nodeInfo, _ := nodeInfos.Get(nomNodeName); nodeInfo != nil { + podPriority := corev1helpers.PodPriority(pod) + for _, p := range nodeInfo.Pods { + if p.Pod.DeletionTimestamp != nil && corev1helpers.PodPriority(p.Pod) < podPriority { + // There is a terminating pod on the nominated node. + return false, fmt.Sprint("not eligible due to a terminating pod on the nominated node.") + } + } + } + } + return true, "" +} + +// filterPodsWithPDBViolation groups the given "pods" into two groups of "violatingPods" +// and "nonViolatingPods" based on whether their PDBs will be violated if they are +// preempted. +// This function is stable and does not change the order of received pods. So, if it +// receives a sorted list, grouping will preserve the order of the input list. +func filterPodsWithPDBViolation(podInfos []*framework.PodInfo, pdbs []*policy.PodDisruptionBudget) (violatingPodInfos, nonViolatingPodInfos []*framework.PodInfo) { + pdbsAllowed := make([]int32, len(pdbs)) + for i, pdb := range pdbs { + pdbsAllowed[i] = pdb.Status.DisruptionsAllowed + } + + for _, podInfo := range podInfos { + pod := podInfo.Pod + pdbForPodIsViolated := false + // A pod with no labels will not match any PDB. So, no need to check. + if len(pod.Labels) != 0 { + for i, pdb := range pdbs { + if pdb.Namespace != pod.Namespace { + continue + } + selector, err := metav1.LabelSelectorAsSelector(pdb.Spec.Selector) + if err != nil { + // This object has an invalid selector, it does not match the pod + continue + } + // A PDB with a nil or empty selector matches nothing. + if selector.Empty() || !selector.Matches(labels.Set(pod.Labels)) { + continue + } + + // Existing in DisruptedPods means it has been processed in API server, + // we don't treat it as a violating case. + if _, exist := pdb.Status.DisruptedPods[pod.Name]; exist { + continue + } + // Only decrement the matched pdb when it's not in its ; + // otherwise we may over-decrement the budget number. + pdbsAllowed[i]-- + // We have found a matching PDB. + if pdbsAllowed[i] < 0 { + pdbForPodIsViolated = true + } + } + } + if pdbForPodIsViolated { + violatingPodInfos = append(violatingPodInfos, podInfo) + } else { + nonViolatingPodInfos = append(nonViolatingPodInfos, podInfo) + } + } + return violatingPodInfos, nonViolatingPodInfos +} + +func getPDBLister(informerFactory informers.SharedInformerFactory) policylisters.PodDisruptionBudgetLister { + return informerFactory.Policy().V1().PodDisruptionBudgets().Lister() +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/dynamicresources/OWNERS b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/dynamicresources/OWNERS new file mode 100644 index 000000000..98ccc3b80 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/dynamicresources/OWNERS @@ -0,0 +1,8 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +reviewers: + - klueska + - pohly + - bart0sh +labels: + - sig/node diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/dynamicresources/dynamicresources.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/dynamicresources/dynamicresources.go new file mode 100644 index 000000000..7d3c9f9f9 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/dynamicresources/dynamicresources.go @@ -0,0 +1,804 @@ +/* +Copyright 2022 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 dynamicresources + +import ( + "context" + "errors" + "fmt" + "sort" + "sync" + + v1 "k8s.io/api/core/v1" + resourcev1alpha1 "k8s.io/api/resource/v1alpha1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/client-go/kubernetes" + resourcev1alpha1listers "k8s.io/client-go/listers/resource/v1alpha1" + corev1helpers "k8s.io/component-helpers/scheduling/corev1" + "k8s.io/component-helpers/scheduling/corev1/nodeaffinity" + "k8s.io/dynamic-resource-allocation/resourceclaim" + "k8s.io/klog/v2" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" +) + +const ( + // Name is the name of the plugin used in Registry and configurations. + Name = names.DynamicResources + + stateKey framework.StateKey = Name +) + +// The state is initialized in PreFilter phase. Because we save the pointer in +// framework.CycleState, in the later phases we don't need to call Write method +// to update the value +type stateData struct { + // A copy of all claims for the Pod (i.e. 1:1 match with + // pod.Spec.ResourceClaims), initially with the status from the start + // of the scheduling cycle. Each claim instance is read-only because it + // might come from the informer cache. The instances get replaced when + // the plugin itself successfully does an Update. + // + // Empty if the Pod has no claims. + claims []*resourcev1alpha1.ResourceClaim + + // The AvailableOnNodes node filters of the claims converted from the + // v1 API to nodeaffinity.NodeSelector by PreFilter for repeated + // evaluation in Filter. Nil for claims which don't have it. + availableOnNodes []*nodeaffinity.NodeSelector + + // The indices of all claims that: + // - are allocated + // - use delayed allocation + // - were not available on at least one node + // + // Set in parallel during Filter, so write access there must be + // protected by the mutex. Used by PostFilter. + unavailableClaims sets.Int + + // A pointer to the PodScheduling object for the pod, if one exists. + // Gets set on demand. + // + // Conceptually, this object belongs into the scheduler framework + // where it might get shared by different plugins. But in practice, + // it is currently only used by dynamic provisioning and thus + // managed entirely here. + podScheduling *resourcev1alpha1.PodScheduling + + // podSchedulingDirty is true if the current copy was locally modified. + podSchedulingDirty bool + + mutex sync.Mutex +} + +func (d *stateData) Clone() framework.StateData { + return d +} + +func (d *stateData) updateClaimStatus(ctx context.Context, clientset kubernetes.Interface, index int, claim *resourcev1alpha1.ResourceClaim) error { + // TODO (#113700): replace with patch operation. Beware that patching must only succeed if the + // object has not been modified in parallel by someone else. + claim, err := clientset.ResourceV1alpha1().ResourceClaims(claim.Namespace).UpdateStatus(ctx, claim, metav1.UpdateOptions{}) + // TODO: metric for update results, with the operation ("set selected + // node", "set PotentialNodes", etc.) as one dimension. + if err != nil { + return fmt.Errorf("update resource claim: %w", err) + } + + // Remember the new instance. This is relevant when the plugin must + // update the same claim multiple times (for example, first reserve + // the claim, then later remove the reservation), because otherwise the second + // update would fail with a "was modified" error. + d.claims[index] = claim + + return nil +} + +// initializePodScheduling can be called concurrently. It returns an existing PodScheduling +// object if there is one already, retrieves one if not, or as a last resort creates +// one from scratch. +func (d *stateData) initializePodScheduling(ctx context.Context, pod *v1.Pod, podSchedulingLister resourcev1alpha1listers.PodSchedulingLister) (*resourcev1alpha1.PodScheduling, error) { + // TODO (#113701): check if this mutex locking can be avoided by calling initializePodScheduling during PreFilter. + d.mutex.Lock() + defer d.mutex.Unlock() + + if d.podScheduling != nil { + return d.podScheduling, nil + } + + podScheduling, err := podSchedulingLister.PodSchedulings(pod.Namespace).Get(pod.Name) + switch { + case apierrors.IsNotFound(err): + controller := true + podScheduling = &resourcev1alpha1.PodScheduling{ + ObjectMeta: metav1.ObjectMeta{ + Name: pod.Name, + Namespace: pod.Namespace, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: "v1", + Kind: "Pod", + Name: pod.Name, + UID: pod.UID, + Controller: &controller, + }, + }, + }, + } + err = nil + case err != nil: + return nil, err + default: + // We have an object, but it might be obsolete. + if !metav1.IsControlledBy(podScheduling, pod) { + return nil, fmt.Errorf("PodScheduling object with UID %s is not owned by Pod %s/%s", podScheduling.UID, pod.Namespace, pod.Name) + } + } + d.podScheduling = podScheduling + return podScheduling, err +} + +// publishPodScheduling creates or updates the PodScheduling object. +func (d *stateData) publishPodScheduling(ctx context.Context, clientset kubernetes.Interface, podScheduling *resourcev1alpha1.PodScheduling) error { + d.mutex.Lock() + defer d.mutex.Unlock() + + var err error + logger := klog.FromContext(ctx) + msg := "Updating PodScheduling" + if podScheduling.UID == "" { + msg = "Creating PodScheduling" + } + if loggerV := logger.V(6); loggerV.Enabled() { + // At a high enough log level, dump the entire object. + loggerV.Info(msg, "podschedulingDump", podScheduling) + } else { + logger.V(5).Info(msg, "podscheduling", klog.KObj(podScheduling)) + } + if podScheduling.UID == "" { + podScheduling, err = clientset.ResourceV1alpha1().PodSchedulings(podScheduling.Namespace).Create(ctx, podScheduling, metav1.CreateOptions{}) + } else { + // TODO (#113700): patch here to avoid racing with drivers which update the status. + podScheduling, err = clientset.ResourceV1alpha1().PodSchedulings(podScheduling.Namespace).Update(ctx, podScheduling, metav1.UpdateOptions{}) + } + if err != nil { + return err + } + d.podScheduling = podScheduling + d.podSchedulingDirty = false + return nil +} + +// storePodScheduling replaces the pod scheduling object in the state. +func (d *stateData) storePodScheduling(podScheduling *resourcev1alpha1.PodScheduling) { + d.mutex.Lock() + defer d.mutex.Unlock() + + d.podScheduling = podScheduling + d.podSchedulingDirty = true +} + +func statusForClaim(podScheduling *resourcev1alpha1.PodScheduling, podClaimName string) *resourcev1alpha1.ResourceClaimSchedulingStatus { + for _, status := range podScheduling.Status.ResourceClaims { + if status.Name == podClaimName { + return &status + } + } + return nil +} + +// dynamicResources is a plugin that ensures that ResourceClaims are allocated. +type dynamicResources struct { + enabled bool + clientset kubernetes.Interface + claimLister resourcev1alpha1listers.ResourceClaimLister + classLister resourcev1alpha1listers.ResourceClassLister + podSchedulingLister resourcev1alpha1listers.PodSchedulingLister +} + +// New initializes a new plugin and returns it. +func New(plArgs runtime.Object, fh framework.Handle, fts feature.Features) (framework.Plugin, error) { + if !fts.EnableDynamicResourceAllocation { + // Disabled, won't do anything. + return &dynamicResources{}, nil + } + + return &dynamicResources{ + enabled: true, + clientset: fh.ClientSet(), + claimLister: fh.SharedInformerFactory().Resource().V1alpha1().ResourceClaims().Lister(), + classLister: fh.SharedInformerFactory().Resource().V1alpha1().ResourceClasses().Lister(), + podSchedulingLister: fh.SharedInformerFactory().Resource().V1alpha1().PodSchedulings().Lister(), + }, nil +} + +var _ framework.PreFilterPlugin = &dynamicResources{} +var _ framework.FilterPlugin = &dynamicResources{} +var _ framework.PostFilterPlugin = &dynamicResources{} +var _ framework.PreScorePlugin = &dynamicResources{} +var _ framework.ReservePlugin = &dynamicResources{} +var _ framework.EnqueueExtensions = &dynamicResources{} +var _ framework.PostBindPlugin = &dynamicResources{} + +// Name returns name of the plugin. It is used in logs, etc. +func (pl *dynamicResources) Name() string { + return Name +} + +// EventsToRegister returns the possible events that may make a Pod +// failed by this plugin schedulable. +func (pl *dynamicResources) EventsToRegister() []framework.ClusterEvent { + if !pl.enabled { + return nil + } + + events := []framework.ClusterEvent{ + // Allocation is tracked in ResourceClaims, so any changes may make the pods schedulable. + {Resource: framework.ResourceClaim, ActionType: framework.Add | framework.Update}, + // When a driver has provided additional information, a pod waiting for that information + // may be schedulable. + // TODO (#113702): can we change this so that such an event does not trigger *all* pods? + // Yes: https://github.com/kubernetes/kubernetes/blob/abcbaed0784baf5ed2382aae9705a8918f2daa18/pkg/scheduler/eventhandlers.go#L70 + {Resource: framework.PodScheduling, ActionType: framework.Add | framework.Update}, + // A resource might depend on node labels for topology filtering. + // A new or updated node may make pods schedulable. + {Resource: framework.Node, ActionType: framework.Add | framework.UpdateNodeLabel}, + } + return events +} + +// podResourceClaims returns the ResourceClaims for all pod.Spec.PodResourceClaims. +func (pl *dynamicResources) podResourceClaims(pod *v1.Pod) ([]*resourcev1alpha1.ResourceClaim, error) { + claims := make([]*resourcev1alpha1.ResourceClaim, 0, len(pod.Spec.ResourceClaims)) + for _, resource := range pod.Spec.ResourceClaims { + claimName := resourceclaim.Name(pod, &resource) + isEphemeral := resource.Source.ResourceClaimTemplateName != nil + claim, err := pl.claimLister.ResourceClaims(pod.Namespace).Get(claimName) + if err != nil { + // The error usually has already enough context ("resourcevolumeclaim "myclaim" not found"), + // but we can do better for generic ephemeral inline volumes where that situation + // is normal directly after creating a pod. + if isEphemeral && apierrors.IsNotFound(err) { + err = fmt.Errorf("waiting for dynamic resource controller to create the resourceclaim %q", claimName) + } + return nil, err + } + + if claim.DeletionTimestamp != nil { + return nil, fmt.Errorf("resourceclaim %q is being deleted", claim.Name) + } + + if isEphemeral { + if err := resourceclaim.IsForPod(pod, claim); err != nil { + return nil, err + } + } + // We store the pointer as returned by the lister. The + // assumption is that if a claim gets modified while our code + // runs, the cache will store a new pointer, not mutate the + // existing object that we point to here. + claims = append(claims, claim) + } + return claims, nil +} + +// PreFilter invoked at the prefilter extension point to check if pod has all +// immediate claims bound. UnschedulableAndUnresolvable is returned if +// the pod cannot be scheduled at the moment on any node. +func (pl *dynamicResources) PreFilter(ctx context.Context, state *framework.CycleState, pod *v1.Pod) (*framework.PreFilterResult, *framework.Status) { + if !pl.enabled { + return nil, nil + } + logger := klog.FromContext(ctx) + + // If the pod does not reference any claim, we don't need to do + // anything for it. We just initialize an empty state to record that + // observation for the other functions. This gets updated below + // if we get that far. + s := &stateData{} + state.Write(stateKey, s) + + claims, err := pl.podResourceClaims(pod) + if err != nil { + return nil, statusUnschedulable(logger, err.Error()) + } + logger.V(5).Info("pod resource claims", "pod", klog.KObj(pod), "resourceclaims", klog.KObjs(claims)) + // If the pod does not reference any claim, we don't need to do + // anything for it. + if len(claims) == 0 { + return nil, nil + } + + s.availableOnNodes = make([]*nodeaffinity.NodeSelector, len(claims)) + for index, claim := range claims { + if claim.Spec.AllocationMode == resourcev1alpha1.AllocationModeImmediate && + claim.Status.Allocation == nil { + // This will get resolved by the resource driver. + return nil, statusUnschedulable(logger, "unallocated immediate resourceclaim", "pod", klog.KObj(pod), "resourceclaim", klog.KObj(claim)) + } + if claim.Status.DeallocationRequested { + // This will get resolved by the resource driver. + return nil, statusUnschedulable(logger, "resourceclaim must be reallocated", "pod", klog.KObj(pod), "resourceclaim", klog.KObj(claim)) + } + if claim.Status.Allocation != nil && + !resourceclaim.CanBeReserved(claim) && + !resourceclaim.IsReservedForPod(pod, claim) { + // Resource is in use. The pod has to wait. + return nil, statusUnschedulable(logger, "resourceclaim in use", "pod", klog.KObj(pod), "resourceclaim", klog.KObj(claim)) + } + if claim.Status.Allocation != nil && + claim.Status.Allocation.AvailableOnNodes != nil { + nodeSelector, err := nodeaffinity.NewNodeSelector(claim.Status.Allocation.AvailableOnNodes) + if err != nil { + return nil, statusError(logger, err) + } + s.availableOnNodes[index] = nodeSelector + } + } + + s.claims = claims + state.Write(stateKey, s) + return nil, nil +} + +// PreFilterExtensions returns prefilter extensions, pod add and remove. +func (pl *dynamicResources) PreFilterExtensions() framework.PreFilterExtensions { + return nil +} + +func getStateData(cs *framework.CycleState) (*stateData, error) { + state, err := cs.Read(stateKey) + if err != nil { + return nil, err + } + s, ok := state.(*stateData) + if !ok { + return nil, errors.New("unable to convert state into stateData") + } + return s, nil +} + +// Filter invoked at the filter extension point. +// It evaluates if a pod can fit due to the resources it requests, +// for both allocated and unallocated claims. +// +// For claims that are bound, then it checks that the node affinity is +// satisfied by the given node. +// +// For claims that are unbound, it checks whether the claim might get allocated +// for the node. +func (pl *dynamicResources) Filter(ctx context.Context, cs *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status { + if !pl.enabled { + return nil + } + state, err := getStateData(cs) + if err != nil { + return statusError(klog.FromContext(ctx), err) + } + if len(state.claims) == 0 { + return nil + } + + logger := klog.FromContext(ctx) + node := nodeInfo.Node() + + var unavailableClaims []int + for index, claim := range state.claims { + logger.V(10).Info("filtering based on resource claims of the pod", "pod", klog.KObj(pod), "node", klog.KObj(node), "resourceclaim", klog.KObj(claim)) + switch { + case claim.Status.Allocation != nil: + if nodeSelector := state.availableOnNodes[index]; nodeSelector != nil { + if !nodeSelector.Match(node) { + logger.V(5).Info("AvailableOnNodes does not match", "pod", klog.KObj(pod), "node", klog.KObj(node), "resourceclaim", klog.KObj(claim)) + unavailableClaims = append(unavailableClaims, index) + } + } + case claim.Status.DeallocationRequested: + // We shouldn't get here. PreFilter already checked this. + return statusUnschedulable(logger, "resourceclaim must be reallocated", "pod", klog.KObj(pod), "node", klog.KObj(node), "resourceclaim", klog.KObj(claim)) + case claim.Spec.AllocationMode == resourcev1alpha1.AllocationModeWaitForFirstConsumer: + // The ResourceClass might have a node filter. This is + // useful for trimming the initial set of potential + // nodes before we ask the driver(s) for information + // about the specific pod. + class, err := pl.classLister.Get(claim.Spec.ResourceClassName) + if err != nil { + // If the class does not exist, then allocation cannot proceed. + return statusError(logger, fmt.Errorf("look up resource class: %v", err)) + } + if class.SuitableNodes != nil { + // TODO (#113700): parse class.SuitableNodes once in PreFilter, reuse result. + matches, err := corev1helpers.MatchNodeSelectorTerms(node, class.SuitableNodes) + if err != nil { + return statusError(logger, fmt.Errorf("potential node filter: %v", err)) + } + if !matches { + return statusUnschedulable(logger, "excluded by resource class node filter", "pod", klog.KObj(pod), "node", klog.KObj(node), "resourceclass", klog.KObj(class)) + } + } + + // Now we need information from drivers. + podScheduling, err := state.initializePodScheduling(ctx, pod, pl.podSchedulingLister) + if err != nil { + return statusError(logger, err) + } + status := statusForClaim(podScheduling, pod.Spec.ResourceClaims[index].Name) + if status != nil { + for _, unsuitableNode := range status.UnsuitableNodes { + if node.Name == unsuitableNode { + return statusUnschedulable(logger, "resourceclaim cannot be allocated for the node (unsuitable)", "pod", klog.KObj(pod), "node", klog.KObj(node), "resourceclaim", klog.KObj(claim), "unsuitablenodes", status.UnsuitableNodes) + } + } + } + default: + // This should have been delayed allocation. Immediate + // allocation was already checked for in PreFilter. + return statusError(logger, fmt.Errorf("internal error, unexpected allocation mode %v", claim.Spec.AllocationMode)) + } + } + + if len(unavailableClaims) > 0 { + state.mutex.Lock() + defer state.mutex.Unlock() + if state.unavailableClaims == nil { + state.unavailableClaims = sets.NewInt() + } + + for index := range unavailableClaims { + claim := state.claims[index] + // Deallocation makes more sense for claims with + // delayed allocation. Claims with immediate allocation + // would just get allocated again for a random node, + // which is unlikely to help the pod. + if claim.Spec.AllocationMode == resourcev1alpha1.AllocationModeWaitForFirstConsumer { + state.unavailableClaims.Insert(unavailableClaims...) + } + } + return statusUnschedulable(logger, "resourceclaim not available on the node", "pod", klog.KObj(pod)) + } + + return nil +} + +// PostFilter checks whether there are allocated claims that could get +// deallocated to help get the Pod schedulable. If yes, it picks one and +// requests its deallocation. This only gets called when filtering found no +// suitable node. +func (pl *dynamicResources) PostFilter(ctx context.Context, cs *framework.CycleState, pod *v1.Pod, filteredNodeStatusMap framework.NodeToStatusMap) (*framework.PostFilterResult, *framework.Status) { + if !pl.enabled { + return nil, framework.NewStatus(framework.Unschedulable, "plugin disabled") + } + logger := klog.FromContext(ctx) + state, err := getStateData(cs) + if err != nil { + return nil, statusError(logger, err) + } + if len(state.claims) == 0 { + return nil, framework.NewStatus(framework.Unschedulable, "no new claims to deallocate") + } + + // Iterating over a map is random. This is intentional here, we want to + // pick one claim randomly because there is no better heuristic. + for index := range state.unavailableClaims { + claim := state.claims[index] + if len(claim.Status.ReservedFor) == 0 || + len(claim.Status.ReservedFor) == 1 && claim.Status.ReservedFor[0].UID == pod.UID { + claim := state.claims[index].DeepCopy() + claim.Status.DeallocationRequested = true + claim.Status.ReservedFor = nil + logger.V(5).Info("Requesting deallocation of ResourceClaim", "pod", klog.KObj(pod), "resourceclaim", klog.KObj(claim)) + if err := state.updateClaimStatus(ctx, pl.clientset, index, claim); err != nil { + return nil, statusError(logger, err) + } + return nil, nil + } + } + return nil, framework.NewStatus(framework.Unschedulable, "still not schedulable") +} + +// PreScore is passed a list of all nodes that would fit the pod. Not all +// claims are necessarily allocated yet, so here we can set the SuitableNodes +// field for those which are pending. +func (pl *dynamicResources) PreScore(ctx context.Context, cs *framework.CycleState, pod *v1.Pod, nodes []*v1.Node) *framework.Status { + if !pl.enabled { + return nil + } + state, err := getStateData(cs) + if err != nil { + return statusError(klog.FromContext(ctx), err) + } + if len(state.claims) == 0 { + return nil + } + + logger := klog.FromContext(ctx) + podScheduling, err := state.initializePodScheduling(ctx, pod, pl.podSchedulingLister) + if err != nil { + return statusError(logger, err) + } + pending := false + for _, claim := range state.claims { + if claim.Status.Allocation == nil { + pending = true + } + } + if pending && !haveAllNodes(podScheduling.Spec.PotentialNodes, nodes) { + // Remember the potential nodes. The object will get created or + // updated in Reserve. This is both an optimization and + // covers the case that PreScore doesn't get called when there + // is only a single node. + logger.V(5).Info("remembering potential nodes", "pod", klog.KObj(pod), "potentialnodes", klog.KObjSlice(nodes)) + podScheduling = podScheduling.DeepCopy() + numNodes := len(nodes) + if numNodes > resourcev1alpha1.PodSchedulingNodeListMaxSize { + numNodes = resourcev1alpha1.PodSchedulingNodeListMaxSize + } + podScheduling.Spec.PotentialNodes = make([]string, 0, numNodes) + if numNodes == len(nodes) { + // Copy all node names. + for _, node := range nodes { + podScheduling.Spec.PotentialNodes = append(podScheduling.Spec.PotentialNodes, node.Name) + } + } else { + // Select a random subset of the nodes to comply with + // the PotentialNodes length limit. Randomization is + // done for us by Go which iterates over map entries + // randomly. + nodeNames := map[string]struct{}{} + for _, node := range nodes { + nodeNames[node.Name] = struct{}{} + } + for nodeName := range nodeNames { + if len(podScheduling.Spec.PotentialNodes) >= resourcev1alpha1.PodSchedulingNodeListMaxSize { + break + } + podScheduling.Spec.PotentialNodes = append(podScheduling.Spec.PotentialNodes, nodeName) + } + } + sort.Strings(podScheduling.Spec.PotentialNodes) + state.storePodScheduling(podScheduling) + } + logger.V(5).Info("all potential nodes already set", "pod", klog.KObj(pod), "potentialnodes", nodes) + return nil +} + +func haveAllNodes(nodeNames []string, nodes []*v1.Node) bool { + for _, node := range nodes { + if !haveNode(nodeNames, node.Name) { + return false + } + } + return true +} + +func haveNode(nodeNames []string, nodeName string) bool { + for _, n := range nodeNames { + if n == nodeName { + return true + } + } + return false +} + +// Reserve reserves claims for the pod. +func (pl *dynamicResources) Reserve(ctx context.Context, cs *framework.CycleState, pod *v1.Pod, nodeName string) *framework.Status { + if !pl.enabled { + return nil + } + state, err := getStateData(cs) + if err != nil { + return statusError(klog.FromContext(ctx), err) + } + if len(state.claims) == 0 { + return nil + } + + numDelayedAllocationPending := 0 + numClaimsWithStatusInfo := 0 + logger := klog.FromContext(ctx) + podScheduling, err := state.initializePodScheduling(ctx, pod, pl.podSchedulingLister) + if err != nil { + return statusError(logger, err) + } + for index, claim := range state.claims { + if claim.Status.Allocation != nil { + // Allocated, but perhaps not reserved yet. + if resourceclaim.IsReservedForPod(pod, claim) { + logger.V(5).Info("is reserved", "pod", klog.KObj(pod), "node", klog.ObjectRef{Name: nodeName}, "resourceclaim", klog.KObj(claim)) + continue + } + claim := claim.DeepCopy() + claim.Status.ReservedFor = append(claim.Status.ReservedFor, + resourcev1alpha1.ResourceClaimConsumerReference{ + Resource: "pods", + Name: pod.Name, + UID: pod.UID, + }) + logger.V(5).Info("reserve", "pod", klog.KObj(pod), "node", klog.ObjectRef{Name: nodeName}, "resourceclaim", klog.KObj(claim)) + _, err := pl.clientset.ResourceV1alpha1().ResourceClaims(claim.Namespace).UpdateStatus(ctx, claim, metav1.UpdateOptions{}) + // TODO: metric for update errors. + if err != nil { + return statusError(logger, err) + } + // If we get here, we know that reserving the claim for + // the pod worked and we can proceed with scheduling + // it. + } else { + // Must be delayed allocation. + numDelayedAllocationPending++ + + // Did the driver provide information that steered node + // selection towards a node that it can support? + if statusForClaim(podScheduling, pod.Spec.ResourceClaims[index].Name) != nil { + numClaimsWithStatusInfo++ + } + } + } + + if numDelayedAllocationPending == 0 { + // Nothing left to do. + return nil + } + + podSchedulingDirty := state.podSchedulingDirty + if len(podScheduling.Spec.PotentialNodes) == 0 { + // PreScore was not called, probably because there was + // only one candidate. We need to ask whether that + // node is suitable, otherwise the scheduler will pick + // it forever even when it cannot satisfy the claim. + podScheduling = podScheduling.DeepCopy() + podScheduling.Spec.PotentialNodes = []string{nodeName} + logger.V(5).Info("asking for information about single potential node", "pod", klog.KObj(pod), "node", klog.ObjectRef{Name: nodeName}) + podSchedulingDirty = true + } + + // When there is only one pending resource, we can go ahead with + // requesting allocation even when we don't have the information from + // the driver yet. Otherwise we wait for information before blindly + // making a decision that might have to be reversed later. + if numDelayedAllocationPending == 1 || numClaimsWithStatusInfo == numDelayedAllocationPending { + podScheduling = podScheduling.DeepCopy() + // TODO: can we increase the chance that the scheduler picks + // the same node as before when allocation is on-going, + // assuming that that node still fits the pod? Picking a + // different node may lead to some claims being allocated for + // one node and others for another, which then would have to be + // resolved with deallocation. + podScheduling.Spec.SelectedNode = nodeName + logger.V(5).Info("start allocation", "pod", klog.KObj(pod), "node", klog.ObjectRef{Name: nodeName}) + if err := state.publishPodScheduling(ctx, pl.clientset, podScheduling); err != nil { + return statusError(logger, err) + } + return statusUnschedulable(logger, "waiting for resource driver to allocate resource", "pod", klog.KObj(pod), "node", klog.ObjectRef{Name: nodeName}) + } + + // May have been modified earlier in PreScore or above. + if podSchedulingDirty { + if err := state.publishPodScheduling(ctx, pl.clientset, podScheduling); err != nil { + return statusError(logger, err) + } + } + + // More than one pending claim and not enough information about all of them. + // + // TODO: can or should we ensure that scheduling gets aborted while + // waiting for resources *before* triggering delayed volume + // provisioning? On the one hand, volume provisioning is currently + // irreversible, so it better should come last. On the other hand, + // triggering both in parallel might be faster. + return statusUnschedulable(logger, "waiting for resource driver to provide information", "pod", klog.KObj(pod)) +} + +// Unreserve clears the ReservedFor field for all claims. +// It's idempotent, and does nothing if no state found for the given pod. +func (pl *dynamicResources) Unreserve(ctx context.Context, cs *framework.CycleState, pod *v1.Pod, nodeName string) { + if !pl.enabled { + return + } + state, err := getStateData(cs) + if err != nil { + return + } + if len(state.claims) == 0 { + return + } + + logger := klog.FromContext(ctx) + for index, claim := range state.claims { + if claim.Status.Allocation != nil && + resourceclaim.IsReservedForPod(pod, claim) { + // Remove pod from ReservedFor. + claim := claim.DeepCopy() + reservedFor := make([]resourcev1alpha1.ResourceClaimConsumerReference, 0, len(claim.Status.ReservedFor)-1) + for _, reserved := range claim.Status.ReservedFor { + // TODO: can UID be assumed to be unique all resources or do we also need to compare Group/Version/Resource? + if reserved.UID != pod.UID { + reservedFor = append(reservedFor, reserved) + } + } + claim.Status.ReservedFor = reservedFor + logger.V(5).Info("unreserve", "resourceclaim", klog.KObj(claim)) + if err := state.updateClaimStatus(ctx, pl.clientset, index, claim); err != nil { + // We will get here again when pod scheduling + // is retried. + logger.Error(err, "unreserve", "resourceclaim", klog.KObj(claim)) + } + } + } +} + +// PostBind is called after a pod is successfully bound to a node. Now we are +// sure that a PodScheduling object, if it exists, is definitely not going to +// be needed anymore and can delete it. This is a one-shot thing, there won't +// be any retries. This is okay because it should usually work and in those +// cases where it doesn't, the garbage collector will eventually clean up. +func (pl *dynamicResources) PostBind(ctx context.Context, cs *framework.CycleState, pod *v1.Pod, nodeName string) { + if !pl.enabled { + return + } + state, err := getStateData(cs) + if err != nil { + return + } + if len(state.claims) == 0 { + return + } + + // We cannot know for sure whether the PodScheduling object exists. We + // might have created it in the previous pod scheduling cycle and not + // have it in our informer cache yet. Let's try to delete, just to be + // on the safe side. + logger := klog.FromContext(ctx) + err = pl.clientset.ResourceV1alpha1().PodSchedulings(pod.Namespace).Delete(ctx, pod.Name, metav1.DeleteOptions{}) + switch { + case apierrors.IsNotFound(err): + logger.V(5).Info("no PodScheduling object to delete") + case err != nil: + logger.Error(err, "delete PodScheduling") + default: + logger.V(5).Info("PodScheduling object deleted") + } +} + +// statusUnschedulable ensures that there is a log message associated with the +// line where the status originated. +func statusUnschedulable(logger klog.Logger, reason string, kv ...interface{}) *framework.Status { + if loggerV := logger.V(5); loggerV.Enabled() { + helper, loggerV := loggerV.WithCallStackHelper() + helper() + kv = append(kv, "reason", reason) + // nolint: logcheck // warns because it cannot check key/values + loggerV.Info("pod unschedulable", kv...) + } + return framework.NewStatus(framework.UnschedulableAndUnresolvable, reason) +} + +// statusError ensures that there is a log message associated with the +// line where the error originated. +func statusError(logger klog.Logger, err error, kv ...interface{}) *framework.Status { + if loggerV := logger.V(5); loggerV.Enabled() { + helper, loggerV := loggerV.WithCallStackHelper() + helper() + // nolint: logcheck // warns because it cannot check key/values + loggerV.Error(err, "dynamic resource plugin failed", kv...) + } + return framework.AsStatus(err) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature/feature.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature/feature.go new file mode 100644 index 000000000..e0790a681 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature/feature.go @@ -0,0 +1,30 @@ +/* +Copyright 2021 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 feature + +// Features carries feature gate values used by various plugins. +// This struct allows us to break the dependency of the plugins on +// the internal k8s features pkg. +type Features struct { + EnableDynamicResourceAllocation bool + EnableReadWriteOncePod bool + EnableVolumeCapacityPriority bool + EnableMinDomainsInPodTopologySpread bool + EnableNodeInclusionPolicyInPodTopologySpread bool + EnableMatchLabelKeysInPodTopologySpread bool + EnablePodSchedulingReadiness bool +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper/normalize_score.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper/normalize_score.go new file mode 100644 index 000000000..3d35ca304 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper/normalize_score.go @@ -0,0 +1,55 @@ +/* +Copyright 2019 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 helper + +import ( + "k8s.io/kubernetes/pkg/scheduler/framework" +) + +// DefaultNormalizeScore generates a Normalize Score function that can normalize the +// scores from [0, max(scores)] to [0, maxPriority]. If reverse is set to true, it +// reverses the scores by subtracting it from maxPriority. +// Note: The input scores are always assumed to be non-negative integers. +func DefaultNormalizeScore(maxPriority int64, reverse bool, scores framework.NodeScoreList) *framework.Status { + var maxCount int64 + for i := range scores { + if scores[i].Score > maxCount { + maxCount = scores[i].Score + } + } + + if maxCount == 0 { + if reverse { + for i := range scores { + scores[i].Score = maxPriority + } + } + return nil + } + + for i := range scores { + score := scores[i].Score + + score = maxPriority * score / maxCount + if reverse { + score = maxPriority - score + } + + scores[i].Score = score + } + return nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper/shape_score.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper/shape_score.go new file mode 100644 index 000000000..f12488b14 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper/shape_score.go @@ -0,0 +1,52 @@ +/* +Copyright 2021 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 helper + +// FunctionShape represents a collection of FunctionShapePoint. +type FunctionShape []FunctionShapePoint + +// FunctionShapePoint represents a shape point. +type FunctionShapePoint struct { + // Utilization is function argument. + Utilization int64 + // Score is function value. + Score int64 +} + +// BuildBrokenLinearFunction creates a function which is built using linear segments. Segments are defined via shape array. +// Shape[i].Utilization slice represents points on "Utilization" axis where different segments meet. +// Shape[i].Score represents function values at meeting points. +// +// function f(p) is defined as: +// +// shape[0].Score for p < shape[0].Utilization +// shape[n-1].Score for p > shape[n-1].Utilization +// +// and linear between points (p < shape[i].Utilization) +func BuildBrokenLinearFunction(shape FunctionShape) func(int64) int64 { + return func(p int64) int64 { + for i := 0; i < len(shape); i++ { + if p <= int64(shape[i].Utilization) { + if i == 0 { + return shape[0].Score + } + return shape[i-1].Score + (shape[i].Score-shape[i-1].Score)*(p-shape[i-1].Utilization)/(shape[i].Utilization-shape[i-1].Utilization) + } + } + return shape[len(shape)-1].Score + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper/spread.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper/spread.go new file mode 100644 index 000000000..636bcaee4 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper/spread.go @@ -0,0 +1,116 @@ +/* +Copyright 2020 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 helper + +import ( + appsv1 "k8s.io/api/apps/v1" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime/schema" + appslisters "k8s.io/client-go/listers/apps/v1" + corelisters "k8s.io/client-go/listers/core/v1" +) + +var ( + rcKind = v1.SchemeGroupVersion.WithKind("ReplicationController") + rsKind = appsv1.SchemeGroupVersion.WithKind("ReplicaSet") + ssKind = appsv1.SchemeGroupVersion.WithKind("StatefulSet") +) + +// DefaultSelector returns a selector deduced from the Services, Replication +// Controllers, Replica Sets, and Stateful Sets matching the given pod. +func DefaultSelector( + pod *v1.Pod, + sl corelisters.ServiceLister, + cl corelisters.ReplicationControllerLister, + rsl appslisters.ReplicaSetLister, + ssl appslisters.StatefulSetLister, +) labels.Selector { + labelSet := make(labels.Set) + // Since services, RCs, RSs and SSs match the pod, they won't have conflicting + // labels. Merging is safe. + + if services, err := GetPodServices(sl, pod); err == nil { + for _, service := range services { + labelSet = labels.Merge(labelSet, service.Spec.Selector) + } + } + selector := labelSet.AsSelector() + + owner := metav1.GetControllerOfNoCopy(pod) + if owner == nil { + return selector + } + + gv, err := schema.ParseGroupVersion(owner.APIVersion) + if err != nil { + return selector + } + + gvk := gv.WithKind(owner.Kind) + switch gvk { + case rcKind: + if rc, err := cl.ReplicationControllers(pod.Namespace).Get(owner.Name); err == nil { + labelSet = labels.Merge(labelSet, rc.Spec.Selector) + selector = labelSet.AsSelector() + } + case rsKind: + if rs, err := rsl.ReplicaSets(pod.Namespace).Get(owner.Name); err == nil { + if other, err := metav1.LabelSelectorAsSelector(rs.Spec.Selector); err == nil { + if r, ok := other.Requirements(); ok { + selector = selector.Add(r...) + } + } + } + case ssKind: + if ss, err := ssl.StatefulSets(pod.Namespace).Get(owner.Name); err == nil { + if other, err := metav1.LabelSelectorAsSelector(ss.Spec.Selector); err == nil { + if r, ok := other.Requirements(); ok { + selector = selector.Add(r...) + } + } + } + default: + // Not owned by a supported controller. + } + + return selector +} + +// GetPodServices gets the services that have the selector that match the labels on the given pod. +func GetPodServices(sl corelisters.ServiceLister, pod *v1.Pod) ([]*v1.Service, error) { + allServices, err := sl.Services(pod.Namespace).List(labels.Everything()) + if err != nil { + return nil, err + } + + var services []*v1.Service + for i := range allServices { + service := allServices[i] + if service.Spec.Selector == nil { + // services with nil selectors match nothing, not everything. + continue + } + selector := labels.Set(service.Spec.Selector).AsSelectorPreValidated() + if selector.Matches(labels.Set(pod.Labels)) { + services = append(services, service) + } + } + + return services, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper/taint.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper/taint.go new file mode 100644 index 000000000..7502d9ce4 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper/taint.go @@ -0,0 +1,28 @@ +/* +Copyright 2022 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 helper + +import v1 "k8s.io/api/core/v1" + +// DoNotScheduleTaintsFilterFunc returns the filter function that can +// filter out the node taints that reject scheduling Pod on a Node. +func DoNotScheduleTaintsFilterFunc() func(t *v1.Taint) bool { + return func(t *v1.Taint) bool { + // PodToleratesNodeTaints is only interested in NoSchedule and NoExecute taints. + return t.Effect == v1.TaintEffectNoSchedule || t.Effect == v1.TaintEffectNoExecute + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/imagelocality/image_locality.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/imagelocality/image_locality.go new file mode 100644 index 000000000..9eeab05b2 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/imagelocality/image_locality.go @@ -0,0 +1,126 @@ +/* +Copyright 2019 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 imagelocality + +import ( + "context" + "fmt" + "strings" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" +) + +// The two thresholds are used as bounds for the image score range. They correspond to a reasonable size range for +// container images compressed and stored in registries; 90%ile of images on dockerhub drops into this range. +const ( + mb int64 = 1024 * 1024 + minThreshold int64 = 23 * mb + maxContainerThreshold int64 = 1000 * mb +) + +// ImageLocality is a score plugin that favors nodes that already have requested pod container's images. +type ImageLocality struct { + handle framework.Handle +} + +var _ framework.ScorePlugin = &ImageLocality{} + +// Name is the name of the plugin used in the plugin registry and configurations. +const Name = names.ImageLocality + +// Name returns name of the plugin. It is used in logs, etc. +func (pl *ImageLocality) Name() string { + return Name +} + +// Score invoked at the score extension point. +func (pl *ImageLocality) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) { + nodeInfo, err := pl.handle.SnapshotSharedLister().NodeInfos().Get(nodeName) + if err != nil { + return 0, framework.AsStatus(fmt.Errorf("getting node %q from Snapshot: %w", nodeName, err)) + } + + nodeInfos, err := pl.handle.SnapshotSharedLister().NodeInfos().List() + if err != nil { + return 0, framework.AsStatus(err) + } + totalNumNodes := len(nodeInfos) + + score := calculatePriority(sumImageScores(nodeInfo, pod.Spec.Containers, totalNumNodes), len(pod.Spec.Containers)) + + return score, nil +} + +// ScoreExtensions of the Score plugin. +func (pl *ImageLocality) ScoreExtensions() framework.ScoreExtensions { + return nil +} + +// New initializes a new plugin and returns it. +func New(_ runtime.Object, h framework.Handle) (framework.Plugin, error) { + return &ImageLocality{handle: h}, nil +} + +// calculatePriority returns the priority of a node. Given the sumScores of requested images on the node, the node's +// priority is obtained by scaling the maximum priority value with a ratio proportional to the sumScores. +func calculatePriority(sumScores int64, numContainers int) int64 { + maxThreshold := maxContainerThreshold * int64(numContainers) + if sumScores < minThreshold { + sumScores = minThreshold + } else if sumScores > maxThreshold { + sumScores = maxThreshold + } + + return int64(framework.MaxNodeScore) * (sumScores - minThreshold) / (maxThreshold - minThreshold) +} + +// sumImageScores returns the sum of image scores of all the containers that are already on the node. +// Each image receives a raw score of its size, scaled by scaledImageScore. The raw scores are later used to calculate +// the final score. Note that the init containers are not considered for it's rare for users to deploy huge init containers. +func sumImageScores(nodeInfo *framework.NodeInfo, containers []v1.Container, totalNumNodes int) int64 { + var sum int64 + for _, container := range containers { + if state, ok := nodeInfo.ImageStates[normalizedImageName(container.Image)]; ok { + sum += scaledImageScore(state, totalNumNodes) + } + } + return sum +} + +// scaledImageScore returns an adaptively scaled score for the given state of an image. +// The size of the image is used as the base score, scaled by a factor which considers how much nodes the image has "spread" to. +// This heuristic aims to mitigate the undesirable "node heating problem", i.e., pods get assigned to the same or +// a few nodes due to image locality. +func scaledImageScore(imageState *framework.ImageStateSummary, totalNumNodes int) int64 { + spread := float64(imageState.NumNodes) / float64(totalNumNodes) + return int64(float64(imageState.Size) * spread) +} + +// normalizedImageName returns the CRI compliant name for a given image. +// TODO: cover the corner cases of missed matches, e.g, +// 1. Using Docker as runtime and docker.io/library/test:tag in pod spec, but only test:tag will present in node status +// 2. Using the implicit registry, i.e., test:tag or library/test:tag in pod spec but only docker.io/library/test:tag +// in node status; note that if users consistently use one registry format, this should not happen. +func normalizedImageName(name string) string { + if strings.LastIndex(name, ":") <= strings.LastIndex(name, "/") { + name = name + ":latest" + } + return name +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity/filtering.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity/filtering.go new file mode 100644 index 000000000..b84fc8a78 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity/filtering.go @@ -0,0 +1,390 @@ +/* +Copyright 2019 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 interpodaffinity + +import ( + "context" + "fmt" + "sync/atomic" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/klog/v2" + "k8s.io/kubernetes/pkg/scheduler/framework" +) + +const ( + // preFilterStateKey is the key in CycleState to InterPodAffinity pre-computed data for Filtering. + // Using the name of the plugin will likely help us avoid collisions with other plugins. + preFilterStateKey = "PreFilter" + Name + + // ErrReasonExistingAntiAffinityRulesNotMatch is used for ExistingPodsAntiAffinityRulesNotMatch predicate error. + ErrReasonExistingAntiAffinityRulesNotMatch = "node(s) didn't satisfy existing pods anti-affinity rules" + // ErrReasonAffinityRulesNotMatch is used for PodAffinityRulesNotMatch predicate error. + ErrReasonAffinityRulesNotMatch = "node(s) didn't match pod affinity rules" + // ErrReasonAntiAffinityRulesNotMatch is used for PodAntiAffinityRulesNotMatch predicate error. + ErrReasonAntiAffinityRulesNotMatch = "node(s) didn't match pod anti-affinity rules" +) + +// preFilterState computed at PreFilter and used at Filter. +type preFilterState struct { + // A map of topology pairs to the number of existing pods that has anti-affinity terms that match the "pod". + existingAntiAffinityCounts topologyToMatchedTermCount + // A map of topology pairs to the number of existing pods that match the affinity terms of the "pod". + affinityCounts topologyToMatchedTermCount + // A map of topology pairs to the number of existing pods that match the anti-affinity terms of the "pod". + antiAffinityCounts topologyToMatchedTermCount + // podInfo of the incoming pod. + podInfo *framework.PodInfo + // A copy of the incoming pod's namespace labels. + namespaceLabels labels.Set +} + +// Clone the prefilter state. +func (s *preFilterState) Clone() framework.StateData { + if s == nil { + return nil + } + + copy := preFilterState{} + copy.affinityCounts = s.affinityCounts.clone() + copy.antiAffinityCounts = s.antiAffinityCounts.clone() + copy.existingAntiAffinityCounts = s.existingAntiAffinityCounts.clone() + // No need to deep copy the podInfo because it shouldn't change. + copy.podInfo = s.podInfo + copy.namespaceLabels = s.namespaceLabels + return © +} + +// updateWithPod updates the preFilterState counters with the (anti)affinity matches for the given podInfo. +func (s *preFilterState) updateWithPod(pInfo *framework.PodInfo, node *v1.Node, multiplier int64) { + if s == nil { + return + } + + s.existingAntiAffinityCounts.updateWithAntiAffinityTerms(pInfo.RequiredAntiAffinityTerms, s.podInfo.Pod, s.namespaceLabels, node, multiplier) + s.affinityCounts.updateWithAffinityTerms(s.podInfo.RequiredAffinityTerms, pInfo.Pod, node, multiplier) + // The incoming pod's terms have the namespaceSelector merged into the namespaces, and so + // here we don't lookup the updated pod's namespace labels, hence passing nil for nsLabels. + s.antiAffinityCounts.updateWithAntiAffinityTerms(s.podInfo.RequiredAntiAffinityTerms, pInfo.Pod, nil, node, multiplier) +} + +type topologyPair struct { + key string + value string +} +type topologyToMatchedTermCount map[topologyPair]int64 + +func (m topologyToMatchedTermCount) append(toAppend topologyToMatchedTermCount) { + for pair := range toAppend { + m[pair] += toAppend[pair] + } +} + +func (m topologyToMatchedTermCount) clone() topologyToMatchedTermCount { + copy := make(topologyToMatchedTermCount, len(m)) + copy.append(m) + return copy +} + +func (m topologyToMatchedTermCount) update(node *v1.Node, tk string, value int64) { + if tv, ok := node.Labels[tk]; ok { + pair := topologyPair{key: tk, value: tv} + m[pair] += value + // value could be negative, hence we delete the entry if it is down to zero. + if m[pair] == 0 { + delete(m, pair) + } + } +} + +// updates the topologyToMatchedTermCount map with the specified value +// for each affinity term if "targetPod" matches ALL terms. +func (m topologyToMatchedTermCount) updateWithAffinityTerms( + terms []framework.AffinityTerm, pod *v1.Pod, node *v1.Node, value int64) { + if podMatchesAllAffinityTerms(terms, pod) { + for _, t := range terms { + m.update(node, t.TopologyKey, value) + } + } +} + +// updates the topologyToMatchedTermCount map with the specified value +// for each anti-affinity term matched the target pod. +func (m topologyToMatchedTermCount) updateWithAntiAffinityTerms(terms []framework.AffinityTerm, pod *v1.Pod, nsLabels labels.Set, node *v1.Node, value int64) { + // Check anti-affinity terms. + for _, t := range terms { + if t.Matches(pod, nsLabels) { + m.update(node, t.TopologyKey, value) + } + } +} + +// returns true IFF the given pod matches all the given terms. +func podMatchesAllAffinityTerms(terms []framework.AffinityTerm, pod *v1.Pod) bool { + if len(terms) == 0 { + return false + } + for _, t := range terms { + // The incoming pod NamespaceSelector was merged into the Namespaces set, and so + // we are not explicitly passing in namespace labels. + if !t.Matches(pod, nil) { + return false + } + } + return true +} + +// calculates the following for each existing pod on each node: +// (1) Whether it has PodAntiAffinity +// (2) Whether any AffinityTerm matches the incoming pod +func (pl *InterPodAffinity) getExistingAntiAffinityCounts(ctx context.Context, pod *v1.Pod, nsLabels labels.Set, nodes []*framework.NodeInfo) topologyToMatchedTermCount { + topoMaps := make([]topologyToMatchedTermCount, len(nodes)) + index := int32(-1) + processNode := func(i int) { + nodeInfo := nodes[i] + node := nodeInfo.Node() + if node == nil { + klog.ErrorS(nil, "Node not found") + return + } + topoMap := make(topologyToMatchedTermCount) + for _, existingPod := range nodeInfo.PodsWithRequiredAntiAffinity { + topoMap.updateWithAntiAffinityTerms(existingPod.RequiredAntiAffinityTerms, pod, nsLabels, node, 1) + } + if len(topoMap) != 0 { + topoMaps[atomic.AddInt32(&index, 1)] = topoMap + } + } + pl.parallelizer.Until(ctx, len(nodes), processNode, pl.Name()) + + result := make(topologyToMatchedTermCount) + for i := 0; i <= int(index); i++ { + result.append(topoMaps[i]) + } + + return result +} + +// finds existing Pods that match affinity terms of the incoming pod's (anti)affinity terms. +// It returns a topologyToMatchedTermCount that are checked later by the affinity +// predicate. With this topologyToMatchedTermCount available, the affinity predicate does not +// need to check all the pods in the cluster. +func (pl *InterPodAffinity) getIncomingAffinityAntiAffinityCounts(ctx context.Context, podInfo *framework.PodInfo, allNodes []*framework.NodeInfo) (topologyToMatchedTermCount, topologyToMatchedTermCount) { + affinityCounts := make(topologyToMatchedTermCount) + antiAffinityCounts := make(topologyToMatchedTermCount) + if len(podInfo.RequiredAffinityTerms) == 0 && len(podInfo.RequiredAntiAffinityTerms) == 0 { + return affinityCounts, antiAffinityCounts + } + + affinityCountsList := make([]topologyToMatchedTermCount, len(allNodes)) + antiAffinityCountsList := make([]topologyToMatchedTermCount, len(allNodes)) + index := int32(-1) + processNode := func(i int) { + nodeInfo := allNodes[i] + node := nodeInfo.Node() + if node == nil { + klog.ErrorS(nil, "Node not found") + return + } + affinity := make(topologyToMatchedTermCount) + antiAffinity := make(topologyToMatchedTermCount) + for _, existingPod := range nodeInfo.Pods { + affinity.updateWithAffinityTerms(podInfo.RequiredAffinityTerms, existingPod.Pod, node, 1) + // The incoming pod's terms have the namespaceSelector merged into the namespaces, and so + // here we don't lookup the existing pod's namespace labels, hence passing nil for nsLabels. + antiAffinity.updateWithAntiAffinityTerms(podInfo.RequiredAntiAffinityTerms, existingPod.Pod, nil, node, 1) + } + + if len(affinity) > 0 || len(antiAffinity) > 0 { + k := atomic.AddInt32(&index, 1) + affinityCountsList[k] = affinity + antiAffinityCountsList[k] = antiAffinity + } + } + pl.parallelizer.Until(ctx, len(allNodes), processNode, pl.Name()) + + for i := 0; i <= int(index); i++ { + affinityCounts.append(affinityCountsList[i]) + antiAffinityCounts.append(antiAffinityCountsList[i]) + } + + return affinityCounts, antiAffinityCounts +} + +// PreFilter invoked at the prefilter extension point. +func (pl *InterPodAffinity) PreFilter(ctx context.Context, cycleState *framework.CycleState, pod *v1.Pod) (*framework.PreFilterResult, *framework.Status) { + var allNodes []*framework.NodeInfo + var nodesWithRequiredAntiAffinityPods []*framework.NodeInfo + var err error + if allNodes, err = pl.sharedLister.NodeInfos().List(); err != nil { + return nil, framework.AsStatus(fmt.Errorf("failed to list NodeInfos: %w", err)) + } + if nodesWithRequiredAntiAffinityPods, err = pl.sharedLister.NodeInfos().HavePodsWithRequiredAntiAffinityList(); err != nil { + return nil, framework.AsStatus(fmt.Errorf("failed to list NodeInfos with pods with affinity: %w", err)) + } + + s := &preFilterState{} + + if s.podInfo, err = framework.NewPodInfo(pod); err != nil { + return nil, framework.NewStatus(framework.UnschedulableAndUnresolvable, fmt.Sprintf("parsing pod: %+v", err)) + } + + for i := range s.podInfo.RequiredAffinityTerms { + if err := pl.mergeAffinityTermNamespacesIfNotEmpty(&s.podInfo.RequiredAffinityTerms[i]); err != nil { + return nil, framework.AsStatus(err) + } + } + for i := range s.podInfo.RequiredAntiAffinityTerms { + if err := pl.mergeAffinityTermNamespacesIfNotEmpty(&s.podInfo.RequiredAntiAffinityTerms[i]); err != nil { + return nil, framework.AsStatus(err) + } + } + s.namespaceLabels = GetNamespaceLabelsSnapshot(pod.Namespace, pl.nsLister) + + s.existingAntiAffinityCounts = pl.getExistingAntiAffinityCounts(ctx, pod, s.namespaceLabels, nodesWithRequiredAntiAffinityPods) + s.affinityCounts, s.antiAffinityCounts = pl.getIncomingAffinityAntiAffinityCounts(ctx, s.podInfo, allNodes) + + cycleState.Write(preFilterStateKey, s) + return nil, nil +} + +// PreFilterExtensions returns prefilter extensions, pod add and remove. +func (pl *InterPodAffinity) PreFilterExtensions() framework.PreFilterExtensions { + return pl +} + +// AddPod from pre-computed data in cycleState. +func (pl *InterPodAffinity) AddPod(ctx context.Context, cycleState *framework.CycleState, podToSchedule *v1.Pod, podInfoToAdd *framework.PodInfo, nodeInfo *framework.NodeInfo) *framework.Status { + state, err := getPreFilterState(cycleState) + if err != nil { + return framework.AsStatus(err) + } + state.updateWithPod(podInfoToAdd, nodeInfo.Node(), 1) + return nil +} + +// RemovePod from pre-computed data in cycleState. +func (pl *InterPodAffinity) RemovePod(ctx context.Context, cycleState *framework.CycleState, podToSchedule *v1.Pod, podInfoToRemove *framework.PodInfo, nodeInfo *framework.NodeInfo) *framework.Status { + state, err := getPreFilterState(cycleState) + if err != nil { + return framework.AsStatus(err) + } + state.updateWithPod(podInfoToRemove, nodeInfo.Node(), -1) + return nil +} + +func getPreFilterState(cycleState *framework.CycleState) (*preFilterState, error) { + c, err := cycleState.Read(preFilterStateKey) + if err != nil { + // preFilterState doesn't exist, likely PreFilter wasn't invoked. + return nil, fmt.Errorf("error reading %q from cycleState: %w", preFilterStateKey, err) + } + + s, ok := c.(*preFilterState) + if !ok { + return nil, fmt.Errorf("%+v convert to interpodaffinity.state error", c) + } + return s, nil +} + +// Checks if scheduling the pod onto this node would break any anti-affinity +// terms indicated by the existing pods. +func satisfyExistingPodsAntiAffinity(state *preFilterState, nodeInfo *framework.NodeInfo) bool { + if len(state.existingAntiAffinityCounts) > 0 { + // Iterate over topology pairs to get any of the pods being affected by + // the scheduled pod anti-affinity terms + for topologyKey, topologyValue := range nodeInfo.Node().Labels { + tp := topologyPair{key: topologyKey, value: topologyValue} + if state.existingAntiAffinityCounts[tp] > 0 { + return false + } + } + } + return true +} + +// Checks if the node satisfies the incoming pod's anti-affinity rules. +func satisfyPodAntiAffinity(state *preFilterState, nodeInfo *framework.NodeInfo) bool { + if len(state.antiAffinityCounts) > 0 { + for _, term := range state.podInfo.RequiredAntiAffinityTerms { + if topologyValue, ok := nodeInfo.Node().Labels[term.TopologyKey]; ok { + tp := topologyPair{key: term.TopologyKey, value: topologyValue} + if state.antiAffinityCounts[tp] > 0 { + return false + } + } + } + } + return true +} + +// Checks if the node satisfies the incoming pod's affinity rules. +func satisfyPodAffinity(state *preFilterState, nodeInfo *framework.NodeInfo) bool { + podsExist := true + for _, term := range state.podInfo.RequiredAffinityTerms { + if topologyValue, ok := nodeInfo.Node().Labels[term.TopologyKey]; ok { + tp := topologyPair{key: term.TopologyKey, value: topologyValue} + if state.affinityCounts[tp] <= 0 { + podsExist = false + } + } else { + // All topology labels must exist on the node. + return false + } + } + + if !podsExist { + // This pod may be the first pod in a series that have affinity to themselves. In order + // to not leave such pods in pending state forever, we check that if no other pod + // in the cluster matches the namespace and selector of this pod, the pod matches + // its own terms, and the node has all the requested topologies, then we allow the pod + // to pass the affinity check. + if len(state.affinityCounts) == 0 && podMatchesAllAffinityTerms(state.podInfo.RequiredAffinityTerms, state.podInfo.Pod) { + return true + } + return false + } + return true +} + +// Filter invoked at the filter extension point. +// It checks if a pod can be scheduled on the specified node with pod affinity/anti-affinity configuration. +func (pl *InterPodAffinity) Filter(ctx context.Context, cycleState *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status { + if nodeInfo.Node() == nil { + return framework.NewStatus(framework.Error, "node not found") + } + + state, err := getPreFilterState(cycleState) + if err != nil { + return framework.AsStatus(err) + } + + if !satisfyPodAffinity(state, nodeInfo) { + return framework.NewStatus(framework.UnschedulableAndUnresolvable, ErrReasonAffinityRulesNotMatch) + } + + if !satisfyPodAntiAffinity(state, nodeInfo) { + return framework.NewStatus(framework.Unschedulable, ErrReasonAntiAffinityRulesNotMatch) + } + + if !satisfyExistingPodsAntiAffinity(state, nodeInfo) { + return framework.NewStatus(framework.Unschedulable, ErrReasonExistingAntiAffinityRulesNotMatch) + } + + return nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity/plugin.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity/plugin.go new file mode 100644 index 000000000..f7e84ce09 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity/plugin.go @@ -0,0 +1,133 @@ +/* +Copyright 2019 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 interpodaffinity + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + listersv1 "k8s.io/client-go/listers/core/v1" + "k8s.io/klog/v2" + "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/kubernetes/pkg/scheduler/apis/config/validation" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/parallelize" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" +) + +// Name is the name of the plugin used in the plugin registry and configurations. +const Name = names.InterPodAffinity + +var _ framework.PreFilterPlugin = &InterPodAffinity{} +var _ framework.FilterPlugin = &InterPodAffinity{} +var _ framework.PreScorePlugin = &InterPodAffinity{} +var _ framework.ScorePlugin = &InterPodAffinity{} +var _ framework.EnqueueExtensions = &InterPodAffinity{} + +// InterPodAffinity is a plugin that checks inter pod affinity +type InterPodAffinity struct { + parallelizer parallelize.Parallelizer + args config.InterPodAffinityArgs + sharedLister framework.SharedLister + nsLister listersv1.NamespaceLister +} + +// Name returns name of the plugin. It is used in logs, etc. +func (pl *InterPodAffinity) Name() string { + return Name +} + +// EventsToRegister returns the possible events that may make a failed Pod +// schedulable +func (pl *InterPodAffinity) EventsToRegister() []framework.ClusterEvent { + return []framework.ClusterEvent{ + // All ActionType includes the following events: + // - Delete. An unschedulable Pod may fail due to violating an existing Pod's anti-affinity constraints, + // deleting an existing Pod may make it schedulable. + // - Update. Updating on an existing Pod's labels (e.g., removal) may make + // an unschedulable Pod schedulable. + // - Add. An unschedulable Pod may fail due to violating pod-affinity constraints, + // adding an assigned Pod may make it schedulable. + {Resource: framework.Pod, ActionType: framework.All}, + {Resource: framework.Node, ActionType: framework.Add | framework.UpdateNodeLabel}, + } +} + +// New initializes a new plugin and returns it. +func New(plArgs runtime.Object, h framework.Handle) (framework.Plugin, error) { + if h.SnapshotSharedLister() == nil { + return nil, fmt.Errorf("SnapshotSharedlister is nil") + } + args, err := getArgs(plArgs) + if err != nil { + return nil, err + } + if err := validation.ValidateInterPodAffinityArgs(nil, &args); err != nil { + return nil, err + } + pl := &InterPodAffinity{ + parallelizer: h.Parallelizer(), + args: args, + sharedLister: h.SnapshotSharedLister(), + nsLister: h.SharedInformerFactory().Core().V1().Namespaces().Lister(), + } + + return pl, nil +} + +func getArgs(obj runtime.Object) (config.InterPodAffinityArgs, error) { + ptr, ok := obj.(*config.InterPodAffinityArgs) + if !ok { + return config.InterPodAffinityArgs{}, fmt.Errorf("want args to be of type InterPodAffinityArgs, got %T", obj) + } + return *ptr, nil +} + +// Updates Namespaces with the set of namespaces identified by NamespaceSelector. +// If successful, NamespaceSelector is set to nil. +// The assumption is that the term is for an incoming pod, in which case +// namespaceSelector is either unrolled into Namespaces (and so the selector +// is set to Nothing()) or is Empty(), which means match everything. Therefore, +// there when matching against this term, there is no need to lookup the existing +// pod's namespace labels to match them against term's namespaceSelector explicitly. +func (pl *InterPodAffinity) mergeAffinityTermNamespacesIfNotEmpty(at *framework.AffinityTerm) error { + if at.NamespaceSelector.Empty() { + return nil + } + ns, err := pl.nsLister.List(at.NamespaceSelector) + if err != nil { + return err + } + for _, n := range ns { + at.Namespaces.Insert(n.Name) + } + at.NamespaceSelector = labels.Nothing() + return nil +} + +// GetNamespaceLabelsSnapshot returns a snapshot of the labels associated with +// the namespace. +func GetNamespaceLabelsSnapshot(ns string, nsLister listersv1.NamespaceLister) (nsLabels labels.Set) { + podNS, err := nsLister.Get(ns) + if err == nil { + // Create and return snapshot of the labels. + return labels.Merge(podNS.Labels, nil) + } + klog.V(3).InfoS("getting namespace, assuming empty set of namespace labels", "namespace", ns, "err", err) + return +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity/scoring.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity/scoring.go new file mode 100644 index 000000000..322ea8543 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity/scoring.go @@ -0,0 +1,291 @@ +/* +Copyright 2019 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 interpodaffinity + +import ( + "context" + "fmt" + "math" + "sync/atomic" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/kubernetes/pkg/scheduler/framework" +) + +// preScoreStateKey is the key in CycleState to InterPodAffinity pre-computed data for Scoring. +const preScoreStateKey = "PreScore" + Name + +type scoreMap map[string]map[string]int64 + +// preScoreState computed at PreScore and used at Score. +type preScoreState struct { + topologyScore scoreMap + podInfo *framework.PodInfo + // A copy of the incoming pod's namespace labels. + namespaceLabels labels.Set +} + +// Clone implements the mandatory Clone interface. We don't really copy the data since +// there is no need for that. +func (s *preScoreState) Clone() framework.StateData { + return s +} + +func (m scoreMap) processTerm(term *framework.AffinityTerm, weight int32, pod *v1.Pod, nsLabels labels.Set, node *v1.Node, multiplier int32) { + if term.Matches(pod, nsLabels) { + if tpValue, tpValueExist := node.Labels[term.TopologyKey]; tpValueExist { + if m[term.TopologyKey] == nil { + m[term.TopologyKey] = make(map[string]int64) + } + m[term.TopologyKey][tpValue] += int64(weight * multiplier) + } + } +} + +func (m scoreMap) processTerms(terms []framework.WeightedAffinityTerm, pod *v1.Pod, nsLabels labels.Set, node *v1.Node, multiplier int32) { + for _, term := range terms { + m.processTerm(&term.AffinityTerm, term.Weight, pod, nsLabels, node, multiplier) + } +} + +func (m scoreMap) append(other scoreMap) { + for topology, oScores := range other { + scores := m[topology] + if scores == nil { + m[topology] = oScores + continue + } + for k, v := range oScores { + scores[k] += v + } + } +} + +func (pl *InterPodAffinity) processExistingPod( + state *preScoreState, + existingPod *framework.PodInfo, + existingPodNodeInfo *framework.NodeInfo, + incomingPod *v1.Pod, + topoScore scoreMap, +) { + existingPodNode := existingPodNodeInfo.Node() + if len(existingPodNode.Labels) == 0 { + return + } + + // For every soft pod affinity term of , if matches the term, + // increment for every node in the cluster with the same + // value as that of `s node by the term`s weight. + // Note that the incoming pod's terms have the namespaceSelector merged into the namespaces, and so + // here we don't lookup the existing pod's namespace labels, hence passing nil for nsLabels. + topoScore.processTerms(state.podInfo.PreferredAffinityTerms, existingPod.Pod, nil, existingPodNode, 1) + + // For every soft pod anti-affinity term of , if matches the term, + // decrement for every node in the cluster with the same + // value as that of `s node by the term`s weight. + // Note that the incoming pod's terms have the namespaceSelector merged into the namespaces, and so + // here we don't lookup the existing pod's namespace labels, hence passing nil for nsLabels. + topoScore.processTerms(state.podInfo.PreferredAntiAffinityTerms, existingPod.Pod, nil, existingPodNode, -1) + + // For every hard pod affinity term of , if matches the term, + // increment for every node in the cluster with the same + // value as that of 's node by the constant + if pl.args.HardPodAffinityWeight > 0 && len(existingPodNode.Labels) != 0 { + for _, t := range existingPod.RequiredAffinityTerms { + topoScore.processTerm(&t, pl.args.HardPodAffinityWeight, incomingPod, state.namespaceLabels, existingPodNode, 1) + } + } + + // For every soft pod affinity term of , if matches the term, + // increment for every node in the cluster with the same + // value as that of 's node by the term's weight. + topoScore.processTerms(existingPod.PreferredAffinityTerms, incomingPod, state.namespaceLabels, existingPodNode, 1) + + // For every soft pod anti-affinity term of , if matches the term, + // decrement for every node in the cluster with the same + // value as that of 's node by the term's weight. + topoScore.processTerms(existingPod.PreferredAntiAffinityTerms, incomingPod, state.namespaceLabels, existingPodNode, -1) +} + +// PreScore builds and writes cycle state used by Score and NormalizeScore. +func (pl *InterPodAffinity) PreScore( + pCtx context.Context, + cycleState *framework.CycleState, + pod *v1.Pod, + nodes []*v1.Node, +) *framework.Status { + if len(nodes) == 0 { + // No nodes to score. + return nil + } + + if pl.sharedLister == nil { + return framework.NewStatus(framework.Error, "empty shared lister in InterPodAffinity PreScore") + } + + affinity := pod.Spec.Affinity + hasPreferredAffinityConstraints := affinity != nil && affinity.PodAffinity != nil && len(affinity.PodAffinity.PreferredDuringSchedulingIgnoredDuringExecution) > 0 + hasPreferredAntiAffinityConstraints := affinity != nil && affinity.PodAntiAffinity != nil && len(affinity.PodAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution) > 0 + + // Unless the pod being scheduled has preferred affinity terms, we only + // need to process nodes hosting pods with affinity. + var allNodes []*framework.NodeInfo + var err error + if hasPreferredAffinityConstraints || hasPreferredAntiAffinityConstraints { + allNodes, err = pl.sharedLister.NodeInfos().List() + if err != nil { + return framework.AsStatus(fmt.Errorf("failed to get all nodes from shared lister: %w", err)) + } + } else { + allNodes, err = pl.sharedLister.NodeInfos().HavePodsWithAffinityList() + if err != nil { + return framework.AsStatus(fmt.Errorf("failed to get pods with affinity list: %w", err)) + } + } + + state := &preScoreState{ + topologyScore: make(map[string]map[string]int64), + } + + if state.podInfo, err = framework.NewPodInfo(pod); err != nil { + // Ideally we never reach here, because errors will be caught by PreFilter + return framework.AsStatus(fmt.Errorf("failed to parse pod: %w", err)) + } + + for i := range state.podInfo.PreferredAffinityTerms { + if err := pl.mergeAffinityTermNamespacesIfNotEmpty(&state.podInfo.PreferredAffinityTerms[i].AffinityTerm); err != nil { + return framework.AsStatus(fmt.Errorf("updating PreferredAffinityTerms: %w", err)) + } + } + for i := range state.podInfo.PreferredAntiAffinityTerms { + if err := pl.mergeAffinityTermNamespacesIfNotEmpty(&state.podInfo.PreferredAntiAffinityTerms[i].AffinityTerm); err != nil { + return framework.AsStatus(fmt.Errorf("updating PreferredAntiAffinityTerms: %w", err)) + } + } + state.namespaceLabels = GetNamespaceLabelsSnapshot(pod.Namespace, pl.nsLister) + + topoScores := make([]scoreMap, len(allNodes)) + index := int32(-1) + processNode := func(i int) { + nodeInfo := allNodes[i] + if nodeInfo.Node() == nil { + return + } + // Unless the pod being scheduled has preferred affinity terms, we only + // need to process pods with affinity in the node. + podsToProcess := nodeInfo.PodsWithAffinity + if hasPreferredAffinityConstraints || hasPreferredAntiAffinityConstraints { + // We need to process all the pods. + podsToProcess = nodeInfo.Pods + } + + topoScore := make(scoreMap) + for _, existingPod := range podsToProcess { + pl.processExistingPod(state, existingPod, nodeInfo, pod, topoScore) + } + if len(topoScore) > 0 { + topoScores[atomic.AddInt32(&index, 1)] = topoScore + } + } + pl.parallelizer.Until(pCtx, len(allNodes), processNode, pl.Name()) + + for i := 0; i <= int(index); i++ { + state.topologyScore.append(topoScores[i]) + } + + cycleState.Write(preScoreStateKey, state) + return nil +} + +func getPreScoreState(cycleState *framework.CycleState) (*preScoreState, error) { + c, err := cycleState.Read(preScoreStateKey) + if err != nil { + return nil, fmt.Errorf("failed to read %q from cycleState: %w", preScoreStateKey, err) + } + + s, ok := c.(*preScoreState) + if !ok { + return nil, fmt.Errorf("%+v convert to interpodaffinity.preScoreState error", c) + } + return s, nil +} + +// Score invoked at the Score extension point. +// The "score" returned in this function is the sum of weights got from cycleState which have its topologyKey matching with the node's labels. +// it is normalized later. +// Note: the returned "score" is positive for pod-affinity, and negative for pod-antiaffinity. +func (pl *InterPodAffinity) Score(ctx context.Context, cycleState *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) { + nodeInfo, err := pl.sharedLister.NodeInfos().Get(nodeName) + if err != nil { + return 0, framework.AsStatus(fmt.Errorf("failed to get node %q from Snapshot: %w", nodeName, err)) + } + node := nodeInfo.Node() + + s, err := getPreScoreState(cycleState) + if err != nil { + return 0, framework.AsStatus(err) + } + var score int64 + for tpKey, tpValues := range s.topologyScore { + if v, exist := node.Labels[tpKey]; exist { + score += tpValues[v] + } + } + + return score, nil +} + +// NormalizeScore normalizes the score for each filteredNode. +func (pl *InterPodAffinity) NormalizeScore(ctx context.Context, cycleState *framework.CycleState, pod *v1.Pod, scores framework.NodeScoreList) *framework.Status { + s, err := getPreScoreState(cycleState) + if err != nil { + return framework.AsStatus(err) + } + if len(s.topologyScore) == 0 { + return nil + } + + var minCount int64 = math.MaxInt64 + var maxCount int64 = math.MinInt64 + for i := range scores { + score := scores[i].Score + if score > maxCount { + maxCount = score + } + if score < minCount { + minCount = score + } + } + + maxMinDiff := maxCount - minCount + for i := range scores { + fScore := float64(0) + if maxMinDiff > 0 { + fScore = float64(framework.MaxNodeScore) * (float64(scores[i].Score-minCount) / float64(maxMinDiff)) + } + + scores[i].Score = int64(fScore) + } + + return nil +} + +// ScoreExtensions of the Score plugin. +func (pl *InterPodAffinity) ScoreExtensions() framework.ScoreExtensions { + return pl +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/names/names.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/names/names.go new file mode 100644 index 000000000..3741f0a10 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/names/names.go @@ -0,0 +1,44 @@ +/* +Copyright 2021 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 names + +const ( + PrioritySort = "PrioritySort" + DefaultBinder = "DefaultBinder" + DefaultPreemption = "DefaultPreemption" + DynamicResources = "DynamicResources" + ImageLocality = "ImageLocality" + InterPodAffinity = "InterPodAffinity" + NodeAffinity = "NodeAffinity" + NodeName = "NodeName" + NodePorts = "NodePorts" + NodeResourcesBalancedAllocation = "NodeResourcesBalancedAllocation" + NodeResourcesFit = "NodeResourcesFit" + NodeUnschedulable = "NodeUnschedulable" + NodeVolumeLimits = "NodeVolumeLimits" + AzureDiskLimits = "AzureDiskLimits" + CinderLimits = "CinderLimits" + EBSLimits = "EBSLimits" + GCEPDLimits = "GCEPDLimits" + PodTopologySpread = "PodTopologySpread" + SchedulingGates = "SchedulingGates" + SelectorSpread = "SelectorSpread" + TaintToleration = "TaintToleration" + VolumeBinding = "VolumeBinding" + VolumeRestrictions = "VolumeRestrictions" + VolumeZone = "VolumeZone" +) diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeaffinity/node_affinity.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeaffinity/node_affinity.go new file mode 100644 index 000000000..41e0a27d7 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeaffinity/node_affinity.go @@ -0,0 +1,309 @@ +/* +Copyright 2019 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 nodeaffinity + +import ( + "context" + "fmt" + + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/component-helpers/scheduling/corev1/nodeaffinity" + "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/kubernetes/pkg/scheduler/apis/config/validation" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" +) + +// NodeAffinity is a plugin that checks if a pod node selector matches the node label. +type NodeAffinity struct { + handle framework.Handle + addedNodeSelector *nodeaffinity.NodeSelector + addedPrefSchedTerms *nodeaffinity.PreferredSchedulingTerms +} + +var _ framework.PreFilterPlugin = &NodeAffinity{} +var _ framework.FilterPlugin = &NodeAffinity{} +var _ framework.PreScorePlugin = &NodeAffinity{} +var _ framework.ScorePlugin = &NodeAffinity{} +var _ framework.EnqueueExtensions = &NodeAffinity{} + +const ( + // Name is the name of the plugin used in the plugin registry and configurations. + Name = names.NodeAffinity + + // preScoreStateKey is the key in CycleState to NodeAffinity pre-computed data for Scoring. + preScoreStateKey = "PreScore" + Name + + // preFilterStateKey is the key in CycleState to NodeAffinity pre-compute data for Filtering. + preFilterStateKey = "PreFilter" + Name + + // ErrReasonPod is the reason for Pod's node affinity/selector not matching. + ErrReasonPod = "node(s) didn't match Pod's node affinity/selector" + + // errReasonEnforced is the reason for added node affinity not matching. + errReasonEnforced = "node(s) didn't match scheduler-enforced node affinity" + + // errReasonConflict is the reason for pod's conflicting affinity rules. + errReasonConflict = "pod affinity terms conflict" +) + +// Name returns name of the plugin. It is used in logs, etc. +func (pl *NodeAffinity) Name() string { + return Name +} + +type preFilterState struct { + requiredNodeSelectorAndAffinity nodeaffinity.RequiredNodeAffinity +} + +// Clone just returns the same state because it is not affected by pod additions or deletions. +func (s *preFilterState) Clone() framework.StateData { + return s +} + +// EventsToRegister returns the possible events that may make a Pod +// failed by this plugin schedulable. +func (pl *NodeAffinity) EventsToRegister() []framework.ClusterEvent { + return []framework.ClusterEvent{ + {Resource: framework.Node, ActionType: framework.Add | framework.Update}, + } +} + +// PreFilter builds and writes cycle state used by Filter. +func (pl *NodeAffinity) PreFilter(ctx context.Context, cycleState *framework.CycleState, pod *v1.Pod) (*framework.PreFilterResult, *framework.Status) { + state := &preFilterState{requiredNodeSelectorAndAffinity: nodeaffinity.GetRequiredNodeAffinity(pod)} + cycleState.Write(preFilterStateKey, state) + affinity := pod.Spec.Affinity + if affinity == nil || + affinity.NodeAffinity == nil || + affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution == nil || + len(affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms) == 0 { + return nil, nil + } + + // Check if there is affinity to a specific node and return it. + terms := affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms + var nodeNames sets.String + for _, t := range terms { + var termNodeNames sets.String + for _, r := range t.MatchFields { + if r.Key == metav1.ObjectNameField && r.Operator == v1.NodeSelectorOpIn { + // The requirements represent ANDed constraints, and so we need to + // find the intersection of nodes. + s := sets.NewString(r.Values...) + if termNodeNames == nil { + termNodeNames = s + } else { + termNodeNames = termNodeNames.Intersection(s) + } + } + } + if termNodeNames == nil { + // If this term has no node.Name field affinity, + // then all nodes are eligible because the terms are ORed. + return nil, nil + } + // If the set is empty, it means the terms had affinity to different + // sets of nodes, and since they are ANDed, then the pod will not match any node. + if len(termNodeNames) == 0 { + return nil, framework.NewStatus(framework.UnschedulableAndUnresolvable, errReasonConflict) + } + nodeNames = nodeNames.Union(termNodeNames) + } + if nodeNames != nil { + return &framework.PreFilterResult{NodeNames: nodeNames}, nil + } + return nil, nil + +} + +// PreFilterExtensions not necessary for this plugin as state doesn't depend on pod additions or deletions. +func (pl *NodeAffinity) PreFilterExtensions() framework.PreFilterExtensions { + return nil +} + +// Filter checks if the Node matches the Pod .spec.affinity.nodeAffinity and +// the plugin's added affinity. +func (pl *NodeAffinity) Filter(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status { + node := nodeInfo.Node() + if node == nil { + return framework.NewStatus(framework.Error, "node not found") + } + if pl.addedNodeSelector != nil && !pl.addedNodeSelector.Match(node) { + return framework.NewStatus(framework.UnschedulableAndUnresolvable, errReasonEnforced) + } + + s, err := getPreFilterState(state) + if err != nil { + // Fallback to calculate requiredNodeSelector and requiredNodeAffinity + // here when PreFilter is disabled. + s = &preFilterState{requiredNodeSelectorAndAffinity: nodeaffinity.GetRequiredNodeAffinity(pod)} + } + + // Ignore parsing errors for backwards compatibility. + match, _ := s.requiredNodeSelectorAndAffinity.Match(node) + if !match { + return framework.NewStatus(framework.UnschedulableAndUnresolvable, ErrReasonPod) + } + + return nil +} + +// preScoreState computed at PreScore and used at Score. +type preScoreState struct { + preferredNodeAffinity *nodeaffinity.PreferredSchedulingTerms +} + +// Clone implements the mandatory Clone interface. We don't really copy the data since +// there is no need for that. +func (s *preScoreState) Clone() framework.StateData { + return s +} + +// PreScore builds and writes cycle state used by Score and NormalizeScore. +func (pl *NodeAffinity) PreScore(ctx context.Context, cycleState *framework.CycleState, pod *v1.Pod, nodes []*v1.Node) *framework.Status { + if len(nodes) == 0 { + return nil + } + preferredNodeAffinity, err := getPodPreferredNodeAffinity(pod) + if err != nil { + return framework.AsStatus(err) + } + state := &preScoreState{ + preferredNodeAffinity: preferredNodeAffinity, + } + cycleState.Write(preScoreStateKey, state) + return nil +} + +// Score returns the sum of the weights of the terms that match the Node. +// Terms came from the Pod .spec.affinity.nodeAffinity and from the plugin's +// default affinity. +func (pl *NodeAffinity) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) { + nodeInfo, err := pl.handle.SnapshotSharedLister().NodeInfos().Get(nodeName) + if err != nil { + return 0, framework.AsStatus(fmt.Errorf("getting node %q from Snapshot: %w", nodeName, err)) + } + + node := nodeInfo.Node() + + var count int64 + if pl.addedPrefSchedTerms != nil { + count += pl.addedPrefSchedTerms.Score(node) + } + + s, err := getPreScoreState(state) + if err != nil { + // Fallback to calculate preferredNodeAffinity here when PreScore is disabled. + preferredNodeAffinity, err := getPodPreferredNodeAffinity(pod) + if err != nil { + return 0, framework.AsStatus(err) + } + s = &preScoreState{ + preferredNodeAffinity: preferredNodeAffinity, + } + } + + if s.preferredNodeAffinity != nil { + count += s.preferredNodeAffinity.Score(node) + } + + return count, nil +} + +// NormalizeScore invoked after scoring all nodes. +func (pl *NodeAffinity) NormalizeScore(ctx context.Context, state *framework.CycleState, pod *v1.Pod, scores framework.NodeScoreList) *framework.Status { + return helper.DefaultNormalizeScore(framework.MaxNodeScore, false, scores) +} + +// ScoreExtensions of the Score plugin. +func (pl *NodeAffinity) ScoreExtensions() framework.ScoreExtensions { + return pl +} + +// New initializes a new plugin and returns it. +func New(plArgs runtime.Object, h framework.Handle) (framework.Plugin, error) { + args, err := getArgs(plArgs) + if err != nil { + return nil, err + } + pl := &NodeAffinity{ + handle: h, + } + if args.AddedAffinity != nil { + if ns := args.AddedAffinity.RequiredDuringSchedulingIgnoredDuringExecution; ns != nil { + pl.addedNodeSelector, err = nodeaffinity.NewNodeSelector(ns) + if err != nil { + return nil, fmt.Errorf("parsing addedAffinity.requiredDuringSchedulingIgnoredDuringExecution: %w", err) + } + } + // TODO: parse requiredDuringSchedulingRequiredDuringExecution when it gets added to the API. + if terms := args.AddedAffinity.PreferredDuringSchedulingIgnoredDuringExecution; len(terms) != 0 { + pl.addedPrefSchedTerms, err = nodeaffinity.NewPreferredSchedulingTerms(terms) + if err != nil { + return nil, fmt.Errorf("parsing addedAffinity.preferredDuringSchedulingIgnoredDuringExecution: %w", err) + } + } + } + return pl, nil +} + +func getArgs(obj runtime.Object) (config.NodeAffinityArgs, error) { + ptr, ok := obj.(*config.NodeAffinityArgs) + if !ok { + return config.NodeAffinityArgs{}, fmt.Errorf("args are not of type NodeAffinityArgs, got %T", obj) + } + return *ptr, validation.ValidateNodeAffinityArgs(nil, ptr) +} + +func getPodPreferredNodeAffinity(pod *v1.Pod) (*nodeaffinity.PreferredSchedulingTerms, error) { + affinity := pod.Spec.Affinity + if affinity != nil && affinity.NodeAffinity != nil && affinity.NodeAffinity.PreferredDuringSchedulingIgnoredDuringExecution != nil { + return nodeaffinity.NewPreferredSchedulingTerms(affinity.NodeAffinity.PreferredDuringSchedulingIgnoredDuringExecution) + } + return nil, nil +} + +func getPreScoreState(cycleState *framework.CycleState) (*preScoreState, error) { + c, err := cycleState.Read(preScoreStateKey) + if err != nil { + return nil, fmt.Errorf("reading %q from cycleState: %w", preScoreStateKey, err) + } + + s, ok := c.(*preScoreState) + if !ok { + return nil, fmt.Errorf("invalid PreScore state, got type %T", c) + } + return s, nil +} + +func getPreFilterState(cycleState *framework.CycleState) (*preFilterState, error) { + c, err := cycleState.Read(preFilterStateKey) + if err != nil { + return nil, fmt.Errorf("reading %q from cycleState: %v", preFilterStateKey, err) + } + + s, ok := c.(*preFilterState) + if !ok { + return nil, fmt.Errorf("invalid PreFilter state, got type %T", c) + } + return s, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodename/node_name.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodename/node_name.go new file mode 100644 index 000000000..e02134f79 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodename/node_name.go @@ -0,0 +1,74 @@ +/* +Copyright 2019 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 nodename + +import ( + "context" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" +) + +// NodeName is a plugin that checks if a pod spec node name matches the current node. +type NodeName struct{} + +var _ framework.FilterPlugin = &NodeName{} +var _ framework.EnqueueExtensions = &NodeName{} + +const ( + // Name is the name of the plugin used in the plugin registry and configurations. + Name = names.NodeName + + // ErrReason returned when node name doesn't match. + ErrReason = "node(s) didn't match the requested node name" +) + +// EventsToRegister returns the possible events that may make a Pod +// failed by this plugin schedulable. +func (pl *NodeName) EventsToRegister() []framework.ClusterEvent { + return []framework.ClusterEvent{ + {Resource: framework.Node, ActionType: framework.Add | framework.Update}, + } +} + +// Name returns name of the plugin. It is used in logs, etc. +func (pl *NodeName) Name() string { + return Name +} + +// Filter invoked at the filter extension point. +func (pl *NodeName) Filter(ctx context.Context, _ *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status { + if nodeInfo.Node() == nil { + return framework.NewStatus(framework.Error, "node not found") + } + if !Fits(pod, nodeInfo) { + return framework.NewStatus(framework.UnschedulableAndUnresolvable, ErrReason) + } + return nil +} + +// Fits actually checks if the pod fits the node. +func Fits(pod *v1.Pod, nodeInfo *framework.NodeInfo) bool { + return len(pod.Spec.NodeName) == 0 || pod.Spec.NodeName == nodeInfo.Node().Name +} + +// New initializes a new plugin and returns it. +func New(_ runtime.Object, _ framework.Handle) (framework.Plugin, error) { + return &NodeName{}, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeports/node_ports.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeports/node_ports.go new file mode 100644 index 000000000..bfd648efe --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeports/node_ports.go @@ -0,0 +1,146 @@ +/* +Copyright 2019 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 nodeports + +import ( + "context" + "fmt" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" +) + +// NodePorts is a plugin that checks if a node has free ports for the requested pod ports. +type NodePorts struct{} + +var _ framework.PreFilterPlugin = &NodePorts{} +var _ framework.FilterPlugin = &NodePorts{} +var _ framework.EnqueueExtensions = &NodePorts{} + +const ( + // Name is the name of the plugin used in the plugin registry and configurations. + Name = names.NodePorts + + // preFilterStateKey is the key in CycleState to NodePorts pre-computed data. + // Using the name of the plugin will likely help us avoid collisions with other plugins. + preFilterStateKey = "PreFilter" + Name + + // ErrReason when node ports aren't available. + ErrReason = "node(s) didn't have free ports for the requested pod ports" +) + +type preFilterState []*v1.ContainerPort + +// Clone the prefilter state. +func (s preFilterState) Clone() framework.StateData { + // The state is not impacted by adding/removing existing pods, hence we don't need to make a deep copy. + return s +} + +// Name returns name of the plugin. It is used in logs, etc. +func (pl *NodePorts) Name() string { + return Name +} + +// getContainerPorts returns the used host ports of Pods: if 'port' was used, a 'port:true' pair +// will be in the result; but it does not resolve port conflict. +func getContainerPorts(pods ...*v1.Pod) []*v1.ContainerPort { + ports := []*v1.ContainerPort{} + for _, pod := range pods { + for j := range pod.Spec.Containers { + container := &pod.Spec.Containers[j] + for k := range container.Ports { + ports = append(ports, &container.Ports[k]) + } + } + } + return ports +} + +// PreFilter invoked at the prefilter extension point. +func (pl *NodePorts) PreFilter(ctx context.Context, cycleState *framework.CycleState, pod *v1.Pod) (*framework.PreFilterResult, *framework.Status) { + s := getContainerPorts(pod) + cycleState.Write(preFilterStateKey, preFilterState(s)) + return nil, nil +} + +// PreFilterExtensions do not exist for this plugin. +func (pl *NodePorts) PreFilterExtensions() framework.PreFilterExtensions { + return nil +} + +func getPreFilterState(cycleState *framework.CycleState) (preFilterState, error) { + c, err := cycleState.Read(preFilterStateKey) + if err != nil { + // preFilterState doesn't exist, likely PreFilter wasn't invoked. + return nil, fmt.Errorf("reading %q from cycleState: %w", preFilterStateKey, err) + } + + s, ok := c.(preFilterState) + if !ok { + return nil, fmt.Errorf("%+v convert to nodeports.preFilterState error", c) + } + return s, nil +} + +// EventsToRegister returns the possible events that may make a Pod +// failed by this plugin schedulable. +func (pl *NodePorts) EventsToRegister() []framework.ClusterEvent { + return []framework.ClusterEvent{ + // Due to immutable fields `spec.containers[*].ports`, pod update events are ignored. + {Resource: framework.Pod, ActionType: framework.Delete}, + {Resource: framework.Node, ActionType: framework.Add | framework.Update}, + } +} + +// Filter invoked at the filter extension point. +func (pl *NodePorts) Filter(ctx context.Context, cycleState *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status { + wantPorts, err := getPreFilterState(cycleState) + if err != nil { + return framework.AsStatus(err) + } + + fits := fitsPorts(wantPorts, nodeInfo) + if !fits { + return framework.NewStatus(framework.Unschedulable, ErrReason) + } + + return nil +} + +// Fits checks if the pod fits the node. +func Fits(pod *v1.Pod, nodeInfo *framework.NodeInfo) bool { + return fitsPorts(getContainerPorts(pod), nodeInfo) +} + +func fitsPorts(wantPorts []*v1.ContainerPort, nodeInfo *framework.NodeInfo) bool { + // try to see whether existingPorts and wantPorts will conflict or not + existingPorts := nodeInfo.UsedPorts + for _, cp := range wantPorts { + if existingPorts.CheckConflict(cp.HostIP, string(cp.Protocol), cp.HostPort) { + return false + } + } + return true +} + +// New initializes a new plugin and returns it. +func New(_ runtime.Object, _ framework.Handle) (framework.Plugin, error) { + return &NodePorts{}, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/balanced_allocation.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/balanced_allocation.go new file mode 100644 index 000000000..baad87699 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/balanced_allocation.go @@ -0,0 +1,130 @@ +/* +Copyright 2019 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 noderesources + +import ( + "context" + "fmt" + "math" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/kubernetes/pkg/scheduler/apis/config/validation" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" +) + +// BalancedAllocation is a score plugin that calculates the difference between the cpu and memory fraction +// of capacity, and prioritizes the host based on how close the two metrics are to each other. +type BalancedAllocation struct { + handle framework.Handle + resourceAllocationScorer +} + +var _ framework.ScorePlugin = &BalancedAllocation{} + +// BalancedAllocationName is the name of the plugin used in the plugin registry and configurations. +const BalancedAllocationName = names.NodeResourcesBalancedAllocation + +// Name returns name of the plugin. It is used in logs, etc. +func (ba *BalancedAllocation) Name() string { + return BalancedAllocationName +} + +// Score invoked at the score extension point. +func (ba *BalancedAllocation) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) { + nodeInfo, err := ba.handle.SnapshotSharedLister().NodeInfos().Get(nodeName) + if err != nil { + return 0, framework.AsStatus(fmt.Errorf("getting node %q from Snapshot: %w", nodeName, err)) + } + + // ba.score favors nodes with balanced resource usage rate. + // It calculates the standard deviation for those resources and prioritizes the node based on how close the usage of those resources is to each other. + // Detail: score = (1 - std) * MaxNodeScore, where std is calculated by the root square of Σ((fraction(i)-mean)^2)/len(resources) + // The algorithm is partly inspired by: + // "Wei Huang et al. An Energy Efficient Virtual Machine Placement Algorithm with Balanced Resource Utilization" + return ba.score(pod, nodeInfo) +} + +// ScoreExtensions of the Score plugin. +func (ba *BalancedAllocation) ScoreExtensions() framework.ScoreExtensions { + return nil +} + +// NewBalancedAllocation initializes a new plugin and returns it. +func NewBalancedAllocation(baArgs runtime.Object, h framework.Handle, fts feature.Features) (framework.Plugin, error) { + args, ok := baArgs.(*config.NodeResourcesBalancedAllocationArgs) + if !ok { + return nil, fmt.Errorf("want args to be of type NodeResourcesBalancedAllocationArgs, got %T", baArgs) + } + + if err := validation.ValidateNodeResourcesBalancedAllocationArgs(nil, args); err != nil { + return nil, err + } + + resToWeightMap := make(resourceToWeightMap) + + for _, resource := range args.Resources { + resToWeightMap[v1.ResourceName(resource.Name)] = resource.Weight + } + + return &BalancedAllocation{ + handle: h, + resourceAllocationScorer: resourceAllocationScorer{ + Name: BalancedAllocationName, + scorer: balancedResourceScorer, + useRequested: true, + resourceToWeightMap: resToWeightMap, + }, + }, nil +} + +func balancedResourceScorer(requested, allocable resourceToValueMap) int64 { + var resourceToFractions []float64 + var totalFraction float64 + for name, value := range requested { + fraction := float64(value) / float64(allocable[name]) + if fraction > 1 { + fraction = 1 + } + totalFraction += fraction + resourceToFractions = append(resourceToFractions, fraction) + } + + std := 0.0 + + // For most cases, resources are limited to cpu and memory, the std could be simplified to std := (fraction1-fraction2)/2 + // len(fractions) > 2: calculate std based on the well-known formula - root square of Σ((fraction(i)-mean)^2)/len(fractions) + // Otherwise, set the std to zero is enough. + if len(resourceToFractions) == 2 { + std = math.Abs((resourceToFractions[0] - resourceToFractions[1]) / 2) + + } else if len(resourceToFractions) > 2 { + mean := totalFraction / float64(len(resourceToFractions)) + var sum float64 + for _, fraction := range resourceToFractions { + sum = sum + (fraction-mean)*(fraction-mean) + } + std = math.Sqrt(sum / float64(len(resourceToFractions))) + } + + // STD (standard deviation) is always a positive value. 1-deviation lets the score to be higher for node which has least deviation and + // multiplying it with `MaxNodeScore` provides the scaling factor needed. + return int64((1 - std) * float64(framework.MaxNodeScore)) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/fit.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/fit.go new file mode 100644 index 000000000..ff62eff00 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/fit.go @@ -0,0 +1,342 @@ +/* +Copyright 2019 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 noderesources + +import ( + "context" + "fmt" + "strings" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/sets" + v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" + "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/kubernetes/pkg/scheduler/apis/config/validation" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" +) + +var _ framework.PreFilterPlugin = &Fit{} +var _ framework.FilterPlugin = &Fit{} +var _ framework.EnqueueExtensions = &Fit{} +var _ framework.ScorePlugin = &Fit{} + +const ( + // Name is the name of the plugin used in the plugin registry and configurations. + Name = names.NodeResourcesFit + + // preFilterStateKey is the key in CycleState to NodeResourcesFit pre-computed data. + // Using the name of the plugin will likely help us avoid collisions with other plugins. + preFilterStateKey = "PreFilter" + Name +) + +// nodeResourceStrategyTypeMap maps strategy to scorer implementation +var nodeResourceStrategyTypeMap = map[config.ScoringStrategyType]scorer{ + config.LeastAllocated: func(args *config.NodeResourcesFitArgs) *resourceAllocationScorer { + resToWeightMap := resourcesToWeightMap(args.ScoringStrategy.Resources) + return &resourceAllocationScorer{ + Name: string(config.LeastAllocated), + scorer: leastResourceScorer(resToWeightMap), + resourceToWeightMap: resToWeightMap, + } + }, + config.MostAllocated: func(args *config.NodeResourcesFitArgs) *resourceAllocationScorer { + resToWeightMap := resourcesToWeightMap(args.ScoringStrategy.Resources) + return &resourceAllocationScorer{ + Name: string(config.MostAllocated), + scorer: mostResourceScorer(resToWeightMap), + resourceToWeightMap: resToWeightMap, + } + }, + config.RequestedToCapacityRatio: func(args *config.NodeResourcesFitArgs) *resourceAllocationScorer { + resToWeightMap := resourcesToWeightMap(args.ScoringStrategy.Resources) + return &resourceAllocationScorer{ + Name: string(config.RequestedToCapacityRatio), + scorer: requestedToCapacityRatioScorer(resToWeightMap, args.ScoringStrategy.RequestedToCapacityRatio.Shape), + resourceToWeightMap: resToWeightMap, + } + }, +} + +// Fit is a plugin that checks if a node has sufficient resources. +type Fit struct { + ignoredResources sets.String + ignoredResourceGroups sets.String + handle framework.Handle + resourceAllocationScorer +} + +// ScoreExtensions of the Score plugin. +func (f *Fit) ScoreExtensions() framework.ScoreExtensions { + return nil +} + +// preFilterState computed at PreFilter and used at Filter. +type preFilterState struct { + framework.Resource +} + +// Clone the prefilter state. +func (s *preFilterState) Clone() framework.StateData { + return s +} + +// Name returns name of the plugin. It is used in logs, etc. +func (f *Fit) Name() string { + return Name +} + +// NewFit initializes a new plugin and returns it. +func NewFit(plArgs runtime.Object, h framework.Handle, fts feature.Features) (framework.Plugin, error) { + args, ok := plArgs.(*config.NodeResourcesFitArgs) + if !ok { + return nil, fmt.Errorf("want args to be of type NodeResourcesFitArgs, got %T", plArgs) + } + if err := validation.ValidateNodeResourcesFitArgs(nil, args); err != nil { + return nil, err + } + + if args.ScoringStrategy == nil { + return nil, fmt.Errorf("scoring strategy not specified") + } + + strategy := args.ScoringStrategy.Type + scorePlugin, exists := nodeResourceStrategyTypeMap[strategy] + if !exists { + return nil, fmt.Errorf("scoring strategy %s is not supported", strategy) + } + + return &Fit{ + ignoredResources: sets.NewString(args.IgnoredResources...), + ignoredResourceGroups: sets.NewString(args.IgnoredResourceGroups...), + handle: h, + resourceAllocationScorer: *scorePlugin(args), + }, nil +} + +// computePodResourceRequest returns a framework.Resource that covers the largest +// width in each resource dimension. Because init-containers run sequentially, we collect +// the max in each dimension iteratively. In contrast, we sum the resource vectors for +// regular containers since they run simultaneously. +// +// # The resources defined for Overhead should be added to the calculated Resource request sum +// +// Example: +// +// Pod: +// +// InitContainers +// IC1: +// CPU: 2 +// Memory: 1G +// IC2: +// CPU: 2 +// Memory: 3G +// Containers +// C1: +// CPU: 2 +// Memory: 1G +// C2: +// CPU: 1 +// Memory: 1G +// +// Result: CPU: 3, Memory: 3G +func computePodResourceRequest(pod *v1.Pod) *preFilterState { + result := &preFilterState{} + for _, container := range pod.Spec.Containers { + result.Add(container.Resources.Requests) + } + + // take max_resource(sum_pod, any_init_container) + for _, container := range pod.Spec.InitContainers { + result.SetMaxResource(container.Resources.Requests) + } + + // If Overhead is being utilized, add to the total requests for the pod + if pod.Spec.Overhead != nil { + result.Add(pod.Spec.Overhead) + } + return result +} + +// PreFilter invoked at the prefilter extension point. +func (f *Fit) PreFilter(ctx context.Context, cycleState *framework.CycleState, pod *v1.Pod) (*framework.PreFilterResult, *framework.Status) { + cycleState.Write(preFilterStateKey, computePodResourceRequest(pod)) + return nil, nil +} + +// PreFilterExtensions returns prefilter extensions, pod add and remove. +func (f *Fit) PreFilterExtensions() framework.PreFilterExtensions { + return nil +} + +func getPreFilterState(cycleState *framework.CycleState) (*preFilterState, error) { + c, err := cycleState.Read(preFilterStateKey) + if err != nil { + // preFilterState doesn't exist, likely PreFilter wasn't invoked. + return nil, fmt.Errorf("error reading %q from cycleState: %w", preFilterStateKey, err) + } + + s, ok := c.(*preFilterState) + if !ok { + return nil, fmt.Errorf("%+v convert to NodeResourcesFit.preFilterState error", c) + } + return s, nil +} + +// EventsToRegister returns the possible events that may make a Pod +// failed by this plugin schedulable. +// NOTE: if in-place-update (KEP 1287) gets implemented, then PodUpdate event +// should be registered for this plugin since a Pod update may free up resources +// that make other Pods schedulable. +func (f *Fit) EventsToRegister() []framework.ClusterEvent { + return []framework.ClusterEvent{ + {Resource: framework.Pod, ActionType: framework.Delete}, + {Resource: framework.Node, ActionType: framework.Add | framework.Update}, + } +} + +// Filter invoked at the filter extension point. +// Checks if a node has sufficient resources, such as cpu, memory, gpu, opaque int resources etc to run a pod. +// It returns a list of insufficient resources, if empty, then the node has all the resources requested by the pod. +func (f *Fit) Filter(ctx context.Context, cycleState *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status { + s, err := getPreFilterState(cycleState) + if err != nil { + return framework.AsStatus(err) + } + + insufficientResources := fitsRequest(s, nodeInfo, f.ignoredResources, f.ignoredResourceGroups) + + if len(insufficientResources) != 0 { + // We will keep all failure reasons. + failureReasons := make([]string, 0, len(insufficientResources)) + for i := range insufficientResources { + failureReasons = append(failureReasons, insufficientResources[i].Reason) + } + return framework.NewStatus(framework.Unschedulable, failureReasons...) + } + return nil +} + +// InsufficientResource describes what kind of resource limit is hit and caused the pod to not fit the node. +type InsufficientResource struct { + ResourceName v1.ResourceName + // We explicitly have a parameter for reason to avoid formatting a message on the fly + // for common resources, which is expensive for cluster autoscaler simulations. + Reason string + Requested int64 + Used int64 + Capacity int64 +} + +// Fits checks if node have enough resources to host the pod. +func Fits(pod *v1.Pod, nodeInfo *framework.NodeInfo) []InsufficientResource { + return fitsRequest(computePodResourceRequest(pod), nodeInfo, nil, nil) +} + +func fitsRequest(podRequest *preFilterState, nodeInfo *framework.NodeInfo, ignoredExtendedResources, ignoredResourceGroups sets.String) []InsufficientResource { + insufficientResources := make([]InsufficientResource, 0, 4) + + allowedPodNumber := nodeInfo.Allocatable.AllowedPodNumber + if len(nodeInfo.Pods)+1 > allowedPodNumber { + insufficientResources = append(insufficientResources, InsufficientResource{ + ResourceName: v1.ResourcePods, + Reason: "Too many pods", + Requested: 1, + Used: int64(len(nodeInfo.Pods)), + Capacity: int64(allowedPodNumber), + }) + } + + if podRequest.MilliCPU == 0 && + podRequest.Memory == 0 && + podRequest.EphemeralStorage == 0 && + len(podRequest.ScalarResources) == 0 { + return insufficientResources + } + + if podRequest.MilliCPU > (nodeInfo.Allocatable.MilliCPU - nodeInfo.Requested.MilliCPU) { + insufficientResources = append(insufficientResources, InsufficientResource{ + ResourceName: v1.ResourceCPU, + Reason: "Insufficient cpu", + Requested: podRequest.MilliCPU, + Used: nodeInfo.Requested.MilliCPU, + Capacity: nodeInfo.Allocatable.MilliCPU, + }) + } + if podRequest.Memory > (nodeInfo.Allocatable.Memory - nodeInfo.Requested.Memory) { + insufficientResources = append(insufficientResources, InsufficientResource{ + ResourceName: v1.ResourceMemory, + Reason: "Insufficient memory", + Requested: podRequest.Memory, + Used: nodeInfo.Requested.Memory, + Capacity: nodeInfo.Allocatable.Memory, + }) + } + if podRequest.EphemeralStorage > (nodeInfo.Allocatable.EphemeralStorage - nodeInfo.Requested.EphemeralStorage) { + insufficientResources = append(insufficientResources, InsufficientResource{ + ResourceName: v1.ResourceEphemeralStorage, + Reason: "Insufficient ephemeral-storage", + Requested: podRequest.EphemeralStorage, + Used: nodeInfo.Requested.EphemeralStorage, + Capacity: nodeInfo.Allocatable.EphemeralStorage, + }) + } + + for rName, rQuant := range podRequest.ScalarResources { + // Skip in case request quantity is zero + if rQuant == 0 { + continue + } + + if v1helper.IsExtendedResourceName(rName) { + // If this resource is one of the extended resources that should be ignored, we will skip checking it. + // rName is guaranteed to have a slash due to API validation. + var rNamePrefix string + if ignoredResourceGroups.Len() > 0 { + rNamePrefix = strings.Split(string(rName), "/")[0] + } + if ignoredExtendedResources.Has(string(rName)) || ignoredResourceGroups.Has(rNamePrefix) { + continue + } + } + + if rQuant > (nodeInfo.Allocatable.ScalarResources[rName] - nodeInfo.Requested.ScalarResources[rName]) { + insufficientResources = append(insufficientResources, InsufficientResource{ + ResourceName: rName, + Reason: fmt.Sprintf("Insufficient %v", rName), + Requested: podRequest.ScalarResources[rName], + Used: nodeInfo.Requested.ScalarResources[rName], + Capacity: nodeInfo.Allocatable.ScalarResources[rName], + }) + } + } + + return insufficientResources +} + +// Score invoked at the Score extension point. +func (f *Fit) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) { + nodeInfo, err := f.handle.SnapshotSharedLister().NodeInfos().Get(nodeName) + if err != nil { + return 0, framework.AsStatus(fmt.Errorf("getting node %q from Snapshot: %w", nodeName, err)) + } + + return f.score(pod, nodeInfo) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/least_allocated.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/least_allocated.go new file mode 100644 index 000000000..1abf97bc6 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/least_allocated.go @@ -0,0 +1,57 @@ +/* +Copyright 2019 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 noderesources + +import ( + "k8s.io/kubernetes/pkg/scheduler/framework" +) + +// leastResourceScorer favors nodes with fewer requested resources. +// It calculates the percentage of memory, CPU and other resources requested by pods scheduled on the node, and +// prioritizes based on the minimum of the average of the fraction of requested to capacity. +// +// Details: +// (cpu((capacity-requested)*MaxNodeScore*cpuWeight/capacity) + memory((capacity-requested)*MaxNodeScore*memoryWeight/capacity) + ...)/weightSum +func leastResourceScorer(resToWeightMap resourceToWeightMap) func(resourceToValueMap, resourceToValueMap) int64 { + return func(requested, allocable resourceToValueMap) int64 { + var nodeScore, weightSum int64 + for resource := range requested { + weight := resToWeightMap[resource] + resourceScore := leastRequestedScore(requested[resource], allocable[resource]) + nodeScore += resourceScore * weight + weightSum += weight + } + if weightSum == 0 { + return 0 + } + return nodeScore / weightSum + } +} + +// The unused capacity is calculated on a scale of 0-MaxNodeScore +// 0 being the lowest priority and `MaxNodeScore` being the highest. +// The more unused resources the higher the score is. +func leastRequestedScore(requested, capacity int64) int64 { + if capacity == 0 { + return 0 + } + if requested > capacity { + return 0 + } + + return ((capacity - requested) * int64(framework.MaxNodeScore)) / capacity +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/most_allocated.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/most_allocated.go new file mode 100644 index 000000000..94c55cbe3 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/most_allocated.go @@ -0,0 +1,61 @@ +/* +Copyright 2019 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 noderesources + +import ( + "k8s.io/kubernetes/pkg/scheduler/framework" +) + +// mostResourceScorer favors nodes with most requested resources. +// It calculates the percentage of memory and CPU requested by pods scheduled on the node, and prioritizes +// based on the maximum of the average of the fraction of requested to capacity. +// +// Details: +// (cpu(MaxNodeScore * requested * cpuWeight / capacity) + memory(MaxNodeScore * requested * memoryWeight / capacity) + ...) / weightSum +func mostResourceScorer(resToWeightMap resourceToWeightMap) func(requested, allocable resourceToValueMap) int64 { + return func(requested, allocable resourceToValueMap) int64 { + var nodeScore, weightSum int64 + for resource := range requested { + weight := resToWeightMap[resource] + resourceScore := mostRequestedScore(requested[resource], allocable[resource]) + nodeScore += resourceScore * weight + weightSum += weight + } + if weightSum == 0 { + return 0 + } + return nodeScore / weightSum + } +} + +// The used capacity is calculated on a scale of 0-MaxNodeScore (MaxNodeScore is +// constant with value set to 100). +// 0 being the lowest priority and 100 being the highest. +// The more resources are used the higher the score is. This function +// is almost a reversed version of noderesources.leastRequestedScore. +func mostRequestedScore(requested, capacity int64) int64 { + if capacity == 0 { + return 0 + } + if requested > capacity { + // `requested` might be greater than `capacity` because pods with no + // requests get minimum values. + requested = capacity + } + + return (requested * framework.MaxNodeScore) / capacity +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/requested_to_capacity_ratio.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/requested_to_capacity_ratio.go new file mode 100644 index 000000000..36cd9f1e6 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/requested_to_capacity_ratio.go @@ -0,0 +1,70 @@ +/* +Copyright 2019 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 noderesources + +import ( + "math" + + "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper" +) + +const maxUtilization = 100 + +// buildRequestedToCapacityRatioScorerFunction allows users to apply bin packing +// on core resources like CPU, Memory as well as extended resources like accelerators. +func buildRequestedToCapacityRatioScorerFunction(scoringFunctionShape helper.FunctionShape, resourceToWeightMap resourceToWeightMap) func(resourceToValueMap, resourceToValueMap) int64 { + rawScoringFunction := helper.BuildBrokenLinearFunction(scoringFunctionShape) + resourceScoringFunction := func(requested, capacity int64) int64 { + if capacity == 0 || requested > capacity { + return rawScoringFunction(maxUtilization) + } + + return rawScoringFunction(requested * maxUtilization / capacity) + } + return func(requested, allocable resourceToValueMap) int64 { + var nodeScore, weightSum int64 + for resource := range requested { + weight := resourceToWeightMap[resource] + resourceScore := resourceScoringFunction(requested[resource], allocable[resource]) + if resourceScore > 0 { + nodeScore += resourceScore * weight + weightSum += weight + } + } + if weightSum == 0 { + return 0 + } + return int64(math.Round(float64(nodeScore) / float64(weightSum))) + } +} + +func requestedToCapacityRatioScorer(weightMap resourceToWeightMap, shape []config.UtilizationShapePoint) func(resourceToValueMap, resourceToValueMap) int64 { + shapes := make([]helper.FunctionShapePoint, 0, len(shape)) + for _, point := range shape { + shapes = append(shapes, helper.FunctionShapePoint{ + Utilization: int64(point.Utilization), + // MaxCustomPriorityScore may diverge from the max score used in the scheduler and defined by MaxNodeScore, + // therefore we need to scale the score returned by requested to capacity ratio to the score range + // used by the scheduler. + Score: int64(point.Score) * (framework.MaxNodeScore / config.MaxCustomPriorityScore), + }) + } + + return buildRequestedToCapacityRatioScorerFunction(shapes, weightMap) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/resource_allocation.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/resource_allocation.go new file mode 100644 index 000000000..6715ccffa --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/resource_allocation.go @@ -0,0 +1,146 @@ +/* +Copyright 2017 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 noderesources + +import ( + v1 "k8s.io/api/core/v1" + "k8s.io/klog/v2" + "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/kubernetes/pkg/scheduler/framework" + schedutil "k8s.io/kubernetes/pkg/scheduler/util" +) + +// resourceToWeightMap contains resource name and weight. +type resourceToWeightMap map[v1.ResourceName]int64 + +// scorer is decorator for resourceAllocationScorer +type scorer func(args *config.NodeResourcesFitArgs) *resourceAllocationScorer + +// resourceAllocationScorer contains information to calculate resource allocation score. +type resourceAllocationScorer struct { + Name string + // used to decide whether to use Requested or NonZeroRequested for + // cpu and memory. + useRequested bool + scorer func(requested, allocable resourceToValueMap) int64 + resourceToWeightMap resourceToWeightMap +} + +// resourceToValueMap is keyed with resource name and valued with quantity. +type resourceToValueMap map[v1.ResourceName]int64 + +// score will use `scorer` function to calculate the score. +func (r *resourceAllocationScorer) score( + pod *v1.Pod, + nodeInfo *framework.NodeInfo) (int64, *framework.Status) { + node := nodeInfo.Node() + if node == nil { + return 0, framework.NewStatus(framework.Error, "node not found") + } + if r.resourceToWeightMap == nil { + return 0, framework.NewStatus(framework.Error, "resources not found") + } + + requested := make(resourceToValueMap) + allocatable := make(resourceToValueMap) + for resource := range r.resourceToWeightMap { + alloc, req := r.calculateResourceAllocatableRequest(nodeInfo, pod, resource) + if alloc != 0 { + // Only fill the extended resource entry when it's non-zero. + allocatable[resource], requested[resource] = alloc, req + } + } + + score := r.scorer(requested, allocatable) + + klog.V(10).InfoS("Listing internal info for allocatable resources, requested resources and score", "pod", + klog.KObj(pod), "node", klog.KObj(node), "resourceAllocationScorer", r.Name, + "allocatableResource", allocatable, "requestedResource", requested, "resourceScore", score, + ) + + return score, nil +} + +// calculateResourceAllocatableRequest returns 2 parameters: +// - 1st param: quantity of allocatable resource on the node. +// - 2nd param: aggregated quantity of requested resource on the node. +// Note: if it's an extended resource, and the pod doesn't request it, (0, 0) is returned. +func (r *resourceAllocationScorer) calculateResourceAllocatableRequest(nodeInfo *framework.NodeInfo, pod *v1.Pod, resource v1.ResourceName) (int64, int64) { + requested := nodeInfo.NonZeroRequested + if r.useRequested { + requested = nodeInfo.Requested + } + + podRequest := r.calculatePodResourceRequest(pod, resource) + // If it's an extended resource, and the pod doesn't request it. We return (0, 0) + // as an implication to bypass scoring on this resource. + if podRequest == 0 && schedutil.IsScalarResourceName(resource) { + return 0, 0 + } + switch resource { + case v1.ResourceCPU: + return nodeInfo.Allocatable.MilliCPU, (requested.MilliCPU + podRequest) + case v1.ResourceMemory: + return nodeInfo.Allocatable.Memory, (requested.Memory + podRequest) + case v1.ResourceEphemeralStorage: + return nodeInfo.Allocatable.EphemeralStorage, (nodeInfo.Requested.EphemeralStorage + podRequest) + default: + if _, exists := nodeInfo.Allocatable.ScalarResources[resource]; exists { + return nodeInfo.Allocatable.ScalarResources[resource], (nodeInfo.Requested.ScalarResources[resource] + podRequest) + } + } + klog.V(10).InfoS("Requested resource is omitted for node score calculation", "resourceName", resource) + return 0, 0 +} + +// calculatePodResourceRequest returns the total non-zero requests. If Overhead is defined for the pod +// the Overhead is added to the result. +// podResourceRequest = max(sum(podSpec.Containers), podSpec.InitContainers) + overHead +func (r *resourceAllocationScorer) calculatePodResourceRequest(pod *v1.Pod, resource v1.ResourceName) int64 { + var podRequest int64 + for i := range pod.Spec.Containers { + container := &pod.Spec.Containers[i] + value := schedutil.GetRequestForResource(resource, &container.Resources.Requests, !r.useRequested) + podRequest += value + } + + for i := range pod.Spec.InitContainers { + initContainer := &pod.Spec.InitContainers[i] + value := schedutil.GetRequestForResource(resource, &initContainer.Resources.Requests, !r.useRequested) + if podRequest < value { + podRequest = value + } + } + + // If Overhead is being utilized, add to the total requests for the pod + if pod.Spec.Overhead != nil { + if quantity, found := pod.Spec.Overhead[resource]; found { + podRequest += quantity.Value() + } + } + + return podRequest +} + +// resourcesToWeightMap make weightmap from resources spec +func resourcesToWeightMap(resources []config.ResourceSpec) resourceToWeightMap { + resourceToWeightMap := make(resourceToWeightMap) + for _, resource := range resources { + resourceToWeightMap[v1.ResourceName(resource.Name)] = resource.Weight + } + return resourceToWeightMap +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/test_util.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/test_util.go new file mode 100644 index 000000000..bcaf2fcd3 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/test_util.go @@ -0,0 +1,56 @@ +/* +Copyright 2019 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 noderesources + +import ( + "github.com/google/go-cmp/cmp/cmpopts" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/kubernetes/pkg/scheduler/apis/config" +) + +var ( + ignoreBadValueDetail = cmpopts.IgnoreFields(field.Error{}, "BadValue", "Detail") + defaultResources = []config.ResourceSpec{ + {Name: string(v1.ResourceCPU), Weight: 1}, + {Name: string(v1.ResourceMemory), Weight: 1}, + } + extendedRes = "abc.com/xyz" + extendedResourceSet = []config.ResourceSpec{ + {Name: string(v1.ResourceCPU), Weight: 1}, + {Name: string(v1.ResourceMemory), Weight: 1}, + {Name: extendedRes, Weight: 1}, + } +) + +func makeNode(node string, milliCPU, memory int64, extendedResource map[string]int64) *v1.Node { + resourceList := make(map[v1.ResourceName]resource.Quantity) + for res, quantity := range extendedResource { + resourceList[v1.ResourceName(res)] = *resource.NewQuantity(quantity, resource.DecimalSI) + } + resourceList[v1.ResourceCPU] = *resource.NewMilliQuantity(milliCPU, resource.DecimalSI) + resourceList[v1.ResourceMemory] = *resource.NewQuantity(memory, resource.BinarySI) + return &v1.Node{ + ObjectMeta: metav1.ObjectMeta{Name: node}, + Status: v1.NodeStatus{ + Capacity: resourceList, + Allocatable: resourceList, + }, + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeunschedulable/node_unschedulable.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeunschedulable/node_unschedulable.go new file mode 100644 index 000000000..47231837e --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeunschedulable/node_unschedulable.go @@ -0,0 +1,80 @@ +/* +Copyright 2019 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 nodeunschedulable + +import ( + "context" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + v1helper "k8s.io/component-helpers/scheduling/corev1" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" +) + +// NodeUnschedulable plugin filters nodes that set node.Spec.Unschedulable=true unless +// the pod tolerates {key=node.kubernetes.io/unschedulable, effect:NoSchedule} taint. +type NodeUnschedulable struct { +} + +var _ framework.FilterPlugin = &NodeUnschedulable{} +var _ framework.EnqueueExtensions = &NodeUnschedulable{} + +// Name is the name of the plugin used in the plugin registry and configurations. +const Name = names.NodeUnschedulable + +const ( + // ErrReasonUnknownCondition is used for NodeUnknownCondition predicate error. + ErrReasonUnknownCondition = "node(s) had unknown conditions" + // ErrReasonUnschedulable is used for NodeUnschedulable predicate error. + ErrReasonUnschedulable = "node(s) were unschedulable" +) + +// EventsToRegister returns the possible events that may make a Pod +// failed by this plugin schedulable. +func (pl *NodeUnschedulable) EventsToRegister() []framework.ClusterEvent { + return []framework.ClusterEvent{ + {Resource: framework.Node, ActionType: framework.Add | framework.UpdateNodeTaint}, + } +} + +// Name returns name of the plugin. It is used in logs, etc. +func (pl *NodeUnschedulable) Name() string { + return Name +} + +// Filter invoked at the filter extension point. +func (pl *NodeUnschedulable) Filter(ctx context.Context, _ *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status { + node := nodeInfo.Node() + if node == nil { + return framework.NewStatus(framework.UnschedulableAndUnresolvable, ErrReasonUnknownCondition) + } + // If pod tolerate unschedulable taint, it's also tolerate `node.Spec.Unschedulable`. + podToleratesUnschedulable := v1helper.TolerationsTolerateTaint(pod.Spec.Tolerations, &v1.Taint{ + Key: v1.TaintNodeUnschedulable, + Effect: v1.TaintEffectNoSchedule, + }) + if node.Spec.Unschedulable && !podToleratesUnschedulable { + return framework.NewStatus(framework.UnschedulableAndUnresolvable, ErrReasonUnschedulable) + } + return nil +} + +// New initializes a new plugin and returns it. +func New(_ runtime.Object, _ framework.Handle) (framework.Plugin, error) { + return &NodeUnschedulable{}, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodevolumelimits/csi.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodevolumelimits/csi.go new file mode 100644 index 000000000..ab2d335f6 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodevolumelimits/csi.go @@ -0,0 +1,392 @@ +/* +Copyright 2019 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 nodevolumelimits + +import ( + "context" + "fmt" + + v1 "k8s.io/api/core/v1" + storagev1 "k8s.io/api/storage/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/rand" + corelisters "k8s.io/client-go/listers/core/v1" + storagelisters "k8s.io/client-go/listers/storage/v1" + ephemeral "k8s.io/component-helpers/storage/ephemeral" + storagehelpers "k8s.io/component-helpers/storage/volume" + csitrans "k8s.io/csi-translation-lib" + "k8s.io/klog/v2" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" + volumeutil "k8s.io/kubernetes/pkg/volume/util" +) + +// InTreeToCSITranslator contains methods required to check migratable status +// and perform translations from InTree PV's to CSI +type InTreeToCSITranslator interface { + IsPVMigratable(pv *v1.PersistentVolume) bool + IsInlineMigratable(vol *v1.Volume) bool + IsMigratableIntreePluginByName(inTreePluginName string) bool + GetInTreePluginNameFromSpec(pv *v1.PersistentVolume, vol *v1.Volume) (string, error) + GetCSINameFromInTreeName(pluginName string) (string, error) + TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) + TranslateInTreeInlineVolumeToCSI(volume *v1.Volume, podNamespace string) (*v1.PersistentVolume, error) +} + +// CSILimits is a plugin that checks node volume limits. +type CSILimits struct { + csiNodeLister storagelisters.CSINodeLister + pvLister corelisters.PersistentVolumeLister + pvcLister corelisters.PersistentVolumeClaimLister + scLister storagelisters.StorageClassLister + + randomVolumeIDPrefix string + + translator InTreeToCSITranslator +} + +var _ framework.FilterPlugin = &CSILimits{} +var _ framework.EnqueueExtensions = &CSILimits{} + +// CSIName is the name of the plugin used in the plugin registry and configurations. +const CSIName = names.NodeVolumeLimits + +// Name returns name of the plugin. It is used in logs, etc. +func (pl *CSILimits) Name() string { + return CSIName +} + +// EventsToRegister returns the possible events that may make a Pod +// failed by this plugin schedulable. +func (pl *CSILimits) EventsToRegister() []framework.ClusterEvent { + return []framework.ClusterEvent{ + {Resource: framework.CSINode, ActionType: framework.Add}, + {Resource: framework.Pod, ActionType: framework.Delete}, + } +} + +// Filter invoked at the filter extension point. +func (pl *CSILimits) Filter(ctx context.Context, _ *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status { + // If the new pod doesn't have any volume attached to it, the predicate will always be true + if len(pod.Spec.Volumes) == 0 { + return nil + } + + node := nodeInfo.Node() + if node == nil { + return framework.NewStatus(framework.Error, "node not found") + } + + // If CSINode doesn't exist, the predicate may read the limits from Node object + csiNode, err := pl.csiNodeLister.Get(node.Name) + if err != nil { + // TODO: return the error once CSINode is created by default (2 releases) + klog.V(5).InfoS("Could not get a CSINode object for the node", "node", klog.KObj(node), "err", err) + } + + newVolumes := make(map[string]string) + if err := pl.filterAttachableVolumes(pod, csiNode, true /* new pod */, newVolumes); err != nil { + return framework.AsStatus(err) + } + + // If the pod doesn't have any new CSI volumes, the predicate will always be true + if len(newVolumes) == 0 { + return nil + } + + // If the node doesn't have volume limits, the predicate will always be true + nodeVolumeLimits := getVolumeLimits(nodeInfo, csiNode) + if len(nodeVolumeLimits) == 0 { + return nil + } + + attachedVolumes := make(map[string]string) + for _, existingPod := range nodeInfo.Pods { + if err := pl.filterAttachableVolumes(existingPod.Pod, csiNode, false /* existing pod */, attachedVolumes); err != nil { + return framework.AsStatus(err) + } + } + + attachedVolumeCount := map[string]int{} + for volumeUniqueName, volumeLimitKey := range attachedVolumes { + // Don't count single volume used in multiple pods more than once + delete(newVolumes, volumeUniqueName) + attachedVolumeCount[volumeLimitKey]++ + } + + newVolumeCount := map[string]int{} + for _, volumeLimitKey := range newVolumes { + newVolumeCount[volumeLimitKey]++ + } + + for volumeLimitKey, count := range newVolumeCount { + maxVolumeLimit, ok := nodeVolumeLimits[v1.ResourceName(volumeLimitKey)] + if ok { + currentVolumeCount := attachedVolumeCount[volumeLimitKey] + klog.V(5).InfoS("Found plugin volume limits", "node", node.Name, "volumeLimitKey", volumeLimitKey, + "maxLimits", maxVolumeLimit, "currentVolumeCount", currentVolumeCount, "newVolumeCount", count, + "pod", klog.KObj(pod)) + if currentVolumeCount+count > int(maxVolumeLimit) { + return framework.NewStatus(framework.Unschedulable, ErrReasonMaxVolumeCountExceeded) + } + } + } + + return nil +} + +func (pl *CSILimits) filterAttachableVolumes( + pod *v1.Pod, csiNode *storagev1.CSINode, newPod bool, result map[string]string) error { + for _, vol := range pod.Spec.Volumes { + pvcName := "" + isEphemeral := false + switch { + case vol.PersistentVolumeClaim != nil: + // Normal CSI volume can only be used through PVC + pvcName = vol.PersistentVolumeClaim.ClaimName + case vol.Ephemeral != nil: + // Generic ephemeral inline volumes also use a PVC, + // just with a computed name and certain ownership. + // That is checked below once the pvc object is + // retrieved. + pvcName = ephemeral.VolumeClaimName(pod, &vol) + isEphemeral = true + default: + // Inline Volume does not have PVC. + // Need to check if CSI migration is enabled for this inline volume. + // - If the volume is migratable and CSI migration is enabled, need to count it + // as well. + // - If the volume is not migratable, it will be count in non_csi filter. + if err := pl.checkAttachableInlineVolume(vol, csiNode, pod, result); err != nil { + return err + } + + continue + } + + if pvcName == "" { + return fmt.Errorf("PersistentVolumeClaim had no name") + } + + pvc, err := pl.pvcLister.PersistentVolumeClaims(pod.Namespace).Get(pvcName) + + if err != nil { + if newPod { + // The PVC is required to proceed with + // scheduling of a new pod because it cannot + // run without it. Bail out immediately. + return fmt.Errorf("looking up PVC %s/%s: %v", pod.Namespace, pvcName, err) + } + // If the PVC is invalid, we don't count the volume because + // there's no guarantee that it belongs to the running predicate. + klog.V(5).InfoS("Unable to look up PVC info", "pod", klog.KObj(pod), "PVC", klog.KRef(pod.Namespace, pvcName)) + continue + } + + // The PVC for an ephemeral volume must be owned by the pod. + if isEphemeral { + if err := ephemeral.VolumeIsForPod(pod, pvc); err != nil { + return err + } + } + + driverName, volumeHandle := pl.getCSIDriverInfo(csiNode, pvc) + if driverName == "" || volumeHandle == "" { + klog.V(5).InfoS("Could not find a CSI driver name or volume handle, not counting volume") + continue + } + + volumeUniqueName := fmt.Sprintf("%s/%s", driverName, volumeHandle) + volumeLimitKey := volumeutil.GetCSIAttachLimitKey(driverName) + result[volumeUniqueName] = volumeLimitKey + } + return nil +} + +// checkAttachableInlineVolume takes an inline volume and add to the result map if the +// volume is migratable and CSI migration for this plugin has been enabled. +func (pl *CSILimits) checkAttachableInlineVolume(vol v1.Volume, csiNode *storagev1.CSINode, + pod *v1.Pod, result map[string]string) error { + if !pl.translator.IsInlineMigratable(&vol) { + return nil + } + // Check if the intree provisioner CSI migration has been enabled. + inTreeProvisionerName, err := pl.translator.GetInTreePluginNameFromSpec(nil, &vol) + if err != nil { + return fmt.Errorf("looking up provisioner name for volume %v: %w", vol, err) + } + if !isCSIMigrationOn(csiNode, inTreeProvisionerName) { + csiNodeName := "" + if csiNode != nil { + csiNodeName = csiNode.Name + } + klog.V(5).InfoS("CSI Migration is not enabled for provisioner", "provisioner", inTreeProvisionerName, + "pod", klog.KObj(pod), "csiNode", csiNodeName) + return nil + } + // Do translation for the in-tree volume. + translatedPV, err := pl.translator.TranslateInTreeInlineVolumeToCSI(&vol, pod.Namespace) + if err != nil || translatedPV == nil { + return fmt.Errorf("converting volume(%v) from inline to csi: %w", vol, err) + } + driverName, err := pl.translator.GetCSINameFromInTreeName(inTreeProvisionerName) + if err != nil { + return fmt.Errorf("looking up CSI driver name for provisioner %s: %w", inTreeProvisionerName, err) + } + // TranslateInTreeInlineVolumeToCSI should translate inline volume to CSI. If it is not set, + // the volume does not support inline. Skip the count. + if translatedPV.Spec.PersistentVolumeSource.CSI == nil { + return nil + } + volumeUniqueName := fmt.Sprintf("%s/%s", driverName, translatedPV.Spec.PersistentVolumeSource.CSI.VolumeHandle) + volumeLimitKey := volumeutil.GetCSIAttachLimitKey(driverName) + result[volumeUniqueName] = volumeLimitKey + return nil +} + +// getCSIDriverInfo returns the CSI driver name and volume ID of a given PVC. +// If the PVC is from a migrated in-tree plugin, this function will return +// the information of the CSI driver that the plugin has been migrated to. +func (pl *CSILimits) getCSIDriverInfo(csiNode *storagev1.CSINode, pvc *v1.PersistentVolumeClaim) (string, string) { + pvName := pvc.Spec.VolumeName + + if pvName == "" { + klog.V(5).InfoS("Persistent volume had no name for claim", "PVC", klog.KObj(pvc)) + return pl.getCSIDriverInfoFromSC(csiNode, pvc) + } + + pv, err := pl.pvLister.Get(pvName) + if err != nil { + klog.V(5).InfoS("Unable to look up PV info for PVC and PV", "PVC", klog.KObj(pvc), "PV", klog.KRef("", pvName)) + // If we can't fetch PV associated with PVC, may be it got deleted + // or PVC was prebound to a PVC that hasn't been created yet. + // fallback to using StorageClass for volume counting + return pl.getCSIDriverInfoFromSC(csiNode, pvc) + } + + csiSource := pv.Spec.PersistentVolumeSource.CSI + if csiSource == nil { + // We make a fast path for non-CSI volumes that aren't migratable + if !pl.translator.IsPVMigratable(pv) { + return "", "" + } + + pluginName, err := pl.translator.GetInTreePluginNameFromSpec(pv, nil) + if err != nil { + klog.V(5).InfoS("Unable to look up plugin name from PV spec", "err", err) + return "", "" + } + + if !isCSIMigrationOn(csiNode, pluginName) { + klog.V(5).InfoS("CSI Migration of plugin is not enabled", "plugin", pluginName) + return "", "" + } + + csiPV, err := pl.translator.TranslateInTreePVToCSI(pv) + if err != nil { + klog.V(5).InfoS("Unable to translate in-tree volume to CSI", "err", err) + return "", "" + } + + if csiPV.Spec.PersistentVolumeSource.CSI == nil { + klog.V(5).InfoS("Unable to get a valid volume source for translated PV", "PV", pvName) + return "", "" + } + + csiSource = csiPV.Spec.PersistentVolumeSource.CSI + } + + return csiSource.Driver, csiSource.VolumeHandle +} + +// getCSIDriverInfoFromSC returns the CSI driver name and a random volume ID of a given PVC's StorageClass. +func (pl *CSILimits) getCSIDriverInfoFromSC(csiNode *storagev1.CSINode, pvc *v1.PersistentVolumeClaim) (string, string) { + namespace := pvc.Namespace + pvcName := pvc.Name + scName := storagehelpers.GetPersistentVolumeClaimClass(pvc) + + // If StorageClass is not set or not found, then PVC must be using immediate binding mode + // and hence it must be bound before scheduling. So it is safe to not count it. + if scName == "" { + klog.V(5).InfoS("PVC has no StorageClass", "PVC", klog.KObj(pvc)) + return "", "" + } + + storageClass, err := pl.scLister.Get(scName) + if err != nil { + klog.V(5).InfoS("Could not get StorageClass for PVC", "PVC", klog.KObj(pvc), "err", err) + return "", "" + } + + // We use random prefix to avoid conflict with volume IDs. If PVC is bound during the execution of the + // predicate and there is another pod on the same node that uses same volume, then we will overcount + // the volume and consider both volumes as different. + volumeHandle := fmt.Sprintf("%s-%s/%s", pl.randomVolumeIDPrefix, namespace, pvcName) + + provisioner := storageClass.Provisioner + if pl.translator.IsMigratableIntreePluginByName(provisioner) { + if !isCSIMigrationOn(csiNode, provisioner) { + klog.V(5).InfoS("CSI Migration of provisioner is not enabled", "provisioner", provisioner) + return "", "" + } + + driverName, err := pl.translator.GetCSINameFromInTreeName(provisioner) + if err != nil { + klog.V(5).InfoS("Unable to look up driver name from provisioner name", "provisioner", provisioner, "err", err) + return "", "" + } + return driverName, volumeHandle + } + + return provisioner, volumeHandle +} + +// NewCSI initializes a new plugin and returns it. +func NewCSI(_ runtime.Object, handle framework.Handle, fts feature.Features) (framework.Plugin, error) { + informerFactory := handle.SharedInformerFactory() + pvLister := informerFactory.Core().V1().PersistentVolumes().Lister() + pvcLister := informerFactory.Core().V1().PersistentVolumeClaims().Lister() + csiNodesLister := informerFactory.Storage().V1().CSINodes().Lister() + scLister := informerFactory.Storage().V1().StorageClasses().Lister() + csiTranslator := csitrans.New() + + return &CSILimits{ + csiNodeLister: csiNodesLister, + pvLister: pvLister, + pvcLister: pvcLister, + scLister: scLister, + randomVolumeIDPrefix: rand.String(32), + translator: csiTranslator, + }, nil +} + +func getVolumeLimits(nodeInfo *framework.NodeInfo, csiNode *storagev1.CSINode) map[v1.ResourceName]int64 { + // TODO: stop getting values from Node object in v1.18 + nodeVolumeLimits := volumeLimits(nodeInfo) + if csiNode != nil { + for i := range csiNode.Spec.Drivers { + d := csiNode.Spec.Drivers[i] + if d.Allocatable != nil && d.Allocatable.Count != nil { + // TODO: drop GetCSIAttachLimitKey once we don't get values from Node object (v1.18) + k := v1.ResourceName(volumeutil.GetCSIAttachLimitKey(d.Name)) + nodeVolumeLimits[k] = int64(*d.Allocatable.Count) + } + } + } + return nodeVolumeLimits +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodevolumelimits/non_csi.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodevolumelimits/non_csi.go new file mode 100644 index 000000000..4a2535e5f --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodevolumelimits/non_csi.go @@ -0,0 +1,538 @@ +/* +Copyright 2019 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 nodevolumelimits + +import ( + "context" + "errors" + "fmt" + "os" + "regexp" + "strconv" + + v1 "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/rand" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/client-go/informers" + corelisters "k8s.io/client-go/listers/core/v1" + storagelisters "k8s.io/client-go/listers/storage/v1" + "k8s.io/component-helpers/storage/ephemeral" + csilibplugins "k8s.io/csi-translation-lib/plugins" + "k8s.io/klog/v2" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" + volumeutil "k8s.io/kubernetes/pkg/volume/util" +) + +const ( + // defaultMaxGCEPDVolumes defines the maximum number of PD Volumes for GCE. + // GCE instances can have up to 16 PD volumes attached. + defaultMaxGCEPDVolumes = 16 + // defaultMaxAzureDiskVolumes defines the maximum number of PD Volumes for Azure. + // Larger Azure VMs can actually have much more disks attached. + // TODO We should determine the max based on VM size + defaultMaxAzureDiskVolumes = 16 + + // ebsVolumeFilterType defines the filter name for ebsVolumeFilter. + ebsVolumeFilterType = "EBS" + // gcePDVolumeFilterType defines the filter name for gcePDVolumeFilter. + gcePDVolumeFilterType = "GCE" + // azureDiskVolumeFilterType defines the filter name for azureDiskVolumeFilter. + azureDiskVolumeFilterType = "AzureDisk" + // cinderVolumeFilterType defines the filter name for cinderVolumeFilter. + cinderVolumeFilterType = "Cinder" + + // ErrReasonMaxVolumeCountExceeded is used for MaxVolumeCount predicate error. + ErrReasonMaxVolumeCountExceeded = "node(s) exceed max volume count" + + // KubeMaxPDVols defines the maximum number of PD Volumes per kubelet. + KubeMaxPDVols = "KUBE_MAX_PD_VOLS" +) + +// AzureDiskName is the name of the plugin used in the plugin registry and configurations. +const AzureDiskName = names.AzureDiskLimits + +// NewAzureDisk returns function that initializes a new plugin and returns it. +func NewAzureDisk(_ runtime.Object, handle framework.Handle, fts feature.Features) (framework.Plugin, error) { + informerFactory := handle.SharedInformerFactory() + return newNonCSILimitsWithInformerFactory(azureDiskVolumeFilterType, informerFactory, fts), nil +} + +// CinderName is the name of the plugin used in the plugin registry and configurations. +const CinderName = names.CinderLimits + +// NewCinder returns function that initializes a new plugin and returns it. +func NewCinder(_ runtime.Object, handle framework.Handle, fts feature.Features) (framework.Plugin, error) { + informerFactory := handle.SharedInformerFactory() + return newNonCSILimitsWithInformerFactory(cinderVolumeFilterType, informerFactory, fts), nil +} + +// EBSName is the name of the plugin used in the plugin registry and configurations. +const EBSName = names.EBSLimits + +// NewEBS returns function that initializes a new plugin and returns it. +func NewEBS(_ runtime.Object, handle framework.Handle, fts feature.Features) (framework.Plugin, error) { + informerFactory := handle.SharedInformerFactory() + return newNonCSILimitsWithInformerFactory(ebsVolumeFilterType, informerFactory, fts), nil +} + +// GCEPDName is the name of the plugin used in the plugin registry and configurations. +const GCEPDName = names.GCEPDLimits + +// NewGCEPD returns function that initializes a new plugin and returns it. +func NewGCEPD(_ runtime.Object, handle framework.Handle, fts feature.Features) (framework.Plugin, error) { + informerFactory := handle.SharedInformerFactory() + return newNonCSILimitsWithInformerFactory(gcePDVolumeFilterType, informerFactory, fts), nil +} + +// nonCSILimits contains information to check the max number of volumes for a plugin. +type nonCSILimits struct { + name string + filter VolumeFilter + volumeLimitKey v1.ResourceName + maxVolumeFunc func(node *v1.Node) int + csiNodeLister storagelisters.CSINodeLister + pvLister corelisters.PersistentVolumeLister + pvcLister corelisters.PersistentVolumeClaimLister + scLister storagelisters.StorageClassLister + + // The string below is generated randomly during the struct's initialization. + // It is used to prefix volumeID generated inside the predicate() method to + // avoid conflicts with any real volume. + randomVolumeIDPrefix string +} + +var _ framework.FilterPlugin = &nonCSILimits{} +var _ framework.EnqueueExtensions = &nonCSILimits{} + +// newNonCSILimitsWithInformerFactory returns a plugin with filter name and informer factory. +func newNonCSILimitsWithInformerFactory( + filterName string, + informerFactory informers.SharedInformerFactory, + fts feature.Features, +) framework.Plugin { + pvLister := informerFactory.Core().V1().PersistentVolumes().Lister() + pvcLister := informerFactory.Core().V1().PersistentVolumeClaims().Lister() + csiNodesLister := informerFactory.Storage().V1().CSINodes().Lister() + scLister := informerFactory.Storage().V1().StorageClasses().Lister() + + return newNonCSILimits(filterName, csiNodesLister, scLister, pvLister, pvcLister, fts) +} + +// newNonCSILimits creates a plugin which evaluates whether a pod can fit based on the +// number of volumes which match a filter that it requests, and those that are already present. +// +// DEPRECATED +// All cloudprovider specific predicates defined here are deprecated in favour of CSI volume limit +// predicate - MaxCSIVolumeCountPred. +// +// The predicate looks for both volumes used directly, as well as PVC volumes that are backed by relevant volume +// types, counts the number of unique volumes, and rejects the new pod if it would place the total count over +// the maximum. +func newNonCSILimits( + filterName string, + csiNodeLister storagelisters.CSINodeLister, + scLister storagelisters.StorageClassLister, + pvLister corelisters.PersistentVolumeLister, + pvcLister corelisters.PersistentVolumeClaimLister, + fts feature.Features, +) framework.Plugin { + var filter VolumeFilter + var volumeLimitKey v1.ResourceName + var name string + + switch filterName { + case ebsVolumeFilterType: + name = EBSName + filter = ebsVolumeFilter + volumeLimitKey = v1.ResourceName(volumeutil.EBSVolumeLimitKey) + case gcePDVolumeFilterType: + name = GCEPDName + filter = gcePDVolumeFilter + volumeLimitKey = v1.ResourceName(volumeutil.GCEVolumeLimitKey) + case azureDiskVolumeFilterType: + name = AzureDiskName + filter = azureDiskVolumeFilter + volumeLimitKey = v1.ResourceName(volumeutil.AzureVolumeLimitKey) + case cinderVolumeFilterType: + name = CinderName + filter = cinderVolumeFilter + volumeLimitKey = v1.ResourceName(volumeutil.CinderVolumeLimitKey) + default: + klog.ErrorS(errors.New("wrong filterName"), "Cannot create nonCSILimits plugin") + return nil + } + pl := &nonCSILimits{ + name: name, + filter: filter, + volumeLimitKey: volumeLimitKey, + maxVolumeFunc: getMaxVolumeFunc(filterName), + csiNodeLister: csiNodeLister, + pvLister: pvLister, + pvcLister: pvcLister, + scLister: scLister, + randomVolumeIDPrefix: rand.String(32), + } + + return pl +} + +// Name returns name of the plugin. It is used in logs, etc. +func (pl *nonCSILimits) Name() string { + return pl.name +} + +// EventsToRegister returns the possible events that may make a Pod +// failed by this plugin schedulable. +func (pl *nonCSILimits) EventsToRegister() []framework.ClusterEvent { + return []framework.ClusterEvent{ + {Resource: framework.Node, ActionType: framework.Add}, + {Resource: framework.Pod, ActionType: framework.Delete}, + } +} + +// Filter invoked at the filter extension point. +func (pl *nonCSILimits) Filter(ctx context.Context, _ *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status { + // If a pod doesn't have any volume attached to it, the predicate will always be true. + // Thus we make a fast path for it, to avoid unnecessary computations in this case. + if len(pod.Spec.Volumes) == 0 { + return nil + } + + newVolumes := make(sets.String) + if err := pl.filterVolumes(pod, true /* new pod */, newVolumes); err != nil { + return framework.AsStatus(err) + } + + // quick return + if len(newVolumes) == 0 { + return nil + } + + node := nodeInfo.Node() + if node == nil { + return framework.NewStatus(framework.Error, "node not found") + } + + var csiNode *storage.CSINode + var err error + if pl.csiNodeLister != nil { + csiNode, err = pl.csiNodeLister.Get(node.Name) + if err != nil { + // we don't fail here because the CSINode object is only necessary + // for determining whether the migration is enabled or not + klog.V(5).InfoS("Could not get a CSINode object for the node", "node", klog.KObj(node), "err", err) + } + } + + // if a plugin has been migrated to a CSI driver, defer to the CSI predicate + if pl.filter.IsMigrated(csiNode) { + return nil + } + + // count unique volumes + existingVolumes := make(sets.String) + for _, existingPod := range nodeInfo.Pods { + if err := pl.filterVolumes(existingPod.Pod, false /* existing pod */, existingVolumes); err != nil { + return framework.AsStatus(err) + } + } + numExistingVolumes := len(existingVolumes) + + // filter out already-mounted volumes + for k := range existingVolumes { + delete(newVolumes, k) + } + + numNewVolumes := len(newVolumes) + maxAttachLimit := pl.maxVolumeFunc(node) + volumeLimits := volumeLimits(nodeInfo) + if maxAttachLimitFromAllocatable, ok := volumeLimits[pl.volumeLimitKey]; ok { + maxAttachLimit = int(maxAttachLimitFromAllocatable) + } + + if numExistingVolumes+numNewVolumes > maxAttachLimit { + return framework.NewStatus(framework.Unschedulable, ErrReasonMaxVolumeCountExceeded) + } + return nil +} + +func (pl *nonCSILimits) filterVolumes(pod *v1.Pod, newPod bool, filteredVolumes sets.String) error { + volumes := pod.Spec.Volumes + for i := range volumes { + vol := &volumes[i] + if id, ok := pl.filter.FilterVolume(vol); ok { + filteredVolumes.Insert(id) + continue + } + + pvcName := "" + isEphemeral := false + switch { + case vol.PersistentVolumeClaim != nil: + pvcName = vol.PersistentVolumeClaim.ClaimName + case vol.Ephemeral != nil: + // Generic ephemeral inline volumes also use a PVC, + // just with a computed name and certain ownership. + // That is checked below once the pvc object is + // retrieved. + pvcName = ephemeral.VolumeClaimName(pod, vol) + isEphemeral = true + default: + continue + } + if pvcName == "" { + return fmt.Errorf("PersistentVolumeClaim had no name") + } + + // Until we know real ID of the volume use namespace/pvcName as substitute + // with a random prefix (calculated and stored inside 'c' during initialization) + // to avoid conflicts with existing volume IDs. + pvID := fmt.Sprintf("%s-%s/%s", pl.randomVolumeIDPrefix, pod.Namespace, pvcName) + + pvc, err := pl.pvcLister.PersistentVolumeClaims(pod.Namespace).Get(pvcName) + if err != nil { + if newPod { + // The PVC is required to proceed with + // scheduling of a new pod because it cannot + // run without it. Bail out immediately. + return fmt.Errorf("looking up PVC %s/%s: %v", pod.Namespace, pvcName, err) + } + // If the PVC is invalid, we don't count the volume because + // there's no guarantee that it belongs to the running predicate. + klog.V(4).InfoS("Unable to look up PVC info, assuming PVC doesn't match predicate when counting limits", "pod", klog.KObj(pod), "PVC", klog.KRef(pod.Namespace, pvcName), "err", err) + continue + } + + // The PVC for an ephemeral volume must be owned by the pod. + if isEphemeral { + if err := ephemeral.VolumeIsForPod(pod, pvc); err != nil { + return err + } + } + + pvName := pvc.Spec.VolumeName + if pvName == "" { + // PVC is not bound. It was either deleted and created again or + // it was forcefully unbound by admin. The pod can still use the + // original PV where it was bound to, so we count the volume if + // it belongs to the running predicate. + if pl.matchProvisioner(pvc) { + klog.V(4).InfoS("PVC is not bound, assuming PVC matches predicate when counting limits", "pod", klog.KObj(pod), "PVC", klog.KRef(pod.Namespace, pvcName)) + filteredVolumes.Insert(pvID) + } + continue + } + + pv, err := pl.pvLister.Get(pvName) + if err != nil { + // If the PV is invalid and PVC belongs to the running predicate, + // log the error and count the PV towards the PV limit. + if pl.matchProvisioner(pvc) { + klog.V(4).InfoS("Unable to look up PV, assuming PV matches predicate when counting limits", "pod", klog.KObj(pod), "PVC", klog.KRef(pod.Namespace, pvcName), "PV", klog.KRef("", pvName), "err", err) + filteredVolumes.Insert(pvID) + } + continue + } + + if id, ok := pl.filter.FilterPersistentVolume(pv); ok { + filteredVolumes.Insert(id) + } + } + + return nil +} + +// matchProvisioner helps identify if the given PVC belongs to the running predicate. +func (pl *nonCSILimits) matchProvisioner(pvc *v1.PersistentVolumeClaim) bool { + if pvc.Spec.StorageClassName == nil { + return false + } + + storageClass, err := pl.scLister.Get(*pvc.Spec.StorageClassName) + if err != nil || storageClass == nil { + return false + } + + return pl.filter.MatchProvisioner(storageClass) +} + +// getMaxVolLimitFromEnv checks the max PD volumes environment variable, otherwise returning a default value. +func getMaxVolLimitFromEnv() int { + if rawMaxVols := os.Getenv(KubeMaxPDVols); rawMaxVols != "" { + if parsedMaxVols, err := strconv.Atoi(rawMaxVols); err != nil { + klog.ErrorS(err, "Unable to parse maximum PD volumes value, using default") + } else if parsedMaxVols <= 0 { + klog.ErrorS(errors.New("maximum PD volumes is negative"), "Unable to parse maximum PD volumes value, using default") + } else { + return parsedMaxVols + } + } + + return -1 +} + +// VolumeFilter contains information on how to filter PD Volumes when checking PD Volume caps. +type VolumeFilter struct { + // Filter normal volumes + FilterVolume func(vol *v1.Volume) (id string, relevant bool) + FilterPersistentVolume func(pv *v1.PersistentVolume) (id string, relevant bool) + // MatchProvisioner evaluates if the StorageClass provisioner matches the running predicate + MatchProvisioner func(sc *storage.StorageClass) (relevant bool) + // IsMigrated returns a boolean specifying whether the plugin is migrated to a CSI driver + IsMigrated func(csiNode *storage.CSINode) bool +} + +// ebsVolumeFilter is a VolumeFilter for filtering AWS ElasticBlockStore Volumes. +var ebsVolumeFilter = VolumeFilter{ + FilterVolume: func(vol *v1.Volume) (string, bool) { + if vol.AWSElasticBlockStore != nil { + return vol.AWSElasticBlockStore.VolumeID, true + } + return "", false + }, + + FilterPersistentVolume: func(pv *v1.PersistentVolume) (string, bool) { + if pv.Spec.AWSElasticBlockStore != nil { + return pv.Spec.AWSElasticBlockStore.VolumeID, true + } + return "", false + }, + + MatchProvisioner: func(sc *storage.StorageClass) bool { + return sc.Provisioner == csilibplugins.AWSEBSInTreePluginName + }, + + IsMigrated: func(csiNode *storage.CSINode) bool { + return isCSIMigrationOn(csiNode, csilibplugins.AWSEBSInTreePluginName) + }, +} + +// gcePDVolumeFilter is a VolumeFilter for filtering gce PersistentDisk Volumes. +var gcePDVolumeFilter = VolumeFilter{ + FilterVolume: func(vol *v1.Volume) (string, bool) { + if vol.GCEPersistentDisk != nil { + return vol.GCEPersistentDisk.PDName, true + } + return "", false + }, + + FilterPersistentVolume: func(pv *v1.PersistentVolume) (string, bool) { + if pv.Spec.GCEPersistentDisk != nil { + return pv.Spec.GCEPersistentDisk.PDName, true + } + return "", false + }, + + MatchProvisioner: func(sc *storage.StorageClass) bool { + return sc.Provisioner == csilibplugins.GCEPDInTreePluginName + }, + + IsMigrated: func(csiNode *storage.CSINode) bool { + return isCSIMigrationOn(csiNode, csilibplugins.GCEPDInTreePluginName) + }, +} + +// azureDiskVolumeFilter is a VolumeFilter for filtering azure Disk Volumes. +var azureDiskVolumeFilter = VolumeFilter{ + FilterVolume: func(vol *v1.Volume) (string, bool) { + if vol.AzureDisk != nil { + return vol.AzureDisk.DiskName, true + } + return "", false + }, + + FilterPersistentVolume: func(pv *v1.PersistentVolume) (string, bool) { + if pv.Spec.AzureDisk != nil { + return pv.Spec.AzureDisk.DiskName, true + } + return "", false + }, + + MatchProvisioner: func(sc *storage.StorageClass) bool { + return sc.Provisioner == csilibplugins.AzureDiskInTreePluginName + }, + + IsMigrated: func(csiNode *storage.CSINode) bool { + return isCSIMigrationOn(csiNode, csilibplugins.AzureDiskInTreePluginName) + }, +} + +// cinderVolumeFilter is a VolumeFilter for filtering cinder Volumes. +// It will be deprecated once Openstack cloudprovider has been removed from in-tree. +var cinderVolumeFilter = VolumeFilter{ + FilterVolume: func(vol *v1.Volume) (string, bool) { + if vol.Cinder != nil { + return vol.Cinder.VolumeID, true + } + return "", false + }, + + FilterPersistentVolume: func(pv *v1.PersistentVolume) (string, bool) { + if pv.Spec.Cinder != nil { + return pv.Spec.Cinder.VolumeID, true + } + return "", false + }, + + MatchProvisioner: func(sc *storage.StorageClass) bool { + return sc.Provisioner == csilibplugins.CinderInTreePluginName + }, + + IsMigrated: func(csiNode *storage.CSINode) bool { + return isCSIMigrationOn(csiNode, csilibplugins.CinderInTreePluginName) + }, +} + +func getMaxVolumeFunc(filterName string) func(node *v1.Node) int { + return func(node *v1.Node) int { + maxVolumesFromEnv := getMaxVolLimitFromEnv() + if maxVolumesFromEnv > 0 { + return maxVolumesFromEnv + } + + var nodeInstanceType string + for k, v := range node.ObjectMeta.Labels { + if k == v1.LabelInstanceType || k == v1.LabelInstanceTypeStable { + nodeInstanceType = v + break + } + } + switch filterName { + case ebsVolumeFilterType: + return getMaxEBSVolume(nodeInstanceType) + case gcePDVolumeFilterType: + return defaultMaxGCEPDVolumes + case azureDiskVolumeFilterType: + return defaultMaxAzureDiskVolumes + case cinderVolumeFilterType: + return volumeutil.DefaultMaxCinderVolumes + default: + return -1 + } + } +} + +func getMaxEBSVolume(nodeInstanceType string) int { + if ok, _ := regexp.MatchString(volumeutil.EBSNitroLimitRegex, nodeInstanceType); ok { + return volumeutil.DefaultMaxEBSNitroVolumeLimit + } + return volumeutil.DefaultMaxEBSVolumes +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodevolumelimits/utils.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodevolumelimits/utils.go new file mode 100644 index 000000000..79d625e17 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodevolumelimits/utils.go @@ -0,0 +1,96 @@ +/* +Copyright 2019 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 nodevolumelimits + +import ( + "strings" + + v1 "k8s.io/api/core/v1" + storagev1 "k8s.io/api/storage/v1" + "k8s.io/apimachinery/pkg/util/sets" + utilfeature "k8s.io/apiserver/pkg/util/feature" + csilibplugins "k8s.io/csi-translation-lib/plugins" + v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" + "k8s.io/kubernetes/pkg/features" + "k8s.io/kubernetes/pkg/scheduler/framework" +) + +// isCSIMigrationOn returns a boolean value indicating whether +// the CSI migration has been enabled for a particular storage plugin. +func isCSIMigrationOn(csiNode *storagev1.CSINode, pluginName string) bool { + if csiNode == nil || len(pluginName) == 0 { + return false + } + + // In-tree storage to CSI driver migration feature should be enabled, + // along with the plugin-specific one + switch pluginName { + case csilibplugins.AWSEBSInTreePluginName: + if !utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationAWS) { + return false + } + case csilibplugins.PortworxVolumePluginName: + if !utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationPortworx) { + return false + } + case csilibplugins.GCEPDInTreePluginName: + if !utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationGCE) { + return false + } + case csilibplugins.AzureDiskInTreePluginName: + if !utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationAzureDisk) { + return false + } + case csilibplugins.CinderInTreePluginName: + return true + case csilibplugins.RBDVolumePluginName: + if !utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationRBD) { + return false + } + default: + return false + } + + // The plugin name should be listed in the CSINode object annotation. + // This indicates that the plugin has been migrated to a CSI driver in the node. + csiNodeAnn := csiNode.GetAnnotations() + if csiNodeAnn == nil { + return false + } + + var mpaSet sets.String + mpa := csiNodeAnn[v1.MigratedPluginsAnnotationKey] + if len(mpa) == 0 { + mpaSet = sets.NewString() + } else { + tok := strings.Split(mpa, ",") + mpaSet = sets.NewString(tok...) + } + + return mpaSet.Has(pluginName) +} + +// volumeLimits returns volume limits associated with the node. +func volumeLimits(n *framework.NodeInfo) map[v1.ResourceName]int64 { + volumeLimits := map[v1.ResourceName]int64{} + for k, v := range n.Allocatable.ScalarResources { + if v1helper.IsAttachableVolumeResourceName(k) { + volumeLimits[k] = v + } + } + return volumeLimits +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread/common.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread/common.go new file mode 100644 index 000000000..55f8d1e42 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread/common.go @@ -0,0 +1,159 @@ +/* +Copyright 2019 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 podtopologyspread + +import ( + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + v1helper "k8s.io/component-helpers/scheduling/corev1" + "k8s.io/component-helpers/scheduling/corev1/nodeaffinity" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper" +) + +type topologyPair struct { + key string + value string +} + +// topologySpreadConstraint is an internal version for v1.TopologySpreadConstraint +// and where the selector is parsed. +// Fields are exported for comparison during testing. +type topologySpreadConstraint struct { + MaxSkew int32 + TopologyKey string + Selector labels.Selector + MinDomains int32 + NodeAffinityPolicy v1.NodeInclusionPolicy + NodeTaintsPolicy v1.NodeInclusionPolicy +} + +func (tsc *topologySpreadConstraint) matchNodeInclusionPolicies(pod *v1.Pod, node *v1.Node, require nodeaffinity.RequiredNodeAffinity) bool { + if tsc.NodeAffinityPolicy == v1.NodeInclusionPolicyHonor { + // We ignore parsing errors here for backwards compatibility. + if match, _ := require.Match(node); !match { + return false + } + } + + if tsc.NodeTaintsPolicy == v1.NodeInclusionPolicyHonor { + if _, untolerated := v1helper.FindMatchingUntoleratedTaint(node.Spec.Taints, pod.Spec.Tolerations, helper.DoNotScheduleTaintsFilterFunc()); untolerated { + return false + } + } + return true +} + +// buildDefaultConstraints builds the constraints for a pod using +// .DefaultConstraints and the selectors from the services, replication +// controllers, replica sets and stateful sets that match the pod. +func (pl *PodTopologySpread) buildDefaultConstraints(p *v1.Pod, action v1.UnsatisfiableConstraintAction) ([]topologySpreadConstraint, error) { + constraints, err := pl.filterTopologySpreadConstraints(pl.defaultConstraints, p.Labels, action) + if err != nil || len(constraints) == 0 { + return nil, err + } + selector := helper.DefaultSelector(p, pl.services, pl.replicationCtrls, pl.replicaSets, pl.statefulSets) + if selector.Empty() { + return nil, nil + } + for i := range constraints { + constraints[i].Selector = selector + } + return constraints, nil +} + +// nodeLabelsMatchSpreadConstraints checks if ALL topology keys in spread Constraints are present in node labels. +func nodeLabelsMatchSpreadConstraints(nodeLabels map[string]string, constraints []topologySpreadConstraint) bool { + for _, c := range constraints { + if _, ok := nodeLabels[c.TopologyKey]; !ok { + return false + } + } + return true +} + +func (pl *PodTopologySpread) filterTopologySpreadConstraints(constraints []v1.TopologySpreadConstraint, podLabels map[string]string, action v1.UnsatisfiableConstraintAction) ([]topologySpreadConstraint, error) { + var result []topologySpreadConstraint + for _, c := range constraints { + if c.WhenUnsatisfiable == action { + selector, err := metav1.LabelSelectorAsSelector(c.LabelSelector) + if err != nil { + return nil, err + } + + if pl.enableMatchLabelKeysInPodTopologySpread && len(c.MatchLabelKeys) > 0 { + matchLabels := make(labels.Set) + for _, labelKey := range c.MatchLabelKeys { + if value, ok := podLabels[labelKey]; ok { + matchLabels[labelKey] = value + } + } + if len(matchLabels) > 0 { + selector = mergeLabelSetWithSelector(matchLabels, selector) + } + } + + tsc := topologySpreadConstraint{ + MaxSkew: c.MaxSkew, + TopologyKey: c.TopologyKey, + Selector: selector, + MinDomains: 1, // If MinDomains is nil, we treat MinDomains as 1. + NodeAffinityPolicy: v1.NodeInclusionPolicyHonor, // If NodeAffinityPolicy is nil, we treat NodeAffinityPolicy as "Honor". + NodeTaintsPolicy: v1.NodeInclusionPolicyIgnore, // If NodeTaintsPolicy is nil, we treat NodeTaintsPolicy as "Ignore". + } + if pl.enableMinDomainsInPodTopologySpread && c.MinDomains != nil { + tsc.MinDomains = *c.MinDomains + } + if pl.enableNodeInclusionPolicyInPodTopologySpread { + if c.NodeAffinityPolicy != nil { + tsc.NodeAffinityPolicy = *c.NodeAffinityPolicy + } + if c.NodeTaintsPolicy != nil { + tsc.NodeTaintsPolicy = *c.NodeTaintsPolicy + } + } + result = append(result, tsc) + } + } + return result, nil +} + +func mergeLabelSetWithSelector(matchLabels labels.Set, s labels.Selector) labels.Selector { + mergedSelector := labels.SelectorFromSet(matchLabels) + if requirements, ok := s.Requirements(); ok { + for _, r := range requirements { + mergedSelector = mergedSelector.Add(r) + } + } + + return mergedSelector +} + +func countPodsMatchSelector(podInfos []*framework.PodInfo, selector labels.Selector, ns string) int { + count := 0 + for _, p := range podInfos { + // Bypass terminating Pod (see #87621). + if p.Pod.DeletionTimestamp != nil || p.Pod.Namespace != ns { + continue + } + if selector.Matches(labels.Set(p.Pod.Labels)) { + count++ + } + } + return count +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread/filtering.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread/filtering.go new file mode 100644 index 000000000..bd0d5a92f --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread/filtering.go @@ -0,0 +1,394 @@ +/* +Copyright 2019 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 podtopologyspread + +import ( + "context" + "fmt" + "math" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/component-helpers/scheduling/corev1/nodeaffinity" + "k8s.io/klog/v2" + "k8s.io/kubernetes/pkg/scheduler/framework" +) + +const preFilterStateKey = "PreFilter" + Name + +// preFilterState computed at PreFilter and used at Filter. +// It combines TpKeyToCriticalPaths and TpPairToMatchNum to represent: +// (1) critical paths where the least pods are matched on each spread constraint. +// (2) number of pods matched on each spread constraint. +// A nil preFilterState denotes it's not set at all (in PreFilter phase); +// An empty preFilterState object denotes it's a legit state and is set in PreFilter phase. +// Fields are exported for comparison during testing. +type preFilterState struct { + Constraints []topologySpreadConstraint + // We record 2 critical paths instead of all critical paths here. + // criticalPaths[0].MatchNum always holds the minimum matching number. + // criticalPaths[1].MatchNum is always greater or equal to criticalPaths[0].MatchNum, but + // it's not guaranteed to be the 2nd minimum match number. + TpKeyToCriticalPaths map[string]*criticalPaths + // TpKeyToDomainsNum is keyed with topologyKey, and valued with the number of domains. + TpKeyToDomainsNum map[string]int + // TpPairToMatchNum is keyed with topologyPair, and valued with the number of matching pods. + TpPairToMatchNum map[topologyPair]int +} + +// minMatchNum returns the global minimum for the calculation of skew while taking MinDomains into account. +func (s *preFilterState) minMatchNum(tpKey string, minDomains int32, enableMinDomainsInPodTopologySpread bool) (int, error) { + paths, ok := s.TpKeyToCriticalPaths[tpKey] + if !ok { + return 0, fmt.Errorf("failed to retrieve path by topology key") + } + + minMatchNum := paths[0].MatchNum + if !enableMinDomainsInPodTopologySpread { + return minMatchNum, nil + } + + domainsNum, ok := s.TpKeyToDomainsNum[tpKey] + if !ok { + return 0, fmt.Errorf("failed to retrieve the number of domains by topology key") + } + + if domainsNum < int(minDomains) { + // When the number of eligible domains with matching topology keys is less than `minDomains`, + // it treats "global minimum" as 0. + minMatchNum = 0 + } + + return minMatchNum, nil +} + +// Clone makes a copy of the given state. +func (s *preFilterState) Clone() framework.StateData { + if s == nil { + return nil + } + copy := preFilterState{ + // Constraints are shared because they don't change. + Constraints: s.Constraints, + TpKeyToCriticalPaths: make(map[string]*criticalPaths, len(s.TpKeyToCriticalPaths)), + // The number of domains does not change as a result of AddPod/RemovePod methods on PreFilter Extensions + TpKeyToDomainsNum: s.TpKeyToDomainsNum, + TpPairToMatchNum: make(map[topologyPair]int, len(s.TpPairToMatchNum)), + } + for tpKey, paths := range s.TpKeyToCriticalPaths { + copy.TpKeyToCriticalPaths[tpKey] = &criticalPaths{paths[0], paths[1]} + } + for tpPair, matchNum := range s.TpPairToMatchNum { + copyPair := topologyPair{key: tpPair.key, value: tpPair.value} + copy.TpPairToMatchNum[copyPair] = matchNum + } + return © +} + +// CAVEAT: the reason that `[2]criticalPath` can work is based on the implementation of current +// preemption algorithm, in particular the following 2 facts: +// Fact 1: we only preempt pods on the same node, instead of pods on multiple nodes. +// Fact 2: each node is evaluated on a separate copy of the preFilterState during its preemption cycle. +// If we plan to turn to a more complex algorithm like "arbitrary pods on multiple nodes", this +// structure needs to be revisited. +// Fields are exported for comparison during testing. +type criticalPaths [2]struct { + // TopologyValue denotes the topology value mapping to topology key. + TopologyValue string + // MatchNum denotes the number of matching pods. + MatchNum int +} + +func newCriticalPaths() *criticalPaths { + return &criticalPaths{{MatchNum: math.MaxInt32}, {MatchNum: math.MaxInt32}} +} + +func (p *criticalPaths) update(tpVal string, num int) { + // first verify if `tpVal` exists or not + i := -1 + if tpVal == p[0].TopologyValue { + i = 0 + } else if tpVal == p[1].TopologyValue { + i = 1 + } + + if i >= 0 { + // `tpVal` exists + p[i].MatchNum = num + if p[0].MatchNum > p[1].MatchNum { + // swap paths[0] and paths[1] + p[0], p[1] = p[1], p[0] + } + } else { + // `tpVal` doesn't exist + if num < p[0].MatchNum { + // update paths[1] with paths[0] + p[1] = p[0] + // update paths[0] + p[0].TopologyValue, p[0].MatchNum = tpVal, num + } else if num < p[1].MatchNum { + // update paths[1] + p[1].TopologyValue, p[1].MatchNum = tpVal, num + } + } +} + +// PreFilter invoked at the prefilter extension point. +func (pl *PodTopologySpread) PreFilter(ctx context.Context, cycleState *framework.CycleState, pod *v1.Pod) (*framework.PreFilterResult, *framework.Status) { + s, err := pl.calPreFilterState(ctx, pod) + if err != nil { + return nil, framework.AsStatus(err) + } + cycleState.Write(preFilterStateKey, s) + return nil, nil +} + +// PreFilterExtensions returns prefilter extensions, pod add and remove. +func (pl *PodTopologySpread) PreFilterExtensions() framework.PreFilterExtensions { + return pl +} + +// AddPod from pre-computed data in cycleState. +func (pl *PodTopologySpread) AddPod(ctx context.Context, cycleState *framework.CycleState, podToSchedule *v1.Pod, podInfoToAdd *framework.PodInfo, nodeInfo *framework.NodeInfo) *framework.Status { + s, err := getPreFilterState(cycleState) + if err != nil { + return framework.AsStatus(err) + } + + pl.updateWithPod(s, podInfoToAdd.Pod, podToSchedule, nodeInfo.Node(), 1) + return nil +} + +// RemovePod from pre-computed data in cycleState. +func (pl *PodTopologySpread) RemovePod(ctx context.Context, cycleState *framework.CycleState, podToSchedule *v1.Pod, podInfoToRemove *framework.PodInfo, nodeInfo *framework.NodeInfo) *framework.Status { + s, err := getPreFilterState(cycleState) + if err != nil { + return framework.AsStatus(err) + } + + pl.updateWithPod(s, podInfoToRemove.Pod, podToSchedule, nodeInfo.Node(), -1) + return nil +} + +func (pl *PodTopologySpread) updateWithPod(s *preFilterState, updatedPod, preemptorPod *v1.Pod, node *v1.Node, delta int) { + if s == nil || updatedPod.Namespace != preemptorPod.Namespace || node == nil { + return + } + if !nodeLabelsMatchSpreadConstraints(node.Labels, s.Constraints) { + return + } + + requiredSchedulingTerm := nodeaffinity.GetRequiredNodeAffinity(preemptorPod) + if !pl.enableNodeInclusionPolicyInPodTopologySpread { + // spreading is applied to nodes that pass those filters. + // Ignore parsing errors for backwards compatibility. + if match, _ := requiredSchedulingTerm.Match(node); !match { + return + } + } + + podLabelSet := labels.Set(updatedPod.Labels) + for _, constraint := range s.Constraints { + if !constraint.Selector.Matches(podLabelSet) { + continue + } + + if pl.enableNodeInclusionPolicyInPodTopologySpread && + !constraint.matchNodeInclusionPolicies(preemptorPod, node, requiredSchedulingTerm) { + continue + } + + k, v := constraint.TopologyKey, node.Labels[constraint.TopologyKey] + pair := topologyPair{key: k, value: v} + s.TpPairToMatchNum[pair] += delta + s.TpKeyToCriticalPaths[k].update(v, s.TpPairToMatchNum[pair]) + } +} + +// getPreFilterState fetches a pre-computed preFilterState. +func getPreFilterState(cycleState *framework.CycleState) (*preFilterState, error) { + c, err := cycleState.Read(preFilterStateKey) + if err != nil { + // preFilterState doesn't exist, likely PreFilter wasn't invoked. + return nil, fmt.Errorf("reading %q from cycleState: %w", preFilterStateKey, err) + } + + s, ok := c.(*preFilterState) + if !ok { + return nil, fmt.Errorf("%+v convert to podtopologyspread.preFilterState error", c) + } + return s, nil +} + +// calPreFilterState computes preFilterState describing how pods are spread on topologies. +func (pl *PodTopologySpread) calPreFilterState(ctx context.Context, pod *v1.Pod) (*preFilterState, error) { + allNodes, err := pl.sharedLister.NodeInfos().List() + if err != nil { + return nil, fmt.Errorf("listing NodeInfos: %w", err) + } + var constraints []topologySpreadConstraint + if len(pod.Spec.TopologySpreadConstraints) > 0 { + // We have feature gating in APIServer to strip the spec + // so don't need to re-check feature gate, just check length of Constraints. + constraints, err = pl.filterTopologySpreadConstraints( + pod.Spec.TopologySpreadConstraints, + pod.Labels, + v1.DoNotSchedule, + ) + if err != nil { + return nil, fmt.Errorf("obtaining pod's hard topology spread constraints: %w", err) + } + } else { + constraints, err = pl.buildDefaultConstraints(pod, v1.DoNotSchedule) + if err != nil { + return nil, fmt.Errorf("setting default hard topology spread constraints: %w", err) + } + } + if len(constraints) == 0 { + return &preFilterState{}, nil + } + + s := preFilterState{ + Constraints: constraints, + TpKeyToCriticalPaths: make(map[string]*criticalPaths, len(constraints)), + TpPairToMatchNum: make(map[topologyPair]int, sizeHeuristic(len(allNodes), constraints)), + } + + tpCountsByNode := make([]map[topologyPair]int, len(allNodes)) + requiredNodeAffinity := nodeaffinity.GetRequiredNodeAffinity(pod) + processNode := func(i int) { + nodeInfo := allNodes[i] + node := nodeInfo.Node() + if node == nil { + klog.ErrorS(nil, "Node not found") + return + } + + if !pl.enableNodeInclusionPolicyInPodTopologySpread { + // spreading is applied to nodes that pass those filters. + // Ignore parsing errors for backwards compatibility. + if match, _ := requiredNodeAffinity.Match(node); !match { + return + } + } + + // Ensure current node's labels contains all topologyKeys in 'Constraints'. + if !nodeLabelsMatchSpreadConstraints(node.Labels, constraints) { + return + } + + tpCounts := make(map[topologyPair]int, len(constraints)) + for _, c := range constraints { + if pl.enableNodeInclusionPolicyInPodTopologySpread && + !c.matchNodeInclusionPolicies(pod, node, requiredNodeAffinity) { + continue + } + + pair := topologyPair{key: c.TopologyKey, value: node.Labels[c.TopologyKey]} + count := countPodsMatchSelector(nodeInfo.Pods, c.Selector, pod.Namespace) + tpCounts[pair] = count + } + tpCountsByNode[i] = tpCounts + } + pl.parallelizer.Until(ctx, len(allNodes), processNode, pl.Name()) + + for _, tpCounts := range tpCountsByNode { + for tp, count := range tpCounts { + s.TpPairToMatchNum[tp] += count + } + } + if pl.enableMinDomainsInPodTopologySpread { + s.TpKeyToDomainsNum = make(map[string]int, len(constraints)) + for tp := range s.TpPairToMatchNum { + s.TpKeyToDomainsNum[tp.key]++ + } + } + + // calculate min match for each topology pair + for i := 0; i < len(constraints); i++ { + key := constraints[i].TopologyKey + s.TpKeyToCriticalPaths[key] = newCriticalPaths() + } + for pair, num := range s.TpPairToMatchNum { + s.TpKeyToCriticalPaths[pair.key].update(pair.value, num) + } + + return &s, nil +} + +// Filter invoked at the filter extension point. +func (pl *PodTopologySpread) Filter(ctx context.Context, cycleState *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status { + node := nodeInfo.Node() + if node == nil { + return framework.AsStatus(fmt.Errorf("node not found")) + } + + s, err := getPreFilterState(cycleState) + if err != nil { + return framework.AsStatus(err) + } + + // However, "empty" preFilterState is legit which tolerates every toSchedule Pod. + if len(s.Constraints) == 0 { + return nil + } + + podLabelSet := labels.Set(pod.Labels) + for _, c := range s.Constraints { + tpKey := c.TopologyKey + tpVal, ok := node.Labels[c.TopologyKey] + if !ok { + klog.V(5).InfoS("Node doesn't have required label", "node", klog.KObj(node), "label", tpKey) + return framework.NewStatus(framework.UnschedulableAndUnresolvable, ErrReasonNodeLabelNotMatch) + } + + // judging criteria: + // 'existing matching num' + 'if self-match (1 or 0)' - 'global minimum' <= 'maxSkew' + minMatchNum, err := s.minMatchNum(tpKey, c.MinDomains, pl.enableMinDomainsInPodTopologySpread) + if err != nil { + klog.ErrorS(err, "Internal error occurred while retrieving value precalculated in PreFilter", "topologyKey", tpKey, "paths", s.TpKeyToCriticalPaths) + continue + } + + selfMatchNum := 0 + if c.Selector.Matches(podLabelSet) { + selfMatchNum = 1 + } + + pair := topologyPair{key: tpKey, value: tpVal} + matchNum := 0 + if tpCount, ok := s.TpPairToMatchNum[pair]; ok { + matchNum = tpCount + } + skew := matchNum + selfMatchNum - minMatchNum + if skew > int(c.MaxSkew) { + klog.V(5).InfoS("Node failed spreadConstraint: matchNum + selfMatchNum - minMatchNum > maxSkew", "node", klog.KObj(node), "topologyKey", tpKey, "matchNum", matchNum, "selfMatchNum", selfMatchNum, "minMatchNum", minMatchNum, "maxSkew", c.MaxSkew) + return framework.NewStatus(framework.Unschedulable, ErrReasonConstraintsNotMatch) + } + } + + return nil +} + +func sizeHeuristic(nodes int, constraints []topologySpreadConstraint) int { + for _, c := range constraints { + if c.TopologyKey == v1.LabelHostname { + return nodes + } + } + return 0 +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread/plugin.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread/plugin.go new file mode 100644 index 000000000..ed2333e76 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread/plugin.go @@ -0,0 +1,148 @@ +/* +Copyright 2019 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 podtopologyspread + +import ( + "fmt" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/informers" + appslisters "k8s.io/client-go/listers/apps/v1" + corelisters "k8s.io/client-go/listers/core/v1" + "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/kubernetes/pkg/scheduler/apis/config/validation" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/parallelize" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" +) + +const ( + // ErrReasonConstraintsNotMatch is used for PodTopologySpread filter error. + ErrReasonConstraintsNotMatch = "node(s) didn't match pod topology spread constraints" + // ErrReasonNodeLabelNotMatch is used when the node doesn't hold the required label. + ErrReasonNodeLabelNotMatch = ErrReasonConstraintsNotMatch + " (missing required label)" +) + +var systemDefaultConstraints = []v1.TopologySpreadConstraint{ + { + TopologyKey: v1.LabelHostname, + WhenUnsatisfiable: v1.ScheduleAnyway, + MaxSkew: 3, + }, + { + TopologyKey: v1.LabelTopologyZone, + WhenUnsatisfiable: v1.ScheduleAnyway, + MaxSkew: 5, + }, +} + +// PodTopologySpread is a plugin that ensures pod's topologySpreadConstraints is satisfied. +type PodTopologySpread struct { + systemDefaulted bool + parallelizer parallelize.Parallelizer + defaultConstraints []v1.TopologySpreadConstraint + sharedLister framework.SharedLister + services corelisters.ServiceLister + replicationCtrls corelisters.ReplicationControllerLister + replicaSets appslisters.ReplicaSetLister + statefulSets appslisters.StatefulSetLister + enableMinDomainsInPodTopologySpread bool + enableNodeInclusionPolicyInPodTopologySpread bool + enableMatchLabelKeysInPodTopologySpread bool +} + +var _ framework.PreFilterPlugin = &PodTopologySpread{} +var _ framework.FilterPlugin = &PodTopologySpread{} +var _ framework.PreScorePlugin = &PodTopologySpread{} +var _ framework.ScorePlugin = &PodTopologySpread{} +var _ framework.EnqueueExtensions = &PodTopologySpread{} + +// Name is the name of the plugin used in the plugin registry and configurations. +const Name = names.PodTopologySpread + +// Name returns name of the plugin. It is used in logs, etc. +func (pl *PodTopologySpread) Name() string { + return Name +} + +// New initializes a new plugin and returns it. +func New(plArgs runtime.Object, h framework.Handle, fts feature.Features) (framework.Plugin, error) { + if h.SnapshotSharedLister() == nil { + return nil, fmt.Errorf("SnapshotSharedlister is nil") + } + args, err := getArgs(plArgs) + if err != nil { + return nil, err + } + if err := validation.ValidatePodTopologySpreadArgs(nil, &args); err != nil { + return nil, err + } + pl := &PodTopologySpread{ + parallelizer: h.Parallelizer(), + sharedLister: h.SnapshotSharedLister(), + defaultConstraints: args.DefaultConstraints, + enableMinDomainsInPodTopologySpread: fts.EnableMinDomainsInPodTopologySpread, + enableNodeInclusionPolicyInPodTopologySpread: fts.EnableNodeInclusionPolicyInPodTopologySpread, + enableMatchLabelKeysInPodTopologySpread: fts.EnableMatchLabelKeysInPodTopologySpread, + } + if args.DefaultingType == config.SystemDefaulting { + pl.defaultConstraints = systemDefaultConstraints + pl.systemDefaulted = true + } + if len(pl.defaultConstraints) != 0 { + if h.SharedInformerFactory() == nil { + return nil, fmt.Errorf("SharedInformerFactory is nil") + } + pl.setListers(h.SharedInformerFactory()) + } + return pl, nil +} + +func getArgs(obj runtime.Object) (config.PodTopologySpreadArgs, error) { + ptr, ok := obj.(*config.PodTopologySpreadArgs) + if !ok { + return config.PodTopologySpreadArgs{}, fmt.Errorf("want args to be of type PodTopologySpreadArgs, got %T", obj) + } + return *ptr, nil +} + +func (pl *PodTopologySpread) setListers(factory informers.SharedInformerFactory) { + pl.services = factory.Core().V1().Services().Lister() + pl.replicationCtrls = factory.Core().V1().ReplicationControllers().Lister() + pl.replicaSets = factory.Apps().V1().ReplicaSets().Lister() + pl.statefulSets = factory.Apps().V1().StatefulSets().Lister() +} + +// EventsToRegister returns the possible events that may make a Pod +// failed by this plugin schedulable. +func (pl *PodTopologySpread) EventsToRegister() []framework.ClusterEvent { + return []framework.ClusterEvent{ + // All ActionType includes the following events: + // - Add. An unschedulable Pod may fail due to violating topology spread constraints, + // adding an assigned Pod may make it schedulable. + // - Update. Updating on an existing Pod's labels (e.g., removal) may make + // an unschedulable Pod schedulable. + // - Delete. An unschedulable Pod may fail due to violating an existing Pod's topology spread constraints, + // deleting an existing Pod may make it schedulable. + {Resource: framework.Pod, ActionType: framework.All}, + // Node add|delete|updateLabel maybe lead an topology key changed, + // and make these pod in scheduling schedulable or unschedulable. + {Resource: framework.Node, ActionType: framework.Add | framework.Delete | framework.UpdateNodeLabel}, + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread/scoring.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread/scoring.go new file mode 100644 index 000000000..7a3c0589b --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread/scoring.go @@ -0,0 +1,309 @@ +/* +Copyright 2019 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 podtopologyspread + +import ( + "context" + "fmt" + "math" + "sync/atomic" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/component-helpers/scheduling/corev1/nodeaffinity" + "k8s.io/kubernetes/pkg/scheduler/framework" +) + +const preScoreStateKey = "PreScore" + Name +const invalidScore = -1 + +// preScoreState computed at PreScore and used at Score. +// Fields are exported for comparison during testing. +type preScoreState struct { + Constraints []topologySpreadConstraint + // IgnoredNodes is a set of node names which miss some Constraints[*].topologyKey. + IgnoredNodes sets.String + // TopologyPairToPodCounts is keyed with topologyPair, and valued with the number of matching pods. + TopologyPairToPodCounts map[topologyPair]*int64 + // TopologyNormalizingWeight is the weight we give to the counts per topology. + // This allows the pod counts of smaller topologies to not be watered down by + // bigger ones. + TopologyNormalizingWeight []float64 +} + +// Clone implements the mandatory Clone interface. We don't really copy the data since +// there is no need for that. +func (s *preScoreState) Clone() framework.StateData { + return s +} + +// initPreScoreState iterates "filteredNodes" to filter out the nodes which +// don't have required topologyKey(s), and initialize: +// 1) s.TopologyPairToPodCounts: keyed with both eligible topology pair and node names. +// 2) s.IgnoredNodes: the set of nodes that shouldn't be scored. +// 3) s.TopologyNormalizingWeight: The weight to be given to each constraint based on the number of values in a topology. +func (pl *PodTopologySpread) initPreScoreState(s *preScoreState, pod *v1.Pod, filteredNodes []*v1.Node, requireAllTopologies bool) error { + var err error + if len(pod.Spec.TopologySpreadConstraints) > 0 { + s.Constraints, err = pl.filterTopologySpreadConstraints( + pod.Spec.TopologySpreadConstraints, + pod.Labels, + v1.ScheduleAnyway, + ) + if err != nil { + return fmt.Errorf("obtaining pod's soft topology spread constraints: %w", err) + } + } else { + s.Constraints, err = pl.buildDefaultConstraints(pod, v1.ScheduleAnyway) + if err != nil { + return fmt.Errorf("setting default soft topology spread constraints: %w", err) + } + } + if len(s.Constraints) == 0 { + return nil + } + topoSize := make([]int, len(s.Constraints)) + for _, node := range filteredNodes { + if requireAllTopologies && !nodeLabelsMatchSpreadConstraints(node.Labels, s.Constraints) { + // Nodes which don't have all required topologyKeys present are ignored + // when scoring later. + s.IgnoredNodes.Insert(node.Name) + continue + } + for i, constraint := range s.Constraints { + // per-node counts are calculated during Score. + if constraint.TopologyKey == v1.LabelHostname { + continue + } + pair := topologyPair{key: constraint.TopologyKey, value: node.Labels[constraint.TopologyKey]} + if s.TopologyPairToPodCounts[pair] == nil { + s.TopologyPairToPodCounts[pair] = new(int64) + topoSize[i]++ + } + } + } + + s.TopologyNormalizingWeight = make([]float64, len(s.Constraints)) + for i, c := range s.Constraints { + sz := topoSize[i] + if c.TopologyKey == v1.LabelHostname { + sz = len(filteredNodes) - len(s.IgnoredNodes) + } + s.TopologyNormalizingWeight[i] = topologyNormalizingWeight(sz) + } + return nil +} + +// PreScore builds and writes cycle state used by Score and NormalizeScore. +func (pl *PodTopologySpread) PreScore( + ctx context.Context, + cycleState *framework.CycleState, + pod *v1.Pod, + filteredNodes []*v1.Node, +) *framework.Status { + allNodes, err := pl.sharedLister.NodeInfos().List() + if err != nil { + return framework.AsStatus(fmt.Errorf("getting all nodes: %w", err)) + } + + if len(filteredNodes) == 0 || len(allNodes) == 0 { + // No nodes to score. + return nil + } + + state := &preScoreState{ + IgnoredNodes: sets.NewString(), + TopologyPairToPodCounts: make(map[topologyPair]*int64), + } + // Only require that nodes have all the topology labels if using + // non-system-default spreading rules. This allows nodes that don't have a + // zone label to still have hostname spreading. + requireAllTopologies := len(pod.Spec.TopologySpreadConstraints) > 0 || !pl.systemDefaulted + err = pl.initPreScoreState(state, pod, filteredNodes, requireAllTopologies) + if err != nil { + return framework.AsStatus(fmt.Errorf("calculating preScoreState: %w", err)) + } + + // return if incoming pod doesn't have soft topology spread Constraints. + if len(state.Constraints) == 0 { + cycleState.Write(preScoreStateKey, state) + return nil + } + + // Ignore parsing errors for backwards compatibility. + requiredNodeAffinity := nodeaffinity.GetRequiredNodeAffinity(pod) + processAllNode := func(i int) { + nodeInfo := allNodes[i] + node := nodeInfo.Node() + if node == nil { + return + } + + if !pl.enableNodeInclusionPolicyInPodTopologySpread { + // `node` should satisfy incoming pod's NodeSelector/NodeAffinity + if match, _ := requiredNodeAffinity.Match(node); !match { + return + } + } + + // All topologyKeys need to be present in `node` + if requireAllTopologies && !nodeLabelsMatchSpreadConstraints(node.Labels, state.Constraints) { + return + } + + for _, c := range state.Constraints { + if pl.enableNodeInclusionPolicyInPodTopologySpread && + !c.matchNodeInclusionPolicies(pod, node, requiredNodeAffinity) { + continue + } + + pair := topologyPair{key: c.TopologyKey, value: node.Labels[c.TopologyKey]} + // If current topology pair is not associated with any candidate node, + // continue to avoid unnecessary calculation. + // Per-node counts are also skipped, as they are done during Score. + tpCount := state.TopologyPairToPodCounts[pair] + if tpCount == nil { + continue + } + count := countPodsMatchSelector(nodeInfo.Pods, c.Selector, pod.Namespace) + atomic.AddInt64(tpCount, int64(count)) + } + } + pl.parallelizer.Until(ctx, len(allNodes), processAllNode, pl.Name()) + + cycleState.Write(preScoreStateKey, state) + return nil +} + +// Score invoked at the Score extension point. +// The "score" returned in this function is the matching number of pods on the `nodeName`, +// it is normalized later. +func (pl *PodTopologySpread) Score(ctx context.Context, cycleState *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) { + nodeInfo, err := pl.sharedLister.NodeInfos().Get(nodeName) + if err != nil { + return 0, framework.AsStatus(fmt.Errorf("getting node %q from Snapshot: %w", nodeName, err)) + } + + node := nodeInfo.Node() + s, err := getPreScoreState(cycleState) + if err != nil { + return 0, framework.AsStatus(err) + } + + // Return if the node is not qualified. + if s.IgnoredNodes.Has(node.Name) { + return 0, nil + } + + // For each present , current node gets a credit of . + // And we sum up and return it as this node's score. + var score float64 + for i, c := range s.Constraints { + if tpVal, ok := node.Labels[c.TopologyKey]; ok { + var cnt int64 + if c.TopologyKey == v1.LabelHostname { + cnt = int64(countPodsMatchSelector(nodeInfo.Pods, c.Selector, pod.Namespace)) + } else { + pair := topologyPair{key: c.TopologyKey, value: tpVal} + cnt = *s.TopologyPairToPodCounts[pair] + } + score += scoreForCount(cnt, c.MaxSkew, s.TopologyNormalizingWeight[i]) + } + } + return int64(math.Round(score)), nil +} + +// NormalizeScore invoked after scoring all nodes. +func (pl *PodTopologySpread) NormalizeScore(ctx context.Context, cycleState *framework.CycleState, pod *v1.Pod, scores framework.NodeScoreList) *framework.Status { + s, err := getPreScoreState(cycleState) + if err != nil { + return framework.AsStatus(err) + } + if s == nil { + return nil + } + + // Calculate and + var minScore int64 = math.MaxInt64 + var maxScore int64 + for i, score := range scores { + // it's mandatory to check if is present in m.IgnoredNodes + if s.IgnoredNodes.Has(score.Name) { + scores[i].Score = invalidScore + continue + } + if score.Score < minScore { + minScore = score.Score + } + if score.Score > maxScore { + maxScore = score.Score + } + } + + for i := range scores { + if scores[i].Score == invalidScore { + scores[i].Score = 0 + continue + } + if maxScore == 0 { + scores[i].Score = framework.MaxNodeScore + continue + } + s := scores[i].Score + scores[i].Score = framework.MaxNodeScore * (maxScore + minScore - s) / maxScore + } + return nil +} + +// ScoreExtensions of the Score plugin. +func (pl *PodTopologySpread) ScoreExtensions() framework.ScoreExtensions { + return pl +} + +func getPreScoreState(cycleState *framework.CycleState) (*preScoreState, error) { + c, err := cycleState.Read(preScoreStateKey) + if err != nil { + return nil, fmt.Errorf("error reading %q from cycleState: %w", preScoreStateKey, err) + } + + s, ok := c.(*preScoreState) + if !ok { + return nil, fmt.Errorf("%+v convert to podtopologyspread.preScoreState error", c) + } + return s, nil +} + +// topologyNormalizingWeight calculates the weight for the topology, based on +// the number of values that exist for a topology. +// Since is at least 1 (all nodes that passed the Filters are in the +// same topology), and k8s supports 5k nodes, the result is in the interval +// <1.09, 8.52>. +// +// Note: could also be zero when no nodes have the required topologies, +// however we don't care about topology weight in this case as we return a 0 +// score for all nodes. +func topologyNormalizingWeight(size int) float64 { + return math.Log(float64(size + 2)) +} + +// scoreForCount calculates the score based on number of matching pods in a +// topology domain, the constraint's maxSkew and the topology weight. +// `maxSkew-1` is added to the score so that differences between topology +// domains get watered down, controlling the tolerance of the score to skews. +func scoreForCount(cnt int64, maxSkew int32, tpWeight float64) float64 { + return float64(cnt)*tpWeight + float64(maxSkew-1) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/queuesort/priority_sort.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/queuesort/priority_sort.go new file mode 100644 index 000000000..43eaa74bd --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/queuesort/priority_sort.go @@ -0,0 +1,51 @@ +/* +Copyright 2020 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 queuesort + +import ( + "k8s.io/apimachinery/pkg/runtime" + corev1helpers "k8s.io/component-helpers/scheduling/corev1" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" +) + +// Name is the name of the plugin used in the plugin registry and configurations. +const Name = names.PrioritySort + +// PrioritySort is a plugin that implements Priority based sorting. +type PrioritySort struct{} + +var _ framework.QueueSortPlugin = &PrioritySort{} + +// Name returns name of the plugin. +func (pl *PrioritySort) Name() string { + return Name +} + +// Less is the function used by the activeQ heap algorithm to sort pods. +// It sorts pods based on their priority. When priorities are equal, it uses +// PodQueueInfo.timestamp. +func (pl *PrioritySort) Less(pInfo1, pInfo2 *framework.QueuedPodInfo) bool { + p1 := corev1helpers.PodPriority(pInfo1.Pod) + p2 := corev1helpers.PodPriority(pInfo2.Pod) + return (p1 > p2) || (p1 == p2 && pInfo1.Timestamp.Before(pInfo2.Timestamp)) +} + +// New initializes a new plugin and returns it. +func New(_ runtime.Object, handle framework.Handle) (framework.Plugin, error) { + return &PrioritySort{}, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/registry.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/registry.go new file mode 100644 index 000000000..5769aee6e --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/registry.go @@ -0,0 +1,87 @@ +/* +Copyright 2019 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 plugins + +import ( + "k8s.io/apiserver/pkg/util/feature" + "k8s.io/kubernetes/pkg/features" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultbinder" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultpreemption" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/dynamicresources" + plfeature "k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/imagelocality" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeaffinity" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodename" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeports" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeunschedulable" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodevolumelimits" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/queuesort" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/schedulinggates" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/selectorspread" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/tainttoleration" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumerestrictions" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumezone" + "k8s.io/kubernetes/pkg/scheduler/framework/runtime" +) + +// NewInTreeRegistry builds the registry with all the in-tree plugins. +// A scheduler that runs out of tree plugins can register additional plugins +// through the WithFrameworkOutOfTreeRegistry option. +func NewInTreeRegistry() runtime.Registry { + fts := plfeature.Features{ + EnableDynamicResourceAllocation: feature.DefaultFeatureGate.Enabled(features.DynamicResourceAllocation), + EnableReadWriteOncePod: feature.DefaultFeatureGate.Enabled(features.ReadWriteOncePod), + EnableVolumeCapacityPriority: feature.DefaultFeatureGate.Enabled(features.VolumeCapacityPriority), + EnableMinDomainsInPodTopologySpread: feature.DefaultFeatureGate.Enabled(features.MinDomainsInPodTopologySpread), + EnableNodeInclusionPolicyInPodTopologySpread: feature.DefaultFeatureGate.Enabled(features.NodeInclusionPolicyInPodTopologySpread), + EnableMatchLabelKeysInPodTopologySpread: feature.DefaultFeatureGate.Enabled(features.MatchLabelKeysInPodTopologySpread), + EnablePodSchedulingReadiness: feature.DefaultFeatureGate.Enabled(features.PodSchedulingReadiness), + } + + registry := runtime.Registry{ + dynamicresources.Name: runtime.FactoryAdapter(fts, dynamicresources.New), + selectorspread.Name: selectorspread.New, + imagelocality.Name: imagelocality.New, + tainttoleration.Name: tainttoleration.New, + nodename.Name: nodename.New, + nodeports.Name: nodeports.New, + nodeaffinity.Name: nodeaffinity.New, + podtopologyspread.Name: runtime.FactoryAdapter(fts, podtopologyspread.New), + nodeunschedulable.Name: nodeunschedulable.New, + noderesources.Name: runtime.FactoryAdapter(fts, noderesources.NewFit), + noderesources.BalancedAllocationName: runtime.FactoryAdapter(fts, noderesources.NewBalancedAllocation), + volumebinding.Name: runtime.FactoryAdapter(fts, volumebinding.New), + volumerestrictions.Name: runtime.FactoryAdapter(fts, volumerestrictions.New), + volumezone.Name: volumezone.New, + nodevolumelimits.CSIName: runtime.FactoryAdapter(fts, nodevolumelimits.NewCSI), + nodevolumelimits.EBSName: runtime.FactoryAdapter(fts, nodevolumelimits.NewEBS), + nodevolumelimits.GCEPDName: runtime.FactoryAdapter(fts, nodevolumelimits.NewGCEPD), + nodevolumelimits.AzureDiskName: runtime.FactoryAdapter(fts, nodevolumelimits.NewAzureDisk), + nodevolumelimits.CinderName: runtime.FactoryAdapter(fts, nodevolumelimits.NewCinder), + interpodaffinity.Name: interpodaffinity.New, + queuesort.Name: queuesort.New, + defaultbinder.Name: defaultbinder.New, + defaultpreemption.Name: runtime.FactoryAdapter(fts, defaultpreemption.New), + schedulinggates.Name: runtime.FactoryAdapter(fts, schedulinggates.New), + } + + return registry +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/schedulinggates/scheduling_gates.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/schedulinggates/scheduling_gates.go new file mode 100644 index 000000000..249e31a3b --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/schedulinggates/scheduling_gates.go @@ -0,0 +1,67 @@ +/* +Copyright 2022 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 schedulinggates + +import ( + "context" + "fmt" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" +) + +// Name of the plugin used in the plugin registry and configurations. +const Name = names.SchedulingGates + +// SchedulingGates checks if a Pod carries .spec.schedulingGates. +type SchedulingGates struct { + enablePodSchedulingReadiness bool +} + +var _ framework.PreEnqueuePlugin = &SchedulingGates{} +var _ framework.EnqueueExtensions = &SchedulingGates{} + +func (pl *SchedulingGates) Name() string { + return Name +} + +func (pl *SchedulingGates) PreEnqueue(ctx context.Context, p *v1.Pod) *framework.Status { + if !pl.enablePodSchedulingReadiness || len(p.Spec.SchedulingGates) == 0 { + return nil + } + var gates []string + for _, gate := range p.Spec.SchedulingGates { + gates = append(gates, gate.Name) + } + return framework.NewStatus(framework.UnschedulableAndUnresolvable, fmt.Sprintf("waiting for scheduling gates: %v", gates)) +} + +// EventsToRegister returns the possible events that may make a Pod +// failed by this plugin schedulable. +func (pl *SchedulingGates) EventsToRegister() []framework.ClusterEvent { + return []framework.ClusterEvent{ + {Resource: framework.Pod, ActionType: framework.Update}, + } +} + +// New initializes a new plugin and returns it. +func New(_ runtime.Object, _ framework.Handle, fts feature.Features) (framework.Plugin, error) { + return &SchedulingGates{enablePodSchedulingReadiness: fts.EnablePodSchedulingReadiness}, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/selectorspread/selector_spread.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/selectorspread/selector_spread.go new file mode 100644 index 000000000..c50e0bfaf --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/selectorspread/selector_spread.go @@ -0,0 +1,234 @@ +/* +Copyright 2019 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 selectorspread + +import ( + "context" + "fmt" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + appslisters "k8s.io/client-go/listers/apps/v1" + corelisters "k8s.io/client-go/listers/core/v1" + utilnode "k8s.io/component-helpers/node/topology" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" +) + +// SelectorSpread is a plugin that calculates selector spread priority. +type SelectorSpread struct { + sharedLister framework.SharedLister + services corelisters.ServiceLister + replicationControllers corelisters.ReplicationControllerLister + replicaSets appslisters.ReplicaSetLister + statefulSets appslisters.StatefulSetLister +} + +var _ framework.PreScorePlugin = &SelectorSpread{} +var _ framework.ScorePlugin = &SelectorSpread{} + +const ( + // Name is the name of the plugin used in the plugin registry and configurations. + Name = names.SelectorSpread + // preScoreStateKey is the key in CycleState to SelectorSpread pre-computed data for Scoring. + preScoreStateKey = "PreScore" + Name + + // When zone information is present, give 2/3 of the weighting to zone spreading, 1/3 to node spreading + // TODO: Any way to justify this weighting? + zoneWeighting float64 = 2.0 / 3.0 +) + +// Name returns name of the plugin. It is used in logs, etc. +func (pl *SelectorSpread) Name() string { + return Name +} + +// preScoreState computed at PreScore and used at Score. +type preScoreState struct { + selector labels.Selector +} + +// Clone implements the mandatory Clone interface. We don't really copy the data since +// there is no need for that. +func (s *preScoreState) Clone() framework.StateData { + return s +} + +// skipSelectorSpread returns true if the pod's TopologySpreadConstraints are specified. +// Note that this doesn't take into account default constraints defined for +// the PodTopologySpread plugin. +func skipSelectorSpread(pod *v1.Pod) bool { + return len(pod.Spec.TopologySpreadConstraints) != 0 +} + +// Score invoked at the Score extension point. +// The "score" returned in this function is the matching number of pods on the `nodeName`, +// it is normalized later. +func (pl *SelectorSpread) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) { + if skipSelectorSpread(pod) { + return 0, nil + } + + c, err := state.Read(preScoreStateKey) + if err != nil { + return 0, framework.AsStatus(fmt.Errorf("reading %q from cycleState: %w", preScoreStateKey, err)) + } + + s, ok := c.(*preScoreState) + if !ok { + return 0, framework.AsStatus(fmt.Errorf("cannot convert saved state to selectorspread.preScoreState")) + } + + nodeInfo, err := pl.sharedLister.NodeInfos().Get(nodeName) + if err != nil { + return 0, framework.AsStatus(fmt.Errorf("getting node %q from Snapshot: %w", nodeName, err)) + } + + count := countMatchingPods(pod.Namespace, s.selector, nodeInfo) + return int64(count), nil +} + +// NormalizeScore invoked after scoring all nodes. +// For this plugin, it calculates the score of each node +// based on the number of existing matching pods on the node +// where zone information is included on the nodes, it favors nodes +// in zones with fewer existing matching pods. +func (pl *SelectorSpread) NormalizeScore(ctx context.Context, state *framework.CycleState, pod *v1.Pod, scores framework.NodeScoreList) *framework.Status { + if skipSelectorSpread(pod) { + return nil + } + + countsByZone := make(map[string]int64, 10) + maxCountByZone := int64(0) + maxCountByNodeName := int64(0) + + for i := range scores { + if scores[i].Score > maxCountByNodeName { + maxCountByNodeName = scores[i].Score + } + nodeInfo, err := pl.sharedLister.NodeInfos().Get(scores[i].Name) + if err != nil { + return framework.AsStatus(fmt.Errorf("getting node %q from Snapshot: %w", scores[i].Name, err)) + } + zoneID := utilnode.GetZoneKey(nodeInfo.Node()) + if zoneID == "" { + continue + } + countsByZone[zoneID] += scores[i].Score + } + + for zoneID := range countsByZone { + if countsByZone[zoneID] > maxCountByZone { + maxCountByZone = countsByZone[zoneID] + } + } + + haveZones := len(countsByZone) != 0 + + maxCountByNodeNameFloat64 := float64(maxCountByNodeName) + maxCountByZoneFloat64 := float64(maxCountByZone) + MaxNodeScoreFloat64 := float64(framework.MaxNodeScore) + + for i := range scores { + // initializing to the default/max node score of maxPriority + fScore := MaxNodeScoreFloat64 + if maxCountByNodeName > 0 { + fScore = MaxNodeScoreFloat64 * (float64(maxCountByNodeName-scores[i].Score) / maxCountByNodeNameFloat64) + } + // If there is zone information present, incorporate it + if haveZones { + nodeInfo, err := pl.sharedLister.NodeInfos().Get(scores[i].Name) + if err != nil { + return framework.AsStatus(fmt.Errorf("getting node %q from Snapshot: %w", scores[i].Name, err)) + } + + zoneID := utilnode.GetZoneKey(nodeInfo.Node()) + if zoneID != "" { + zoneScore := MaxNodeScoreFloat64 + if maxCountByZone > 0 { + zoneScore = MaxNodeScoreFloat64 * (float64(maxCountByZone-countsByZone[zoneID]) / maxCountByZoneFloat64) + } + fScore = (fScore * (1.0 - zoneWeighting)) + (zoneWeighting * zoneScore) + } + } + scores[i].Score = int64(fScore) + } + return nil +} + +// ScoreExtensions of the Score plugin. +func (pl *SelectorSpread) ScoreExtensions() framework.ScoreExtensions { + return pl +} + +// PreScore builds and writes cycle state used by Score and NormalizeScore. +func (pl *SelectorSpread) PreScore(ctx context.Context, cycleState *framework.CycleState, pod *v1.Pod, nodes []*v1.Node) *framework.Status { + if skipSelectorSpread(pod) { + return nil + } + selector := helper.DefaultSelector( + pod, + pl.services, + pl.replicationControllers, + pl.replicaSets, + pl.statefulSets, + ) + state := &preScoreState{ + selector: selector, + } + cycleState.Write(preScoreStateKey, state) + return nil +} + +// New initializes a new plugin and returns it. +func New(_ runtime.Object, handle framework.Handle) (framework.Plugin, error) { + sharedLister := handle.SnapshotSharedLister() + if sharedLister == nil { + return nil, fmt.Errorf("SnapshotSharedLister is nil") + } + sharedInformerFactory := handle.SharedInformerFactory() + if sharedInformerFactory == nil { + return nil, fmt.Errorf("SharedInformerFactory is nil") + } + return &SelectorSpread{ + sharedLister: sharedLister, + services: sharedInformerFactory.Core().V1().Services().Lister(), + replicationControllers: sharedInformerFactory.Core().V1().ReplicationControllers().Lister(), + replicaSets: sharedInformerFactory.Apps().V1().ReplicaSets().Lister(), + statefulSets: sharedInformerFactory.Apps().V1().StatefulSets().Lister(), + }, nil +} + +// countMatchingPods counts pods based on namespace and matching all selectors +func countMatchingPods(namespace string, selector labels.Selector, nodeInfo *framework.NodeInfo) int { + if len(nodeInfo.Pods) == 0 || selector.Empty() { + return 0 + } + count := 0 + for _, p := range nodeInfo.Pods { + // Ignore pods being deleted for spreading purposes + // Similar to how it is done for SelectorSpreadPriority + if namespace == p.Pod.Namespace && p.Pod.DeletionTimestamp == nil { + if selector.Matches(labels.Set(p.Pod.Labels)) { + count++ + } + } + } + return count +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/tainttoleration/taint_toleration.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/tainttoleration/taint_toleration.go new file mode 100644 index 000000000..4611a9815 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/tainttoleration/taint_toleration.go @@ -0,0 +1,172 @@ +/* +Copyright 2019 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 tainttoleration + +import ( + "context" + "fmt" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + v1helper "k8s.io/component-helpers/scheduling/corev1" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" +) + +// TaintToleration is a plugin that checks if a pod tolerates a node's taints. +type TaintToleration struct { + handle framework.Handle +} + +var _ framework.FilterPlugin = &TaintToleration{} +var _ framework.PreScorePlugin = &TaintToleration{} +var _ framework.ScorePlugin = &TaintToleration{} +var _ framework.EnqueueExtensions = &TaintToleration{} + +const ( + // Name is the name of the plugin used in the plugin registry and configurations. + Name = names.TaintToleration + // preScoreStateKey is the key in CycleState to TaintToleration pre-computed data for Scoring. + preScoreStateKey = "PreScore" + Name + // ErrReasonNotMatch is the Filter reason status when not matching. + ErrReasonNotMatch = "node(s) had taints that the pod didn't tolerate" +) + +// Name returns name of the plugin. It is used in logs, etc. +func (pl *TaintToleration) Name() string { + return Name +} + +// EventsToRegister returns the possible events that may make a Pod +// failed by this plugin schedulable. +func (pl *TaintToleration) EventsToRegister() []framework.ClusterEvent { + return []framework.ClusterEvent{ + {Resource: framework.Node, ActionType: framework.Add | framework.Update}, + } +} + +// Filter invoked at the filter extension point. +func (pl *TaintToleration) Filter(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status { + node := nodeInfo.Node() + if node == nil { + return framework.AsStatus(fmt.Errorf("invalid nodeInfo")) + } + + taint, isUntolerated := v1helper.FindMatchingUntoleratedTaint(node.Spec.Taints, pod.Spec.Tolerations, helper.DoNotScheduleTaintsFilterFunc()) + if !isUntolerated { + return nil + } + + errReason := fmt.Sprintf("node(s) had untolerated taint {%s: %s}", taint.Key, taint.Value) + return framework.NewStatus(framework.UnschedulableAndUnresolvable, errReason) +} + +// preScoreState computed at PreScore and used at Score. +type preScoreState struct { + tolerationsPreferNoSchedule []v1.Toleration +} + +// Clone implements the mandatory Clone interface. We don't really copy the data since +// there is no need for that. +func (s *preScoreState) Clone() framework.StateData { + return s +} + +// getAllTolerationEffectPreferNoSchedule gets the list of all Tolerations with Effect PreferNoSchedule or with no effect. +func getAllTolerationPreferNoSchedule(tolerations []v1.Toleration) (tolerationList []v1.Toleration) { + for _, toleration := range tolerations { + // Empty effect means all effects which includes PreferNoSchedule, so we need to collect it as well. + if len(toleration.Effect) == 0 || toleration.Effect == v1.TaintEffectPreferNoSchedule { + tolerationList = append(tolerationList, toleration) + } + } + return +} + +// PreScore builds and writes cycle state used by Score and NormalizeScore. +func (pl *TaintToleration) PreScore(ctx context.Context, cycleState *framework.CycleState, pod *v1.Pod, nodes []*v1.Node) *framework.Status { + if len(nodes) == 0 { + return nil + } + tolerationsPreferNoSchedule := getAllTolerationPreferNoSchedule(pod.Spec.Tolerations) + state := &preScoreState{ + tolerationsPreferNoSchedule: tolerationsPreferNoSchedule, + } + cycleState.Write(preScoreStateKey, state) + return nil +} + +func getPreScoreState(cycleState *framework.CycleState) (*preScoreState, error) { + c, err := cycleState.Read(preScoreStateKey) + if err != nil { + return nil, fmt.Errorf("failed to read %q from cycleState: %w", preScoreStateKey, err) + } + + s, ok := c.(*preScoreState) + if !ok { + return nil, fmt.Errorf("%+v convert to tainttoleration.preScoreState error", c) + } + return s, nil +} + +// CountIntolerableTaintsPreferNoSchedule gives the count of intolerable taints of a pod with effect PreferNoSchedule +func countIntolerableTaintsPreferNoSchedule(taints []v1.Taint, tolerations []v1.Toleration) (intolerableTaints int) { + for _, taint := range taints { + // check only on taints that have effect PreferNoSchedule + if taint.Effect != v1.TaintEffectPreferNoSchedule { + continue + } + + if !v1helper.TolerationsTolerateTaint(tolerations, &taint) { + intolerableTaints++ + } + } + return +} + +// Score invoked at the Score extension point. +func (pl *TaintToleration) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) { + nodeInfo, err := pl.handle.SnapshotSharedLister().NodeInfos().Get(nodeName) + if err != nil { + return 0, framework.AsStatus(fmt.Errorf("getting node %q from Snapshot: %w", nodeName, err)) + } + node := nodeInfo.Node() + + s, err := getPreScoreState(state) + if err != nil { + return 0, framework.AsStatus(err) + } + + score := int64(countIntolerableTaintsPreferNoSchedule(node.Spec.Taints, s.tolerationsPreferNoSchedule)) + return score, nil +} + +// NormalizeScore invoked after scoring all nodes. +func (pl *TaintToleration) NormalizeScore(ctx context.Context, _ *framework.CycleState, pod *v1.Pod, scores framework.NodeScoreList) *framework.Status { + return helper.DefaultNormalizeScore(framework.MaxNodeScore, true, scores) +} + +// ScoreExtensions of the Score plugin. +func (pl *TaintToleration) ScoreExtensions() framework.ScoreExtensions { + return pl +} + +// New initializes a new plugin and returns it. +func New(_ runtime.Object, h framework.Handle) (framework.Plugin, error) { + return &TaintToleration{handle: h}, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/OWNERS b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/OWNERS new file mode 100644 index 000000000..be3245e85 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/OWNERS @@ -0,0 +1,10 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +approvers: + - sig-storage-approvers + - cofyc +reviewers: + - sig-storage-reviewers + - cofyc +labels: + - sig/storage diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/assume_cache.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/assume_cache.go new file mode 100644 index 000000000..283b4083e --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/assume_cache.go @@ -0,0 +1,456 @@ +/* +Copyright 2017 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 volumebinding + +import ( + "fmt" + "strconv" + "sync" + + "k8s.io/klog/v2" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/client-go/tools/cache" + storagehelpers "k8s.io/component-helpers/storage/volume" +) + +// AssumeCache is a cache on top of the informer that allows for updating +// objects outside of informer events and also restoring the informer +// cache's version of the object. Objects are assumed to be +// Kubernetes API objects that implement meta.Interface +type AssumeCache interface { + // Assume updates the object in-memory only + Assume(obj interface{}) error + + // Restore the informer cache's version of the object + Restore(objName string) + + // Get the object by name + Get(objName string) (interface{}, error) + + // Get the API object by name + GetAPIObj(objName string) (interface{}, error) + + // List all the objects in the cache + List(indexObj interface{}) []interface{} +} + +type errWrongType struct { + typeName string + object interface{} +} + +func (e *errWrongType) Error() string { + return fmt.Sprintf("could not convert object to type %v: %+v", e.typeName, e.object) +} + +type errNotFound struct { + typeName string + objectName string +} + +func (e *errNotFound) Error() string { + return fmt.Sprintf("could not find %v %q", e.typeName, e.objectName) +} + +type errObjectName struct { + detailedErr error +} + +func (e *errObjectName) Error() string { + return fmt.Sprintf("failed to get object name: %v", e.detailedErr) +} + +// assumeCache stores two pointers to represent a single object: +// - The pointer to the informer object. +// - The pointer to the latest object, which could be the same as +// the informer object, or an in-memory object. +// +// An informer update always overrides the latest object pointer. +// +// Assume() only updates the latest object pointer. +// Restore() sets the latest object pointer back to the informer object. +// Get/List() always returns the latest object pointer. +type assumeCache struct { + // Synchronizes updates to store + rwMutex sync.RWMutex + + // describes the object stored + description string + + // Stores objInfo pointers + store cache.Indexer + + // Index function for object + indexFunc cache.IndexFunc + indexName string +} + +type objInfo struct { + // name of the object + name string + + // Latest version of object could be cached-only or from informer + latestObj interface{} + + // Latest object from informer + apiObj interface{} +} + +func objInfoKeyFunc(obj interface{}) (string, error) { + objInfo, ok := obj.(*objInfo) + if !ok { + return "", &errWrongType{"objInfo", obj} + } + return objInfo.name, nil +} + +func (c *assumeCache) objInfoIndexFunc(obj interface{}) ([]string, error) { + objInfo, ok := obj.(*objInfo) + if !ok { + return []string{""}, &errWrongType{"objInfo", obj} + } + return c.indexFunc(objInfo.latestObj) +} + +// NewAssumeCache creates an assume cache for general objects. +func NewAssumeCache(informer cache.SharedIndexInformer, description, indexName string, indexFunc cache.IndexFunc) AssumeCache { + c := &assumeCache{ + description: description, + indexFunc: indexFunc, + indexName: indexName, + } + indexers := cache.Indexers{} + if indexName != "" && indexFunc != nil { + indexers[indexName] = c.objInfoIndexFunc + } + c.store = cache.NewIndexer(objInfoKeyFunc, indexers) + + // Unit tests don't use informers + if informer != nil { + informer.AddEventHandler( + cache.ResourceEventHandlerFuncs{ + AddFunc: c.add, + UpdateFunc: c.update, + DeleteFunc: c.delete, + }, + ) + } + return c +} + +func (c *assumeCache) add(obj interface{}) { + if obj == nil { + return + } + + name, err := cache.MetaNamespaceKeyFunc(obj) + if err != nil { + klog.ErrorS(&errObjectName{err}, "Add failed") + return + } + + c.rwMutex.Lock() + defer c.rwMutex.Unlock() + + if objInfo, _ := c.getObjInfo(name); objInfo != nil { + newVersion, err := c.getObjVersion(name, obj) + if err != nil { + klog.ErrorS(err, "Add failed: couldn't get object version") + return + } + + storedVersion, err := c.getObjVersion(name, objInfo.latestObj) + if err != nil { + klog.ErrorS(err, "Add failed: couldn't get stored object version") + return + } + + // Only update object if version is newer. + // This is so we don't override assumed objects due to informer resync. + if newVersion <= storedVersion { + klog.V(10).InfoS("Skip adding object to assume cache because version is not newer than storedVersion", "description", c.description, "cacheKey", name, "newVersion", newVersion, "storedVersion", storedVersion) + return + } + } + + objInfo := &objInfo{name: name, latestObj: obj, apiObj: obj} + if err = c.store.Update(objInfo); err != nil { + klog.InfoS("Error occurred while updating stored object", "err", err) + } else { + klog.V(10).InfoS("Adding object to assume cache", "description", c.description, "cacheKey", name, "assumeCache", obj) + } +} + +func (c *assumeCache) update(oldObj interface{}, newObj interface{}) { + c.add(newObj) +} + +func (c *assumeCache) delete(obj interface{}) { + if obj == nil { + return + } + + name, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj) + if err != nil { + klog.ErrorS(&errObjectName{err}, "Failed to delete") + return + } + + c.rwMutex.Lock() + defer c.rwMutex.Unlock() + + objInfo := &objInfo{name: name} + err = c.store.Delete(objInfo) + if err != nil { + klog.ErrorS(err, "Failed to delete", "description", c.description, "cacheKey", name) + } +} + +func (c *assumeCache) getObjVersion(name string, obj interface{}) (int64, error) { + objAccessor, err := meta.Accessor(obj) + if err != nil { + return -1, err + } + + objResourceVersion, err := strconv.ParseInt(objAccessor.GetResourceVersion(), 10, 64) + if err != nil { + return -1, fmt.Errorf("error parsing ResourceVersion %q for %v %q: %s", objAccessor.GetResourceVersion(), c.description, name, err) + } + return objResourceVersion, nil +} + +func (c *assumeCache) getObjInfo(name string) (*objInfo, error) { + obj, ok, err := c.store.GetByKey(name) + if err != nil { + return nil, err + } + if !ok { + return nil, &errNotFound{c.description, name} + } + + objInfo, ok := obj.(*objInfo) + if !ok { + return nil, &errWrongType{"objInfo", obj} + } + return objInfo, nil +} + +func (c *assumeCache) Get(objName string) (interface{}, error) { + c.rwMutex.RLock() + defer c.rwMutex.RUnlock() + + objInfo, err := c.getObjInfo(objName) + if err != nil { + return nil, err + } + return objInfo.latestObj, nil +} + +func (c *assumeCache) GetAPIObj(objName string) (interface{}, error) { + c.rwMutex.RLock() + defer c.rwMutex.RUnlock() + + objInfo, err := c.getObjInfo(objName) + if err != nil { + return nil, err + } + return objInfo.apiObj, nil +} + +func (c *assumeCache) List(indexObj interface{}) []interface{} { + c.rwMutex.RLock() + defer c.rwMutex.RUnlock() + + allObjs := []interface{}{} + objs, err := c.store.Index(c.indexName, &objInfo{latestObj: indexObj}) + if err != nil { + klog.ErrorS(err, "List index error") + return nil + } + + for _, obj := range objs { + objInfo, ok := obj.(*objInfo) + if !ok { + klog.ErrorS(&errWrongType{"objInfo", obj}, "List error") + continue + } + allObjs = append(allObjs, objInfo.latestObj) + } + return allObjs +} + +func (c *assumeCache) Assume(obj interface{}) error { + name, err := cache.MetaNamespaceKeyFunc(obj) + if err != nil { + return &errObjectName{err} + } + + c.rwMutex.Lock() + defer c.rwMutex.Unlock() + + objInfo, err := c.getObjInfo(name) + if err != nil { + return err + } + + newVersion, err := c.getObjVersion(name, obj) + if err != nil { + return err + } + + storedVersion, err := c.getObjVersion(name, objInfo.latestObj) + if err != nil { + return err + } + + if newVersion < storedVersion { + return fmt.Errorf("%v %q is out of sync (stored: %d, assume: %d)", c.description, name, storedVersion, newVersion) + } + + // Only update the cached object + objInfo.latestObj = obj + klog.V(4).InfoS("Assumed object", "description", c.description, "cacheKey", name, "version", newVersion) + return nil +} + +func (c *assumeCache) Restore(objName string) { + c.rwMutex.Lock() + defer c.rwMutex.Unlock() + + objInfo, err := c.getObjInfo(objName) + if err != nil { + // This could be expected if object got deleted + klog.V(5).InfoS("Restore object", "description", c.description, "cacheKey", objName, "err", err) + } else { + objInfo.latestObj = objInfo.apiObj + klog.V(4).InfoS("Restored object", "description", c.description, "cacheKey", objName) + } +} + +// PVAssumeCache is a AssumeCache for PersistentVolume objects +type PVAssumeCache interface { + AssumeCache + + GetPV(pvName string) (*v1.PersistentVolume, error) + GetAPIPV(pvName string) (*v1.PersistentVolume, error) + ListPVs(storageClassName string) []*v1.PersistentVolume +} + +type pvAssumeCache struct { + AssumeCache +} + +func pvStorageClassIndexFunc(obj interface{}) ([]string, error) { + if pv, ok := obj.(*v1.PersistentVolume); ok { + return []string{storagehelpers.GetPersistentVolumeClass(pv)}, nil + } + return []string{""}, fmt.Errorf("object is not a v1.PersistentVolume: %v", obj) +} + +// NewPVAssumeCache creates a PV assume cache. +func NewPVAssumeCache(informer cache.SharedIndexInformer) PVAssumeCache { + return &pvAssumeCache{NewAssumeCache(informer, "v1.PersistentVolume", "storageclass", pvStorageClassIndexFunc)} +} + +func (c *pvAssumeCache) GetPV(pvName string) (*v1.PersistentVolume, error) { + obj, err := c.Get(pvName) + if err != nil { + return nil, err + } + + pv, ok := obj.(*v1.PersistentVolume) + if !ok { + return nil, &errWrongType{"v1.PersistentVolume", obj} + } + return pv, nil +} + +func (c *pvAssumeCache) GetAPIPV(pvName string) (*v1.PersistentVolume, error) { + obj, err := c.GetAPIObj(pvName) + if err != nil { + return nil, err + } + pv, ok := obj.(*v1.PersistentVolume) + if !ok { + return nil, &errWrongType{"v1.PersistentVolume", obj} + } + return pv, nil +} + +func (c *pvAssumeCache) ListPVs(storageClassName string) []*v1.PersistentVolume { + objs := c.List(&v1.PersistentVolume{ + Spec: v1.PersistentVolumeSpec{ + StorageClassName: storageClassName, + }, + }) + pvs := []*v1.PersistentVolume{} + for _, obj := range objs { + pv, ok := obj.(*v1.PersistentVolume) + if !ok { + klog.ErrorS(&errWrongType{"v1.PersistentVolume", obj}, "ListPVs") + continue + } + pvs = append(pvs, pv) + } + return pvs +} + +// PVCAssumeCache is a AssumeCache for PersistentVolumeClaim objects +type PVCAssumeCache interface { + AssumeCache + + // GetPVC returns the PVC from the cache with given pvcKey. + // pvcKey is the result of MetaNamespaceKeyFunc on PVC obj + GetPVC(pvcKey string) (*v1.PersistentVolumeClaim, error) + GetAPIPVC(pvcKey string) (*v1.PersistentVolumeClaim, error) +} + +type pvcAssumeCache struct { + AssumeCache +} + +// NewPVCAssumeCache creates a PVC assume cache. +func NewPVCAssumeCache(informer cache.SharedIndexInformer) PVCAssumeCache { + return &pvcAssumeCache{NewAssumeCache(informer, "v1.PersistentVolumeClaim", "", nil)} +} + +func (c *pvcAssumeCache) GetPVC(pvcKey string) (*v1.PersistentVolumeClaim, error) { + obj, err := c.Get(pvcKey) + if err != nil { + return nil, err + } + + pvc, ok := obj.(*v1.PersistentVolumeClaim) + if !ok { + return nil, &errWrongType{"v1.PersistentVolumeClaim", obj} + } + return pvc, nil +} + +func (c *pvcAssumeCache) GetAPIPVC(pvcKey string) (*v1.PersistentVolumeClaim, error) { + obj, err := c.GetAPIObj(pvcKey) + if err != nil { + return nil, err + } + pvc, ok := obj.(*v1.PersistentVolumeClaim) + if !ok { + return nil, &errWrongType{"v1.PersistentVolumeClaim", obj} + } + return pvc, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/binder.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/binder.go new file mode 100644 index 000000000..362588601 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/binder.go @@ -0,0 +1,1069 @@ +/* +Copyright 2017 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 volumebinding + +import ( + "context" + "fmt" + "sort" + "strings" + "time" + + v1 "k8s.io/api/core/v1" + storagev1 "k8s.io/api/storage/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/apiserver/pkg/storage" + utilfeature "k8s.io/apiserver/pkg/util/feature" + coreinformers "k8s.io/client-go/informers/core/v1" + storageinformers "k8s.io/client-go/informers/storage/v1" + clientset "k8s.io/client-go/kubernetes" + corelisters "k8s.io/client-go/listers/core/v1" + storagelisters "k8s.io/client-go/listers/storage/v1" + "k8s.io/component-helpers/storage/ephemeral" + "k8s.io/component-helpers/storage/volume" + csitrans "k8s.io/csi-translation-lib" + csiplugins "k8s.io/csi-translation-lib/plugins" + "k8s.io/klog/v2" + v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" + "k8s.io/kubernetes/pkg/features" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/metrics" +) + +// ConflictReason is used for the special strings which explain why +// volume binding is impossible for a node. +type ConflictReason string + +// ConflictReasons contains all reasons that explain why volume binding is impossible for a node. +type ConflictReasons []ConflictReason + +func (reasons ConflictReasons) Len() int { return len(reasons) } +func (reasons ConflictReasons) Less(i, j int) bool { return reasons[i] < reasons[j] } +func (reasons ConflictReasons) Swap(i, j int) { reasons[i], reasons[j] = reasons[j], reasons[i] } + +const ( + // ErrReasonBindConflict is used for VolumeBindingNoMatch predicate error. + ErrReasonBindConflict ConflictReason = "node(s) didn't find available persistent volumes to bind" + // ErrReasonNodeConflict is used for VolumeNodeAffinityConflict predicate error. + ErrReasonNodeConflict ConflictReason = "node(s) had volume node affinity conflict" + // ErrReasonNotEnoughSpace is used when a pod cannot start on a node because not enough storage space is available. + ErrReasonNotEnoughSpace = "node(s) did not have enough free storage" + // ErrReasonPVNotExist is used when a pod has one or more PVC(s) bound to non-existent persistent volume(s)" + ErrReasonPVNotExist = "node(s) unavailable due to one or more pvc(s) bound to non-existent pv(s)" +) + +// BindingInfo holds a binding between PV and PVC. +type BindingInfo struct { + // PVC that needs to be bound + pvc *v1.PersistentVolumeClaim + + // Proposed PV to bind to this PVC + pv *v1.PersistentVolume +} + +// StorageClassName returns the name of the storage class. +func (b *BindingInfo) StorageClassName() string { + return b.pv.Spec.StorageClassName +} + +// StorageResource represents storage resource. +type StorageResource struct { + Requested int64 + Capacity int64 +} + +// StorageResource returns storage resource. +func (b *BindingInfo) StorageResource() *StorageResource { + // both fields are mandatory + requestedQty := b.pvc.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)] + capacityQty := b.pv.Spec.Capacity[v1.ResourceName(v1.ResourceStorage)] + return &StorageResource{ + Requested: requestedQty.Value(), + Capacity: capacityQty.Value(), + } +} + +// PodVolumes holds pod's volumes information used in volume scheduling. +type PodVolumes struct { + // StaticBindings are binding decisions for PVCs which can be bound to + // pre-provisioned static PVs. + StaticBindings []*BindingInfo + // DynamicProvisions are PVCs that require dynamic provisioning + DynamicProvisions []*v1.PersistentVolumeClaim +} + +// InTreeToCSITranslator contains methods required to check migratable status +// and perform translations from InTree PV's to CSI +type InTreeToCSITranslator interface { + IsPVMigratable(pv *v1.PersistentVolume) bool + GetInTreePluginNameFromSpec(pv *v1.PersistentVolume, vol *v1.Volume) (string, error) + TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) +} + +// SchedulerVolumeBinder is used by the scheduler VolumeBinding plugin to +// handle PVC/PV binding and dynamic provisioning. The binding decisions are +// integrated into the pod scheduling workflow so that the PV NodeAffinity is +// also considered along with the pod's other scheduling requirements. +// +// This integrates into the existing scheduler workflow as follows: +// 1. The scheduler takes a Pod off the scheduler queue and processes it serially: +// a. Invokes all pre-filter plugins for the pod. GetPodVolumes() is invoked +// here, pod volume information will be saved in current scheduling cycle state for later use. +// b. Invokes all filter plugins, parallelized across nodes. FindPodVolumes() is invoked here. +// c. Invokes all score plugins. Future/TBD +// d. Selects the best node for the Pod. +// e. Invokes all reserve plugins. AssumePodVolumes() is invoked here. +// i. If PVC binding is required, cache in-memory only: +// * For manual binding: update PV objects for prebinding to the corresponding PVCs. +// * For dynamic provisioning: update PVC object with a selected node from c) +// * For the pod, which PVCs and PVs need API updates. +// ii. Afterwards, the main scheduler caches the Pod->Node binding in the scheduler's pod cache, +// This is handled in the scheduler and not here. +// f. Asynchronously bind volumes and pod in a separate goroutine +// i. BindPodVolumes() is called first in PreBind phase. It makes all the necessary API updates and waits for +// PV controller to fully bind and provision the PVCs. If binding fails, the Pod is sent +// back through the scheduler. +// ii. After BindPodVolumes() is complete, then the scheduler does the final Pod->Node binding. +// 2. Once all the assume operations are done in e), the scheduler processes the next Pod in the scheduler queue +// while the actual binding operation occurs in the background. +type SchedulerVolumeBinder interface { + // GetPodVolumes returns a pod's PVCs separated into bound, unbound with delayed binding (including provisioning) + // and unbound with immediate binding (including prebound) + GetPodVolumes(pod *v1.Pod) (boundClaims, unboundClaimsDelayBinding, unboundClaimsImmediate []*v1.PersistentVolumeClaim, err error) + + // FindPodVolumes checks if all of a Pod's PVCs can be satisfied by the + // node and returns pod's volumes information. + // + // If a PVC is bound, it checks if the PV's NodeAffinity matches the Node. + // Otherwise, it tries to find an available PV to bind to the PVC. + // + // It returns an error when something went wrong or a list of reasons why the node is + // (currently) not usable for the pod. + // + // If the CSIStorageCapacity feature is enabled, then it also checks for sufficient storage + // for volumes that still need to be created. + // + // This function is called by the scheduler VolumeBinding plugin and can be called in parallel + FindPodVolumes(pod *v1.Pod, boundClaims, claimsToBind []*v1.PersistentVolumeClaim, node *v1.Node) (podVolumes *PodVolumes, reasons ConflictReasons, err error) + + // AssumePodVolumes will: + // 1. Take the PV matches for unbound PVCs and update the PV cache assuming + // that the PV is prebound to the PVC. + // 2. Take the PVCs that need provisioning and update the PVC cache with related + // annotations set. + // + // It returns true if all volumes are fully bound + // + // This function is called serially. + AssumePodVolumes(assumedPod *v1.Pod, nodeName string, podVolumes *PodVolumes) (allFullyBound bool, err error) + + // RevertAssumedPodVolumes will revert assumed PV and PVC cache. + RevertAssumedPodVolumes(podVolumes *PodVolumes) + + // BindPodVolumes will: + // 1. Initiate the volume binding by making the API call to prebind the PV + // to its matching PVC. + // 2. Trigger the volume provisioning by making the API call to set related + // annotations on the PVC + // 3. Wait for PVCs to be completely bound by the PV controller + // + // This function can be called in parallel. + BindPodVolumes(ctx context.Context, assumedPod *v1.Pod, podVolumes *PodVolumes) error +} + +type volumeBinder struct { + kubeClient clientset.Interface + + classLister storagelisters.StorageClassLister + podLister corelisters.PodLister + nodeLister corelisters.NodeLister + csiNodeLister storagelisters.CSINodeLister + + pvcCache PVCAssumeCache + pvCache PVAssumeCache + + // Amount of time to wait for the bind operation to succeed + bindTimeout time.Duration + + translator InTreeToCSITranslator + + csiDriverLister storagelisters.CSIDriverLister + csiStorageCapacityLister storagelisters.CSIStorageCapacityLister +} + +// CapacityCheck contains additional parameters for NewVolumeBinder that +// are only needed when checking volume sizes against available storage +// capacity is desired. +type CapacityCheck struct { + CSIDriverInformer storageinformers.CSIDriverInformer + CSIStorageCapacityInformer storageinformers.CSIStorageCapacityInformer +} + +// NewVolumeBinder sets up all the caches needed for the scheduler to make volume binding decisions. +// +// capacityCheck determines how storage capacity is checked (CSIStorageCapacity feature). +func NewVolumeBinder( + kubeClient clientset.Interface, + podInformer coreinformers.PodInformer, + nodeInformer coreinformers.NodeInformer, + csiNodeInformer storageinformers.CSINodeInformer, + pvcInformer coreinformers.PersistentVolumeClaimInformer, + pvInformer coreinformers.PersistentVolumeInformer, + storageClassInformer storageinformers.StorageClassInformer, + capacityCheck CapacityCheck, + bindTimeout time.Duration) SchedulerVolumeBinder { + b := &volumeBinder{ + kubeClient: kubeClient, + podLister: podInformer.Lister(), + classLister: storageClassInformer.Lister(), + nodeLister: nodeInformer.Lister(), + csiNodeLister: csiNodeInformer.Lister(), + pvcCache: NewPVCAssumeCache(pvcInformer.Informer()), + pvCache: NewPVAssumeCache(pvInformer.Informer()), + bindTimeout: bindTimeout, + translator: csitrans.New(), + } + + b.csiDriverLister = capacityCheck.CSIDriverInformer.Lister() + b.csiStorageCapacityLister = capacityCheck.CSIStorageCapacityInformer.Lister() + + return b +} + +// FindPodVolumes finds the matching PVs for PVCs and nodes to provision PVs +// for the given pod and node. If the node does not fit, confilict reasons are +// returned. +func (b *volumeBinder) FindPodVolumes(pod *v1.Pod, boundClaims, claimsToBind []*v1.PersistentVolumeClaim, node *v1.Node) (podVolumes *PodVolumes, reasons ConflictReasons, err error) { + podVolumes = &PodVolumes{} + + // Warning: Below log needs high verbosity as it can be printed several times (#60933). + klog.V(5).InfoS("FindPodVolumes", "pod", klog.KObj(pod), "node", klog.KObj(node)) + + // Initialize to true for pods that don't have volumes. These + // booleans get translated into reason strings when the function + // returns without an error. + unboundVolumesSatisfied := true + boundVolumesSatisfied := true + sufficientStorage := true + boundPVsFound := true + defer func() { + if err != nil { + return + } + if !boundVolumesSatisfied { + reasons = append(reasons, ErrReasonNodeConflict) + } + if !unboundVolumesSatisfied { + reasons = append(reasons, ErrReasonBindConflict) + } + if !sufficientStorage { + reasons = append(reasons, ErrReasonNotEnoughSpace) + } + if !boundPVsFound { + reasons = append(reasons, ErrReasonPVNotExist) + } + }() + + defer func() { + if err != nil { + metrics.VolumeSchedulingStageFailed.WithLabelValues("predicate").Inc() + } + }() + + var ( + staticBindings []*BindingInfo + dynamicProvisions []*v1.PersistentVolumeClaim + ) + defer func() { + // Although we do not distinguish nil from empty in this function, for + // easier testing, we normalize empty to nil. + if len(staticBindings) == 0 { + staticBindings = nil + } + if len(dynamicProvisions) == 0 { + dynamicProvisions = nil + } + podVolumes.StaticBindings = staticBindings + podVolumes.DynamicProvisions = dynamicProvisions + }() + + // Check PV node affinity on bound volumes + if len(boundClaims) > 0 { + boundVolumesSatisfied, boundPVsFound, err = b.checkBoundClaims(boundClaims, node, pod) + if err != nil { + return + } + } + + // Find matching volumes and node for unbound claims + if len(claimsToBind) > 0 { + var ( + claimsToFindMatching []*v1.PersistentVolumeClaim + claimsToProvision []*v1.PersistentVolumeClaim + ) + + // Filter out claims to provision + for _, claim := range claimsToBind { + if selectedNode, ok := claim.Annotations[volume.AnnSelectedNode]; ok { + if selectedNode != node.Name { + // Fast path, skip unmatched node. + unboundVolumesSatisfied = false + return + } + claimsToProvision = append(claimsToProvision, claim) + } else { + claimsToFindMatching = append(claimsToFindMatching, claim) + } + } + + // Find matching volumes + if len(claimsToFindMatching) > 0 { + var unboundClaims []*v1.PersistentVolumeClaim + unboundVolumesSatisfied, staticBindings, unboundClaims, err = b.findMatchingVolumes(pod, claimsToFindMatching, node) + if err != nil { + return + } + claimsToProvision = append(claimsToProvision, unboundClaims...) + } + + // Check for claims to provision. This is the first time where we potentially + // find out that storage is not sufficient for the node. + if len(claimsToProvision) > 0 { + unboundVolumesSatisfied, sufficientStorage, dynamicProvisions, err = b.checkVolumeProvisions(pod, claimsToProvision, node) + if err != nil { + return + } + } + } + + return +} + +// AssumePodVolumes will take the matching PVs and PVCs to provision in pod's +// volume information for the chosen node, and: +// 1. Update the pvCache with the new prebound PV. +// 2. Update the pvcCache with the new PVCs with annotations set +// 3. Update PodVolumes again with cached API updates for PVs and PVCs. +func (b *volumeBinder) AssumePodVolumes(assumedPod *v1.Pod, nodeName string, podVolumes *PodVolumes) (allFullyBound bool, err error) { + klog.V(4).InfoS("AssumePodVolumes", "pod", klog.KObj(assumedPod), "node", klog.KRef("", nodeName)) + defer func() { + if err != nil { + metrics.VolumeSchedulingStageFailed.WithLabelValues("assume").Inc() + } + }() + + if allBound := b.arePodVolumesBound(assumedPod); allBound { + klog.V(4).InfoS("AssumePodVolumes: all PVCs bound and nothing to do", "pod", klog.KObj(assumedPod), "node", klog.KRef("", nodeName)) + return true, nil + } + + // Assume PV + newBindings := []*BindingInfo{} + for _, binding := range podVolumes.StaticBindings { + newPV, dirty, err := volume.GetBindVolumeToClaim(binding.pv, binding.pvc) + klog.V(5).InfoS("AssumePodVolumes: GetBindVolumeToClaim", + "pod", klog.KObj(assumedPod), + "PV", klog.KObj(binding.pv), + "PVC", klog.KObj(binding.pvc), + "newPV", klog.KObj(newPV), + "dirty", dirty, + ) + if err != nil { + klog.ErrorS(err, "AssumePodVolumes: fail to GetBindVolumeToClaim") + b.revertAssumedPVs(newBindings) + return false, err + } + // TODO: can we assume every time? + if dirty { + err = b.pvCache.Assume(newPV) + if err != nil { + b.revertAssumedPVs(newBindings) + return false, err + } + } + newBindings = append(newBindings, &BindingInfo{pv: newPV, pvc: binding.pvc}) + } + + // Assume PVCs + newProvisionedPVCs := []*v1.PersistentVolumeClaim{} + for _, claim := range podVolumes.DynamicProvisions { + // The claims from method args can be pointing to watcher cache. We must not + // modify these, therefore create a copy. + claimClone := claim.DeepCopy() + metav1.SetMetaDataAnnotation(&claimClone.ObjectMeta, volume.AnnSelectedNode, nodeName) + err = b.pvcCache.Assume(claimClone) + if err != nil { + b.revertAssumedPVs(newBindings) + b.revertAssumedPVCs(newProvisionedPVCs) + return + } + + newProvisionedPVCs = append(newProvisionedPVCs, claimClone) + } + + podVolumes.StaticBindings = newBindings + podVolumes.DynamicProvisions = newProvisionedPVCs + return +} + +// RevertAssumedPodVolumes will revert assumed PV and PVC cache. +func (b *volumeBinder) RevertAssumedPodVolumes(podVolumes *PodVolumes) { + b.revertAssumedPVs(podVolumes.StaticBindings) + b.revertAssumedPVCs(podVolumes.DynamicProvisions) +} + +// BindPodVolumes gets the cached bindings and PVCs to provision in pod's volumes information, +// makes the API update for those PVs/PVCs, and waits for the PVCs to be completely bound +// by the PV controller. +func (b *volumeBinder) BindPodVolumes(ctx context.Context, assumedPod *v1.Pod, podVolumes *PodVolumes) (err error) { + klog.V(4).InfoS("BindPodVolumes", "pod", klog.KObj(assumedPod), "node", klog.KRef("", assumedPod.Spec.NodeName)) + + defer func() { + if err != nil { + metrics.VolumeSchedulingStageFailed.WithLabelValues("bind").Inc() + } + }() + + bindings := podVolumes.StaticBindings + claimsToProvision := podVolumes.DynamicProvisions + + // Start API operations + err = b.bindAPIUpdate(ctx, assumedPod, bindings, claimsToProvision) + if err != nil { + return err + } + + err = wait.Poll(time.Second, b.bindTimeout, func() (bool, error) { + b, err := b.checkBindings(assumedPod, bindings, claimsToProvision) + return b, err + }) + if err != nil { + return fmt.Errorf("binding volumes: %w", err) + } + return nil +} + +func getPodName(pod *v1.Pod) string { + return pod.Namespace + "/" + pod.Name +} + +func getPVCName(pvc *v1.PersistentVolumeClaim) string { + return pvc.Namespace + "/" + pvc.Name +} + +// bindAPIUpdate makes the API update for those PVs/PVCs. +func (b *volumeBinder) bindAPIUpdate(ctx context.Context, pod *v1.Pod, bindings []*BindingInfo, claimsToProvision []*v1.PersistentVolumeClaim) error { + podName := getPodName(pod) + if bindings == nil { + return fmt.Errorf("failed to get cached bindings for pod %q", podName) + } + if claimsToProvision == nil { + return fmt.Errorf("failed to get cached claims to provision for pod %q", podName) + } + + lastProcessedBinding := 0 + lastProcessedProvisioning := 0 + defer func() { + // only revert assumed cached updates for volumes we haven't successfully bound + if lastProcessedBinding < len(bindings) { + b.revertAssumedPVs(bindings[lastProcessedBinding:]) + } + // only revert assumed cached updates for claims we haven't updated, + if lastProcessedProvisioning < len(claimsToProvision) { + b.revertAssumedPVCs(claimsToProvision[lastProcessedProvisioning:]) + } + }() + + var ( + binding *BindingInfo + i int + claim *v1.PersistentVolumeClaim + ) + + // Do the actual prebinding. Let the PV controller take care of the rest + // There is no API rollback if the actual binding fails + for _, binding = range bindings { + // TODO: does it hurt if we make an api call and nothing needs to be updated? + klog.V(5).InfoS("Updating PersistentVolume: binding to claim", "pod", klog.KObj(pod), "PV", klog.KObj(binding.pv), "PVC", klog.KObj(binding.pvc)) + newPV, err := b.kubeClient.CoreV1().PersistentVolumes().Update(ctx, binding.pv, metav1.UpdateOptions{}) + if err != nil { + klog.V(4).InfoS("Updating PersistentVolume: binding to claim failed", "pod", klog.KObj(pod), "PV", klog.KObj(binding.pv), "PVC", klog.KObj(binding.pvc), "err", err) + return err + } + klog.V(2).InfoS("Updated PersistentVolume with claim. Waiting for binding to complete", "pod", klog.KObj(pod), "PV", klog.KObj(binding.pv), "PVC", klog.KObj(binding.pvc)) + // Save updated object from apiserver for later checking. + binding.pv = newPV + lastProcessedBinding++ + } + + // Update claims objects to trigger volume provisioning. Let the PV controller take care of the rest + // PV controller is expected to signal back by removing related annotations if actual provisioning fails + for i, claim = range claimsToProvision { + klog.V(5).InfoS("Updating claims objects to trigger volume provisioning", "pod", klog.KObj(pod), "PVC", klog.KObj(claim)) + newClaim, err := b.kubeClient.CoreV1().PersistentVolumeClaims(claim.Namespace).Update(ctx, claim, metav1.UpdateOptions{}) + if err != nil { + klog.V(4).InfoS("Updating PersistentVolumeClaim: binding to volume failed", "PVC", klog.KObj(claim), "err", err) + return err + } + + // Save updated object from apiserver for later checking. + claimsToProvision[i] = newClaim + lastProcessedProvisioning++ + } + + return nil +} + +var ( + versioner = storage.APIObjectVersioner{} +) + +// checkBindings runs through all the PVCs in the Pod and checks: +// * if the PVC is fully bound +// * if there are any conditions that require binding to fail and be retried +// +// It returns true when all of the Pod's PVCs are fully bound, and error if +// binding (and scheduling) needs to be retried +// Note that it checks on API objects not PV/PVC cache, this is because +// PV/PVC cache can be assumed again in main scheduler loop, we must check +// latest state in API server which are shared with PV controller and +// provisioners +func (b *volumeBinder) checkBindings(pod *v1.Pod, bindings []*BindingInfo, claimsToProvision []*v1.PersistentVolumeClaim) (bool, error) { + podName := getPodName(pod) + if bindings == nil { + return false, fmt.Errorf("failed to get cached bindings for pod %q", podName) + } + if claimsToProvision == nil { + return false, fmt.Errorf("failed to get cached claims to provision for pod %q", podName) + } + + node, err := b.nodeLister.Get(pod.Spec.NodeName) + if err != nil { + return false, fmt.Errorf("failed to get node %q: %w", pod.Spec.NodeName, err) + } + + csiNode, err := b.csiNodeLister.Get(node.Name) + if err != nil { + // TODO: return the error once CSINode is created by default + klog.V(4).InfoS("Could not get a CSINode object for the node", "node", klog.KObj(node), "err", err) + } + + // Check for any conditions that might require scheduling retry + + // When pod is deleted, binding operation should be cancelled. There is no + // need to check PV/PVC bindings any more. + _, err = b.podLister.Pods(pod.Namespace).Get(pod.Name) + if err != nil { + if apierrors.IsNotFound(err) { + return false, fmt.Errorf("pod does not exist any more: %w", err) + } + klog.ErrorS(err, "Failed to get pod from the lister", "pod", klog.KObj(pod)) + } + + for _, binding := range bindings { + pv, err := b.pvCache.GetAPIPV(binding.pv.Name) + if err != nil { + return false, fmt.Errorf("failed to check binding: %w", err) + } + + pvc, err := b.pvcCache.GetAPIPVC(getPVCName(binding.pvc)) + if err != nil { + return false, fmt.Errorf("failed to check binding: %w", err) + } + + // Because we updated PV in apiserver, skip if API object is older + // and wait for new API object propagated from apiserver. + if versioner.CompareResourceVersion(binding.pv, pv) > 0 { + return false, nil + } + + pv, err = b.tryTranslatePVToCSI(pv, csiNode) + if err != nil { + return false, fmt.Errorf("failed to translate pv to csi: %w", err) + } + + // Check PV's node affinity (the node might not have the proper label) + if err := volume.CheckNodeAffinity(pv, node.Labels); err != nil { + return false, fmt.Errorf("pv %q node affinity doesn't match node %q: %w", pv.Name, node.Name, err) + } + + // Check if pv.ClaimRef got dropped by unbindVolume() + if pv.Spec.ClaimRef == nil || pv.Spec.ClaimRef.UID == "" { + return false, fmt.Errorf("ClaimRef got reset for pv %q", pv.Name) + } + + // Check if pvc is fully bound + if !b.isPVCFullyBound(pvc) { + return false, nil + } + } + + for _, claim := range claimsToProvision { + pvc, err := b.pvcCache.GetAPIPVC(getPVCName(claim)) + if err != nil { + return false, fmt.Errorf("failed to check provisioning pvc: %w", err) + } + + // Because we updated PVC in apiserver, skip if API object is older + // and wait for new API object propagated from apiserver. + if versioner.CompareResourceVersion(claim, pvc) > 0 { + return false, nil + } + + // Check if selectedNode annotation is still set + if pvc.Annotations == nil { + return false, fmt.Errorf("selectedNode annotation reset for PVC %q", pvc.Name) + } + selectedNode := pvc.Annotations[volume.AnnSelectedNode] + if selectedNode != pod.Spec.NodeName { + // If provisioner fails to provision a volume, selectedNode + // annotation will be removed to signal back to the scheduler to + // retry. + return false, fmt.Errorf("provisioning failed for PVC %q", pvc.Name) + } + + // If the PVC is bound to a PV, check its node affinity + if pvc.Spec.VolumeName != "" { + pv, err := b.pvCache.GetAPIPV(pvc.Spec.VolumeName) + if err != nil { + if _, ok := err.(*errNotFound); ok { + // We tolerate NotFound error here, because PV is possibly + // not found because of API delay, we can check next time. + // And if PV does not exist because it's deleted, PVC will + // be unbound eventually. + return false, nil + } + return false, fmt.Errorf("failed to get pv %q from cache: %w", pvc.Spec.VolumeName, err) + } + + pv, err = b.tryTranslatePVToCSI(pv, csiNode) + if err != nil { + return false, err + } + + if err := volume.CheckNodeAffinity(pv, node.Labels); err != nil { + return false, fmt.Errorf("pv %q node affinity doesn't match node %q: %w", pv.Name, node.Name, err) + } + } + + // Check if pvc is fully bound + if !b.isPVCFullyBound(pvc) { + return false, nil + } + } + + // All pvs and pvcs that we operated on are bound + klog.V(2).InfoS("All PVCs for pod are bound", "pod", klog.KObj(pod)) + return true, nil +} + +func (b *volumeBinder) isVolumeBound(pod *v1.Pod, vol *v1.Volume) (bound bool, pvc *v1.PersistentVolumeClaim, err error) { + pvcName := "" + isEphemeral := false + switch { + case vol.PersistentVolumeClaim != nil: + pvcName = vol.PersistentVolumeClaim.ClaimName + case vol.Ephemeral != nil: + // Generic ephemeral inline volumes also use a PVC, + // just with a computed name, and... + pvcName = ephemeral.VolumeClaimName(pod, vol) + isEphemeral = true + default: + return true, nil, nil + } + + bound, pvc, err = b.isPVCBound(pod.Namespace, pvcName) + // ... the PVC must be owned by the pod. + if isEphemeral && err == nil && pvc != nil { + if err := ephemeral.VolumeIsForPod(pod, pvc); err != nil { + return false, nil, err + } + } + return +} + +func (b *volumeBinder) isPVCBound(namespace, pvcName string) (bool, *v1.PersistentVolumeClaim, error) { + claim := &v1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: pvcName, + Namespace: namespace, + }, + } + pvcKey := getPVCName(claim) + pvc, err := b.pvcCache.GetPVC(pvcKey) + if err != nil || pvc == nil { + return false, nil, fmt.Errorf("error getting PVC %q: %v", pvcKey, err) + } + + fullyBound := b.isPVCFullyBound(pvc) + if fullyBound { + klog.V(5).InfoS("PVC is fully bound to PV", "PVC", klog.KObj(pvc), "PV", klog.KRef("", pvc.Spec.VolumeName)) + } else { + if pvc.Spec.VolumeName != "" { + klog.V(5).InfoS("PVC is not fully bound to PV", "PVC", klog.KObj(pvc), "PV", klog.KRef("", pvc.Spec.VolumeName)) + } else { + klog.V(5).InfoS("PVC is not bound", "PVC", klog.KObj(pvc)) + } + } + return fullyBound, pvc, nil +} + +func (b *volumeBinder) isPVCFullyBound(pvc *v1.PersistentVolumeClaim) bool { + return pvc.Spec.VolumeName != "" && metav1.HasAnnotation(pvc.ObjectMeta, volume.AnnBindCompleted) +} + +// arePodVolumesBound returns true if all volumes are fully bound +func (b *volumeBinder) arePodVolumesBound(pod *v1.Pod) bool { + for _, vol := range pod.Spec.Volumes { + if isBound, _, _ := b.isVolumeBound(pod, &vol); !isBound { + // Pod has at least one PVC that needs binding + return false + } + } + return true +} + +// GetPodVolumes returns a pod's PVCs separated into bound, unbound with delayed binding (including provisioning) +// and unbound with immediate binding (including prebound) +func (b *volumeBinder) GetPodVolumes(pod *v1.Pod) (boundClaims []*v1.PersistentVolumeClaim, unboundClaimsDelayBinding []*v1.PersistentVolumeClaim, unboundClaimsImmediate []*v1.PersistentVolumeClaim, err error) { + boundClaims = []*v1.PersistentVolumeClaim{} + unboundClaimsImmediate = []*v1.PersistentVolumeClaim{} + unboundClaimsDelayBinding = []*v1.PersistentVolumeClaim{} + + for _, vol := range pod.Spec.Volumes { + volumeBound, pvc, err := b.isVolumeBound(pod, &vol) + if err != nil { + return nil, nil, nil, err + } + if pvc == nil { + continue + } + if volumeBound { + boundClaims = append(boundClaims, pvc) + } else { + delayBindingMode, err := volume.IsDelayBindingMode(pvc, b.classLister) + if err != nil { + return nil, nil, nil, err + } + // Prebound PVCs are treated as unbound immediate binding + if delayBindingMode && pvc.Spec.VolumeName == "" { + // Scheduler path + unboundClaimsDelayBinding = append(unboundClaimsDelayBinding, pvc) + } else { + // !delayBindingMode || pvc.Spec.VolumeName != "" + // Immediate binding should have already been bound + unboundClaimsImmediate = append(unboundClaimsImmediate, pvc) + } + } + } + return boundClaims, unboundClaimsDelayBinding, unboundClaimsImmediate, nil +} + +func (b *volumeBinder) checkBoundClaims(claims []*v1.PersistentVolumeClaim, node *v1.Node, pod *v1.Pod) (bool, bool, error) { + csiNode, err := b.csiNodeLister.Get(node.Name) + if err != nil { + // TODO: return the error once CSINode is created by default + klog.V(4).InfoS("Could not get a CSINode object for the node", "node", klog.KObj(node), "err", err) + } + + for _, pvc := range claims { + pvName := pvc.Spec.VolumeName + pv, err := b.pvCache.GetPV(pvName) + if err != nil { + if _, ok := err.(*errNotFound); ok { + err = nil + } + return true, false, err + } + + pv, err = b.tryTranslatePVToCSI(pv, csiNode) + if err != nil { + return false, true, err + } + + err = volume.CheckNodeAffinity(pv, node.Labels) + if err != nil { + klog.V(4).InfoS("PersistentVolume and node mismatch for pod", "PV", klog.KRef("", pvName), "node", klog.KObj(node), "pod", klog.KObj(pod), "err", err) + return false, true, nil + } + klog.V(5).InfoS("PersistentVolume and node matches for pod", "PV", klog.KRef("", pvName), "node", klog.KObj(node), "pod", klog.KObj(pod)) + } + + klog.V(4).InfoS("All bound volumes for pod match with node", "pod", klog.KObj(pod), "node", klog.KObj(node)) + return true, true, nil +} + +// findMatchingVolumes tries to find matching volumes for given claims, +// and return unbound claims for further provision. +func (b *volumeBinder) findMatchingVolumes(pod *v1.Pod, claimsToBind []*v1.PersistentVolumeClaim, node *v1.Node) (foundMatches bool, bindings []*BindingInfo, unboundClaims []*v1.PersistentVolumeClaim, err error) { + // Sort all the claims by increasing size request to get the smallest fits + sort.Sort(byPVCSize(claimsToBind)) + + chosenPVs := map[string]*v1.PersistentVolume{} + + foundMatches = true + + for _, pvc := range claimsToBind { + // Get storage class name from each PVC + storageClassName := volume.GetPersistentVolumeClaimClass(pvc) + allPVs := b.pvCache.ListPVs(storageClassName) + + // Find a matching PV + pv, err := volume.FindMatchingVolume(pvc, allPVs, node, chosenPVs, true) + if err != nil { + return false, nil, nil, err + } + if pv == nil { + klog.V(4).InfoS("No matching volumes for pod", "pod", klog.KObj(pod), "PVC", klog.KObj(pvc), "node", klog.KObj(node)) + unboundClaims = append(unboundClaims, pvc) + foundMatches = false + continue + } + + // matching PV needs to be excluded so we don't select it again + chosenPVs[pv.Name] = pv + bindings = append(bindings, &BindingInfo{pv: pv, pvc: pvc}) + klog.V(5).InfoS("Found matching PV for PVC for pod", "PV", klog.KObj(pv), "PVC", klog.KObj(pvc), "node", klog.KObj(node), "pod", klog.KObj(pod)) + } + + if foundMatches { + klog.V(4).InfoS("Found matching volumes for pod", "pod", klog.KObj(pod), "node", klog.KObj(node)) + } + + return +} + +// checkVolumeProvisions checks given unbound claims (the claims have gone through func +// findMatchingVolumes, and do not have matching volumes for binding), and return true +// if all of the claims are eligible for dynamic provision. +func (b *volumeBinder) checkVolumeProvisions(pod *v1.Pod, claimsToProvision []*v1.PersistentVolumeClaim, node *v1.Node) (provisionSatisfied, sufficientStorage bool, dynamicProvisions []*v1.PersistentVolumeClaim, err error) { + dynamicProvisions = []*v1.PersistentVolumeClaim{} + + // We return early with provisionedClaims == nil if a check + // fails or we encounter an error. + for _, claim := range claimsToProvision { + pvcName := getPVCName(claim) + className := volume.GetPersistentVolumeClaimClass(claim) + if className == "" { + return false, false, nil, fmt.Errorf("no class for claim %q", pvcName) + } + + class, err := b.classLister.Get(className) + if err != nil { + return false, false, nil, fmt.Errorf("failed to find storage class %q", className) + } + provisioner := class.Provisioner + if provisioner == "" || provisioner == volume.NotSupportedProvisioner { + klog.V(4).InfoS("Storage class of claim does not support dynamic provisioning", "storageClassName", className, "PVC", klog.KObj(claim)) + return false, true, nil, nil + } + + // Check if the node can satisfy the topology requirement in the class + if !v1helper.MatchTopologySelectorTerms(class.AllowedTopologies, labels.Set(node.Labels)) { + klog.V(4).InfoS("Node cannot satisfy provisioning topology requirements of claim", "node", klog.KObj(node), "PVC", klog.KObj(claim)) + return false, true, nil, nil + } + + // Check storage capacity. + sufficient, err := b.hasEnoughCapacity(provisioner, claim, class, node) + if err != nil { + return false, false, nil, err + } + if !sufficient { + // hasEnoughCapacity logs an explanation. + return true, false, nil, nil + } + + dynamicProvisions = append(dynamicProvisions, claim) + + } + klog.V(4).InfoS("Provisioning for claims of pod that has no matching volumes...", "claimCount", len(claimsToProvision), "pod", klog.KObj(pod), "node", klog.KObj(node)) + + return true, true, dynamicProvisions, nil +} + +func (b *volumeBinder) revertAssumedPVs(bindings []*BindingInfo) { + for _, BindingInfo := range bindings { + b.pvCache.Restore(BindingInfo.pv.Name) + } +} + +func (b *volumeBinder) revertAssumedPVCs(claims []*v1.PersistentVolumeClaim) { + for _, claim := range claims { + b.pvcCache.Restore(getPVCName(claim)) + } +} + +// hasEnoughCapacity checks whether the provisioner has enough capacity left for a new volume of the given size +// that is available from the node. +func (b *volumeBinder) hasEnoughCapacity(provisioner string, claim *v1.PersistentVolumeClaim, storageClass *storagev1.StorageClass, node *v1.Node) (bool, error) { + quantity, ok := claim.Spec.Resources.Requests[v1.ResourceStorage] + if !ok { + // No capacity to check for. + return true, nil + } + + // Only enabled for CSI drivers which opt into it. + driver, err := b.csiDriverLister.Get(provisioner) + if err != nil { + if apierrors.IsNotFound(err) { + // Either the provisioner is not a CSI driver or the driver does not + // opt into storage capacity scheduling. Either way, skip + // capacity checking. + return true, nil + } + return false, err + } + if driver.Spec.StorageCapacity == nil || !*driver.Spec.StorageCapacity { + return true, nil + } + + // Look for a matching CSIStorageCapacity object(s). + // TODO (for beta): benchmark this and potentially introduce some kind of lookup structure (https://github.com/kubernetes/enhancements/issues/1698#issuecomment-654356718). + capacities, err := b.csiStorageCapacityLister.List(labels.Everything()) + if err != nil { + return false, err + } + + sizeInBytes := quantity.Value() + for _, capacity := range capacities { + if capacity.StorageClassName == storageClass.Name && + capacitySufficient(capacity, sizeInBytes) && + b.nodeHasAccess(node, capacity) { + // Enough capacity found. + return true, nil + } + } + + // TODO (?): this doesn't give any information about which pools where considered and why + // they had to be rejected. Log that above? But that might be a lot of log output... + klog.V(4).InfoS("Node has no accessible CSIStorageCapacity with enough capacity for PVC", + "node", klog.KObj(node), "PVC", klog.KObj(claim), "size", sizeInBytes, "storageClass", klog.KObj(storageClass)) + return false, nil +} + +func capacitySufficient(capacity *storagev1.CSIStorageCapacity, sizeInBytes int64) bool { + limit := capacity.Capacity + if capacity.MaximumVolumeSize != nil { + // Prefer MaximumVolumeSize if available, it is more precise. + limit = capacity.MaximumVolumeSize + } + return limit != nil && limit.Value() >= sizeInBytes +} + +func (b *volumeBinder) nodeHasAccess(node *v1.Node, capacity *storagev1.CSIStorageCapacity) bool { + if capacity.NodeTopology == nil { + // Unavailable + return false + } + // Only matching by label is supported. + selector, err := metav1.LabelSelectorAsSelector(capacity.NodeTopology) + if err != nil { + klog.ErrorS(err, "Unexpected error converting to a label selector", "nodeTopology", capacity.NodeTopology) + return false + } + return selector.Matches(labels.Set(node.Labels)) +} + +type byPVCSize []*v1.PersistentVolumeClaim + +func (a byPVCSize) Len() int { + return len(a) +} + +func (a byPVCSize) Swap(i, j int) { + a[i], a[j] = a[j], a[i] +} + +func (a byPVCSize) Less(i, j int) bool { + iSize := a[i].Spec.Resources.Requests[v1.ResourceStorage] + jSize := a[j].Spec.Resources.Requests[v1.ResourceStorage] + // return true if iSize is less than jSize + return iSize.Cmp(jSize) == -1 +} + +// isCSIMigrationOnForPlugin checks if CSI migration is enabled for a given plugin. +func isCSIMigrationOnForPlugin(pluginName string) bool { + switch pluginName { + case csiplugins.AWSEBSInTreePluginName: + return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationAWS) + case csiplugins.GCEPDInTreePluginName: + return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationGCE) + case csiplugins.AzureDiskInTreePluginName: + return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationAzureDisk) + case csiplugins.CinderInTreePluginName: + return true + case csiplugins.PortworxVolumePluginName: + return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationPortworx) + case csiplugins.RBDVolumePluginName: + return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationRBD) + } + return false +} + +// isPluginMigratedToCSIOnNode checks if an in-tree plugin has been migrated to a CSI driver on the node. +func isPluginMigratedToCSIOnNode(pluginName string, csiNode *storagev1.CSINode) bool { + if csiNode == nil { + return false + } + + csiNodeAnn := csiNode.GetAnnotations() + if csiNodeAnn == nil { + return false + } + + var mpaSet sets.String + mpa := csiNodeAnn[v1.MigratedPluginsAnnotationKey] + if len(mpa) == 0 { + mpaSet = sets.NewString() + } else { + tok := strings.Split(mpa, ",") + mpaSet = sets.NewString(tok...) + } + + return mpaSet.Has(pluginName) +} + +// tryTranslatePVToCSI will translate the in-tree PV to CSI if it meets the criteria. If not, it returns the unmodified in-tree PV. +func (b *volumeBinder) tryTranslatePVToCSI(pv *v1.PersistentVolume, csiNode *storagev1.CSINode) (*v1.PersistentVolume, error) { + if !b.translator.IsPVMigratable(pv) { + return pv, nil + } + + pluginName, err := b.translator.GetInTreePluginNameFromSpec(pv, nil) + if err != nil { + return nil, fmt.Errorf("could not get plugin name from pv: %v", err) + } + + if !isCSIMigrationOnForPlugin(pluginName) { + return pv, nil + } + + if !isPluginMigratedToCSIOnNode(pluginName, csiNode) { + return pv, nil + } + + transPV, err := b.translator.TranslateInTreePVToCSI(pv) + if err != nil { + return nil, fmt.Errorf("could not translate pv: %v", err) + } + + return transPV, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/fake_binder.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/fake_binder.go new file mode 100644 index 000000000..ef28891f2 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/fake_binder.go @@ -0,0 +1,72 @@ +/* +Copyright 2017 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 volumebinding + +import ( + "context" + + v1 "k8s.io/api/core/v1" +) + +// FakeVolumeBinderConfig holds configurations for fake volume binder. +type FakeVolumeBinderConfig struct { + AllBound bool + FindReasons ConflictReasons + FindErr error + AssumeErr error + BindErr error +} + +// NewFakeVolumeBinder sets up all the caches needed for the scheduler to make +// topology-aware volume binding decisions. +func NewFakeVolumeBinder(config *FakeVolumeBinderConfig) *FakeVolumeBinder { + return &FakeVolumeBinder{ + config: config, + } +} + +// FakeVolumeBinder represents a fake volume binder for testing. +type FakeVolumeBinder struct { + config *FakeVolumeBinderConfig + AssumeCalled bool + BindCalled bool +} + +// GetPodVolumes implements SchedulerVolumeBinder.GetPodVolumes. +func (b *FakeVolumeBinder) GetPodVolumes(pod *v1.Pod) (boundClaims, unboundClaimsDelayBinding, unboundClaimsImmediate []*v1.PersistentVolumeClaim, err error) { + return nil, nil, nil, nil +} + +// FindPodVolumes implements SchedulerVolumeBinder.FindPodVolumes. +func (b *FakeVolumeBinder) FindPodVolumes(pod *v1.Pod, _, _ []*v1.PersistentVolumeClaim, node *v1.Node) (podVolumes *PodVolumes, reasons ConflictReasons, err error) { + return nil, b.config.FindReasons, b.config.FindErr +} + +// AssumePodVolumes implements SchedulerVolumeBinder.AssumePodVolumes. +func (b *FakeVolumeBinder) AssumePodVolumes(assumedPod *v1.Pod, nodeName string, podVolumes *PodVolumes) (bool, error) { + b.AssumeCalled = true + return b.config.AllBound, b.config.AssumeErr +} + +// RevertAssumedPodVolumes implements SchedulerVolumeBinder.RevertAssumedPodVolumes +func (b *FakeVolumeBinder) RevertAssumedPodVolumes(_ *PodVolumes) {} + +// BindPodVolumes implements SchedulerVolumeBinder.BindPodVolumes. +func (b *FakeVolumeBinder) BindPodVolumes(ctx context.Context, assumedPod *v1.Pod, podVolumes *PodVolumes) error { + b.BindCalled = true + return b.config.BindErr +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/metrics/metrics.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/metrics/metrics.go new file mode 100644 index 000000000..a52b19632 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/metrics/metrics.go @@ -0,0 +1,55 @@ +/* +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 metrics + +import ( + "k8s.io/component-base/metrics" + "k8s.io/component-base/metrics/legacyregistry" +) + +// VolumeSchedulerSubsystem - subsystem name used by scheduler +const VolumeSchedulerSubsystem = "scheduler_volume" + +var ( + // VolumeBindingRequestSchedulerBinderCache tracks the number of volume binder cache operations. + VolumeBindingRequestSchedulerBinderCache = metrics.NewCounterVec( + &metrics.CounterOpts{ + Subsystem: VolumeSchedulerSubsystem, + Name: "binder_cache_requests_total", + Help: "Total number for request volume binding cache", + StabilityLevel: metrics.ALPHA, + }, + []string{"operation"}, + ) + // VolumeSchedulingStageFailed tracks the number of failed volume scheduling operations. + VolumeSchedulingStageFailed = metrics.NewCounterVec( + &metrics.CounterOpts{ + Subsystem: VolumeSchedulerSubsystem, + Name: "scheduling_stage_error_total", + Help: "Volume scheduling stage error count", + StabilityLevel: metrics.ALPHA, + }, + []string{"operation"}, + ) +) + +// RegisterVolumeSchedulingMetrics is used for scheduler, because the volume binding cache is a library +// used by scheduler process. +func RegisterVolumeSchedulingMetrics() { + legacyregistry.MustRegister(VolumeBindingRequestSchedulerBinderCache) + legacyregistry.MustRegister(VolumeSchedulingStageFailed) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/scorer.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/scorer.go new file mode 100644 index 000000000..4c079f28d --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/scorer.go @@ -0,0 +1,54 @@ +/* +Copyright 2021 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 volumebinding + +import ( + "math" + + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper" +) + +// classResourceMap holds a map of storage class to resource. +type classResourceMap map[string]*StorageResource + +// volumeCapacityScorer calculates the score based on class storage resource information. +type volumeCapacityScorer func(classResourceMap) int64 + +// buildScorerFunction builds volumeCapacityScorer from the scoring function shape. +func buildScorerFunction(scoringFunctionShape helper.FunctionShape) volumeCapacityScorer { + rawScoringFunction := helper.BuildBrokenLinearFunction(scoringFunctionShape) + f := func(requested, capacity int64) int64 { + if capacity == 0 || requested > capacity { + return rawScoringFunction(maxUtilization) + } + + return rawScoringFunction(requested * maxUtilization / capacity) + } + return func(classResources classResourceMap) int64 { + var nodeScore int64 + // in alpha stage, all classes have the same weight + weightSum := len(classResources) + if weightSum == 0 { + return 0 + } + for _, resource := range classResources { + classScore := f(resource.Requested, resource.Capacity) + nodeScore += classScore + } + return int64(math.Round(float64(nodeScore) / float64(weightSum))) + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/test_utils.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/test_utils.go new file mode 100644 index 000000000..d58e36679 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/test_utils.go @@ -0,0 +1,206 @@ +/* +Copyright 2021 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 volumebinding + +import ( + "fmt" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/component-helpers/storage/volume" + "k8s.io/utils/pointer" +) + +type nodeBuilder struct { + *v1.Node +} + +func makeNode(name string) nodeBuilder { + return nodeBuilder{Node: &v1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Labels: map[string]string{ + v1.LabelHostname: name, + }, + }, + }} +} + +func (nb nodeBuilder) withLabel(key, value string) nodeBuilder { + if nb.Node.ObjectMeta.Labels == nil { + nb.Node.ObjectMeta.Labels = map[string]string{} + } + nb.Node.ObjectMeta.Labels[key] = value + return nb +} + +type pvBuilder struct { + *v1.PersistentVolume +} + +func makePV(name, className string) pvBuilder { + return pvBuilder{PersistentVolume: &v1.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Spec: v1.PersistentVolumeSpec{ + StorageClassName: className, + }, + }} +} + +func (pvb pvBuilder) withNodeAffinity(keyValues map[string][]string) pvBuilder { + matchExpressions := make([]v1.NodeSelectorRequirement, 0) + for key, values := range keyValues { + matchExpressions = append(matchExpressions, v1.NodeSelectorRequirement{ + Key: key, + Operator: v1.NodeSelectorOpIn, + Values: values, + }) + } + pvb.PersistentVolume.Spec.NodeAffinity = &v1.VolumeNodeAffinity{ + Required: &v1.NodeSelector{ + NodeSelectorTerms: []v1.NodeSelectorTerm{ + { + MatchExpressions: matchExpressions, + }, + }, + }, + } + return pvb +} + +func (pvb pvBuilder) withVersion(version string) pvBuilder { + pvb.PersistentVolume.ObjectMeta.ResourceVersion = version + return pvb +} + +func (pvb pvBuilder) withCapacity(capacity resource.Quantity) pvBuilder { + pvb.PersistentVolume.Spec.Capacity = v1.ResourceList{ + v1.ResourceName(v1.ResourceStorage): capacity, + } + return pvb +} + +func (pvb pvBuilder) withPhase(phase v1.PersistentVolumePhase) pvBuilder { + pvb.PersistentVolume.Status = v1.PersistentVolumeStatus{ + Phase: phase, + } + return pvb +} + +type pvcBuilder struct { + *v1.PersistentVolumeClaim +} + +func makePVC(name string, storageClassName string) pvcBuilder { + return pvcBuilder{PersistentVolumeClaim: &v1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: v1.NamespaceDefault, + }, + Spec: v1.PersistentVolumeClaimSpec{ + StorageClassName: pointer.String(storageClassName), + }, + }} +} + +func (pvcb pvcBuilder) withBoundPV(pvName string) pvcBuilder { + pvcb.PersistentVolumeClaim.Spec.VolumeName = pvName + metav1.SetMetaDataAnnotation(&pvcb.PersistentVolumeClaim.ObjectMeta, volume.AnnBindCompleted, "true") + return pvcb +} + +func (pvcb pvcBuilder) withRequestStorage(request resource.Quantity) pvcBuilder { + pvcb.PersistentVolumeClaim.Spec.Resources = v1.ResourceRequirements{ + Requests: v1.ResourceList{ + v1.ResourceName(v1.ResourceStorage): request, + }, + } + return pvcb +} + +func (pvcb pvcBuilder) withPhase(phase v1.PersistentVolumeClaimPhase) pvcBuilder { + pvcb.PersistentVolumeClaim.Status = v1.PersistentVolumeClaimStatus{ + Phase: phase, + } + return pvcb +} + +type podBuilder struct { + *v1.Pod +} + +func makePod(name string) podBuilder { + pb := podBuilder{Pod: &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: v1.NamespaceDefault, + }, + }} + pb.Pod.Spec.Volumes = make([]v1.Volume, 0) + return pb +} + +func (pb podBuilder) withNodeName(name string) podBuilder { + pb.Pod.Spec.NodeName = name + return pb +} + +func (pb podBuilder) withNamespace(name string) podBuilder { + pb.Pod.ObjectMeta.Namespace = name + return pb +} + +func (pb podBuilder) withPVCVolume(pvcName, name string) podBuilder { + pb.Pod.Spec.Volumes = append(pb.Pod.Spec.Volumes, v1.Volume{ + Name: name, + VolumeSource: v1.VolumeSource{ + PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ + ClaimName: pvcName, + }, + }, + }) + return pb +} + +func (pb podBuilder) withPVCSVolume(pvcs []*v1.PersistentVolumeClaim) podBuilder { + for i, pvc := range pvcs { + pb.withPVCVolume(pvc.Name, fmt.Sprintf("vol%v", i)) + } + return pb +} + +func (pb podBuilder) withEmptyDirVolume() podBuilder { + pb.Pod.Spec.Volumes = append(pb.Pod.Spec.Volumes, v1.Volume{ + VolumeSource: v1.VolumeSource{ + EmptyDir: &v1.EmptyDirVolumeSource{}, + }, + }) + return pb +} + +func (pb podBuilder) withGenericEphemeralVolume(name string) podBuilder { + pb.Pod.Spec.Volumes = append(pb.Pod.Spec.Volumes, v1.Volume{ + Name: name, + VolumeSource: v1.VolumeSource{ + Ephemeral: &v1.EphemeralVolumeSource{}, + }, + }) + return pb +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/volume_binding.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/volume_binding.go new file mode 100644 index 000000000..3983064cb --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/volume_binding.go @@ -0,0 +1,398 @@ +/* +Copyright 2019 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 volumebinding + +import ( + "context" + "errors" + "fmt" + "sync" + "time" + + v1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + corelisters "k8s.io/client-go/listers/core/v1" + "k8s.io/component-helpers/storage/ephemeral" + "k8s.io/klog/v2" + "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/kubernetes/pkg/scheduler/apis/config/validation" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" +) + +const ( + stateKey framework.StateKey = Name + + maxUtilization = 100 +) + +// the state is initialized in PreFilter phase. because we save the pointer in +// framework.CycleState, in the later phases we don't need to call Write method +// to update the value +type stateData struct { + skip bool // set true if pod does not have PVCs + boundClaims []*v1.PersistentVolumeClaim + claimsToBind []*v1.PersistentVolumeClaim + allBound bool + // podVolumesByNode holds the pod's volume information found in the Filter + // phase for each node + // it's initialized in the PreFilter phase + podVolumesByNode map[string]*PodVolumes + sync.Mutex +} + +func (d *stateData) Clone() framework.StateData { + return d +} + +// VolumeBinding is a plugin that binds pod volumes in scheduling. +// In the Filter phase, pod binding cache is created for the pod and used in +// Reserve and PreBind phases. +type VolumeBinding struct { + Binder SchedulerVolumeBinder + PVCLister corelisters.PersistentVolumeClaimLister + scorer volumeCapacityScorer + fts feature.Features +} + +var _ framework.PreFilterPlugin = &VolumeBinding{} +var _ framework.FilterPlugin = &VolumeBinding{} +var _ framework.ReservePlugin = &VolumeBinding{} +var _ framework.PreBindPlugin = &VolumeBinding{} +var _ framework.ScorePlugin = &VolumeBinding{} +var _ framework.EnqueueExtensions = &VolumeBinding{} + +// Name is the name of the plugin used in Registry and configurations. +const Name = names.VolumeBinding + +// Name returns name of the plugin. It is used in logs, etc. +func (pl *VolumeBinding) Name() string { + return Name +} + +// EventsToRegister returns the possible events that may make a Pod +// failed by this plugin schedulable. +func (pl *VolumeBinding) EventsToRegister() []framework.ClusterEvent { + events := []framework.ClusterEvent{ + // Pods may fail because of missing or mis-configured storage class + // (e.g., allowedTopologies, volumeBindingMode), and hence may become + // schedulable upon StorageClass Add or Update events. + {Resource: framework.StorageClass, ActionType: framework.Add | framework.Update}, + // We bind PVCs with PVs, so any changes may make the pods schedulable. + {Resource: framework.PersistentVolumeClaim, ActionType: framework.Add | framework.Update}, + {Resource: framework.PersistentVolume, ActionType: framework.Add | framework.Update}, + // Pods may fail to find available PVs because the node labels do not + // match the storage class's allowed topologies or PV's node affinity. + // A new or updated node may make pods schedulable. + {Resource: framework.Node, ActionType: framework.Add | framework.UpdateNodeLabel}, + // We rely on CSI node to translate in-tree PV to CSI. + {Resource: framework.CSINode, ActionType: framework.Add | framework.Update}, + // When CSIStorageCapacity is enabled, pods may become schedulable + // on CSI driver & storage capacity changes. + {Resource: framework.CSIDriver, ActionType: framework.Add | framework.Update}, + {Resource: framework.CSIStorageCapacity, ActionType: framework.Add | framework.Update}, + } + return events +} + +// podHasPVCs returns 2 values: +// - the first one to denote if the given "pod" has any PVC defined. +// - the second one to return any error if the requested PVC is illegal. +func (pl *VolumeBinding) podHasPVCs(pod *v1.Pod) (bool, error) { + hasPVC := false + for _, vol := range pod.Spec.Volumes { + var pvcName string + isEphemeral := false + switch { + case vol.PersistentVolumeClaim != nil: + pvcName = vol.PersistentVolumeClaim.ClaimName + case vol.Ephemeral != nil: + pvcName = ephemeral.VolumeClaimName(pod, &vol) + isEphemeral = true + default: + // Volume is not using a PVC, ignore + continue + } + hasPVC = true + pvc, err := pl.PVCLister.PersistentVolumeClaims(pod.Namespace).Get(pvcName) + if err != nil { + // The error usually has already enough context ("persistentvolumeclaim "myclaim" not found"), + // but we can do better for generic ephemeral inline volumes where that situation + // is normal directly after creating a pod. + if isEphemeral && apierrors.IsNotFound(err) { + err = fmt.Errorf("waiting for ephemeral volume controller to create the persistentvolumeclaim %q", pvcName) + } + return hasPVC, err + } + + if pvc.Status.Phase == v1.ClaimLost { + return hasPVC, fmt.Errorf("persistentvolumeclaim %q bound to non-existent persistentvolume %q", pvc.Name, pvc.Spec.VolumeName) + } + + if pvc.DeletionTimestamp != nil { + return hasPVC, fmt.Errorf("persistentvolumeclaim %q is being deleted", pvc.Name) + } + + if isEphemeral { + if err := ephemeral.VolumeIsForPod(pod, pvc); err != nil { + return hasPVC, err + } + } + } + return hasPVC, nil +} + +// PreFilter invoked at the prefilter extension point to check if pod has all +// immediate PVCs bound. If not all immediate PVCs are bound, an +// UnschedulableAndUnresolvable is returned. +func (pl *VolumeBinding) PreFilter(ctx context.Context, state *framework.CycleState, pod *v1.Pod) (*framework.PreFilterResult, *framework.Status) { + // If pod does not reference any PVC, we don't need to do anything. + if hasPVC, err := pl.podHasPVCs(pod); err != nil { + return nil, framework.NewStatus(framework.UnschedulableAndUnresolvable, err.Error()) + } else if !hasPVC { + state.Write(stateKey, &stateData{skip: true}) + return nil, nil + } + boundClaims, claimsToBind, unboundClaimsImmediate, err := pl.Binder.GetPodVolumes(pod) + if err != nil { + return nil, framework.AsStatus(err) + } + if len(unboundClaimsImmediate) > 0 { + // Return UnschedulableAndUnresolvable error if immediate claims are + // not bound. Pod will be moved to active/backoff queues once these + // claims are bound by PV controller. + status := framework.NewStatus(framework.UnschedulableAndUnresolvable) + status.AppendReason("pod has unbound immediate PersistentVolumeClaims") + return nil, status + } + state.Write(stateKey, &stateData{boundClaims: boundClaims, claimsToBind: claimsToBind, podVolumesByNode: make(map[string]*PodVolumes)}) + return nil, nil +} + +// PreFilterExtensions returns prefilter extensions, pod add and remove. +func (pl *VolumeBinding) PreFilterExtensions() framework.PreFilterExtensions { + return nil +} + +func getStateData(cs *framework.CycleState) (*stateData, error) { + state, err := cs.Read(stateKey) + if err != nil { + return nil, err + } + s, ok := state.(*stateData) + if !ok { + return nil, errors.New("unable to convert state into stateData") + } + return s, nil +} + +// Filter invoked at the filter extension point. +// It evaluates if a pod can fit due to the volumes it requests, +// for both bound and unbound PVCs. +// +// For PVCs that are bound, then it checks that the corresponding PV's node affinity is +// satisfied by the given node. +// +// For PVCs that are unbound, it tries to find available PVs that can satisfy the PVC requirements +// and that the PV node affinity is satisfied by the given node. +// +// If storage capacity tracking is enabled, then enough space has to be available +// for the node and volumes that still need to be created. +// +// The predicate returns true if all bound PVCs have compatible PVs with the node, and if all unbound +// PVCs can be matched with an available and node-compatible PV. +func (pl *VolumeBinding) Filter(ctx context.Context, cs *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status { + node := nodeInfo.Node() + if node == nil { + return framework.NewStatus(framework.Error, "node not found") + } + + state, err := getStateData(cs) + if err != nil { + return framework.AsStatus(err) + } + + if state.skip { + return nil + } + + podVolumes, reasons, err := pl.Binder.FindPodVolumes(pod, state.boundClaims, state.claimsToBind, node) + + if err != nil { + return framework.AsStatus(err) + } + + if len(reasons) > 0 { + status := framework.NewStatus(framework.UnschedulableAndUnresolvable) + for _, reason := range reasons { + status.AppendReason(string(reason)) + } + return status + } + + // multiple goroutines call `Filter` on different nodes simultaneously and the `CycleState` may be duplicated, so we must use a local lock here + state.Lock() + state.podVolumesByNode[node.Name] = podVolumes + state.Unlock() + return nil +} + +// Score invoked at the score extension point. +func (pl *VolumeBinding) Score(ctx context.Context, cs *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) { + if pl.scorer == nil { + return 0, nil + } + state, err := getStateData(cs) + if err != nil { + return 0, framework.AsStatus(err) + } + podVolumes, ok := state.podVolumesByNode[nodeName] + if !ok { + return 0, nil + } + // group by storage class + classResources := make(classResourceMap) + for _, staticBinding := range podVolumes.StaticBindings { + class := staticBinding.StorageClassName() + storageResource := staticBinding.StorageResource() + if _, ok := classResources[class]; !ok { + classResources[class] = &StorageResource{ + Requested: 0, + Capacity: 0, + } + } + classResources[class].Requested += storageResource.Requested + classResources[class].Capacity += storageResource.Capacity + } + return pl.scorer(classResources), nil +} + +// ScoreExtensions of the Score plugin. +func (pl *VolumeBinding) ScoreExtensions() framework.ScoreExtensions { + return nil +} + +// Reserve reserves volumes of pod and saves binding status in cycle state. +func (pl *VolumeBinding) Reserve(ctx context.Context, cs *framework.CycleState, pod *v1.Pod, nodeName string) *framework.Status { + state, err := getStateData(cs) + if err != nil { + return framework.AsStatus(err) + } + // we don't need to hold the lock as only one node will be reserved for the given pod + podVolumes, ok := state.podVolumesByNode[nodeName] + if ok { + allBound, err := pl.Binder.AssumePodVolumes(pod, nodeName, podVolumes) + if err != nil { + return framework.AsStatus(err) + } + state.allBound = allBound + } else { + // may not exist if the pod does not reference any PVC + state.allBound = true + } + return nil +} + +// PreBind will make the API update with the assumed bindings and wait until +// the PV controller has completely finished the binding operation. +// +// If binding errors, times out or gets undone, then an error will be returned to +// retry scheduling. +func (pl *VolumeBinding) PreBind(ctx context.Context, cs *framework.CycleState, pod *v1.Pod, nodeName string) *framework.Status { + s, err := getStateData(cs) + if err != nil { + return framework.AsStatus(err) + } + if s.allBound { + // no need to bind volumes + return nil + } + // we don't need to hold the lock as only one node will be pre-bound for the given pod + podVolumes, ok := s.podVolumesByNode[nodeName] + if !ok { + return framework.AsStatus(fmt.Errorf("no pod volumes found for node %q", nodeName)) + } + klog.V(5).InfoS("Trying to bind volumes for pod", "pod", klog.KObj(pod)) + err = pl.Binder.BindPodVolumes(ctx, pod, podVolumes) + if err != nil { + klog.V(1).InfoS("Failed to bind volumes for pod", "pod", klog.KObj(pod), "err", err) + return framework.AsStatus(err) + } + klog.V(5).InfoS("Success binding volumes for pod", "pod", klog.KObj(pod)) + return nil +} + +// Unreserve clears assumed PV and PVC cache. +// It's idempotent, and does nothing if no cache found for the given pod. +func (pl *VolumeBinding) Unreserve(ctx context.Context, cs *framework.CycleState, pod *v1.Pod, nodeName string) { + s, err := getStateData(cs) + if err != nil { + return + } + // we don't need to hold the lock as only one node may be unreserved + podVolumes, ok := s.podVolumesByNode[nodeName] + if !ok { + return + } + pl.Binder.RevertAssumedPodVolumes(podVolumes) +} + +// New initializes a new plugin and returns it. +func New(plArgs runtime.Object, fh framework.Handle, fts feature.Features) (framework.Plugin, error) { + args, ok := plArgs.(*config.VolumeBindingArgs) + if !ok { + return nil, fmt.Errorf("want args to be of type VolumeBindingArgs, got %T", plArgs) + } + if err := validation.ValidateVolumeBindingArgsWithOptions(nil, args, validation.VolumeBindingArgsValidationOptions{ + AllowVolumeCapacityPriority: fts.EnableVolumeCapacityPriority, + }); err != nil { + return nil, err + } + podInformer := fh.SharedInformerFactory().Core().V1().Pods() + nodeInformer := fh.SharedInformerFactory().Core().V1().Nodes() + pvcInformer := fh.SharedInformerFactory().Core().V1().PersistentVolumeClaims() + pvInformer := fh.SharedInformerFactory().Core().V1().PersistentVolumes() + storageClassInformer := fh.SharedInformerFactory().Storage().V1().StorageClasses() + csiNodeInformer := fh.SharedInformerFactory().Storage().V1().CSINodes() + capacityCheck := CapacityCheck{ + CSIDriverInformer: fh.SharedInformerFactory().Storage().V1().CSIDrivers(), + CSIStorageCapacityInformer: fh.SharedInformerFactory().Storage().V1().CSIStorageCapacities(), + } + binder := NewVolumeBinder(fh.ClientSet(), podInformer, nodeInformer, csiNodeInformer, pvcInformer, pvInformer, storageClassInformer, capacityCheck, time.Duration(args.BindTimeoutSeconds)*time.Second) + + // build score function + var scorer volumeCapacityScorer + if fts.EnableVolumeCapacityPriority { + shape := make(helper.FunctionShape, 0, len(args.Shape)) + for _, point := range args.Shape { + shape = append(shape, helper.FunctionShapePoint{ + Utilization: int64(point.Utilization), + Score: int64(point.Score) * (framework.MaxNodeScore / config.MaxCustomPriorityScore), + }) + } + scorer = buildScorerFunction(shape) + } + return &VolumeBinding{ + Binder: binder, + PVCLister: pvcInformer.Lister(), + scorer: scorer, + fts: fts, + }, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumerestrictions/volume_restrictions.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumerestrictions/volume_restrictions.go new file mode 100644 index 000000000..6e7e8ed97 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumerestrictions/volume_restrictions.go @@ -0,0 +1,215 @@ +/* +Copyright 2019 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 volumerestrictions + +import ( + "context" + + v1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/sets" + corelisters "k8s.io/client-go/listers/core/v1" + v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" +) + +// VolumeRestrictions is a plugin that checks volume restrictions. +type VolumeRestrictions struct { + pvcLister corelisters.PersistentVolumeClaimLister + sharedLister framework.SharedLister + enableReadWriteOncePod bool +} + +var _ framework.PreFilterPlugin = &VolumeRestrictions{} +var _ framework.FilterPlugin = &VolumeRestrictions{} +var _ framework.EnqueueExtensions = &VolumeRestrictions{} + +// Name is the name of the plugin used in the plugin registry and configurations. +const Name = names.VolumeRestrictions + +const ( + // ErrReasonDiskConflict is used for NoDiskConflict predicate error. + ErrReasonDiskConflict = "node(s) had no available disk" + // ErrReasonReadWriteOncePodConflict is used when a pod is found using the same PVC with the ReadWriteOncePod access mode. + ErrReasonReadWriteOncePodConflict = "node has pod using PersistentVolumeClaim with the same name and ReadWriteOncePod access mode" +) + +// Name returns name of the plugin. It is used in logs, etc. +func (pl *VolumeRestrictions) Name() string { + return Name +} + +func isVolumeConflict(volume *v1.Volume, pod *v1.Pod) bool { + for _, existingVolume := range pod.Spec.Volumes { + // Same GCE disk mounted by multiple pods conflicts unless all pods mount it read-only. + if volume.GCEPersistentDisk != nil && existingVolume.GCEPersistentDisk != nil { + disk, existingDisk := volume.GCEPersistentDisk, existingVolume.GCEPersistentDisk + if disk.PDName == existingDisk.PDName && !(disk.ReadOnly && existingDisk.ReadOnly) { + return true + } + } + + if volume.AWSElasticBlockStore != nil && existingVolume.AWSElasticBlockStore != nil { + if volume.AWSElasticBlockStore.VolumeID == existingVolume.AWSElasticBlockStore.VolumeID { + return true + } + } + + if volume.ISCSI != nil && existingVolume.ISCSI != nil { + iqn := volume.ISCSI.IQN + eiqn := existingVolume.ISCSI.IQN + // two ISCSI volumes are same, if they share the same iqn. As iscsi volumes are of type + // RWO or ROX, we could permit only one RW mount. Same iscsi volume mounted by multiple Pods + // conflict unless all other pods mount as read only. + if iqn == eiqn && !(volume.ISCSI.ReadOnly && existingVolume.ISCSI.ReadOnly) { + return true + } + } + + if volume.RBD != nil && existingVolume.RBD != nil { + mon, pool, image := volume.RBD.CephMonitors, volume.RBD.RBDPool, volume.RBD.RBDImage + emon, epool, eimage := existingVolume.RBD.CephMonitors, existingVolume.RBD.RBDPool, existingVolume.RBD.RBDImage + // two RBDs images are the same if they share the same Ceph monitor, are in the same RADOS Pool, and have the same image name + // only one read-write mount is permitted for the same RBD image. + // same RBD image mounted by multiple Pods conflicts unless all Pods mount the image read-only + if haveOverlap(mon, emon) && pool == epool && image == eimage && !(volume.RBD.ReadOnly && existingVolume.RBD.ReadOnly) { + return true + } + } + } + + return false +} + +// haveOverlap searches two arrays and returns true if they have at least one common element; returns false otherwise. +func haveOverlap(a1, a2 []string) bool { + if len(a1) > len(a2) { + a1, a2 = a2, a1 + } + m := make(sets.String) + + for _, val := range a1 { + m.Insert(val) + } + for _, val := range a2 { + if _, ok := m[val]; ok { + return true + } + } + + return false +} + +func (pl *VolumeRestrictions) PreFilter(ctx context.Context, cycleState *framework.CycleState, pod *v1.Pod) (*framework.PreFilterResult, *framework.Status) { + if pl.enableReadWriteOncePod { + return nil, pl.isReadWriteOncePodAccessModeConflict(ctx, pod) + } + return nil, framework.NewStatus(framework.Success) +} + +// isReadWriteOncePodAccessModeConflict checks if a pod uses a PVC with the ReadWriteOncePod access mode. +// This access mode restricts volume access to a single pod on a single node. Since only a single pod can +// use a ReadWriteOncePod PVC, mark any other pods attempting to use this PVC as UnschedulableAndUnresolvable. +// TODO(#103132): Mark pod as Unschedulable and add preemption logic. +func (pl *VolumeRestrictions) isReadWriteOncePodAccessModeConflict(ctx context.Context, pod *v1.Pod) *framework.Status { + for _, volume := range pod.Spec.Volumes { + if volume.PersistentVolumeClaim == nil { + continue + } + + pvc, err := pl.pvcLister.PersistentVolumeClaims(pod.Namespace).Get(volume.PersistentVolumeClaim.ClaimName) + if err != nil { + if apierrors.IsNotFound(err) { + return framework.NewStatus(framework.UnschedulableAndUnresolvable, err.Error()) + } + return framework.AsStatus(err) + } + + if !v1helper.ContainsAccessMode(pvc.Spec.AccessModes, v1.ReadWriteOncePod) { + continue + } + + key := framework.GetNamespacedName(pod.Namespace, volume.PersistentVolumeClaim.ClaimName) + if pl.sharedLister.StorageInfos().IsPVCUsedByPods(key) { + return framework.NewStatus(framework.UnschedulableAndUnresolvable, ErrReasonReadWriteOncePodConflict) + } + } + + return nil +} + +func (pl *VolumeRestrictions) PreFilterExtensions() framework.PreFilterExtensions { + return nil +} + +// Filter invoked at the filter extension point. +// It evaluates if a pod can fit due to the volumes it requests, and those that +// are already mounted. If there is already a volume mounted on that node, another pod that uses the same volume +// can't be scheduled there. +// This is GCE, Amazon EBS, ISCSI and Ceph RBD specific for now: +// - GCE PD allows multiple mounts as long as they're all read-only +// - AWS EBS forbids any two pods mounting the same volume ID +// - Ceph RBD forbids if any two pods share at least same monitor, and match pool and image, and the image is read-only +// - ISCSI forbids if any two pods share at least same IQN and ISCSI volume is read-only +func (pl *VolumeRestrictions) Filter(ctx context.Context, _ *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status { + for i := range pod.Spec.Volumes { + v := &pod.Spec.Volumes[i] + // fast path if there is no conflict checking targets. + if v.GCEPersistentDisk == nil && v.AWSElasticBlockStore == nil && v.RBD == nil && v.ISCSI == nil { + continue + } + + for _, ev := range nodeInfo.Pods { + if isVolumeConflict(v, ev.Pod) { + return framework.NewStatus(framework.Unschedulable, ErrReasonDiskConflict) + } + } + } + return nil +} + +// EventsToRegister returns the possible events that may make a Pod +// failed by this plugin schedulable. +func (pl *VolumeRestrictions) EventsToRegister() []framework.ClusterEvent { + return []framework.ClusterEvent{ + // Pods may fail to schedule because of volumes conflicting with other pods on same node. + // Once running pods are deleted and volumes have been released, the unschedulable pod will be schedulable. + // Due to immutable fields `spec.volumes`, pod update events are ignored. + {Resource: framework.Pod, ActionType: framework.Delete}, + // A new Node may make a pod schedulable. + {Resource: framework.Node, ActionType: framework.Add}, + // Pods may fail to schedule because the PVC it uses has not yet been created. + // This PVC is required to exist to check its access modes. + {Resource: framework.PersistentVolumeClaim, ActionType: framework.Add | framework.Update}, + } +} + +// New initializes a new plugin and returns it. +func New(_ runtime.Object, handle framework.Handle, fts feature.Features) (framework.Plugin, error) { + informerFactory := handle.SharedInformerFactory() + pvcLister := informerFactory.Core().V1().PersistentVolumeClaims().Lister() + sharedLister := handle.SnapshotSharedLister() + + return &VolumeRestrictions{ + pvcLister: pvcLister, + sharedLister: sharedLister, + enableReadWriteOncePod: fts.EnableReadWriteOncePod, + }, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumezone/volume_zone.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumezone/volume_zone.go new file mode 100644 index 000000000..1bfab85fc --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumezone/volume_zone.go @@ -0,0 +1,206 @@ +/* +Copyright 2019 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 volumezone + +import ( + "context" + "fmt" + + v1 "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/sets" + corelisters "k8s.io/client-go/listers/core/v1" + storagelisters "k8s.io/client-go/listers/storage/v1" + volumehelpers "k8s.io/cloud-provider/volume/helpers" + storagehelpers "k8s.io/component-helpers/storage/volume" + "k8s.io/klog/v2" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" +) + +// VolumeZone is a plugin that checks volume zone. +type VolumeZone struct { + pvLister corelisters.PersistentVolumeLister + pvcLister corelisters.PersistentVolumeClaimLister + scLister storagelisters.StorageClassLister +} + +var _ framework.FilterPlugin = &VolumeZone{} +var _ framework.EnqueueExtensions = &VolumeZone{} + +const ( + // Name is the name of the plugin used in the plugin registry and configurations. + Name = names.VolumeZone + + // ErrReasonConflict is used for NoVolumeZoneConflict predicate error. + ErrReasonConflict = "node(s) had no available volume zone" +) + +var volumeZoneLabels = sets.NewString( + v1.LabelFailureDomainBetaZone, + v1.LabelFailureDomainBetaRegion, + v1.LabelTopologyZone, + v1.LabelTopologyRegion, +) + +// Name returns name of the plugin. It is used in logs, etc. +func (pl *VolumeZone) Name() string { + return Name +} + +// Filter invoked at the filter extension point. +// +// It evaluates if a pod can fit due to the volumes it requests, given +// that some volumes may have zone scheduling constraints. The requirement is that any +// volume zone-labels must match the equivalent zone-labels on the node. It is OK for +// the node to have more zone-label constraints (for example, a hypothetical replicated +// volume might allow region-wide access) +// +// Currently this is only supported with PersistentVolumeClaims, and looks to the labels +// only on the bound PersistentVolume. +// +// Working with volumes declared inline in the pod specification (i.e. not +// using a PersistentVolume) is likely to be harder, as it would require +// determining the zone of a volume during scheduling, and that is likely to +// require calling out to the cloud provider. It seems that we are moving away +// from inline volume declarations anyway. +func (pl *VolumeZone) Filter(ctx context.Context, _ *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status { + // If a pod doesn't have any volume attached to it, the predicate will always be true. + // Thus we make a fast path for it, to avoid unnecessary computations in this case. + if len(pod.Spec.Volumes) == 0 { + return nil + } + node := nodeInfo.Node() + if node == nil { + return framework.NewStatus(framework.Error, "node not found") + } + nodeConstraints := make(map[string]string) + for k, v := range node.ObjectMeta.Labels { + if !volumeZoneLabels.Has(k) { + continue + } + nodeConstraints[k] = v + } + if len(nodeConstraints) == 0 { + // The node has no zone constraints, so we're OK to schedule. + // In practice, when using zones, all nodes must be labeled with zone labels. + // We want to fast-path this case though. + return nil + } + + for i := range pod.Spec.Volumes { + volume := pod.Spec.Volumes[i] + if volume.PersistentVolumeClaim == nil { + continue + } + pvcName := volume.PersistentVolumeClaim.ClaimName + if pvcName == "" { + return framework.NewStatus(framework.UnschedulableAndUnresolvable, "PersistentVolumeClaim had no name") + } + pvc, err := pl.pvcLister.PersistentVolumeClaims(pod.Namespace).Get(pvcName) + if s := getErrorAsStatus(err); !s.IsSuccess() { + return s + } + + pvName := pvc.Spec.VolumeName + if pvName == "" { + scName := storagehelpers.GetPersistentVolumeClaimClass(pvc) + if len(scName) == 0 { + return framework.NewStatus(framework.UnschedulableAndUnresolvable, "PersistentVolumeClaim had no pv name and storageClass name") + } + + class, err := pl.scLister.Get(scName) + if s := getErrorAsStatus(err); !s.IsSuccess() { + return s + } + if class.VolumeBindingMode == nil { + return framework.NewStatus(framework.UnschedulableAndUnresolvable, fmt.Sprintf("VolumeBindingMode not set for StorageClass %q", scName)) + } + if *class.VolumeBindingMode == storage.VolumeBindingWaitForFirstConsumer { + // Skip unbound volumes + continue + } + + return framework.NewStatus(framework.UnschedulableAndUnresolvable, "PersistentVolume had no name") + } + + pv, err := pl.pvLister.Get(pvName) + if s := getErrorAsStatus(err); !s.IsSuccess() { + return s + } + + for k, v := range pv.ObjectMeta.Labels { + if !volumeZoneLabels.Has(k) { + continue + } + nodeV := nodeConstraints[k] + volumeVSet, err := volumehelpers.LabelZonesToSet(v) + if err != nil { + klog.InfoS("Failed to parse label, ignoring the label", "label", fmt.Sprintf("%s:%s", k, v), "err", err) + continue + } + + if !volumeVSet.Has(nodeV) { + klog.V(10).InfoS("Won't schedule pod onto node due to volume (mismatch on label key)", "pod", klog.KObj(pod), "node", klog.KObj(node), "PV", klog.KRef("", pvName), "PVLabelKey", k) + return framework.NewStatus(framework.UnschedulableAndUnresolvable, ErrReasonConflict) + } + } + } + return nil +} + +func getErrorAsStatus(err error) *framework.Status { + if err != nil { + if errors.IsNotFound(err) { + return framework.NewStatus(framework.UnschedulableAndUnresolvable, err.Error()) + } + return framework.AsStatus(err) + } + return nil +} + +// EventsToRegister returns the possible events that may make a Pod +// failed by this plugin schedulable. +func (pl *VolumeZone) EventsToRegister() []framework.ClusterEvent { + return []framework.ClusterEvent{ + // New storageClass with bind mode `VolumeBindingWaitForFirstConsumer` will make a pod schedulable. + // Due to immutable field `storageClass.volumeBindingMode`, storageClass update events are ignored. + {Resource: framework.StorageClass, ActionType: framework.Add}, + // A new node or updating a node's volume zone labels may make a pod schedulable. + {Resource: framework.Node, ActionType: framework.Add | framework.UpdateNodeLabel}, + // A new pvc may make a pod schedulable. + // Due to fields are immutable except `spec.resources`, pvc update events are ignored. + {Resource: framework.PersistentVolumeClaim, ActionType: framework.Add}, + // A new pv or updating a pv's volume zone labels may make a pod schedulable. + {Resource: framework.PersistentVolume, ActionType: framework.Add | framework.Update}, + } +} + +// New initializes a new plugin and returns it. +func New(_ runtime.Object, handle framework.Handle) (framework.Plugin, error) { + informerFactory := handle.SharedInformerFactory() + pvLister := informerFactory.Core().V1().PersistentVolumes().Lister() + pvcLister := informerFactory.Core().V1().PersistentVolumeClaims().Lister() + scLister := informerFactory.Storage().V1().StorageClasses().Lister() + return &VolumeZone{ + pvLister, + pvcLister, + scLister, + }, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/preemption/preemption.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/preemption/preemption.go new file mode 100644 index 000000000..26a5c2054 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/preemption/preemption.go @@ -0,0 +1,635 @@ +/* +Copyright 2021 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 preemption + +import ( + "context" + "errors" + "fmt" + "math" + "sync" + "sync/atomic" + + v1 "k8s.io/api/core/v1" + policy "k8s.io/api/policy/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apiserver/pkg/util/feature" + corev1apply "k8s.io/client-go/applyconfigurations/core/v1" + corelisters "k8s.io/client-go/listers/core/v1" + policylisters "k8s.io/client-go/listers/policy/v1" + corev1helpers "k8s.io/component-helpers/scheduling/corev1" + "k8s.io/klog/v2" + extenderv1 "k8s.io/kube-scheduler/extender/v1" + "k8s.io/kubernetes/pkg/features" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/parallelize" + "k8s.io/kubernetes/pkg/scheduler/metrics" + "k8s.io/kubernetes/pkg/scheduler/util" +) + +const ( + // fieldManager used to add pod disruption condition to the victim pods + fieldManager = "KubeScheduler" +) + +// Candidate represents a nominated node on which the preemptor can be scheduled, +// along with the list of victims that should be evicted for the preemptor to fit the node. +type Candidate interface { + // Victims wraps a list of to-be-preempted Pods and the number of PDB violation. + Victims() *extenderv1.Victims + // Name returns the target node name where the preemptor gets nominated to run. + Name() string +} + +type candidate struct { + victims *extenderv1.Victims + name string +} + +// Victims returns s.victims. +func (s *candidate) Victims() *extenderv1.Victims { + return s.victims +} + +// Name returns s.name. +func (s *candidate) Name() string { + return s.name +} + +type candidateList struct { + idx int32 + items []Candidate +} + +func newCandidateList(size int32) *candidateList { + return &candidateList{idx: -1, items: make([]Candidate, size)} +} + +// add adds a new candidate to the internal array atomically. +func (cl *candidateList) add(c *candidate) { + if idx := atomic.AddInt32(&cl.idx, 1); idx < int32(len(cl.items)) { + cl.items[idx] = c + } +} + +// size returns the number of candidate stored. Note that some add() operations +// might still be executing when this is called, so care must be taken to +// ensure that all add() operations complete before accessing the elements of +// the list. +func (cl *candidateList) size() int32 { + n := atomic.LoadInt32(&cl.idx) + 1 + if n >= int32(len(cl.items)) { + n = int32(len(cl.items)) + } + return n +} + +// get returns the internal candidate array. This function is NOT atomic and +// assumes that all add() operations have been completed. +func (cl *candidateList) get() []Candidate { + return cl.items[:cl.size()] +} + +// Interface is expected to be implemented by different preemption plugins as all those member +// methods might have different behavior compared with the default preemption. +type Interface interface { + // GetOffsetAndNumCandidates chooses a random offset and calculates the number of candidates that should be + // shortlisted for dry running preemption. + GetOffsetAndNumCandidates(nodes int32) (int32, int32) + // CandidatesToVictimsMap builds a map from the target node to a list of to-be-preempted Pods and the number of PDB violation. + CandidatesToVictimsMap(candidates []Candidate) map[string]*extenderv1.Victims + // PodEligibleToPreemptOthers returns one bool and one string. The bool indicates whether this pod should be considered for + // preempting other pods or not. The string includes the reason if this pod isn't eligible. + PodEligibleToPreemptOthers(pod *v1.Pod, nominatedNodeStatus *framework.Status) (bool, string) + // SelectVictimsOnNode finds minimum set of pods on the given node that should be preempted in order to make enough room + // for "pod" to be scheduled. + // Note that both `state` and `nodeInfo` are deep copied. + SelectVictimsOnNode(ctx context.Context, state *framework.CycleState, + pod *v1.Pod, nodeInfo *framework.NodeInfo, pdbs []*policy.PodDisruptionBudget) ([]*v1.Pod, int, *framework.Status) +} + +type Evaluator struct { + PluginName string + Handler framework.Handle + PodLister corelisters.PodLister + PdbLister policylisters.PodDisruptionBudgetLister + State *framework.CycleState + Interface +} + +// Preempt returns a PostFilterResult carrying suggested nominatedNodeName, along with a Status. +// The semantics of returned varies on different scenarios: +// +// - . This denotes it's a transient/rare error that may be self-healed in future cycles. +// +// - . This status is mostly as expected like the preemptor is waiting for the +// victims to be fully terminated. +// +// - In both cases above, a nil PostFilterResult is returned to keep the pod's nominatedNodeName unchanged. +// +// - . It indicates the pod cannot be scheduled even with preemption. +// In this case, a non-nil PostFilterResult is returned and result.NominatingMode instructs how to deal with +// the nominatedNodeName. +// +// - . It's the regular happy path +// and the non-empty nominatedNodeName will be applied to the preemptor pod. +func (ev *Evaluator) Preempt(ctx context.Context, pod *v1.Pod, m framework.NodeToStatusMap) (*framework.PostFilterResult, *framework.Status) { + // 0) Fetch the latest version of . + // It's safe to directly fetch pod here. Because the informer cache has already been + // initialized when creating the Scheduler obj. + // However, tests may need to manually initialize the shared pod informer. + podNamespace, podName := pod.Namespace, pod.Name + pod, err := ev.PodLister.Pods(pod.Namespace).Get(pod.Name) + if err != nil { + klog.ErrorS(err, "Getting the updated preemptor pod object", "pod", klog.KRef(podNamespace, podName)) + return nil, framework.AsStatus(err) + } + + // 1) Ensure the preemptor is eligible to preempt other pods. + if ok, msg := ev.PodEligibleToPreemptOthers(pod, m[pod.Status.NominatedNodeName]); !ok { + klog.V(5).InfoS("Pod is not eligible for preemption", "pod", klog.KObj(pod), "reason", msg) + return nil, framework.NewStatus(framework.Unschedulable, msg) + } + + // 2) Find all preemption candidates. + candidates, nodeToStatusMap, err := ev.findCandidates(ctx, pod, m) + if err != nil && len(candidates) == 0 { + return nil, framework.AsStatus(err) + } + + // Return a FitError only when there are no candidates that fit the pod. + if len(candidates) == 0 { + fitError := &framework.FitError{ + Pod: pod, + NumAllNodes: len(nodeToStatusMap), + Diagnosis: framework.Diagnosis{ + NodeToStatusMap: nodeToStatusMap, + // Leave FailedPlugins as nil as it won't be used on moving Pods. + }, + } + // Specify nominatedNodeName to clear the pod's nominatedNodeName status, if applicable. + return framework.NewPostFilterResultWithNominatedNode(""), framework.NewStatus(framework.Unschedulable, fitError.Error()) + } + + // 3) Interact with registered Extenders to filter out some candidates if needed. + candidates, status := ev.callExtenders(pod, candidates) + if !status.IsSuccess() { + return nil, status + } + + // 4) Find the best candidate. + bestCandidate := ev.SelectCandidate(candidates) + if bestCandidate == nil || len(bestCandidate.Name()) == 0 { + return nil, framework.NewStatus(framework.Unschedulable, "no candidate node for preemption") + } + + // 5) Perform preparation work before nominating the selected candidate. + if status := ev.prepareCandidate(ctx, bestCandidate, pod, ev.PluginName); !status.IsSuccess() { + return nil, status + } + + return framework.NewPostFilterResultWithNominatedNode(bestCandidate.Name()), framework.NewStatus(framework.Success) +} + +// FindCandidates calculates a slice of preemption candidates. +// Each candidate is executable to make the given schedulable. +func (ev *Evaluator) findCandidates(ctx context.Context, pod *v1.Pod, m framework.NodeToStatusMap) ([]Candidate, framework.NodeToStatusMap, error) { + allNodes, err := ev.Handler.SnapshotSharedLister().NodeInfos().List() + if err != nil { + return nil, nil, err + } + if len(allNodes) == 0 { + return nil, nil, errors.New("no nodes available") + } + potentialNodes, unschedulableNodeStatus := nodesWherePreemptionMightHelp(allNodes, m) + if len(potentialNodes) == 0 { + klog.V(3).InfoS("Preemption will not help schedule pod on any node", "pod", klog.KObj(pod)) + // In this case, we should clean-up any existing nominated node name of the pod. + if err := util.ClearNominatedNodeName(ctx, ev.Handler.ClientSet(), pod); err != nil { + klog.ErrorS(err, "Cannot clear 'NominatedNodeName' field of pod", "pod", klog.KObj(pod)) + // We do not return as this error is not critical. + } + return nil, unschedulableNodeStatus, nil + } + + pdbs, err := getPodDisruptionBudgets(ev.PdbLister) + if err != nil { + return nil, nil, err + } + + offset, numCandidates := ev.GetOffsetAndNumCandidates(int32(len(potentialNodes))) + if klogV := klog.V(5); klogV.Enabled() { + var sample []string + for i := offset; i < offset+10 && i < int32(len(potentialNodes)); i++ { + sample = append(sample, potentialNodes[i].Node().Name) + } + klogV.InfoS("Selecting candidates from a pool of nodes", "potentialNodesCount", len(potentialNodes), "offset", offset, "sampleLength", len(sample), "sample", sample, "candidates", numCandidates) + } + candidates, nodeStatuses, err := ev.DryRunPreemption(ctx, pod, potentialNodes, pdbs, offset, numCandidates) + for node, nodeStatus := range unschedulableNodeStatus { + nodeStatuses[node] = nodeStatus + } + return candidates, nodeStatuses, err +} + +// callExtenders calls given to select the list of feasible candidates. +// We will only check with extenders that support preemption. +// Extenders which do not support preemption may later prevent preemptor from being scheduled on the nominated +// node. In that case, scheduler will find a different host for the preemptor in subsequent scheduling cycles. +func (ev *Evaluator) callExtenders(pod *v1.Pod, candidates []Candidate) ([]Candidate, *framework.Status) { + extenders := ev.Handler.Extenders() + nodeLister := ev.Handler.SnapshotSharedLister().NodeInfos() + if len(extenders) == 0 { + return candidates, nil + } + + // Migrate candidate slice to victimsMap to adapt to the Extender interface. + // It's only applicable for candidate slice that have unique nominated node name. + victimsMap := ev.CandidatesToVictimsMap(candidates) + if len(victimsMap) == 0 { + return candidates, nil + } + for _, extender := range extenders { + if !extender.SupportsPreemption() || !extender.IsInterested(pod) { + continue + } + nodeNameToVictims, err := extender.ProcessPreemption(pod, victimsMap, nodeLister) + if err != nil { + if extender.IsIgnorable() { + klog.InfoS("Skipping extender as it returned error and has ignorable flag set", + "extender", extender, "err", err) + continue + } + return nil, framework.AsStatus(err) + } + // Check if the returned victims are valid. + for nodeName, victims := range nodeNameToVictims { + if victims == nil || len(victims.Pods) == 0 { + if extender.IsIgnorable() { + delete(nodeNameToVictims, nodeName) + klog.InfoS("Ignoring node without victims", "node", klog.KRef("", nodeName)) + continue + } + return nil, framework.AsStatus(fmt.Errorf("expected at least one victim pod on node %q", nodeName)) + } + } + + // Replace victimsMap with new result after preemption. So the + // rest of extenders can continue use it as parameter. + victimsMap = nodeNameToVictims + + // If node list becomes empty, no preemption can happen regardless of other extenders. + if len(victimsMap) == 0 { + break + } + } + + var newCandidates []Candidate + for nodeName := range victimsMap { + newCandidates = append(newCandidates, &candidate{ + victims: victimsMap[nodeName], + name: nodeName, + }) + } + return newCandidates, nil +} + +// SelectCandidate chooses the best-fit candidate from given and return it. +// NOTE: This method is exported for easier testing in default preemption. +func (ev *Evaluator) SelectCandidate(candidates []Candidate) Candidate { + if len(candidates) == 0 { + return nil + } + if len(candidates) == 1 { + return candidates[0] + } + + victimsMap := ev.CandidatesToVictimsMap(candidates) + candidateNode := pickOneNodeForPreemption(victimsMap) + + // Same as candidatesToVictimsMap, this logic is not applicable for out-of-tree + // preemption plugins that exercise different candidates on the same nominated node. + if victims := victimsMap[candidateNode]; victims != nil { + return &candidate{ + victims: victims, + name: candidateNode, + } + } + + // We shouldn't reach here. + klog.ErrorS(errors.New("no candidate selected"), "Should not reach here", "candidates", candidates) + // To not break the whole flow, return the first candidate. + return candidates[0] +} + +// prepareCandidate does some preparation work before nominating the selected candidate: +// - Evict the victim pods +// - Reject the victim pods if they are in waitingPod map +// - Clear the low-priority pods' nominatedNodeName status if needed +func (ev *Evaluator) prepareCandidate(ctx context.Context, c Candidate, pod *v1.Pod, pluginName string) *framework.Status { + fh := ev.Handler + cs := ev.Handler.ClientSet() + + ctx, cancel := context.WithCancel(ctx) + defer cancel() + errCh := parallelize.NewErrorChannel() + preemptPod := func(index int) { + victim := c.Victims().Pods[index] + // If the victim is a WaitingPod, send a reject message to the PermitPlugin. + // Otherwise we should delete the victim. + if waitingPod := fh.GetWaitingPod(victim.UID); waitingPod != nil { + waitingPod.Reject(pluginName, "preempted") + } else { + if feature.DefaultFeatureGate.Enabled(features.PodDisruptionConditions) { + victimPodApply := corev1apply.Pod(victim.Name, victim.Namespace).WithStatus(corev1apply.PodStatus()) + victimPodApply.Status.WithConditions(corev1apply.PodCondition(). + WithType(v1.DisruptionTarget). + WithStatus(v1.ConditionTrue). + WithReason("PreemptionByKubeScheduler"). + WithMessage(fmt.Sprintf("%s: preempting to accommodate a higher priority pod", pod.Spec.SchedulerName)). + WithLastTransitionTime(metav1.Now()), + ) + + if _, err := cs.CoreV1().Pods(victim.Namespace).ApplyStatus(ctx, victimPodApply, metav1.ApplyOptions{FieldManager: fieldManager, Force: true}); err != nil { + klog.ErrorS(err, "Preparing pod preemption", "pod", klog.KObj(victim), "preemptor", klog.KObj(pod)) + errCh.SendErrorWithCancel(err, cancel) + return + } + } + if err := util.DeletePod(ctx, cs, victim); err != nil { + klog.ErrorS(err, "Preempting pod", "pod", klog.KObj(victim), "preemptor", klog.KObj(pod)) + errCh.SendErrorWithCancel(err, cancel) + return + } + } + fh.EventRecorder().Eventf(victim, pod, v1.EventTypeNormal, "Preempted", "Preempting", "Preempted by a pod on node %v", c.Name()) + } + + fh.Parallelizer().Until(ctx, len(c.Victims().Pods), preemptPod, ev.PluginName) + if err := errCh.ReceiveError(); err != nil { + return framework.AsStatus(err) + } + + metrics.PreemptionVictims.Observe(float64(len(c.Victims().Pods))) + + // Lower priority pods nominated to run on this node, may no longer fit on + // this node. So, we should remove their nomination. Removing their + // nomination updates these pods and moves them to the active queue. It + // lets scheduler find another place for them. + nominatedPods := getLowerPriorityNominatedPods(fh, pod, c.Name()) + if err := util.ClearNominatedNodeName(ctx, cs, nominatedPods...); err != nil { + klog.ErrorS(err, "Cannot clear 'NominatedNodeName' field") + // We do not return as this error is not critical. + } + + return nil +} + +// nodesWherePreemptionMightHelp returns a list of nodes with failed predicates +// that may be satisfied by removing pods from the node. +func nodesWherePreemptionMightHelp(nodes []*framework.NodeInfo, m framework.NodeToStatusMap) ([]*framework.NodeInfo, framework.NodeToStatusMap) { + var potentialNodes []*framework.NodeInfo + nodeStatuses := make(framework.NodeToStatusMap) + for _, node := range nodes { + name := node.Node().Name + // We rely on the status by each plugin - 'Unschedulable' or 'UnschedulableAndUnresolvable' + // to determine whether preemption may help or not on the node. + if m[name].Code() == framework.UnschedulableAndUnresolvable { + nodeStatuses[node.Node().Name] = framework.NewStatus(framework.UnschedulableAndUnresolvable, "Preemption is not helpful for scheduling") + continue + } + potentialNodes = append(potentialNodes, node) + } + return potentialNodes, nodeStatuses +} + +func getPodDisruptionBudgets(pdbLister policylisters.PodDisruptionBudgetLister) ([]*policy.PodDisruptionBudget, error) { + if pdbLister != nil { + return pdbLister.List(labels.Everything()) + } + return nil, nil +} + +// pickOneNodeForPreemption chooses one node among the given nodes. It assumes +// pods in each map entry are ordered by decreasing priority. +// It picks a node based on the following criteria: +// 1. A node with minimum number of PDB violations. +// 2. A node with minimum highest priority victim is picked. +// 3. Ties are broken by sum of priorities of all victims. +// 4. If there are still ties, node with the minimum number of victims is picked. +// 5. If there are still ties, node with the latest start time of all highest priority victims is picked. +// 6. If there are still ties, the first such node is picked (sort of randomly). +// The 'minNodes1' and 'minNodes2' are being reused here to save the memory +// allocation and garbage collection time. +func pickOneNodeForPreemption(nodesToVictims map[string]*extenderv1.Victims) string { + if len(nodesToVictims) == 0 { + return "" + } + minNumPDBViolatingPods := int64(math.MaxInt32) + var minNodes1 []string + lenNodes1 := 0 + for node, victims := range nodesToVictims { + numPDBViolatingPods := victims.NumPDBViolations + if numPDBViolatingPods < minNumPDBViolatingPods { + minNumPDBViolatingPods = numPDBViolatingPods + minNodes1 = nil + lenNodes1 = 0 + } + if numPDBViolatingPods == minNumPDBViolatingPods { + minNodes1 = append(minNodes1, node) + lenNodes1++ + } + } + if lenNodes1 == 1 { + return minNodes1[0] + } + + // There are more than one node with minimum number PDB violating pods. Find + // the one with minimum highest priority victim. + minHighestPriority := int32(math.MaxInt32) + var minNodes2 = make([]string, lenNodes1) + lenNodes2 := 0 + for i := 0; i < lenNodes1; i++ { + node := minNodes1[i] + victims := nodesToVictims[node] + // highestPodPriority is the highest priority among the victims on this node. + highestPodPriority := corev1helpers.PodPriority(victims.Pods[0]) + if highestPodPriority < minHighestPriority { + minHighestPriority = highestPodPriority + lenNodes2 = 0 + } + if highestPodPriority == minHighestPriority { + minNodes2[lenNodes2] = node + lenNodes2++ + } + } + if lenNodes2 == 1 { + return minNodes2[0] + } + + // There are a few nodes with minimum highest priority victim. Find the + // smallest sum of priorities. + minSumPriorities := int64(math.MaxInt64) + lenNodes1 = 0 + for i := 0; i < lenNodes2; i++ { + var sumPriorities int64 + node := minNodes2[i] + for _, pod := range nodesToVictims[node].Pods { + // We add MaxInt32+1 to all priorities to make all of them >= 0. This is + // needed so that a node with a few pods with negative priority is not + // picked over a node with a smaller number of pods with the same negative + // priority (and similar scenarios). + sumPriorities += int64(corev1helpers.PodPriority(pod)) + int64(math.MaxInt32+1) + } + if sumPriorities < minSumPriorities { + minSumPriorities = sumPriorities + lenNodes1 = 0 + } + if sumPriorities == minSumPriorities { + minNodes1[lenNodes1] = node + lenNodes1++ + } + } + if lenNodes1 == 1 { + return minNodes1[0] + } + + // There are a few nodes with minimum highest priority victim and sum of priorities. + // Find one with the minimum number of pods. + minNumPods := math.MaxInt32 + lenNodes2 = 0 + for i := 0; i < lenNodes1; i++ { + node := minNodes1[i] + numPods := len(nodesToVictims[node].Pods) + if numPods < minNumPods { + minNumPods = numPods + lenNodes2 = 0 + } + if numPods == minNumPods { + minNodes2[lenNodes2] = node + lenNodes2++ + } + } + if lenNodes2 == 1 { + return minNodes2[0] + } + + // There are a few nodes with same number of pods. + // Find the node that satisfies latest(earliestStartTime(all highest-priority pods on node)) + latestStartTime := util.GetEarliestPodStartTime(nodesToVictims[minNodes2[0]]) + if latestStartTime == nil { + // If the earliest start time of all pods on the 1st node is nil, just return it, + // which is not expected to happen. + klog.ErrorS(errors.New("earliestStartTime is nil for node"), "Should not reach here", "node", klog.KRef("", minNodes2[0])) + return minNodes2[0] + } + nodeToReturn := minNodes2[0] + for i := 1; i < lenNodes2; i++ { + node := minNodes2[i] + // Get earliest start time of all pods on the current node. + earliestStartTimeOnNode := util.GetEarliestPodStartTime(nodesToVictims[node]) + if earliestStartTimeOnNode == nil { + klog.ErrorS(errors.New("earliestStartTime is nil for node"), "Should not reach here", "node", klog.KRef("", node)) + continue + } + if earliestStartTimeOnNode.After(latestStartTime.Time) { + latestStartTime = earliestStartTimeOnNode + nodeToReturn = node + } + } + + return nodeToReturn +} + +// getLowerPriorityNominatedPods returns pods whose priority is smaller than the +// priority of the given "pod" and are nominated to run on the given node. +// Note: We could possibly check if the nominated lower priority pods still fit +// and return those that no longer fit, but that would require lots of +// manipulation of NodeInfo and PreFilter state per nominated pod. It may not be +// worth the complexity, especially because we generally expect to have a very +// small number of nominated pods per node. +func getLowerPriorityNominatedPods(pn framework.PodNominator, pod *v1.Pod, nodeName string) []*v1.Pod { + podInfos := pn.NominatedPodsForNode(nodeName) + + if len(podInfos) == 0 { + return nil + } + + var lowerPriorityPods []*v1.Pod + podPriority := corev1helpers.PodPriority(pod) + for _, pi := range podInfos { + if corev1helpers.PodPriority(pi.Pod) < podPriority { + lowerPriorityPods = append(lowerPriorityPods, pi.Pod) + } + } + return lowerPriorityPods +} + +// DryRunPreemption simulates Preemption logic on in parallel, +// returns preemption candidates and a map indicating filtered nodes statuses. +// The number of candidates depends on the constraints defined in the plugin's args. In the returned list of +// candidates, ones that do not violate PDB are preferred over ones that do. +// NOTE: This method is exported for easier testing in default preemption. +func (ev *Evaluator) DryRunPreemption(ctx context.Context, pod *v1.Pod, potentialNodes []*framework.NodeInfo, + pdbs []*policy.PodDisruptionBudget, offset int32, numCandidates int32) ([]Candidate, framework.NodeToStatusMap, error) { + fh := ev.Handler + nonViolatingCandidates := newCandidateList(numCandidates) + violatingCandidates := newCandidateList(numCandidates) + ctx, cancel := context.WithCancel(ctx) + defer cancel() + nodeStatuses := make(framework.NodeToStatusMap) + var statusesLock sync.Mutex + var errs []error + checkNode := func(i int) { + nodeInfoCopy := potentialNodes[(int(offset)+i)%len(potentialNodes)].Clone() + stateCopy := ev.State.Clone() + pods, numPDBViolations, status := ev.SelectVictimsOnNode(ctx, stateCopy, pod, nodeInfoCopy, pdbs) + if status.IsSuccess() && len(pods) != 0 { + victims := extenderv1.Victims{ + Pods: pods, + NumPDBViolations: int64(numPDBViolations), + } + c := &candidate{ + victims: &victims, + name: nodeInfoCopy.Node().Name, + } + if numPDBViolations == 0 { + nonViolatingCandidates.add(c) + } else { + violatingCandidates.add(c) + } + nvcSize, vcSize := nonViolatingCandidates.size(), violatingCandidates.size() + if nvcSize > 0 && nvcSize+vcSize >= numCandidates { + cancel() + } + return + } + if status.IsSuccess() && len(pods) == 0 { + status = framework.AsStatus(fmt.Errorf("expected at least one victim pod on node %q", nodeInfoCopy.Node().Name)) + } + statusesLock.Lock() + if status.Code() == framework.Error { + errs = append(errs, status.AsError()) + } + nodeStatuses[nodeInfoCopy.Node().Name] = status + statusesLock.Unlock() + } + fh.Parallelizer().Until(ctx, len(potentialNodes), checkNode, ev.PluginName) + return append(nonViolatingCandidates.get(), violatingCandidates.get()...), nodeStatuses, utilerrors.NewAggregate(errs) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/runtime/framework.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/runtime/framework.go new file mode 100644 index 000000000..cc7ef65bb --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/runtime/framework.go @@ -0,0 +1,1374 @@ +/* +Copyright 2019 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 runtime + +import ( + "context" + "fmt" + "reflect" + "sort" + "time" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/client-go/informers" + clientset "k8s.io/client-go/kubernetes" + restclient "k8s.io/client-go/rest" + "k8s.io/client-go/tools/events" + "k8s.io/component-helpers/scheduling/corev1" + "k8s.io/klog/v2" + "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/parallelize" + "k8s.io/kubernetes/pkg/scheduler/metrics" +) + +const ( + // Filter is the name of the filter extension point. + Filter = "Filter" + // Specifies the maximum timeout a permit plugin can return. + maxTimeout = 15 * time.Minute + preFilter = "PreFilter" + preFilterExtensionAddPod = "PreFilterExtensionAddPod" + preFilterExtensionRemovePod = "PreFilterExtensionRemovePod" + postFilter = "PostFilter" + preScore = "PreScore" + score = "Score" + scoreExtensionNormalize = "ScoreExtensionNormalize" + preBind = "PreBind" + bind = "Bind" + postBind = "PostBind" + reserve = "Reserve" + unreserve = "Unreserve" + permit = "Permit" +) + +var allClusterEvents = []framework.ClusterEvent{ + {Resource: framework.Pod, ActionType: framework.All}, + {Resource: framework.Node, ActionType: framework.All}, + {Resource: framework.CSINode, ActionType: framework.All}, + {Resource: framework.PersistentVolume, ActionType: framework.All}, + {Resource: framework.PersistentVolumeClaim, ActionType: framework.All}, + {Resource: framework.StorageClass, ActionType: framework.All}, +} + +// frameworkImpl is the component responsible for initializing and running scheduler +// plugins. +type frameworkImpl struct { + registry Registry + snapshotSharedLister framework.SharedLister + waitingPods *waitingPodsMap + scorePluginWeight map[string]int + preEnqueuePlugins []framework.PreEnqueuePlugin + queueSortPlugins []framework.QueueSortPlugin + preFilterPlugins []framework.PreFilterPlugin + filterPlugins []framework.FilterPlugin + postFilterPlugins []framework.PostFilterPlugin + preScorePlugins []framework.PreScorePlugin + scorePlugins []framework.ScorePlugin + reservePlugins []framework.ReservePlugin + preBindPlugins []framework.PreBindPlugin + bindPlugins []framework.BindPlugin + postBindPlugins []framework.PostBindPlugin + permitPlugins []framework.PermitPlugin + + clientSet clientset.Interface + kubeConfig *restclient.Config + eventRecorder events.EventRecorder + informerFactory informers.SharedInformerFactory + + metricsRecorder *metricsRecorder + profileName string + percentageOfNodesToScore *int32 + + extenders []framework.Extender + framework.PodNominator + + parallelizer parallelize.Parallelizer +} + +// extensionPoint encapsulates desired and applied set of plugins at a specific extension +// point. This is used to simplify iterating over all extension points supported by the +// frameworkImpl. +type extensionPoint struct { + // the set of plugins to be configured at this extension point. + plugins *config.PluginSet + // a pointer to the slice storing plugins implementations that will run at this + // extension point. + slicePtr interface{} +} + +func (f *frameworkImpl) getExtensionPoints(plugins *config.Plugins) []extensionPoint { + return []extensionPoint{ + {&plugins.PreFilter, &f.preFilterPlugins}, + {&plugins.Filter, &f.filterPlugins}, + {&plugins.PostFilter, &f.postFilterPlugins}, + {&plugins.Reserve, &f.reservePlugins}, + {&plugins.PreScore, &f.preScorePlugins}, + {&plugins.Score, &f.scorePlugins}, + {&plugins.PreBind, &f.preBindPlugins}, + {&plugins.Bind, &f.bindPlugins}, + {&plugins.PostBind, &f.postBindPlugins}, + {&plugins.Permit, &f.permitPlugins}, + {&plugins.PreEnqueue, &f.preEnqueuePlugins}, + {&plugins.QueueSort, &f.queueSortPlugins}, + } +} + +// Extenders returns the registered extenders. +func (f *frameworkImpl) Extenders() []framework.Extender { + return f.extenders +} + +type frameworkOptions struct { + componentConfigVersion string + clientSet clientset.Interface + kubeConfig *restclient.Config + eventRecorder events.EventRecorder + informerFactory informers.SharedInformerFactory + snapshotSharedLister framework.SharedLister + metricsRecorder *metricsRecorder + podNominator framework.PodNominator + extenders []framework.Extender + captureProfile CaptureProfile + clusterEventMap map[framework.ClusterEvent]sets.String + parallelizer parallelize.Parallelizer +} + +// Option for the frameworkImpl. +type Option func(*frameworkOptions) + +// WithComponentConfigVersion sets the component config version to the +// KubeSchedulerConfiguration version used. The string should be the full +// scheme group/version of the external type we converted from (for example +// "kubescheduler.config.k8s.io/v1beta2") +func WithComponentConfigVersion(componentConfigVersion string) Option { + return func(o *frameworkOptions) { + o.componentConfigVersion = componentConfigVersion + } +} + +// WithClientSet sets clientSet for the scheduling frameworkImpl. +func WithClientSet(clientSet clientset.Interface) Option { + return func(o *frameworkOptions) { + o.clientSet = clientSet + } +} + +// WithKubeConfig sets kubeConfig for the scheduling frameworkImpl. +func WithKubeConfig(kubeConfig *restclient.Config) Option { + return func(o *frameworkOptions) { + o.kubeConfig = kubeConfig + } +} + +// WithEventRecorder sets clientSet for the scheduling frameworkImpl. +func WithEventRecorder(recorder events.EventRecorder) Option { + return func(o *frameworkOptions) { + o.eventRecorder = recorder + } +} + +// WithInformerFactory sets informer factory for the scheduling frameworkImpl. +func WithInformerFactory(informerFactory informers.SharedInformerFactory) Option { + return func(o *frameworkOptions) { + o.informerFactory = informerFactory + } +} + +// WithSnapshotSharedLister sets the SharedLister of the snapshot. +func WithSnapshotSharedLister(snapshotSharedLister framework.SharedLister) Option { + return func(o *frameworkOptions) { + o.snapshotSharedLister = snapshotSharedLister + } +} + +// WithPodNominator sets podNominator for the scheduling frameworkImpl. +func WithPodNominator(nominator framework.PodNominator) Option { + return func(o *frameworkOptions) { + o.podNominator = nominator + } +} + +// WithExtenders sets extenders for the scheduling frameworkImpl. +func WithExtenders(extenders []framework.Extender) Option { + return func(o *frameworkOptions) { + o.extenders = extenders + } +} + +// WithParallelism sets parallelism for the scheduling frameworkImpl. +func WithParallelism(parallelism int) Option { + return func(o *frameworkOptions) { + o.parallelizer = parallelize.NewParallelizer(parallelism) + } +} + +// CaptureProfile is a callback to capture a finalized profile. +type CaptureProfile func(config.KubeSchedulerProfile) + +// WithCaptureProfile sets a callback to capture the finalized profile. +func WithCaptureProfile(c CaptureProfile) Option { + return func(o *frameworkOptions) { + o.captureProfile = c + } +} + +func defaultFrameworkOptions(stopCh <-chan struct{}) frameworkOptions { + return frameworkOptions{ + metricsRecorder: newMetricsRecorder(1000, time.Second, stopCh), + clusterEventMap: make(map[framework.ClusterEvent]sets.String), + parallelizer: parallelize.NewParallelizer(parallelize.DefaultParallelism), + } +} + +// WithClusterEventMap sets clusterEventMap for the scheduling frameworkImpl. +func WithClusterEventMap(m map[framework.ClusterEvent]sets.String) Option { + return func(o *frameworkOptions) { + o.clusterEventMap = m + } +} + +var _ framework.Framework = &frameworkImpl{} + +// NewFramework initializes plugins given the configuration and the registry. +func NewFramework(r Registry, profile *config.KubeSchedulerProfile, stopCh <-chan struct{}, opts ...Option) (framework.Framework, error) { + options := defaultFrameworkOptions(stopCh) + for _, opt := range opts { + opt(&options) + } + + f := &frameworkImpl{ + registry: r, + snapshotSharedLister: options.snapshotSharedLister, + scorePluginWeight: make(map[string]int), + waitingPods: newWaitingPodsMap(), + clientSet: options.clientSet, + kubeConfig: options.kubeConfig, + eventRecorder: options.eventRecorder, + informerFactory: options.informerFactory, + metricsRecorder: options.metricsRecorder, + extenders: options.extenders, + PodNominator: options.podNominator, + parallelizer: options.parallelizer, + } + + if profile == nil { + return f, nil + } + + f.profileName = profile.SchedulerName + f.percentageOfNodesToScore = profile.PercentageOfNodesToScore + if profile.Plugins == nil { + return f, nil + } + + // get needed plugins from config + pg := f.pluginsNeeded(profile.Plugins) + + pluginConfig := make(map[string]runtime.Object, len(profile.PluginConfig)) + for i := range profile.PluginConfig { + name := profile.PluginConfig[i].Name + if _, ok := pluginConfig[name]; ok { + return nil, fmt.Errorf("repeated config for plugin %s", name) + } + pluginConfig[name] = profile.PluginConfig[i].Args + } + outputProfile := config.KubeSchedulerProfile{ + SchedulerName: f.profileName, + PercentageOfNodesToScore: f.percentageOfNodesToScore, + Plugins: profile.Plugins, + PluginConfig: make([]config.PluginConfig, 0, len(pg)), + } + + pluginsMap := make(map[string]framework.Plugin) + for name, factory := range r { + // initialize only needed plugins. + if !pg.Has(name) { + continue + } + + args := pluginConfig[name] + if args != nil { + outputProfile.PluginConfig = append(outputProfile.PluginConfig, config.PluginConfig{ + Name: name, + Args: args, + }) + } + p, err := factory(args, f) + if err != nil { + return nil, fmt.Errorf("initializing plugin %q: %w", name, err) + } + pluginsMap[name] = p + + // Update ClusterEventMap in place. + fillEventToPluginMap(p, options.clusterEventMap) + } + + // initialize plugins per individual extension points + for _, e := range f.getExtensionPoints(profile.Plugins) { + if err := updatePluginList(e.slicePtr, *e.plugins, pluginsMap); err != nil { + return nil, err + } + } + + // initialize multiPoint plugins to their expanded extension points + if len(profile.Plugins.MultiPoint.Enabled) > 0 { + if err := f.expandMultiPointPlugins(profile, pluginsMap); err != nil { + return nil, err + } + } + + if len(f.queueSortPlugins) != 1 { + return nil, fmt.Errorf("only one queue sort plugin required for profile with scheduler name %q, but got %d", profile.SchedulerName, len(f.queueSortPlugins)) + } + if len(f.bindPlugins) == 0 { + return nil, fmt.Errorf("at least one bind plugin is needed for profile with scheduler name %q", profile.SchedulerName) + } + + if err := getScoreWeights(f, pluginsMap, append(profile.Plugins.Score.Enabled, profile.Plugins.MultiPoint.Enabled...)); err != nil { + return nil, err + } + + // Verifying the score weights again since Plugin.Name() could return a different + // value from the one used in the configuration. + for _, scorePlugin := range f.scorePlugins { + if f.scorePluginWeight[scorePlugin.Name()] == 0 { + return nil, fmt.Errorf("score plugin %q is not configured with weight", scorePlugin.Name()) + } + } + + if options.captureProfile != nil { + if len(outputProfile.PluginConfig) != 0 { + sort.Slice(outputProfile.PluginConfig, func(i, j int) bool { + return outputProfile.PluginConfig[i].Name < outputProfile.PluginConfig[j].Name + }) + } else { + outputProfile.PluginConfig = nil + } + options.captureProfile(outputProfile) + } + + return f, nil +} + +func (f *frameworkImpl) SetPodNominator(n framework.PodNominator) { + f.PodNominator = n +} + +// getScoreWeights makes sure that, between MultiPoint-Score plugin weights and individual Score +// plugin weights there is not an overflow of MaxTotalScore. +func getScoreWeights(f *frameworkImpl, pluginsMap map[string]framework.Plugin, plugins []config.Plugin) error { + var totalPriority int64 + scorePlugins := reflect.ValueOf(&f.scorePlugins).Elem() + pluginType := scorePlugins.Type().Elem() + for _, e := range plugins { + pg := pluginsMap[e.Name] + if !reflect.TypeOf(pg).Implements(pluginType) { + continue + } + + // We append MultiPoint plugins to the list of Score plugins. So if this plugin has already been + // encountered, let the individual Score weight take precedence. + if _, ok := f.scorePluginWeight[e.Name]; ok { + continue + } + // a weight of zero is not permitted, plugins can be disabled explicitly + // when configured. + f.scorePluginWeight[e.Name] = int(e.Weight) + if f.scorePluginWeight[e.Name] == 0 { + f.scorePluginWeight[e.Name] = 1 + } + + // Checks totalPriority against MaxTotalScore to avoid overflow + if int64(f.scorePluginWeight[e.Name])*framework.MaxNodeScore > framework.MaxTotalScore-totalPriority { + return fmt.Errorf("total score of Score plugins could overflow") + } + totalPriority += int64(f.scorePluginWeight[e.Name]) * framework.MaxNodeScore + } + return nil +} + +type orderedSet struct { + set map[string]int + list []string + deletionCnt int +} + +func newOrderedSet() *orderedSet { + return &orderedSet{set: make(map[string]int)} +} + +func (os *orderedSet) insert(s string) { + if os.has(s) { + return + } + os.set[s] = len(os.list) + os.list = append(os.list, s) +} + +func (os *orderedSet) has(s string) bool { + _, found := os.set[s] + return found +} + +func (os *orderedSet) delete(s string) { + if i, found := os.set[s]; found { + delete(os.set, s) + os.list = append(os.list[:i-os.deletionCnt], os.list[i+1-os.deletionCnt:]...) + os.deletionCnt++ + } +} + +func (f *frameworkImpl) expandMultiPointPlugins(profile *config.KubeSchedulerProfile, pluginsMap map[string]framework.Plugin) error { + // initialize MultiPoint plugins + for _, e := range f.getExtensionPoints(profile.Plugins) { + plugins := reflect.ValueOf(e.slicePtr).Elem() + pluginType := plugins.Type().Elem() + // build enabledSet of plugins already registered via normal extension points + // to check double registration + enabledSet := newOrderedSet() + for _, plugin := range e.plugins.Enabled { + enabledSet.insert(plugin.Name) + } + + disabledSet := sets.NewString() + for _, disabledPlugin := range e.plugins.Disabled { + disabledSet.Insert(disabledPlugin.Name) + } + if disabledSet.Has("*") { + klog.V(4).InfoS("all plugins disabled for extension point, skipping MultiPoint expansion", "extension", pluginType) + continue + } + + // track plugins enabled via multipoint separately from those enabled by specific extensions, + // so that we can distinguish between double-registration and explicit overrides + multiPointEnabled := newOrderedSet() + overridePlugins := newOrderedSet() + for _, ep := range profile.Plugins.MultiPoint.Enabled { + pg, ok := pluginsMap[ep.Name] + if !ok { + return fmt.Errorf("%s %q does not exist", pluginType.Name(), ep.Name) + } + + // if this plugin doesn't implement the type for the current extension we're trying to expand, skip + if !reflect.TypeOf(pg).Implements(pluginType) { + continue + } + + // a plugin that's enabled via MultiPoint can still be disabled for specific extension points + if disabledSet.Has(ep.Name) { + klog.V(4).InfoS("plugin disabled for extension point", "plugin", ep.Name, "extension", pluginType) + continue + } + + // if this plugin has already been enabled by the specific extension point, + // the user intent is to override the default plugin or make some other explicit setting. + // Either way, discard the MultiPoint value for this plugin. + // This maintains expected behavior for overriding default plugins (see https://github.com/kubernetes/kubernetes/pull/99582) + if enabledSet.has(ep.Name) { + overridePlugins.insert(ep.Name) + klog.InfoS("MultiPoint plugin is explicitly re-configured; overriding", "plugin", ep.Name) + continue + } + + // if this plugin is already registered via MultiPoint, then this is + // a double registration and an error in the config. + if multiPointEnabled.has(ep.Name) { + return fmt.Errorf("plugin %q already registered as %q", ep.Name, pluginType.Name()) + } + + // we only need to update the multipoint set, since we already have the specific extension set from above + multiPointEnabled.insert(ep.Name) + } + + // Reorder plugins. Here is the expected order: + // - part 1: overridePlugins. Their order stay intact as how they're specified in regular extension point. + // - part 2: multiPointEnabled - i.e., plugin defined in multipoint but not in regular extension point. + // - part 3: other plugins (excluded by part 1 & 2) in regular extension point. + newPlugins := reflect.New(reflect.TypeOf(e.slicePtr).Elem()).Elem() + // part 1 + for _, name := range enabledSet.list { + if overridePlugins.has(name) { + newPlugins = reflect.Append(newPlugins, reflect.ValueOf(pluginsMap[name])) + enabledSet.delete(name) + } + } + // part 2 + for _, name := range multiPointEnabled.list { + newPlugins = reflect.Append(newPlugins, reflect.ValueOf(pluginsMap[name])) + } + // part 3 + for _, name := range enabledSet.list { + newPlugins = reflect.Append(newPlugins, reflect.ValueOf(pluginsMap[name])) + } + plugins.Set(newPlugins) + } + return nil +} + +func fillEventToPluginMap(p framework.Plugin, eventToPlugins map[framework.ClusterEvent]sets.String) { + ext, ok := p.(framework.EnqueueExtensions) + if !ok { + // If interface EnqueueExtensions is not implemented, register the default events + // to the plugin. This is to ensure backward compatibility. + registerClusterEvents(p.Name(), eventToPlugins, allClusterEvents) + return + } + + events := ext.EventsToRegister() + // It's rare that a plugin implements EnqueueExtensions but returns nil. + // We treat it as: the plugin is not interested in any event, and hence pod failed by that plugin + // cannot be moved by any regular cluster event. + if len(events) == 0 { + klog.InfoS("Plugin's EventsToRegister() returned nil", "plugin", p.Name()) + return + } + // The most common case: a plugin implements EnqueueExtensions and returns non-nil result. + registerClusterEvents(p.Name(), eventToPlugins, events) +} + +func registerClusterEvents(name string, eventToPlugins map[framework.ClusterEvent]sets.String, evts []framework.ClusterEvent) { + for _, evt := range evts { + if eventToPlugins[evt] == nil { + eventToPlugins[evt] = sets.NewString(name) + } else { + eventToPlugins[evt].Insert(name) + } + } +} + +func updatePluginList(pluginList interface{}, pluginSet config.PluginSet, pluginsMap map[string]framework.Plugin) error { + plugins := reflect.ValueOf(pluginList).Elem() + pluginType := plugins.Type().Elem() + set := sets.NewString() + for _, ep := range pluginSet.Enabled { + pg, ok := pluginsMap[ep.Name] + if !ok { + return fmt.Errorf("%s %q does not exist", pluginType.Name(), ep.Name) + } + + if !reflect.TypeOf(pg).Implements(pluginType) { + return fmt.Errorf("plugin %q does not extend %s plugin", ep.Name, pluginType.Name()) + } + + if set.Has(ep.Name) { + return fmt.Errorf("plugin %q already registered as %q", ep.Name, pluginType.Name()) + } + + set.Insert(ep.Name) + + newPlugins := reflect.Append(plugins, reflect.ValueOf(pg)) + plugins.Set(newPlugins) + } + return nil +} + +// EnqueuePlugins returns the registered enqueue plugins. +func (f *frameworkImpl) PreEnqueuePlugins() []framework.PreEnqueuePlugin { + return f.preEnqueuePlugins +} + +// QueueSortFunc returns the function to sort pods in scheduling queue +func (f *frameworkImpl) QueueSortFunc() framework.LessFunc { + if f == nil { + // If frameworkImpl is nil, simply keep their order unchanged. + // NOTE: this is primarily for tests. + return func(_, _ *framework.QueuedPodInfo) bool { return false } + } + + if len(f.queueSortPlugins) == 0 { + panic("No QueueSort plugin is registered in the frameworkImpl.") + } + + // Only one QueueSort plugin can be enabled. + return f.queueSortPlugins[0].Less +} + +// RunPreFilterPlugins runs the set of configured PreFilter plugins. It returns +// *Status and its code is set to non-success if any of the plugins returns +// anything but Success. If a non-success status is returned, then the scheduling +// cycle is aborted. +func (f *frameworkImpl) RunPreFilterPlugins(ctx context.Context, state *framework.CycleState, pod *v1.Pod) (_ *framework.PreFilterResult, status *framework.Status) { + startTime := time.Now() + defer func() { + metrics.FrameworkExtensionPointDuration.WithLabelValues(preFilter, status.Code().String(), f.profileName).Observe(metrics.SinceInSeconds(startTime)) + }() + var result *framework.PreFilterResult + var pluginsWithNodes []string + for _, pl := range f.preFilterPlugins { + r, s := f.runPreFilterPlugin(ctx, pl, state, pod) + if !s.IsSuccess() { + s.SetFailedPlugin(pl.Name()) + if s.IsUnschedulable() { + return nil, s + } + return nil, framework.AsStatus(fmt.Errorf("running PreFilter plugin %q: %w", pl.Name(), s.AsError())).WithFailedPlugin(pl.Name()) + } + if !r.AllNodes() { + pluginsWithNodes = append(pluginsWithNodes, pl.Name()) + } + result = result.Merge(r) + if !result.AllNodes() && len(result.NodeNames) == 0 { + msg := fmt.Sprintf("node(s) didn't satisfy plugin(s) %v simultaneously", pluginsWithNodes) + if len(pluginsWithNodes) == 1 { + msg = fmt.Sprintf("node(s) didn't satisfy plugin %v", pluginsWithNodes[0]) + } + return nil, framework.NewStatus(framework.Unschedulable, msg) + } + + } + return result, nil +} + +func (f *frameworkImpl) runPreFilterPlugin(ctx context.Context, pl framework.PreFilterPlugin, state *framework.CycleState, pod *v1.Pod) (*framework.PreFilterResult, *framework.Status) { + if !state.ShouldRecordPluginMetrics() { + return pl.PreFilter(ctx, state, pod) + } + startTime := time.Now() + result, status := pl.PreFilter(ctx, state, pod) + f.metricsRecorder.observePluginDurationAsync(preFilter, pl.Name(), status, metrics.SinceInSeconds(startTime)) + return result, status +} + +// RunPreFilterExtensionAddPod calls the AddPod interface for the set of configured +// PreFilter plugins. It returns directly if any of the plugins return any +// status other than Success. +func (f *frameworkImpl) RunPreFilterExtensionAddPod( + ctx context.Context, + state *framework.CycleState, + podToSchedule *v1.Pod, + podInfoToAdd *framework.PodInfo, + nodeInfo *framework.NodeInfo, +) (status *framework.Status) { + for _, pl := range f.preFilterPlugins { + if pl.PreFilterExtensions() == nil { + continue + } + status = f.runPreFilterExtensionAddPod(ctx, pl, state, podToSchedule, podInfoToAdd, nodeInfo) + if !status.IsSuccess() { + err := status.AsError() + klog.ErrorS(err, "Failed running AddPod on PreFilter plugin", "plugin", pl.Name(), "pod", klog.KObj(podToSchedule)) + return framework.AsStatus(fmt.Errorf("running AddPod on PreFilter plugin %q: %w", pl.Name(), err)) + } + } + + return nil +} + +func (f *frameworkImpl) runPreFilterExtensionAddPod(ctx context.Context, pl framework.PreFilterPlugin, state *framework.CycleState, podToSchedule *v1.Pod, podInfoToAdd *framework.PodInfo, nodeInfo *framework.NodeInfo) *framework.Status { + if !state.ShouldRecordPluginMetrics() { + return pl.PreFilterExtensions().AddPod(ctx, state, podToSchedule, podInfoToAdd, nodeInfo) + } + startTime := time.Now() + status := pl.PreFilterExtensions().AddPod(ctx, state, podToSchedule, podInfoToAdd, nodeInfo) + f.metricsRecorder.observePluginDurationAsync(preFilterExtensionAddPod, pl.Name(), status, metrics.SinceInSeconds(startTime)) + return status +} + +// RunPreFilterExtensionRemovePod calls the RemovePod interface for the set of configured +// PreFilter plugins. It returns directly if any of the plugins return any +// status other than Success. +func (f *frameworkImpl) RunPreFilterExtensionRemovePod( + ctx context.Context, + state *framework.CycleState, + podToSchedule *v1.Pod, + podInfoToRemove *framework.PodInfo, + nodeInfo *framework.NodeInfo, +) (status *framework.Status) { + for _, pl := range f.preFilterPlugins { + if pl.PreFilterExtensions() == nil { + continue + } + status = f.runPreFilterExtensionRemovePod(ctx, pl, state, podToSchedule, podInfoToRemove, nodeInfo) + if !status.IsSuccess() { + err := status.AsError() + klog.ErrorS(err, "Failed running RemovePod on PreFilter plugin", "plugin", pl.Name(), "pod", klog.KObj(podToSchedule)) + return framework.AsStatus(fmt.Errorf("running RemovePod on PreFilter plugin %q: %w", pl.Name(), err)) + } + } + + return nil +} + +func (f *frameworkImpl) runPreFilterExtensionRemovePod(ctx context.Context, pl framework.PreFilterPlugin, state *framework.CycleState, podToSchedule *v1.Pod, podInfoToRemove *framework.PodInfo, nodeInfo *framework.NodeInfo) *framework.Status { + if !state.ShouldRecordPluginMetrics() { + return pl.PreFilterExtensions().RemovePod(ctx, state, podToSchedule, podInfoToRemove, nodeInfo) + } + startTime := time.Now() + status := pl.PreFilterExtensions().RemovePod(ctx, state, podToSchedule, podInfoToRemove, nodeInfo) + f.metricsRecorder.observePluginDurationAsync(preFilterExtensionRemovePod, pl.Name(), status, metrics.SinceInSeconds(startTime)) + return status +} + +// RunFilterPlugins runs the set of configured Filter plugins for pod on +// the given node. If any of these plugins doesn't return "Success", the +// given node is not suitable for running pod. +// Meanwhile, the failure message and status are set for the given node. +func (f *frameworkImpl) RunFilterPlugins( + ctx context.Context, + state *framework.CycleState, + pod *v1.Pod, + nodeInfo *framework.NodeInfo, +) framework.PluginToStatus { + statuses := make(framework.PluginToStatus) + for _, pl := range f.filterPlugins { + pluginStatus := f.runFilterPlugin(ctx, pl, state, pod, nodeInfo) + if !pluginStatus.IsSuccess() { + if !pluginStatus.IsUnschedulable() { + // Filter plugins are not supposed to return any status other than + // Success or Unschedulable. + pluginStatus = framework.AsStatus(fmt.Errorf("running %q filter plugin: %w", pl.Name(), pluginStatus.AsError())) + } + pluginStatus.SetFailedPlugin(pl.Name()) + return map[string]*framework.Status{pl.Name(): pluginStatus} + } + } + + return statuses +} + +func (f *frameworkImpl) runFilterPlugin(ctx context.Context, pl framework.FilterPlugin, state *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status { + if !state.ShouldRecordPluginMetrics() { + return pl.Filter(ctx, state, pod, nodeInfo) + } + startTime := time.Now() + status := pl.Filter(ctx, state, pod, nodeInfo) + f.metricsRecorder.observePluginDurationAsync(Filter, pl.Name(), status, metrics.SinceInSeconds(startTime)) + return status +} + +// RunPostFilterPlugins runs the set of configured PostFilter plugins until the first +// Success or Error is met, otherwise continues to execute all plugins. +func (f *frameworkImpl) RunPostFilterPlugins(ctx context.Context, state *framework.CycleState, pod *v1.Pod, filteredNodeStatusMap framework.NodeToStatusMap) (_ *framework.PostFilterResult, status *framework.Status) { + startTime := time.Now() + defer func() { + metrics.FrameworkExtensionPointDuration.WithLabelValues(postFilter, status.Code().String(), f.profileName).Observe(metrics.SinceInSeconds(startTime)) + }() + + statuses := make(framework.PluginToStatus) + // `result` records the last meaningful(non-noop) PostFilterResult. + var result *framework.PostFilterResult + for _, pl := range f.postFilterPlugins { + r, s := f.runPostFilterPlugin(ctx, pl, state, pod, filteredNodeStatusMap) + if s.IsSuccess() { + return r, s + } else if !s.IsUnschedulable() { + // Any status other than Success or Unschedulable is Error. + return nil, framework.AsStatus(s.AsError()) + } else if r != nil && r.Mode() != framework.ModeNoop { + result = r + } + statuses[pl.Name()] = s + } + + return result, statuses.Merge() +} + +func (f *frameworkImpl) runPostFilterPlugin(ctx context.Context, pl framework.PostFilterPlugin, state *framework.CycleState, pod *v1.Pod, filteredNodeStatusMap framework.NodeToStatusMap) (*framework.PostFilterResult, *framework.Status) { + if !state.ShouldRecordPluginMetrics() { + return pl.PostFilter(ctx, state, pod, filteredNodeStatusMap) + } + startTime := time.Now() + r, s := pl.PostFilter(ctx, state, pod, filteredNodeStatusMap) + f.metricsRecorder.observePluginDurationAsync(postFilter, pl.Name(), s, metrics.SinceInSeconds(startTime)) + return r, s +} + +// RunFilterPluginsWithNominatedPods runs the set of configured filter plugins +// for nominated pod on the given node. +// This function is called from two different places: Schedule and Preempt. +// When it is called from Schedule, we want to test whether the pod is +// schedulable on the node with all the existing pods on the node plus higher +// and equal priority pods nominated to run on the node. +// When it is called from Preempt, we should remove the victims of preemption +// and add the nominated pods. Removal of the victims is done by +// SelectVictimsOnNode(). Preempt removes victims from PreFilter state and +// NodeInfo before calling this function. +func (f *frameworkImpl) RunFilterPluginsWithNominatedPods(ctx context.Context, state *framework.CycleState, pod *v1.Pod, info *framework.NodeInfo) *framework.Status { + var status *framework.Status + + podsAdded := false + // We run filters twice in some cases. If the node has greater or equal priority + // nominated pods, we run them when those pods are added to PreFilter state and nodeInfo. + // If all filters succeed in this pass, we run them again when these + // nominated pods are not added. This second pass is necessary because some + // filters such as inter-pod affinity may not pass without the nominated pods. + // If there are no nominated pods for the node or if the first run of the + // filters fail, we don't run the second pass. + // We consider only equal or higher priority pods in the first pass, because + // those are the current "pod" must yield to them and not take a space opened + // for running them. It is ok if the current "pod" take resources freed for + // lower priority pods. + // Requiring that the new pod is schedulable in both circumstances ensures that + // we are making a conservative decision: filters like resources and inter-pod + // anti-affinity are more likely to fail when the nominated pods are treated + // as running, while filters like pod affinity are more likely to fail when + // the nominated pods are treated as not running. We can't just assume the + // nominated pods are running because they are not running right now and in fact, + // they may end up getting scheduled to a different node. + for i := 0; i < 2; i++ { + stateToUse := state + nodeInfoToUse := info + if i == 0 { + var err error + podsAdded, stateToUse, nodeInfoToUse, err = addNominatedPods(ctx, f, pod, state, info) + if err != nil { + return framework.AsStatus(err) + } + } else if !podsAdded || !status.IsSuccess() { + break + } + + statusMap := f.RunFilterPlugins(ctx, stateToUse, pod, nodeInfoToUse) + status = statusMap.Merge() + if !status.IsSuccess() && !status.IsUnschedulable() { + return status + } + } + + return status +} + +// addNominatedPods adds pods with equal or greater priority which are nominated +// to run on the node. It returns 1) whether any pod was added, 2) augmented cycleState, +// 3) augmented nodeInfo. +func addNominatedPods(ctx context.Context, fh framework.Handle, pod *v1.Pod, state *framework.CycleState, nodeInfo *framework.NodeInfo) (bool, *framework.CycleState, *framework.NodeInfo, error) { + if fh == nil || nodeInfo.Node() == nil { + // This may happen only in tests. + return false, state, nodeInfo, nil + } + nominatedPodInfos := fh.NominatedPodsForNode(nodeInfo.Node().Name) + if len(nominatedPodInfos) == 0 { + return false, state, nodeInfo, nil + } + nodeInfoOut := nodeInfo.Clone() + stateOut := state.Clone() + podsAdded := false + for _, pi := range nominatedPodInfos { + if corev1.PodPriority(pi.Pod) >= corev1.PodPriority(pod) && pi.Pod.UID != pod.UID { + nodeInfoOut.AddPodInfo(pi) + status := fh.RunPreFilterExtensionAddPod(ctx, stateOut, pod, pi, nodeInfoOut) + if !status.IsSuccess() { + return false, state, nodeInfo, status.AsError() + } + podsAdded = true + } + } + return podsAdded, stateOut, nodeInfoOut, nil +} + +// RunPreScorePlugins runs the set of configured pre-score plugins. If any +// of these plugins returns any status other than "Success", the given pod is rejected. +func (f *frameworkImpl) RunPreScorePlugins( + ctx context.Context, + state *framework.CycleState, + pod *v1.Pod, + nodes []*v1.Node, +) (status *framework.Status) { + startTime := time.Now() + defer func() { + metrics.FrameworkExtensionPointDuration.WithLabelValues(preScore, status.Code().String(), f.profileName).Observe(metrics.SinceInSeconds(startTime)) + }() + for _, pl := range f.preScorePlugins { + status = f.runPreScorePlugin(ctx, pl, state, pod, nodes) + if !status.IsSuccess() { + return framework.AsStatus(fmt.Errorf("running PreScore plugin %q: %w", pl.Name(), status.AsError())) + } + } + + return nil +} + +func (f *frameworkImpl) runPreScorePlugin(ctx context.Context, pl framework.PreScorePlugin, state *framework.CycleState, pod *v1.Pod, nodes []*v1.Node) *framework.Status { + if !state.ShouldRecordPluginMetrics() { + return pl.PreScore(ctx, state, pod, nodes) + } + startTime := time.Now() + status := pl.PreScore(ctx, state, pod, nodes) + f.metricsRecorder.observePluginDurationAsync(preScore, pl.Name(), status, metrics.SinceInSeconds(startTime)) + return status +} + +// RunScorePlugins runs the set of configured scoring plugins. +// It returns a list that stores scores from each plugin and total score for each Node. +// It also returns *Status, which is set to non-success if any of the plugins returns +// a non-success status. +func (f *frameworkImpl) RunScorePlugins(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodes []*v1.Node) (ns []framework.NodePluginScores, status *framework.Status) { + startTime := time.Now() + defer func() { + metrics.FrameworkExtensionPointDuration.WithLabelValues(score, status.Code().String(), f.profileName).Observe(metrics.SinceInSeconds(startTime)) + }() + allNodePluginScores := make([]framework.NodePluginScores, len(nodes)) + pluginToNodeScores := make(map[string]framework.NodeScoreList, len(f.scorePlugins)) + for _, pl := range f.scorePlugins { + pluginToNodeScores[pl.Name()] = make(framework.NodeScoreList, len(nodes)) + } + ctx, cancel := context.WithCancel(ctx) + defer cancel() + errCh := parallelize.NewErrorChannel() + + // Run Score method for each node in parallel. + f.Parallelizer().Until(ctx, len(nodes), func(index int) { + for _, pl := range f.scorePlugins { + nodeName := nodes[index].Name + s, status := f.runScorePlugin(ctx, pl, state, pod, nodeName) + if !status.IsSuccess() { + err := fmt.Errorf("plugin %q failed with: %w", pl.Name(), status.AsError()) + errCh.SendErrorWithCancel(err, cancel) + return + } + pluginToNodeScores[pl.Name()][index] = framework.NodeScore{ + Name: nodeName, + Score: s, + } + } + }, score) + if err := errCh.ReceiveError(); err != nil { + return nil, framework.AsStatus(fmt.Errorf("running Score plugins: %w", err)) + } + + // Run NormalizeScore method for each ScorePlugin in parallel. + f.Parallelizer().Until(ctx, len(f.scorePlugins), func(index int) { + pl := f.scorePlugins[index] + if pl.ScoreExtensions() == nil { + return + } + nodeScoreList := pluginToNodeScores[pl.Name()] + status := f.runScoreExtension(ctx, pl, state, pod, nodeScoreList) + if !status.IsSuccess() { + err := fmt.Errorf("plugin %q failed with: %w", pl.Name(), status.AsError()) + errCh.SendErrorWithCancel(err, cancel) + return + } + }, score) + if err := errCh.ReceiveError(); err != nil { + return nil, framework.AsStatus(fmt.Errorf("running Normalize on Score plugins: %w", err)) + } + + // Apply score weight for each ScorePlugin in parallel, + // and then, build allNodePluginScores. + f.Parallelizer().Until(ctx, len(nodes), func(index int) { + nodePluginScores := framework.NodePluginScores{ + Name: nodes[index].Name, + Scores: make([]framework.PluginScore, len(f.scorePlugins)), + } + + for i, pl := range f.scorePlugins { + weight := f.scorePluginWeight[pl.Name()] + nodeScoreList := pluginToNodeScores[pl.Name()] + score := nodeScoreList[index].Score + + if score > framework.MaxNodeScore || score < framework.MinNodeScore { + err := fmt.Errorf("plugin %q returns an invalid score %v, it should in the range of [%v, %v] after normalizing", pl.Name(), score, framework.MinNodeScore, framework.MaxNodeScore) + errCh.SendErrorWithCancel(err, cancel) + return + } + weightedScore := score * int64(weight) + nodePluginScores.Scores[i] = framework.PluginScore{ + Name: pl.Name(), + Score: weightedScore, + } + nodePluginScores.TotalScore += weightedScore + } + allNodePluginScores[index] = nodePluginScores + }, score) + if err := errCh.ReceiveError(); err != nil { + return nil, framework.AsStatus(fmt.Errorf("applying score defaultWeights on Score plugins: %w", err)) + } + + return allNodePluginScores, nil +} + +func (f *frameworkImpl) runScorePlugin(ctx context.Context, pl framework.ScorePlugin, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) { + if !state.ShouldRecordPluginMetrics() { + return pl.Score(ctx, state, pod, nodeName) + } + startTime := time.Now() + s, status := pl.Score(ctx, state, pod, nodeName) + f.metricsRecorder.observePluginDurationAsync(score, pl.Name(), status, metrics.SinceInSeconds(startTime)) + return s, status +} + +func (f *frameworkImpl) runScoreExtension(ctx context.Context, pl framework.ScorePlugin, state *framework.CycleState, pod *v1.Pod, nodeScoreList framework.NodeScoreList) *framework.Status { + if !state.ShouldRecordPluginMetrics() { + return pl.ScoreExtensions().NormalizeScore(ctx, state, pod, nodeScoreList) + } + startTime := time.Now() + status := pl.ScoreExtensions().NormalizeScore(ctx, state, pod, nodeScoreList) + f.metricsRecorder.observePluginDurationAsync(scoreExtensionNormalize, pl.Name(), status, metrics.SinceInSeconds(startTime)) + return status +} + +// RunPreBindPlugins runs the set of configured prebind plugins. It returns a +// failure (bool) if any of the plugins returns an error. It also returns an +// error containing the rejection message or the error occurred in the plugin. +func (f *frameworkImpl) RunPreBindPlugins(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (status *framework.Status) { + startTime := time.Now() + defer func() { + metrics.FrameworkExtensionPointDuration.WithLabelValues(preBind, status.Code().String(), f.profileName).Observe(metrics.SinceInSeconds(startTime)) + }() + for _, pl := range f.preBindPlugins { + status = f.runPreBindPlugin(ctx, pl, state, pod, nodeName) + if !status.IsSuccess() { + if status.IsUnschedulable() { + klog.V(4).InfoS("Pod rejected by PreBind plugin", "pod", klog.KObj(pod), "node", nodeName, "plugin", pl.Name(), "status", status.Message()) + status.SetFailedPlugin(pl.Name()) + return status + } + err := status.AsError() + klog.ErrorS(err, "Failed running PreBind plugin", "plugin", pl.Name(), "pod", klog.KObj(pod), "node", nodeName) + return framework.AsStatus(fmt.Errorf("running PreBind plugin %q: %w", pl.Name(), err)) + } + } + return nil +} + +func (f *frameworkImpl) runPreBindPlugin(ctx context.Context, pl framework.PreBindPlugin, state *framework.CycleState, pod *v1.Pod, nodeName string) *framework.Status { + if !state.ShouldRecordPluginMetrics() { + return pl.PreBind(ctx, state, pod, nodeName) + } + startTime := time.Now() + status := pl.PreBind(ctx, state, pod, nodeName) + f.metricsRecorder.observePluginDurationAsync(preBind, pl.Name(), status, metrics.SinceInSeconds(startTime)) + return status +} + +// RunBindPlugins runs the set of configured bind plugins until one returns a non `Skip` status. +func (f *frameworkImpl) RunBindPlugins(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (status *framework.Status) { + startTime := time.Now() + defer func() { + metrics.FrameworkExtensionPointDuration.WithLabelValues(bind, status.Code().String(), f.profileName).Observe(metrics.SinceInSeconds(startTime)) + }() + if len(f.bindPlugins) == 0 { + return framework.NewStatus(framework.Skip, "") + } + for _, pl := range f.bindPlugins { + status = f.runBindPlugin(ctx, pl, state, pod, nodeName) + if status.IsSkip() { + continue + } + if !status.IsSuccess() { + if status.IsUnschedulable() { + klog.V(4).InfoS("Pod rejected by Bind plugin", "pod", klog.KObj(pod), "node", nodeName, "plugin", pl.Name(), "status", status.Message()) + status.SetFailedPlugin(pl.Name()) + return status + } + err := status.AsError() + klog.ErrorS(err, "Failed running Bind plugin", "plugin", pl.Name(), "pod", klog.KObj(pod), "node", nodeName) + return framework.AsStatus(fmt.Errorf("running Bind plugin %q: %w", pl.Name(), err)) + } + return status + } + return status +} + +func (f *frameworkImpl) runBindPlugin(ctx context.Context, bp framework.BindPlugin, state *framework.CycleState, pod *v1.Pod, nodeName string) *framework.Status { + if !state.ShouldRecordPluginMetrics() { + return bp.Bind(ctx, state, pod, nodeName) + } + startTime := time.Now() + status := bp.Bind(ctx, state, pod, nodeName) + f.metricsRecorder.observePluginDurationAsync(bind, bp.Name(), status, metrics.SinceInSeconds(startTime)) + return status +} + +// RunPostBindPlugins runs the set of configured postbind plugins. +func (f *frameworkImpl) RunPostBindPlugins(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) { + startTime := time.Now() + defer func() { + metrics.FrameworkExtensionPointDuration.WithLabelValues(postBind, framework.Success.String(), f.profileName).Observe(metrics.SinceInSeconds(startTime)) + }() + for _, pl := range f.postBindPlugins { + f.runPostBindPlugin(ctx, pl, state, pod, nodeName) + } +} + +func (f *frameworkImpl) runPostBindPlugin(ctx context.Context, pl framework.PostBindPlugin, state *framework.CycleState, pod *v1.Pod, nodeName string) { + if !state.ShouldRecordPluginMetrics() { + pl.PostBind(ctx, state, pod, nodeName) + return + } + startTime := time.Now() + pl.PostBind(ctx, state, pod, nodeName) + f.metricsRecorder.observePluginDurationAsync(postBind, pl.Name(), nil, metrics.SinceInSeconds(startTime)) +} + +// RunReservePluginsReserve runs the Reserve method in the set of configured +// reserve plugins. If any of these plugins returns an error, it does not +// continue running the remaining ones and returns the error. In such a case, +// the pod will not be scheduled and the caller will be expected to call +// RunReservePluginsUnreserve. +func (f *frameworkImpl) RunReservePluginsReserve(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (status *framework.Status) { + startTime := time.Now() + defer func() { + metrics.FrameworkExtensionPointDuration.WithLabelValues(reserve, status.Code().String(), f.profileName).Observe(metrics.SinceInSeconds(startTime)) + }() + for _, pl := range f.reservePlugins { + status = f.runReservePluginReserve(ctx, pl, state, pod, nodeName) + if !status.IsSuccess() { + err := status.AsError() + klog.ErrorS(err, "Failed running Reserve plugin", "plugin", pl.Name(), "pod", klog.KObj(pod)) + return framework.AsStatus(fmt.Errorf("running Reserve plugin %q: %w", pl.Name(), err)) + } + } + return nil +} + +func (f *frameworkImpl) runReservePluginReserve(ctx context.Context, pl framework.ReservePlugin, state *framework.CycleState, pod *v1.Pod, nodeName string) *framework.Status { + if !state.ShouldRecordPluginMetrics() { + return pl.Reserve(ctx, state, pod, nodeName) + } + startTime := time.Now() + status := pl.Reserve(ctx, state, pod, nodeName) + f.metricsRecorder.observePluginDurationAsync(reserve, pl.Name(), status, metrics.SinceInSeconds(startTime)) + return status +} + +// RunReservePluginsUnreserve runs the Unreserve method in the set of +// configured reserve plugins. +func (f *frameworkImpl) RunReservePluginsUnreserve(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) { + startTime := time.Now() + defer func() { + metrics.FrameworkExtensionPointDuration.WithLabelValues(unreserve, framework.Success.String(), f.profileName).Observe(metrics.SinceInSeconds(startTime)) + }() + // Execute the Unreserve operation of each reserve plugin in the + // *reverse* order in which the Reserve operation was executed. + for i := len(f.reservePlugins) - 1; i >= 0; i-- { + f.runReservePluginUnreserve(ctx, f.reservePlugins[i], state, pod, nodeName) + } +} + +func (f *frameworkImpl) runReservePluginUnreserve(ctx context.Context, pl framework.ReservePlugin, state *framework.CycleState, pod *v1.Pod, nodeName string) { + if !state.ShouldRecordPluginMetrics() { + pl.Unreserve(ctx, state, pod, nodeName) + return + } + startTime := time.Now() + pl.Unreserve(ctx, state, pod, nodeName) + f.metricsRecorder.observePluginDurationAsync(unreserve, pl.Name(), nil, metrics.SinceInSeconds(startTime)) +} + +// RunPermitPlugins runs the set of configured permit plugins. If any of these +// plugins returns a status other than "Success" or "Wait", it does not continue +// running the remaining plugins and returns an error. Otherwise, if any of the +// plugins returns "Wait", then this function will create and add waiting pod +// to a map of currently waiting pods and return status with "Wait" code. +// Pod will remain waiting pod for the minimum duration returned by the permit plugins. +func (f *frameworkImpl) RunPermitPlugins(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (status *framework.Status) { + startTime := time.Now() + defer func() { + metrics.FrameworkExtensionPointDuration.WithLabelValues(permit, status.Code().String(), f.profileName).Observe(metrics.SinceInSeconds(startTime)) + }() + pluginsWaitTime := make(map[string]time.Duration) + statusCode := framework.Success + for _, pl := range f.permitPlugins { + status, timeout := f.runPermitPlugin(ctx, pl, state, pod, nodeName) + if !status.IsSuccess() { + if status.IsUnschedulable() { + klog.V(4).InfoS("Pod rejected by permit plugin", "pod", klog.KObj(pod), "plugin", pl.Name(), "status", status.Message()) + status.SetFailedPlugin(pl.Name()) + return status + } + if status.IsWait() { + // Not allowed to be greater than maxTimeout. + if timeout > maxTimeout { + timeout = maxTimeout + } + pluginsWaitTime[pl.Name()] = timeout + statusCode = framework.Wait + } else { + err := status.AsError() + klog.ErrorS(err, "Failed running Permit plugin", "plugin", pl.Name(), "pod", klog.KObj(pod)) + return framework.AsStatus(fmt.Errorf("running Permit plugin %q: %w", pl.Name(), err)).WithFailedPlugin(pl.Name()) + } + } + } + if statusCode == framework.Wait { + waitingPod := newWaitingPod(pod, pluginsWaitTime) + f.waitingPods.add(waitingPod) + msg := fmt.Sprintf("one or more plugins asked to wait and no plugin rejected pod %q", pod.Name) + klog.V(4).InfoS("One or more plugins asked to wait and no plugin rejected pod", "pod", klog.KObj(pod)) + return framework.NewStatus(framework.Wait, msg) + } + return nil +} + +func (f *frameworkImpl) runPermitPlugin(ctx context.Context, pl framework.PermitPlugin, state *framework.CycleState, pod *v1.Pod, nodeName string) (*framework.Status, time.Duration) { + if !state.ShouldRecordPluginMetrics() { + return pl.Permit(ctx, state, pod, nodeName) + } + startTime := time.Now() + status, timeout := pl.Permit(ctx, state, pod, nodeName) + f.metricsRecorder.observePluginDurationAsync(permit, pl.Name(), status, metrics.SinceInSeconds(startTime)) + return status, timeout +} + +// WaitOnPermit will block, if the pod is a waiting pod, until the waiting pod is rejected or allowed. +func (f *frameworkImpl) WaitOnPermit(ctx context.Context, pod *v1.Pod) *framework.Status { + waitingPod := f.waitingPods.get(pod.UID) + if waitingPod == nil { + return nil + } + defer f.waitingPods.remove(pod.UID) + klog.V(4).InfoS("Pod waiting on permit", "pod", klog.KObj(pod)) + + startTime := time.Now() + s := <-waitingPod.s + metrics.PermitWaitDuration.WithLabelValues(s.Code().String()).Observe(metrics.SinceInSeconds(startTime)) + + if !s.IsSuccess() { + if s.IsUnschedulable() { + klog.V(4).InfoS("Pod rejected while waiting on permit", "pod", klog.KObj(pod), "status", s.Message()) + return s + } + err := s.AsError() + klog.ErrorS(err, "Failed waiting on permit for pod", "pod", klog.KObj(pod)) + return framework.AsStatus(fmt.Errorf("waiting on permit for pod: %w", err)).WithFailedPlugin(s.FailedPlugin()) + } + return nil +} + +// SnapshotSharedLister returns the scheduler's SharedLister of the latest NodeInfo +// snapshot. The snapshot is taken at the beginning of a scheduling cycle and remains +// unchanged until a pod finishes "Reserve". There is no guarantee that the information +// remains unchanged after "Reserve". +func (f *frameworkImpl) SnapshotSharedLister() framework.SharedLister { + return f.snapshotSharedLister +} + +// IterateOverWaitingPods acquires a read lock and iterates over the WaitingPods map. +func (f *frameworkImpl) IterateOverWaitingPods(callback func(framework.WaitingPod)) { + f.waitingPods.iterate(callback) +} + +// GetWaitingPod returns a reference to a WaitingPod given its UID. +func (f *frameworkImpl) GetWaitingPod(uid types.UID) framework.WaitingPod { + if wp := f.waitingPods.get(uid); wp != nil { + return wp + } + return nil // Returning nil instead of *waitingPod(nil). +} + +// RejectWaitingPod rejects a WaitingPod given its UID. +// The returned value indicates if the given pod is waiting or not. +func (f *frameworkImpl) RejectWaitingPod(uid types.UID) bool { + if waitingPod := f.waitingPods.get(uid); waitingPod != nil { + waitingPod.Reject("", "removed") + return true + } + return false +} + +// HasFilterPlugins returns true if at least one filter plugin is defined. +func (f *frameworkImpl) HasFilterPlugins() bool { + return len(f.filterPlugins) > 0 +} + +// HasPostFilterPlugins returns true if at least one postFilter plugin is defined. +func (f *frameworkImpl) HasPostFilterPlugins() bool { + return len(f.postFilterPlugins) > 0 +} + +// HasScorePlugins returns true if at least one score plugin is defined. +func (f *frameworkImpl) HasScorePlugins() bool { + return len(f.scorePlugins) > 0 +} + +// ListPlugins returns a map of extension point name to plugin names configured at each extension +// point. Returns nil if no plugins where configured. +func (f *frameworkImpl) ListPlugins() *config.Plugins { + m := config.Plugins{} + + for _, e := range f.getExtensionPoints(&m) { + plugins := reflect.ValueOf(e.slicePtr).Elem() + extName := plugins.Type().Elem().Name() + var cfgs []config.Plugin + for i := 0; i < plugins.Len(); i++ { + name := plugins.Index(i).Interface().(framework.Plugin).Name() + p := config.Plugin{Name: name} + if extName == "ScorePlugin" { + // Weights apply only to score plugins. + p.Weight = int32(f.scorePluginWeight[name]) + } + cfgs = append(cfgs, p) + } + if len(cfgs) > 0 { + e.plugins.Enabled = cfgs + } + } + return &m +} + +// ClientSet returns a kubernetes clientset. +func (f *frameworkImpl) ClientSet() clientset.Interface { + return f.clientSet +} + +// KubeConfig returns a kubernetes config. +func (f *frameworkImpl) KubeConfig() *restclient.Config { + return f.kubeConfig +} + +// EventRecorder returns an event recorder. +func (f *frameworkImpl) EventRecorder() events.EventRecorder { + return f.eventRecorder +} + +// SharedInformerFactory returns a shared informer factory. +func (f *frameworkImpl) SharedInformerFactory() informers.SharedInformerFactory { + return f.informerFactory +} + +func (f *frameworkImpl) pluginsNeeded(plugins *config.Plugins) sets.String { + pgSet := sets.String{} + + if plugins == nil { + return pgSet + } + + find := func(pgs *config.PluginSet) { + for _, pg := range pgs.Enabled { + pgSet.Insert(pg.Name) + } + } + + for _, e := range f.getExtensionPoints(plugins) { + find(e.plugins) + } + // Parse MultiPoint separately since they are not returned by f.getExtensionPoints() + find(&plugins.MultiPoint) + + return pgSet +} + +// ProfileName returns the profile name associated to this framework. +func (f *frameworkImpl) ProfileName() string { + return f.profileName +} + +// PercentageOfNodesToScore returns percentageOfNodesToScore associated to a profile. +func (f *frameworkImpl) PercentageOfNodesToScore() *int32 { + return f.percentageOfNodesToScore +} + +// Parallelizer returns a parallelizer holding parallelism for scheduler. +func (f *frameworkImpl) Parallelizer() parallelize.Parallelizer { + return f.parallelizer +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/runtime/metrics_recorder.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/runtime/metrics_recorder.go new file mode 100644 index 000000000..23b25fa3b --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/runtime/metrics_recorder.go @@ -0,0 +1,101 @@ +/* +Copyright 2019 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 runtime + +import ( + "time" + + k8smetrics "k8s.io/component-base/metrics" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/metrics" +) + +// frameworkMetric is the data structure passed in the buffer channel between the main framework thread +// and the metricsRecorder goroutine. +type frameworkMetric struct { + metric *k8smetrics.HistogramVec + labelValues []string + value float64 +} + +// metricRecorder records framework metrics in a separate goroutine to avoid overhead in the critical path. +type metricsRecorder struct { + // bufferCh is a channel that serves as a metrics buffer before the metricsRecorder goroutine reports it. + bufferCh chan *frameworkMetric + // if bufferSize is reached, incoming metrics will be discarded. + bufferSize int + // how often the recorder runs to flush the metrics. + interval time.Duration + + // stopCh is used to stop the goroutine which periodically flushes metrics. + stopCh <-chan struct{} + // isStoppedCh indicates whether the goroutine is stopped. It's used in tests only to make sure + // the metric flushing goroutine is stopped so that tests can collect metrics for verification. + isStoppedCh chan struct{} +} + +func newMetricsRecorder(bufferSize int, interval time.Duration, stopCh <-chan struct{}) *metricsRecorder { + recorder := &metricsRecorder{ + bufferCh: make(chan *frameworkMetric, bufferSize), + bufferSize: bufferSize, + interval: interval, + stopCh: stopCh, + isStoppedCh: make(chan struct{}), + } + go recorder.run() + return recorder +} + +// observePluginDurationAsync observes the plugin_execution_duration_seconds metric. +// The metric will be flushed to Prometheus asynchronously. +func (r *metricsRecorder) observePluginDurationAsync(extensionPoint, pluginName string, status *framework.Status, value float64) { + newMetric := &frameworkMetric{ + metric: metrics.PluginExecutionDuration, + labelValues: []string{pluginName, extensionPoint, status.Code().String()}, + value: value, + } + select { + case r.bufferCh <- newMetric: + default: + } +} + +// run flushes buffered metrics into Prometheus every second. +func (r *metricsRecorder) run() { + for { + select { + case <-r.stopCh: + close(r.isStoppedCh) + return + default: + } + r.flushMetrics() + time.Sleep(r.interval) + } +} + +// flushMetrics tries to clean up the bufferCh by reading at most bufferSize metrics. +func (r *metricsRecorder) flushMetrics() { + for i := 0; i < r.bufferSize; i++ { + select { + case m := <-r.bufferCh: + m.metric.WithLabelValues(m.labelValues...).Observe(m.value) + default: + return + } + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/runtime/registry.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/runtime/registry.go new file mode 100644 index 000000000..b0b1d8557 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/runtime/registry.go @@ -0,0 +1,100 @@ +/* +Copyright 2019 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 runtime + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/json" + "k8s.io/kubernetes/pkg/scheduler/framework" + plfeature "k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature" + "sigs.k8s.io/yaml" +) + +// PluginFactory is a function that builds a plugin. +type PluginFactory = func(configuration runtime.Object, f framework.Handle) (framework.Plugin, error) + +// PluginFactoryWithFts is a function that builds a plugin with certain feature gates. +type PluginFactoryWithFts func(runtime.Object, framework.Handle, plfeature.Features) (framework.Plugin, error) + +// FactoryAdapter can be used to inject feature gates for a plugin that needs +// them when the caller expects the older PluginFactory method. +func FactoryAdapter(fts plfeature.Features, withFts PluginFactoryWithFts) PluginFactory { + return func(plArgs runtime.Object, fh framework.Handle) (framework.Plugin, error) { + return withFts(plArgs, fh, fts) + } +} + +// DecodeInto decodes configuration whose type is *runtime.Unknown to the interface into. +func DecodeInto(obj runtime.Object, into interface{}) error { + if obj == nil { + return nil + } + configuration, ok := obj.(*runtime.Unknown) + if !ok { + return fmt.Errorf("want args of type runtime.Unknown, got %T", obj) + } + if configuration.Raw == nil { + return nil + } + + switch configuration.ContentType { + // If ContentType is empty, it means ContentTypeJSON by default. + case runtime.ContentTypeJSON, "": + return json.Unmarshal(configuration.Raw, into) + case runtime.ContentTypeYAML: + return yaml.Unmarshal(configuration.Raw, into) + default: + return fmt.Errorf("not supported content type %s", configuration.ContentType) + } +} + +// Registry is a collection of all available plugins. The framework uses a +// registry to enable and initialize configured plugins. +// All plugins must be in the registry before initializing the framework. +type Registry map[string]PluginFactory + +// Register adds a new plugin to the registry. If a plugin with the same name +// exists, it returns an error. +func (r Registry) Register(name string, factory PluginFactory) error { + if _, ok := r[name]; ok { + return fmt.Errorf("a plugin named %v already exists", name) + } + r[name] = factory + return nil +} + +// Unregister removes an existing plugin from the registry. If no plugin with +// the provided name exists, it returns an error. +func (r Registry) Unregister(name string) error { + if _, ok := r[name]; !ok { + return fmt.Errorf("no plugin named %v exists", name) + } + delete(r, name) + return nil +} + +// Merge merges the provided registry to the current one. +func (r Registry) Merge(in Registry) error { + for name, factory := range in { + if err := r.Register(name, factory); err != nil { + return err + } + } + return nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/runtime/waiting_pods_map.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/runtime/waiting_pods_map.go new file mode 100644 index 000000000..d5df63974 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/runtime/waiting_pods_map.go @@ -0,0 +1,165 @@ +/* +Copyright 2019 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 runtime + +import ( + "fmt" + "sync" + "time" + + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/kubernetes/pkg/scheduler/framework" +) + +// waitingPodsMap a thread-safe map used to maintain pods waiting in the permit phase. +type waitingPodsMap struct { + pods map[types.UID]*waitingPod + mu sync.RWMutex +} + +// newWaitingPodsMap returns a new waitingPodsMap. +func newWaitingPodsMap() *waitingPodsMap { + return &waitingPodsMap{ + pods: make(map[types.UID]*waitingPod), + } +} + +// add a new WaitingPod to the map. +func (m *waitingPodsMap) add(wp *waitingPod) { + m.mu.Lock() + defer m.mu.Unlock() + m.pods[wp.GetPod().UID] = wp +} + +// remove a WaitingPod from the map. +func (m *waitingPodsMap) remove(uid types.UID) { + m.mu.Lock() + defer m.mu.Unlock() + delete(m.pods, uid) +} + +// get a WaitingPod from the map. +func (m *waitingPodsMap) get(uid types.UID) *waitingPod { + m.mu.RLock() + defer m.mu.RUnlock() + return m.pods[uid] +} + +// iterate acquires a read lock and iterates over the WaitingPods map. +func (m *waitingPodsMap) iterate(callback func(framework.WaitingPod)) { + m.mu.RLock() + defer m.mu.RUnlock() + for _, v := range m.pods { + callback(v) + } +} + +// waitingPod represents a pod waiting in the permit phase. +type waitingPod struct { + pod *v1.Pod + pendingPlugins map[string]*time.Timer + s chan *framework.Status + mu sync.RWMutex +} + +var _ framework.WaitingPod = &waitingPod{} + +// newWaitingPod returns a new waitingPod instance. +func newWaitingPod(pod *v1.Pod, pluginsMaxWaitTime map[string]time.Duration) *waitingPod { + wp := &waitingPod{ + pod: pod, + // Allow() and Reject() calls are non-blocking. This property is guaranteed + // by using non-blocking send to this channel. This channel has a buffer of size 1 + // to ensure that non-blocking send will not be ignored - possible situation when + // receiving from this channel happens after non-blocking send. + s: make(chan *framework.Status, 1), + } + + wp.pendingPlugins = make(map[string]*time.Timer, len(pluginsMaxWaitTime)) + // The time.AfterFunc calls wp.Reject which iterates through pendingPlugins map. Acquire the + // lock here so that time.AfterFunc can only execute after newWaitingPod finishes. + wp.mu.Lock() + defer wp.mu.Unlock() + for k, v := range pluginsMaxWaitTime { + plugin, waitTime := k, v + wp.pendingPlugins[plugin] = time.AfterFunc(waitTime, func() { + msg := fmt.Sprintf("rejected due to timeout after waiting %v at plugin %v", + waitTime, plugin) + wp.Reject(plugin, msg) + }) + } + + return wp +} + +// GetPod returns a reference to the waiting pod. +func (w *waitingPod) GetPod() *v1.Pod { + return w.pod +} + +// GetPendingPlugins returns a list of pending permit plugin's name. +func (w *waitingPod) GetPendingPlugins() []string { + w.mu.RLock() + defer w.mu.RUnlock() + plugins := make([]string, 0, len(w.pendingPlugins)) + for p := range w.pendingPlugins { + plugins = append(plugins, p) + } + + return plugins +} + +// Allow declares the waiting pod is allowed to be scheduled by plugin pluginName. +// If this is the last remaining plugin to allow, then a success signal is delivered +// to unblock the pod. +func (w *waitingPod) Allow(pluginName string) { + w.mu.Lock() + defer w.mu.Unlock() + if timer, exist := w.pendingPlugins[pluginName]; exist { + timer.Stop() + delete(w.pendingPlugins, pluginName) + } + + // Only signal success status after all plugins have allowed + if len(w.pendingPlugins) != 0 { + return + } + + // The select clause works as a non-blocking send. + // If there is no receiver, it's a no-op (default case). + select { + case w.s <- framework.NewStatus(framework.Success, ""): + default: + } +} + +// Reject declares the waiting pod unschedulable. +func (w *waitingPod) Reject(pluginName, msg string) { + w.mu.RLock() + defer w.mu.RUnlock() + for _, timer := range w.pendingPlugins { + timer.Stop() + } + + // The select clause works as a non-blocking send. + // If there is no receiver, it's a no-op (default case). + select { + case w.s <- framework.NewStatus(framework.Unschedulable, msg).WithFailedPlugin(pluginName): + default: + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/types.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/types.go new file mode 100644 index 000000000..b15a6064f --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/types.go @@ -0,0 +1,929 @@ +/* +Copyright 2015 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 framework + +import ( + "errors" + "fmt" + "sort" + "strings" + "sync/atomic" + "time" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/klog/v2" + schedutil "k8s.io/kubernetes/pkg/scheduler/util" +) + +var generation int64 + +// ActionType is an integer to represent one type of resource change. +// Different ActionTypes can be bit-wised to compose new semantics. +type ActionType int64 + +// Constants for ActionTypes. +const ( + Add ActionType = 1 << iota // 1 + Delete // 10 + // UpdateNodeXYZ is only applicable for Node events. + UpdateNodeAllocatable // 100 + UpdateNodeLabel // 1000 + UpdateNodeTaint // 10000 + UpdateNodeCondition // 100000 + + All ActionType = 1<. . ." +func (f *FitError) Error() string { + reasons := make(map[string]int) + for _, status := range f.Diagnosis.NodeToStatusMap { + for _, reason := range status.Reasons() { + reasons[reason]++ + } + } + + reasonMsg := fmt.Sprintf(NoNodeAvailableMsg+":", f.NumAllNodes) + // Add the messages from PreFilter plugins to reasonMsg. + preFilterMsg := f.Diagnosis.PreFilterMsg + if preFilterMsg != "" { + reasonMsg += fmt.Sprintf(SeparatorFormat, preFilterMsg) + } + sortReasonsHistogram := func() []string { + var reasonStrings []string + for k, v := range reasons { + reasonStrings = append(reasonStrings, fmt.Sprintf("%v %v", v, k)) + } + sort.Strings(reasonStrings) + return reasonStrings + } + sortedFilterMsg := sortReasonsHistogram() + if len(sortedFilterMsg) != 0 { + reasonMsg += fmt.Sprintf(SeparatorFormat, strings.Join(sortedFilterMsg, ", ")) + } + // Add the messages from PostFilter plugins to reasonMsg. + postFilterMsg := f.Diagnosis.PostFilterMsg + if postFilterMsg != "" { + reasonMsg += fmt.Sprintf(SeparatorFormat, postFilterMsg) + } + return reasonMsg +} + +func newAffinityTerm(pod *v1.Pod, term *v1.PodAffinityTerm) (*AffinityTerm, error) { + selector, err := metav1.LabelSelectorAsSelector(term.LabelSelector) + if err != nil { + return nil, err + } + + namespaces := getNamespacesFromPodAffinityTerm(pod, term) + nsSelector, err := metav1.LabelSelectorAsSelector(term.NamespaceSelector) + if err != nil { + return nil, err + } + + return &AffinityTerm{Namespaces: namespaces, Selector: selector, TopologyKey: term.TopologyKey, NamespaceSelector: nsSelector}, nil +} + +// getAffinityTerms receives a Pod and affinity terms and returns the namespaces and +// selectors of the terms. +func getAffinityTerms(pod *v1.Pod, v1Terms []v1.PodAffinityTerm) ([]AffinityTerm, error) { + if v1Terms == nil { + return nil, nil + } + + var terms []AffinityTerm + for i := range v1Terms { + t, err := newAffinityTerm(pod, &v1Terms[i]) + if err != nil { + // We get here if the label selector failed to process + return nil, err + } + terms = append(terms, *t) + } + return terms, nil +} + +// getWeightedAffinityTerms returns the list of processed affinity terms. +func getWeightedAffinityTerms(pod *v1.Pod, v1Terms []v1.WeightedPodAffinityTerm) ([]WeightedAffinityTerm, error) { + if v1Terms == nil { + return nil, nil + } + + var terms []WeightedAffinityTerm + for i := range v1Terms { + t, err := newAffinityTerm(pod, &v1Terms[i].PodAffinityTerm) + if err != nil { + // We get here if the label selector failed to process + return nil, err + } + terms = append(terms, WeightedAffinityTerm{AffinityTerm: *t, Weight: v1Terms[i].Weight}) + } + return terms, nil +} + +// NewPodInfo returns a new PodInfo. +func NewPodInfo(pod *v1.Pod) (*PodInfo, error) { + pInfo := &PodInfo{} + err := pInfo.Update(pod) + return pInfo, err +} + +func getPodAffinityTerms(affinity *v1.Affinity) (terms []v1.PodAffinityTerm) { + if affinity != nil && affinity.PodAffinity != nil { + if len(affinity.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution) != 0 { + terms = affinity.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution + } + // TODO: Uncomment this block when implement RequiredDuringSchedulingRequiredDuringExecution. + // if len(affinity.PodAffinity.RequiredDuringSchedulingRequiredDuringExecution) != 0 { + // terms = append(terms, affinity.PodAffinity.RequiredDuringSchedulingRequiredDuringExecution...) + // } + } + return terms +} + +func getPodAntiAffinityTerms(affinity *v1.Affinity) (terms []v1.PodAffinityTerm) { + if affinity != nil && affinity.PodAntiAffinity != nil { + if len(affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution) != 0 { + terms = affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution + } + // TODO: Uncomment this block when implement RequiredDuringSchedulingRequiredDuringExecution. + // if len(affinity.PodAntiAffinity.RequiredDuringSchedulingRequiredDuringExecution) != 0 { + // terms = append(terms, affinity.PodAntiAffinity.RequiredDuringSchedulingRequiredDuringExecution...) + // } + } + return terms +} + +// returns a set of names according to the namespaces indicated in podAffinityTerm. +// If namespaces is empty it considers the given pod's namespace. +func getNamespacesFromPodAffinityTerm(pod *v1.Pod, podAffinityTerm *v1.PodAffinityTerm) sets.String { + names := sets.String{} + if len(podAffinityTerm.Namespaces) == 0 && podAffinityTerm.NamespaceSelector == nil { + names.Insert(pod.Namespace) + } else { + names.Insert(podAffinityTerm.Namespaces...) + } + return names +} + +// ImageStateSummary provides summarized information about the state of an image. +type ImageStateSummary struct { + // Size of the image + Size int64 + // Used to track how many nodes have this image + NumNodes int +} + +// NodeInfo is node level aggregated information. +type NodeInfo struct { + // Overall node information. + node *v1.Node + + // Pods running on the node. + Pods []*PodInfo + + // The subset of pods with affinity. + PodsWithAffinity []*PodInfo + + // The subset of pods with required anti-affinity. + PodsWithRequiredAntiAffinity []*PodInfo + + // Ports allocated on the node. + UsedPorts HostPortInfo + + // Total requested resources of all pods on this node. This includes assumed + // pods, which scheduler has sent for binding, but may not be scheduled yet. + Requested *Resource + // Total requested resources of all pods on this node with a minimum value + // applied to each container's CPU and memory requests. This does not reflect + // the actual resource requests for this node, but is used to avoid scheduling + // many zero-request pods onto one node. + NonZeroRequested *Resource + // We store allocatedResources (which is Node.Status.Allocatable.*) explicitly + // as int64, to avoid conversions and accessing map. + Allocatable *Resource + + // ImageStates holds the entry of an image if and only if this image is on the node. The entry can be used for + // checking an image's existence and advanced usage (e.g., image locality scheduling policy) based on the image + // state information. + ImageStates map[string]*ImageStateSummary + + // PVCRefCounts contains a mapping of PVC names to the number of pods on the node using it. + // Keys are in the format "namespace/name". + PVCRefCounts map[string]int + + // Whenever NodeInfo changes, generation is bumped. + // This is used to avoid cloning it if the object didn't change. + Generation int64 +} + +// nextGeneration: Let's make sure history never forgets the name... +// Increments the generation number monotonically ensuring that generation numbers never collide. +// Collision of the generation numbers would be particularly problematic if a node was deleted and +// added back with the same name. See issue#63262. +func nextGeneration() int64 { + return atomic.AddInt64(&generation, 1) +} + +// Resource is a collection of compute resource. +type Resource struct { + MilliCPU int64 + Memory int64 + EphemeralStorage int64 + // We store allowedPodNumber (which is Node.Status.Allocatable.Pods().Value()) + // explicitly as int, to avoid conversions and improve performance. + AllowedPodNumber int + // ScalarResources + ScalarResources map[v1.ResourceName]int64 +} + +// NewResource creates a Resource from ResourceList +func NewResource(rl v1.ResourceList) *Resource { + r := &Resource{} + r.Add(rl) + return r +} + +// Add adds ResourceList into Resource. +func (r *Resource) Add(rl v1.ResourceList) { + if r == nil { + return + } + + for rName, rQuant := range rl { + switch rName { + case v1.ResourceCPU: + r.MilliCPU += rQuant.MilliValue() + case v1.ResourceMemory: + r.Memory += rQuant.Value() + case v1.ResourcePods: + r.AllowedPodNumber += int(rQuant.Value()) + case v1.ResourceEphemeralStorage: + r.EphemeralStorage += rQuant.Value() + default: + if schedutil.IsScalarResourceName(rName) { + r.AddScalar(rName, rQuant.Value()) + } + } + } +} + +// Clone returns a copy of this resource. +func (r *Resource) Clone() *Resource { + res := &Resource{ + MilliCPU: r.MilliCPU, + Memory: r.Memory, + AllowedPodNumber: r.AllowedPodNumber, + EphemeralStorage: r.EphemeralStorage, + } + if r.ScalarResources != nil { + res.ScalarResources = make(map[v1.ResourceName]int64) + for k, v := range r.ScalarResources { + res.ScalarResources[k] = v + } + } + return res +} + +// AddScalar adds a resource by a scalar value of this resource. +func (r *Resource) AddScalar(name v1.ResourceName, quantity int64) { + r.SetScalar(name, r.ScalarResources[name]+quantity) +} + +// SetScalar sets a resource by a scalar value of this resource. +func (r *Resource) SetScalar(name v1.ResourceName, quantity int64) { + // Lazily allocate scalar resource map. + if r.ScalarResources == nil { + r.ScalarResources = map[v1.ResourceName]int64{} + } + r.ScalarResources[name] = quantity +} + +// SetMaxResource compares with ResourceList and takes max value for each Resource. +func (r *Resource) SetMaxResource(rl v1.ResourceList) { + if r == nil { + return + } + + for rName, rQuantity := range rl { + switch rName { + case v1.ResourceMemory: + r.Memory = max(r.Memory, rQuantity.Value()) + case v1.ResourceCPU: + r.MilliCPU = max(r.MilliCPU, rQuantity.MilliValue()) + case v1.ResourceEphemeralStorage: + r.EphemeralStorage = max(r.EphemeralStorage, rQuantity.Value()) + default: + if schedutil.IsScalarResourceName(rName) { + r.SetScalar(rName, max(r.ScalarResources[rName], rQuantity.Value())) + } + } + } +} + +// NewNodeInfo returns a ready to use empty NodeInfo object. +// If any pods are given in arguments, their information will be aggregated in +// the returned object. +func NewNodeInfo(pods ...*v1.Pod) *NodeInfo { + ni := &NodeInfo{ + Requested: &Resource{}, + NonZeroRequested: &Resource{}, + Allocatable: &Resource{}, + Generation: nextGeneration(), + UsedPorts: make(HostPortInfo), + ImageStates: make(map[string]*ImageStateSummary), + PVCRefCounts: make(map[string]int), + } + for _, pod := range pods { + ni.AddPod(pod) + } + return ni +} + +// Node returns overall information about this node. +func (n *NodeInfo) Node() *v1.Node { + if n == nil { + return nil + } + return n.node +} + +// Clone returns a copy of this node. +func (n *NodeInfo) Clone() *NodeInfo { + clone := &NodeInfo{ + node: n.node, + Requested: n.Requested.Clone(), + NonZeroRequested: n.NonZeroRequested.Clone(), + Allocatable: n.Allocatable.Clone(), + UsedPorts: make(HostPortInfo), + ImageStates: n.ImageStates, + PVCRefCounts: make(map[string]int), + Generation: n.Generation, + } + if len(n.Pods) > 0 { + clone.Pods = append([]*PodInfo(nil), n.Pods...) + } + if len(n.UsedPorts) > 0 { + // HostPortInfo is a map-in-map struct + // make sure it's deep copied + for ip, portMap := range n.UsedPorts { + clone.UsedPorts[ip] = make(map[ProtocolPort]struct{}) + for protocolPort, v := range portMap { + clone.UsedPorts[ip][protocolPort] = v + } + } + } + if len(n.PodsWithAffinity) > 0 { + clone.PodsWithAffinity = append([]*PodInfo(nil), n.PodsWithAffinity...) + } + if len(n.PodsWithRequiredAntiAffinity) > 0 { + clone.PodsWithRequiredAntiAffinity = append([]*PodInfo(nil), n.PodsWithRequiredAntiAffinity...) + } + for key, value := range n.PVCRefCounts { + clone.PVCRefCounts[key] = value + } + return clone +} + +// String returns representation of human readable format of this NodeInfo. +func (n *NodeInfo) String() string { + podKeys := make([]string, len(n.Pods)) + for i, p := range n.Pods { + podKeys[i] = p.Pod.Name + } + return fmt.Sprintf("&NodeInfo{Pods:%v, RequestedResource:%#v, NonZeroRequest: %#v, UsedPort: %#v, AllocatableResource:%#v}", + podKeys, n.Requested, n.NonZeroRequested, n.UsedPorts, n.Allocatable) +} + +// AddPodInfo adds pod information to this NodeInfo. +// Consider using this instead of AddPod if a PodInfo is already computed. +func (n *NodeInfo) AddPodInfo(podInfo *PodInfo) { + n.Pods = append(n.Pods, podInfo) + if podWithAffinity(podInfo.Pod) { + n.PodsWithAffinity = append(n.PodsWithAffinity, podInfo) + } + if podWithRequiredAntiAffinity(podInfo.Pod) { + n.PodsWithRequiredAntiAffinity = append(n.PodsWithRequiredAntiAffinity, podInfo) + } + n.update(podInfo.Pod, 1) +} + +// AddPod is a wrapper around AddPodInfo. +func (n *NodeInfo) AddPod(pod *v1.Pod) { + // ignore this err since apiserver doesn't properly validate affinity terms + // and we can't fix the validation for backwards compatibility. + podInfo, _ := NewPodInfo(pod) + n.AddPodInfo(podInfo) +} + +func podWithAffinity(p *v1.Pod) bool { + affinity := p.Spec.Affinity + return affinity != nil && (affinity.PodAffinity != nil || affinity.PodAntiAffinity != nil) +} + +func podWithRequiredAntiAffinity(p *v1.Pod) bool { + affinity := p.Spec.Affinity + return affinity != nil && affinity.PodAntiAffinity != nil && + len(affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution) != 0 +} + +func removeFromSlice(s []*PodInfo, k string) []*PodInfo { + for i := range s { + k2, err := GetPodKey(s[i].Pod) + if err != nil { + klog.ErrorS(err, "Cannot get pod key", "pod", klog.KObj(s[i].Pod)) + continue + } + if k == k2 { + // delete the element + s[i] = s[len(s)-1] + s = s[:len(s)-1] + break + } + } + return s +} + +// RemovePod subtracts pod information from this NodeInfo. +func (n *NodeInfo) RemovePod(pod *v1.Pod) error { + k, err := GetPodKey(pod) + if err != nil { + return err + } + if podWithAffinity(pod) { + n.PodsWithAffinity = removeFromSlice(n.PodsWithAffinity, k) + } + if podWithRequiredAntiAffinity(pod) { + n.PodsWithRequiredAntiAffinity = removeFromSlice(n.PodsWithRequiredAntiAffinity, k) + } + + for i := range n.Pods { + k2, err := GetPodKey(n.Pods[i].Pod) + if err != nil { + klog.ErrorS(err, "Cannot get pod key", "pod", klog.KObj(n.Pods[i].Pod)) + continue + } + if k == k2 { + // delete the element + n.Pods[i] = n.Pods[len(n.Pods)-1] + n.Pods = n.Pods[:len(n.Pods)-1] + + n.update(pod, -1) + n.resetSlicesIfEmpty() + return nil + } + } + return fmt.Errorf("no corresponding pod %s in pods of node %s", pod.Name, n.node.Name) +} + +// update node info based on the pod and sign. +// The sign will be set to `+1` when AddPod and to `-1` when RemovePod. +func (n *NodeInfo) update(pod *v1.Pod, sign int64) { + res, non0CPU, non0Mem := calculateResource(pod) + n.Requested.MilliCPU += sign * res.MilliCPU + n.Requested.Memory += sign * res.Memory + n.Requested.EphemeralStorage += sign * res.EphemeralStorage + if n.Requested.ScalarResources == nil && len(res.ScalarResources) > 0 { + n.Requested.ScalarResources = map[v1.ResourceName]int64{} + } + for rName, rQuant := range res.ScalarResources { + n.Requested.ScalarResources[rName] += sign * rQuant + } + n.NonZeroRequested.MilliCPU += sign * non0CPU + n.NonZeroRequested.Memory += sign * non0Mem + + // Consume ports when pod added or release ports when pod removed. + n.updateUsedPorts(pod, sign > 0) + n.updatePVCRefCounts(pod, sign > 0) + + n.Generation = nextGeneration() +} + +// resets the slices to nil so that we can do DeepEqual in unit tests. +func (n *NodeInfo) resetSlicesIfEmpty() { + if len(n.PodsWithAffinity) == 0 { + n.PodsWithAffinity = nil + } + if len(n.PodsWithRequiredAntiAffinity) == 0 { + n.PodsWithRequiredAntiAffinity = nil + } + if len(n.Pods) == 0 { + n.Pods = nil + } +} + +func max(a, b int64) int64 { + if a >= b { + return a + } + return b +} + +// resourceRequest = max(sum(podSpec.Containers), podSpec.InitContainers) + overHead +func calculateResource(pod *v1.Pod) (res Resource, non0CPU int64, non0Mem int64) { + resPtr := &res + for _, c := range pod.Spec.Containers { + resPtr.Add(c.Resources.Requests) + non0CPUReq, non0MemReq := schedutil.GetNonzeroRequests(&c.Resources.Requests) + non0CPU += non0CPUReq + non0Mem += non0MemReq + // No non-zero resources for GPUs or opaque resources. + } + + for _, ic := range pod.Spec.InitContainers { + resPtr.SetMaxResource(ic.Resources.Requests) + non0CPUReq, non0MemReq := schedutil.GetNonzeroRequests(&ic.Resources.Requests) + non0CPU = max(non0CPU, non0CPUReq) + non0Mem = max(non0Mem, non0MemReq) + } + + // If Overhead is being utilized, add to the total requests for the pod + if pod.Spec.Overhead != nil { + resPtr.Add(pod.Spec.Overhead) + if _, found := pod.Spec.Overhead[v1.ResourceCPU]; found { + non0CPU += pod.Spec.Overhead.Cpu().MilliValue() + } + + if _, found := pod.Spec.Overhead[v1.ResourceMemory]; found { + non0Mem += pod.Spec.Overhead.Memory().Value() + } + } + + return +} + +// updateUsedPorts updates the UsedPorts of NodeInfo. +func (n *NodeInfo) updateUsedPorts(pod *v1.Pod, add bool) { + for _, container := range pod.Spec.Containers { + for _, podPort := range container.Ports { + if add { + n.UsedPorts.Add(podPort.HostIP, string(podPort.Protocol), podPort.HostPort) + } else { + n.UsedPorts.Remove(podPort.HostIP, string(podPort.Protocol), podPort.HostPort) + } + } + } +} + +// updatePVCRefCounts updates the PVCRefCounts of NodeInfo. +func (n *NodeInfo) updatePVCRefCounts(pod *v1.Pod, add bool) { + for _, v := range pod.Spec.Volumes { + if v.PersistentVolumeClaim == nil { + continue + } + + key := GetNamespacedName(pod.Namespace, v.PersistentVolumeClaim.ClaimName) + if add { + n.PVCRefCounts[key] += 1 + } else { + n.PVCRefCounts[key] -= 1 + if n.PVCRefCounts[key] <= 0 { + delete(n.PVCRefCounts, key) + } + } + } +} + +// SetNode sets the overall node information. +func (n *NodeInfo) SetNode(node *v1.Node) { + n.node = node + n.Allocatable = NewResource(node.Status.Allocatable) + n.Generation = nextGeneration() +} + +// RemoveNode removes the node object, leaving all other tracking information. +func (n *NodeInfo) RemoveNode() { + n.node = nil + n.Generation = nextGeneration() +} + +// GetPodKey returns the string key of a pod. +func GetPodKey(pod *v1.Pod) (string, error) { + uid := string(pod.UID) + if len(uid) == 0 { + return "", errors.New("cannot get cache key for pod with empty UID") + } + return uid, nil +} + +// GetNamespacedName returns the string format of a namespaced resource name. +func GetNamespacedName(namespace, name string) string { + return fmt.Sprintf("%s/%s", namespace, name) +} + +// DefaultBindAllHostIP defines the default ip address used to bind to all host. +const DefaultBindAllHostIP = "0.0.0.0" + +// ProtocolPort represents a protocol port pair, e.g. tcp:80. +type ProtocolPort struct { + Protocol string + Port int32 +} + +// NewProtocolPort creates a ProtocolPort instance. +func NewProtocolPort(protocol string, port int32) *ProtocolPort { + pp := &ProtocolPort{ + Protocol: protocol, + Port: port, + } + + if len(pp.Protocol) == 0 { + pp.Protocol = string(v1.ProtocolTCP) + } + + return pp +} + +// HostPortInfo stores mapping from ip to a set of ProtocolPort +type HostPortInfo map[string]map[ProtocolPort]struct{} + +// Add adds (ip, protocol, port) to HostPortInfo +func (h HostPortInfo) Add(ip, protocol string, port int32) { + if port <= 0 { + return + } + + h.sanitize(&ip, &protocol) + + pp := NewProtocolPort(protocol, port) + if _, ok := h[ip]; !ok { + h[ip] = map[ProtocolPort]struct{}{ + *pp: {}, + } + return + } + + h[ip][*pp] = struct{}{} +} + +// Remove removes (ip, protocol, port) from HostPortInfo +func (h HostPortInfo) Remove(ip, protocol string, port int32) { + if port <= 0 { + return + } + + h.sanitize(&ip, &protocol) + + pp := NewProtocolPort(protocol, port) + if m, ok := h[ip]; ok { + delete(m, *pp) + if len(h[ip]) == 0 { + delete(h, ip) + } + } +} + +// Len returns the total number of (ip, protocol, port) tuple in HostPortInfo +func (h HostPortInfo) Len() int { + length := 0 + for _, m := range h { + length += len(m) + } + return length +} + +// CheckConflict checks if the input (ip, protocol, port) conflicts with the existing +// ones in HostPortInfo. +func (h HostPortInfo) CheckConflict(ip, protocol string, port int32) bool { + if port <= 0 { + return false + } + + h.sanitize(&ip, &protocol) + + pp := NewProtocolPort(protocol, port) + + // If ip is 0.0.0.0 check all IP's (protocol, port) pair + if ip == DefaultBindAllHostIP { + for _, m := range h { + if _, ok := m[*pp]; ok { + return true + } + } + return false + } + + // If ip isn't 0.0.0.0, only check IP and 0.0.0.0's (protocol, port) pair + for _, key := range []string{DefaultBindAllHostIP, ip} { + if m, ok := h[key]; ok { + if _, ok2 := m[*pp]; ok2 { + return true + } + } + } + + return false +} + +// sanitize the parameters +func (h HostPortInfo) sanitize(ip, protocol *string) { + if len(*ip) == 0 { + *ip = DefaultBindAllHostIP + } + if len(*protocol) == 0 { + *protocol = string(v1.ProtocolTCP) + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/cache.go b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/cache.go new file mode 100644 index 000000000..041bf4178 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/cache.go @@ -0,0 +1,770 @@ +/* +Copyright 2015 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 cache + +import ( + "fmt" + "sync" + "time" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/klog/v2" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/metrics" +) + +var ( + cleanAssumedPeriod = 1 * time.Second +) + +// New returns a Cache implementation. +// It automatically starts a go routine that manages expiration of assumed pods. +// "ttl" is how long the assumed pod will get expired, "0" means pod will never expire. +// "stop" is the channel that would close the background goroutine. +func New(ttl time.Duration, stop <-chan struct{}) Cache { + cache := newCache(ttl, cleanAssumedPeriod, stop) + cache.run() + return cache +} + +// nodeInfoListItem holds a NodeInfo pointer and acts as an item in a doubly +// linked list. When a NodeInfo is updated, it goes to the head of the list. +// The items closer to the head are the most recently updated items. +type nodeInfoListItem struct { + info *framework.NodeInfo + next *nodeInfoListItem + prev *nodeInfoListItem +} + +type cacheImpl struct { + stop <-chan struct{} + ttl time.Duration + period time.Duration + + // This mutex guards all fields within this cache struct. + mu sync.RWMutex + // a set of assumed pod keys. + // The key could further be used to get an entry in podStates. + assumedPods sets.String + // a map from pod key to podState. + podStates map[string]*podState + nodes map[string]*nodeInfoListItem + // headNode points to the most recently updated NodeInfo in "nodes". It is the + // head of the linked list. + headNode *nodeInfoListItem + nodeTree *nodeTree + // A map from image name to its imageState. + imageStates map[string]*imageState +} + +type podState struct { + pod *v1.Pod + // Used by assumedPod to determinate expiration. + // If deadline is nil, assumedPod will never expire. + deadline *time.Time + // Used to block cache from expiring assumedPod if binding still runs + bindingFinished bool +} + +type imageState struct { + // Size of the image + size int64 + // A set of node names for nodes having this image present + nodes sets.String +} + +// createImageStateSummary returns a summarizing snapshot of the given image's state. +func (cache *cacheImpl) createImageStateSummary(state *imageState) *framework.ImageStateSummary { + return &framework.ImageStateSummary{ + Size: state.size, + NumNodes: len(state.nodes), + } +} + +func newCache(ttl, period time.Duration, stop <-chan struct{}) *cacheImpl { + return &cacheImpl{ + ttl: ttl, + period: period, + stop: stop, + + nodes: make(map[string]*nodeInfoListItem), + nodeTree: newNodeTree(nil), + assumedPods: make(sets.String), + podStates: make(map[string]*podState), + imageStates: make(map[string]*imageState), + } +} + +// newNodeInfoListItem initializes a new nodeInfoListItem. +func newNodeInfoListItem(ni *framework.NodeInfo) *nodeInfoListItem { + return &nodeInfoListItem{ + info: ni, + } +} + +// moveNodeInfoToHead moves a NodeInfo to the head of "cache.nodes" doubly +// linked list. The head is the most recently updated NodeInfo. +// We assume cache lock is already acquired. +func (cache *cacheImpl) moveNodeInfoToHead(name string) { + ni, ok := cache.nodes[name] + if !ok { + klog.ErrorS(nil, "No node info with given name found in the cache", "node", klog.KRef("", name)) + return + } + // if the node info list item is already at the head, we are done. + if ni == cache.headNode { + return + } + + if ni.prev != nil { + ni.prev.next = ni.next + } + if ni.next != nil { + ni.next.prev = ni.prev + } + if cache.headNode != nil { + cache.headNode.prev = ni + } + ni.next = cache.headNode + ni.prev = nil + cache.headNode = ni +} + +// removeNodeInfoFromList removes a NodeInfo from the "cache.nodes" doubly +// linked list. +// We assume cache lock is already acquired. +func (cache *cacheImpl) removeNodeInfoFromList(name string) { + ni, ok := cache.nodes[name] + if !ok { + klog.ErrorS(nil, "No node info with given name found in the cache", "node", klog.KRef("", name)) + return + } + + if ni.prev != nil { + ni.prev.next = ni.next + } + if ni.next != nil { + ni.next.prev = ni.prev + } + // if the removed item was at the head, we must update the head. + if ni == cache.headNode { + cache.headNode = ni.next + } + delete(cache.nodes, name) +} + +// Dump produces a dump of the current scheduler cache. This is used for +// debugging purposes only and shouldn't be confused with UpdateSnapshot +// function. +// This method is expensive, and should be only used in non-critical path. +func (cache *cacheImpl) Dump() *Dump { + cache.mu.RLock() + defer cache.mu.RUnlock() + + nodes := make(map[string]*framework.NodeInfo, len(cache.nodes)) + for k, v := range cache.nodes { + nodes[k] = v.info.Clone() + } + + return &Dump{ + Nodes: nodes, + AssumedPods: cache.assumedPods.Union(nil), + } +} + +// UpdateSnapshot takes a snapshot of cached NodeInfo map. This is called at +// beginning of every scheduling cycle. +// The snapshot only includes Nodes that are not deleted at the time this function is called. +// nodeInfo.Node() is guaranteed to be not nil for all the nodes in the snapshot. +// This function tracks generation number of NodeInfo and updates only the +// entries of an existing snapshot that have changed after the snapshot was taken. +func (cache *cacheImpl) UpdateSnapshot(nodeSnapshot *Snapshot) error { + cache.mu.Lock() + defer cache.mu.Unlock() + + // Get the last generation of the snapshot. + snapshotGeneration := nodeSnapshot.generation + + // NodeInfoList and HavePodsWithAffinityNodeInfoList must be re-created if a node was added + // or removed from the cache. + updateAllLists := false + // HavePodsWithAffinityNodeInfoList must be re-created if a node changed its + // status from having pods with affinity to NOT having pods with affinity or the other + // way around. + updateNodesHavePodsWithAffinity := false + // HavePodsWithRequiredAntiAffinityNodeInfoList must be re-created if a node changed its + // status from having pods with required anti-affinity to NOT having pods with required + // anti-affinity or the other way around. + updateNodesHavePodsWithRequiredAntiAffinity := false + // usedPVCSet must be re-created whenever the head node generation is greater than + // last snapshot generation. + updateUsedPVCSet := false + + // Start from the head of the NodeInfo doubly linked list and update snapshot + // of NodeInfos updated after the last snapshot. + for node := cache.headNode; node != nil; node = node.next { + if node.info.Generation <= snapshotGeneration { + // all the nodes are updated before the existing snapshot. We are done. + break + } + if np := node.info.Node(); np != nil { + existing, ok := nodeSnapshot.nodeInfoMap[np.Name] + if !ok { + updateAllLists = true + existing = &framework.NodeInfo{} + nodeSnapshot.nodeInfoMap[np.Name] = existing + } + clone := node.info.Clone() + // We track nodes that have pods with affinity, here we check if this node changed its + // status from having pods with affinity to NOT having pods with affinity or the other + // way around. + if (len(existing.PodsWithAffinity) > 0) != (len(clone.PodsWithAffinity) > 0) { + updateNodesHavePodsWithAffinity = true + } + if (len(existing.PodsWithRequiredAntiAffinity) > 0) != (len(clone.PodsWithRequiredAntiAffinity) > 0) { + updateNodesHavePodsWithRequiredAntiAffinity = true + } + if !updateUsedPVCSet { + if len(existing.PVCRefCounts) != len(clone.PVCRefCounts) { + updateUsedPVCSet = true + } else { + for pvcKey := range clone.PVCRefCounts { + if _, found := existing.PVCRefCounts[pvcKey]; !found { + updateUsedPVCSet = true + break + } + } + } + } + // We need to preserve the original pointer of the NodeInfo struct since it + // is used in the NodeInfoList, which we may not update. + *existing = *clone + } + } + // Update the snapshot generation with the latest NodeInfo generation. + if cache.headNode != nil { + nodeSnapshot.generation = cache.headNode.info.Generation + } + + // Comparing to pods in nodeTree. + // Deleted nodes get removed from the tree, but they might remain in the nodes map + // if they still have non-deleted Pods. + if len(nodeSnapshot.nodeInfoMap) > cache.nodeTree.numNodes { + cache.removeDeletedNodesFromSnapshot(nodeSnapshot) + updateAllLists = true + } + + if updateAllLists || updateNodesHavePodsWithAffinity || updateNodesHavePodsWithRequiredAntiAffinity || updateUsedPVCSet { + cache.updateNodeInfoSnapshotList(nodeSnapshot, updateAllLists) + } + + if len(nodeSnapshot.nodeInfoList) != cache.nodeTree.numNodes { + errMsg := fmt.Sprintf("snapshot state is not consistent, length of NodeInfoList=%v not equal to length of nodes in tree=%v "+ + ", length of NodeInfoMap=%v, length of nodes in cache=%v"+ + ", trying to recover", + len(nodeSnapshot.nodeInfoList), cache.nodeTree.numNodes, + len(nodeSnapshot.nodeInfoMap), len(cache.nodes)) + klog.ErrorS(nil, errMsg) + // We will try to recover by re-creating the lists for the next scheduling cycle, but still return an + // error to surface the problem, the error will likely cause a failure to the current scheduling cycle. + cache.updateNodeInfoSnapshotList(nodeSnapshot, true) + return fmt.Errorf(errMsg) + } + + return nil +} + +func (cache *cacheImpl) updateNodeInfoSnapshotList(snapshot *Snapshot, updateAll bool) { + snapshot.havePodsWithAffinityNodeInfoList = make([]*framework.NodeInfo, 0, cache.nodeTree.numNodes) + snapshot.havePodsWithRequiredAntiAffinityNodeInfoList = make([]*framework.NodeInfo, 0, cache.nodeTree.numNodes) + snapshot.usedPVCSet = sets.NewString() + if updateAll { + // Take a snapshot of the nodes order in the tree + snapshot.nodeInfoList = make([]*framework.NodeInfo, 0, cache.nodeTree.numNodes) + nodesList, err := cache.nodeTree.list() + if err != nil { + klog.ErrorS(err, "Error occurred while retrieving the list of names of the nodes from node tree") + } + for _, nodeName := range nodesList { + if nodeInfo := snapshot.nodeInfoMap[nodeName]; nodeInfo != nil { + snapshot.nodeInfoList = append(snapshot.nodeInfoList, nodeInfo) + if len(nodeInfo.PodsWithAffinity) > 0 { + snapshot.havePodsWithAffinityNodeInfoList = append(snapshot.havePodsWithAffinityNodeInfoList, nodeInfo) + } + if len(nodeInfo.PodsWithRequiredAntiAffinity) > 0 { + snapshot.havePodsWithRequiredAntiAffinityNodeInfoList = append(snapshot.havePodsWithRequiredAntiAffinityNodeInfoList, nodeInfo) + } + for key := range nodeInfo.PVCRefCounts { + snapshot.usedPVCSet.Insert(key) + } + } else { + klog.ErrorS(nil, "Node exists in nodeTree but not in NodeInfoMap, this should not happen", "node", klog.KRef("", nodeName)) + } + } + } else { + for _, nodeInfo := range snapshot.nodeInfoList { + if len(nodeInfo.PodsWithAffinity) > 0 { + snapshot.havePodsWithAffinityNodeInfoList = append(snapshot.havePodsWithAffinityNodeInfoList, nodeInfo) + } + if len(nodeInfo.PodsWithRequiredAntiAffinity) > 0 { + snapshot.havePodsWithRequiredAntiAffinityNodeInfoList = append(snapshot.havePodsWithRequiredAntiAffinityNodeInfoList, nodeInfo) + } + for key := range nodeInfo.PVCRefCounts { + snapshot.usedPVCSet.Insert(key) + } + } + } +} + +// If certain nodes were deleted after the last snapshot was taken, we should remove them from the snapshot. +func (cache *cacheImpl) removeDeletedNodesFromSnapshot(snapshot *Snapshot) { + toDelete := len(snapshot.nodeInfoMap) - cache.nodeTree.numNodes + for name := range snapshot.nodeInfoMap { + if toDelete <= 0 { + break + } + if n, ok := cache.nodes[name]; !ok || n.info.Node() == nil { + delete(snapshot.nodeInfoMap, name) + toDelete-- + } + } +} + +// NodeCount returns the number of nodes in the cache. +// DO NOT use outside of tests. +func (cache *cacheImpl) NodeCount() int { + cache.mu.RLock() + defer cache.mu.RUnlock() + return len(cache.nodes) +} + +// PodCount returns the number of pods in the cache (including those from deleted nodes). +// DO NOT use outside of tests. +func (cache *cacheImpl) PodCount() (int, error) { + cache.mu.RLock() + defer cache.mu.RUnlock() + // podFilter is expected to return true for most or all of the pods. We + // can avoid expensive array growth without wasting too much memory by + // pre-allocating capacity. + count := 0 + for _, n := range cache.nodes { + count += len(n.info.Pods) + } + return count, nil +} + +func (cache *cacheImpl) AssumePod(pod *v1.Pod) error { + key, err := framework.GetPodKey(pod) + if err != nil { + return err + } + + cache.mu.Lock() + defer cache.mu.Unlock() + if _, ok := cache.podStates[key]; ok { + return fmt.Errorf("pod %v(%v) is in the cache, so can't be assumed", key, klog.KObj(pod)) + } + + return cache.addPod(pod, true) +} + +func (cache *cacheImpl) FinishBinding(pod *v1.Pod) error { + return cache.finishBinding(pod, time.Now()) +} + +// finishBinding exists to make tests deterministic by injecting now as an argument +func (cache *cacheImpl) finishBinding(pod *v1.Pod, now time.Time) error { + key, err := framework.GetPodKey(pod) + if err != nil { + return err + } + + cache.mu.RLock() + defer cache.mu.RUnlock() + + klog.V(5).InfoS("Finished binding for pod, can be expired", "podKey", key, "pod", klog.KObj(pod)) + currState, ok := cache.podStates[key] + if ok && cache.assumedPods.Has(key) { + if cache.ttl == time.Duration(0) { + currState.deadline = nil + } else { + dl := now.Add(cache.ttl) + currState.deadline = &dl + } + currState.bindingFinished = true + } + return nil +} + +func (cache *cacheImpl) ForgetPod(pod *v1.Pod) error { + key, err := framework.GetPodKey(pod) + if err != nil { + return err + } + + cache.mu.Lock() + defer cache.mu.Unlock() + + currState, ok := cache.podStates[key] + if ok && currState.pod.Spec.NodeName != pod.Spec.NodeName { + return fmt.Errorf("pod %v(%v) was assumed on %v but assigned to %v", key, klog.KObj(pod), pod.Spec.NodeName, currState.pod.Spec.NodeName) + } + + // Only assumed pod can be forgotten. + if ok && cache.assumedPods.Has(key) { + return cache.removePod(pod) + } + return fmt.Errorf("pod %v(%v) wasn't assumed so cannot be forgotten", key, klog.KObj(pod)) +} + +// Assumes that lock is already acquired. +func (cache *cacheImpl) addPod(pod *v1.Pod, assumePod bool) error { + key, err := framework.GetPodKey(pod) + if err != nil { + return err + } + n, ok := cache.nodes[pod.Spec.NodeName] + if !ok { + n = newNodeInfoListItem(framework.NewNodeInfo()) + cache.nodes[pod.Spec.NodeName] = n + } + n.info.AddPod(pod) + cache.moveNodeInfoToHead(pod.Spec.NodeName) + ps := &podState{ + pod: pod, + } + cache.podStates[key] = ps + if assumePod { + cache.assumedPods.Insert(key) + } + return nil +} + +// Assumes that lock is already acquired. +func (cache *cacheImpl) updatePod(oldPod, newPod *v1.Pod) error { + if err := cache.removePod(oldPod); err != nil { + return err + } + return cache.addPod(newPod, false) +} + +// Assumes that lock is already acquired. +// Removes a pod from the cached node info. If the node information was already +// removed and there are no more pods left in the node, cleans up the node from +// the cache. +func (cache *cacheImpl) removePod(pod *v1.Pod) error { + key, err := framework.GetPodKey(pod) + if err != nil { + return err + } + + n, ok := cache.nodes[pod.Spec.NodeName] + if !ok { + klog.ErrorS(nil, "Node not found when trying to remove pod", "node", klog.KRef("", pod.Spec.NodeName), "podKey", key, "pod", klog.KObj(pod)) + + } else { + if err := n.info.RemovePod(pod); err != nil { + return err + } + if len(n.info.Pods) == 0 && n.info.Node() == nil { + cache.removeNodeInfoFromList(pod.Spec.NodeName) + } else { + cache.moveNodeInfoToHead(pod.Spec.NodeName) + } + } + + delete(cache.podStates, key) + delete(cache.assumedPods, key) + return nil +} + +func (cache *cacheImpl) AddPod(pod *v1.Pod) error { + key, err := framework.GetPodKey(pod) + if err != nil { + return err + } + + cache.mu.Lock() + defer cache.mu.Unlock() + + currState, ok := cache.podStates[key] + switch { + case ok && cache.assumedPods.Has(key): + // When assuming, we've already added the Pod to cache, + // Just update here to make sure the Pod's status is up-to-date. + if err = cache.updatePod(currState.pod, pod); err != nil { + klog.ErrorS(err, "Error occurred while updating pod") + } + if currState.pod.Spec.NodeName != pod.Spec.NodeName { + // The pod was added to a different node than it was assumed to. + klog.InfoS("Pod was added to a different node than it was assumed", "podKey", key, "pod", klog.KObj(pod), "assumedNode", klog.KRef("", pod.Spec.NodeName), "currentNode", klog.KRef("", currState.pod.Spec.NodeName)) + return nil + } + case !ok: + // Pod was expired. We should add it back. + if err = cache.addPod(pod, false); err != nil { + klog.ErrorS(err, "Error occurred while adding pod") + } + default: + return fmt.Errorf("pod %v(%v) was already in added state", key, klog.KObj(pod)) + } + return nil +} + +func (cache *cacheImpl) UpdatePod(oldPod, newPod *v1.Pod) error { + key, err := framework.GetPodKey(oldPod) + if err != nil { + return err + } + + cache.mu.Lock() + defer cache.mu.Unlock() + + currState, ok := cache.podStates[key] + // An assumed pod won't have Update/Remove event. It needs to have Add event + // before Update event, in which case the state would change from Assumed to Added. + if ok && !cache.assumedPods.Has(key) { + if currState.pod.Spec.NodeName != newPod.Spec.NodeName { + klog.ErrorS(nil, "Pod updated on a different node than previously added to", "podKey", key, "pod", klog.KObj(oldPod)) + klog.ErrorS(nil, "scheduler cache is corrupted and can badly affect scheduling decisions") + klog.FlushAndExit(klog.ExitFlushTimeout, 1) + } + return cache.updatePod(oldPod, newPod) + } + return fmt.Errorf("pod %v(%v) is not added to scheduler cache, so cannot be updated", key, klog.KObj(oldPod)) +} + +func (cache *cacheImpl) RemovePod(pod *v1.Pod) error { + key, err := framework.GetPodKey(pod) + if err != nil { + return err + } + + cache.mu.Lock() + defer cache.mu.Unlock() + + currState, ok := cache.podStates[key] + if !ok { + return fmt.Errorf("pod %v(%v) is not found in scheduler cache, so cannot be removed from it", key, klog.KObj(pod)) + } + if currState.pod.Spec.NodeName != pod.Spec.NodeName { + klog.ErrorS(nil, "Pod was added to a different node than it was assumed", "podKey", key, "pod", klog.KObj(pod), "assumedNode", klog.KRef("", pod.Spec.NodeName), "currentNode", klog.KRef("", currState.pod.Spec.NodeName)) + if pod.Spec.NodeName != "" { + // An empty NodeName is possible when the scheduler misses a Delete + // event and it gets the last known state from the informer cache. + klog.ErrorS(nil, "scheduler cache is corrupted and can badly affect scheduling decisions") + klog.FlushAndExit(klog.ExitFlushTimeout, 1) + } + } + return cache.removePod(currState.pod) +} + +func (cache *cacheImpl) IsAssumedPod(pod *v1.Pod) (bool, error) { + key, err := framework.GetPodKey(pod) + if err != nil { + return false, err + } + + cache.mu.RLock() + defer cache.mu.RUnlock() + + return cache.assumedPods.Has(key), nil +} + +// GetPod might return a pod for which its node has already been deleted from +// the main cache. This is useful to properly process pod update events. +func (cache *cacheImpl) GetPod(pod *v1.Pod) (*v1.Pod, error) { + key, err := framework.GetPodKey(pod) + if err != nil { + return nil, err + } + + cache.mu.RLock() + defer cache.mu.RUnlock() + + podState, ok := cache.podStates[key] + if !ok { + return nil, fmt.Errorf("pod %v(%v) does not exist in scheduler cache", key, klog.KObj(pod)) + } + + return podState.pod, nil +} + +func (cache *cacheImpl) AddNode(node *v1.Node) *framework.NodeInfo { + cache.mu.Lock() + defer cache.mu.Unlock() + + n, ok := cache.nodes[node.Name] + if !ok { + n = newNodeInfoListItem(framework.NewNodeInfo()) + cache.nodes[node.Name] = n + } else { + cache.removeNodeImageStates(n.info.Node()) + } + cache.moveNodeInfoToHead(node.Name) + + cache.nodeTree.addNode(node) + cache.addNodeImageStates(node, n.info) + n.info.SetNode(node) + return n.info.Clone() +} + +func (cache *cacheImpl) UpdateNode(oldNode, newNode *v1.Node) *framework.NodeInfo { + cache.mu.Lock() + defer cache.mu.Unlock() + + n, ok := cache.nodes[newNode.Name] + if !ok { + n = newNodeInfoListItem(framework.NewNodeInfo()) + cache.nodes[newNode.Name] = n + cache.nodeTree.addNode(newNode) + } else { + cache.removeNodeImageStates(n.info.Node()) + } + cache.moveNodeInfoToHead(newNode.Name) + + cache.nodeTree.updateNode(oldNode, newNode) + cache.addNodeImageStates(newNode, n.info) + n.info.SetNode(newNode) + return n.info.Clone() +} + +// RemoveNode removes a node from the cache's tree. +// The node might still have pods because their deletion events didn't arrive +// yet. Those pods are considered removed from the cache, being the node tree +// the source of truth. +// However, we keep a ghost node with the list of pods until all pod deletion +// events have arrived. A ghost node is skipped from snapshots. +func (cache *cacheImpl) RemoveNode(node *v1.Node) error { + cache.mu.Lock() + defer cache.mu.Unlock() + + n, ok := cache.nodes[node.Name] + if !ok { + return fmt.Errorf("node %v is not found", node.Name) + } + n.info.RemoveNode() + // We remove NodeInfo for this node only if there aren't any pods on this node. + // We can't do it unconditionally, because notifications about pods are delivered + // in a different watch, and thus can potentially be observed later, even though + // they happened before node removal. + if len(n.info.Pods) == 0 { + cache.removeNodeInfoFromList(node.Name) + } else { + cache.moveNodeInfoToHead(node.Name) + } + if err := cache.nodeTree.removeNode(node); err != nil { + return err + } + cache.removeNodeImageStates(node) + return nil +} + +// addNodeImageStates adds states of the images on given node to the given nodeInfo and update the imageStates in +// scheduler cache. This function assumes the lock to scheduler cache has been acquired. +func (cache *cacheImpl) addNodeImageStates(node *v1.Node, nodeInfo *framework.NodeInfo) { + newSum := make(map[string]*framework.ImageStateSummary) + + for _, image := range node.Status.Images { + for _, name := range image.Names { + // update the entry in imageStates + state, ok := cache.imageStates[name] + if !ok { + state = &imageState{ + size: image.SizeBytes, + nodes: sets.NewString(node.Name), + } + cache.imageStates[name] = state + } else { + state.nodes.Insert(node.Name) + } + // create the imageStateSummary for this image + if _, ok := newSum[name]; !ok { + newSum[name] = cache.createImageStateSummary(state) + } + } + } + nodeInfo.ImageStates = newSum +} + +// removeNodeImageStates removes the given node record from image entries having the node +// in imageStates cache. After the removal, if any image becomes free, i.e., the image +// is no longer available on any node, the image entry will be removed from imageStates. +func (cache *cacheImpl) removeNodeImageStates(node *v1.Node) { + if node == nil { + return + } + + for _, image := range node.Status.Images { + for _, name := range image.Names { + state, ok := cache.imageStates[name] + if ok { + state.nodes.Delete(node.Name) + if len(state.nodes) == 0 { + // Remove the unused image to make sure the length of + // imageStates represents the total number of different + // images on all nodes + delete(cache.imageStates, name) + } + } + } + } +} + +func (cache *cacheImpl) run() { + go wait.Until(cache.cleanupExpiredAssumedPods, cache.period, cache.stop) +} + +func (cache *cacheImpl) cleanupExpiredAssumedPods() { + cache.cleanupAssumedPods(time.Now()) +} + +// cleanupAssumedPods exists for making test deterministic by taking time as input argument. +// It also reports metrics on the cache size for nodes, pods, and assumed pods. +func (cache *cacheImpl) cleanupAssumedPods(now time.Time) { + cache.mu.Lock() + defer cache.mu.Unlock() + defer cache.updateMetrics() + + // The size of assumedPods should be small + for key := range cache.assumedPods { + ps, ok := cache.podStates[key] + if !ok { + klog.ErrorS(nil, "Key found in assumed set but not in podStates, potentially a logical error") + klog.FlushAndExit(klog.ExitFlushTimeout, 1) + } + if !ps.bindingFinished { + klog.V(5).InfoS("Could not expire cache for pod as binding is still in progress", "podKey", key, "pod", klog.KObj(ps.pod)) + continue + } + if cache.ttl != 0 && now.After(*ps.deadline) { + klog.InfoS("Pod expired", "podKey", key, "pod", klog.KObj(ps.pod)) + if err := cache.removePod(ps.pod); err != nil { + klog.ErrorS(err, "ExpirePod failed", "podKey", key, "pod", klog.KObj(ps.pod)) + } + } + } +} + +// updateMetrics updates cache size metric values for pods, assumed pods, and nodes +func (cache *cacheImpl) updateMetrics() { + metrics.CacheSize.WithLabelValues("assumed_pods").Set(float64(len(cache.assumedPods))) + metrics.CacheSize.WithLabelValues("pods").Set(float64(len(cache.podStates))) + metrics.CacheSize.WithLabelValues("nodes").Set(float64(len(cache.nodes))) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger/comparer.go b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger/comparer.go new file mode 100644 index 000000000..bf8cafb78 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger/comparer.go @@ -0,0 +1,135 @@ +/* +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 debugger + +import ( + "sort" + "strings" + + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" + corelisters "k8s.io/client-go/listers/core/v1" + "k8s.io/klog/v2" + "k8s.io/kubernetes/pkg/scheduler/framework" + internalcache "k8s.io/kubernetes/pkg/scheduler/internal/cache" + internalqueue "k8s.io/kubernetes/pkg/scheduler/internal/queue" +) + +// CacheComparer is an implementation of the Scheduler's cache comparer. +type CacheComparer struct { + NodeLister corelisters.NodeLister + PodLister corelisters.PodLister + Cache internalcache.Cache + PodQueue internalqueue.SchedulingQueue +} + +// Compare compares the nodes and pods of NodeLister with Cache.Snapshot. +func (c *CacheComparer) Compare() error { + klog.V(3).InfoS("Cache comparer started") + defer klog.V(3).InfoS("Cache comparer finished") + + nodes, err := c.NodeLister.List(labels.Everything()) + if err != nil { + return err + } + + pods, err := c.PodLister.List(labels.Everything()) + if err != nil { + return err + } + + dump := c.Cache.Dump() + + pendingPods, _ := c.PodQueue.PendingPods() + + if missed, redundant := c.CompareNodes(nodes, dump.Nodes); len(missed)+len(redundant) != 0 { + klog.InfoS("Cache mismatch", "missedNodes", missed, "redundantNodes", redundant) + } + + if missed, redundant := c.ComparePods(pods, pendingPods, dump.Nodes); len(missed)+len(redundant) != 0 { + klog.InfoS("Cache mismatch", "missedPods", missed, "redundantPods", redundant) + } + + return nil +} + +// CompareNodes compares actual nodes with cached nodes. +func (c *CacheComparer) CompareNodes(nodes []*v1.Node, nodeinfos map[string]*framework.NodeInfo) (missed, redundant []string) { + actual := []string{} + for _, node := range nodes { + actual = append(actual, node.Name) + } + + cached := []string{} + for nodeName := range nodeinfos { + cached = append(cached, nodeName) + } + + return compareStrings(actual, cached) +} + +// ComparePods compares actual pods with cached pods. +func (c *CacheComparer) ComparePods(pods, waitingPods []*v1.Pod, nodeinfos map[string]*framework.NodeInfo) (missed, redundant []string) { + actual := []string{} + for _, pod := range pods { + actual = append(actual, string(pod.UID)) + } + + cached := []string{} + for _, nodeinfo := range nodeinfos { + for _, p := range nodeinfo.Pods { + cached = append(cached, string(p.Pod.UID)) + } + } + for _, pod := range waitingPods { + cached = append(cached, string(pod.UID)) + } + + return compareStrings(actual, cached) +} + +func compareStrings(actual, cached []string) (missed, redundant []string) { + missed, redundant = []string{}, []string{} + + sort.Strings(actual) + sort.Strings(cached) + + compare := func(i, j int) int { + if i == len(actual) { + return 1 + } else if j == len(cached) { + return -1 + } + return strings.Compare(actual[i], cached[j]) + } + + for i, j := 0, 0; i < len(actual) || j < len(cached); { + switch compare(i, j) { + case 0: + i++ + j++ + case -1: + missed = append(missed, actual[i]) + i++ + case 1: + redundant = append(redundant, cached[j]) + j++ + } + } + + return +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger/debugger.go b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger/debugger.go new file mode 100644 index 000000000..d8839ec67 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger/debugger.go @@ -0,0 +1,72 @@ +/* +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 debugger + +import ( + "os" + "os/signal" + + corelisters "k8s.io/client-go/listers/core/v1" + internalcache "k8s.io/kubernetes/pkg/scheduler/internal/cache" + internalqueue "k8s.io/kubernetes/pkg/scheduler/internal/queue" +) + +// CacheDebugger provides ways to check and write cache information for debugging. +type CacheDebugger struct { + Comparer CacheComparer + Dumper CacheDumper +} + +// New creates a CacheDebugger. +func New( + nodeLister corelisters.NodeLister, + podLister corelisters.PodLister, + cache internalcache.Cache, + podQueue internalqueue.SchedulingQueue, +) *CacheDebugger { + return &CacheDebugger{ + Comparer: CacheComparer{ + NodeLister: nodeLister, + PodLister: podLister, + Cache: cache, + PodQueue: podQueue, + }, + Dumper: CacheDumper{ + cache: cache, + podQueue: podQueue, + }, + } +} + +// ListenForSignal starts a goroutine that will trigger the CacheDebugger's +// behavior when the process receives SIGINT (Windows) or SIGUSER2 (non-Windows). +func (d *CacheDebugger) ListenForSignal(stopCh <-chan struct{}) { + ch := make(chan os.Signal, 1) + signal.Notify(ch, compareSignal) + + go func() { + for { + select { + case <-stopCh: + return + case <-ch: + d.Comparer.Compare() + d.Dumper.DumpAll() + } + } + }() +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger/dumper.go b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger/dumper.go new file mode 100644 index 000000000..d95c234ee --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger/dumper.go @@ -0,0 +1,88 @@ +/* +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 debugger + +import ( + "fmt" + "strings" + + "k8s.io/klog/v2" + + "k8s.io/api/core/v1" + "k8s.io/kubernetes/pkg/scheduler/framework" + internalcache "k8s.io/kubernetes/pkg/scheduler/internal/cache" + "k8s.io/kubernetes/pkg/scheduler/internal/queue" +) + +// CacheDumper writes some information from the scheduler cache and the scheduling queue to the +// scheduler logs for debugging purposes. +type CacheDumper struct { + cache internalcache.Cache + podQueue queue.SchedulingQueue +} + +// DumpAll writes cached nodes and scheduling queue information to the scheduler logs. +func (d *CacheDumper) DumpAll() { + d.dumpNodes() + d.dumpSchedulingQueue() +} + +// dumpNodes writes NodeInfo to the scheduler logs. +func (d *CacheDumper) dumpNodes() { + dump := d.cache.Dump() + nodeInfos := make([]string, 0, len(dump.Nodes)) + for name, nodeInfo := range dump.Nodes { + nodeInfos = append(nodeInfos, d.printNodeInfo(name, nodeInfo)) + } + // Extra blank line added between node entries for readability. + klog.InfoS("Dump of cached NodeInfo", "nodes", strings.Join(nodeInfos, "\n\n")) +} + +// dumpSchedulingQueue writes pods in the scheduling queue to the scheduler logs. +func (d *CacheDumper) dumpSchedulingQueue() { + pendingPods, s := d.podQueue.PendingPods() + var podData strings.Builder + for _, p := range pendingPods { + podData.WriteString(printPod(p)) + } + klog.InfoS("Dump of scheduling queue", "summary", s, "pods", podData.String()) +} + +// printNodeInfo writes parts of NodeInfo to a string. +func (d *CacheDumper) printNodeInfo(name string, n *framework.NodeInfo) string { + var nodeData strings.Builder + nodeData.WriteString(fmt.Sprintf("Node name: %s\nDeleted: %t\nRequested Resources: %+v\nAllocatable Resources:%+v\nScheduled Pods(number: %v):\n", + name, n.Node() == nil, n.Requested, n.Allocatable, len(n.Pods))) + // Dumping Pod Info + for _, p := range n.Pods { + nodeData.WriteString(printPod(p.Pod)) + } + // Dumping nominated pods info on the node + nominatedPodInfos := d.podQueue.NominatedPodsForNode(name) + if len(nominatedPodInfos) != 0 { + nodeData.WriteString(fmt.Sprintf("Nominated Pods(number: %v):\n", len(nominatedPodInfos))) + for _, pi := range nominatedPodInfos { + nodeData.WriteString(printPod(pi.Pod)) + } + } + return nodeData.String() +} + +// printPod writes parts of a Pod object to a string. +func printPod(p *v1.Pod) string { + return fmt.Sprintf("name: %v, namespace: %v, uid: %v, phase: %v, nominated node: %v\n", p.Name, p.Namespace, p.UID, p.Status.Phase, p.Status.NominatedNodeName) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger/signal.go b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger/signal.go new file mode 100644 index 000000000..df5c83cea --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger/signal.go @@ -0,0 +1,26 @@ +//go:build !windows +// +build !windows + +/* +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 debugger + +import "syscall" + +// compareSignal is the signal to trigger cache compare. For non-windows +// environment it's SIGUSR2. +var compareSignal = syscall.SIGUSR2 diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger/signal_windows.go b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger/signal_windows.go new file mode 100644 index 000000000..25c015b0e --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger/signal_windows.go @@ -0,0 +1,23 @@ +/* +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 debugger + +import "os" + +// compareSignal is the signal to trigger cache compare. For windows, +// it's SIGINT. +var compareSignal = os.Interrupt diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/interface.go b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/interface.go new file mode 100644 index 000000000..f6298bd34 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/interface.go @@ -0,0 +1,122 @@ +/* +Copyright 2015 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 cache + +import ( + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/kubernetes/pkg/scheduler/framework" +) + +// Cache collects pods' information and provides node-level aggregated information. +// It's intended for generic scheduler to do efficient lookup. +// Cache's operations are pod centric. It does incremental updates based on pod events. +// Pod events are sent via network. We don't have guaranteed delivery of all events: +// We use Reflector to list and watch from remote. +// Reflector might be slow and do a relist, which would lead to missing events. +// +// State Machine of a pod's events in scheduler's cache: +// +// +-------------------------------------------+ +----+ +// | Add | | | +// | | | | Update +// + Assume Add v v | +// +// Initial +--------> Assumed +------------+---> Added <--+ +// +// ^ + + | + +// | | | | | +// | | | Add | | Remove +// | | | | | +// | | | + | +// +----------------+ +-----------> Expired +----> Deleted +// Forget Expire +// +// Note that an assumed pod can expire, because if we haven't received Add event notifying us +// for a while, there might be some problems and we shouldn't keep the pod in cache anymore. +// +// Note that "Initial", "Expired", and "Deleted" pods do not actually exist in cache. +// Based on existing use cases, we are making the following assumptions: +// - No pod would be assumed twice +// - A pod could be added without going through scheduler. In this case, we will see Add but not Assume event. +// - If a pod wasn't added, it wouldn't be removed or updated. +// - Both "Expired" and "Deleted" are valid end states. In case of some problems, e.g. network issue, +// a pod might have changed its state (e.g. added and deleted) without delivering notification to the cache. +type Cache interface { + // NodeCount returns the number of nodes in the cache. + // DO NOT use outside of tests. + NodeCount() int + + // PodCount returns the number of pods in the cache (including those from deleted nodes). + // DO NOT use outside of tests. + PodCount() (int, error) + + // AssumePod assumes a pod scheduled and aggregates the pod's information into its node. + // The implementation also decides the policy to expire pod before being confirmed (receiving Add event). + // After expiration, its information would be subtracted. + AssumePod(pod *v1.Pod) error + + // FinishBinding signals that cache for assumed pod can be expired + FinishBinding(pod *v1.Pod) error + + // ForgetPod removes an assumed pod from cache. + ForgetPod(pod *v1.Pod) error + + // AddPod either confirms a pod if it's assumed, or adds it back if it's expired. + // If added back, the pod's information would be added again. + AddPod(pod *v1.Pod) error + + // UpdatePod removes oldPod's information and adds newPod's information. + UpdatePod(oldPod, newPod *v1.Pod) error + + // RemovePod removes a pod. The pod's information would be subtracted from assigned node. + RemovePod(pod *v1.Pod) error + + // GetPod returns the pod from the cache with the same namespace and the + // same name of the specified pod. + GetPod(pod *v1.Pod) (*v1.Pod, error) + + // IsAssumedPod returns true if the pod is assumed and not expired. + IsAssumedPod(pod *v1.Pod) (bool, error) + + // AddNode adds overall information about node. + // It returns a clone of added NodeInfo object. + AddNode(node *v1.Node) *framework.NodeInfo + + // UpdateNode updates overall information about node. + // It returns a clone of updated NodeInfo object. + UpdateNode(oldNode, newNode *v1.Node) *framework.NodeInfo + + // RemoveNode removes overall information about node. + RemoveNode(node *v1.Node) error + + // UpdateSnapshot updates the passed infoSnapshot to the current contents of Cache. + // The node info contains aggregated information of pods scheduled (including assumed to be) + // on this node. + // The snapshot only includes Nodes that are not deleted at the time this function is called. + // nodeinfo.Node() is guaranteed to be not nil for all the nodes in the snapshot. + UpdateSnapshot(nodeSnapshot *Snapshot) error + + // Dump produces a dump of the current cache. + Dump() *Dump +} + +// Dump is a dump of the cache state. +type Dump struct { + AssumedPods sets.String + Nodes map[string]*framework.NodeInfo +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/node_tree.go b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/node_tree.go new file mode 100644 index 000000000..2463e3a95 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/node_tree.go @@ -0,0 +1,143 @@ +/* +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 cache + +import ( + "errors" + "fmt" + + v1 "k8s.io/api/core/v1" + utilnode "k8s.io/component-helpers/node/topology" + "k8s.io/klog/v2" +) + +// nodeTree is a tree-like data structure that holds node names in each zone. Zone names are +// keys to "NodeTree.tree" and values of "NodeTree.tree" are arrays of node names. +// NodeTree is NOT thread-safe, any concurrent updates/reads from it must be synchronized by the caller. +// It is used only by schedulerCache, and should stay as such. +type nodeTree struct { + tree map[string][]string // a map from zone (region-zone) to an array of nodes in the zone. + zones []string // a list of all the zones in the tree (keys) + numNodes int +} + +// newNodeTree creates a NodeTree from nodes. +func newNodeTree(nodes []*v1.Node) *nodeTree { + nt := &nodeTree{ + tree: make(map[string][]string, len(nodes)), + } + for _, n := range nodes { + nt.addNode(n) + } + return nt +} + +// addNode adds a node and its corresponding zone to the tree. If the zone already exists, the node +// is added to the array of nodes in that zone. +func (nt *nodeTree) addNode(n *v1.Node) { + zone := utilnode.GetZoneKey(n) + if na, ok := nt.tree[zone]; ok { + for _, nodeName := range na { + if nodeName == n.Name { + klog.InfoS("Node already exists in the NodeTree", "node", klog.KObj(n)) + return + } + } + nt.tree[zone] = append(na, n.Name) + } else { + nt.zones = append(nt.zones, zone) + nt.tree[zone] = []string{n.Name} + } + klog.V(2).InfoS("Added node in listed group to NodeTree", "node", klog.KObj(n), "zone", zone) + nt.numNodes++ +} + +// removeNode removes a node from the NodeTree. +func (nt *nodeTree) removeNode(n *v1.Node) error { + zone := utilnode.GetZoneKey(n) + if na, ok := nt.tree[zone]; ok { + for i, nodeName := range na { + if nodeName == n.Name { + nt.tree[zone] = append(na[:i], na[i+1:]...) + if len(nt.tree[zone]) == 0 { + nt.removeZone(zone) + } + klog.V(2).InfoS("Removed node in listed group from NodeTree", "node", klog.KObj(n), "zone", zone) + nt.numNodes-- + return nil + } + } + } + klog.ErrorS(nil, "Node in listed group was not found", "node", klog.KObj(n), "zone", zone) + return fmt.Errorf("node %q in group %q was not found", n.Name, zone) +} + +// removeZone removes a zone from tree. +// This function must be called while writer locks are hold. +func (nt *nodeTree) removeZone(zone string) { + delete(nt.tree, zone) + for i, z := range nt.zones { + if z == zone { + nt.zones = append(nt.zones[:i], nt.zones[i+1:]...) + return + } + } +} + +// updateNode updates a node in the NodeTree. +func (nt *nodeTree) updateNode(old, new *v1.Node) { + var oldZone string + if old != nil { + oldZone = utilnode.GetZoneKey(old) + } + newZone := utilnode.GetZoneKey(new) + // If the zone ID of the node has not changed, we don't need to do anything. Name of the node + // cannot be changed in an update. + if oldZone == newZone { + return + } + nt.removeNode(old) // No error checking. We ignore whether the old node exists or not. + nt.addNode(new) +} + +// list returns the list of names of the node. NodeTree iterates over zones and in each zone iterates +// over nodes in a round robin fashion. +func (nt *nodeTree) list() ([]string, error) { + if len(nt.zones) == 0 { + return nil, nil + } + nodesList := make([]string, 0, nt.numNodes) + numExhaustedZones := 0 + nodeIndex := 0 + for len(nodesList) < nt.numNodes { + if numExhaustedZones >= len(nt.zones) { // all zones are exhausted. + return nodesList, errors.New("all zones exhausted before reaching count of nodes expected") + } + for zoneIndex := 0; zoneIndex < len(nt.zones); zoneIndex++ { + na := nt.tree[nt.zones[zoneIndex]] + if nodeIndex >= len(na) { // If the zone is exhausted, continue + if nodeIndex == len(na) { // If it is the first time the zone is exhausted + numExhaustedZones++ + } + continue + } + nodesList = append(nodesList, na[nodeIndex]) + } + nodeIndex++ + } + return nodesList, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/snapshot.go b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/snapshot.go new file mode 100644 index 000000000..78b67322a --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/cache/snapshot.go @@ -0,0 +1,198 @@ +/* +Copyright 2019 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 cache + +import ( + "fmt" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/kubernetes/pkg/scheduler/framework" +) + +// Snapshot is a snapshot of cache NodeInfo and NodeTree order. The scheduler takes a +// snapshot at the beginning of each scheduling cycle and uses it for its operations in that cycle. +type Snapshot struct { + // nodeInfoMap a map of node name to a snapshot of its NodeInfo. + nodeInfoMap map[string]*framework.NodeInfo + // nodeInfoList is the list of nodes as ordered in the cache's nodeTree. + nodeInfoList []*framework.NodeInfo + // havePodsWithAffinityNodeInfoList is the list of nodes with at least one pod declaring affinity terms. + havePodsWithAffinityNodeInfoList []*framework.NodeInfo + // havePodsWithRequiredAntiAffinityNodeInfoList is the list of nodes with at least one pod declaring + // required anti-affinity terms. + havePodsWithRequiredAntiAffinityNodeInfoList []*framework.NodeInfo + // usedPVCSet contains a set of PVC names that have one or more scheduled pods using them, + // keyed in the format "namespace/name". + usedPVCSet sets.String + generation int64 +} + +var _ framework.SharedLister = &Snapshot{} + +// NewEmptySnapshot initializes a Snapshot struct and returns it. +func NewEmptySnapshot() *Snapshot { + return &Snapshot{ + nodeInfoMap: make(map[string]*framework.NodeInfo), + usedPVCSet: sets.NewString(), + } +} + +// NewSnapshot initializes a Snapshot struct and returns it. +func NewSnapshot(pods []*v1.Pod, nodes []*v1.Node) *Snapshot { + nodeInfoMap := createNodeInfoMap(pods, nodes) + nodeInfoList := make([]*framework.NodeInfo, 0, len(nodeInfoMap)) + havePodsWithAffinityNodeInfoList := make([]*framework.NodeInfo, 0, len(nodeInfoMap)) + havePodsWithRequiredAntiAffinityNodeInfoList := make([]*framework.NodeInfo, 0, len(nodeInfoMap)) + for _, v := range nodeInfoMap { + nodeInfoList = append(nodeInfoList, v) + if len(v.PodsWithAffinity) > 0 { + havePodsWithAffinityNodeInfoList = append(havePodsWithAffinityNodeInfoList, v) + } + if len(v.PodsWithRequiredAntiAffinity) > 0 { + havePodsWithRequiredAntiAffinityNodeInfoList = append(havePodsWithRequiredAntiAffinityNodeInfoList, v) + } + } + + s := NewEmptySnapshot() + s.nodeInfoMap = nodeInfoMap + s.nodeInfoList = nodeInfoList + s.havePodsWithAffinityNodeInfoList = havePodsWithAffinityNodeInfoList + s.havePodsWithRequiredAntiAffinityNodeInfoList = havePodsWithRequiredAntiAffinityNodeInfoList + s.usedPVCSet = createUsedPVCSet(pods) + + return s +} + +// createNodeInfoMap obtains a list of pods and pivots that list into a map +// where the keys are node names and the values are the aggregated information +// for that node. +func createNodeInfoMap(pods []*v1.Pod, nodes []*v1.Node) map[string]*framework.NodeInfo { + nodeNameToInfo := make(map[string]*framework.NodeInfo) + for _, pod := range pods { + nodeName := pod.Spec.NodeName + if _, ok := nodeNameToInfo[nodeName]; !ok { + nodeNameToInfo[nodeName] = framework.NewNodeInfo() + } + nodeNameToInfo[nodeName].AddPod(pod) + } + imageExistenceMap := createImageExistenceMap(nodes) + + for _, node := range nodes { + if _, ok := nodeNameToInfo[node.Name]; !ok { + nodeNameToInfo[node.Name] = framework.NewNodeInfo() + } + nodeInfo := nodeNameToInfo[node.Name] + nodeInfo.SetNode(node) + nodeInfo.ImageStates = getNodeImageStates(node, imageExistenceMap) + } + return nodeNameToInfo +} + +func createUsedPVCSet(pods []*v1.Pod) sets.String { + usedPVCSet := sets.NewString() + for _, pod := range pods { + if pod.Spec.NodeName == "" { + continue + } + + for _, v := range pod.Spec.Volumes { + if v.PersistentVolumeClaim == nil { + continue + } + + key := framework.GetNamespacedName(pod.Namespace, v.PersistentVolumeClaim.ClaimName) + usedPVCSet.Insert(key) + } + } + return usedPVCSet +} + +// getNodeImageStates returns the given node's image states based on the given imageExistence map. +func getNodeImageStates(node *v1.Node, imageExistenceMap map[string]sets.String) map[string]*framework.ImageStateSummary { + imageStates := make(map[string]*framework.ImageStateSummary) + + for _, image := range node.Status.Images { + for _, name := range image.Names { + imageStates[name] = &framework.ImageStateSummary{ + Size: image.SizeBytes, + NumNodes: len(imageExistenceMap[name]), + } + } + } + return imageStates +} + +// createImageExistenceMap returns a map recording on which nodes the images exist, keyed by the images' names. +func createImageExistenceMap(nodes []*v1.Node) map[string]sets.String { + imageExistenceMap := make(map[string]sets.String) + for _, node := range nodes { + for _, image := range node.Status.Images { + for _, name := range image.Names { + if _, ok := imageExistenceMap[name]; !ok { + imageExistenceMap[name] = sets.NewString(node.Name) + } else { + imageExistenceMap[name].Insert(node.Name) + } + } + } + } + return imageExistenceMap +} + +// NodeInfos returns a NodeInfoLister. +func (s *Snapshot) NodeInfos() framework.NodeInfoLister { + return s +} + +// StorageInfos returns a StorageInfoLister. +func (s *Snapshot) StorageInfos() framework.StorageInfoLister { + return s +} + +// NumNodes returns the number of nodes in the snapshot. +func (s *Snapshot) NumNodes() int { + return len(s.nodeInfoList) +} + +// List returns the list of nodes in the snapshot. +func (s *Snapshot) List() ([]*framework.NodeInfo, error) { + return s.nodeInfoList, nil +} + +// HavePodsWithAffinityList returns the list of nodes with at least one pod with inter-pod affinity +func (s *Snapshot) HavePodsWithAffinityList() ([]*framework.NodeInfo, error) { + return s.havePodsWithAffinityNodeInfoList, nil +} + +// HavePodsWithRequiredAntiAffinityList returns the list of nodes with at least one pod with +// required inter-pod anti-affinity +func (s *Snapshot) HavePodsWithRequiredAntiAffinityList() ([]*framework.NodeInfo, error) { + return s.havePodsWithRequiredAntiAffinityNodeInfoList, nil +} + +// Get returns the NodeInfo of the given node name. +func (s *Snapshot) Get(nodeName string) (*framework.NodeInfo, error) { + if v, ok := s.nodeInfoMap[nodeName]; ok && v.Node() != nil { + return v, nil + } + return nil, fmt.Errorf("nodeinfo not found for node name %q", nodeName) +} + +func (s *Snapshot) IsPVCUsedByPods(key string) bool { + return s.usedPVCSet.Has(key) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/internal/heap/heap.go b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/heap/heap.go new file mode 100644 index 000000000..8bc387aaf --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/heap/heap.go @@ -0,0 +1,246 @@ +/* +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. +*/ + +// Below is the implementation of the a heap. The logic is pretty much the same +// as cache.heap, however, this heap does not perform synchronization. It leaves +// synchronization to the SchedulingQueue. + +package heap + +import ( + "container/heap" + "fmt" + + "k8s.io/client-go/tools/cache" + "k8s.io/kubernetes/pkg/scheduler/metrics" +) + +// KeyFunc is a function type to get the key from an object. +type KeyFunc func(obj interface{}) (string, error) + +type heapItem struct { + obj interface{} // The object which is stored in the heap. + index int // The index of the object's key in the Heap.queue. +} + +type itemKeyValue struct { + key string + obj interface{} +} + +// data is an internal struct that implements the standard heap interface +// and keeps the data stored in the heap. +type data struct { + // items is a map from key of the objects to the objects and their index. + // We depend on the property that items in the map are in the queue and vice versa. + items map[string]*heapItem + // queue implements a heap data structure and keeps the order of elements + // according to the heap invariant. The queue keeps the keys of objects stored + // in "items". + queue []string + + // keyFunc is used to make the key used for queued item insertion and retrieval, and + // should be deterministic. + keyFunc KeyFunc + // lessFunc is used to compare two objects in the heap. + lessFunc lessFunc +} + +var ( + _ = heap.Interface(&data{}) // heapData is a standard heap +) + +// Less compares two objects and returns true if the first one should go +// in front of the second one in the heap. +func (h *data) Less(i, j int) bool { + if i > len(h.queue) || j > len(h.queue) { + return false + } + itemi, ok := h.items[h.queue[i]] + if !ok { + return false + } + itemj, ok := h.items[h.queue[j]] + if !ok { + return false + } + return h.lessFunc(itemi.obj, itemj.obj) +} + +// Len returns the number of items in the Heap. +func (h *data) Len() int { return len(h.queue) } + +// Swap implements swapping of two elements in the heap. This is a part of standard +// heap interface and should never be called directly. +func (h *data) Swap(i, j int) { + h.queue[i], h.queue[j] = h.queue[j], h.queue[i] + item := h.items[h.queue[i]] + item.index = i + item = h.items[h.queue[j]] + item.index = j +} + +// Push is supposed to be called by heap.Push only. +func (h *data) Push(kv interface{}) { + keyValue := kv.(*itemKeyValue) + n := len(h.queue) + h.items[keyValue.key] = &heapItem{keyValue.obj, n} + h.queue = append(h.queue, keyValue.key) +} + +// Pop is supposed to be called by heap.Pop only. +func (h *data) Pop() interface{} { + key := h.queue[len(h.queue)-1] + h.queue = h.queue[0 : len(h.queue)-1] + item, ok := h.items[key] + if !ok { + // This is an error + return nil + } + delete(h.items, key) + return item.obj +} + +// Peek is supposed to be called by heap.Peek only. +func (h *data) Peek() interface{} { + if len(h.queue) > 0 { + return h.items[h.queue[0]].obj + } + return nil +} + +// Heap is a producer/consumer queue that implements a heap data structure. +// It can be used to implement priority queues and similar data structures. +type Heap struct { + // data stores objects and has a queue that keeps their ordering according + // to the heap invariant. + data *data + // metricRecorder updates the counter when elements of a heap get added or + // removed, and it does nothing if it's nil + metricRecorder metrics.MetricRecorder +} + +// Add inserts an item, and puts it in the queue. The item is updated if it +// already exists. +func (h *Heap) Add(obj interface{}) error { + key, err := h.data.keyFunc(obj) + if err != nil { + return cache.KeyError{Obj: obj, Err: err} + } + if _, exists := h.data.items[key]; exists { + h.data.items[key].obj = obj + heap.Fix(h.data, h.data.items[key].index) + } else { + heap.Push(h.data, &itemKeyValue{key, obj}) + if h.metricRecorder != nil { + h.metricRecorder.Inc() + } + } + return nil +} + +// Update is the same as Add in this implementation. When the item does not +// exist, it is added. +func (h *Heap) Update(obj interface{}) error { + return h.Add(obj) +} + +// Delete removes an item. +func (h *Heap) Delete(obj interface{}) error { + key, err := h.data.keyFunc(obj) + if err != nil { + return cache.KeyError{Obj: obj, Err: err} + } + if item, ok := h.data.items[key]; ok { + heap.Remove(h.data, item.index) + if h.metricRecorder != nil { + h.metricRecorder.Dec() + } + return nil + } + return fmt.Errorf("object not found") +} + +// Peek returns the head of the heap without removing it. +func (h *Heap) Peek() interface{} { + return h.data.Peek() +} + +// Pop returns the head of the heap and removes it. +func (h *Heap) Pop() (interface{}, error) { + obj := heap.Pop(h.data) + if obj != nil { + if h.metricRecorder != nil { + h.metricRecorder.Dec() + } + return obj, nil + } + return nil, fmt.Errorf("object was removed from heap data") +} + +// Get returns the requested item, or sets exists=false. +func (h *Heap) Get(obj interface{}) (interface{}, bool, error) { + key, err := h.data.keyFunc(obj) + if err != nil { + return nil, false, cache.KeyError{Obj: obj, Err: err} + } + return h.GetByKey(key) +} + +// GetByKey returns the requested item, or sets exists=false. +func (h *Heap) GetByKey(key string) (interface{}, bool, error) { + item, exists := h.data.items[key] + if !exists { + return nil, false, nil + } + return item.obj, true, nil +} + +// List returns a list of all the items. +func (h *Heap) List() []interface{} { + list := make([]interface{}, 0, len(h.data.items)) + for _, item := range h.data.items { + list = append(list, item.obj) + } + return list +} + +// Len returns the number of items in the heap. +func (h *Heap) Len() int { + return len(h.data.queue) +} + +// New returns a Heap which can be used to queue up items to process. +func New(keyFn KeyFunc, lessFn lessFunc) *Heap { + return NewWithRecorder(keyFn, lessFn, nil) +} + +// NewWithRecorder wraps an optional metricRecorder to compose a Heap object. +func NewWithRecorder(keyFn KeyFunc, lessFn lessFunc, metricRecorder metrics.MetricRecorder) *Heap { + return &Heap{ + data: &data{ + items: map[string]*heapItem{}, + queue: []string{}, + keyFunc: keyFn, + lessFunc: lessFn, + }, + metricRecorder: metricRecorder, + } +} + +// lessFunc is a function that receives two items and returns true if the first +// item should be placed before the second one when the list is sorted. +type lessFunc = func(item1, item2 interface{}) bool diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/internal/queue/events.go b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/queue/events.go new file mode 100644 index 000000000..44f892296 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/queue/events.go @@ -0,0 +1,87 @@ +/* +Copyright 2019 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 queue + +import ( + "k8s.io/kubernetes/pkg/scheduler/framework" +) + +const ( + // PodAdd is the event when a new pod is added to API server. + PodAdd = "PodAdd" + // ScheduleAttemptFailure is the event when a schedule attempt fails. + ScheduleAttemptFailure = "ScheduleAttemptFailure" + // BackoffComplete is the event when a pod finishes backoff. + BackoffComplete = "BackoffComplete" + // ForceActivate is the event when a pod is moved from unschedulablePods/backoffQ + // to activeQ. Usually it's triggered by plugin implementations. + ForceActivate = "ForceActivate" + // PodUpdate is the event when a pod is updated + PodUpdate = "PodUpdate" +) + +var ( + // AssignedPodAdd is the event when a pod is added that causes pods with matching affinity terms + // to be more schedulable. + AssignedPodAdd = framework.ClusterEvent{Resource: framework.Pod, ActionType: framework.Add, Label: "AssignedPodAdd"} + // NodeAdd is the event when a new node is added to the cluster. + NodeAdd = framework.ClusterEvent{Resource: framework.Node, ActionType: framework.Add, Label: "NodeAdd"} + // AssignedPodUpdate is the event when a pod is updated that causes pods with matching affinity + // terms to be more schedulable. + AssignedPodUpdate = framework.ClusterEvent{Resource: framework.Pod, ActionType: framework.Update, Label: "AssignedPodUpdate"} + // AssignedPodDelete is the event when a pod is deleted that causes pods with matching affinity + // terms to be more schedulable. + AssignedPodDelete = framework.ClusterEvent{Resource: framework.Pod, ActionType: framework.Delete, Label: "AssignedPodDelete"} + // NodeSpecUnschedulableChange is the event when unschedulable node spec is changed. + NodeSpecUnschedulableChange = framework.ClusterEvent{Resource: framework.Node, ActionType: framework.UpdateNodeTaint, Label: "NodeSpecUnschedulableChange"} + // NodeAllocatableChange is the event when node allocatable is changed. + NodeAllocatableChange = framework.ClusterEvent{Resource: framework.Node, ActionType: framework.UpdateNodeAllocatable, Label: "NodeAllocatableChange"} + // NodeLabelChange is the event when node label is changed. + NodeLabelChange = framework.ClusterEvent{Resource: framework.Node, ActionType: framework.UpdateNodeLabel, Label: "NodeLabelChange"} + // NodeTaintChange is the event when node taint is changed. + NodeTaintChange = framework.ClusterEvent{Resource: framework.Node, ActionType: framework.UpdateNodeTaint, Label: "NodeTaintChange"} + // NodeConditionChange is the event when node condition is changed. + NodeConditionChange = framework.ClusterEvent{Resource: framework.Node, ActionType: framework.UpdateNodeCondition, Label: "NodeConditionChange"} + // PvAdd is the event when a persistent volume is added in the cluster. + PvAdd = framework.ClusterEvent{Resource: framework.PersistentVolume, ActionType: framework.Add, Label: "PvAdd"} + // PvUpdate is the event when a persistent volume is updated in the cluster. + PvUpdate = framework.ClusterEvent{Resource: framework.PersistentVolume, ActionType: framework.Update, Label: "PvUpdate"} + // PvcAdd is the event when a persistent volume claim is added in the cluster. + PvcAdd = framework.ClusterEvent{Resource: framework.PersistentVolumeClaim, ActionType: framework.Add, Label: "PvcAdd"} + // PvcUpdate is the event when a persistent volume claim is updated in the cluster. + PvcUpdate = framework.ClusterEvent{Resource: framework.PersistentVolumeClaim, ActionType: framework.Update, Label: "PvcUpdate"} + // StorageClassAdd is the event when a StorageClass is added in the cluster. + StorageClassAdd = framework.ClusterEvent{Resource: framework.StorageClass, ActionType: framework.Add, Label: "StorageClassAdd"} + // StorageClassUpdate is the event when a StorageClass is updated in the cluster. + StorageClassUpdate = framework.ClusterEvent{Resource: framework.StorageClass, ActionType: framework.Update, Label: "StorageClassUpdate"} + // CSINodeAdd is the event when a CSI node is added in the cluster. + CSINodeAdd = framework.ClusterEvent{Resource: framework.CSINode, ActionType: framework.Add, Label: "CSINodeAdd"} + // CSINodeUpdate is the event when a CSI node is updated in the cluster. + CSINodeUpdate = framework.ClusterEvent{Resource: framework.CSINode, ActionType: framework.Update, Label: "CSINodeUpdate"} + // CSIDriverAdd is the event when a CSI driver is added in the cluster. + CSIDriverAdd = framework.ClusterEvent{Resource: framework.CSIDriver, ActionType: framework.Add, Label: "CSIDriverAdd"} + // CSIDriverUpdate is the event when a CSI driver is updated in the cluster. + CSIDriverUpdate = framework.ClusterEvent{Resource: framework.CSIDriver, ActionType: framework.Update, Label: "CSIDriverUpdate"} + // CSIStorageCapacityAdd is the event when a CSI storage capacity is added in the cluster. + CSIStorageCapacityAdd = framework.ClusterEvent{Resource: framework.CSIStorageCapacity, ActionType: framework.Add, Label: "CSIStorageCapacityAdd"} + // CSIStorageCapacityUpdate is the event when a CSI storage capacity is updated in the cluster. + CSIStorageCapacityUpdate = framework.ClusterEvent{Resource: framework.CSIStorageCapacity, ActionType: framework.Update, Label: "CSIStorageCapacityUpdate"} + // WildCardEvent semantically matches all resources on all actions. + WildCardEvent = framework.ClusterEvent{Resource: framework.WildCard, ActionType: framework.All, Label: "WildCardEvent"} + // UnschedulableTimeout is the event when a pod stays in unschedulable for longer than timeout. + UnschedulableTimeout = framework.ClusterEvent{Resource: framework.WildCard, ActionType: framework.All, Label: "UnschedulableTimeout"} +) diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/internal/queue/scheduling_queue.go b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/queue/scheduling_queue.go new file mode 100644 index 000000000..a0af8d074 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/queue/scheduling_queue.go @@ -0,0 +1,1118 @@ +/* +Copyright 2017 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. +*/ + +// This file contains structures that implement scheduling queue types. +// Scheduling queues hold pods waiting to be scheduled. This file implements a +// priority queue which has two sub queues and a additional data structure, +// namely: activeQ, backoffQ and unschedulablePods. +// - activeQ holds pods that are being considered for scheduling. +// - backoffQ holds pods that moved from unschedulablePods and will move to +// activeQ when their backoff periods complete. +// - unschedulablePods holds pods that were already attempted for scheduling and +// are currently determined to be unschedulable. + +package queue + +import ( + "context" + "fmt" + "reflect" + "sync" + "time" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/informers" + listersv1 "k8s.io/client-go/listers/core/v1" + "k8s.io/client-go/tools/cache" + "k8s.io/klog/v2" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity" + "k8s.io/kubernetes/pkg/scheduler/internal/heap" + "k8s.io/kubernetes/pkg/scheduler/metrics" + "k8s.io/kubernetes/pkg/scheduler/util" + "k8s.io/utils/clock" +) + +const ( + // DefaultPodMaxInUnschedulablePodsDuration is the default value for the maximum + // time a pod can stay in unschedulablePods. If a pod stays in unschedulablePods + // for longer than this value, the pod will be moved from unschedulablePods to + // backoffQ or activeQ. If this value is empty, the default value (5min) + // will be used. + DefaultPodMaxInUnschedulablePodsDuration time.Duration = 5 * time.Minute + + queueClosed = "scheduling queue is closed" + + // Scheduling queue names + activeQName = "Active" + backoffQName = "Backoff" + unschedulablePods = "Unschedulable" + + preEnqueue = "PreEnqueue" +) + +const ( + // DefaultPodInitialBackoffDuration is the default value for the initial backoff duration + // for unschedulable pods. To change the default podInitialBackoffDurationSeconds used by the + // scheduler, update the ComponentConfig value in defaults.go + DefaultPodInitialBackoffDuration time.Duration = 1 * time.Second + // DefaultPodMaxBackoffDuration is the default value for the max backoff duration + // for unschedulable pods. To change the default podMaxBackoffDurationSeconds used by the + // scheduler, update the ComponentConfig value in defaults.go + DefaultPodMaxBackoffDuration time.Duration = 10 * time.Second +) + +// PreEnqueueCheck is a function type. It's used to build functions that +// run against a Pod and the caller can choose to enqueue or skip the Pod +// by the checking result. +type PreEnqueueCheck func(pod *v1.Pod) bool + +// SchedulingQueue is an interface for a queue to store pods waiting to be scheduled. +// The interface follows a pattern similar to cache.FIFO and cache.Heap and +// makes it easy to use those data structures as a SchedulingQueue. +type SchedulingQueue interface { + framework.PodNominator + Add(pod *v1.Pod) error + // Activate moves the given pods to activeQ iff they're in unschedulablePods or backoffQ. + // The passed-in pods are originally compiled from plugins that want to activate Pods, + // by injecting the pods through a reserved CycleState struct (PodsToActivate). + Activate(pods map[string]*v1.Pod) + // AddUnschedulableIfNotPresent adds an unschedulable pod back to scheduling queue. + // The podSchedulingCycle represents the current scheduling cycle number which can be + // returned by calling SchedulingCycle(). + AddUnschedulableIfNotPresent(pod *framework.QueuedPodInfo, podSchedulingCycle int64) error + // SchedulingCycle returns the current number of scheduling cycle which is + // cached by scheduling queue. Normally, incrementing this number whenever + // a pod is popped (e.g. called Pop()) is enough. + SchedulingCycle() int64 + // Pop removes the head of the queue and returns it. It blocks if the + // queue is empty and waits until a new item is added to the queue. + Pop() (*framework.QueuedPodInfo, error) + Update(oldPod, newPod *v1.Pod) error + Delete(pod *v1.Pod) error + MoveAllToActiveOrBackoffQueue(event framework.ClusterEvent, preCheck PreEnqueueCheck) + AssignedPodAdded(pod *v1.Pod) + AssignedPodUpdated(pod *v1.Pod) + PendingPods() ([]*v1.Pod, string) + // Close closes the SchedulingQueue so that the goroutine which is + // waiting to pop items can exit gracefully. + Close() + // Run starts the goroutines managing the queue. + Run() +} + +// NewSchedulingQueue initializes a priority queue as a new scheduling queue. +func NewSchedulingQueue( + lessFn framework.LessFunc, + informerFactory informers.SharedInformerFactory, + opts ...Option) SchedulingQueue { + return NewPriorityQueue(lessFn, informerFactory, opts...) +} + +// NominatedNodeName returns nominated node name of a Pod. +func NominatedNodeName(pod *v1.Pod) string { + return pod.Status.NominatedNodeName +} + +// PriorityQueue implements a scheduling queue. +// The head of PriorityQueue is the highest priority pending pod. This structure +// has two sub queues and a additional data structure, namely: activeQ, +// backoffQ and unschedulablePods. +// - activeQ holds pods that are being considered for scheduling. +// - backoffQ holds pods that moved from unschedulablePods and will move to +// activeQ when their backoff periods complete. +// - unschedulablePods holds pods that were already attempted for scheduling and +// are currently determined to be unschedulable. +type PriorityQueue struct { + *nominator + + stop chan struct{} + clock clock.Clock + + // pod initial backoff duration. + podInitialBackoffDuration time.Duration + // pod maximum backoff duration. + podMaxBackoffDuration time.Duration + // the maximum time a pod can stay in the unschedulablePods. + podMaxInUnschedulablePodsDuration time.Duration + + cond sync.Cond + + // activeQ is heap structure that scheduler actively looks at to find pods to + // schedule. Head of heap is the highest priority pod. + activeQ *heap.Heap + // podBackoffQ is a heap ordered by backoff expiry. Pods which have completed backoff + // are popped from this heap before the scheduler looks at activeQ + podBackoffQ *heap.Heap + // unschedulablePods holds pods that have been tried and determined unschedulable. + unschedulablePods *UnschedulablePods + // schedulingCycle represents sequence number of scheduling cycle and is incremented + // when a pod is popped. + schedulingCycle int64 + // moveRequestCycle caches the sequence number of scheduling cycle when we + // received a move request. Unschedulable pods in and before this scheduling + // cycle will be put back to activeQueue if we were trying to schedule them + // when we received move request. + moveRequestCycle int64 + + clusterEventMap map[framework.ClusterEvent]sets.String + // preEnqueuePluginMap is keyed with profile name, valued with registered preEnqueue plugins. + preEnqueuePluginMap map[string][]framework.PreEnqueuePlugin + + // closed indicates that the queue is closed. + // It is mainly used to let Pop() exit its control loop while waiting for an item. + closed bool + + nsLister listersv1.NamespaceLister +} + +type priorityQueueOptions struct { + clock clock.Clock + podInitialBackoffDuration time.Duration + podMaxBackoffDuration time.Duration + podMaxInUnschedulablePodsDuration time.Duration + podLister listersv1.PodLister + clusterEventMap map[framework.ClusterEvent]sets.String + preEnqueuePluginMap map[string][]framework.PreEnqueuePlugin +} + +// Option configures a PriorityQueue +type Option func(*priorityQueueOptions) + +// WithClock sets clock for PriorityQueue, the default clock is clock.RealClock. +func WithClock(clock clock.Clock) Option { + return func(o *priorityQueueOptions) { + o.clock = clock + } +} + +// WithPodInitialBackoffDuration sets pod initial backoff duration for PriorityQueue. +func WithPodInitialBackoffDuration(duration time.Duration) Option { + return func(o *priorityQueueOptions) { + o.podInitialBackoffDuration = duration + } +} + +// WithPodMaxBackoffDuration sets pod max backoff duration for PriorityQueue. +func WithPodMaxBackoffDuration(duration time.Duration) Option { + return func(o *priorityQueueOptions) { + o.podMaxBackoffDuration = duration + } +} + +// WithPodLister sets pod lister for PriorityQueue. +func WithPodLister(pl listersv1.PodLister) Option { + return func(o *priorityQueueOptions) { + o.podLister = pl + } +} + +// WithClusterEventMap sets clusterEventMap for PriorityQueue. +func WithClusterEventMap(m map[framework.ClusterEvent]sets.String) Option { + return func(o *priorityQueueOptions) { + o.clusterEventMap = m + } +} + +// WithPodMaxInUnschedulablePodsDuration sets podMaxInUnschedulablePodsDuration for PriorityQueue. +func WithPodMaxInUnschedulablePodsDuration(duration time.Duration) Option { + return func(o *priorityQueueOptions) { + o.podMaxInUnschedulablePodsDuration = duration + } +} + +// WithPreEnqueuePluginMap sets preEnqueuePluginMap for PriorityQueue. +func WithPreEnqueuePluginMap(m map[string][]framework.PreEnqueuePlugin) Option { + return func(o *priorityQueueOptions) { + o.preEnqueuePluginMap = m + } +} + +var defaultPriorityQueueOptions = priorityQueueOptions{ + clock: clock.RealClock{}, + podInitialBackoffDuration: DefaultPodInitialBackoffDuration, + podMaxBackoffDuration: DefaultPodMaxBackoffDuration, + podMaxInUnschedulablePodsDuration: DefaultPodMaxInUnschedulablePodsDuration, +} + +// Making sure that PriorityQueue implements SchedulingQueue. +var _ SchedulingQueue = &PriorityQueue{} + +// newQueuedPodInfoForLookup builds a QueuedPodInfo object for a lookup in the queue. +func newQueuedPodInfoForLookup(pod *v1.Pod, plugins ...string) *framework.QueuedPodInfo { + // Since this is only used for a lookup in the queue, we only need to set the Pod, + // and so we avoid creating a full PodInfo, which is expensive to instantiate frequently. + return &framework.QueuedPodInfo{ + PodInfo: &framework.PodInfo{Pod: pod}, + UnschedulablePlugins: sets.NewString(plugins...), + } +} + +// NewPriorityQueue creates a PriorityQueue object. +func NewPriorityQueue( + lessFn framework.LessFunc, + informerFactory informers.SharedInformerFactory, + opts ...Option, +) *PriorityQueue { + options := defaultPriorityQueueOptions + if options.podLister == nil { + options.podLister = informerFactory.Core().V1().Pods().Lister() + } + for _, opt := range opts { + opt(&options) + } + + comp := func(podInfo1, podInfo2 interface{}) bool { + pInfo1 := podInfo1.(*framework.QueuedPodInfo) + pInfo2 := podInfo2.(*framework.QueuedPodInfo) + return lessFn(pInfo1, pInfo2) + } + + pq := &PriorityQueue{ + nominator: newPodNominator(options.podLister), + clock: options.clock, + stop: make(chan struct{}), + podInitialBackoffDuration: options.podInitialBackoffDuration, + podMaxBackoffDuration: options.podMaxBackoffDuration, + podMaxInUnschedulablePodsDuration: options.podMaxInUnschedulablePodsDuration, + activeQ: heap.NewWithRecorder(podInfoKeyFunc, comp, metrics.NewActivePodsRecorder()), + unschedulablePods: newUnschedulablePods(metrics.NewUnschedulablePodsRecorder(), metrics.NewGatedPodsRecorder()), + moveRequestCycle: -1, + clusterEventMap: options.clusterEventMap, + preEnqueuePluginMap: options.preEnqueuePluginMap, + } + pq.cond.L = &pq.lock + pq.podBackoffQ = heap.NewWithRecorder(podInfoKeyFunc, pq.podsCompareBackoffCompleted, metrics.NewBackoffPodsRecorder()) + pq.nsLister = informerFactory.Core().V1().Namespaces().Lister() + + return pq +} + +// Run starts the goroutine to pump from podBackoffQ to activeQ +func (p *PriorityQueue) Run() { + go wait.Until(p.flushBackoffQCompleted, 1.0*time.Second, p.stop) + go wait.Until(p.flushUnschedulablePodsLeftover, 30*time.Second, p.stop) +} + +// runPreEnqueuePlugins iterates PreEnqueue function in each registered PreEnqueuePlugin. +// It returns true if all PreEnqueue function run successfully; otherwise returns false +// upon the first failure. +// Note: we need to associate the failed plugin to `pInfo`, so that the pod can be moved back +// to activeQ by related cluster event. +func (p *PriorityQueue) runPreEnqueuePlugins(ctx context.Context, pInfo *framework.QueuedPodInfo) bool { + var s *framework.Status + pod := pInfo.Pod + startTime := time.Now() + defer func() { + metrics.FrameworkExtensionPointDuration.WithLabelValues(preEnqueue, s.Code().String(), pod.Spec.SchedulerName).Observe(metrics.SinceInSeconds(startTime)) + }() + + for _, pl := range p.preEnqueuePluginMap[pod.Spec.SchedulerName] { + s = pl.PreEnqueue(ctx, pod) + if s.IsSuccess() { + continue + } + pInfo.UnschedulablePlugins.Insert(pl.Name()) + metrics.UnschedulableReason(pl.Name(), pod.Spec.SchedulerName).Inc() + if s.Code() == framework.Error { + klog.ErrorS(s.AsError(), "Unexpected error running PreEnqueue plugin", "pod", klog.KObj(pod), "plugin", pl.Name()) + } else { + klog.V(5).InfoS("Status after running PreEnqueue plugin", "pod", klog.KObj(pod), "plugin", pl.Name(), "status", s) + } + return false + } + return true +} + +// addToActiveQ tries to add pod to active queue. It returns 2 parameters: +// 1. a boolean flag to indicate whether the pod is added successfully. +// 2. an error for the caller to act on. +func (p *PriorityQueue) addToActiveQ(pInfo *framework.QueuedPodInfo) (bool, error) { + pInfo.Gated = !p.runPreEnqueuePlugins(context.Background(), pInfo) + if pInfo.Gated { + // Add the Pod to unschedulablePods if it's not passing PreEnqueuePlugins. + p.unschedulablePods.addOrUpdate(pInfo) + return false, nil + } + if err := p.activeQ.Add(pInfo); err != nil { + klog.ErrorS(err, "Error adding pod to the active queue", "pod", klog.KObj(pInfo.Pod)) + return false, err + } + return true, nil +} + +// Add adds a pod to the active queue. It should be called only when a new pod +// is added so there is no chance the pod is already in active/unschedulable/backoff queues +func (p *PriorityQueue) Add(pod *v1.Pod) error { + p.lock.Lock() + defer p.lock.Unlock() + + pInfo := p.newQueuedPodInfo(pod) + gated := pInfo.Gated + if added, err := p.addToActiveQ(pInfo); !added { + return err + } + if p.unschedulablePods.get(pod) != nil { + klog.ErrorS(nil, "Error: pod is already in the unschedulable queue", "pod", klog.KObj(pod)) + p.unschedulablePods.delete(pod, gated) + } + // Delete pod from backoffQ if it is backing off + if err := p.podBackoffQ.Delete(pInfo); err == nil { + klog.ErrorS(nil, "Error: pod is already in the podBackoff queue", "pod", klog.KObj(pod)) + } + klog.V(5).InfoS("Pod moved to an internal scheduling queue", "pod", klog.KObj(pod), "event", PodAdd, "queue", activeQName) + metrics.SchedulerQueueIncomingPods.WithLabelValues("active", PodAdd).Inc() + p.addNominatedPodUnlocked(pInfo.PodInfo, nil) + p.cond.Broadcast() + + return nil +} + +// Activate moves the given pods to activeQ iff they're in unschedulablePods or backoffQ. +func (p *PriorityQueue) Activate(pods map[string]*v1.Pod) { + p.lock.Lock() + defer p.lock.Unlock() + + activated := false + for _, pod := range pods { + if p.activate(pod) { + activated = true + } + } + + if activated { + p.cond.Broadcast() + } +} + +func (p *PriorityQueue) activate(pod *v1.Pod) bool { + // Verify if the pod is present in activeQ. + if _, exists, _ := p.activeQ.Get(newQueuedPodInfoForLookup(pod)); exists { + // No need to activate if it's already present in activeQ. + return false + } + var pInfo *framework.QueuedPodInfo + // Verify if the pod is present in unschedulablePods or backoffQ. + if pInfo = p.unschedulablePods.get(pod); pInfo == nil { + // If the pod doesn't belong to unschedulablePods or backoffQ, don't activate it. + if obj, exists, _ := p.podBackoffQ.Get(newQueuedPodInfoForLookup(pod)); !exists { + klog.ErrorS(nil, "To-activate pod does not exist in unschedulablePods or backoffQ", "pod", klog.KObj(pod)) + return false + } else { + pInfo = obj.(*framework.QueuedPodInfo) + } + } + + if pInfo == nil { + // Redundant safe check. We shouldn't reach here. + klog.ErrorS(nil, "Internal error: cannot obtain pInfo") + return false + } + + gated := pInfo.Gated + if added, _ := p.addToActiveQ(pInfo); !added { + return false + } + p.unschedulablePods.delete(pInfo.Pod, gated) + p.podBackoffQ.Delete(pInfo) + metrics.SchedulerQueueIncomingPods.WithLabelValues("active", ForceActivate).Inc() + p.addNominatedPodUnlocked(pInfo.PodInfo, nil) + return true +} + +// isPodBackingoff returns true if a pod is still waiting for its backoff timer. +// If this returns true, the pod should not be re-tried. +func (p *PriorityQueue) isPodBackingoff(podInfo *framework.QueuedPodInfo) bool { + if podInfo.Gated { + return false + } + boTime := p.getBackoffTime(podInfo) + return boTime.After(p.clock.Now()) +} + +// SchedulingCycle returns current scheduling cycle. +func (p *PriorityQueue) SchedulingCycle() int64 { + p.lock.RLock() + defer p.lock.RUnlock() + return p.schedulingCycle +} + +// AddUnschedulableIfNotPresent inserts a pod that cannot be scheduled into +// the queue, unless it is already in the queue. Normally, PriorityQueue puts +// unschedulable pods in `unschedulablePods`. But if there has been a recent move +// request, then the pod is put in `podBackoffQ`. +func (p *PriorityQueue) AddUnschedulableIfNotPresent(pInfo *framework.QueuedPodInfo, podSchedulingCycle int64) error { + p.lock.Lock() + defer p.lock.Unlock() + pod := pInfo.Pod + if p.unschedulablePods.get(pod) != nil { + return fmt.Errorf("Pod %v is already present in unschedulable queue", klog.KObj(pod)) + } + + if _, exists, _ := p.activeQ.Get(pInfo); exists { + return fmt.Errorf("Pod %v is already present in the active queue", klog.KObj(pod)) + } + if _, exists, _ := p.podBackoffQ.Get(pInfo); exists { + return fmt.Errorf("Pod %v is already present in the backoff queue", klog.KObj(pod)) + } + + // Refresh the timestamp since the pod is re-added. + pInfo.Timestamp = p.clock.Now() + + // If a move request has been received, move it to the BackoffQ, otherwise move + // it to unschedulablePods. + for plugin := range pInfo.UnschedulablePlugins { + metrics.UnschedulableReason(plugin, pInfo.Pod.Spec.SchedulerName).Inc() + } + if p.moveRequestCycle >= podSchedulingCycle { + if err := p.podBackoffQ.Add(pInfo); err != nil { + return fmt.Errorf("error adding pod %v to the backoff queue: %v", klog.KObj(pod), err) + } + klog.V(5).InfoS("Pod moved to an internal scheduling queue", "pod", klog.KObj(pod), "event", ScheduleAttemptFailure, "queue", backoffQName) + metrics.SchedulerQueueIncomingPods.WithLabelValues("backoff", ScheduleAttemptFailure).Inc() + } else { + p.unschedulablePods.addOrUpdate(pInfo) + klog.V(5).InfoS("Pod moved to an internal scheduling queue", "pod", klog.KObj(pod), "event", ScheduleAttemptFailure, "queue", unschedulablePods) + metrics.SchedulerQueueIncomingPods.WithLabelValues("unschedulable", ScheduleAttemptFailure).Inc() + + } + + p.addNominatedPodUnlocked(pInfo.PodInfo, nil) + return nil +} + +// flushBackoffQCompleted Moves all pods from backoffQ which have completed backoff in to activeQ +func (p *PriorityQueue) flushBackoffQCompleted() { + p.lock.Lock() + defer p.lock.Unlock() + activated := false + for { + rawPodInfo := p.podBackoffQ.Peek() + if rawPodInfo == nil { + break + } + pInfo := rawPodInfo.(*framework.QueuedPodInfo) + pod := pInfo.Pod + if p.isPodBackingoff(pInfo) { + break + } + _, err := p.podBackoffQ.Pop() + if err != nil { + klog.ErrorS(err, "Unable to pop pod from backoff queue despite backoff completion", "pod", klog.KObj(pod)) + break + } + if added, _ := p.addToActiveQ(pInfo); added { + klog.V(5).InfoS("Pod moved to an internal scheduling queue", "pod", klog.KObj(pod), "event", BackoffComplete, "queue", activeQName) + metrics.SchedulerQueueIncomingPods.WithLabelValues("active", BackoffComplete).Inc() + activated = true + } + } + + if activated { + p.cond.Broadcast() + } +} + +// flushUnschedulablePodsLeftover moves pods which stay in unschedulablePods +// longer than podMaxInUnschedulablePodsDuration to backoffQ or activeQ. +func (p *PriorityQueue) flushUnschedulablePodsLeftover() { + p.lock.Lock() + defer p.lock.Unlock() + + var podsToMove []*framework.QueuedPodInfo + currentTime := p.clock.Now() + for _, pInfo := range p.unschedulablePods.podInfoMap { + lastScheduleTime := pInfo.Timestamp + if currentTime.Sub(lastScheduleTime) > p.podMaxInUnschedulablePodsDuration { + podsToMove = append(podsToMove, pInfo) + } + } + + if len(podsToMove) > 0 { + p.movePodsToActiveOrBackoffQueue(podsToMove, UnschedulableTimeout) + } +} + +// Pop removes the head of the active queue and returns it. It blocks if the +// activeQ is empty and waits until a new item is added to the queue. It +// increments scheduling cycle when a pod is popped. +func (p *PriorityQueue) Pop() (*framework.QueuedPodInfo, error) { + p.lock.Lock() + defer p.lock.Unlock() + for p.activeQ.Len() == 0 { + // When the queue is empty, invocation of Pop() is blocked until new item is enqueued. + // When Close() is called, the p.closed is set and the condition is broadcast, + // which causes this loop to continue and return from the Pop(). + if p.closed { + return nil, fmt.Errorf(queueClosed) + } + p.cond.Wait() + } + obj, err := p.activeQ.Pop() + if err != nil { + return nil, err + } + pInfo := obj.(*framework.QueuedPodInfo) + pInfo.Attempts++ + p.schedulingCycle++ + return pInfo, nil +} + +// isPodUpdated checks if the pod is updated in a way that it may have become +// schedulable. It drops status of the pod and compares it with old version. +func isPodUpdated(oldPod, newPod *v1.Pod) bool { + strip := func(pod *v1.Pod) *v1.Pod { + p := pod.DeepCopy() + p.ResourceVersion = "" + p.Generation = 0 + p.Status = v1.PodStatus{} + p.ManagedFields = nil + p.Finalizers = nil + return p + } + return !reflect.DeepEqual(strip(oldPod), strip(newPod)) +} + +// Update updates a pod in the active or backoff queue if present. Otherwise, it removes +// the item from the unschedulable queue if pod is updated in a way that it may +// become schedulable and adds the updated one to the active queue. +// If pod is not present in any of the queues, it is added to the active queue. +func (p *PriorityQueue) Update(oldPod, newPod *v1.Pod) error { + p.lock.Lock() + defer p.lock.Unlock() + + if oldPod != nil { + oldPodInfo := newQueuedPodInfoForLookup(oldPod) + // If the pod is already in the active queue, just update it there. + if oldPodInfo, exists, _ := p.activeQ.Get(oldPodInfo); exists { + pInfo := updatePod(oldPodInfo, newPod) + p.updateNominatedPodUnlocked(oldPod, pInfo.PodInfo) + return p.activeQ.Update(pInfo) + } + + // If the pod is in the backoff queue, update it there. + if oldPodInfo, exists, _ := p.podBackoffQ.Get(oldPodInfo); exists { + pInfo := updatePod(oldPodInfo, newPod) + p.updateNominatedPodUnlocked(oldPod, pInfo.PodInfo) + return p.podBackoffQ.Update(pInfo) + } + } + + // If the pod is in the unschedulable queue, updating it may make it schedulable. + if usPodInfo := p.unschedulablePods.get(newPod); usPodInfo != nil { + pInfo := updatePod(usPodInfo, newPod) + p.updateNominatedPodUnlocked(oldPod, pInfo.PodInfo) + if isPodUpdated(oldPod, newPod) { + gated := usPodInfo.Gated + if p.isPodBackingoff(usPodInfo) { + if err := p.podBackoffQ.Add(pInfo); err != nil { + return err + } + p.unschedulablePods.delete(usPodInfo.Pod, gated) + klog.V(5).InfoS("Pod moved to an internal scheduling queue", "pod", klog.KObj(pInfo.Pod), "event", PodUpdate, "queue", backoffQName) + } else { + if added, err := p.addToActiveQ(pInfo); !added { + return err + } + p.unschedulablePods.delete(usPodInfo.Pod, gated) + klog.V(5).InfoS("Pod moved to an internal scheduling queue", "pod", klog.KObj(pInfo.Pod), "event", BackoffComplete, "queue", activeQName) + p.cond.Broadcast() + } + } else { + // Pod update didn't make it schedulable, keep it in the unschedulable queue. + p.unschedulablePods.addOrUpdate(pInfo) + } + + return nil + } + // If pod is not in any of the queues, we put it in the active queue. + pInfo := p.newQueuedPodInfo(newPod) + if added, err := p.addToActiveQ(pInfo); !added { + return err + } + p.addNominatedPodUnlocked(pInfo.PodInfo, nil) + klog.V(5).InfoS("Pod moved to an internal scheduling queue", "pod", klog.KObj(pInfo.Pod), "event", PodUpdate, "queue", activeQName) + p.cond.Broadcast() + return nil +} + +// Delete deletes the item from either of the two queues. It assumes the pod is +// only in one queue. +func (p *PriorityQueue) Delete(pod *v1.Pod) error { + p.lock.Lock() + defer p.lock.Unlock() + p.deleteNominatedPodIfExistsUnlocked(pod) + pInfo := newQueuedPodInfoForLookup(pod) + if err := p.activeQ.Delete(pInfo); err != nil { + // The item was probably not found in the activeQ. + p.podBackoffQ.Delete(pInfo) + if pInfo = p.unschedulablePods.get(pod); pInfo != nil { + p.unschedulablePods.delete(pod, pInfo.Gated) + } + } + return nil +} + +// AssignedPodAdded is called when a bound pod is added. Creation of this pod +// may make pending pods with matching affinity terms schedulable. +func (p *PriorityQueue) AssignedPodAdded(pod *v1.Pod) { + p.lock.Lock() + p.movePodsToActiveOrBackoffQueue(p.getUnschedulablePodsWithMatchingAffinityTerm(pod), AssignedPodAdd) + p.lock.Unlock() +} + +// AssignedPodUpdated is called when a bound pod is updated. Change of labels +// may make pending pods with matching affinity terms schedulable. +func (p *PriorityQueue) AssignedPodUpdated(pod *v1.Pod) { + p.lock.Lock() + p.movePodsToActiveOrBackoffQueue(p.getUnschedulablePodsWithMatchingAffinityTerm(pod), AssignedPodUpdate) + p.lock.Unlock() +} + +// MoveAllToActiveOrBackoffQueue moves all pods from unschedulablePods to activeQ or backoffQ. +// This function adds all pods and then signals the condition variable to ensure that +// if Pop() is waiting for an item, it receives the signal after all the pods are in the +// queue and the head is the highest priority pod. +func (p *PriorityQueue) MoveAllToActiveOrBackoffQueue(event framework.ClusterEvent, preCheck PreEnqueueCheck) { + p.lock.Lock() + defer p.lock.Unlock() + unschedulablePods := make([]*framework.QueuedPodInfo, 0, len(p.unschedulablePods.podInfoMap)) + for _, pInfo := range p.unschedulablePods.podInfoMap { + if preCheck == nil || preCheck(pInfo.Pod) { + unschedulablePods = append(unschedulablePods, pInfo) + } + } + p.movePodsToActiveOrBackoffQueue(unschedulablePods, event) +} + +// NOTE: this function assumes lock has been acquired in caller +func (p *PriorityQueue) movePodsToActiveOrBackoffQueue(podInfoList []*framework.QueuedPodInfo, event framework.ClusterEvent) { + activated := false + for _, pInfo := range podInfoList { + // If the event doesn't help making the Pod schedulable, continue. + // Note: we don't run the check if pInfo.UnschedulablePlugins is nil, which denotes + // either there is some abnormal error, or scheduling the pod failed by plugins other than PreFilter, Filter and Permit. + // In that case, it's desired to move it anyways. + if len(pInfo.UnschedulablePlugins) != 0 && !p.podMatchesEvent(pInfo, event) { + continue + } + pod := pInfo.Pod + if p.isPodBackingoff(pInfo) { + if err := p.podBackoffQ.Add(pInfo); err != nil { + klog.ErrorS(err, "Error adding pod to the backoff queue", "pod", klog.KObj(pod)) + } else { + klog.V(5).InfoS("Pod moved to an internal scheduling queue", "pod", klog.KObj(pInfo.Pod), "event", event, "queue", backoffQName) + metrics.SchedulerQueueIncomingPods.WithLabelValues("backoff", event.Label).Inc() + p.unschedulablePods.delete(pod, pInfo.Gated) + } + } else { + gated := pInfo.Gated + if added, _ := p.addToActiveQ(pInfo); added { + klog.V(5).InfoS("Pod moved to an internal scheduling queue", "pod", klog.KObj(pInfo.Pod), "event", event, "queue", activeQName) + activated = true + metrics.SchedulerQueueIncomingPods.WithLabelValues("active", event.Label).Inc() + p.unschedulablePods.delete(pod, gated) + } + } + } + p.moveRequestCycle = p.schedulingCycle + if activated { + p.cond.Broadcast() + } +} + +// getUnschedulablePodsWithMatchingAffinityTerm returns unschedulable pods which have +// any affinity term that matches "pod". +// NOTE: this function assumes lock has been acquired in caller. +func (p *PriorityQueue) getUnschedulablePodsWithMatchingAffinityTerm(pod *v1.Pod) []*framework.QueuedPodInfo { + nsLabels := interpodaffinity.GetNamespaceLabelsSnapshot(pod.Namespace, p.nsLister) + + var podsToMove []*framework.QueuedPodInfo + for _, pInfo := range p.unschedulablePods.podInfoMap { + for _, term := range pInfo.RequiredAffinityTerms { + if term.Matches(pod, nsLabels) { + podsToMove = append(podsToMove, pInfo) + break + } + } + + } + return podsToMove +} + +var pendingPodsSummary = "activeQ:%v; backoffQ:%v; unschedulablePods:%v" + +// PendingPods returns all the pending pods in the queue; accompanied by a debugging string +// recording showing the number of pods in each queue respectively. +// This function is used for debugging purposes in the scheduler cache dumper and comparer. +func (p *PriorityQueue) PendingPods() ([]*v1.Pod, string) { + p.lock.RLock() + defer p.lock.RUnlock() + var result []*v1.Pod + for _, pInfo := range p.activeQ.List() { + result = append(result, pInfo.(*framework.QueuedPodInfo).Pod) + } + for _, pInfo := range p.podBackoffQ.List() { + result = append(result, pInfo.(*framework.QueuedPodInfo).Pod) + } + for _, pInfo := range p.unschedulablePods.podInfoMap { + result = append(result, pInfo.Pod) + } + return result, fmt.Sprintf(pendingPodsSummary, p.activeQ.Len(), p.podBackoffQ.Len(), len(p.unschedulablePods.podInfoMap)) +} + +// Close closes the priority queue. +func (p *PriorityQueue) Close() { + p.lock.Lock() + defer p.lock.Unlock() + close(p.stop) + p.closed = true + p.cond.Broadcast() +} + +// DeleteNominatedPodIfExists deletes from nominatedPods. +func (npm *nominator) DeleteNominatedPodIfExists(pod *v1.Pod) { + npm.lock.Lock() + npm.deleteNominatedPodIfExistsUnlocked(pod) + npm.lock.Unlock() +} + +func (npm *nominator) deleteNominatedPodIfExistsUnlocked(pod *v1.Pod) { + npm.delete(pod) +} + +// AddNominatedPod adds a pod to the nominated pods of the given node. +// This is called during the preemption process after a node is nominated to run +// the pod. We update the structure before sending a request to update the pod +// object to avoid races with the following scheduling cycles. +func (npm *nominator) AddNominatedPod(pi *framework.PodInfo, nominatingInfo *framework.NominatingInfo) { + npm.lock.Lock() + npm.addNominatedPodUnlocked(pi, nominatingInfo) + npm.lock.Unlock() +} + +// NominatedPodsForNode returns a copy of pods that are nominated to run on the given node, +// but they are waiting for other pods to be removed from the node. +func (npm *nominator) NominatedPodsForNode(nodeName string) []*framework.PodInfo { + npm.lock.RLock() + defer npm.lock.RUnlock() + // Make a copy of the nominated Pods so the caller can mutate safely. + pods := make([]*framework.PodInfo, len(npm.nominatedPods[nodeName])) + for i := 0; i < len(pods); i++ { + pods[i] = npm.nominatedPods[nodeName][i].DeepCopy() + } + return pods +} + +func (p *PriorityQueue) podsCompareBackoffCompleted(podInfo1, podInfo2 interface{}) bool { + pInfo1 := podInfo1.(*framework.QueuedPodInfo) + pInfo2 := podInfo2.(*framework.QueuedPodInfo) + bo1 := p.getBackoffTime(pInfo1) + bo2 := p.getBackoffTime(pInfo2) + return bo1.Before(bo2) +} + +// newQueuedPodInfo builds a QueuedPodInfo object. +func (p *PriorityQueue) newQueuedPodInfo(pod *v1.Pod, plugins ...string) *framework.QueuedPodInfo { + now := p.clock.Now() + // ignore this err since apiserver doesn't properly validate affinity terms + // and we can't fix the validation for backwards compatibility. + podInfo, _ := framework.NewPodInfo(pod) + return &framework.QueuedPodInfo{ + PodInfo: podInfo, + Timestamp: now, + InitialAttemptTimestamp: now, + UnschedulablePlugins: sets.NewString(plugins...), + } +} + +// getBackoffTime returns the time that podInfo completes backoff +func (p *PriorityQueue) getBackoffTime(podInfo *framework.QueuedPodInfo) time.Time { + duration := p.calculateBackoffDuration(podInfo) + backoffTime := podInfo.Timestamp.Add(duration) + return backoffTime +} + +// calculateBackoffDuration is a helper function for calculating the backoffDuration +// based on the number of attempts the pod has made. +func (p *PriorityQueue) calculateBackoffDuration(podInfo *framework.QueuedPodInfo) time.Duration { + duration := p.podInitialBackoffDuration + for i := 1; i < podInfo.Attempts; i++ { + // Use subtraction instead of addition or multiplication to avoid overflow. + if duration > p.podMaxBackoffDuration-duration { + return p.podMaxBackoffDuration + } + duration += duration + } + return duration +} + +func updatePod(oldPodInfo interface{}, newPod *v1.Pod) *framework.QueuedPodInfo { + pInfo := oldPodInfo.(*framework.QueuedPodInfo) + pInfo.Update(newPod) + return pInfo +} + +// UnschedulablePods holds pods that cannot be scheduled. This data structure +// is used to implement unschedulablePods. +type UnschedulablePods struct { + // podInfoMap is a map key by a pod's full-name and the value is a pointer to the QueuedPodInfo. + podInfoMap map[string]*framework.QueuedPodInfo + keyFunc func(*v1.Pod) string + // unschedulableRecorder/gatedRecorder updates the counter when elements of an unschedulablePodsMap + // get added or removed, and it does nothing if it's nil. + unschedulableRecorder, gatedRecorder metrics.MetricRecorder +} + +// addOrUpdate adds a pod to the unschedulable podInfoMap. +func (u *UnschedulablePods) addOrUpdate(pInfo *framework.QueuedPodInfo) { + podID := u.keyFunc(pInfo.Pod) + if _, exists := u.podInfoMap[podID]; !exists { + if pInfo.Gated && u.gatedRecorder != nil { + u.gatedRecorder.Inc() + } else if !pInfo.Gated && u.unschedulableRecorder != nil { + u.unschedulableRecorder.Inc() + } + } + u.podInfoMap[podID] = pInfo +} + +// delete deletes a pod from the unschedulable podInfoMap. +// The `gated` parameter is used to figure out which metric should be decreased. +func (u *UnschedulablePods) delete(pod *v1.Pod, gated bool) { + podID := u.keyFunc(pod) + if _, exists := u.podInfoMap[podID]; exists { + if gated && u.gatedRecorder != nil { + u.gatedRecorder.Dec() + } else if !gated && u.unschedulableRecorder != nil { + u.unschedulableRecorder.Dec() + } + } + delete(u.podInfoMap, podID) +} + +// get returns the QueuedPodInfo if a pod with the same key as the key of the given "pod" +// is found in the map. It returns nil otherwise. +func (u *UnschedulablePods) get(pod *v1.Pod) *framework.QueuedPodInfo { + podKey := u.keyFunc(pod) + if pInfo, exists := u.podInfoMap[podKey]; exists { + return pInfo + } + return nil +} + +// clear removes all the entries from the unschedulable podInfoMap. +func (u *UnschedulablePods) clear() { + u.podInfoMap = make(map[string]*framework.QueuedPodInfo) + if u.unschedulableRecorder != nil { + u.unschedulableRecorder.Clear() + } + if u.gatedRecorder != nil { + u.gatedRecorder.Clear() + } +} + +// newUnschedulablePods initializes a new object of UnschedulablePods. +func newUnschedulablePods(unschedulableRecorder, gatedRecorder metrics.MetricRecorder) *UnschedulablePods { + return &UnschedulablePods{ + podInfoMap: make(map[string]*framework.QueuedPodInfo), + keyFunc: util.GetPodFullName, + unschedulableRecorder: unschedulableRecorder, + gatedRecorder: gatedRecorder, + } +} + +// nominator is a structure that stores pods nominated to run on nodes. +// It exists because nominatedNodeName of pod objects stored in the structure +// may be different than what scheduler has here. We should be able to find pods +// by their UID and update/delete them. +type nominator struct { + // podLister is used to verify if the given pod is alive. + podLister listersv1.PodLister + // nominatedPods is a map keyed by a node name and the value is a list of + // pods which are nominated to run on the node. These are pods which can be in + // the activeQ or unschedulablePods. + nominatedPods map[string][]*framework.PodInfo + // nominatedPodToNode is map keyed by a Pod UID to the node name where it is + // nominated. + nominatedPodToNode map[types.UID]string + + lock sync.RWMutex +} + +func (npm *nominator) addNominatedPodUnlocked(pi *framework.PodInfo, nominatingInfo *framework.NominatingInfo) { + // Always delete the pod if it already exists, to ensure we never store more than + // one instance of the pod. + npm.delete(pi.Pod) + + var nodeName string + if nominatingInfo.Mode() == framework.ModeOverride { + nodeName = nominatingInfo.NominatedNodeName + } else if nominatingInfo.Mode() == framework.ModeNoop { + if pi.Pod.Status.NominatedNodeName == "" { + return + } + nodeName = pi.Pod.Status.NominatedNodeName + } + + if npm.podLister != nil { + // If the pod was removed or if it was already scheduled, don't nominate it. + updatedPod, err := npm.podLister.Pods(pi.Pod.Namespace).Get(pi.Pod.Name) + if err != nil { + klog.V(4).InfoS("Pod doesn't exist in podLister, aborted adding it to the nominator", "pod", klog.KObj(pi.Pod)) + return + } + if updatedPod.Spec.NodeName != "" { + klog.V(4).InfoS("Pod is already scheduled to a node, aborted adding it to the nominator", "pod", klog.KObj(pi.Pod), "node", updatedPod.Spec.NodeName) + return + } + } + + npm.nominatedPodToNode[pi.Pod.UID] = nodeName + for _, npi := range npm.nominatedPods[nodeName] { + if npi.Pod.UID == pi.Pod.UID { + klog.V(4).InfoS("Pod already exists in the nominator", "pod", klog.KObj(npi.Pod)) + return + } + } + npm.nominatedPods[nodeName] = append(npm.nominatedPods[nodeName], pi) +} + +func (npm *nominator) delete(p *v1.Pod) { + nnn, ok := npm.nominatedPodToNode[p.UID] + if !ok { + return + } + for i, np := range npm.nominatedPods[nnn] { + if np.Pod.UID == p.UID { + npm.nominatedPods[nnn] = append(npm.nominatedPods[nnn][:i], npm.nominatedPods[nnn][i+1:]...) + if len(npm.nominatedPods[nnn]) == 0 { + delete(npm.nominatedPods, nnn) + } + break + } + } + delete(npm.nominatedPodToNode, p.UID) +} + +// UpdateNominatedPod updates the with . +func (npm *nominator) UpdateNominatedPod(oldPod *v1.Pod, newPodInfo *framework.PodInfo) { + npm.lock.Lock() + defer npm.lock.Unlock() + npm.updateNominatedPodUnlocked(oldPod, newPodInfo) +} + +func (npm *nominator) updateNominatedPodUnlocked(oldPod *v1.Pod, newPodInfo *framework.PodInfo) { + // In some cases, an Update event with no "NominatedNode" present is received right + // after a node("NominatedNode") is reserved for this pod in memory. + // In this case, we need to keep reserving the NominatedNode when updating the pod pointer. + var nominatingInfo *framework.NominatingInfo + // We won't fall into below `if` block if the Update event represents: + // (1) NominatedNode info is added + // (2) NominatedNode info is updated + // (3) NominatedNode info is removed + if NominatedNodeName(oldPod) == "" && NominatedNodeName(newPodInfo.Pod) == "" { + if nnn, ok := npm.nominatedPodToNode[oldPod.UID]; ok { + // This is the only case we should continue reserving the NominatedNode + nominatingInfo = &framework.NominatingInfo{ + NominatingMode: framework.ModeOverride, + NominatedNodeName: nnn, + } + } + } + // We update irrespective of the nominatedNodeName changed or not, to ensure + // that pod pointer is updated. + npm.delete(oldPod) + npm.addNominatedPodUnlocked(newPodInfo, nominatingInfo) +} + +// NewPodNominator creates a nominator as a backing of framework.PodNominator. +// A podLister is passed in so as to check if the pod exists +// before adding its nominatedNode info. +func NewPodNominator(podLister listersv1.PodLister) framework.PodNominator { + return newPodNominator(podLister) +} + +func newPodNominator(podLister listersv1.PodLister) *nominator { + return &nominator{ + podLister: podLister, + nominatedPods: make(map[string][]*framework.PodInfo), + nominatedPodToNode: make(map[types.UID]string), + } +} + +// MakeNextPodFunc returns a function to retrieve the next pod from a given +// scheduling queue +func MakeNextPodFunc(queue SchedulingQueue) func() *framework.QueuedPodInfo { + return func() *framework.QueuedPodInfo { + podInfo, err := queue.Pop() + if err == nil { + klog.V(4).InfoS("About to try and schedule pod", "pod", klog.KObj(podInfo.Pod)) + for plugin := range podInfo.UnschedulablePlugins { + metrics.UnschedulableReason(plugin, podInfo.Pod.Spec.SchedulerName).Dec() + } + return podInfo + } + klog.ErrorS(err, "Error while retrieving next pod from scheduling queue") + return nil + } +} + +func podInfoKeyFunc(obj interface{}) (string, error) { + return cache.MetaNamespaceKeyFunc(obj.(*framework.QueuedPodInfo).Pod) +} + +// Checks if the Pod may become schedulable upon the event. +// This is achieved by looking up the global clusterEventMap registry. +func (p *PriorityQueue) podMatchesEvent(podInfo *framework.QueuedPodInfo, clusterEvent framework.ClusterEvent) bool { + if clusterEvent.IsWildCard() { + return true + } + + for evt, nameSet := range p.clusterEventMap { + // Firstly verify if the two ClusterEvents match: + // - either the registered event from plugin side is a WildCardEvent, + // - or the two events have identical Resource fields and *compatible* ActionType. + // Note the ActionTypes don't need to be *identical*. We check if the ANDed value + // is zero or not. In this way, it's easy to tell Update&Delete is not compatible, + // but Update&All is. + evtMatch := evt.IsWildCard() || + (evt.Resource == clusterEvent.Resource && evt.ActionType&clusterEvent.ActionType != 0) + + // Secondly verify the plugin name matches. + // Note that if it doesn't match, we shouldn't continue to search. + if evtMatch && intersect(nameSet, podInfo.UnschedulablePlugins) { + return true + } + } + + return false +} + +func intersect(x, y sets.String) bool { + if len(x) > len(y) { + x, y = y, x + } + for v := range x { + if y.Has(v) { + return true + } + } + return false +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/internal/queue/testing.go b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/queue/testing.go new file mode 100644 index 000000000..e0ee28312 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/internal/queue/testing.go @@ -0,0 +1,55 @@ +/* +Copyright 2021 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 queue + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/informers" + "k8s.io/client-go/kubernetes/fake" + "k8s.io/kubernetes/pkg/scheduler/framework" +) + +// NewTestQueue creates a priority queue with an empty informer factory. +func NewTestQueue(ctx context.Context, lessFn framework.LessFunc, opts ...Option) *PriorityQueue { + return NewTestQueueWithObjects(ctx, lessFn, nil, opts...) +} + +// NewTestQueueWithObjects creates a priority queue with an informer factory +// populated with the provided objects. +func NewTestQueueWithObjects( + ctx context.Context, + lessFn framework.LessFunc, + objs []runtime.Object, + opts ...Option, +) *PriorityQueue { + informerFactory := informers.NewSharedInformerFactory(fake.NewSimpleClientset(objs...), 0) + return NewTestQueueWithInformerFactory(ctx, lessFn, informerFactory, opts...) +} + +func NewTestQueueWithInformerFactory( + ctx context.Context, + lessFn framework.LessFunc, + informerFactory informers.SharedInformerFactory, + opts ...Option, +) *PriorityQueue { + pq := NewPriorityQueue(lessFn, informerFactory, opts...) + informerFactory.Start(ctx.Done()) + informerFactory.WaitForCacheSync(ctx.Done()) + return pq +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/metrics/metric_recorder.go b/vendor/k8s.io/kubernetes/pkg/scheduler/metrics/metric_recorder.go new file mode 100644 index 000000000..b52b6a545 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/metrics/metric_recorder.go @@ -0,0 +1,79 @@ +/* +Copyright 2019 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 metrics + +import ( + "k8s.io/component-base/metrics" +) + +// MetricRecorder represents a metric recorder which takes action when the +// metric Inc(), Dec() and Clear() +type MetricRecorder interface { + Inc() + Dec() + Clear() +} + +var _ MetricRecorder = &PendingPodsRecorder{} + +// PendingPodsRecorder is an implementation of MetricRecorder +type PendingPodsRecorder struct { + recorder metrics.GaugeMetric +} + +// NewActivePodsRecorder returns ActivePods in a Prometheus metric fashion +func NewActivePodsRecorder() *PendingPodsRecorder { + return &PendingPodsRecorder{ + recorder: ActivePods(), + } +} + +// NewUnschedulablePodsRecorder returns UnschedulablePods in a Prometheus metric fashion +func NewUnschedulablePodsRecorder() *PendingPodsRecorder { + return &PendingPodsRecorder{ + recorder: UnschedulablePods(), + } +} + +// NewBackoffPodsRecorder returns BackoffPods in a Prometheus metric fashion +func NewBackoffPodsRecorder() *PendingPodsRecorder { + return &PendingPodsRecorder{ + recorder: BackoffPods(), + } +} + +// NewGatedPodsRecorder returns GatedPods in a Prometheus metric fashion +func NewGatedPodsRecorder() *PendingPodsRecorder { + return &PendingPodsRecorder{ + recorder: GatedPods(), + } +} + +// Inc increases a metric counter by 1, in an atomic way +func (r *PendingPodsRecorder) Inc() { + r.recorder.Inc() +} + +// Dec decreases a metric counter by 1, in an atomic way +func (r *PendingPodsRecorder) Dec() { + r.recorder.Dec() +} + +// Clear set a metric counter to 0, in an atomic way +func (r *PendingPodsRecorder) Clear() { + r.recorder.Set(float64(0)) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/metrics/metrics.go b/vendor/k8s.io/kubernetes/pkg/scheduler/metrics/metrics.go new file mode 100644 index 000000000..335cba293 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/metrics/metrics.go @@ -0,0 +1,264 @@ +/* +Copyright 2015 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 metrics + +import ( + "sync" + "time" + + "k8s.io/component-base/metrics" + "k8s.io/component-base/metrics/legacyregistry" + volumebindingmetrics "k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/metrics" +) + +const ( + // SchedulerSubsystem - subsystem name used by scheduler + SchedulerSubsystem = "scheduler" + // Below are possible values for the work label. + + // PrioritizingExtender - prioritizing extender work label value + PrioritizingExtender = "prioritizing_extender" + // Binding - binding work label value + Binding = "binding" +) + +// All the histogram based metrics have 1ms as size for the smallest bucket. +var ( + scheduleAttempts = metrics.NewCounterVec( + &metrics.CounterOpts{ + Subsystem: SchedulerSubsystem, + Name: "schedule_attempts_total", + Help: "Number of attempts to schedule pods, by the result. 'unschedulable' means a pod could not be scheduled, while 'error' means an internal scheduler problem.", + StabilityLevel: metrics.STABLE, + }, []string{"result", "profile"}) + + e2eSchedulingLatency = metrics.NewHistogramVec( + &metrics.HistogramOpts{ + Subsystem: SchedulerSubsystem, + Name: "e2e_scheduling_duration_seconds", + DeprecatedVersion: "1.23.0", + Help: "E2e scheduling latency in seconds (scheduling algorithm + binding). This metric is replaced by scheduling_attempt_duration_seconds.", + Buckets: metrics.ExponentialBuckets(0.001, 2, 15), + StabilityLevel: metrics.ALPHA, + }, []string{"result", "profile"}) + schedulingLatency = metrics.NewHistogramVec( + &metrics.HistogramOpts{ + Subsystem: SchedulerSubsystem, + Name: "scheduling_attempt_duration_seconds", + Help: "Scheduling attempt latency in seconds (scheduling algorithm + binding)", + Buckets: metrics.ExponentialBuckets(0.001, 2, 15), + StabilityLevel: metrics.STABLE, + }, []string{"result", "profile"}) + SchedulingAlgorithmLatency = metrics.NewHistogram( + &metrics.HistogramOpts{ + Subsystem: SchedulerSubsystem, + Name: "scheduling_algorithm_duration_seconds", + Help: "Scheduling algorithm latency in seconds", + Buckets: metrics.ExponentialBuckets(0.001, 2, 15), + StabilityLevel: metrics.ALPHA, + }, + ) + PreemptionVictims = metrics.NewHistogram( + &metrics.HistogramOpts{ + Subsystem: SchedulerSubsystem, + Name: "preemption_victims", + Help: "Number of selected preemption victims", + // we think #victims>64 is pretty rare, therefore [64, +Inf) is considered a single bucket. + Buckets: metrics.ExponentialBuckets(1, 2, 7), + StabilityLevel: metrics.STABLE, + }) + PreemptionAttempts = metrics.NewCounter( + &metrics.CounterOpts{ + Subsystem: SchedulerSubsystem, + Name: "preemption_attempts_total", + Help: "Total preemption attempts in the cluster till now", + StabilityLevel: metrics.STABLE, + }) + pendingPods = metrics.NewGaugeVec( + &metrics.GaugeOpts{ + Subsystem: SchedulerSubsystem, + Name: "pending_pods", + Help: "Number of pending pods, by the queue type. 'active' means number of pods in activeQ; 'backoff' means number of pods in backoffQ; 'unschedulable' means number of pods in unschedulablePods that the scheduler attempted to schedule and failed; 'gated' is the number of unschedulable pods that the scheduler never attempted to schedule because they are gated.", + StabilityLevel: metrics.STABLE, + }, []string{"queue"}) + // SchedulerGoroutines isn't called in some parts where goroutines start. + // Goroutines metric replaces SchedulerGoroutines metric. Goroutine metric tracks all goroutines. + SchedulerGoroutines = metrics.NewGaugeVec( + &metrics.GaugeOpts{ + Subsystem: SchedulerSubsystem, + DeprecatedVersion: "1.26.0", + Name: "scheduler_goroutines", + Help: "Number of running goroutines split by the work they do such as binding. This metric is replaced by the \"goroutines\" metric.", + StabilityLevel: metrics.ALPHA, + }, []string{"work"}) + Goroutines = metrics.NewGaugeVec( + &metrics.GaugeOpts{ + Subsystem: SchedulerSubsystem, + Name: "goroutines", + Help: "Number of running goroutines split by the work they do such as binding.", + StabilityLevel: metrics.ALPHA, + }, []string{"operation"}) + PodSchedulingDuration = metrics.NewHistogramVec( + &metrics.HistogramOpts{ + Subsystem: SchedulerSubsystem, + Name: "pod_scheduling_duration_seconds", + Help: "E2e latency for a pod being scheduled which may include multiple scheduling attempts.", + // Start with 10ms with the last bucket being [~88m, Inf). + Buckets: metrics.ExponentialBuckets(0.01, 2, 20), + StabilityLevel: metrics.STABLE, + }, + []string{"attempts"}) + + PodSchedulingAttempts = metrics.NewHistogram( + &metrics.HistogramOpts{ + Subsystem: SchedulerSubsystem, + Name: "pod_scheduling_attempts", + Help: "Number of attempts to successfully schedule a pod.", + Buckets: metrics.ExponentialBuckets(1, 2, 5), + StabilityLevel: metrics.STABLE, + }) + + FrameworkExtensionPointDuration = metrics.NewHistogramVec( + &metrics.HistogramOpts{ + Subsystem: SchedulerSubsystem, + Name: "framework_extension_point_duration_seconds", + Help: "Latency for running all plugins of a specific extension point.", + // Start with 0.1ms with the last bucket being [~200ms, Inf) + Buckets: metrics.ExponentialBuckets(0.0001, 2, 12), + StabilityLevel: metrics.STABLE, + }, + []string{"extension_point", "status", "profile"}) + + PluginExecutionDuration = metrics.NewHistogramVec( + &metrics.HistogramOpts{ + Subsystem: SchedulerSubsystem, + Name: "plugin_execution_duration_seconds", + Help: "Duration for running a plugin at a specific extension point.", + // Start with 0.01ms with the last bucket being [~22ms, Inf). We use a small factor (1.5) + // so that we have better granularity since plugin latency is very sensitive. + Buckets: metrics.ExponentialBuckets(0.00001, 1.5, 20), + StabilityLevel: metrics.ALPHA, + }, + []string{"plugin", "extension_point", "status"}) + + SchedulerQueueIncomingPods = metrics.NewCounterVec( + &metrics.CounterOpts{ + Subsystem: SchedulerSubsystem, + Name: "queue_incoming_pods_total", + Help: "Number of pods added to scheduling queues by event and queue type.", + StabilityLevel: metrics.STABLE, + }, []string{"queue", "event"}) + + PermitWaitDuration = metrics.NewHistogramVec( + &metrics.HistogramOpts{ + Subsystem: SchedulerSubsystem, + Name: "permit_wait_duration_seconds", + Help: "Duration of waiting on permit.", + Buckets: metrics.ExponentialBuckets(0.001, 2, 15), + StabilityLevel: metrics.ALPHA, + }, + []string{"result"}) + + CacheSize = metrics.NewGaugeVec( + &metrics.GaugeOpts{ + Subsystem: SchedulerSubsystem, + Name: "scheduler_cache_size", + Help: "Number of nodes, pods, and assumed (bound) pods in the scheduler cache.", + StabilityLevel: metrics.ALPHA, + }, []string{"type"}) + + unschedulableReasons = metrics.NewGaugeVec( + &metrics.GaugeOpts{ + Subsystem: SchedulerSubsystem, + Name: "unschedulable_pods", + Help: "The number of unschedulable pods broken down by plugin name. A pod will increment the gauge for all plugins that caused it to not schedule and so this metric have meaning only when broken down by plugin.", + StabilityLevel: metrics.ALPHA, + }, []string{"plugin", "profile"}) + + metricsList = []metrics.Registerable{ + scheduleAttempts, + e2eSchedulingLatency, + schedulingLatency, + SchedulingAlgorithmLatency, + PreemptionVictims, + PreemptionAttempts, + pendingPods, + PodSchedulingDuration, + PodSchedulingAttempts, + FrameworkExtensionPointDuration, + PluginExecutionDuration, + SchedulerQueueIncomingPods, + SchedulerGoroutines, + Goroutines, + PermitWaitDuration, + CacheSize, + unschedulableReasons, + } +) + +var registerMetrics sync.Once + +// Register all metrics. +func Register() { + // Register the metrics. + registerMetrics.Do(func() { + RegisterMetrics(metricsList...) + volumebindingmetrics.RegisterVolumeSchedulingMetrics() + }) +} + +// RegisterMetrics registers a list of metrics. +// This function is exported because it is intended to be used by out-of-tree plugins to register their custom metrics. +func RegisterMetrics(extraMetrics ...metrics.Registerable) { + for _, metric := range extraMetrics { + legacyregistry.MustRegister(metric) + } +} + +// GetGather returns the gatherer. It used by test case outside current package. +func GetGather() metrics.Gatherer { + return legacyregistry.DefaultGatherer +} + +// ActivePods returns the pending pods metrics with the label active +func ActivePods() metrics.GaugeMetric { + return pendingPods.With(metrics.Labels{"queue": "active"}) +} + +// BackoffPods returns the pending pods metrics with the label backoff +func BackoffPods() metrics.GaugeMetric { + return pendingPods.With(metrics.Labels{"queue": "backoff"}) +} + +// UnschedulablePods returns the pending pods metrics with the label unschedulable +func UnschedulablePods() metrics.GaugeMetric { + return pendingPods.With(metrics.Labels{"queue": "unschedulable"}) +} + +// GatedPods returns the pending pods metrics with the label gated +func GatedPods() metrics.GaugeMetric { + return pendingPods.With(metrics.Labels{"queue": "gated"}) +} + +// SinceInSeconds gets the time since the specified start in seconds. +func SinceInSeconds(start time.Time) float64 { + return time.Since(start).Seconds() +} + +func UnschedulableReason(plugin string, profile string) metrics.GaugeMetric { + return unschedulableReasons.With(metrics.Labels{"plugin": plugin, "profile": profile}) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/metrics/profile_metrics.go b/vendor/k8s.io/kubernetes/pkg/scheduler/metrics/profile_metrics.go new file mode 100644 index 000000000..b844ef687 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/metrics/profile_metrics.go @@ -0,0 +1,49 @@ +/* +Copyright 2020 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 metrics + +// This file contains helpers for metrics that are associated to a profile. + +var ( + scheduledResult = "scheduled" + unschedulableResult = "unschedulable" + errorResult = "error" +) + +// PodScheduled can records a successful scheduling attempt and the duration +// since `start`. +func PodScheduled(profile string, duration float64) { + observeScheduleAttemptAndLatency(scheduledResult, profile, duration) +} + +// PodUnschedulable can records a scheduling attempt for an unschedulable pod +// and the duration since `start`. +func PodUnschedulable(profile string, duration float64) { + observeScheduleAttemptAndLatency(unschedulableResult, profile, duration) +} + +// PodScheduleError can records a scheduling attempt that had an error and the +// duration since `start`. +func PodScheduleError(profile string, duration float64) { + observeScheduleAttemptAndLatency(errorResult, profile, duration) +} + +func observeScheduleAttemptAndLatency(result, profile string, duration float64) { + e2eSchedulingLatency.WithLabelValues(result, profile).Observe(duration) + schedulingLatency.WithLabelValues(result, profile).Observe(duration) + scheduleAttempts.WithLabelValues(result, profile).Inc() +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/metrics/resources/resources.go b/vendor/k8s.io/kubernetes/pkg/scheduler/metrics/resources/resources.go new file mode 100644 index 000000000..b02862863 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/metrics/resources/resources.go @@ -0,0 +1,201 @@ +/* +Copyright 2020 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 resources provides a metrics collector that reports the +// resource consumption (requests and limits) of the pods in the cluster +// as the scheduler and kubelet would interpret it. +package resources + +import ( + "net/http" + "strconv" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/labels" + corelisters "k8s.io/client-go/listers/core/v1" + "k8s.io/component-base/metrics" + + v1resource "k8s.io/kubernetes/pkg/api/v1/resource" + v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" +) + +type resourceLifecycleDescriptors struct { + total *metrics.Desc +} + +func (d resourceLifecycleDescriptors) Describe(ch chan<- *metrics.Desc) { + ch <- d.total +} + +type resourceMetricsDescriptors struct { + requests resourceLifecycleDescriptors + limits resourceLifecycleDescriptors +} + +func (d resourceMetricsDescriptors) Describe(ch chan<- *metrics.Desc) { + d.requests.Describe(ch) + d.limits.Describe(ch) +} + +var podResourceDesc = resourceMetricsDescriptors{ + requests: resourceLifecycleDescriptors{ + total: metrics.NewDesc("kube_pod_resource_request", + "Resources requested by workloads on the cluster, broken down by pod. This shows the resource usage the scheduler and kubelet expect per pod for resources along with the unit for the resource if any.", + []string{"namespace", "pod", "node", "scheduler", "priority", "resource", "unit"}, + nil, + metrics.ALPHA, + ""), + }, + limits: resourceLifecycleDescriptors{ + total: metrics.NewDesc("kube_pod_resource_limit", + "Resources limit for workloads on the cluster, broken down by pod. This shows the resource usage the scheduler and kubelet expect per pod for resources along with the unit for the resource if any.", + []string{"namespace", "pod", "node", "scheduler", "priority", "resource", "unit"}, + nil, + metrics.ALPHA, + ""), + }, +} + +// Handler creates a collector from the provided podLister and returns an http.Handler that +// will report the requested metrics in the prometheus format. It does not include any other +// metrics. +func Handler(podLister corelisters.PodLister) http.Handler { + collector := NewPodResourcesMetricsCollector(podLister) + registry := metrics.NewKubeRegistry() + registry.CustomMustRegister(collector) + return metrics.HandlerWithReset(registry, metrics.HandlerOpts{}) +} + +// Check if resourceMetricsCollector implements necessary interface +var _ metrics.StableCollector = &podResourceCollector{} + +// NewPodResourcesMetricsCollector registers a O(pods) cardinality metric that +// reports the current resources requested by all pods on the cluster within +// the Kubernetes resource model. Metrics are broken down by pod, node, resource, +// and phase of lifecycle. Each pod returns two series per resource - one for +// their aggregate usage (required to schedule) and one for their phase specific +// usage. This allows admins to assess the cost per resource at different phases +// of startup and compare to actual resource usage. +func NewPodResourcesMetricsCollector(podLister corelisters.PodLister) metrics.StableCollector { + return &podResourceCollector{ + lister: podLister, + } +} + +type podResourceCollector struct { + metrics.BaseStableCollector + lister corelisters.PodLister +} + +func (c *podResourceCollector) DescribeWithStability(ch chan<- *metrics.Desc) { + podResourceDesc.Describe(ch) +} + +func (c *podResourceCollector) CollectWithStability(ch chan<- metrics.Metric) { + pods, err := c.lister.List(labels.Everything()) + if err != nil { + return + } + reuseReqs, reuseLimits := make(v1.ResourceList, 4), make(v1.ResourceList, 4) + for _, p := range pods { + reqs, limits, terminal := podRequestsAndLimitsByLifecycle(p, reuseReqs, reuseLimits) + if terminal { + // terminal pods are excluded from resource usage calculations + continue + } + for _, t := range []struct { + desc resourceLifecycleDescriptors + total v1.ResourceList + }{ + { + desc: podResourceDesc.requests, + total: reqs, + }, + { + desc: podResourceDesc.limits, + total: limits, + }, + } { + for resourceName, val := range t.total { + var unitName string + switch resourceName { + case v1.ResourceCPU: + unitName = "cores" + case v1.ResourceMemory: + unitName = "bytes" + case v1.ResourceStorage: + unitName = "bytes" + case v1.ResourceEphemeralStorage: + unitName = "bytes" + default: + switch { + case v1helper.IsHugePageResourceName(resourceName): + unitName = "bytes" + case v1helper.IsAttachableVolumeResourceName(resourceName): + unitName = "integer" + } + } + var priority string + if p.Spec.Priority != nil { + priority = strconv.FormatInt(int64(*p.Spec.Priority), 10) + } + recordMetricWithUnit(ch, t.desc.total, p.Namespace, p.Name, p.Spec.NodeName, p.Spec.SchedulerName, priority, resourceName, unitName, val) + } + } + } +} + +func recordMetricWithUnit( + ch chan<- metrics.Metric, + desc *metrics.Desc, + namespace, name, nodeName, schedulerName, priority string, + resourceName v1.ResourceName, + unit string, + val resource.Quantity, +) { + if val.IsZero() { + return + } + ch <- metrics.NewLazyConstMetric(desc, metrics.GaugeValue, + val.AsApproximateFloat64(), + namespace, name, nodeName, schedulerName, priority, string(resourceName), unit, + ) +} + +// podRequestsAndLimitsByLifecycle returns a dictionary of all defined resources summed up for all +// containers of the pod. Pod overhead is added to the +// total container resource requests and to the total container limits which have a +// non-zero quantity. The caller may avoid allocations of resource lists by passing +// a requests and limits list to the function, which will be cleared before use. +// This method is the same as v1resource.PodRequestsAndLimits but avoids allocating in several +// scenarios for efficiency. +func podRequestsAndLimitsByLifecycle(pod *v1.Pod, reuseReqs, reuseLimits v1.ResourceList) (reqs, limits v1.ResourceList, terminal bool) { + switch { + case len(pod.Spec.NodeName) == 0: + // unscheduled pods cannot be terminal + case pod.Status.Phase == v1.PodSucceeded, pod.Status.Phase == v1.PodFailed: + terminal = true + // TODO: resolve https://github.com/kubernetes/kubernetes/issues/96515 and add a condition here + // for checking that terminal state + } + if terminal { + return + } + + reqs, limits = v1resource.PodRequestsAndLimitsReuse(pod, reuseReqs, reuseLimits) + return +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/profile/profile.go b/vendor/k8s.io/kubernetes/pkg/scheduler/profile/profile.go new file mode 100644 index 000000000..b023b03f6 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/profile/profile.go @@ -0,0 +1,116 @@ +/* +Copyright 2020 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 profile holds the definition of a scheduling Profile. +package profile + +import ( + "errors" + "fmt" + + "github.com/google/go-cmp/cmp" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/tools/events" + "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/kubernetes/pkg/scheduler/framework" + frameworkruntime "k8s.io/kubernetes/pkg/scheduler/framework/runtime" +) + +// RecorderFactory builds an EventRecorder for a given scheduler name. +type RecorderFactory func(string) events.EventRecorder + +// newProfile builds a Profile for the given configuration. +func newProfile(cfg config.KubeSchedulerProfile, r frameworkruntime.Registry, recorderFact RecorderFactory, + stopCh <-chan struct{}, opts ...frameworkruntime.Option) (framework.Framework, error) { + recorder := recorderFact(cfg.SchedulerName) + opts = append(opts, frameworkruntime.WithEventRecorder(recorder)) + return frameworkruntime.NewFramework(r, &cfg, stopCh, opts...) +} + +// Map holds frameworks indexed by scheduler name. +type Map map[string]framework.Framework + +// NewMap builds the frameworks given by the configuration, indexed by name. +func NewMap(cfgs []config.KubeSchedulerProfile, r frameworkruntime.Registry, recorderFact RecorderFactory, + stopCh <-chan struct{}, opts ...frameworkruntime.Option) (Map, error) { + m := make(Map) + v := cfgValidator{m: m} + + for _, cfg := range cfgs { + p, err := newProfile(cfg, r, recorderFact, stopCh, opts...) + if err != nil { + return nil, fmt.Errorf("creating profile for scheduler name %s: %v", cfg.SchedulerName, err) + } + if err := v.validate(cfg, p); err != nil { + return nil, err + } + m[cfg.SchedulerName] = p + } + return m, nil +} + +// HandlesSchedulerName returns whether a profile handles the given scheduler name. +func (m Map) HandlesSchedulerName(name string) bool { + _, ok := m[name] + return ok +} + +// NewRecorderFactory returns a RecorderFactory for the broadcaster. +func NewRecorderFactory(b events.EventBroadcaster) RecorderFactory { + return func(name string) events.EventRecorder { + return b.NewRecorder(scheme.Scheme, name) + } +} + +type cfgValidator struct { + m Map + queueSort string + queueSortArgs runtime.Object +} + +func (v *cfgValidator) validate(cfg config.KubeSchedulerProfile, f framework.Framework) error { + if len(f.ProfileName()) == 0 { + return errors.New("scheduler name is needed") + } + if cfg.Plugins == nil { + return fmt.Errorf("plugins required for profile with scheduler name %q", f.ProfileName()) + } + if v.m[f.ProfileName()] != nil { + return fmt.Errorf("duplicate profile with scheduler name %q", f.ProfileName()) + } + + queueSort := f.ListPlugins().QueueSort.Enabled[0].Name + var queueSortArgs runtime.Object + for _, plCfg := range cfg.PluginConfig { + if plCfg.Name == queueSort { + queueSortArgs = plCfg.Args + break + } + } + if len(v.queueSort) == 0 { + v.queueSort = queueSort + v.queueSortArgs = queueSortArgs + return nil + } + if v.queueSort != queueSort { + return fmt.Errorf("different queue sort plugins for profile %q: %q, first: %q", cfg.SchedulerName, queueSort, v.queueSort) + } + if !cmp.Equal(v.queueSortArgs, queueSortArgs) { + return fmt.Errorf("different queue sort plugin args for profile %q", cfg.SchedulerName) + } + return nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/schedule_one.go b/vendor/k8s.io/kubernetes/pkg/scheduler/schedule_one.go new file mode 100644 index 000000000..4a45f5b4a --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/schedule_one.go @@ -0,0 +1,942 @@ +/* +Copyright 2014 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 scheduler + +import ( + "context" + "fmt" + "math/rand" + "strconv" + "sync" + "sync/atomic" + "time" + + v1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apimachinery/pkg/util/sets" + clientset "k8s.io/client-go/kubernetes" + "k8s.io/klog/v2" + extenderv1 "k8s.io/kube-scheduler/extender/v1" + podutil "k8s.io/kubernetes/pkg/api/v1/pod" + "k8s.io/kubernetes/pkg/apis/core/validation" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/parallelize" + frameworkruntime "k8s.io/kubernetes/pkg/scheduler/framework/runtime" + internalqueue "k8s.io/kubernetes/pkg/scheduler/internal/queue" + "k8s.io/kubernetes/pkg/scheduler/metrics" + "k8s.io/kubernetes/pkg/scheduler/util" + utiltrace "k8s.io/utils/trace" +) + +const ( + // Percentage of plugin metrics to be sampled. + pluginMetricsSamplePercent = 10 + // minFeasibleNodesToFind is the minimum number of nodes that would be scored + // in each scheduling cycle. This is a semi-arbitrary value to ensure that a + // certain minimum of nodes are checked for feasibility. This in turn helps + // ensure a minimum level of spreading. + minFeasibleNodesToFind = 100 + // minFeasibleNodesPercentageToFind is the minimum percentage of nodes that + // would be scored in each scheduling cycle. This is a semi-arbitrary value + // to ensure that a certain minimum of nodes are checked for feasibility. + // This in turn helps ensure a minimum level of spreading. + minFeasibleNodesPercentageToFind = 5 +) + +// scheduleOne does the entire scheduling workflow for a single pod. It is serialized on the scheduling algorithm's host fitting. +func (sched *Scheduler) scheduleOne(ctx context.Context) { + podInfo := sched.NextPod() + // pod could be nil when schedulerQueue is closed + if podInfo == nil || podInfo.Pod == nil { + return + } + pod := podInfo.Pod + fwk, err := sched.frameworkForPod(pod) + if err != nil { + // This shouldn't happen, because we only accept for scheduling the pods + // which specify a scheduler name that matches one of the profiles. + klog.ErrorS(err, "Error occurred") + return + } + if sched.skipPodSchedule(fwk, pod) { + return + } + + klog.V(3).InfoS("Attempting to schedule pod", "pod", klog.KObj(pod)) + + // Synchronously attempt to find a fit for the pod. + start := time.Now() + state := framework.NewCycleState() + state.SetRecordPluginMetrics(rand.Intn(100) < pluginMetricsSamplePercent) + + // Initialize an empty podsToActivate struct, which will be filled up by plugins or stay empty. + podsToActivate := framework.NewPodsToActivate() + state.Write(framework.PodsToActivateKey, podsToActivate) + + schedulingCycleCtx, cancel := context.WithCancel(ctx) + defer cancel() + + scheduleResult, assumedPodInfo, err := sched.schedulingCycle(schedulingCycleCtx, state, fwk, podInfo, start, podsToActivate) + if err != nil { + sched.FailureHandler(schedulingCycleCtx, fwk, assumedPodInfo, err, scheduleResult.reason, scheduleResult.nominatingInfo, start) + return + } + + // bind the pod to its host asynchronously (we can do this b/c of the assumption step above). + go func() { + bindingCycleCtx, cancel := context.WithCancel(ctx) + defer cancel() + + metrics.SchedulerGoroutines.WithLabelValues(metrics.Binding).Inc() + defer metrics.SchedulerGoroutines.WithLabelValues(metrics.Binding).Dec() + metrics.Goroutines.WithLabelValues(metrics.Binding).Inc() + defer metrics.Goroutines.WithLabelValues(metrics.Binding).Dec() + + status := sched.bindingCycle(bindingCycleCtx, state, fwk, scheduleResult, assumedPodInfo, start, podsToActivate) + if !status.IsSuccess() { + sched.handleBindingCycleError(bindingCycleCtx, state, fwk, assumedPodInfo, start, scheduleResult, status) + } + }() +} + +var clearNominatedNode = &framework.NominatingInfo{NominatingMode: framework.ModeOverride, NominatedNodeName: ""} + +// schedulingCycle tries to schedule a single Pod. +func (sched *Scheduler) schedulingCycle( + ctx context.Context, + state *framework.CycleState, + fwk framework.Framework, + podInfo *framework.QueuedPodInfo, + start time.Time, + podsToActivate *framework.PodsToActivate, +) (ScheduleResult, *framework.QueuedPodInfo, error) { + + pod := podInfo.Pod + scheduleResult, err := sched.SchedulePod(ctx, fwk, state, pod) + if err != nil { + // SchedulePod() may have failed because the pod would not fit on any host, so we try to + // preempt, with the expectation that the next time the pod is tried for scheduling it + // will fit due to the preemption. It is also possible that a different pod will schedule + // into the resources that were preempted, but this is harmless. + var nominatingInfo *framework.NominatingInfo + reason := v1.PodReasonUnschedulable + if fitError, ok := err.(*framework.FitError); ok { + if !fwk.HasPostFilterPlugins() { + klog.V(3).InfoS("No PostFilter plugins are registered, so no preemption will be performed") + } else { + // Run PostFilter plugins to try to make the pod schedulable in a future scheduling cycle. + result, status := fwk.RunPostFilterPlugins(ctx, state, pod, fitError.Diagnosis.NodeToStatusMap) + if status.Code() == framework.Error { + klog.ErrorS(nil, "Status after running PostFilter plugins for pod", "pod", klog.KObj(pod), "status", status) + } else { + fitError.Diagnosis.PostFilterMsg = status.Message() + klog.V(5).InfoS("Status after running PostFilter plugins for pod", "pod", klog.KObj(pod), "status", status) + } + if result != nil { + nominatingInfo = result.NominatingInfo + } + } + } else if err == ErrNoNodesAvailable { + nominatingInfo = clearNominatedNode + } else { + klog.ErrorS(err, "Error selecting node for pod", "pod", klog.KObj(pod)) + nominatingInfo = clearNominatedNode + reason = v1.PodReasonSchedulerError + } + return ScheduleResult{nominatingInfo: nominatingInfo, reason: reason}, podInfo, err + } + metrics.SchedulingAlgorithmLatency.Observe(metrics.SinceInSeconds(start)) + // Tell the cache to assume that a pod now is running on a given node, even though it hasn't been bound yet. + // This allows us to keep scheduling without waiting on binding to occur. + assumedPodInfo := podInfo.DeepCopy() + assumedPod := assumedPodInfo.Pod + // assume modifies `assumedPod` by setting NodeName=scheduleResult.SuggestedHost + err = sched.assume(assumedPod, scheduleResult.SuggestedHost) + if err != nil { + // This is most probably result of a BUG in retrying logic. + // We report an error here so that pod scheduling can be retried. + // This relies on the fact that Error will check if the pod has been bound + // to a node and if so will not add it back to the unscheduled pods queue + // (otherwise this would cause an infinite loop). + return ScheduleResult{nominatingInfo: clearNominatedNode, reason: v1.PodReasonSchedulerError}, + assumedPodInfo, + err + } + + // Run the Reserve method of reserve plugins. + if sts := fwk.RunReservePluginsReserve(ctx, state, assumedPod, scheduleResult.SuggestedHost); !sts.IsSuccess() { + // trigger un-reserve to clean up state associated with the reserved Pod + fwk.RunReservePluginsUnreserve(ctx, state, assumedPod, scheduleResult.SuggestedHost) + if forgetErr := sched.Cache.ForgetPod(assumedPod); forgetErr != nil { + klog.ErrorS(forgetErr, "Scheduler cache ForgetPod failed") + } + + return ScheduleResult{nominatingInfo: clearNominatedNode, reason: v1.PodReasonSchedulerError}, + assumedPodInfo, + sts.AsError() + } + + // Run "permit" plugins. + runPermitStatus := fwk.RunPermitPlugins(ctx, state, assumedPod, scheduleResult.SuggestedHost) + if !runPermitStatus.IsWait() && !runPermitStatus.IsSuccess() { + // trigger un-reserve to clean up state associated with the reserved Pod + fwk.RunReservePluginsUnreserve(ctx, state, assumedPod, scheduleResult.SuggestedHost) + if forgetErr := sched.Cache.ForgetPod(assumedPod); forgetErr != nil { + klog.ErrorS(forgetErr, "Scheduler cache ForgetPod failed") + } + + reason := v1.PodReasonSchedulerError + if runPermitStatus.IsUnschedulable() { + reason = v1.PodReasonUnschedulable + } + + return ScheduleResult{nominatingInfo: clearNominatedNode, reason: reason}, + assumedPodInfo, + runPermitStatus.AsError() + } + + // At the end of a successful scheduling cycle, pop and move up Pods if needed. + if len(podsToActivate.Map) != 0 { + sched.SchedulingQueue.Activate(podsToActivate.Map) + // Clear the entries after activation. + podsToActivate.Map = make(map[string]*v1.Pod) + } + + return scheduleResult, assumedPodInfo, nil +} + +// bindingCycle tries to bind an assumed Pod. +func (sched *Scheduler) bindingCycle( + ctx context.Context, + state *framework.CycleState, + fwk framework.Framework, + scheduleResult ScheduleResult, + assumedPodInfo *framework.QueuedPodInfo, + start time.Time, + podsToActivate *framework.PodsToActivate) *framework.Status { + + assumedPod := assumedPodInfo.Pod + + // Run "permit" plugins. + if status := fwk.WaitOnPermit(ctx, assumedPod); !status.IsSuccess() { + return status + } + + // Run "prebind" plugins. + if status := fwk.RunPreBindPlugins(ctx, state, assumedPod, scheduleResult.SuggestedHost); !status.IsSuccess() { + return status + } + + // Run "bind" plugins. + if status := sched.bind(ctx, fwk, assumedPod, scheduleResult.SuggestedHost, state); !status.IsSuccess() { + return status + } + + // Calculating nodeResourceString can be heavy. Avoid it if klog verbosity is below 2. + klog.V(2).InfoS("Successfully bound pod to node", "pod", klog.KObj(assumedPod), "node", scheduleResult.SuggestedHost, "evaluatedNodes", scheduleResult.EvaluatedNodes, "feasibleNodes", scheduleResult.FeasibleNodes) + metrics.PodScheduled(fwk.ProfileName(), metrics.SinceInSeconds(start)) + metrics.PodSchedulingAttempts.Observe(float64(assumedPodInfo.Attempts)) + metrics.PodSchedulingDuration.WithLabelValues(getAttemptsLabel(assumedPodInfo)).Observe(metrics.SinceInSeconds(assumedPodInfo.InitialAttemptTimestamp)) + + // Run "postbind" plugins. + fwk.RunPostBindPlugins(ctx, state, assumedPod, scheduleResult.SuggestedHost) + + // At the end of a successful binding cycle, move up Pods if needed. + if len(podsToActivate.Map) != 0 { + sched.SchedulingQueue.Activate(podsToActivate.Map) + // Unlike the logic in schedulingCycle(), we don't bother deleting the entries + // as `podsToActivate.Map` is no longer consumed. + } + + return nil +} + +func (sched *Scheduler) handleBindingCycleError( + ctx context.Context, + state *framework.CycleState, + fwk framework.Framework, + podInfo *framework.QueuedPodInfo, + start time.Time, + scheduleResult ScheduleResult, + status *framework.Status) { + + assumedPod := podInfo.Pod + // trigger un-reserve plugins to clean up state associated with the reserved Pod + fwk.RunReservePluginsUnreserve(ctx, state, assumedPod, scheduleResult.SuggestedHost) + if forgetErr := sched.Cache.ForgetPod(assumedPod); forgetErr != nil { + klog.ErrorS(forgetErr, "scheduler cache ForgetPod failed") + } else { + // "Forget"ing an assumed Pod in binding cycle should be treated as a PodDelete event, + // as the assumed Pod had occupied a certain amount of resources in scheduler cache. + // + // Avoid moving the assumed Pod itself as it's always Unschedulable. + // It's intentional to "defer" this operation; otherwise MoveAllToActiveOrBackoffQueue() would + // update `q.moveRequest` and thus move the assumed pod to backoffQ anyways. + if status.IsUnschedulable() { + defer sched.SchedulingQueue.MoveAllToActiveOrBackoffQueue(internalqueue.AssignedPodDelete, func(pod *v1.Pod) bool { + return assumedPod.UID != pod.UID + }) + } else { + sched.SchedulingQueue.MoveAllToActiveOrBackoffQueue(internalqueue.AssignedPodDelete, nil) + } + } + + reason := v1.PodReasonSchedulerError + if status.IsUnschedulable() { + reason = v1.PodReasonUnschedulable + } + + sched.FailureHandler(ctx, fwk, podInfo, status.AsError(), reason, clearNominatedNode, start) +} + +func (sched *Scheduler) frameworkForPod(pod *v1.Pod) (framework.Framework, error) { + fwk, ok := sched.Profiles[pod.Spec.SchedulerName] + if !ok { + return nil, fmt.Errorf("profile not found for scheduler name %q", pod.Spec.SchedulerName) + } + return fwk, nil +} + +// skipPodSchedule returns true if we could skip scheduling the pod for specified cases. +func (sched *Scheduler) skipPodSchedule(fwk framework.Framework, pod *v1.Pod) bool { + // Case 1: pod is being deleted. + if pod.DeletionTimestamp != nil { + fwk.EventRecorder().Eventf(pod, nil, v1.EventTypeWarning, "FailedScheduling", "Scheduling", "skip schedule deleting pod: %v/%v", pod.Namespace, pod.Name) + klog.V(3).InfoS("Skip schedule deleting pod", "pod", klog.KObj(pod)) + return true + } + + // Case 2: pod that has been assumed could be skipped. + // An assumed pod can be added again to the scheduling queue if it got an update event + // during its previous scheduling cycle but before getting assumed. + isAssumed, err := sched.Cache.IsAssumedPod(pod) + if err != nil { + utilruntime.HandleError(fmt.Errorf("failed to check whether pod %s/%s is assumed: %v", pod.Namespace, pod.Name, err)) + return false + } + return isAssumed +} + +// schedulePod tries to schedule the given pod to one of the nodes in the node list. +// If it succeeds, it will return the name of the node. +// If it fails, it will return a FitError with reasons. +func (sched *Scheduler) schedulePod(ctx context.Context, fwk framework.Framework, state *framework.CycleState, pod *v1.Pod) (result ScheduleResult, err error) { + trace := utiltrace.New("Scheduling", utiltrace.Field{Key: "namespace", Value: pod.Namespace}, utiltrace.Field{Key: "name", Value: pod.Name}) + defer trace.LogIfLong(100 * time.Millisecond) + + if err := sched.Cache.UpdateSnapshot(sched.nodeInfoSnapshot); err != nil { + return result, err + } + trace.Step("Snapshotting scheduler cache and node infos done") + + if sched.nodeInfoSnapshot.NumNodes() == 0 { + return result, ErrNoNodesAvailable + } + + feasibleNodes, diagnosis, err := sched.findNodesThatFitPod(ctx, fwk, state, pod) + if err != nil { + return result, err + } + trace.Step("Computing predicates done") + + if len(feasibleNodes) == 0 { + return result, &framework.FitError{ + Pod: pod, + NumAllNodes: sched.nodeInfoSnapshot.NumNodes(), + Diagnosis: diagnosis, + } + } + + // When only one node after predicate, just use it. + if len(feasibleNodes) == 1 { + return ScheduleResult{ + SuggestedHost: feasibleNodes[0].Name, + EvaluatedNodes: 1 + len(diagnosis.NodeToStatusMap), + FeasibleNodes: 1, + }, nil + } + + priorityList, err := prioritizeNodes(ctx, sched.Extenders, fwk, state, pod, feasibleNodes) + if err != nil { + return result, err + } + + host, err := selectHost(priorityList) + trace.Step("Prioritizing done") + + return ScheduleResult{ + SuggestedHost: host, + EvaluatedNodes: len(feasibleNodes) + len(diagnosis.NodeToStatusMap), + FeasibleNodes: len(feasibleNodes), + }, err +} + +// Filters the nodes to find the ones that fit the pod based on the framework +// filter plugins and filter extenders. +func (sched *Scheduler) findNodesThatFitPod(ctx context.Context, fwk framework.Framework, state *framework.CycleState, pod *v1.Pod) ([]*v1.Node, framework.Diagnosis, error) { + diagnosis := framework.Diagnosis{ + NodeToStatusMap: make(framework.NodeToStatusMap), + UnschedulablePlugins: sets.NewString(), + } + + allNodes, err := sched.nodeInfoSnapshot.NodeInfos().List() + if err != nil { + return nil, diagnosis, err + } + // Run "prefilter" plugins. + preRes, s := fwk.RunPreFilterPlugins(ctx, state, pod) + if !s.IsSuccess() { + if !s.IsUnschedulable() { + return nil, diagnosis, s.AsError() + } + // Record the messages from PreFilter in Diagnosis.PreFilterMsg. + diagnosis.PreFilterMsg = s.Message() + klog.V(5).InfoS("Status after running PreFilter plugins for pod", "pod", klog.KObj(pod), "status", s) + // Status satisfying IsUnschedulable() gets injected into diagnosis.UnschedulablePlugins. + if s.FailedPlugin() != "" { + diagnosis.UnschedulablePlugins.Insert(s.FailedPlugin()) + } + return nil, diagnosis, nil + } + + // "NominatedNodeName" can potentially be set in a previous scheduling cycle as a result of preemption. + // This node is likely the only candidate that will fit the pod, and hence we try it first before iterating over all nodes. + if len(pod.Status.NominatedNodeName) > 0 { + feasibleNodes, err := sched.evaluateNominatedNode(ctx, pod, fwk, state, diagnosis) + if err != nil { + klog.ErrorS(err, "Evaluation failed on nominated node", "pod", klog.KObj(pod), "node", pod.Status.NominatedNodeName) + } + // Nominated node passes all the filters, scheduler is good to assign this node to the pod. + if len(feasibleNodes) != 0 { + return feasibleNodes, diagnosis, nil + } + } + + nodes := allNodes + if !preRes.AllNodes() { + nodes = make([]*framework.NodeInfo, 0, len(preRes.NodeNames)) + for n := range preRes.NodeNames { + nInfo, err := sched.nodeInfoSnapshot.NodeInfos().Get(n) + if err != nil { + return nil, diagnosis, err + } + nodes = append(nodes, nInfo) + } + } + feasibleNodes, err := sched.findNodesThatPassFilters(ctx, fwk, state, pod, diagnosis, nodes) + // always try to update the sched.nextStartNodeIndex regardless of whether an error has occurred + // this is helpful to make sure that all the nodes have a chance to be searched + processedNodes := len(feasibleNodes) + len(diagnosis.NodeToStatusMap) + sched.nextStartNodeIndex = (sched.nextStartNodeIndex + processedNodes) % len(nodes) + if err != nil { + return nil, diagnosis, err + } + + feasibleNodes, err = findNodesThatPassExtenders(sched.Extenders, pod, feasibleNodes, diagnosis.NodeToStatusMap) + if err != nil { + return nil, diagnosis, err + } + return feasibleNodes, diagnosis, nil +} + +func (sched *Scheduler) evaluateNominatedNode(ctx context.Context, pod *v1.Pod, fwk framework.Framework, state *framework.CycleState, diagnosis framework.Diagnosis) ([]*v1.Node, error) { + nnn := pod.Status.NominatedNodeName + nodeInfo, err := sched.nodeInfoSnapshot.Get(nnn) + if err != nil { + return nil, err + } + node := []*framework.NodeInfo{nodeInfo} + feasibleNodes, err := sched.findNodesThatPassFilters(ctx, fwk, state, pod, diagnosis, node) + if err != nil { + return nil, err + } + + feasibleNodes, err = findNodesThatPassExtenders(sched.Extenders, pod, feasibleNodes, diagnosis.NodeToStatusMap) + if err != nil { + return nil, err + } + + return feasibleNodes, nil +} + +// findNodesThatPassFilters finds the nodes that fit the filter plugins. +func (sched *Scheduler) findNodesThatPassFilters( + ctx context.Context, + fwk framework.Framework, + state *framework.CycleState, + pod *v1.Pod, + diagnosis framework.Diagnosis, + nodes []*framework.NodeInfo) ([]*v1.Node, error) { + numAllNodes := len(nodes) + numNodesToFind := sched.numFeasibleNodesToFind(fwk.PercentageOfNodesToScore(), int32(numAllNodes)) + + // Create feasible list with enough space to avoid growing it + // and allow assigning. + feasibleNodes := make([]*v1.Node, numNodesToFind) + + if !fwk.HasFilterPlugins() { + for i := range feasibleNodes { + feasibleNodes[i] = nodes[(sched.nextStartNodeIndex+i)%numAllNodes].Node() + } + return feasibleNodes, nil + } + + errCh := parallelize.NewErrorChannel() + var statusesLock sync.Mutex + var feasibleNodesLen int32 + ctx, cancel := context.WithCancel(ctx) + defer cancel() + checkNode := func(i int) { + // We check the nodes starting from where we left off in the previous scheduling cycle, + // this is to make sure all nodes have the same chance of being examined across pods. + nodeInfo := nodes[(sched.nextStartNodeIndex+i)%numAllNodes] + status := fwk.RunFilterPluginsWithNominatedPods(ctx, state, pod, nodeInfo) + if status.Code() == framework.Error { + errCh.SendErrorWithCancel(status.AsError(), cancel) + return + } + if status.IsSuccess() { + length := atomic.AddInt32(&feasibleNodesLen, 1) + if length > numNodesToFind { + cancel() + atomic.AddInt32(&feasibleNodesLen, -1) + } else { + feasibleNodes[length-1] = nodeInfo.Node() + } + } else { + statusesLock.Lock() + diagnosis.NodeToStatusMap[nodeInfo.Node().Name] = status + diagnosis.UnschedulablePlugins.Insert(status.FailedPlugin()) + statusesLock.Unlock() + } + } + + beginCheckNode := time.Now() + statusCode := framework.Success + defer func() { + // We record Filter extension point latency here instead of in framework.go because framework.RunFilterPlugins + // function is called for each node, whereas we want to have an overall latency for all nodes per scheduling cycle. + // Note that this latency also includes latency for `addNominatedPods`, which calls framework.RunPreFilterAddPod. + metrics.FrameworkExtensionPointDuration.WithLabelValues(frameworkruntime.Filter, statusCode.String(), fwk.ProfileName()).Observe(metrics.SinceInSeconds(beginCheckNode)) + }() + + // Stops searching for more nodes once the configured number of feasible nodes + // are found. + fwk.Parallelizer().Until(ctx, numAllNodes, checkNode, frameworkruntime.Filter) + feasibleNodes = feasibleNodes[:feasibleNodesLen] + if err := errCh.ReceiveError(); err != nil { + statusCode = framework.Error + return feasibleNodes, err + } + return feasibleNodes, nil +} + +// numFeasibleNodesToFind returns the number of feasible nodes that once found, the scheduler stops +// its search for more feasible nodes. +func (sched *Scheduler) numFeasibleNodesToFind(percentageOfNodesToScore *int32, numAllNodes int32) (numNodes int32) { + if numAllNodes < minFeasibleNodesToFind { + return numAllNodes + } + + // Use profile percentageOfNodesToScore if it's set. Otherwise, use global percentageOfNodesToScore. + var percentage int32 + if percentageOfNodesToScore != nil { + percentage = *percentageOfNodesToScore + } else { + percentage = sched.percentageOfNodesToScore + } + + if percentage == 0 { + percentage = int32(50) - numAllNodes/125 + if percentage < minFeasibleNodesPercentageToFind { + percentage = minFeasibleNodesPercentageToFind + } + } + + numNodes = numAllNodes * percentage / 100 + if numNodes < minFeasibleNodesToFind { + return minFeasibleNodesToFind + } + + return numNodes +} + +func findNodesThatPassExtenders(extenders []framework.Extender, pod *v1.Pod, feasibleNodes []*v1.Node, statuses framework.NodeToStatusMap) ([]*v1.Node, error) { + // Extenders are called sequentially. + // Nodes in original feasibleNodes can be excluded in one extender, and pass on to the next + // extender in a decreasing manner. + for _, extender := range extenders { + if len(feasibleNodes) == 0 { + break + } + if !extender.IsInterested(pod) { + continue + } + + // Status of failed nodes in failedAndUnresolvableMap will be added or overwritten in , + // so that the scheduler framework can respect the UnschedulableAndUnresolvable status for + // particular nodes, and this may eventually improve preemption efficiency. + // Note: users are recommended to configure the extenders that may return UnschedulableAndUnresolvable + // status ahead of others. + feasibleList, failedMap, failedAndUnresolvableMap, err := extender.Filter(pod, feasibleNodes) + if err != nil { + if extender.IsIgnorable() { + klog.InfoS("Skipping extender as it returned error and has ignorable flag set", "extender", extender, "err", err) + continue + } + return nil, err + } + + for failedNodeName, failedMsg := range failedAndUnresolvableMap { + var aggregatedReasons []string + if _, found := statuses[failedNodeName]; found { + aggregatedReasons = statuses[failedNodeName].Reasons() + } + aggregatedReasons = append(aggregatedReasons, failedMsg) + statuses[failedNodeName] = framework.NewStatus(framework.UnschedulableAndUnresolvable, aggregatedReasons...) + } + + for failedNodeName, failedMsg := range failedMap { + if _, found := failedAndUnresolvableMap[failedNodeName]; found { + // failedAndUnresolvableMap takes precedence over failedMap + // note that this only happens if the extender returns the node in both maps + continue + } + if _, found := statuses[failedNodeName]; !found { + statuses[failedNodeName] = framework.NewStatus(framework.Unschedulable, failedMsg) + } else { + statuses[failedNodeName].AppendReason(failedMsg) + } + } + + feasibleNodes = feasibleList + } + return feasibleNodes, nil +} + +// prioritizeNodes prioritizes the nodes by running the score plugins, +// which return a score for each node from the call to RunScorePlugins(). +// The scores from each plugin are added together to make the score for that node, then +// any extenders are run as well. +// All scores are finally combined (added) to get the total weighted scores of all nodes +func prioritizeNodes( + ctx context.Context, + extenders []framework.Extender, + fwk framework.Framework, + state *framework.CycleState, + pod *v1.Pod, + nodes []*v1.Node, +) (framework.NodeScoreList, error) { + // If no priority configs are provided, then all nodes will have a score of one. + // This is required to generate the priority list in the required format + if len(extenders) == 0 && !fwk.HasScorePlugins() { + result := make(framework.NodeScoreList, 0, len(nodes)) + for i := range nodes { + result = append(result, framework.NodeScore{ + Name: nodes[i].Name, + Score: 1, + }) + } + return result, nil + } + + // Run PreScore plugins. + preScoreStatus := fwk.RunPreScorePlugins(ctx, state, pod, nodes) + if !preScoreStatus.IsSuccess() { + return nil, preScoreStatus.AsError() + } + + // Run the Score plugins. + nodesScores, scoreStatus := fwk.RunScorePlugins(ctx, state, pod, nodes) + if !scoreStatus.IsSuccess() { + return nil, scoreStatus.AsError() + } + + // Additional details logged at level 10 if enabled. + klogV := klog.V(10) + if klogV.Enabled() { + for _, nodeScore := range nodesScores { + for _, pluginScore := range nodeScore.Scores { + klogV.InfoS("Plugin scored node for pod", "pod", klog.KObj(pod), "plugin", pluginScore.Name, "node", nodeScore.Name, "score", pluginScore.Score) + } + } + } + + // Summarize all scores. + result := make(framework.NodeScoreList, len(nodes)) + for i, pluginScores := range nodesScores { + result[i] = framework.NodeScore{Name: nodes[i].Name, Score: pluginScores.TotalScore} + } + + if len(extenders) != 0 && nodes != nil { + var mu sync.Mutex + var wg sync.WaitGroup + combinedScores := make(map[string]int64, len(nodes)) + for i := range extenders { + if !extenders[i].IsInterested(pod) { + continue + } + wg.Add(1) + go func(extIndex int) { + metrics.SchedulerGoroutines.WithLabelValues(metrics.PrioritizingExtender).Inc() + metrics.Goroutines.WithLabelValues(metrics.PrioritizingExtender).Inc() + defer func() { + metrics.SchedulerGoroutines.WithLabelValues(metrics.PrioritizingExtender).Dec() + metrics.Goroutines.WithLabelValues(metrics.PrioritizingExtender).Dec() + wg.Done() + }() + prioritizedList, weight, err := extenders[extIndex].Prioritize(pod, nodes) + if err != nil { + // Prioritization errors from extender can be ignored, let k8s/other extenders determine the priorities + klog.V(5).InfoS("Failed to run extender's priority function. No score given by this extender.", "error", err, "pod", klog.KObj(pod), "extender", extenders[extIndex].Name()) + return + } + mu.Lock() + for i := range *prioritizedList { + host, score := (*prioritizedList)[i].Host, (*prioritizedList)[i].Score + if klogV.Enabled() { + klogV.InfoS("Extender scored node for pod", "pod", klog.KObj(pod), "extender", extenders[extIndex].Name(), "node", host, "score", score) + } + combinedScores[host] += score * weight + } + mu.Unlock() + }(i) + } + // wait for all go routines to finish + wg.Wait() + for i := range result { + // MaxExtenderPriority may diverge from the max priority used in the scheduler and defined by MaxNodeScore, + // therefore we need to scale the score returned by extenders to the score range used by the scheduler. + result[i].Score += combinedScores[result[i].Name] * (framework.MaxNodeScore / extenderv1.MaxExtenderPriority) + } + } + + if klogV.Enabled() { + for i := range result { + klogV.InfoS("Calculated node's final score for pod", "pod", klog.KObj(pod), "node", result[i].Name, "score", result[i].Score) + } + } + return result, nil +} + +// selectHost takes a prioritized list of nodes and then picks one +// in a reservoir sampling manner from the nodes that had the highest score. +func selectHost(nodeScoreList framework.NodeScoreList) (string, error) { + if len(nodeScoreList) == 0 { + return "", fmt.Errorf("empty priorityList") + } + maxScore := nodeScoreList[0].Score + selected := nodeScoreList[0].Name + cntOfMaxScore := 1 + for _, ns := range nodeScoreList[1:] { + if ns.Score > maxScore { + maxScore = ns.Score + selected = ns.Name + cntOfMaxScore = 1 + } else if ns.Score == maxScore { + cntOfMaxScore++ + if rand.Intn(cntOfMaxScore) == 0 { + // Replace the candidate with probability of 1/cntOfMaxScore + selected = ns.Name + } + } + } + return selected, nil +} + +// assume signals to the cache that a pod is already in the cache, so that binding can be asynchronous. +// assume modifies `assumed`. +func (sched *Scheduler) assume(assumed *v1.Pod, host string) error { + // Optimistically assume that the binding will succeed and send it to apiserver + // in the background. + // If the binding fails, scheduler will release resources allocated to assumed pod + // immediately. + assumed.Spec.NodeName = host + + if err := sched.Cache.AssumePod(assumed); err != nil { + klog.ErrorS(err, "Scheduler cache AssumePod failed") + return err + } + // if "assumed" is a nominated pod, we should remove it from internal cache + if sched.SchedulingQueue != nil { + sched.SchedulingQueue.DeleteNominatedPodIfExists(assumed) + } + + return nil +} + +// bind binds a pod to a given node defined in a binding object. +// The precedence for binding is: (1) extenders and (2) framework plugins. +// We expect this to run asynchronously, so we handle binding metrics internally. +func (sched *Scheduler) bind(ctx context.Context, fwk framework.Framework, assumed *v1.Pod, targetNode string, state *framework.CycleState) (status *framework.Status) { + defer func() { + sched.finishBinding(fwk, assumed, targetNode, status) + }() + + bound, err := sched.extendersBinding(assumed, targetNode) + if bound { + return framework.AsStatus(err) + } + return fwk.RunBindPlugins(ctx, state, assumed, targetNode) +} + +// TODO(#87159): Move this to a Plugin. +func (sched *Scheduler) extendersBinding(pod *v1.Pod, node string) (bool, error) { + for _, extender := range sched.Extenders { + if !extender.IsBinder() || !extender.IsInterested(pod) { + continue + } + return true, extender.Bind(&v1.Binding{ + ObjectMeta: metav1.ObjectMeta{Namespace: pod.Namespace, Name: pod.Name, UID: pod.UID}, + Target: v1.ObjectReference{Kind: "Node", Name: node}, + }) + } + return false, nil +} + +func (sched *Scheduler) finishBinding(fwk framework.Framework, assumed *v1.Pod, targetNode string, status *framework.Status) { + if finErr := sched.Cache.FinishBinding(assumed); finErr != nil { + klog.ErrorS(finErr, "Scheduler cache FinishBinding failed") + } + if !status.IsSuccess() { + klog.V(1).InfoS("Failed to bind pod", "pod", klog.KObj(assumed)) + return + } + + fwk.EventRecorder().Eventf(assumed, nil, v1.EventTypeNormal, "Scheduled", "Binding", "Successfully assigned %v/%v to %v", assumed.Namespace, assumed.Name, targetNode) +} + +func getAttemptsLabel(p *framework.QueuedPodInfo) string { + // We breakdown the pod scheduling duration by attempts capped to a limit + // to avoid ending up with a high cardinality metric. + if p.Attempts >= 15 { + return "15+" + } + return strconv.Itoa(p.Attempts) +} + +// handleSchedulingFailure records an event for the pod that indicates the +// pod has failed to schedule. Also, update the pod condition and nominated node name if set. +func (sched *Scheduler) handleSchedulingFailure(ctx context.Context, fwk framework.Framework, podInfo *framework.QueuedPodInfo, err error, reason string, nominatingInfo *framework.NominatingInfo, start time.Time) { + switch reason { + case v1.PodReasonUnschedulable: + metrics.PodUnschedulable(fwk.ProfileName(), metrics.SinceInSeconds(start)) + case v1.PodReasonSchedulerError: + metrics.PodScheduleError(fwk.ProfileName(), metrics.SinceInSeconds(start)) + } + + pod := podInfo.Pod + var errMsg string + if err != nil { + errMsg = err.Error() + } + if err == ErrNoNodesAvailable { + klog.V(2).InfoS("Unable to schedule pod; no nodes are registered to the cluster; waiting", "pod", klog.KObj(pod)) + } else if fitError, ok := err.(*framework.FitError); ok { + // Inject UnschedulablePlugins to PodInfo, which will be used later for moving Pods between queues efficiently. + podInfo.UnschedulablePlugins = fitError.Diagnosis.UnschedulablePlugins + klog.V(2).InfoS("Unable to schedule pod; no fit; waiting", "pod", klog.KObj(pod), "err", errMsg) + } else if apierrors.IsNotFound(err) { + klog.V(2).InfoS("Unable to schedule pod, possibly due to node not found; waiting", "pod", klog.KObj(pod), "err", errMsg) + if errStatus, ok := err.(apierrors.APIStatus); ok && errStatus.Status().Details.Kind == "node" { + nodeName := errStatus.Status().Details.Name + // when node is not found, We do not remove the node right away. Trying again to get + // the node and if the node is still not found, then remove it from the scheduler cache. + _, err := fwk.ClientSet().CoreV1().Nodes().Get(context.TODO(), nodeName, metav1.GetOptions{}) + if err != nil && apierrors.IsNotFound(err) { + node := v1.Node{ObjectMeta: metav1.ObjectMeta{Name: nodeName}} + if err := sched.Cache.RemoveNode(&node); err != nil { + klog.V(4).InfoS("Node is not found; failed to remove it from the cache", "node", node.Name) + } + } + } + } else { + klog.ErrorS(err, "Error scheduling pod; retrying", "pod", klog.KObj(pod)) + } + + // Check if the Pod exists in informer cache. + podLister := fwk.SharedInformerFactory().Core().V1().Pods().Lister() + cachedPod, e := podLister.Pods(pod.Namespace).Get(pod.Name) + if e != nil { + klog.InfoS("Pod doesn't exist in informer cache", "pod", klog.KObj(pod), "err", e) + } else { + // In the case of extender, the pod may have been bound successfully, but timed out returning its response to the scheduler. + // It could result in the live version to carry .spec.nodeName, and that's inconsistent with the internal-queued version. + if len(cachedPod.Spec.NodeName) != 0 { + klog.InfoS("Pod has been assigned to node. Abort adding it back to queue.", "pod", klog.KObj(pod), "node", cachedPod.Spec.NodeName) + } else { + // As is from SharedInformer, we need to do a DeepCopy() here. + // ignore this err since apiserver doesn't properly validate affinity terms + // and we can't fix the validation for backwards compatibility. + podInfo.PodInfo, _ = framework.NewPodInfo(cachedPod.DeepCopy()) + if err := sched.SchedulingQueue.AddUnschedulableIfNotPresent(podInfo, sched.SchedulingQueue.SchedulingCycle()); err != nil { + klog.ErrorS(err, "Error occurred") + } + } + } + + // Update the scheduling queue with the nominated pod information. Without + // this, there would be a race condition between the next scheduling cycle + // and the time the scheduler receives a Pod Update for the nominated pod. + // Here we check for nil only for tests. + if sched.SchedulingQueue != nil { + sched.SchedulingQueue.AddNominatedPod(podInfo.PodInfo, nominatingInfo) + } + + if err == nil { + // Only tests can reach here. + return + } + + msg := truncateMessage(errMsg) + fwk.EventRecorder().Eventf(pod, nil, v1.EventTypeWarning, "FailedScheduling", "Scheduling", msg) + if err := updatePod(ctx, sched.client, pod, &v1.PodCondition{ + Type: v1.PodScheduled, + Status: v1.ConditionFalse, + Reason: reason, + Message: errMsg, + }, nominatingInfo); err != nil { + klog.ErrorS(err, "Error updating pod", "pod", klog.KObj(pod)) + } +} + +// truncateMessage truncates a message if it hits the NoteLengthLimit. +func truncateMessage(message string) string { + max := validation.NoteLengthLimit + if len(message) <= max { + return message + } + suffix := " ..." + return message[:max-len(suffix)] + suffix +} + +func updatePod(ctx context.Context, client clientset.Interface, pod *v1.Pod, condition *v1.PodCondition, nominatingInfo *framework.NominatingInfo) error { + klog.V(3).InfoS("Updating pod condition", "pod", klog.KObj(pod), "conditionType", condition.Type, "conditionStatus", condition.Status, "conditionReason", condition.Reason) + podStatusCopy := pod.Status.DeepCopy() + // NominatedNodeName is updated only if we are trying to set it, and the value is + // different from the existing one. + nnnNeedsUpdate := nominatingInfo.Mode() == framework.ModeOverride && pod.Status.NominatedNodeName != nominatingInfo.NominatedNodeName + if !podutil.UpdatePodCondition(podStatusCopy, condition) && !nnnNeedsUpdate { + return nil + } + if nnnNeedsUpdate { + podStatusCopy.NominatedNodeName = nominatingInfo.NominatedNodeName + } + return util.PatchPodStatus(ctx, client, pod, podStatusCopy) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/scheduler.go b/vendor/k8s.io/kubernetes/pkg/scheduler/scheduler.go new file mode 100644 index 000000000..958b9ce80 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/scheduler.go @@ -0,0 +1,456 @@ +/* +Copyright 2014 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 scheduler + +import ( + "context" + "errors" + "fmt" + "time" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/dynamic/dynamicinformer" + "k8s.io/client-go/informers" + coreinformers "k8s.io/client-go/informers/core/v1" + clientset "k8s.io/client-go/kubernetes" + restclient "k8s.io/client-go/rest" + "k8s.io/client-go/tools/cache" + "k8s.io/klog/v2" + configv1 "k8s.io/kube-scheduler/config/v1" + schedulerapi "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/kubernetes/pkg/scheduler/apis/config/scheme" + "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/parallelize" + frameworkplugins "k8s.io/kubernetes/pkg/scheduler/framework/plugins" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources" + frameworkruntime "k8s.io/kubernetes/pkg/scheduler/framework/runtime" + internalcache "k8s.io/kubernetes/pkg/scheduler/internal/cache" + cachedebugger "k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger" + internalqueue "k8s.io/kubernetes/pkg/scheduler/internal/queue" + "k8s.io/kubernetes/pkg/scheduler/metrics" + "k8s.io/kubernetes/pkg/scheduler/profile" +) + +const ( + // Duration the scheduler will wait before expiring an assumed pod. + // See issue #106361 for more details about this parameter and its value. + durationToExpireAssumedPod time.Duration = 0 +) + +// ErrNoNodesAvailable is used to describe the error that no nodes available to schedule pods. +var ErrNoNodesAvailable = fmt.Errorf("no nodes available to schedule pods") + +// Scheduler watches for new unscheduled pods. It attempts to find +// nodes that they fit on and writes bindings back to the api server. +type Scheduler struct { + // It is expected that changes made via Cache will be observed + // by NodeLister and Algorithm. + Cache internalcache.Cache + + Extenders []framework.Extender + + // NextPod should be a function that blocks until the next pod + // is available. We don't use a channel for this, because scheduling + // a pod may take some amount of time and we don't want pods to get + // stale while they sit in a channel. + NextPod func() *framework.QueuedPodInfo + + // FailureHandler is called upon a scheduling failure. + FailureHandler FailureHandlerFn + + // SchedulePod tries to schedule the given pod to one of the nodes in the node list. + // Return a struct of ScheduleResult with the name of suggested host on success, + // otherwise will return a FitError with reasons. + SchedulePod func(ctx context.Context, fwk framework.Framework, state *framework.CycleState, pod *v1.Pod) (ScheduleResult, error) + + // Close this to shut down the scheduler. + StopEverything <-chan struct{} + + // SchedulingQueue holds pods to be scheduled + SchedulingQueue internalqueue.SchedulingQueue + + // Profiles are the scheduling profiles. + Profiles profile.Map + + client clientset.Interface + + nodeInfoSnapshot *internalcache.Snapshot + + percentageOfNodesToScore int32 + + nextStartNodeIndex int +} + +func (s *Scheduler) applyDefaultHandlers() { + s.SchedulePod = s.schedulePod + s.FailureHandler = s.handleSchedulingFailure +} + +type schedulerOptions struct { + componentConfigVersion string + kubeConfig *restclient.Config + // Overridden by profile level percentageOfNodesToScore if set in v1. + percentageOfNodesToScore int32 + podInitialBackoffSeconds int64 + podMaxBackoffSeconds int64 + podMaxInUnschedulablePodsDuration time.Duration + // Contains out-of-tree plugins to be merged with the in-tree registry. + frameworkOutOfTreeRegistry frameworkruntime.Registry + profiles []schedulerapi.KubeSchedulerProfile + extenders []schedulerapi.Extender + frameworkCapturer FrameworkCapturer + parallelism int32 + applyDefaultProfile bool +} + +// Option configures a Scheduler +type Option func(*schedulerOptions) + +// ScheduleResult represents the result of scheduling a pod. +type ScheduleResult struct { + // Name of the selected node. + SuggestedHost string + // The number of nodes the scheduler evaluated the pod against in the filtering + // phase and beyond. + EvaluatedNodes int + // The number of nodes out of the evaluated ones that fit the pod. + FeasibleNodes int + + // The reason records the failure in scheduling cycle. + reason string + // The nominating info for scheduling cycle. + nominatingInfo *framework.NominatingInfo +} + +// WithComponentConfigVersion sets the component config version to the +// KubeSchedulerConfiguration version used. The string should be the full +// scheme group/version of the external type we converted from (for example +// "kubescheduler.config.k8s.io/v1") +func WithComponentConfigVersion(apiVersion string) Option { + return func(o *schedulerOptions) { + o.componentConfigVersion = apiVersion + } +} + +// WithKubeConfig sets the kube config for Scheduler. +func WithKubeConfig(cfg *restclient.Config) Option { + return func(o *schedulerOptions) { + o.kubeConfig = cfg + } +} + +// WithProfiles sets profiles for Scheduler. By default, there is one profile +// with the name "default-scheduler". +func WithProfiles(p ...schedulerapi.KubeSchedulerProfile) Option { + return func(o *schedulerOptions) { + o.profiles = p + o.applyDefaultProfile = false + } +} + +// WithParallelism sets the parallelism for all scheduler algorithms. Default is 16. +func WithParallelism(threads int32) Option { + return func(o *schedulerOptions) { + o.parallelism = threads + } +} + +// WithPercentageOfNodesToScore sets percentageOfNodesToScore for Scheduler. +// The default value of 0 will use an adaptive percentage: 50 - (num of nodes)/125. +func WithPercentageOfNodesToScore(percentageOfNodesToScore *int32) Option { + return func(o *schedulerOptions) { + if percentageOfNodesToScore != nil { + o.percentageOfNodesToScore = *percentageOfNodesToScore + } + } +} + +// WithFrameworkOutOfTreeRegistry sets the registry for out-of-tree plugins. Those plugins +// will be appended to the default registry. +func WithFrameworkOutOfTreeRegistry(registry frameworkruntime.Registry) Option { + return func(o *schedulerOptions) { + o.frameworkOutOfTreeRegistry = registry + } +} + +// WithPodInitialBackoffSeconds sets podInitialBackoffSeconds for Scheduler, the default value is 1 +func WithPodInitialBackoffSeconds(podInitialBackoffSeconds int64) Option { + return func(o *schedulerOptions) { + o.podInitialBackoffSeconds = podInitialBackoffSeconds + } +} + +// WithPodMaxBackoffSeconds sets podMaxBackoffSeconds for Scheduler, the default value is 10 +func WithPodMaxBackoffSeconds(podMaxBackoffSeconds int64) Option { + return func(o *schedulerOptions) { + o.podMaxBackoffSeconds = podMaxBackoffSeconds + } +} + +// WithPodMaxInUnschedulablePodsDuration sets podMaxInUnschedulablePodsDuration for PriorityQueue. +func WithPodMaxInUnschedulablePodsDuration(duration time.Duration) Option { + return func(o *schedulerOptions) { + o.podMaxInUnschedulablePodsDuration = duration + } +} + +// WithExtenders sets extenders for the Scheduler +func WithExtenders(e ...schedulerapi.Extender) Option { + return func(o *schedulerOptions) { + o.extenders = e + } +} + +// FrameworkCapturer is used for registering a notify function in building framework. +type FrameworkCapturer func(schedulerapi.KubeSchedulerProfile) + +// WithBuildFrameworkCapturer sets a notify function for getting buildFramework details. +func WithBuildFrameworkCapturer(fc FrameworkCapturer) Option { + return func(o *schedulerOptions) { + o.frameworkCapturer = fc + } +} + +var defaultSchedulerOptions = schedulerOptions{ + percentageOfNodesToScore: schedulerapi.DefaultPercentageOfNodesToScore, + podInitialBackoffSeconds: int64(internalqueue.DefaultPodInitialBackoffDuration.Seconds()), + podMaxBackoffSeconds: int64(internalqueue.DefaultPodMaxBackoffDuration.Seconds()), + podMaxInUnschedulablePodsDuration: internalqueue.DefaultPodMaxInUnschedulablePodsDuration, + parallelism: int32(parallelize.DefaultParallelism), + // Ideally we would statically set the default profile here, but we can't because + // creating the default profile may require testing feature gates, which may get + // set dynamically in tests. Therefore, we delay creating it until New is actually + // invoked. + applyDefaultProfile: true, +} + +// New returns a Scheduler +func New(client clientset.Interface, + informerFactory informers.SharedInformerFactory, + dynInformerFactory dynamicinformer.DynamicSharedInformerFactory, + recorderFactory profile.RecorderFactory, + stopCh <-chan struct{}, + opts ...Option) (*Scheduler, error) { + + stopEverything := stopCh + if stopEverything == nil { + stopEverything = wait.NeverStop + } + + options := defaultSchedulerOptions + for _, opt := range opts { + opt(&options) + } + + if options.applyDefaultProfile { + var versionedCfg configv1.KubeSchedulerConfiguration + scheme.Scheme.Default(&versionedCfg) + cfg := schedulerapi.KubeSchedulerConfiguration{} + if err := scheme.Scheme.Convert(&versionedCfg, &cfg, nil); err != nil { + return nil, err + } + options.profiles = cfg.Profiles + } + + registry := frameworkplugins.NewInTreeRegistry() + if err := registry.Merge(options.frameworkOutOfTreeRegistry); err != nil { + return nil, err + } + + metrics.Register() + + extenders, err := buildExtenders(options.extenders, options.profiles) + if err != nil { + return nil, fmt.Errorf("couldn't build extenders: %w", err) + } + + podLister := informerFactory.Core().V1().Pods().Lister() + nodeLister := informerFactory.Core().V1().Nodes().Lister() + + snapshot := internalcache.NewEmptySnapshot() + clusterEventMap := make(map[framework.ClusterEvent]sets.String) + + profiles, err := profile.NewMap(options.profiles, registry, recorderFactory, stopCh, + frameworkruntime.WithComponentConfigVersion(options.componentConfigVersion), + frameworkruntime.WithClientSet(client), + frameworkruntime.WithKubeConfig(options.kubeConfig), + frameworkruntime.WithInformerFactory(informerFactory), + frameworkruntime.WithSnapshotSharedLister(snapshot), + frameworkruntime.WithCaptureProfile(frameworkruntime.CaptureProfile(options.frameworkCapturer)), + frameworkruntime.WithClusterEventMap(clusterEventMap), + frameworkruntime.WithParallelism(int(options.parallelism)), + frameworkruntime.WithExtenders(extenders), + ) + if err != nil { + return nil, fmt.Errorf("initializing profiles: %v", err) + } + + if len(profiles) == 0 { + return nil, errors.New("at least one profile is required") + } + + preEnqueuePluginMap := make(map[string][]framework.PreEnqueuePlugin) + for profileName, profile := range profiles { + preEnqueuePluginMap[profileName] = profile.PreEnqueuePlugins() + } + podQueue := internalqueue.NewSchedulingQueue( + profiles[options.profiles[0].SchedulerName].QueueSortFunc(), + informerFactory, + internalqueue.WithPodInitialBackoffDuration(time.Duration(options.podInitialBackoffSeconds)*time.Second), + internalqueue.WithPodMaxBackoffDuration(time.Duration(options.podMaxBackoffSeconds)*time.Second), + internalqueue.WithPodLister(podLister), + internalqueue.WithClusterEventMap(clusterEventMap), + internalqueue.WithPodMaxInUnschedulablePodsDuration(options.podMaxInUnschedulablePodsDuration), + internalqueue.WithPreEnqueuePluginMap(preEnqueuePluginMap), + ) + + for _, fwk := range profiles { + fwk.SetPodNominator(podQueue) + } + + schedulerCache := internalcache.New(durationToExpireAssumedPod, stopEverything) + + // Setup cache debugger. + debugger := cachedebugger.New(nodeLister, podLister, schedulerCache, podQueue) + debugger.ListenForSignal(stopEverything) + + sched := &Scheduler{ + Cache: schedulerCache, + client: client, + nodeInfoSnapshot: snapshot, + percentageOfNodesToScore: options.percentageOfNodesToScore, + Extenders: extenders, + NextPod: internalqueue.MakeNextPodFunc(podQueue), + StopEverything: stopEverything, + SchedulingQueue: podQueue, + Profiles: profiles, + } + sched.applyDefaultHandlers() + + addAllEventHandlers(sched, informerFactory, dynInformerFactory, unionedGVKs(clusterEventMap)) + + return sched, nil +} + +// Run begins watching and scheduling. It starts scheduling and blocked until the context is done. +func (sched *Scheduler) Run(ctx context.Context) { + sched.SchedulingQueue.Run() + + // We need to start scheduleOne loop in a dedicated goroutine, + // because scheduleOne function hangs on getting the next item + // from the SchedulingQueue. + // If there are no new pods to schedule, it will be hanging there + // and if done in this goroutine it will be blocking closing + // SchedulingQueue, in effect causing a deadlock on shutdown. + go wait.UntilWithContext(ctx, sched.scheduleOne, 0) + + <-ctx.Done() + sched.SchedulingQueue.Close() +} + +// NewInformerFactory creates a SharedInformerFactory and initializes a scheduler specific +// in-place podInformer. +func NewInformerFactory(cs clientset.Interface, resyncPeriod time.Duration) informers.SharedInformerFactory { + informerFactory := informers.NewSharedInformerFactory(cs, resyncPeriod) + informerFactory.InformerFor(&v1.Pod{}, newPodInformer) + return informerFactory +} + +func buildExtenders(extenders []schedulerapi.Extender, profiles []schedulerapi.KubeSchedulerProfile) ([]framework.Extender, error) { + var fExtenders []framework.Extender + if len(extenders) == 0 { + return nil, nil + } + + var ignoredExtendedResources []string + var ignorableExtenders []framework.Extender + for i := range extenders { + klog.V(2).InfoS("Creating extender", "extender", extenders[i]) + extender, err := NewHTTPExtender(&extenders[i]) + if err != nil { + return nil, err + } + if !extender.IsIgnorable() { + fExtenders = append(fExtenders, extender) + } else { + ignorableExtenders = append(ignorableExtenders, extender) + } + for _, r := range extenders[i].ManagedResources { + if r.IgnoredByScheduler { + ignoredExtendedResources = append(ignoredExtendedResources, r.Name) + } + } + } + // place ignorable extenders to the tail of extenders + fExtenders = append(fExtenders, ignorableExtenders...) + + // If there are any extended resources found from the Extenders, append them to the pluginConfig for each profile. + // This should only have an effect on ComponentConfig, where it is possible to configure Extenders and + // plugin args (and in which case the extender ignored resources take precedence). + if len(ignoredExtendedResources) == 0 { + return fExtenders, nil + } + + for i := range profiles { + prof := &profiles[i] + var found = false + for k := range prof.PluginConfig { + if prof.PluginConfig[k].Name == noderesources.Name { + // Update the existing args + pc := &prof.PluginConfig[k] + args, ok := pc.Args.(*schedulerapi.NodeResourcesFitArgs) + if !ok { + return nil, fmt.Errorf("want args to be of type NodeResourcesFitArgs, got %T", pc.Args) + } + args.IgnoredResources = ignoredExtendedResources + found = true + break + } + } + if !found { + return nil, fmt.Errorf("can't find NodeResourcesFitArgs in plugin config") + } + } + return fExtenders, nil +} + +type FailureHandlerFn func(ctx context.Context, fwk framework.Framework, podInfo *framework.QueuedPodInfo, err error, reason string, nominatingInfo *framework.NominatingInfo, start time.Time) + +func unionedGVKs(m map[framework.ClusterEvent]sets.String) map[framework.GVK]framework.ActionType { + gvkMap := make(map[framework.GVK]framework.ActionType) + for evt := range m { + if _, ok := gvkMap[evt.Resource]; ok { + gvkMap[evt.Resource] |= evt.ActionType + } else { + gvkMap[evt.Resource] = evt.ActionType + } + } + return gvkMap +} + +// newPodInformer creates a shared index informer that returns only non-terminal pods. +// The PodInformer allows indexers to be added, but note that only non-conflict indexers are allowed. +func newPodInformer(cs clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + selector := fmt.Sprintf("status.phase!=%v,status.phase!=%v", v1.PodSucceeded, v1.PodFailed) + tweakListOptions := func(options *metav1.ListOptions) { + options.FieldSelector = selector + } + return coreinformers.NewFilteredPodInformer(cs, metav1.NamespaceAll, resyncPeriod, cache.Indexers{}, tweakListOptions) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/util/pod_resources.go b/vendor/k8s.io/kubernetes/pkg/scheduler/util/pod_resources.go new file mode 100644 index 000000000..bf665c68c --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/util/pod_resources.go @@ -0,0 +1,78 @@ +/* +Copyright 2016 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 util + +import ( + v1 "k8s.io/api/core/v1" +) + +// For each of these resources, a pod that doesn't request the resource explicitly +// will be treated as having requested the amount indicated below, for the purpose +// of computing priority only. This ensures that when scheduling zero-request pods, such +// pods will not all be scheduled to the node with the smallest in-use request, +// and that when scheduling regular pods, such pods will not see zero-request pods as +// consuming no resources whatsoever. We chose these values to be similar to the +// resources that we give to cluster addon pods (#10653). But they are pretty arbitrary. +// As described in #11713, we use request instead of limit to deal with resource requirements. +const ( + // DefaultMilliCPURequest defines default milli cpu request number. + DefaultMilliCPURequest int64 = 100 // 0.1 core + // DefaultMemoryRequest defines default memory request size. + DefaultMemoryRequest int64 = 200 * 1024 * 1024 // 200 MB +) + +// GetNonzeroRequests returns the default cpu and memory resource request if none is found or +// what is provided on the request. +func GetNonzeroRequests(requests *v1.ResourceList) (int64, int64) { + return GetRequestForResource(v1.ResourceCPU, requests, true), + GetRequestForResource(v1.ResourceMemory, requests, true) +} + +// GetRequestForResource returns the requested values unless nonZero is true and there is no defined request +// for CPU and memory. +// If nonZero is true and the resource has no defined request for CPU or memory, it returns a default value. +func GetRequestForResource(resource v1.ResourceName, requests *v1.ResourceList, nonZero bool) int64 { + if requests == nil { + return 0 + } + switch resource { + case v1.ResourceCPU: + // Override if un-set, but not if explicitly set to zero + if _, found := (*requests)[v1.ResourceCPU]; !found && nonZero { + return DefaultMilliCPURequest + } + return requests.Cpu().MilliValue() + case v1.ResourceMemory: + // Override if un-set, but not if explicitly set to zero + if _, found := (*requests)[v1.ResourceMemory]; !found && nonZero { + return DefaultMemoryRequest + } + return requests.Memory().Value() + case v1.ResourceEphemeralStorage: + quantity, found := (*requests)[v1.ResourceEphemeralStorage] + if !found { + return 0 + } + return quantity.Value() + default: + quantity, found := (*requests)[resource] + if !found { + return 0 + } + return quantity.Value() + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/util/utils.go b/vendor/k8s.io/kubernetes/pkg/scheduler/util/utils.go new file mode 100644 index 000000000..6cc18eee7 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/util/utils.go @@ -0,0 +1,161 @@ +/* +Copyright 2017 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 util + +import ( + "context" + "encoding/json" + "fmt" + "time" + + v1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apimachinery/pkg/util/net" + "k8s.io/apimachinery/pkg/util/strategicpatch" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/util/retry" + corev1helpers "k8s.io/component-helpers/scheduling/corev1" + "k8s.io/klog/v2" + extenderv1 "k8s.io/kube-scheduler/extender/v1" + v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" +) + +// GetPodFullName returns a name that uniquely identifies a pod. +func GetPodFullName(pod *v1.Pod) string { + // Use underscore as the delimiter because it is not allowed in pod name + // (DNS subdomain format). + return pod.Name + "_" + pod.Namespace +} + +// GetPodStartTime returns start time of the given pod or current timestamp +// if it hasn't started yet. +func GetPodStartTime(pod *v1.Pod) *metav1.Time { + if pod.Status.StartTime != nil { + return pod.Status.StartTime + } + // Assumed pods and bound pods that haven't started don't have a StartTime yet. + return &metav1.Time{Time: time.Now()} +} + +// GetEarliestPodStartTime returns the earliest start time of all pods that +// have the highest priority among all victims. +func GetEarliestPodStartTime(victims *extenderv1.Victims) *metav1.Time { + if len(victims.Pods) == 0 { + // should not reach here. + klog.ErrorS(fmt.Errorf("victims.Pods is empty. Should not reach here"), "") + return nil + } + + earliestPodStartTime := GetPodStartTime(victims.Pods[0]) + maxPriority := corev1helpers.PodPriority(victims.Pods[0]) + + for _, pod := range victims.Pods { + if corev1helpers.PodPriority(pod) == maxPriority { + if GetPodStartTime(pod).Before(earliestPodStartTime) { + earliestPodStartTime = GetPodStartTime(pod) + } + } else if corev1helpers.PodPriority(pod) > maxPriority { + maxPriority = corev1helpers.PodPriority(pod) + earliestPodStartTime = GetPodStartTime(pod) + } + } + + return earliestPodStartTime +} + +// MoreImportantPod return true when priority of the first pod is higher than +// the second one. If two pods' priorities are equal, compare their StartTime. +// It takes arguments of the type "interface{}" to be used with SortableList, +// but expects those arguments to be *v1.Pod. +func MoreImportantPod(pod1, pod2 *v1.Pod) bool { + p1 := corev1helpers.PodPriority(pod1) + p2 := corev1helpers.PodPriority(pod2) + if p1 != p2 { + return p1 > p2 + } + return GetPodStartTime(pod1).Before(GetPodStartTime(pod2)) +} + +// Retriable defines the retriable errors during a scheduling cycle. +func Retriable(err error) bool { + return apierrors.IsInternalError(err) || apierrors.IsServiceUnavailable(err) || + net.IsConnectionRefused(err) +} + +// PatchPodStatus calculates the delta bytes change from to , +// and then submit a request to API server to patch the pod changes. +func PatchPodStatus(ctx context.Context, cs kubernetes.Interface, old *v1.Pod, newStatus *v1.PodStatus) error { + if newStatus == nil { + return nil + } + + oldData, err := json.Marshal(v1.Pod{Status: old.Status}) + if err != nil { + return err + } + + newData, err := json.Marshal(v1.Pod{Status: *newStatus}) + if err != nil { + return err + } + patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, &v1.Pod{}) + if err != nil { + return fmt.Errorf("failed to create merge patch for pod %q/%q: %v", old.Namespace, old.Name, err) + } + + if "{}" == string(patchBytes) { + return nil + } + + patchFn := func() error { + _, err := cs.CoreV1().Pods(old.Namespace).Patch(ctx, old.Name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{}, "status") + return err + } + + return retry.OnError(retry.DefaultBackoff, Retriable, patchFn) +} + +// DeletePod deletes the given from API server +func DeletePod(ctx context.Context, cs kubernetes.Interface, pod *v1.Pod) error { + return cs.CoreV1().Pods(pod.Namespace).Delete(ctx, pod.Name, metav1.DeleteOptions{}) +} + +// ClearNominatedNodeName internally submit a patch request to API server +// to set each pods[*].Status.NominatedNodeName> to "". +func ClearNominatedNodeName(ctx context.Context, cs kubernetes.Interface, pods ...*v1.Pod) utilerrors.Aggregate { + var errs []error + for _, p := range pods { + if len(p.Status.NominatedNodeName) == 0 { + continue + } + podStatusCopy := p.Status.DeepCopy() + podStatusCopy.NominatedNodeName = "" + if err := PatchPodStatus(ctx, cs, p, podStatusCopy); err != nil { + errs = append(errs, err) + } + } + return utilerrors.NewAggregate(errs) +} + +// IsScalarResourceName validates the resource for Extended, Hugepages, Native and AttachableVolume resources +func IsScalarResourceName(name v1.ResourceName) bool { + return v1helper.IsExtendedResourceName(name) || v1helper.IsHugePageResourceName(name) || + v1helper.IsPrefixedNativeResource(name) || v1helper.IsAttachableVolumeResourceName(name) +} diff --git a/vendor/k8s.io/kubernetes/pkg/securitycontext/accessors.go b/vendor/k8s.io/kubernetes/pkg/securitycontext/accessors.go new file mode 100644 index 000000000..283181a77 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/securitycontext/accessors.go @@ -0,0 +1,474 @@ +/* +Copyright 2017 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 securitycontext + +import ( + "reflect" + + api "k8s.io/kubernetes/pkg/apis/core" +) + +// PodSecurityContextAccessor allows reading the values of a PodSecurityContext object +type PodSecurityContextAccessor interface { + HostNetwork() bool + HostPID() bool + HostIPC() bool + SELinuxOptions() *api.SELinuxOptions + RunAsUser() *int64 + RunAsGroup() *int64 + RunAsNonRoot() *bool + SupplementalGroups() []int64 + FSGroup() *int64 +} + +// PodSecurityContextMutator allows reading and writing the values of a PodSecurityContext object +type PodSecurityContextMutator interface { + PodSecurityContextAccessor + + SetHostNetwork(bool) + SetHostPID(bool) + SetHostIPC(bool) + SetSELinuxOptions(*api.SELinuxOptions) + SetRunAsUser(*int64) + SetRunAsGroup(*int64) + SetRunAsNonRoot(*bool) + SetSupplementalGroups([]int64) + SetFSGroup(*int64) + + // PodSecurityContext returns the current PodSecurityContext object + PodSecurityContext() *api.PodSecurityContext +} + +// NewPodSecurityContextAccessor returns an accessor for the given pod security context. +// May be initialized with a nil PodSecurityContext. +func NewPodSecurityContextAccessor(podSC *api.PodSecurityContext) PodSecurityContextAccessor { + return &podSecurityContextWrapper{podSC: podSC} +} + +// NewPodSecurityContextMutator returns a mutator for the given pod security context. +// May be initialized with a nil PodSecurityContext. +func NewPodSecurityContextMutator(podSC *api.PodSecurityContext) PodSecurityContextMutator { + return &podSecurityContextWrapper{podSC: podSC} +} + +type podSecurityContextWrapper struct { + podSC *api.PodSecurityContext +} + +func (w *podSecurityContextWrapper) PodSecurityContext() *api.PodSecurityContext { + return w.podSC +} + +func (w *podSecurityContextWrapper) ensurePodSC() { + if w.podSC == nil { + w.podSC = &api.PodSecurityContext{} + } +} + +func (w *podSecurityContextWrapper) HostNetwork() bool { + if w.podSC == nil { + return false + } + return w.podSC.HostNetwork +} +func (w *podSecurityContextWrapper) SetHostNetwork(v bool) { + if w.podSC == nil && v == false { + return + } + w.ensurePodSC() + w.podSC.HostNetwork = v +} +func (w *podSecurityContextWrapper) HostPID() bool { + if w.podSC == nil { + return false + } + return w.podSC.HostPID +} +func (w *podSecurityContextWrapper) SetHostPID(v bool) { + if w.podSC == nil && v == false { + return + } + w.ensurePodSC() + w.podSC.HostPID = v +} +func (w *podSecurityContextWrapper) HostIPC() bool { + if w.podSC == nil { + return false + } + return w.podSC.HostIPC +} +func (w *podSecurityContextWrapper) SetHostIPC(v bool) { + if w.podSC == nil && v == false { + return + } + w.ensurePodSC() + w.podSC.HostIPC = v +} +func (w *podSecurityContextWrapper) SELinuxOptions() *api.SELinuxOptions { + if w.podSC == nil { + return nil + } + return w.podSC.SELinuxOptions +} +func (w *podSecurityContextWrapper) SetSELinuxOptions(v *api.SELinuxOptions) { + if w.podSC == nil && v == nil { + return + } + w.ensurePodSC() + w.podSC.SELinuxOptions = v +} +func (w *podSecurityContextWrapper) RunAsUser() *int64 { + if w.podSC == nil { + return nil + } + return w.podSC.RunAsUser +} +func (w *podSecurityContextWrapper) SetRunAsUser(v *int64) { + if w.podSC == nil && v == nil { + return + } + w.ensurePodSC() + w.podSC.RunAsUser = v +} +func (w *podSecurityContextWrapper) RunAsGroup() *int64 { + if w.podSC == nil { + return nil + } + return w.podSC.RunAsGroup +} +func (w *podSecurityContextWrapper) SetRunAsGroup(v *int64) { + if w.podSC == nil && v == nil { + return + } + w.ensurePodSC() + w.podSC.RunAsGroup = v +} + +func (w *podSecurityContextWrapper) RunAsNonRoot() *bool { + if w.podSC == nil { + return nil + } + return w.podSC.RunAsNonRoot +} +func (w *podSecurityContextWrapper) SetRunAsNonRoot(v *bool) { + if w.podSC == nil && v == nil { + return + } + w.ensurePodSC() + w.podSC.RunAsNonRoot = v +} +func (w *podSecurityContextWrapper) SupplementalGroups() []int64 { + if w.podSC == nil { + return nil + } + return w.podSC.SupplementalGroups +} +func (w *podSecurityContextWrapper) SetSupplementalGroups(v []int64) { + if w.podSC == nil && len(v) == 0 { + return + } + w.ensurePodSC() + if len(v) == 0 && len(w.podSC.SupplementalGroups) == 0 { + return + } + w.podSC.SupplementalGroups = v +} +func (w *podSecurityContextWrapper) FSGroup() *int64 { + if w.podSC == nil { + return nil + } + return w.podSC.FSGroup +} +func (w *podSecurityContextWrapper) SetFSGroup(v *int64) { + if w.podSC == nil && v == nil { + return + } + w.ensurePodSC() + w.podSC.FSGroup = v +} + +// ContainerSecurityContextAccessor allows reading the values of a SecurityContext object +type ContainerSecurityContextAccessor interface { + Capabilities() *api.Capabilities + Privileged() *bool + ProcMount() api.ProcMountType + SELinuxOptions() *api.SELinuxOptions + RunAsUser() *int64 + RunAsGroup() *int64 + RunAsNonRoot() *bool + ReadOnlyRootFilesystem() *bool + AllowPrivilegeEscalation() *bool +} + +// ContainerSecurityContextMutator allows reading and writing the values of a SecurityContext object +type ContainerSecurityContextMutator interface { + ContainerSecurityContextAccessor + + ContainerSecurityContext() *api.SecurityContext + + SetCapabilities(*api.Capabilities) + SetPrivileged(*bool) + SetSELinuxOptions(*api.SELinuxOptions) + SetRunAsUser(*int64) + SetRunAsGroup(*int64) + SetRunAsNonRoot(*bool) + SetReadOnlyRootFilesystem(*bool) + SetAllowPrivilegeEscalation(*bool) +} + +// NewContainerSecurityContextAccessor returns an accessor for the provided container security context +// May be initialized with a nil SecurityContext +func NewContainerSecurityContextAccessor(containerSC *api.SecurityContext) ContainerSecurityContextAccessor { + return &containerSecurityContextWrapper{containerSC: containerSC} +} + +// NewContainerSecurityContextMutator returns a mutator for the provided container security context +// May be initialized with a nil SecurityContext +func NewContainerSecurityContextMutator(containerSC *api.SecurityContext) ContainerSecurityContextMutator { + return &containerSecurityContextWrapper{containerSC: containerSC} +} + +type containerSecurityContextWrapper struct { + containerSC *api.SecurityContext +} + +func (w *containerSecurityContextWrapper) ContainerSecurityContext() *api.SecurityContext { + return w.containerSC +} + +func (w *containerSecurityContextWrapper) ensureContainerSC() { + if w.containerSC == nil { + w.containerSC = &api.SecurityContext{} + } +} + +func (w *containerSecurityContextWrapper) Capabilities() *api.Capabilities { + if w.containerSC == nil { + return nil + } + return w.containerSC.Capabilities +} +func (w *containerSecurityContextWrapper) SetCapabilities(v *api.Capabilities) { + if w.containerSC == nil && v == nil { + return + } + w.ensureContainerSC() + w.containerSC.Capabilities = v +} +func (w *containerSecurityContextWrapper) Privileged() *bool { + if w.containerSC == nil { + return nil + } + return w.containerSC.Privileged +} +func (w *containerSecurityContextWrapper) SetPrivileged(v *bool) { + if w.containerSC == nil && v == nil { + return + } + w.ensureContainerSC() + w.containerSC.Privileged = v +} +func (w *containerSecurityContextWrapper) ProcMount() api.ProcMountType { + if w.containerSC == nil { + return api.DefaultProcMount + } + if w.containerSC.ProcMount == nil { + return api.DefaultProcMount + } + return *w.containerSC.ProcMount +} +func (w *containerSecurityContextWrapper) SELinuxOptions() *api.SELinuxOptions { + if w.containerSC == nil { + return nil + } + return w.containerSC.SELinuxOptions +} +func (w *containerSecurityContextWrapper) SetSELinuxOptions(v *api.SELinuxOptions) { + if w.containerSC == nil && v == nil { + return + } + w.ensureContainerSC() + w.containerSC.SELinuxOptions = v +} +func (w *containerSecurityContextWrapper) RunAsUser() *int64 { + if w.containerSC == nil { + return nil + } + return w.containerSC.RunAsUser +} +func (w *containerSecurityContextWrapper) SetRunAsUser(v *int64) { + if w.containerSC == nil && v == nil { + return + } + w.ensureContainerSC() + w.containerSC.RunAsUser = v +} +func (w *containerSecurityContextWrapper) RunAsGroup() *int64 { + if w.containerSC == nil { + return nil + } + return w.containerSC.RunAsGroup +} +func (w *containerSecurityContextWrapper) SetRunAsGroup(v *int64) { + if w.containerSC == nil && v == nil { + return + } + w.ensureContainerSC() + w.containerSC.RunAsGroup = v +} + +func (w *containerSecurityContextWrapper) RunAsNonRoot() *bool { + if w.containerSC == nil { + return nil + } + return w.containerSC.RunAsNonRoot +} +func (w *containerSecurityContextWrapper) SetRunAsNonRoot(v *bool) { + if w.containerSC == nil && v == nil { + return + } + w.ensureContainerSC() + w.containerSC.RunAsNonRoot = v +} +func (w *containerSecurityContextWrapper) ReadOnlyRootFilesystem() *bool { + if w.containerSC == nil { + return nil + } + return w.containerSC.ReadOnlyRootFilesystem +} +func (w *containerSecurityContextWrapper) SetReadOnlyRootFilesystem(v *bool) { + if w.containerSC == nil && v == nil { + return + } + w.ensureContainerSC() + w.containerSC.ReadOnlyRootFilesystem = v +} +func (w *containerSecurityContextWrapper) AllowPrivilegeEscalation() *bool { + if w.containerSC == nil { + return nil + } + return w.containerSC.AllowPrivilegeEscalation +} +func (w *containerSecurityContextWrapper) SetAllowPrivilegeEscalation(v *bool) { + if w.containerSC == nil && v == nil { + return + } + w.ensureContainerSC() + w.containerSC.AllowPrivilegeEscalation = v +} + +// NewEffectiveContainerSecurityContextAccessor returns an accessor for reading effective values +// for the provided pod security context and container security context +func NewEffectiveContainerSecurityContextAccessor(podSC PodSecurityContextAccessor, containerSC ContainerSecurityContextMutator) ContainerSecurityContextAccessor { + return &effectiveContainerSecurityContextWrapper{podSC: podSC, containerSC: containerSC} +} + +// NewEffectiveContainerSecurityContextMutator returns a mutator for reading and writing effective values +// for the provided pod security context and container security context +func NewEffectiveContainerSecurityContextMutator(podSC PodSecurityContextAccessor, containerSC ContainerSecurityContextMutator) ContainerSecurityContextMutator { + return &effectiveContainerSecurityContextWrapper{podSC: podSC, containerSC: containerSC} +} + +type effectiveContainerSecurityContextWrapper struct { + podSC PodSecurityContextAccessor + containerSC ContainerSecurityContextMutator +} + +func (w *effectiveContainerSecurityContextWrapper) ContainerSecurityContext() *api.SecurityContext { + return w.containerSC.ContainerSecurityContext() +} + +func (w *effectiveContainerSecurityContextWrapper) Capabilities() *api.Capabilities { + return w.containerSC.Capabilities() +} +func (w *effectiveContainerSecurityContextWrapper) SetCapabilities(v *api.Capabilities) { + if !reflect.DeepEqual(w.Capabilities(), v) { + w.containerSC.SetCapabilities(v) + } +} +func (w *effectiveContainerSecurityContextWrapper) Privileged() *bool { + return w.containerSC.Privileged() +} +func (w *effectiveContainerSecurityContextWrapper) SetPrivileged(v *bool) { + if !reflect.DeepEqual(w.Privileged(), v) { + w.containerSC.SetPrivileged(v) + } +} +func (w *effectiveContainerSecurityContextWrapper) ProcMount() api.ProcMountType { + return w.containerSC.ProcMount() +} +func (w *effectiveContainerSecurityContextWrapper) SELinuxOptions() *api.SELinuxOptions { + if v := w.containerSC.SELinuxOptions(); v != nil { + return v + } + return w.podSC.SELinuxOptions() +} +func (w *effectiveContainerSecurityContextWrapper) SetSELinuxOptions(v *api.SELinuxOptions) { + if !reflect.DeepEqual(w.SELinuxOptions(), v) { + w.containerSC.SetSELinuxOptions(v) + } +} +func (w *effectiveContainerSecurityContextWrapper) RunAsUser() *int64 { + if v := w.containerSC.RunAsUser(); v != nil { + return v + } + return w.podSC.RunAsUser() +} +func (w *effectiveContainerSecurityContextWrapper) SetRunAsUser(v *int64) { + if !reflect.DeepEqual(w.RunAsUser(), v) { + w.containerSC.SetRunAsUser(v) + } +} +func (w *effectiveContainerSecurityContextWrapper) RunAsGroup() *int64 { + if v := w.containerSC.RunAsGroup(); v != nil { + return v + } + return w.podSC.RunAsGroup() +} +func (w *effectiveContainerSecurityContextWrapper) SetRunAsGroup(v *int64) { + if !reflect.DeepEqual(w.RunAsGroup(), v) { + w.containerSC.SetRunAsGroup(v) + } +} + +func (w *effectiveContainerSecurityContextWrapper) RunAsNonRoot() *bool { + if v := w.containerSC.RunAsNonRoot(); v != nil { + return v + } + return w.podSC.RunAsNonRoot() +} +func (w *effectiveContainerSecurityContextWrapper) SetRunAsNonRoot(v *bool) { + if !reflect.DeepEqual(w.RunAsNonRoot(), v) { + w.containerSC.SetRunAsNonRoot(v) + } +} +func (w *effectiveContainerSecurityContextWrapper) ReadOnlyRootFilesystem() *bool { + return w.containerSC.ReadOnlyRootFilesystem() +} +func (w *effectiveContainerSecurityContextWrapper) SetReadOnlyRootFilesystem(v *bool) { + if !reflect.DeepEqual(w.ReadOnlyRootFilesystem(), v) { + w.containerSC.SetReadOnlyRootFilesystem(v) + } +} +func (w *effectiveContainerSecurityContextWrapper) AllowPrivilegeEscalation() *bool { + return w.containerSC.AllowPrivilegeEscalation() +} +func (w *effectiveContainerSecurityContextWrapper) SetAllowPrivilegeEscalation(v *bool) { + if !reflect.DeepEqual(w.AllowPrivilegeEscalation(), v) { + w.containerSC.SetAllowPrivilegeEscalation(v) + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/securitycontext/doc.go b/vendor/k8s.io/kubernetes/pkg/securitycontext/doc.go new file mode 100644 index 000000000..3ec795d47 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/securitycontext/doc.go @@ -0,0 +1,18 @@ +/* +Copyright 2014 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 securitycontext contains security context api implementations +package securitycontext // import "k8s.io/kubernetes/pkg/securitycontext" diff --git a/vendor/k8s.io/kubernetes/pkg/securitycontext/fake.go b/vendor/k8s.io/kubernetes/pkg/securitycontext/fake.go new file mode 100644 index 000000000..a0a4ae193 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/securitycontext/fake.go @@ -0,0 +1,46 @@ +/* +Copyright 2014 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 securitycontext + +import ( + "k8s.io/api/core/v1" + api "k8s.io/kubernetes/pkg/apis/core" +) + +// ValidSecurityContextWithContainerDefaults creates a valid security context provider based on +// empty container defaults. Used for testing. +func ValidSecurityContextWithContainerDefaults() *v1.SecurityContext { + priv := false + defProcMount := v1.DefaultProcMount + return &v1.SecurityContext{ + Capabilities: &v1.Capabilities{}, + Privileged: &priv, + ProcMount: &defProcMount, + } +} + +// ValidInternalSecurityContextWithContainerDefaults creates a valid security context provider based on +// empty container defaults. Used for testing. +func ValidInternalSecurityContextWithContainerDefaults() *api.SecurityContext { + priv := false + dpm := api.DefaultProcMount + return &api.SecurityContext{ + Capabilities: &api.Capabilities{}, + Privileged: &priv, + ProcMount: &dpm, + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/securitycontext/util.go b/vendor/k8s.io/kubernetes/pkg/securitycontext/util.go new file mode 100644 index 000000000..82a2fc5e0 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/securitycontext/util.go @@ -0,0 +1,260 @@ +/* +Copyright 2014 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 securitycontext + +import ( + v1 "k8s.io/api/core/v1" +) + +// HasPrivilegedRequest returns the value of SecurityContext.Privileged, taking into account +// the possibility of nils +func HasPrivilegedRequest(container *v1.Container) bool { + if container.SecurityContext == nil { + return false + } + if container.SecurityContext.Privileged == nil { + return false + } + return *container.SecurityContext.Privileged +} + +// HasCapabilitiesRequest returns true if Adds or Drops are defined in the security context +// capabilities, taking into account nils +func HasCapabilitiesRequest(container *v1.Container) bool { + if container.SecurityContext == nil { + return false + } + if container.SecurityContext.Capabilities == nil { + return false + } + return len(container.SecurityContext.Capabilities.Add) > 0 || len(container.SecurityContext.Capabilities.Drop) > 0 +} + +// HasWindowsHostProcessRequest returns true if container should run as HostProcess container, +// taking into account nils +func HasWindowsHostProcessRequest(pod *v1.Pod, container *v1.Container) bool { + effectiveSc := DetermineEffectiveSecurityContext(pod, container) + + if effectiveSc.WindowsOptions == nil { + return false + } + if effectiveSc.WindowsOptions.HostProcess == nil { + return false + } + return *effectiveSc.WindowsOptions.HostProcess +} + +// DetermineEffectiveSecurityContext returns a synthesized SecurityContext for reading effective configurations +// from the provided pod's and container's security context. Container's fields take precedence in cases where both +// are set +func DetermineEffectiveSecurityContext(pod *v1.Pod, container *v1.Container) *v1.SecurityContext { + effectiveSc := securityContextFromPodSecurityContext(pod) + containerSc := container.SecurityContext + + if effectiveSc == nil && containerSc == nil { + return &v1.SecurityContext{} + } + if effectiveSc != nil && containerSc == nil { + return effectiveSc + } + if effectiveSc == nil && containerSc != nil { + return containerSc + } + + if containerSc.SELinuxOptions != nil { + effectiveSc.SELinuxOptions = new(v1.SELinuxOptions) + *effectiveSc.SELinuxOptions = *containerSc.SELinuxOptions + } + + if containerSc.WindowsOptions != nil { + // only override fields that are set at the container level, not the whole thing + if effectiveSc.WindowsOptions == nil { + effectiveSc.WindowsOptions = &v1.WindowsSecurityContextOptions{} + } + if containerSc.WindowsOptions.GMSACredentialSpecName != nil || containerSc.WindowsOptions.GMSACredentialSpec != nil { + // both GMSA fields go hand in hand + effectiveSc.WindowsOptions.GMSACredentialSpecName = containerSc.WindowsOptions.GMSACredentialSpecName + effectiveSc.WindowsOptions.GMSACredentialSpec = containerSc.WindowsOptions.GMSACredentialSpec + } + if containerSc.WindowsOptions.RunAsUserName != nil { + effectiveSc.WindowsOptions.RunAsUserName = containerSc.WindowsOptions.RunAsUserName + } + if containerSc.WindowsOptions.HostProcess != nil { + effectiveSc.WindowsOptions.HostProcess = containerSc.WindowsOptions.HostProcess + } + } + + if containerSc.Capabilities != nil { + effectiveSc.Capabilities = new(v1.Capabilities) + *effectiveSc.Capabilities = *containerSc.Capabilities + } + + if containerSc.Privileged != nil { + effectiveSc.Privileged = new(bool) + *effectiveSc.Privileged = *containerSc.Privileged + } + + if containerSc.RunAsUser != nil { + effectiveSc.RunAsUser = new(int64) + *effectiveSc.RunAsUser = *containerSc.RunAsUser + } + + if containerSc.RunAsGroup != nil { + effectiveSc.RunAsGroup = new(int64) + *effectiveSc.RunAsGroup = *containerSc.RunAsGroup + } + + if containerSc.RunAsNonRoot != nil { + effectiveSc.RunAsNonRoot = new(bool) + *effectiveSc.RunAsNonRoot = *containerSc.RunAsNonRoot + } + + if containerSc.ReadOnlyRootFilesystem != nil { + effectiveSc.ReadOnlyRootFilesystem = new(bool) + *effectiveSc.ReadOnlyRootFilesystem = *containerSc.ReadOnlyRootFilesystem + } + + if containerSc.AllowPrivilegeEscalation != nil { + effectiveSc.AllowPrivilegeEscalation = new(bool) + *effectiveSc.AllowPrivilegeEscalation = *containerSc.AllowPrivilegeEscalation + } + + if containerSc.ProcMount != nil { + effectiveSc.ProcMount = new(v1.ProcMountType) + *effectiveSc.ProcMount = *containerSc.ProcMount + } + + return effectiveSc +} + +// DetermineEffectiveRunAsUser returns a pointer of UID from the provided pod's +// and container's security context and a bool value to indicate if it is absent. +// Container's runAsUser take precedence in cases where both are set. +func DetermineEffectiveRunAsUser(pod *v1.Pod, container *v1.Container) (*int64, bool) { + var runAsUser *int64 + if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.RunAsUser != nil { + runAsUser = new(int64) + *runAsUser = *pod.Spec.SecurityContext.RunAsUser + } + if container.SecurityContext != nil && container.SecurityContext.RunAsUser != nil { + runAsUser = new(int64) + *runAsUser = *container.SecurityContext.RunAsUser + } + if runAsUser == nil { + return nil, false + } + return runAsUser, true +} + +func securityContextFromPodSecurityContext(pod *v1.Pod) *v1.SecurityContext { + if pod.Spec.SecurityContext == nil { + return nil + } + + synthesized := &v1.SecurityContext{} + + if pod.Spec.SecurityContext.SELinuxOptions != nil { + synthesized.SELinuxOptions = &v1.SELinuxOptions{} + *synthesized.SELinuxOptions = *pod.Spec.SecurityContext.SELinuxOptions + } + + if pod.Spec.SecurityContext.WindowsOptions != nil { + synthesized.WindowsOptions = &v1.WindowsSecurityContextOptions{} + *synthesized.WindowsOptions = *pod.Spec.SecurityContext.WindowsOptions + } + + if pod.Spec.SecurityContext.RunAsUser != nil { + synthesized.RunAsUser = new(int64) + *synthesized.RunAsUser = *pod.Spec.SecurityContext.RunAsUser + } + + if pod.Spec.SecurityContext.RunAsGroup != nil { + synthesized.RunAsGroup = new(int64) + *synthesized.RunAsGroup = *pod.Spec.SecurityContext.RunAsGroup + } + + if pod.Spec.SecurityContext.RunAsNonRoot != nil { + synthesized.RunAsNonRoot = new(bool) + *synthesized.RunAsNonRoot = *pod.Spec.SecurityContext.RunAsNonRoot + } + + return synthesized +} + +// AddNoNewPrivileges returns if we should add the no_new_privs option. +func AddNoNewPrivileges(sc *v1.SecurityContext) bool { + if sc == nil { + return false + } + + // handle the case where the user did not set the default and did not explicitly set allowPrivilegeEscalation + if sc.AllowPrivilegeEscalation == nil { + return false + } + + // handle the case where defaultAllowPrivilegeEscalation is false or the user explicitly set allowPrivilegeEscalation to true/false + return !*sc.AllowPrivilegeEscalation +} + +var ( + // These *must* be kept in sync with moby/moby. + // https://github.com/moby/moby/blob/master/oci/defaults.go#L116-L134 + // @jessfraz will watch changes to those files upstream. + defaultMaskedPaths = []string{ + "/proc/acpi", + "/proc/kcore", + "/proc/keys", + "/proc/latency_stats", + "/proc/timer_list", + "/proc/timer_stats", + "/proc/sched_debug", + "/proc/scsi", + "/sys/firmware", + } + defaultReadonlyPaths = []string{ + "/proc/asound", + "/proc/bus", + "/proc/fs", + "/proc/irq", + "/proc/sys", + "/proc/sysrq-trigger", + } +) + +// ConvertToRuntimeMaskedPaths converts the ProcMountType to the specified or default +// masked paths. +func ConvertToRuntimeMaskedPaths(opt *v1.ProcMountType) []string { + if opt != nil && *opt == v1.UnmaskedProcMount { + // Unmasked proc mount should have no paths set as masked. + return []string{} + } + + // Otherwise, add the default masked paths to the runtime security context. + return defaultMaskedPaths +} + +// ConvertToRuntimeReadonlyPaths converts the ProcMountType to the specified or default +// readonly paths. +func ConvertToRuntimeReadonlyPaths(opt *v1.ProcMountType) []string { + if opt != nil && *opt == v1.UnmaskedProcMount { + // Unmasked proc mount should have no paths set as readonly. + return []string{} + } + + // Otherwise, add the default readonly paths to the runtime security context. + return defaultReadonlyPaths +} diff --git a/vendor/k8s.io/kubernetes/pkg/util/parsers/parsers.go b/vendor/k8s.io/kubernetes/pkg/util/parsers/parsers.go new file mode 100644 index 000000000..ef869cd76 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/util/parsers/parsers.go @@ -0,0 +1,54 @@ +/* +Copyright 2015 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 parsers + +import ( + "fmt" + // Import the crypto sha256 algorithm for the docker image parser to work + _ "crypto/sha256" + // Import the crypto/sha512 algorithm for the docker image parser to work with 384 and 512 sha hashes + _ "crypto/sha512" + + dockerref "github.com/docker/distribution/reference" +) + +// ParseImageName parses a docker image string into three parts: repo, tag and digest. +// If both tag and digest are empty, a default image tag will be returned. +func ParseImageName(image string) (string, string, string, error) { + named, err := dockerref.ParseNormalizedNamed(image) + if err != nil { + return "", "", "", fmt.Errorf("couldn't parse image name: %v", err) + } + + repoToPull := named.Name() + var tag, digest string + + tagged, ok := named.(dockerref.Tagged) + if ok { + tag = tagged.Tag() + } + + digested, ok := named.(dockerref.Digested) + if ok { + digest = digested.Digest().String() + } + // If no tag was specified, use the default "latest". + if len(tag) == 0 && len(digest) == 0 { + tag = "latest" + } + return repoToPull, tag, digest, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/OWNERS b/vendor/k8s.io/kubernetes/pkg/volume/OWNERS new file mode 100644 index 000000000..451008a3e --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/OWNERS @@ -0,0 +1,8 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +approvers: + - sig-storage-approvers +reviewers: + - sig-storage-reviewers +labels: + - sig/storage diff --git a/vendor/k8s.io/kubernetes/pkg/volume/doc.go b/vendor/k8s.io/kubernetes/pkg/volume/doc.go new file mode 100644 index 000000000..c98a5a153 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2014 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 volume includes internal representations of external volume types +// as well as utility methods required to mount/unmount volumes to kubelets. +package volume // import "k8s.io/kubernetes/pkg/volume" diff --git a/vendor/k8s.io/kubernetes/pkg/volume/metrics_block.go b/vendor/k8s.io/kubernetes/pkg/volume/metrics_block.go new file mode 100644 index 000000000..e370afca2 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/metrics_block.go @@ -0,0 +1,92 @@ +/* +Copyright 2021 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 volume + +import ( + "fmt" + "io" + "os" + "runtime" + "time" + + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + servermetrics "k8s.io/kubernetes/pkg/kubelet/server/metrics" +) + +var _ MetricsProvider = &metricsBlock{} + +// metricsBlock represents a MetricsProvider that detects the size of the +// BlockMode Volume. +type metricsBlock struct { + // the device node where the volume is attached to. + device string +} + +// NewMetricsStatfs creates a new metricsBlock with the device node of the +// Volume. +func NewMetricsBlock(device string) MetricsProvider { + return &metricsBlock{device} +} + +// See MetricsProvider.GetMetrics +// GetMetrics detects the size of the BlockMode volume for the device node +// where the Volume is attached. +// +// Note that only the capacity of the device can be detected with standard +// tools. Storage systems may have more information that they can provide by +// going through specialized APIs. +func (mb *metricsBlock) GetMetrics() (*Metrics, error) { + startTime := time.Now() + defer servermetrics.CollectVolumeStatCalDuration("block", startTime) + + // TODO: Windows does not yet support VolumeMode=Block + if runtime.GOOS == "windows" { + return nil, NewNotImplementedError("Windows does not support Block volumes") + } + + metrics := &Metrics{Time: metav1.Now()} + if mb.device == "" { + return metrics, NewNoPathDefinedError() + } + + err := mb.getBlockInfo(metrics) + if err != nil { + return metrics, err + } + + return metrics, nil +} + +// getBlockInfo fetches metrics.Capacity by opening the device and seeking to +// the end. +func (mb *metricsBlock) getBlockInfo(metrics *Metrics) error { + dev, err := os.Open(mb.device) + if err != nil { + return fmt.Errorf("unable to open device %q: %w", mb.device, err) + } + defer dev.Close() + + end, err := dev.Seek(0, io.SeekEnd) + if err != nil { + return fmt.Errorf("failed to detect size of %q: %w", mb.device, err) + } + + metrics.Capacity = resource.NewQuantity(end, resource.BinarySI) + + return nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/metrics_cached.go b/vendor/k8s.io/kubernetes/pkg/volume/metrics_cached.go new file mode 100644 index 000000000..3aef3d206 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/metrics_cached.go @@ -0,0 +1,74 @@ +/* +Copyright 2014 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 volume + +import ( + "sync" + "sync/atomic" +) + +var _ MetricsProvider = &cachedMetrics{} + +// cachedMetrics represents a MetricsProvider that wraps another provider and +// caches the result. +type cachedMetrics struct { + wrapped MetricsProvider + resultError error + resultMetrics *Metrics + once cacheOnce +} + +// NewCachedMetrics creates a new cachedMetrics wrapping another +// MetricsProvider and caching the results. +func NewCachedMetrics(provider MetricsProvider) MetricsProvider { + return &cachedMetrics{wrapped: provider} +} + +// GetMetrics runs the wrapped metrics provider's GetMetrics method once and +// caches the result. Will not cache result if there is an error. +// See MetricsProvider.GetMetrics +func (md *cachedMetrics) GetMetrics() (*Metrics, error) { + md.once.cache(func() error { + md.resultMetrics, md.resultError = md.wrapped.GetMetrics() + return md.resultError + }) + return md.resultMetrics, md.resultError +} + +// Copied from sync.Once but we don't want to cache the results if there is an +// error +type cacheOnce struct { + m sync.Mutex + done uint32 +} + +// Copied from sync.Once but we don't want to cache the results if there is an +// error +func (o *cacheOnce) cache(f func() error) { + if atomic.LoadUint32(&o.done) == 1 { + return + } + // Slow-path. + o.m.Lock() + defer o.m.Unlock() + if o.done == 0 { + err := f() + if err == nil { + atomic.StoreUint32(&o.done, 1) + } + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/metrics_du.go b/vendor/k8s.io/kubernetes/pkg/volume/metrics_du.go new file mode 100644 index 000000000..f080fac2b --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/metrics_du.go @@ -0,0 +1,85 @@ +/* +Copyright 2014 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 volume + +import ( + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/kubernetes/pkg/volume/util/fs" +) + +var _ MetricsProvider = &metricsDu{} + +// metricsDu represents a MetricsProvider that calculates the used and +// available Volume space by calling fs.DiskUsage() and gathering +// filesystem info for the Volume path. +type metricsDu struct { + // the directory path the volume is mounted to. + path string +} + +// NewMetricsDu creates a new metricsDu with the Volume path. +func NewMetricsDu(path string) MetricsProvider { + return &metricsDu{path} +} + +// GetMetrics calculates the volume usage and device free space by executing "du" +// and gathering filesystem info for the Volume path. +// See MetricsProvider.GetMetrics +func (md *metricsDu) GetMetrics() (*Metrics, error) { + metrics := &Metrics{Time: metav1.Now()} + if md.path == "" { + return metrics, NewNoPathDefinedError() + } + + err := md.getDiskUsage(metrics) + if err != nil { + return metrics, err + } + + err = md.getFsInfo(metrics) + if err != nil { + return metrics, err + } + + return metrics, nil +} + +// getDiskUsage writes metrics.Used and metric.InodesUsed from fs.DiskUsage +func (md *metricsDu) getDiskUsage(metrics *Metrics) error { + usage, err := fs.DiskUsage(md.path) + if err != nil { + return err + } + metrics.Used = resource.NewQuantity(usage.Bytes, resource.BinarySI) + metrics.InodesUsed = resource.NewQuantity(usage.Inodes, resource.BinarySI) + return nil +} + +// getFsInfo writes metrics.Capacity and metrics.Available from the filesystem +// info +func (md *metricsDu) getFsInfo(metrics *Metrics) error { + available, capacity, _, inodes, inodesFree, _, err := fs.Info(md.path) + if err != nil { + return NewFsInfoFailedError(err) + } + metrics.Available = resource.NewQuantity(available, resource.BinarySI) + metrics.Capacity = resource.NewQuantity(capacity, resource.BinarySI) + metrics.Inodes = resource.NewQuantity(inodes, resource.BinarySI) + metrics.InodesFree = resource.NewQuantity(inodesFree, resource.BinarySI) + return nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/metrics_errors.go b/vendor/k8s.io/kubernetes/pkg/volume/metrics_errors.go new file mode 100644 index 000000000..0f7987e09 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/metrics_errors.go @@ -0,0 +1,94 @@ +/* +Copyright 2016 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 volume + +import ( + "fmt" +) + +const ( + // ErrCodeNotSupported code for NotSupported Errors. + ErrCodeNotSupported int = iota + 1 + ErrCodeNoPathDefined + ErrCodeFsInfoFailed +) + +// NewNotSupportedError creates a new MetricsError with code NotSupported. +func NewNotSupportedError() *MetricsError { + return &MetricsError{ + Code: ErrCodeNotSupported, + Msg: "metrics are not supported for MetricsNil Volumes", + } +} + +// NewNotImplementedError creates a new MetricsError with code NotSupported. +func NewNotImplementedError(reason string) *MetricsError { + return &MetricsError{ + Code: ErrCodeNotSupported, + Msg: fmt.Sprintf("metrics support is not implemented: %s", reason), + } +} + +// NewNotSupportedErrorWithDriverName creates a new MetricsError with code NotSupported. +// driver name is added to the error message. +func NewNotSupportedErrorWithDriverName(name string) *MetricsError { + return &MetricsError{ + Code: ErrCodeNotSupported, + Msg: fmt.Sprintf("metrics are not supported for %s volumes", name), + } +} + +// NewNoPathDefinedError creates a new MetricsError with code NoPathDefined. +func NewNoPathDefinedError() *MetricsError { + return &MetricsError{ + Code: ErrCodeNoPathDefined, + Msg: "no path defined for disk usage metrics.", + } +} + +// NewFsInfoFailedError creates a new MetricsError with code FsInfoFailed. +func NewFsInfoFailedError(err error) *MetricsError { + return &MetricsError{ + Code: ErrCodeFsInfoFailed, + Msg: fmt.Sprintf("failed to get FsInfo due to error %v", err), + } +} + +// MetricsError to distinguish different Metrics Errors. +type MetricsError struct { + Code int + Msg string +} + +func (e *MetricsError) Error() string { + return e.Msg +} + +// IsNotSupported returns true if and only if err is "key" not found error. +func IsNotSupported(err error) bool { + return isErrCode(err, ErrCodeNotSupported) +} + +func isErrCode(err error, code int) bool { + if err == nil { + return false + } + if e, ok := err.(*MetricsError); ok { + return e.Code == code + } + return false +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/metrics_nil.go b/vendor/k8s.io/kubernetes/pkg/volume/metrics_nil.go new file mode 100644 index 000000000..11b74e079 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/metrics_nil.go @@ -0,0 +1,35 @@ +/* +Copyright 2014 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 volume + +var _ MetricsProvider = &MetricsNil{} + +// MetricsNil represents a MetricsProvider that does not support returning +// Metrics. It serves as a placeholder for Volumes that do not yet support +// metrics. +type MetricsNil struct{} + +// SupportsMetrics returns false for the MetricsNil type. +func (*MetricsNil) SupportsMetrics() bool { + return false +} + +// GetMetrics returns an empty Metrics and an error. +// See MetricsProvider.GetMetrics +func (*MetricsNil) GetMetrics() (*Metrics, error) { + return &Metrics{}, NewNotSupportedError() +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/metrics_statfs.go b/vendor/k8s.io/kubernetes/pkg/volume/metrics_statfs.go new file mode 100644 index 000000000..81a6748b1 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/metrics_statfs.go @@ -0,0 +1,75 @@ +/* +Copyright 2016 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 volume + +import ( + "time" + + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + servermetrics "k8s.io/kubernetes/pkg/kubelet/server/metrics" + "k8s.io/kubernetes/pkg/volume/util/fs" +) + +var _ MetricsProvider = &metricsStatFS{} + +// metricsStatFS represents a MetricsProvider that calculates the used and available +// Volume space by stat'ing and gathering filesystem info for the Volume path. +type metricsStatFS struct { + // the directory path the volume is mounted to. + path string +} + +// NewMetricsStatfs creates a new metricsStatFS with the Volume path. +func NewMetricsStatFS(path string) MetricsProvider { + return &metricsStatFS{path} +} + +// See MetricsProvider.GetMetrics +// GetMetrics calculates the volume usage and device free space by executing "du" +// and gathering filesystem info for the Volume path. +func (md *metricsStatFS) GetMetrics() (*Metrics, error) { + startTime := time.Now() + defer servermetrics.CollectVolumeStatCalDuration("statfs", startTime) + + metrics := &Metrics{Time: metav1.Now()} + if md.path == "" { + return metrics, NewNoPathDefinedError() + } + + err := md.getFsInfo(metrics) + if err != nil { + return metrics, err + } + + return metrics, nil +} + +// getFsInfo writes metrics.Capacity, metrics.Used and metrics.Available from the filesystem info +func (md *metricsStatFS) getFsInfo(metrics *Metrics) error { + available, capacity, usage, inodes, inodesFree, inodesUsed, err := fs.Info(md.path) + if err != nil { + return NewFsInfoFailedError(err) + } + metrics.Available = resource.NewQuantity(available, resource.BinarySI) + metrics.Capacity = resource.NewQuantity(capacity, resource.BinarySI) + metrics.Used = resource.NewQuantity(usage, resource.BinarySI) + metrics.Inodes = resource.NewQuantity(inodes, resource.BinarySI) + metrics.InodesFree = resource.NewQuantity(inodesFree, resource.BinarySI) + metrics.InodesUsed = resource.NewQuantity(inodesUsed, resource.BinarySI) + return nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/noop_expandable_plugin.go b/vendor/k8s.io/kubernetes/pkg/volume/noop_expandable_plugin.go new file mode 100644 index 000000000..9db19f16b --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/noop_expandable_plugin.go @@ -0,0 +1,81 @@ +/* +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 volume + +import ( + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/types" +) + +type noopExpandableVolumePluginInstance struct { + spec *Spec +} + +var _ ExpandableVolumePlugin = &noopExpandableVolumePluginInstance{} + +func (n *noopExpandableVolumePluginInstance) ExpandVolumeDevice(spec *Spec, newSize resource.Quantity, oldSize resource.Quantity) (resource.Quantity, error) { + return newSize, nil +} + +func (n *noopExpandableVolumePluginInstance) Init(host VolumeHost) error { + return nil +} + +func (n *noopExpandableVolumePluginInstance) GetPluginName() string { + return n.spec.KubeletExpandablePluginName() +} + +func (n *noopExpandableVolumePluginInstance) GetVolumeName(spec *Spec) (string, error) { + return n.spec.Name(), nil +} + +func (n *noopExpandableVolumePluginInstance) CanSupport(spec *Spec) bool { + return true +} + +func (n *noopExpandableVolumePluginInstance) RequiresRemount(spec *Spec) bool { + return false +} + +func (n *noopExpandableVolumePluginInstance) NewMounter(spec *Spec, podRef *v1.Pod, opts VolumeOptions) (Mounter, error) { + return nil, nil +} + +func (n *noopExpandableVolumePluginInstance) NewUnmounter(name string, podUID types.UID) (Unmounter, error) { + return nil, nil +} + +func (n *noopExpandableVolumePluginInstance) ConstructVolumeSpec(volumeName, mountPath string) (ReconstructedVolume, error) { + return ReconstructedVolume{Spec: n.spec}, nil +} + +func (n *noopExpandableVolumePluginInstance) SupportsMountOption() bool { + return true +} + +func (n *noopExpandableVolumePluginInstance) SupportsBulkVolumeVerification() bool { + return false +} + +func (n *noopExpandableVolumePluginInstance) RequiresFSResize() bool { + return true +} + +func (n *noopExpandableVolumePluginInstance) SupportsSELinuxContextMount(spec *Spec) (bool, error) { + return false, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/plugins.go b/vendor/k8s.io/kubernetes/pkg/volume/plugins.go new file mode 100644 index 000000000..c0ec12f0c --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/plugins.go @@ -0,0 +1,1104 @@ +/* +Copyright 2014 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 volume + +import ( + "fmt" + "net" + "strings" + "sync" + + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/klog/v2" + "k8s.io/mount-utils" + "k8s.io/utils/exec" + + authenticationv1 "k8s.io/api/authentication/v1" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apimachinery/pkg/util/validation" + "k8s.io/client-go/informers" + clientset "k8s.io/client-go/kubernetes" + storagelistersv1 "k8s.io/client-go/listers/storage/v1" + "k8s.io/client-go/tools/cache" + "k8s.io/client-go/tools/record" + cloudprovider "k8s.io/cloud-provider" + proxyutil "k8s.io/kubernetes/pkg/proxy/util" + "k8s.io/kubernetes/pkg/volume/util/hostutil" + "k8s.io/kubernetes/pkg/volume/util/recyclerclient" + "k8s.io/kubernetes/pkg/volume/util/subpath" +) + +type ProbeOperation uint32 +type ProbeEvent struct { + Plugin VolumePlugin // VolumePlugin that was added/updated/removed. if ProbeEvent.Op is 'ProbeRemove', Plugin should be nil + PluginName string + Op ProbeOperation // The operation to the plugin +} + +const ( + // Common parameter which can be specified in StorageClass to specify the desired FSType + // Provisioners SHOULD implement support for this if they are block device based + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Default value depends on the provisioner + VolumeParameterFSType = "fstype" + + ProbeAddOrUpdate ProbeOperation = 1 << iota + ProbeRemove +) + +// VolumeOptions contains option information about a volume. +type VolumeOptions struct { + // The attributes below are required by volume.Provisioner + // TODO: refactor all of this out of volumes when an admin can configure + // many kinds of provisioners. + + // Reclamation policy for a persistent volume + PersistentVolumeReclaimPolicy v1.PersistentVolumeReclaimPolicy + // Mount options for a persistent volume + MountOptions []string + // Suggested PV.Name of the PersistentVolume to provision. + // This is a generated name guaranteed to be unique in Kubernetes cluster. + // If you choose not to use it as volume name, ensure uniqueness by either + // combining it with your value or create unique values of your own. + PVName string + // PVC is reference to the claim that lead to provisioning of a new PV. + // Provisioners *must* create a PV that would be matched by this PVC, + // i.e. with required capacity, accessMode, labels matching PVC.Selector and + // so on. + PVC *v1.PersistentVolumeClaim + // Unique name of Kubernetes cluster. + ClusterName string + // Tags to attach to the real volume in the cloud provider - e.g. AWS EBS + CloudTags *map[string]string + // Volume provisioning parameters from StorageClass + Parameters map[string]string +} + +// NodeResizeOptions contain options to be passed for node expansion. +type NodeResizeOptions struct { + VolumeSpec *Spec + + // DevicePath - location of actual device on the node. In case of CSI + // this just could be volumeID + DevicePath string + + // DeviceMountPath location where device is mounted on the node. If volume type + // is attachable - this would be global mount path otherwise + // it would be location where volume was mounted for the pod + DeviceMountPath string + + // DeviceStagingPath stores location where the volume is staged + DeviceStagePath string + + NewSize resource.Quantity + OldSize resource.Quantity +} + +type DynamicPluginProber interface { + Init() error + + // aggregates events for successful drivers and errors for failed drivers + Probe() (events []ProbeEvent, err error) +} + +// VolumePlugin is an interface to volume plugins that can be used on a +// kubernetes node (e.g. by kubelet) to instantiate and manage volumes. +type VolumePlugin interface { + // Init initializes the plugin. This will be called exactly once + // before any New* calls are made - implementations of plugins may + // depend on this. + Init(host VolumeHost) error + + // Name returns the plugin's name. Plugins must use namespaced names + // such as "example.com/volume" and contain exactly one '/' character. + // The "kubernetes.io" namespace is reserved for plugins which are + // bundled with kubernetes. + GetPluginName() string + + // GetVolumeName returns the name/ID to uniquely identifying the actual + // backing device, directory, path, etc. referenced by the specified volume + // spec. + // For Attachable volumes, this value must be able to be passed back to + // volume Detach methods to identify the device to act on. + // If the plugin does not support the given spec, this returns an error. + GetVolumeName(spec *Spec) (string, error) + + // CanSupport tests whether the plugin supports a given volume + // specification from the API. The spec pointer should be considered + // const. + CanSupport(spec *Spec) bool + + // RequiresRemount returns true if this plugin requires mount calls to be + // reexecuted. Atomically updating volumes, like Downward API, depend on + // this to update the contents of the volume. + RequiresRemount(spec *Spec) bool + + // NewMounter creates a new volume.Mounter from an API specification. + // Ownership of the spec pointer in *not* transferred. + // - spec: The v1.Volume spec + // - pod: The enclosing pod + NewMounter(spec *Spec, podRef *v1.Pod, opts VolumeOptions) (Mounter, error) + + // NewUnmounter creates a new volume.Unmounter from recoverable state. + // - name: The volume name, as per the v1.Volume spec. + // - podUID: The UID of the enclosing pod + NewUnmounter(name string, podUID types.UID) (Unmounter, error) + + // ConstructVolumeSpec constructs a volume spec based on the given volume name + // and volumePath. The spec may have incomplete information due to limited + // information from input. This function is used by volume manager to reconstruct + // volume spec by reading the volume directories from disk + ConstructVolumeSpec(volumeName, volumePath string) (ReconstructedVolume, error) + + // SupportsMountOption returns true if volume plugins supports Mount options + // Specifying mount options in a volume plugin that doesn't support + // user specified mount options will result in error creating persistent volumes + SupportsMountOption() bool + + // SupportsBulkVolumeVerification checks if volume plugin type is capable + // of enabling bulk polling of all nodes. This can speed up verification of + // attached volumes by quite a bit, but underlying pluging must support it. + SupportsBulkVolumeVerification() bool + + // SupportsSELinuxContextMount returns true if volume plugins supports + // mount -o context=XYZ for a given volume. + SupportsSELinuxContextMount(spec *Spec) (bool, error) +} + +// PersistentVolumePlugin is an extended interface of VolumePlugin and is used +// by volumes that want to provide long term persistence of data +type PersistentVolumePlugin interface { + VolumePlugin + // GetAccessModes describes the ways a given volume can be accessed/mounted. + GetAccessModes() []v1.PersistentVolumeAccessMode +} + +// RecyclableVolumePlugin is an extended interface of VolumePlugin and is used +// by persistent volumes that want to be recycled before being made available +// again to new claims +type RecyclableVolumePlugin interface { + VolumePlugin + + // Recycle knows how to reclaim this + // resource after the volume's release from a PersistentVolumeClaim. + // Recycle will use the provided recorder to write any events that might be + // interesting to user. It's expected that caller will pass these events to + // the PV being recycled. + Recycle(pvName string, spec *Spec, eventRecorder recyclerclient.RecycleEventRecorder) error +} + +// DeletableVolumePlugin is an extended interface of VolumePlugin and is used +// by persistent volumes that want to be deleted from the cluster after their +// release from a PersistentVolumeClaim. +type DeletableVolumePlugin interface { + VolumePlugin + // NewDeleter creates a new volume.Deleter which knows how to delete this + // resource in accordance with the underlying storage provider after the + // volume's release from a claim + NewDeleter(spec *Spec) (Deleter, error) +} + +// ProvisionableVolumePlugin is an extended interface of VolumePlugin and is +// used to create volumes for the cluster. +type ProvisionableVolumePlugin interface { + VolumePlugin + // NewProvisioner creates a new volume.Provisioner which knows how to + // create PersistentVolumes in accordance with the plugin's underlying + // storage provider + NewProvisioner(options VolumeOptions) (Provisioner, error) +} + +// AttachableVolumePlugin is an extended interface of VolumePlugin and is used for volumes that require attachment +// to a node before mounting. +type AttachableVolumePlugin interface { + DeviceMountableVolumePlugin + NewAttacher() (Attacher, error) + NewDetacher() (Detacher, error) + // CanAttach tests if provided volume spec is attachable + CanAttach(spec *Spec) (bool, error) +} + +// DeviceMountableVolumePlugin is an extended interface of VolumePlugin and is used +// for volumes that requires mount device to a node before binding to volume to pod. +type DeviceMountableVolumePlugin interface { + VolumePlugin + NewDeviceMounter() (DeviceMounter, error) + NewDeviceUnmounter() (DeviceUnmounter, error) + GetDeviceMountRefs(deviceMountPath string) ([]string, error) + // CanDeviceMount determines if device in volume.Spec is mountable + CanDeviceMount(spec *Spec) (bool, error) +} + +// ExpandableVolumePlugin is an extended interface of VolumePlugin and is used for volumes that can be +// expanded via control-plane ExpandVolumeDevice call. +type ExpandableVolumePlugin interface { + VolumePlugin + ExpandVolumeDevice(spec *Spec, newSize resource.Quantity, oldSize resource.Quantity) (resource.Quantity, error) + RequiresFSResize() bool +} + +// NodeExpandableVolumePlugin is an expanded interface of VolumePlugin and is used for volumes that +// require expansion on the node via NodeExpand call. +type NodeExpandableVolumePlugin interface { + VolumePlugin + RequiresFSResize() bool + // NodeExpand expands volume on given deviceMountPath and returns true if resize is successful. + NodeExpand(resizeOptions NodeResizeOptions) (bool, error) +} + +// VolumePluginWithAttachLimits is an extended interface of VolumePlugin that restricts number of +// volumes that can be attached to a node. +type VolumePluginWithAttachLimits interface { + VolumePlugin + // Return maximum number of volumes that can be attached to a node for this plugin. + // The key must be same as string returned by VolumeLimitKey function. The returned + // map may look like: + // - { "storage-limits-aws-ebs": 39 } + // - { "storage-limits-gce-pd": 10 } + // A volume plugin may return error from this function - if it can not be used on a given node or not + // applicable in given environment (where environment could be cloudprovider or any other dependency) + // For example - calling this function for EBS volume plugin on a GCE node should + // result in error. + // The returned values are stored in node allocatable property and will be used + // by scheduler to determine how many pods with volumes can be scheduled on given node. + GetVolumeLimits() (map[string]int64, error) + // Return volume limit key string to be used in node capacity constraints + // The key must start with prefix storage-limits-. For example: + // - storage-limits-aws-ebs + // - storage-limits-csi-cinder + // The key should respect character limit of ResourceName type + // This function may be called by kubelet or scheduler to identify node allocatable property + // which stores volumes limits. + VolumeLimitKey(spec *Spec) string +} + +// BlockVolumePlugin is an extend interface of VolumePlugin and is used for block volumes support. +type BlockVolumePlugin interface { + VolumePlugin + // NewBlockVolumeMapper creates a new volume.BlockVolumeMapper from an API specification. + // Ownership of the spec pointer in *not* transferred. + // - spec: The v1.Volume spec + // - pod: The enclosing pod + NewBlockVolumeMapper(spec *Spec, podRef *v1.Pod, opts VolumeOptions) (BlockVolumeMapper, error) + // NewBlockVolumeUnmapper creates a new volume.BlockVolumeUnmapper from recoverable state. + // - name: The volume name, as per the v1.Volume spec. + // - podUID: The UID of the enclosing pod + NewBlockVolumeUnmapper(name string, podUID types.UID) (BlockVolumeUnmapper, error) + // ConstructBlockVolumeSpec constructs a volume spec based on the given + // podUID, volume name and a pod device map path. + // The spec may have incomplete information due to limited information + // from input. This function is used by volume manager to reconstruct + // volume spec by reading the volume directories from disk. + ConstructBlockVolumeSpec(podUID types.UID, volumeName, volumePath string) (*Spec, error) +} + +// TODO(#14217) +// As part of the Volume Host refactor we are starting to create Volume Hosts +// for specific hosts. New methods for each specific host can be added here. +// Currently consumers will do type assertions to get the specific type of Volume +// Host; however, the end result should be that specific Volume Hosts are passed +// to the specific functions they are needed in (instead of using a catch-all +// VolumeHost interface) + +// KubeletVolumeHost is a Kubelet specific interface that plugins can use to access the kubelet. +type KubeletVolumeHost interface { + // SetKubeletError lets plugins set an error on the Kubelet runtime status + // that will cause the Kubelet to post NotReady status with the error message provided + SetKubeletError(err error) + + // GetInformerFactory returns the informer factory for CSIDriverLister + GetInformerFactory() informers.SharedInformerFactory + // CSIDriverLister returns the informer lister for the CSIDriver API Object + CSIDriverLister() storagelistersv1.CSIDriverLister + // CSIDriverSynced returns the informer synced for the CSIDriver API Object + CSIDriversSynced() cache.InformerSynced + // WaitForCacheSync is a helper function that waits for cache sync for CSIDriverLister + WaitForCacheSync() error + // Returns hostutil.HostUtils + GetHostUtil() hostutil.HostUtils + // GetHostIDsForPod if the pod uses user namespaces, takes the uid and + // gid inside the container and returns the host UID and GID those are + // mapped to on the host. If containerUID/containerGID is nil, then it + // returns the host UID/GID for ID 0 inside the container. + // If the pod is not using user namespaces, as there is no mapping needed, the + // same containerUID and containerGID params are returned. + GetHostIDsForPod(pod *v1.Pod, containerUID, containerGID *int64) (hostUID, hostGID *int64, err error) +} + +// AttachDetachVolumeHost is a AttachDetach Controller specific interface that plugins can use +// to access methods on the Attach Detach Controller. +type AttachDetachVolumeHost interface { + // CSINodeLister returns the informer lister for the CSINode API Object + CSINodeLister() storagelistersv1.CSINodeLister + + // CSIDriverLister returns the informer lister for the CSIDriver API Object + CSIDriverLister() storagelistersv1.CSIDriverLister + + // VolumeAttachmentLister returns the informer lister for the VolumeAttachment API Object + VolumeAttachmentLister() storagelistersv1.VolumeAttachmentLister + // IsAttachDetachController is an interface marker to strictly tie AttachDetachVolumeHost + // to the attachDetachController + IsAttachDetachController() bool +} + +// VolumeHost is an interface that plugins can use to access the kubelet. +type VolumeHost interface { + // GetPluginDir returns the absolute path to a directory under which + // a given plugin may store data. This directory might not actually + // exist on disk yet. For plugin data that is per-pod, see + // GetPodPluginDir(). + GetPluginDir(pluginName string) string + + // GetVolumeDevicePluginDir returns the absolute path to a directory + // under which a given plugin may store data. + // ex. plugins/kubernetes.io/{PluginName}/{DefaultKubeletVolumeDevicesDirName}/{volumePluginDependentPath}/ + GetVolumeDevicePluginDir(pluginName string) string + + // GetPodsDir returns the absolute path to a directory where all the pods + // information is stored + GetPodsDir() string + + // GetPodVolumeDir returns the absolute path a directory which + // represents the named volume under the named plugin for the given + // pod. If the specified pod does not exist, the result of this call + // might not exist. + GetPodVolumeDir(podUID types.UID, pluginName string, volumeName string) string + + // GetPodPluginDir returns the absolute path to a directory under which + // a given plugin may store data for a given pod. If the specified pod + // does not exist, the result of this call might not exist. This + // directory might not actually exist on disk yet. + GetPodPluginDir(podUID types.UID, pluginName string) string + + // GetPodVolumeDeviceDir returns the absolute path a directory which + // represents the named plugin for the given pod. + // If the specified pod does not exist, the result of this call + // might not exist. + // ex. pods/{podUid}/{DefaultKubeletVolumeDevicesDirName}/{escapeQualifiedPluginName}/ + GetPodVolumeDeviceDir(podUID types.UID, pluginName string) string + + // GetKubeClient returns a client interface + GetKubeClient() clientset.Interface + + // NewWrapperMounter finds an appropriate plugin with which to handle + // the provided spec. This is used to implement volume plugins which + // "wrap" other plugins. For example, the "secret" volume is + // implemented in terms of the "emptyDir" volume. + NewWrapperMounter(volName string, spec Spec, pod *v1.Pod, opts VolumeOptions) (Mounter, error) + + // NewWrapperUnmounter finds an appropriate plugin with which to handle + // the provided spec. See comments on NewWrapperMounter for more + // context. + NewWrapperUnmounter(volName string, spec Spec, podUID types.UID) (Unmounter, error) + + // Get cloud provider from kubelet. + GetCloudProvider() cloudprovider.Interface + + // Get mounter interface. + GetMounter(pluginName string) mount.Interface + + // Returns the hostname of the host kubelet is running on + GetHostName() string + + // Returns host IP or nil in the case of error. + GetHostIP() (net.IP, error) + + // Returns node allocatable. + GetNodeAllocatable() (v1.ResourceList, error) + + // Returns a function that returns a secret. + GetSecretFunc() func(namespace, name string) (*v1.Secret, error) + + // Returns a function that returns a configmap. + GetConfigMapFunc() func(namespace, name string) (*v1.ConfigMap, error) + + GetServiceAccountTokenFunc() func(namespace, name string, tr *authenticationv1.TokenRequest) (*authenticationv1.TokenRequest, error) + + DeleteServiceAccountTokenFunc() func(podUID types.UID) + + // Returns an interface that should be used to execute any utilities in volume plugins + GetExec(pluginName string) exec.Interface + + // Returns the labels on the node + GetNodeLabels() (map[string]string, error) + + // Returns the name of the node + GetNodeName() types.NodeName + + GetAttachedVolumesFromNodeStatus() (map[v1.UniqueVolumeName]string, error) + + // Returns the event recorder of kubelet. + GetEventRecorder() record.EventRecorder + + // Returns an interface that should be used to execute subpath operations + GetSubpather() subpath.Interface + + // Returns options to pass for proxyutil filtered dialers. + GetFilteredDialOptions() *proxyutil.FilteredDialOptions +} + +// VolumePluginMgr tracks registered plugins. +type VolumePluginMgr struct { + mutex sync.RWMutex + plugins map[string]VolumePlugin + prober DynamicPluginProber + probedPlugins map[string]VolumePlugin + loggedDeprecationWarnings sets.String + Host VolumeHost +} + +// Spec is an internal representation of a volume. All API volume types translate to Spec. +type Spec struct { + Volume *v1.Volume + PersistentVolume *v1.PersistentVolume + ReadOnly bool + InlineVolumeSpecForCSIMigration bool + Migrated bool +} + +// Name returns the name of either Volume or PersistentVolume, one of which must not be nil. +func (spec *Spec) Name() string { + switch { + case spec.Volume != nil: + return spec.Volume.Name + case spec.PersistentVolume != nil: + return spec.PersistentVolume.Name + default: + return "" + } +} + +// IsKubeletExpandable returns true for volume types that can be expanded only by the node +// and not the controller. Currently Flex volume is the only one in this category since +// it is typically not installed on the controller +func (spec *Spec) IsKubeletExpandable() bool { + switch { + case spec.Volume != nil: + return spec.Volume.FlexVolume != nil + case spec.PersistentVolume != nil: + return spec.PersistentVolume.Spec.FlexVolume != nil + default: + return false + } +} + +// KubeletExpandablePluginName creates and returns a name for the plugin +// this is used in context on the controller where the plugin lookup fails +// as volume expansion on controller isn't supported, but a plugin name is +// required +func (spec *Spec) KubeletExpandablePluginName() string { + switch { + case spec.Volume != nil && spec.Volume.FlexVolume != nil: + return spec.Volume.FlexVolume.Driver + case spec.PersistentVolume != nil && spec.PersistentVolume.Spec.FlexVolume != nil: + return spec.PersistentVolume.Spec.FlexVolume.Driver + default: + return "" + } +} + +// VolumeConfig is how volume plugins receive configuration. An instance +// specific to the plugin will be passed to the plugin's +// ProbeVolumePlugins(config) func. Reasonable defaults will be provided by +// the binary hosting the plugins while allowing override of those default +// values. Those config values are then set to an instance of VolumeConfig +// and passed to the plugin. +// +// Values in VolumeConfig are intended to be relevant to several plugins, but +// not necessarily all plugins. The preference is to leverage strong typing +// in this struct. All config items must have a descriptive but non-specific +// name (i.e, RecyclerMinimumTimeout is OK but RecyclerMinimumTimeoutForNFS is +// !OK). An instance of config will be given directly to the plugin, so +// config names specific to plugins are unneeded and wrongly expose plugins in +// this VolumeConfig struct. +// +// OtherAttributes is a map of string values intended for one-off +// configuration of a plugin or config that is only relevant to a single +// plugin. All values are passed by string and require interpretation by the +// plugin. Passing config as strings is the least desirable option but can be +// used for truly one-off configuration. The binary should still use strong +// typing for this value when binding CLI values before they are passed as +// strings in OtherAttributes. +type VolumeConfig struct { + // RecyclerPodTemplate is pod template that understands how to scrub clean + // a persistent volume after its release. The template is used by plugins + // which override specific properties of the pod in accordance with that + // plugin. See NewPersistentVolumeRecyclerPodTemplate for the properties + // that are expected to be overridden. + RecyclerPodTemplate *v1.Pod + + // RecyclerMinimumTimeout is the minimum amount of time in seconds for the + // recycler pod's ActiveDeadlineSeconds attribute. Added to the minimum + // timeout is the increment per Gi of capacity. + RecyclerMinimumTimeout int + + // RecyclerTimeoutIncrement is the number of seconds added to the recycler + // pod's ActiveDeadlineSeconds for each Gi of capacity in the persistent + // volume. Example: 5Gi volume x 30s increment = 150s + 30s minimum = 180s + // ActiveDeadlineSeconds for recycler pod + RecyclerTimeoutIncrement int + + // PVName is name of the PersistentVolume instance that is being recycled. + // It is used to generate unique recycler pod name. + PVName string + + // OtherAttributes stores config as strings. These strings are opaque to + // the system and only understood by the binary hosting the plugin and the + // plugin itself. + OtherAttributes map[string]string + + // ProvisioningEnabled configures whether provisioning of this plugin is + // enabled or not. Currently used only in host_path plugin. + ProvisioningEnabled bool +} + +// ReconstructedVolume contains information about a volume reconstructed by +// ConstructVolumeSpec(). +type ReconstructedVolume struct { + // Spec is the volume spec of a mounted volume + Spec *Spec + // SELinuxMountContext is value of -o context=XYZ mount option. + // If empty, no such mount option is used. + SELinuxMountContext string +} + +// NewSpecFromVolume creates an Spec from an v1.Volume +func NewSpecFromVolume(vs *v1.Volume) *Spec { + return &Spec{ + Volume: vs, + } +} + +// NewSpecFromPersistentVolume creates an Spec from an v1.PersistentVolume +func NewSpecFromPersistentVolume(pv *v1.PersistentVolume, readOnly bool) *Spec { + return &Spec{ + PersistentVolume: pv, + ReadOnly: readOnly, + } +} + +// InitPlugins initializes each plugin. All plugins must have unique names. +// This must be called exactly once before any New* methods are called on any +// plugins. +func (pm *VolumePluginMgr) InitPlugins(plugins []VolumePlugin, prober DynamicPluginProber, host VolumeHost) error { + pm.mutex.Lock() + defer pm.mutex.Unlock() + + pm.Host = host + pm.loggedDeprecationWarnings = sets.NewString() + + if prober == nil { + // Use a dummy prober to prevent nil deference. + pm.prober = &dummyPluginProber{} + } else { + pm.prober = prober + } + if err := pm.prober.Init(); err != nil { + // Prober init failure should not affect the initialization of other plugins. + klog.ErrorS(err, "Error initializing dynamic plugin prober") + pm.prober = &dummyPluginProber{} + } + + if pm.plugins == nil { + pm.plugins = map[string]VolumePlugin{} + } + if pm.probedPlugins == nil { + pm.probedPlugins = map[string]VolumePlugin{} + } + + allErrs := []error{} + for _, plugin := range plugins { + name := plugin.GetPluginName() + if errs := validation.IsQualifiedName(name); len(errs) != 0 { + allErrs = append(allErrs, fmt.Errorf("volume plugin has invalid name: %q: %s", name, strings.Join(errs, ";"))) + continue + } + + if _, found := pm.plugins[name]; found { + allErrs = append(allErrs, fmt.Errorf("volume plugin %q was registered more than once", name)) + continue + } + err := plugin.Init(host) + if err != nil { + klog.ErrorS(err, "Failed to load volume plugin", "pluginName", name) + allErrs = append(allErrs, err) + continue + } + pm.plugins[name] = plugin + klog.V(1).InfoS("Loaded volume plugin", "pluginName", name) + } + return utilerrors.NewAggregate(allErrs) +} + +func (pm *VolumePluginMgr) initProbedPlugin(probedPlugin VolumePlugin) error { + name := probedPlugin.GetPluginName() + if errs := validation.IsQualifiedName(name); len(errs) != 0 { + return fmt.Errorf("volume plugin has invalid name: %q: %s", name, strings.Join(errs, ";")) + } + + err := probedPlugin.Init(pm.Host) + if err != nil { + return fmt.Errorf("failed to load volume plugin %s, error: %s", name, err.Error()) + } + + klog.V(1).InfoS("Loaded volume plugin", "pluginName", name) + return nil +} + +// FindPluginBySpec looks for a plugin that can support a given volume +// specification. If no plugins can support or more than one plugin can +// support it, return error. +func (pm *VolumePluginMgr) FindPluginBySpec(spec *Spec) (VolumePlugin, error) { + pm.mutex.RLock() + defer pm.mutex.RUnlock() + + if spec == nil { + return nil, fmt.Errorf("could not find plugin because volume spec is nil") + } + + var match VolumePlugin + matchedPluginNames := []string{} + for _, v := range pm.plugins { + if v.CanSupport(spec) { + match = v + matchedPluginNames = append(matchedPluginNames, v.GetPluginName()) + } + } + + pm.refreshProbedPlugins() + for _, plugin := range pm.probedPlugins { + if plugin.CanSupport(spec) { + match = plugin + matchedPluginNames = append(matchedPluginNames, plugin.GetPluginName()) + } + } + + if len(matchedPluginNames) == 0 { + return nil, fmt.Errorf("no volume plugin matched") + } + if len(matchedPluginNames) > 1 { + return nil, fmt.Errorf("multiple volume plugins matched: %s", strings.Join(matchedPluginNames, ",")) + } + + return match, nil +} + +// FindPluginByName fetches a plugin by name or by legacy name. If no plugin +// is found, returns error. +func (pm *VolumePluginMgr) FindPluginByName(name string) (VolumePlugin, error) { + pm.mutex.RLock() + defer pm.mutex.RUnlock() + + // Once we can get rid of legacy names we can reduce this to a map lookup. + var match VolumePlugin + if v, found := pm.plugins[name]; found { + match = v + } + + pm.refreshProbedPlugins() + if plugin, found := pm.probedPlugins[name]; found { + if match != nil { + return nil, fmt.Errorf("multiple volume plugins matched: %s and %s", match.GetPluginName(), plugin.GetPluginName()) + } + match = plugin + } + + if match == nil { + return nil, fmt.Errorf("no volume plugin matched name: %s", name) + } + return match, nil +} + +// Check if probedPlugin cache update is required. +// If it is, initialize all probed plugins and replace the cache with them. +func (pm *VolumePluginMgr) refreshProbedPlugins() { + events, err := pm.prober.Probe() + + if err != nil { + klog.ErrorS(err, "Error dynamically probing plugins") + } + + // because the probe function can return a list of valid plugins + // even when an error is present we still must add the plugins + // or they will be skipped because each event only fires once + for _, event := range events { + if event.Op == ProbeAddOrUpdate { + if err := pm.initProbedPlugin(event.Plugin); err != nil { + klog.ErrorS(err, "Error initializing dynamically probed plugin", + "pluginName", event.Plugin.GetPluginName()) + continue + } + pm.probedPlugins[event.Plugin.GetPluginName()] = event.Plugin + } else if event.Op == ProbeRemove { + // Plugin is not available on ProbeRemove event, only PluginName + delete(pm.probedPlugins, event.PluginName) + } else { + klog.ErrorS(nil, "Unknown Operation on PluginName.", + "pluginName", event.Plugin.GetPluginName()) + } + } +} + +// ListVolumePluginWithLimits returns plugins that have volume limits on nodes +func (pm *VolumePluginMgr) ListVolumePluginWithLimits() []VolumePluginWithAttachLimits { + pm.mutex.RLock() + defer pm.mutex.RUnlock() + + matchedPlugins := []VolumePluginWithAttachLimits{} + for _, v := range pm.plugins { + if plugin, ok := v.(VolumePluginWithAttachLimits); ok { + matchedPlugins = append(matchedPlugins, plugin) + } + } + return matchedPlugins +} + +// FindPersistentPluginBySpec looks for a persistent volume plugin that can +// support a given volume specification. If no plugin is found, return an +// error +func (pm *VolumePluginMgr) FindPersistentPluginBySpec(spec *Spec) (PersistentVolumePlugin, error) { + volumePlugin, err := pm.FindPluginBySpec(spec) + if err != nil { + return nil, fmt.Errorf("could not find volume plugin for spec: %#v", spec) + } + if persistentVolumePlugin, ok := volumePlugin.(PersistentVolumePlugin); ok { + return persistentVolumePlugin, nil + } + return nil, fmt.Errorf("no persistent volume plugin matched") +} + +// FindVolumePluginWithLimitsBySpec returns volume plugin that has a limit on how many +// of them can be attached to a node +func (pm *VolumePluginMgr) FindVolumePluginWithLimitsBySpec(spec *Spec) (VolumePluginWithAttachLimits, error) { + volumePlugin, err := pm.FindPluginBySpec(spec) + if err != nil { + return nil, fmt.Errorf("could not find volume plugin for spec : %#v", spec) + } + + if limitedPlugin, ok := volumePlugin.(VolumePluginWithAttachLimits); ok { + return limitedPlugin, nil + } + return nil, fmt.Errorf("no plugin with limits found") +} + +// FindPersistentPluginByName fetches a persistent volume plugin by name. If +// no plugin is found, returns error. +func (pm *VolumePluginMgr) FindPersistentPluginByName(name string) (PersistentVolumePlugin, error) { + volumePlugin, err := pm.FindPluginByName(name) + if err != nil { + return nil, err + } + if persistentVolumePlugin, ok := volumePlugin.(PersistentVolumePlugin); ok { + return persistentVolumePlugin, nil + } + return nil, fmt.Errorf("no persistent volume plugin matched") +} + +// FindRecyclablePluginByName fetches a persistent volume plugin by name. If +// no plugin is found, returns error. +func (pm *VolumePluginMgr) FindRecyclablePluginBySpec(spec *Spec) (RecyclableVolumePlugin, error) { + volumePlugin, err := pm.FindPluginBySpec(spec) + if err != nil { + return nil, err + } + if recyclableVolumePlugin, ok := volumePlugin.(RecyclableVolumePlugin); ok { + return recyclableVolumePlugin, nil + } + return nil, fmt.Errorf("no recyclable volume plugin matched") +} + +// FindProvisionablePluginByName fetches a persistent volume plugin by name. If +// no plugin is found, returns error. +func (pm *VolumePluginMgr) FindProvisionablePluginByName(name string) (ProvisionableVolumePlugin, error) { + volumePlugin, err := pm.FindPluginByName(name) + if err != nil { + return nil, err + } + if provisionableVolumePlugin, ok := volumePlugin.(ProvisionableVolumePlugin); ok { + return provisionableVolumePlugin, nil + } + return nil, fmt.Errorf("no provisionable volume plugin matched") +} + +// FindDeletablePluginBySpec fetches a persistent volume plugin by spec. If +// no plugin is found, returns error. +func (pm *VolumePluginMgr) FindDeletablePluginBySpec(spec *Spec) (DeletableVolumePlugin, error) { + volumePlugin, err := pm.FindPluginBySpec(spec) + if err != nil { + return nil, err + } + if deletableVolumePlugin, ok := volumePlugin.(DeletableVolumePlugin); ok { + return deletableVolumePlugin, nil + } + return nil, fmt.Errorf("no deletable volume plugin matched") +} + +// FindDeletablePluginByName fetches a persistent volume plugin by name. If +// no plugin is found, returns error. +func (pm *VolumePluginMgr) FindDeletablePluginByName(name string) (DeletableVolumePlugin, error) { + volumePlugin, err := pm.FindPluginByName(name) + if err != nil { + return nil, err + } + if deletableVolumePlugin, ok := volumePlugin.(DeletableVolumePlugin); ok { + return deletableVolumePlugin, nil + } + return nil, fmt.Errorf("no deletable volume plugin matched") +} + +// FindCreatablePluginBySpec fetches a persistent volume plugin by name. If +// no plugin is found, returns error. +func (pm *VolumePluginMgr) FindCreatablePluginBySpec(spec *Spec) (ProvisionableVolumePlugin, error) { + volumePlugin, err := pm.FindPluginBySpec(spec) + if err != nil { + return nil, err + } + if provisionableVolumePlugin, ok := volumePlugin.(ProvisionableVolumePlugin); ok { + return provisionableVolumePlugin, nil + } + return nil, fmt.Errorf("no creatable volume plugin matched") +} + +// FindAttachablePluginBySpec fetches a persistent volume plugin by spec. +// Unlike the other "FindPlugin" methods, this does not return error if no +// plugin is found. All volumes require a mounter and unmounter, but not +// every volume will have an attacher/detacher. +func (pm *VolumePluginMgr) FindAttachablePluginBySpec(spec *Spec) (AttachableVolumePlugin, error) { + volumePlugin, err := pm.FindPluginBySpec(spec) + if err != nil { + return nil, err + } + if attachableVolumePlugin, ok := volumePlugin.(AttachableVolumePlugin); ok { + if canAttach, err := attachableVolumePlugin.CanAttach(spec); err != nil { + return nil, err + } else if canAttach { + return attachableVolumePlugin, nil + } + } + return nil, nil +} + +// FindAttachablePluginByName fetches an attachable volume plugin by name. +// Unlike the other "FindPlugin" methods, this does not return error if no +// plugin is found. All volumes require a mounter and unmounter, but not +// every volume will have an attacher/detacher. +func (pm *VolumePluginMgr) FindAttachablePluginByName(name string) (AttachableVolumePlugin, error) { + volumePlugin, err := pm.FindPluginByName(name) + if err != nil { + return nil, err + } + if attachablePlugin, ok := volumePlugin.(AttachableVolumePlugin); ok { + return attachablePlugin, nil + } + return nil, nil +} + +// FindDeviceMountablePluginBySpec fetches a persistent volume plugin by spec. +func (pm *VolumePluginMgr) FindDeviceMountablePluginBySpec(spec *Spec) (DeviceMountableVolumePlugin, error) { + volumePlugin, err := pm.FindPluginBySpec(spec) + if err != nil { + return nil, err + } + if deviceMountableVolumePlugin, ok := volumePlugin.(DeviceMountableVolumePlugin); ok { + if canMount, err := deviceMountableVolumePlugin.CanDeviceMount(spec); err != nil { + return nil, err + } else if canMount { + return deviceMountableVolumePlugin, nil + } + } + return nil, nil +} + +// FindDeviceMountablePluginByName fetches a devicemountable volume plugin by name. +func (pm *VolumePluginMgr) FindDeviceMountablePluginByName(name string) (DeviceMountableVolumePlugin, error) { + volumePlugin, err := pm.FindPluginByName(name) + if err != nil { + return nil, err + } + if deviceMountableVolumePlugin, ok := volumePlugin.(DeviceMountableVolumePlugin); ok { + return deviceMountableVolumePlugin, nil + } + return nil, nil +} + +// FindExpandablePluginBySpec fetches a persistent volume plugin by spec. +func (pm *VolumePluginMgr) FindExpandablePluginBySpec(spec *Spec) (ExpandableVolumePlugin, error) { + volumePlugin, err := pm.FindPluginBySpec(spec) + if err != nil { + if spec.IsKubeletExpandable() { + // for kubelet expandable volumes, return a noop plugin that + // returns success for expand on the controller + klog.V(4).InfoS("FindExpandablePluginBySpec -> returning noopExpandableVolumePluginInstance", "specName", spec.Name()) + return &noopExpandableVolumePluginInstance{spec}, nil + } + klog.V(4).InfoS("FindExpandablePluginBySpec -> err", "specName", spec.Name(), "err", err) + return nil, err + } + + if expandableVolumePlugin, ok := volumePlugin.(ExpandableVolumePlugin); ok { + return expandableVolumePlugin, nil + } + return nil, nil +} + +// FindExpandablePluginBySpec fetches a persistent volume plugin by name. +func (pm *VolumePluginMgr) FindExpandablePluginByName(name string) (ExpandableVolumePlugin, error) { + volumePlugin, err := pm.FindPluginByName(name) + if err != nil { + return nil, err + } + + if expandableVolumePlugin, ok := volumePlugin.(ExpandableVolumePlugin); ok { + return expandableVolumePlugin, nil + } + return nil, nil +} + +// FindMapperPluginBySpec fetches a block volume plugin by spec. +func (pm *VolumePluginMgr) FindMapperPluginBySpec(spec *Spec) (BlockVolumePlugin, error) { + volumePlugin, err := pm.FindPluginBySpec(spec) + if err != nil { + return nil, err + } + + if blockVolumePlugin, ok := volumePlugin.(BlockVolumePlugin); ok { + return blockVolumePlugin, nil + } + return nil, nil +} + +// FindMapperPluginByName fetches a block volume plugin by name. +func (pm *VolumePluginMgr) FindMapperPluginByName(name string) (BlockVolumePlugin, error) { + volumePlugin, err := pm.FindPluginByName(name) + if err != nil { + return nil, err + } + + if blockVolumePlugin, ok := volumePlugin.(BlockVolumePlugin); ok { + return blockVolumePlugin, nil + } + return nil, nil +} + +// FindNodeExpandablePluginBySpec fetches a persistent volume plugin by spec +func (pm *VolumePluginMgr) FindNodeExpandablePluginBySpec(spec *Spec) (NodeExpandableVolumePlugin, error) { + volumePlugin, err := pm.FindPluginBySpec(spec) + if err != nil { + return nil, err + } + if fsResizablePlugin, ok := volumePlugin.(NodeExpandableVolumePlugin); ok { + return fsResizablePlugin, nil + } + return nil, nil +} + +// FindNodeExpandablePluginByName fetches a persistent volume plugin by name +func (pm *VolumePluginMgr) FindNodeExpandablePluginByName(name string) (NodeExpandableVolumePlugin, error) { + volumePlugin, err := pm.FindPluginByName(name) + if err != nil { + return nil, err + } + + if fsResizablePlugin, ok := volumePlugin.(NodeExpandableVolumePlugin); ok { + return fsResizablePlugin, nil + } + + return nil, nil +} + +func (pm *VolumePluginMgr) Run(stopCh <-chan struct{}) { + kletHost, ok := pm.Host.(KubeletVolumeHost) + if ok { + // start informer for CSIDriver + informerFactory := kletHost.GetInformerFactory() + informerFactory.Start(stopCh) + informerFactory.WaitForCacheSync(stopCh) + } +} + +// NewPersistentVolumeRecyclerPodTemplate creates a template for a recycler +// pod. By default, a recycler pod simply runs "rm -rf" on a volume and tests +// for emptiness. Most attributes of the template will be correct for most +// plugin implementations. The following attributes can be overridden per +// plugin via configuration: +// +// 1. pod.Spec.Volumes[0].VolumeSource must be overridden. Recycler +// implementations without a valid VolumeSource will fail. +// 2. pod.GenerateName helps distinguish recycler pods by name. Recommended. +// Default is "pv-recycler-". +// 3. pod.Spec.ActiveDeadlineSeconds gives the recycler pod a maximum timeout +// before failing. Recommended. Default is 60 seconds. +// +// See HostPath and NFS for working recycler examples +func NewPersistentVolumeRecyclerPodTemplate() *v1.Pod { + timeout := int64(60) + pod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "pv-recycler-", + Namespace: metav1.NamespaceDefault, + }, + Spec: v1.PodSpec{ + ActiveDeadlineSeconds: &timeout, + RestartPolicy: v1.RestartPolicyNever, + Volumes: []v1.Volume{ + { + Name: "vol", + // IMPORTANT! All plugins using this template MUST + // override pod.Spec.Volumes[0].VolumeSource Recycler + // implementations without a valid VolumeSource will fail. + VolumeSource: v1.VolumeSource{}, + }, + }, + Containers: []v1.Container{ + { + Name: "pv-recycler", + Image: "registry.k8s.io/debian-base:v2.0.0", + Command: []string{"/bin/sh"}, + Args: []string{"-c", "test -e /scrub && rm -rf /scrub/..?* /scrub/.[!.]* /scrub/* && test -z \"$(ls -A /scrub)\" || exit 1"}, + VolumeMounts: []v1.VolumeMount{ + { + Name: "vol", + MountPath: "/scrub", + }, + }, + }, + }, + }, + } + return pod +} + +// Check validity of recycle pod template +// List of checks: +// - at least one volume is defined in the recycle pod template +// If successful, returns nil +// if unsuccessful, returns an error. +func ValidateRecyclerPodTemplate(pod *v1.Pod) error { + if len(pod.Spec.Volumes) < 1 { + return fmt.Errorf("does not contain any volume(s)") + } + return nil +} + +type dummyPluginProber struct{} + +func (*dummyPluginProber) Init() error { return nil } +func (*dummyPluginProber) Probe() ([]ProbeEvent, error) { return nil, nil } diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/atomic_writer.go b/vendor/k8s.io/kubernetes/pkg/volume/util/atomic_writer.go new file mode 100644 index 000000000..94428f6ff --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/atomic_writer.go @@ -0,0 +1,468 @@ +/* +Copyright 2016 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 util + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "path" + "path/filepath" + "runtime" + "strings" + "time" + + "k8s.io/klog/v2" + + "k8s.io/apimachinery/pkg/util/sets" +) + +const ( + maxFileNameLength = 255 + maxPathLength = 4096 +) + +// AtomicWriter handles atomically projecting content for a set of files into +// a target directory. +// +// Note: +// +// 1. AtomicWriter reserves the set of pathnames starting with `..`. +// 2. AtomicWriter offers no concurrency guarantees and must be synchronized +// by the caller. +// +// The visible files in this volume are symlinks to files in the writer's data +// directory. Actual files are stored in a hidden timestamped directory which +// is symlinked to by the data directory. The timestamped directory and +// data directory symlink are created in the writer's target dir.  This scheme +// allows the files to be atomically updated by changing the target of the +// data directory symlink. +// +// Consumers of the target directory can monitor the ..data symlink using +// inotify or fanotify to receive events when the content in the volume is +// updated. +type AtomicWriter struct { + targetDir string + logContext string +} + +// FileProjection contains file Data and access Mode +type FileProjection struct { + Data []byte + Mode int32 + FsUser *int64 +} + +// NewAtomicWriter creates a new AtomicWriter configured to write to the given +// target directory, or returns an error if the target directory does not exist. +func NewAtomicWriter(targetDir string, logContext string) (*AtomicWriter, error) { + _, err := os.Stat(targetDir) + if os.IsNotExist(err) { + return nil, err + } + + return &AtomicWriter{targetDir: targetDir, logContext: logContext}, nil +} + +const ( + dataDirName = "..data" + newDataDirName = "..data_tmp" +) + +// Write does an atomic projection of the given payload into the writer's target +// directory. Input paths must not begin with '..'. +// +// The Write algorithm is: +// +// 1. The payload is validated; if the payload is invalid, the function returns +// 2.  The current timestamped directory is detected by reading the data directory +// symlink +// +// 3. The old version of the volume is walked to determine whether any +// portion of the payload was deleted and is still present on disk. +// +// 4. The data in the current timestamped directory is compared to the projected +// data to determine if an update is required. +// 5.  A new timestamped dir is created +// +// 6. The payload is written to the new timestamped directory +// 7.  A symlink to the new timestamped directory ..data_tmp is created that will +// become the new data directory +// 8.  The new data directory symlink is renamed to the data directory; rename is atomic +// 9.  Symlinks and directory for new user-visible files are created (if needed). +// +// For example, consider the files: +// /podName +// /user/labels +// /k8s/annotations +// +// The user visible files are symbolic links into the internal data directory: +// /podName -> ..data/podName +// /usr -> ..data/usr +// /k8s -> ..data/k8s +// +// The data directory itself is a link to a timestamped directory with +// the real data: +// /..data -> ..2016_02_01_15_04_05.12345678/ +// NOTE(claudiub): We need to create these symlinks AFTER we've finished creating and +// linking everything else. On Windows, if a target does not exist, the created symlink +// will not work properly if the target ends up being a directory. +// +// 10. Old paths are removed from the user-visible portion of the target directory +// 11.  The previous timestamped directory is removed, if it exists +func (w *AtomicWriter) Write(payload map[string]FileProjection) error { + // (1) + cleanPayload, err := validatePayload(payload) + if err != nil { + klog.Errorf("%s: invalid payload: %v", w.logContext, err) + return err + } + + // (2) + dataDirPath := filepath.Join(w.targetDir, dataDirName) + oldTsDir, err := os.Readlink(dataDirPath) + if err != nil { + if !os.IsNotExist(err) { + klog.Errorf("%s: error reading link for data directory: %v", w.logContext, err) + return err + } + // although Readlink() returns "" on err, don't be fragile by relying on it (since it's not specified in docs) + // empty oldTsDir indicates that it didn't exist + oldTsDir = "" + } + oldTsPath := filepath.Join(w.targetDir, oldTsDir) + + var pathsToRemove sets.String + // if there was no old version, there's nothing to remove + if len(oldTsDir) != 0 { + // (3) + pathsToRemove, err = w.pathsToRemove(cleanPayload, oldTsPath) + if err != nil { + klog.Errorf("%s: error determining user-visible files to remove: %v", w.logContext, err) + return err + } + + // (4) + if should, err := shouldWritePayload(cleanPayload, oldTsPath); err != nil { + klog.Errorf("%s: error determining whether payload should be written to disk: %v", w.logContext, err) + return err + } else if !should && len(pathsToRemove) == 0 { + klog.V(4).Infof("%s: no update required for target directory %v", w.logContext, w.targetDir) + return nil + } else { + klog.V(4).Infof("%s: write required for target directory %v", w.logContext, w.targetDir) + } + } + + // (5) + tsDir, err := w.newTimestampDir() + if err != nil { + klog.V(4).Infof("%s: error creating new ts data directory: %v", w.logContext, err) + return err + } + tsDirName := filepath.Base(tsDir) + + // (6) + if err = w.writePayloadToDir(cleanPayload, tsDir); err != nil { + klog.Errorf("%s: error writing payload to ts data directory %s: %v", w.logContext, tsDir, err) + return err + } + klog.V(4).Infof("%s: performed write of new data to ts data directory: %s", w.logContext, tsDir) + + // (7) + newDataDirPath := filepath.Join(w.targetDir, newDataDirName) + if err = os.Symlink(tsDirName, newDataDirPath); err != nil { + os.RemoveAll(tsDir) + klog.Errorf("%s: error creating symbolic link for atomic update: %v", w.logContext, err) + return err + } + + // (8) + if runtime.GOOS == "windows" { + os.Remove(dataDirPath) + err = os.Symlink(tsDirName, dataDirPath) + os.Remove(newDataDirPath) + } else { + err = os.Rename(newDataDirPath, dataDirPath) + } + if err != nil { + os.Remove(newDataDirPath) + os.RemoveAll(tsDir) + klog.Errorf("%s: error renaming symbolic link for data directory %s: %v", w.logContext, newDataDirPath, err) + return err + } + + // (9) + if err = w.createUserVisibleFiles(cleanPayload); err != nil { + klog.Errorf("%s: error creating visible symlinks in %s: %v", w.logContext, w.targetDir, err) + return err + } + + // (10) + if err = w.removeUserVisiblePaths(pathsToRemove); err != nil { + klog.Errorf("%s: error removing old visible symlinks: %v", w.logContext, err) + return err + } + + // (11) + if len(oldTsDir) > 0 { + if err = os.RemoveAll(oldTsPath); err != nil { + klog.Errorf("%s: error removing old data directory %s: %v", w.logContext, oldTsDir, err) + return err + } + } + + return nil +} + +// validatePayload returns an error if any path in the payload returns a copy of the payload with the paths cleaned. +func validatePayload(payload map[string]FileProjection) (map[string]FileProjection, error) { + cleanPayload := make(map[string]FileProjection) + for k, content := range payload { + if err := validatePath(k); err != nil { + return nil, err + } + + cleanPayload[filepath.Clean(k)] = content + } + + return cleanPayload, nil +} + +// validatePath validates a single path, returning an error if the path is +// invalid. paths may not: +// +// 1. be absolute +// 2. contain '..' as an element +// 3. start with '..' +// 4. contain filenames larger than 255 characters +// 5. be longer than 4096 characters +func validatePath(targetPath string) error { + // TODO: somehow unify this with the similar api validation, + // validateVolumeSourcePath; the error semantics are just different enough + // from this that it was time-prohibitive trying to find the right + // refactoring to re-use. + if targetPath == "" { + return fmt.Errorf("invalid path: must not be empty: %q", targetPath) + } + if path.IsAbs(targetPath) { + return fmt.Errorf("invalid path: must be relative path: %s", targetPath) + } + + if len(targetPath) > maxPathLength { + return fmt.Errorf("invalid path: must be less than or equal to %d characters", maxPathLength) + } + + items := strings.Split(targetPath, string(os.PathSeparator)) + for _, item := range items { + if item == ".." { + return fmt.Errorf("invalid path: must not contain '..': %s", targetPath) + } + if len(item) > maxFileNameLength { + return fmt.Errorf("invalid path: filenames must be less than or equal to %d characters", maxFileNameLength) + } + } + if strings.HasPrefix(items[0], "..") && len(items[0]) > 2 { + return fmt.Errorf("invalid path: must not start with '..': %s", targetPath) + } + + return nil +} + +// shouldWritePayload returns whether the payload should be written to disk. +func shouldWritePayload(payload map[string]FileProjection, oldTsDir string) (bool, error) { + for userVisiblePath, fileProjection := range payload { + shouldWrite, err := shouldWriteFile(filepath.Join(oldTsDir, userVisiblePath), fileProjection.Data) + if err != nil { + return false, err + } + + if shouldWrite { + return true, nil + } + } + + return false, nil +} + +// shouldWriteFile returns whether a new version of a file should be written to disk. +func shouldWriteFile(path string, content []byte) (bool, error) { + _, err := os.Lstat(path) + if os.IsNotExist(err) { + return true, nil + } + + contentOnFs, err := ioutil.ReadFile(path) + if err != nil { + return false, err + } + + return !bytes.Equal(content, contentOnFs), nil +} + +// pathsToRemove walks the current version of the data directory and +// determines which paths should be removed (if any) after the payload is +// written to the target directory. +func (w *AtomicWriter) pathsToRemove(payload map[string]FileProjection, oldTsDir string) (sets.String, error) { + paths := sets.NewString() + visitor := func(path string, info os.FileInfo, err error) error { + relativePath := strings.TrimPrefix(path, oldTsDir) + relativePath = strings.TrimPrefix(relativePath, string(os.PathSeparator)) + if relativePath == "" { + return nil + } + + paths.Insert(relativePath) + return nil + } + + err := filepath.Walk(oldTsDir, visitor) + if os.IsNotExist(err) { + return nil, nil + } else if err != nil { + return nil, err + } + klog.V(5).Infof("%s: current paths: %+v", w.targetDir, paths.List()) + + newPaths := sets.NewString() + for file := range payload { + // add all subpaths for the payload to the set of new paths + // to avoid attempting to remove non-empty dirs + for subPath := file; subPath != ""; { + newPaths.Insert(subPath) + subPath, _ = filepath.Split(subPath) + subPath = strings.TrimSuffix(subPath, string(os.PathSeparator)) + } + } + klog.V(5).Infof("%s: new paths: %+v", w.targetDir, newPaths.List()) + + result := paths.Difference(newPaths) + klog.V(5).Infof("%s: paths to remove: %+v", w.targetDir, result) + + return result, nil +} + +// newTimestampDir creates a new timestamp directory +func (w *AtomicWriter) newTimestampDir() (string, error) { + tsDir, err := ioutil.TempDir(w.targetDir, time.Now().UTC().Format("..2006_01_02_15_04_05.")) + if err != nil { + klog.Errorf("%s: unable to create new temp directory: %v", w.logContext, err) + return "", err + } + + // 0755 permissions are needed to allow 'group' and 'other' to recurse the + // directory tree. do a chmod here to ensure that permissions are set correctly + // regardless of the process' umask. + err = os.Chmod(tsDir, 0755) + if err != nil { + klog.Errorf("%s: unable to set mode on new temp directory: %v", w.logContext, err) + return "", err + } + + return tsDir, nil +} + +// writePayloadToDir writes the given payload to the given directory. The +// directory must exist. +func (w *AtomicWriter) writePayloadToDir(payload map[string]FileProjection, dir string) error { + for userVisiblePath, fileProjection := range payload { + content := fileProjection.Data + mode := os.FileMode(fileProjection.Mode) + fullPath := filepath.Join(dir, userVisiblePath) + baseDir, _ := filepath.Split(fullPath) + + if err := os.MkdirAll(baseDir, os.ModePerm); err != nil { + klog.Errorf("%s: unable to create directory %s: %v", w.logContext, baseDir, err) + return err + } + + if err := ioutil.WriteFile(fullPath, content, mode); err != nil { + klog.Errorf("%s: unable to write file %s with mode %v: %v", w.logContext, fullPath, mode, err) + return err + } + // Chmod is needed because ioutil.WriteFile() ends up calling + // open(2) to create the file, so the final mode used is "mode & + // ~umask". But we want to make sure the specified mode is used + // in the file no matter what the umask is. + if err := os.Chmod(fullPath, mode); err != nil { + klog.Errorf("%s: unable to change file %s with mode %v: %v", w.logContext, fullPath, mode, err) + return err + } + + if fileProjection.FsUser == nil { + continue + } + if err := os.Chown(fullPath, int(*fileProjection.FsUser), -1); err != nil { + klog.Errorf("%s: unable to change file %s with owner %v: %v", w.logContext, fullPath, int(*fileProjection.FsUser), err) + return err + } + } + + return nil +} + +// createUserVisibleFiles creates the relative symlinks for all the +// files configured in the payload. If the directory in a file path does not +// exist, it is created. +// +// Viz: +// For files: "bar", "foo/bar", "baz/bar", "foo/baz/blah" +// the following symlinks are created: +// bar -> ..data/bar +// foo -> ..data/foo +// baz -> ..data/baz +func (w *AtomicWriter) createUserVisibleFiles(payload map[string]FileProjection) error { + for userVisiblePath := range payload { + slashpos := strings.Index(userVisiblePath, string(os.PathSeparator)) + if slashpos == -1 { + slashpos = len(userVisiblePath) + } + linkname := userVisiblePath[:slashpos] + _, err := os.Readlink(filepath.Join(w.targetDir, linkname)) + if err != nil && os.IsNotExist(err) { + // The link into the data directory for this path doesn't exist; create it + visibleFile := filepath.Join(w.targetDir, linkname) + dataDirFile := filepath.Join(dataDirName, linkname) + + err = os.Symlink(dataDirFile, visibleFile) + if err != nil { + return err + } + } + } + return nil +} + +// removeUserVisiblePaths removes the set of paths from the user-visible +// portion of the writer's target directory. +func (w *AtomicWriter) removeUserVisiblePaths(paths sets.String) error { + ps := string(os.PathSeparator) + var lasterr error + for p := range paths { + // only remove symlinks from the volume root directory (i.e. items that don't contain '/') + if strings.Contains(p, ps) { + continue + } + if err := os.Remove(filepath.Join(w.targetDir, p)); err != nil { + klog.Errorf("%s: error pruning old user-visible path %s: %v", w.logContext, p, err) + lasterr = err + } + } + + return lasterr +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/attach_limit.go b/vendor/k8s.io/kubernetes/pkg/volume/util/attach_limit.go new file mode 100644 index 000000000..943357b65 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/attach_limit.go @@ -0,0 +1,70 @@ +/* +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 util + +import ( + "crypto/sha1" + "encoding/hex" +) + +// This file is a common place holder for volume limit utility constants +// shared between volume package and scheduler + +const ( + // EBSVolumeLimitKey resource name that will store volume limits for EBS + EBSVolumeLimitKey = "attachable-volumes-aws-ebs" + // EBSNitroLimitRegex finds nitro instance types with different limit than EBS defaults + EBSNitroLimitRegex = "^[cmr]5.*|t3|z1d" + // DefaultMaxEBSVolumes is the limit for volumes attached to an instance. + // Amazon recommends no more than 40; the system root volume uses at least one. + // See http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/volume_limits.html#linux-specific-volume-limits + DefaultMaxEBSVolumes = 39 + // DefaultMaxEBSNitroVolumeLimit is default EBS volume limit on m5 and c5 instances + DefaultMaxEBSNitroVolumeLimit = 25 + // AzureVolumeLimitKey stores resource name that will store volume limits for Azure + AzureVolumeLimitKey = "attachable-volumes-azure-disk" + // GCEVolumeLimitKey stores resource name that will store volume limits for GCE node + GCEVolumeLimitKey = "attachable-volumes-gce-pd" + + // CinderVolumeLimitKey contains Volume limit key for Cinder + CinderVolumeLimitKey = "attachable-volumes-cinder" + // DefaultMaxCinderVolumes defines the maximum number of PD Volumes for Cinder + // For Openstack we are keeping this to a high enough value so as depending on backend + // cluster admins can configure it. + DefaultMaxCinderVolumes = 256 + + // CSIAttachLimitPrefix defines prefix used for CSI volumes + CSIAttachLimitPrefix = "attachable-volumes-csi-" + + // ResourceNameLengthLimit stores maximum allowed Length for a ResourceName + ResourceNameLengthLimit = 63 +) + +// GetCSIAttachLimitKey returns limit key used for CSI volumes +func GetCSIAttachLimitKey(driverName string) string { + csiPrefixLength := len(CSIAttachLimitPrefix) + totalkeyLength := csiPrefixLength + len(driverName) + if totalkeyLength >= ResourceNameLengthLimit { + charsFromDriverName := driverName[:23] + hash := sha1.New() + hash.Write([]byte(driverName)) + hashed := hex.EncodeToString(hash.Sum(nil)) + hashed = hashed[:16] + return CSIAttachLimitPrefix + charsFromDriverName + hashed + } + return CSIAttachLimitPrefix + driverName +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/device_util.go b/vendor/k8s.io/kubernetes/pkg/volume/util/device_util.go new file mode 100644 index 000000000..4b2fc8854 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/device_util.go @@ -0,0 +1,34 @@ +/* +Copyright 2016 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 util + +// DeviceUtil is a util for common device methods +type DeviceUtil interface { + FindMultipathDeviceForDevice(disk string) string + FindSlaveDevicesOnMultipath(disk string) []string + GetISCSIPortalHostMapForTarget(targetIqn string) (map[string]int, error) + FindDevicesForISCSILun(targetIqn string, lun int) ([]string, error) +} + +type deviceHandler struct { + getIo IoUtil +} + +// NewDeviceHandler Create a new IoHandler implementation +func NewDeviceHandler(io IoUtil) DeviceUtil { + return &deviceHandler{getIo: io} +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/device_util_linux.go b/vendor/k8s.io/kubernetes/pkg/volume/util/device_util_linux.go new file mode 100644 index 000000000..66ac77835 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/device_util_linux.go @@ -0,0 +1,301 @@ +//go:build linux +// +build linux + +/* +Copyright 2016 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 util + +import ( + "errors" + "fmt" + "net" + "os" + "path/filepath" + "strconv" + "strings" + + "k8s.io/klog/v2" +) + +// FindMultipathDeviceForDevice given a device name like /dev/sdx, find the devicemapper parent +func (handler *deviceHandler) FindMultipathDeviceForDevice(device string) string { + io := handler.getIo + disk, err := findDeviceForPath(device, io) + if err != nil { + return "" + } + sysPath := "/sys/block/" + if dirs, err := io.ReadDir(sysPath); err == nil { + for _, f := range dirs { + name := f.Name() + if strings.HasPrefix(name, "dm-") { + if _, err1 := io.Lstat(sysPath + name + "/slaves/" + disk); err1 == nil { + return "/dev/" + name + } + } + } + } + return "" +} + +// findDeviceForPath Find the underlying disk for a linked path such as /dev/disk/by-path/XXXX or /dev/mapper/XXXX +// will return sdX or hdX etc, if /dev/sdX is passed in then sdX will be returned +func findDeviceForPath(path string, io IoUtil) (string, error) { + devicePath, err := io.EvalSymlinks(path) + if err != nil { + return "", err + } + // if path /dev/hdX split into "", "dev", "hdX" then we will + // return just the last part + parts := strings.Split(devicePath, "/") + if len(parts) == 3 && strings.HasPrefix(parts[1], "dev") { + return parts[2], nil + } + return "", errors.New("Illegal path for device " + devicePath) +} + +// FindSlaveDevicesOnMultipath given a dm name like /dev/dm-1, find all devices +// which are managed by the devicemapper dm-1. +func (handler *deviceHandler) FindSlaveDevicesOnMultipath(dm string) []string { + var devices []string + io := handler.getIo + // Split path /dev/dm-1 into "", "dev", "dm-1" + parts := strings.Split(dm, "/") + if len(parts) != 3 || !strings.HasPrefix(parts[1], "dev") { + return devices + } + disk := parts[2] + slavesPath := filepath.Join("/sys/block/", disk, "/slaves/") + if files, err := io.ReadDir(slavesPath); err == nil { + for _, f := range files { + devices = append(devices, filepath.Join("/dev/", f.Name())) + } + } + return devices +} + +// GetISCSIPortalHostMapForTarget given a target iqn, find all the scsi hosts logged into +// that target. Returns a map of iSCSI portals (string) to SCSI host numbers (integers). +// +// For example: { +// "192.168.30.7:3260": 2, +// "192.168.30.8:3260": 3, +// } +func (handler *deviceHandler) GetISCSIPortalHostMapForTarget(targetIqn string) (map[string]int, error) { + portalHostMap := make(map[string]int) + io := handler.getIo + + // Iterate over all the iSCSI hosts in sysfs + sysPath := "/sys/class/iscsi_host" + hostDirs, err := io.ReadDir(sysPath) + if err != nil { + if os.IsNotExist(err) { + return portalHostMap, nil + } + return nil, err + } + for _, hostDir := range hostDirs { + // iSCSI hosts are always of the format "host%d" + // See drivers/scsi/hosts.c in Linux + hostName := hostDir.Name() + if !strings.HasPrefix(hostName, "host") { + continue + } + hostNumber, err := strconv.Atoi(strings.TrimPrefix(hostName, "host")) + if err != nil { + klog.Errorf("Could not get number from iSCSI host: %s", hostName) + continue + } + + // Iterate over the children of the iscsi_host device + // We are looking for the associated session + devicePath := sysPath + "/" + hostName + "/device" + deviceDirs, err := io.ReadDir(devicePath) + if err != nil { + return nil, err + } + for _, deviceDir := range deviceDirs { + // Skip over files that aren't the session + // Sessions are of the format "session%u" + // See drivers/scsi/scsi_transport_iscsi.c in Linux + sessionName := deviceDir.Name() + if !strings.HasPrefix(sessionName, "session") { + continue + } + + sessionPath := devicePath + "/" + sessionName + + // Read the target name for the iSCSI session + targetNamePath := sessionPath + "/iscsi_session/" + sessionName + "/targetname" + targetName, err := io.ReadFile(targetNamePath) + if err != nil { + klog.Infof("Failed to process session %s, assuming this session is unavailable: %s", sessionName, err) + continue + } + + // Ignore hosts that don't matchthe target we were looking for. + if strings.TrimSpace(string(targetName)) != targetIqn { + continue + } + + // Iterate over the children of the iSCSI session looking + // for the iSCSI connection. + dirs2, err := io.ReadDir(sessionPath) + if err != nil { + klog.Infof("Failed to process session %s, assuming this session is unavailable: %s", sessionName, err) + continue + } + for _, dir2 := range dirs2 { + // Skip over files that aren't the connection + // Connections are of the format "connection%d:%u" + // See drivers/scsi/scsi_transport_iscsi.c in Linux + dirName := dir2.Name() + if !strings.HasPrefix(dirName, "connection") { + continue + } + + connectionPath := sessionPath + "/" + dirName + "/iscsi_connection/" + dirName + + // Read the current and persistent portal information for the connection. + addrPath := connectionPath + "/address" + addr, err := io.ReadFile(addrPath) + if err != nil { + klog.Infof("Failed to process connection %s, assuming this connection is unavailable: %s", dirName, err) + continue + } + + portPath := connectionPath + "/port" + port, err := io.ReadFile(portPath) + if err != nil { + klog.Infof("Failed to process connection %s, assuming this connection is unavailable: %s", dirName, err) + continue + } + + persistentAddrPath := connectionPath + "/persistent_address" + persistentAddr, err := io.ReadFile(persistentAddrPath) + if err != nil { + klog.Infof("Failed to process connection %s, assuming this connection is unavailable: %s", dirName, err) + continue + } + + persistentPortPath := connectionPath + "/persistent_port" + persistentPort, err := io.ReadFile(persistentPortPath) + if err != nil { + klog.Infof("Failed to process connection %s, assuming this connection is unavailable: %s", dirName, err) + continue + } + + // Add entries to the map for both the current and persistent portals + // pointing to the SCSI host for those connections + // JoinHostPort will add `[]` around IPv6 addresses. + portal := net.JoinHostPort(strings.TrimSpace(string(addr)), strings.TrimSpace(string(port))) + portalHostMap[portal] = hostNumber + + persistentPortal := net.JoinHostPort(strings.TrimSpace(string(persistentAddr)), strings.TrimSpace(string(persistentPort))) + portalHostMap[persistentPortal] = hostNumber + } + } + } + + return portalHostMap, nil +} + +// FindDevicesForISCSILun given an iqn, and lun number, find all the devices +// corresponding to that LUN. +func (handler *deviceHandler) FindDevicesForISCSILun(targetIqn string, lun int) ([]string, error) { + devices := make([]string, 0) + io := handler.getIo + + // Iterate over all the iSCSI hosts in sysfs + sysPath := "/sys/class/iscsi_host" + hostDirs, err := io.ReadDir(sysPath) + if err != nil { + return nil, err + } + for _, hostDir := range hostDirs { + // iSCSI hosts are always of the format "host%d" + // See drivers/scsi/hosts.c in Linux + hostName := hostDir.Name() + if !strings.HasPrefix(hostName, "host") { + continue + } + hostNumber, err := strconv.Atoi(strings.TrimPrefix(hostName, "host")) + if err != nil { + klog.Errorf("Could not get number from iSCSI host: %s", hostName) + continue + } + + // Iterate over the children of the iscsi_host device + // We are looking for the associated session + devicePath := sysPath + "/" + hostName + "/device" + deviceDirs, err := io.ReadDir(devicePath) + if err != nil { + return nil, err + } + for _, deviceDir := range deviceDirs { + // Skip over files that aren't the session + // Sessions are of the format "session%u" + // See drivers/scsi/scsi_transport_iscsi.c in Linux + sessionName := deviceDir.Name() + if !strings.HasPrefix(sessionName, "session") { + continue + } + + // Read the target name for the iSCSI session + targetNamePath := devicePath + "/" + sessionName + "/iscsi_session/" + sessionName + "/targetname" + targetName, err := io.ReadFile(targetNamePath) + if err != nil { + return nil, err + } + + // Only if the session matches the target we were looking for, + // add it to the map + if strings.TrimSpace(string(targetName)) != targetIqn { + continue + } + + // The list of block devices on the scsi bus will be in a + // directory called "target%d:%d:%d". + // See drivers/scsi/scsi_scan.c in Linux + // We assume the channel/bus and device/controller are always zero for iSCSI + targetPath := devicePath + "/" + sessionName + fmt.Sprintf("/target%d:0:0", hostNumber) + + // The block device for a given lun will be "%d:%d:%d:%d" -- + // host:channel:bus:LUN + blockDevicePath := targetPath + fmt.Sprintf("/%d:0:0:%d", hostNumber, lun) + + // If the LUN doesn't exist on this bus, continue on + _, err = io.Lstat(blockDevicePath) + if err != nil { + continue + } + + // Read the block directory, there should only be one child -- + // the block device "sd*" + path := blockDevicePath + "/block" + dirs, err := io.ReadDir(path) + if err != nil { + return nil, err + } + if 0 < len(dirs) { + devices = append(devices, dirs[0].Name()) + } + } + } + + return devices, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/device_util_unsupported.go b/vendor/k8s.io/kubernetes/pkg/volume/util/device_util_unsupported.go new file mode 100644 index 000000000..ea4786aff --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/device_util_unsupported.go @@ -0,0 +1,43 @@ +//go:build !linux +// +build !linux + +/* +Copyright 2016 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 util + +// FindMultipathDeviceForDevice unsupported returns "" +func (handler *deviceHandler) FindMultipathDeviceForDevice(device string) string { + return "" +} + +// FindSlaveDevicesOnMultipath unsupported returns "" +func (handler *deviceHandler) FindSlaveDevicesOnMultipath(disk string) []string { + out := []string{} + return out +} + +// GetISCSIPortalHostMapForTarget unsupported returns nil +func (handler *deviceHandler) GetISCSIPortalHostMapForTarget(targetIqn string) (map[string]int, error) { + portalHostMap := make(map[string]int) + return portalHostMap, nil +} + +// FindDevicesForISCSILun unsupported returns nil +func (handler *deviceHandler) FindDevicesForISCSILun(targetIqn string, lun int) ([]string, error) { + devices := []string{} + return devices, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/doc.go b/vendor/k8s.io/kubernetes/pkg/volume/util/doc.go new file mode 100644 index 000000000..b32dae216 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/doc.go @@ -0,0 +1,18 @@ +/* +Copyright 2015 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 util contains utility code for use by volume plugins. +package util // import "k8s.io/kubernetes/pkg/volume/util" diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/finalizer.go b/vendor/k8s.io/kubernetes/pkg/volume/util/finalizer.go new file mode 100644 index 000000000..e1fdf5673 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/finalizer.go @@ -0,0 +1,25 @@ +/* +Copyright 2017 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 util + +const ( + // PVCProtectionFinalizer is the name of finalizer on PVCs that have a running pod. + PVCProtectionFinalizer = "kubernetes.io/pvc-protection" + + // PVProtectionFinalizer is the name of finalizer on PVs that are bound by PVCs + PVProtectionFinalizer = "kubernetes.io/pv-protection" +) diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/fs/fs.go b/vendor/k8s.io/kubernetes/pkg/volume/util/fs/fs.go new file mode 100644 index 000000000..64301fd5d --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/fs/fs.go @@ -0,0 +1,148 @@ +//go:build linux || darwin +// +build linux darwin + +/* +Copyright 2014 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 fs + +import ( + "fmt" + "os" + "path/filepath" + "syscall" + "time" + + "golang.org/x/sys/unix" + + servermetrics "k8s.io/kubernetes/pkg/kubelet/server/metrics" + "k8s.io/kubernetes/pkg/volume/util/fsquota" +) + +type UsageInfo struct { + Bytes int64 + Inodes int64 +} + +// Info linux returns (available bytes, byte capacity, byte usage, total inodes, inodes free, inode usage, error) +// for the filesystem that path resides upon. +func Info(path string) (int64, int64, int64, int64, int64, int64, error) { + statfs := &unix.Statfs_t{} + err := unix.Statfs(path, statfs) + if err != nil { + return 0, 0, 0, 0, 0, 0, err + } + + // Available is blocks available * fragment size + available := int64(statfs.Bavail) * int64(statfs.Bsize) + + // Capacity is total block count * fragment size + capacity := int64(statfs.Blocks) * int64(statfs.Bsize) + + // Usage is block being used * fragment size (aka block size). + usage := (int64(statfs.Blocks) - int64(statfs.Bfree)) * int64(statfs.Bsize) + + inodes := int64(statfs.Files) + inodesFree := int64(statfs.Ffree) + inodesUsed := inodes - inodesFree + + return available, capacity, usage, inodes, inodesFree, inodesUsed, nil +} + +// DiskUsage calculates the number of inodes and disk usage for a given directory +func DiskUsage(path string) (UsageInfo, error) { + var usage UsageInfo + + if path == "" { + return usage, fmt.Errorf("invalid directory") + } + + // First check whether the quota system knows about this directory + // A nil quantity or error means that the path does not support quotas + // or xfs_quota tool is missing and we should use other mechanisms. + startTime := time.Now() + consumption, _ := fsquota.GetConsumption(path) + if consumption != nil { + usage.Bytes = consumption.Value() + defer servermetrics.CollectVolumeStatCalDuration("fsquota", startTime) + } else { + defer servermetrics.CollectVolumeStatCalDuration("du", startTime) + } + + inodes, _ := fsquota.GetInodes(path) + if inodes != nil { + usage.Inodes = inodes.Value() + } + + if inodes != nil && consumption != nil { + return usage, nil + } + + topLevelStat := &unix.Stat_t{} + err := unix.Stat(path, topLevelStat) + if err != nil { + return usage, err + } + + // dedupedInode stores inodes that could be duplicates (nlink > 1) + dedupedInodes := make(map[uint64]struct{}) + + err = filepath.Walk(path, func(path string, info os.FileInfo, err error) error { + // ignore files that have been deleted after directory was read + if os.IsNotExist(err) { + return nil + } + if err != nil { + return fmt.Errorf("unable to count inodes for %s: %s", path, err) + } + + // according to the docs, Sys can be nil + if info.Sys() == nil { + return fmt.Errorf("fileinfo Sys is nil") + } + + s, ok := info.Sys().(*syscall.Stat_t) + if !ok { + return fmt.Errorf("unsupported fileinfo; could not convert to stat_t") + } + + if s.Dev != topLevelStat.Dev { + // don't descend into directories on other devices + return filepath.SkipDir + } + + // Dedupe hardlinks + if s.Nlink > 1 { + if _, ok := dedupedInodes[s.Ino]; !ok { + dedupedInodes[s.Ino] = struct{}{} + } else { + return nil + } + } + + if consumption == nil { + usage.Bytes += int64(s.Blocks) * int64(512) // blocksize in bytes + } + + if inodes == nil { + usage.Inodes++ + } + + return nil + }) + + return usage, err +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/fs/fs_unsupported.go b/vendor/k8s.io/kubernetes/pkg/volume/util/fs/fs_unsupported.go new file mode 100644 index 000000000..f66df0d06 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/fs/fs_unsupported.go @@ -0,0 +1,40 @@ +//go:build !linux && !darwin && !windows +// +build !linux,!darwin,!windows + +/* +Copyright 2014 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 fs + +import ( + "fmt" +) + +type UsageInfo struct { + Bytes int64 + Inodes int64 +} + +// Info unsupported returns 0 values for available and capacity and an error. +func Info(path string) (int64, int64, int64, int64, int64, int64, error) { + return 0, 0, 0, 0, 0, 0, fmt.Errorf("fsinfo not supported for this build") +} + +// DiskUsage gets disk usage of specified path. +func DiskUsage(path string) (UsageInfo, error) { + var usage UsageInfo + return usage, fmt.Errorf("directory disk usage not supported for this build.") +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/fs/fs_windows.go b/vendor/k8s.io/kubernetes/pkg/volume/util/fs/fs_windows.go new file mode 100644 index 000000000..6e138514a --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/fs/fs_windows.go @@ -0,0 +1,117 @@ +//go:build windows +// +build windows + +/* +Copyright 2014 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 fs + +import ( + "os" + "path/filepath" + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +var ( + modkernel32 = windows.NewLazySystemDLL("kernel32.dll") + procGetDiskFreeSpaceEx = modkernel32.NewProc("GetDiskFreeSpaceExW") +) + +type UsageInfo struct { + Bytes int64 + Inodes int64 +} + +// Info returns (available bytes, byte capacity, byte usage, total inodes, inodes free, inode usage, error) +// for the filesystem that path resides upon. +func Info(path string) (int64, int64, int64, int64, int64, int64, error) { + var freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes int64 + var err error + + // The equivalent linux call supports calls against files but the syscall for windows + // fails for files with error code: The directory name is invalid. (#99173) + // https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499- + // By always ensuring the directory path we meet all uses cases of this function + path = filepath.Dir(path) + ret, _, err := syscall.Syscall6( + procGetDiskFreeSpaceEx.Addr(), + 4, + uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(path))), + uintptr(unsafe.Pointer(&freeBytesAvailable)), + uintptr(unsafe.Pointer(&totalNumberOfBytes)), + uintptr(unsafe.Pointer(&totalNumberOfFreeBytes)), + 0, + 0, + ) + if ret == 0 { + return 0, 0, 0, 0, 0, 0, err + } + + return freeBytesAvailable, totalNumberOfBytes, totalNumberOfBytes - freeBytesAvailable, 0, 0, 0, nil +} + +// DiskUsage gets disk usage of specified path. +func DiskUsage(path string) (UsageInfo, error) { + var usage UsageInfo + info, err := os.Lstat(path) + if err != nil { + return usage, err + } + + usage.Bytes, err = diskUsage(path, info) + return usage, err +} + +func diskUsage(currPath string, info os.FileInfo) (int64, error) { + var size int64 + + if info.Mode()&os.ModeSymlink != 0 { + return size, nil + } + + size += info.Size() + + if !info.IsDir() { + return size, nil + } + + dir, err := os.Open(currPath) + if err != nil { + return size, err + } + defer dir.Close() + + files, err := dir.Readdir(-1) + if err != nil { + return size, err + } + + for _, file := range files { + if file.IsDir() { + s, err := diskUsage(filepath.Join(currPath, file.Name()), file) + if err != nil { + return size, err + } + size += s + } else { + size += file.Size() + } + } + return size, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/common/quota_linux_common.go b/vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/common/quota_linux_common.go new file mode 100644 index 000000000..8275a7f1c --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/common/quota_linux_common.go @@ -0,0 +1,101 @@ +//go:build linux +// +build linux + +/* +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 common + +import ( + "regexp" +) + +// QuotaID is generic quota identifier. +// Data type based on quotactl(2). +type QuotaID int32 + +const ( + // UnknownQuotaID -- cannot determine whether a quota is in force + UnknownQuotaID QuotaID = -1 + // BadQuotaID -- Invalid quota + BadQuotaID QuotaID = 0 +) + +// QuotaType -- type of quota to be applied +type QuotaType int + +const ( + // FSQuotaAccounting for quotas for accounting only + FSQuotaAccounting QuotaType = 1 << iota + // FSQuotaEnforcing for quotas for enforcement + FSQuotaEnforcing QuotaType = 1 << iota +) + +// FirstQuota is the quota ID we start with. +// XXXXXXX Need a better way of doing this... +var FirstQuota QuotaID = 1048577 + +// MountsFile is the location of the system mount data +var MountsFile = "/proc/self/mounts" + +// MountParseRegexp parses out /proc/sys/self/mounts +var MountParseRegexp = regexp.MustCompilePOSIX("^([^ ]*)[ \t]*([^ ]*)[ \t]*([^ ]*)") // Ignore options etc. + +// LinuxVolumeQuotaProvider returns an appropriate quota applier +// object if we can support quotas on this device +type LinuxVolumeQuotaProvider interface { + // GetQuotaApplier retrieves an object that can apply + // quotas (or nil if this provider cannot support quotas + // on the device) + GetQuotaApplier(mountpoint string, backingDev string) LinuxVolumeQuotaApplier +} + +// LinuxVolumeQuotaApplier is a generic interface to any quota +// mechanism supported by Linux +type LinuxVolumeQuotaApplier interface { + // GetQuotaOnDir gets the quota ID (if any) that applies to + // this directory + GetQuotaOnDir(path string) (QuotaID, error) + + // SetQuotaOnDir applies the specified quota ID to a directory. + // Negative value for bytes means that a non-enforcing quota + // should be applied (perhaps by setting a quota too large to + // be hit) + SetQuotaOnDir(path string, id QuotaID, bytes int64) error + + // QuotaIDIsInUse determines whether the quota ID is in use. + // Implementations should not check /etc/project or /etc/projid, + // only whether their underlying mechanism already has the ID in + // use. + // Return value of false with no error means that the ID is not + // in use; true means that it is already in use. An error + // return means that any quota ID will fail. + QuotaIDIsInUse(id QuotaID) (bool, error) + + // GetConsumption returns the consumption (in bytes) of the + // directory, determined by the implementation's quota-based + // mechanism. If it is unable to do so using that mechanism, + // it should return an error and allow higher layers to + // enumerate the directory. + GetConsumption(path string, id QuotaID) (int64, error) + + // GetInodes returns the number of inodes used by the + // directory, determined by the implementation's quota-based + // mechanism. If it is unable to do so using that mechanism, + // it should return an error and allow higher layers to + // enumerate the directory. + GetInodes(path string, id QuotaID) (int64, error) +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/common/quota_linux_common_impl.go b/vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/common/quota_linux_common_impl.go new file mode 100644 index 000000000..7f24ca1cd --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/common/quota_linux_common_impl.go @@ -0,0 +1,287 @@ +//go:build linux +// +build linux + +/* +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 common + +import ( + "bufio" + "fmt" + "io/ioutil" + "os" + "os/exec" + "regexp" + "strconv" + "strings" + "sync" + "syscall" + + "k8s.io/klog/v2" +) + +var quotaCmd string +var quotaCmdInitialized bool +var quotaCmdLock sync.RWMutex + +// If we later get a filesystem that uses project quota semantics other than +// XFS, we'll need to change this. +// Higher levels don't need to know what's inside +type linuxFilesystemType struct { + name string + typeMagic int64 // Filesystem magic number, per statfs(2) + maxQuota int64 + allowEmptyOutput bool // Accept empty output from "quota" command +} + +const ( + bitsPerWord = 32 << (^uint(0) >> 63) // either 32 or 64 +) + +var ( + linuxSupportedFilesystems = []linuxFilesystemType{ + { + name: "XFS", + typeMagic: 0x58465342, + maxQuota: 1<<(bitsPerWord-1) - 1, + allowEmptyOutput: true, // XFS filesystems report nothing if a quota is not present + }, { + name: "ext4fs", + typeMagic: 0xef53, + maxQuota: (1<<(bitsPerWord-1) - 1) & (1<<58 - 1), + allowEmptyOutput: false, // ext4 filesystems always report something even if a quota is not present + }, + } +) + +// VolumeProvider supplies a quota applier to the generic code. +type VolumeProvider struct { +} + +var quotaCmds = []string{"/sbin/xfs_quota", + "/usr/sbin/xfs_quota", + "/bin/xfs_quota"} + +var quotaParseRegexp = regexp.MustCompilePOSIX("^[^ \t]*[ \t]*([0-9]+)") + +var lsattrCmd = "/usr/bin/lsattr" +var lsattrParseRegexp = regexp.MustCompilePOSIX("^ *([0-9]+) [^ ]+ (.*)$") + +// GetQuotaApplier -- does this backing device support quotas that +// can be applied to directories? +func (*VolumeProvider) GetQuotaApplier(mountpoint string, backingDev string) LinuxVolumeQuotaApplier { + for _, fsType := range linuxSupportedFilesystems { + if isFilesystemOfType(mountpoint, backingDev, fsType.typeMagic) { + return linuxVolumeQuotaApplier{mountpoint: mountpoint, + maxQuota: fsType.maxQuota, + allowEmptyOutput: fsType.allowEmptyOutput, + } + } + } + return nil +} + +type linuxVolumeQuotaApplier struct { + mountpoint string + maxQuota int64 + allowEmptyOutput bool +} + +func getXFSQuotaCmd() (string, error) { + quotaCmdLock.Lock() + defer quotaCmdLock.Unlock() + if quotaCmdInitialized { + return quotaCmd, nil + } + for _, program := range quotaCmds { + fileinfo, err := os.Stat(program) + if err == nil && ((fileinfo.Mode().Perm() & (1 << 6)) != 0) { + klog.V(3).Infof("Found xfs_quota program %s", program) + quotaCmd = program + quotaCmdInitialized = true + return quotaCmd, nil + } + } + quotaCmdInitialized = true + return "", fmt.Errorf("no xfs_quota program found") +} + +func doRunXFSQuotaCommand(mountpoint string, mountsFile, command string) (string, error) { + quotaCmd, err := getXFSQuotaCmd() + if err != nil { + return "", err + } + // We're using numeric project IDs directly; no need to scan + // /etc/projects or /etc/projid + klog.V(4).Infof("runXFSQuotaCommand %s -t %s -P/dev/null -D/dev/null -x -f %s -c %s", quotaCmd, mountsFile, mountpoint, command) + cmd := exec.Command(quotaCmd, "-t", mountsFile, "-P/dev/null", "-D/dev/null", "-x", "-f", mountpoint, "-c", command) + + data, err := cmd.Output() + if err != nil { + return "", err + } + klog.V(4).Infof("runXFSQuotaCommand output %q", string(data)) + return string(data), nil +} + +// Extract the mountpoint we care about into a temporary mounts file so that xfs_quota does +// not attempt to scan every mount on the filesystem, which could hang if e. g. +// a stuck NFS mount is present. +// See https://bugzilla.redhat.com/show_bug.cgi?id=237120 for an example +// of the problem that could be caused if this were to happen. +func runXFSQuotaCommand(mountpoint string, command string) (string, error) { + tmpMounts, err := ioutil.TempFile("", "mounts") + if err != nil { + return "", fmt.Errorf("cannot create temporary mount file: %v", err) + } + tmpMountsFileName := tmpMounts.Name() + defer tmpMounts.Close() + defer os.Remove(tmpMountsFileName) + + mounts, err := os.Open(MountsFile) + if err != nil { + return "", fmt.Errorf("cannot open mounts file %s: %v", MountsFile, err) + } + defer mounts.Close() + + scanner := bufio.NewScanner(mounts) + for scanner.Scan() { + match := MountParseRegexp.FindStringSubmatch(scanner.Text()) + if match != nil { + mount := match[2] + if mount == mountpoint { + if _, err := tmpMounts.WriteString(fmt.Sprintf("%s\n", scanner.Text())); err != nil { + return "", fmt.Errorf("cannot write temporary mounts file: %v", err) + } + if err := tmpMounts.Sync(); err != nil { + return "", fmt.Errorf("cannot sync temporary mounts file: %v", err) + } + return doRunXFSQuotaCommand(mountpoint, tmpMountsFileName, command) + } + } + } + return "", fmt.Errorf("cannot run xfs_quota: cannot find mount point %s in %s", mountpoint, MountsFile) +} + +// SupportsQuotas determines whether the filesystem supports quotas. +func SupportsQuotas(mountpoint string, qType QuotaType) (bool, error) { + data, err := runXFSQuotaCommand(mountpoint, "state -p") + if err != nil { + return false, err + } + if qType == FSQuotaEnforcing { + return strings.Contains(data, "Enforcement: ON"), nil + } + return strings.Contains(data, "Accounting: ON"), nil +} + +func isFilesystemOfType(mountpoint string, backingDev string, typeMagic int64) bool { + var buf syscall.Statfs_t + err := syscall.Statfs(mountpoint, &buf) + if err != nil { + klog.Warningf("Warning: Unable to statfs %s: %v", mountpoint, err) + return false + } + if int64(buf.Type) != typeMagic { + return false + } + if answer, _ := SupportsQuotas(mountpoint, FSQuotaAccounting); answer { + return true + } + return false +} + +// GetQuotaOnDir retrieves the quota ID (if any) associated with the specified directory +// If we can't make system calls, all we can say is that we don't know whether +// it has a quota, and higher levels have to make the call. +func (v linuxVolumeQuotaApplier) GetQuotaOnDir(path string) (QuotaID, error) { + cmd := exec.Command(lsattrCmd, "-pd", path) + data, err := cmd.Output() + if err != nil { + return BadQuotaID, fmt.Errorf("cannot run lsattr: %v", err) + } + match := lsattrParseRegexp.FindStringSubmatch(string(data)) + if match == nil { + return BadQuotaID, fmt.Errorf("unable to parse lsattr -pd %s output %s", path, string(data)) + } + if match[2] != path { + return BadQuotaID, fmt.Errorf("mismatch between supplied and returned path (%s != %s)", path, match[2]) + } + projid, err := strconv.ParseInt(match[1], 10, 32) + if err != nil { + return BadQuotaID, fmt.Errorf("unable to parse project ID from %s (%v)", match[1], err) + } + return QuotaID(projid), nil +} + +// SetQuotaOnDir applies a quota to the specified directory under the specified mountpoint. +func (v linuxVolumeQuotaApplier) SetQuotaOnDir(path string, id QuotaID, bytes int64) error { + if bytes < 0 || bytes > v.maxQuota { + bytes = v.maxQuota + } + _, err := runXFSQuotaCommand(v.mountpoint, fmt.Sprintf("limit -p bhard=%v bsoft=%v %v", bytes, bytes, id)) + if err != nil { + return err + } + + _, err = runXFSQuotaCommand(v.mountpoint, fmt.Sprintf("project -s -p %s %v", path, id)) + return err +} + +func getQuantity(mountpoint string, id QuotaID, xfsQuotaArg string, multiplier int64, allowEmptyOutput bool) (int64, error) { + data, err := runXFSQuotaCommand(mountpoint, fmt.Sprintf("quota -p -N -n -v %s %v", xfsQuotaArg, id)) + if err != nil { + return 0, fmt.Errorf("unable to run xfs_quota: %v", err) + } + if data == "" && allowEmptyOutput { + return 0, nil + } + match := quotaParseRegexp.FindStringSubmatch(data) + if match == nil { + return 0, fmt.Errorf("unable to parse quota output '%s'", data) + } + size, err := strconv.ParseInt(match[1], 10, 64) + if err != nil { + return 0, fmt.Errorf("unable to parse data size '%s' from '%s': %v", match[1], data, err) + } + klog.V(4).Infof("getQuantity %s %d %s %d => %d %v", mountpoint, id, xfsQuotaArg, multiplier, size, err) + return size * multiplier, nil +} + +// GetConsumption returns the consumption in bytes if available via quotas +func (v linuxVolumeQuotaApplier) GetConsumption(_ string, id QuotaID) (int64, error) { + return getQuantity(v.mountpoint, id, "-b", 1024, v.allowEmptyOutput) +} + +// GetInodes returns the inodes in use if available via quotas +func (v linuxVolumeQuotaApplier) GetInodes(_ string, id QuotaID) (int64, error) { + return getQuantity(v.mountpoint, id, "-i", 1, v.allowEmptyOutput) +} + +// QuotaIDIsInUse checks whether the specified quota ID is in use on the specified +// filesystem +func (v linuxVolumeQuotaApplier) QuotaIDIsInUse(id QuotaID) (bool, error) { + bytes, err := v.GetConsumption(v.mountpoint, id) + if err != nil { + return false, err + } + if bytes > 0 { + return true, nil + } + inodes, err := v.GetInodes(v.mountpoint, id) + return inodes > 0, err +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/project.go b/vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/project.go new file mode 100644 index 000000000..3861f9905 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/project.go @@ -0,0 +1,358 @@ +//go:build linux +// +build linux + +/* +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 fsquota + +import ( + "bufio" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "regexp" + "strconv" + "sync" + + "golang.org/x/sys/unix" + "k8s.io/kubernetes/pkg/volume/util/fsquota/common" +) + +var projectsFile = "/etc/projects" +var projidFile = "/etc/projid" + +var projectsParseRegexp = regexp.MustCompilePOSIX("^([[:digit:]]+):(.*)$") +var projidParseRegexp = regexp.MustCompilePOSIX("^([^#][^:]*):([[:digit:]]+)$") + +var quotaIDLock sync.RWMutex + +const maxUnusedQuotasToSearch = 128 // Don't go into an infinite loop searching for an unused quota + +type projectType struct { + isValid bool // False if we need to remove this line + id common.QuotaID + data string // Project name (projid) or directory (projects) + line string +} + +type projectsList struct { + projects []projectType + projid []projectType +} + +func projFilesAreOK() error { + if sf, err := os.Lstat(projectsFile); err != nil || sf.Mode().IsRegular() { + if sf, err := os.Lstat(projidFile); err != nil || sf.Mode().IsRegular() { + return nil + } + return fmt.Errorf("%s exists but is not a plain file, cannot continue", projidFile) + } + return fmt.Errorf("%s exists but is not a plain file, cannot continue", projectsFile) +} + +func lockFile(file *os.File) error { + return unix.Flock(int(file.Fd()), unix.LOCK_EX) +} + +func unlockFile(file *os.File) error { + return unix.Flock(int(file.Fd()), unix.LOCK_UN) +} + +// openAndLockProjectFiles opens /etc/projects and /etc/projid locked. +// Creates them if they don't exist +func openAndLockProjectFiles() (*os.File, *os.File, error) { + // Make sure neither project-related file is a symlink! + if err := projFilesAreOK(); err != nil { + return nil, nil, fmt.Errorf("system project files failed verification: %v", err) + } + // We don't actually modify the original files; we create temporaries and + // move them over the originals + fProjects, err := os.OpenFile(projectsFile, os.O_RDONLY|os.O_CREATE, 0644) + if err != nil { + err = fmt.Errorf("unable to open %s: %v", projectsFile, err) + return nil, nil, err + } + fProjid, err := os.OpenFile(projidFile, os.O_RDONLY|os.O_CREATE, 0644) + if err == nil { + // Check once more, to ensure nothing got changed out from under us + if err = projFilesAreOK(); err == nil { + err = lockFile(fProjects) + if err == nil { + err = lockFile(fProjid) + if err == nil { + return fProjects, fProjid, nil + } + // Nothing useful we can do if we get an error here + err = fmt.Errorf("unable to lock %s: %v", projidFile, err) + unlockFile(fProjects) + } else { + err = fmt.Errorf("unable to lock %s: %v", projectsFile, err) + } + } else { + err = fmt.Errorf("system project files failed re-verification: %v", err) + } + fProjid.Close() + } else { + err = fmt.Errorf("unable to open %s: %v", projidFile, err) + } + fProjects.Close() + return nil, nil, err +} + +func closeProjectFiles(fProjects *os.File, fProjid *os.File) error { + // Nothing useful we can do if either of these fail, + // but we have to close (and thereby unlock) the files anyway. + var err error + var err1 error + if fProjid != nil { + err = fProjid.Close() + } + if fProjects != nil { + err1 = fProjects.Close() + } + if err == nil { + return err1 + } + return err +} + +func parseProject(l string) projectType { + if match := projectsParseRegexp.FindStringSubmatch(l); match != nil { + i, err := strconv.Atoi(match[1]) + if err == nil { + return projectType{true, common.QuotaID(i), match[2], l} + } + } + return projectType{true, common.BadQuotaID, "", l} +} + +func parseProjid(l string) projectType { + if match := projidParseRegexp.FindStringSubmatch(l); match != nil { + i, err := strconv.Atoi(match[2]) + if err == nil { + return projectType{true, common.QuotaID(i), match[1], l} + } + } + return projectType{true, common.BadQuotaID, "", l} +} + +func parseProjFile(f *os.File, parser func(l string) projectType) []projectType { + var answer []projectType + scanner := bufio.NewScanner(f) + for scanner.Scan() { + answer = append(answer, parser(scanner.Text())) + } + return answer +} + +func readProjectFiles(projects *os.File, projid *os.File) projectsList { + return projectsList{parseProjFile(projects, parseProject), parseProjFile(projid, parseProjid)} +} + +func findAvailableQuota(path string, idMap map[common.QuotaID]bool) (common.QuotaID, error) { + unusedQuotasSearched := 0 + for id := common.FirstQuota; true; id++ { + if _, ok := idMap[id]; !ok { + isInUse, err := getApplier(path).QuotaIDIsInUse(id) + if err != nil { + return common.BadQuotaID, err + } else if !isInUse { + return id, nil + } + unusedQuotasSearched++ + if unusedQuotasSearched > maxUnusedQuotasToSearch { + break + } + } + } + return common.BadQuotaID, fmt.Errorf("cannot find available quota ID") +} + +func addDirToProject(path string, id common.QuotaID, list *projectsList) (common.QuotaID, bool, error) { + idMap := make(map[common.QuotaID]bool) + for _, project := range list.projects { + if project.data == path { + if id != project.id { + return common.BadQuotaID, false, fmt.Errorf("attempt to reassign project ID for %s", path) + } + // Trying to reassign a directory to the project it's + // already in. Maybe this should be an error, but for + // now treat it as an idempotent operation + return id, false, nil + } + idMap[project.id] = true + } + var needToAddProjid = true + for _, projid := range list.projid { + idMap[projid.id] = true + if projid.id == id && id != common.BadQuotaID { + needToAddProjid = false + } + } + var err error + if id == common.BadQuotaID { + id, err = findAvailableQuota(path, idMap) + if err != nil { + return common.BadQuotaID, false, err + } + needToAddProjid = true + } + if needToAddProjid { + name := fmt.Sprintf("volume%v", id) + line := fmt.Sprintf("%s:%v", name, id) + list.projid = append(list.projid, projectType{true, id, name, line}) + } + line := fmt.Sprintf("%v:%s", id, path) + list.projects = append(list.projects, projectType{true, id, path, line}) + return id, needToAddProjid, nil +} + +func removeDirFromProject(path string, id common.QuotaID, list *projectsList) (bool, error) { + if id == common.BadQuotaID { + return false, fmt.Errorf("attempt to remove invalid quota ID from %s", path) + } + foundAt := -1 + countByID := make(map[common.QuotaID]int) + for i, project := range list.projects { + if project.data == path { + if id != project.id { + return false, fmt.Errorf("attempting to remove quota ID %v from path %s, but expecting ID %v", id, path, project.id) + } else if foundAt != -1 { + return false, fmt.Errorf("found multiple quota IDs for path %s", path) + } + // Faster and easier than deleting an element + list.projects[i].isValid = false + foundAt = i + } + countByID[project.id]++ + } + if foundAt == -1 { + return false, fmt.Errorf("cannot find quota associated with path %s", path) + } + if countByID[id] <= 1 { + // Removing the last entry means that we're no longer using + // the quota ID, so remove that as well + for i, projid := range list.projid { + if projid.id == id { + list.projid[i].isValid = false + } + } + return true, nil + } + return false, nil +} + +func writeProjectFile(base *os.File, projects []projectType) (string, error) { + oname := base.Name() + stat, err := base.Stat() + if err != nil { + return "", err + } + mode := stat.Mode() & os.ModePerm + f, err := ioutil.TempFile(filepath.Dir(oname), filepath.Base(oname)) + if err != nil { + return "", err + } + filename := f.Name() + if err := os.Chmod(filename, mode); err != nil { + return "", err + } + for _, proj := range projects { + if proj.isValid { + if _, err := f.WriteString(fmt.Sprintf("%s\n", proj.line)); err != nil { + f.Close() + os.Remove(filename) + return "", err + } + } + } + if err := f.Close(); err != nil { + os.Remove(filename) + return "", err + } + return filename, nil +} + +func writeProjectFiles(fProjects *os.File, fProjid *os.File, writeProjid bool, list projectsList) error { + tmpProjects, err := writeProjectFile(fProjects, list.projects) + if err == nil { + // Ensure that both files are written before we try to rename either. + if writeProjid { + tmpProjid, err := writeProjectFile(fProjid, list.projid) + if err == nil { + err = os.Rename(tmpProjid, fProjid.Name()) + if err != nil { + os.Remove(tmpProjid) + } + } + } + if err == nil { + err = os.Rename(tmpProjects, fProjects.Name()) + if err == nil { + return nil + } + // We're in a bit of trouble here; at this + // point we've successfully renamed tmpProjid + // to the real thing, but renaming tmpProject + // to the real file failed. There's not much we + // can do in this position. Anything we could do + // to try to undo it would itself be likely to fail. + } + os.Remove(tmpProjects) + } + return fmt.Errorf("unable to write project files: %v", err) +} + +func createProjectID(path string, ID common.QuotaID) (common.QuotaID, error) { + quotaIDLock.Lock() + defer quotaIDLock.Unlock() + fProjects, fProjid, err := openAndLockProjectFiles() + if err == nil { + defer closeProjectFiles(fProjects, fProjid) + list := readProjectFiles(fProjects, fProjid) + var writeProjid bool + ID, writeProjid, err = addDirToProject(path, ID, &list) + if err == nil && ID != common.BadQuotaID { + if err = writeProjectFiles(fProjects, fProjid, writeProjid, list); err == nil { + return ID, nil + } + } + } + return common.BadQuotaID, fmt.Errorf("createProjectID %s %v failed %v", path, ID, err) +} + +func removeProjectID(path string, ID common.QuotaID) error { + if ID == common.BadQuotaID { + return fmt.Errorf("attempting to remove invalid quota ID %v", ID) + } + quotaIDLock.Lock() + defer quotaIDLock.Unlock() + fProjects, fProjid, err := openAndLockProjectFiles() + if err == nil { + defer closeProjectFiles(fProjects, fProjid) + list := readProjectFiles(fProjects, fProjid) + var writeProjid bool + writeProjid, err = removeDirFromProject(path, ID, &list) + if err == nil { + if err = writeProjectFiles(fProjects, fProjid, writeProjid, list); err == nil { + return nil + } + } + } + return fmt.Errorf("removeProjectID %s %v failed %v", path, ID, err) +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/quota.go b/vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/quota.go new file mode 100644 index 000000000..fbd29fba7 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/quota.go @@ -0,0 +1,50 @@ +/* +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 fsquota + +import ( + "k8s.io/mount-utils" + + "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/types" + utilfeature "k8s.io/apiserver/pkg/util/feature" + "k8s.io/kubernetes/pkg/features" +) + +// Interface -- quota interface +type Interface interface { + // Does the path provided support quotas, and if so, what types + SupportsQuotas(m mount.Interface, path string) (bool, error) + // Assign a quota (picked by the quota mechanism) to a path, + // and return it. + AssignQuota(m mount.Interface, path string, poduid types.UID, bytes *resource.Quantity) error + + // Get the quota-based storage consumption for the path + GetConsumption(path string) (*resource.Quantity, error) + + // Get the quota-based inode consumption for the path + GetInodes(path string) (*resource.Quantity, error) + + // Remove the quota from a path + // Implementations may assume that any data covered by the + // quota has already been removed. + ClearQuota(m mount.Interface, path string) error +} + +func enabledQuotasForMonitoring() bool { + return utilfeature.DefaultFeatureGate.Enabled(features.LocalStorageCapacityIsolationFSQuotaMonitoring) +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/quota_linux.go b/vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/quota_linux.go new file mode 100644 index 000000000..85784204a --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/quota_linux.go @@ -0,0 +1,452 @@ +//go:build linux +// +build linux + +/* +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 fsquota + +import ( + "bufio" + "fmt" + "os" + "path/filepath" + "sync" + + "k8s.io/klog/v2" + "k8s.io/mount-utils" + + "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/uuid" + "k8s.io/kubernetes/pkg/volume/util/fsquota/common" +) + +// Pod -> ID +var podQuotaMap = make(map[types.UID]common.QuotaID) + +// Dir -> ID (for convenience) +var dirQuotaMap = make(map[string]common.QuotaID) + +// ID -> pod +var quotaPodMap = make(map[common.QuotaID]types.UID) + +// Directory -> pod +var dirPodMap = make(map[string]types.UID) + +// Backing device -> applier +// This is *not* cleaned up; its size will be bounded. +var devApplierMap = make(map[string]common.LinuxVolumeQuotaApplier) + +// Directory -> applier +var dirApplierMap = make(map[string]common.LinuxVolumeQuotaApplier) +var dirApplierLock sync.RWMutex + +// Pod -> refcount +var podDirCountMap = make(map[types.UID]int) + +// ID -> size +var quotaSizeMap = make(map[common.QuotaID]int64) +var quotaLock sync.RWMutex + +var supportsQuotasMap = make(map[string]bool) +var supportsQuotasLock sync.RWMutex + +// Directory -> backingDev +var backingDevMap = make(map[string]string) +var backingDevLock sync.RWMutex + +var mountpointMap = make(map[string]string) +var mountpointLock sync.RWMutex + +var providers = []common.LinuxVolumeQuotaProvider{ + &common.VolumeProvider{}, +} + +// Separate the innards for ease of testing +func detectBackingDevInternal(mountpoint string, mounts string) (string, error) { + file, err := os.Open(mounts) + if err != nil { + return "", err + } + defer file.Close() + scanner := bufio.NewScanner(file) + for scanner.Scan() { + match := common.MountParseRegexp.FindStringSubmatch(scanner.Text()) + if match != nil { + device := match[1] + mount := match[2] + if mount == mountpoint { + return device, nil + } + } + } + return "", fmt.Errorf("couldn't find backing device for %s", mountpoint) +} + +// detectBackingDev assumes that the mount point provided is valid +func detectBackingDev(_ mount.Interface, mountpoint string) (string, error) { + return detectBackingDevInternal(mountpoint, common.MountsFile) +} + +func clearBackingDev(path string) { + backingDevLock.Lock() + defer backingDevLock.Unlock() + delete(backingDevMap, path) +} + +// Assumes that the path has been fully canonicalized +// Breaking this up helps with testing +func detectMountpointInternal(m mount.Interface, path string) (string, error) { + for path != "" && path != "/" { + // per k8s.io/mount-utils/mount_linux this detects all but + // a bind mount from one part of a mount to another. + // For our purposes that's fine; we simply want the "true" + // mount point + // + // IsNotMountPoint proved much more troublesome; it actually + // scans the mounts, and when a lot of mount/unmount + // activity takes place, it is not able to get a consistent + // view of /proc/self/mounts, causing it to time out and + // report incorrectly. + isNotMount, err := m.IsLikelyNotMountPoint(path) + if err != nil { + return "/", err + } + if !isNotMount { + return path, nil + } + path = filepath.Dir(path) + } + return "/", nil +} + +func detectMountpoint(m mount.Interface, path string) (string, error) { + xpath, err := filepath.Abs(path) + if err != nil { + return "/", err + } + xpath, err = filepath.EvalSymlinks(xpath) + if err != nil { + return "/", err + } + if xpath, err = detectMountpointInternal(m, xpath); err == nil { + return xpath, nil + } + return "/", err +} + +func clearMountpoint(path string) { + mountpointLock.Lock() + defer mountpointLock.Unlock() + delete(mountpointMap, path) +} + +// getFSInfo Returns mountpoint and backing device +// getFSInfo should cache the mountpoint and backing device for the +// path. +func getFSInfo(m mount.Interface, path string) (string, string, error) { + mountpointLock.Lock() + defer mountpointLock.Unlock() + + backingDevLock.Lock() + defer backingDevLock.Unlock() + + var err error + + mountpoint, okMountpoint := mountpointMap[path] + if !okMountpoint { + mountpoint, err = detectMountpoint(m, path) + if err != nil { + return "", "", fmt.Errorf("cannot determine mountpoint for %s: %v", path, err) + } + } + + backingDev, okBackingDev := backingDevMap[path] + if !okBackingDev { + backingDev, err = detectBackingDev(m, mountpoint) + if err != nil { + return "", "", fmt.Errorf("cannot determine backing device for %s: %v", path, err) + } + } + mountpointMap[path] = mountpoint + backingDevMap[path] = backingDev + return mountpoint, backingDev, nil +} + +func clearFSInfo(path string) { + clearMountpoint(path) + clearBackingDev(path) +} + +func getApplier(path string) common.LinuxVolumeQuotaApplier { + dirApplierLock.Lock() + defer dirApplierLock.Unlock() + return dirApplierMap[path] +} + +func setApplier(path string, applier common.LinuxVolumeQuotaApplier) { + dirApplierLock.Lock() + defer dirApplierLock.Unlock() + dirApplierMap[path] = applier +} + +func clearApplier(path string) { + dirApplierLock.Lock() + defer dirApplierLock.Unlock() + delete(dirApplierMap, path) +} + +func setQuotaOnDir(path string, id common.QuotaID, bytes int64) error { + return getApplier(path).SetQuotaOnDir(path, id, bytes) +} + +func getQuotaOnDir(m mount.Interface, path string) (common.QuotaID, error) { + _, _, err := getFSInfo(m, path) + if err != nil { + return common.BadQuotaID, err + } + return getApplier(path).GetQuotaOnDir(path) +} + +func clearQuotaOnDir(m mount.Interface, path string) error { + // Since we may be called without path being in the map, + // we explicitly have to check in this case. + klog.V(4).Infof("clearQuotaOnDir %s", path) + supportsQuotas, err := SupportsQuotas(m, path) + if err != nil { + // Log-and-continue instead of returning an error for now + // due to unspecified backwards compatibility concerns (a subject to revise) + klog.V(3).Infof("Attempt to check for quota support failed: %v", err) + } + if !supportsQuotas { + return nil + } + projid, err := getQuotaOnDir(m, path) + if err == nil && projid != common.BadQuotaID { + // This means that we have a quota on the directory but + // we can't clear it. That's not good. + err = setQuotaOnDir(path, projid, 0) + if err != nil { + klog.V(3).Infof("Attempt to clear quota failed: %v", err) + } + // Even if clearing the quota failed, we still need to + // try to remove the project ID, or that may be left dangling. + err1 := removeProjectID(path, projid) + if err1 != nil { + klog.V(3).Infof("Attempt to remove quota ID from system files failed: %v", err1) + } + clearFSInfo(path) + if err != nil { + return err + } + return err1 + } + // If we couldn't get a quota, that's fine -- there may + // never have been one, and we have no way to know otherwise + klog.V(3).Infof("clearQuotaOnDir fails %v", err) + return nil +} + +// SupportsQuotas -- Does the path support quotas +// Cache the applier for paths that support quotas. For paths that don't, +// don't cache the result because nothing will clean it up. +// However, do cache the device->applier map; the number of devices +// is bounded. +func SupportsQuotas(m mount.Interface, path string) (bool, error) { + if !enabledQuotasForMonitoring() { + klog.V(3).Info("SupportsQuotas called, but quotas disabled") + return false, nil + } + supportsQuotasLock.Lock() + defer supportsQuotasLock.Unlock() + if supportsQuotas, ok := supportsQuotasMap[path]; ok { + return supportsQuotas, nil + } + mount, dev, err := getFSInfo(m, path) + if err != nil { + return false, err + } + // Do we know about this device? + applier, ok := devApplierMap[mount] + if !ok { + for _, provider := range providers { + if applier = provider.GetQuotaApplier(mount, dev); applier != nil { + devApplierMap[mount] = applier + break + } + } + } + if applier != nil { + supportsQuotasMap[path] = true + setApplier(path, applier) + return true, nil + } + delete(backingDevMap, path) + delete(mountpointMap, path) + return false, nil +} + +// AssignQuota -- assign a quota to the specified directory. +// AssignQuota chooses the quota ID based on the pod UID and path. +// If the pod UID is identical to another one known, it may (but presently +// doesn't) choose the same quota ID as other volumes in the pod. +func AssignQuota(m mount.Interface, path string, poduid types.UID, bytes *resource.Quantity) error { //nolint:staticcheck // SA4009 poduid is overwritten by design, see comment below + if bytes == nil { + return fmt.Errorf("attempting to assign null quota to %s", path) + } + ibytes := bytes.Value() + if ok, err := SupportsQuotas(m, path); !ok { + return fmt.Errorf("quotas not supported on %s: %v", path, err) + } + quotaLock.Lock() + defer quotaLock.Unlock() + // Current policy is to set individual quotas on each volumes. + // If we decide later that we want to assign one quota for all + // volumes in a pod, we can simply remove this line of code. + // If and when we decide permanently that we're going to adopt + // one quota per volume, we can rip all of the pod code out. + poduid = types.UID(uuid.NewUUID()) //nolint:staticcheck // SA4009 poduid is overwritten by design, see comment above + if pod, ok := dirPodMap[path]; ok && pod != poduid { + return fmt.Errorf("requesting quota on existing directory %s but different pod %s %s", path, pod, poduid) + } + oid, ok := podQuotaMap[poduid] + if ok { + if quotaSizeMap[oid] != ibytes { + return fmt.Errorf("requesting quota of different size: old %v new %v", quotaSizeMap[oid], bytes) + } + } else { + oid = common.BadQuotaID + } + id, err := createProjectID(path, oid) + if err == nil { + if oid != common.BadQuotaID && oid != id { + return fmt.Errorf("attempt to reassign quota %v to %v", oid, id) + } + // When enforcing quotas are enabled, we'll condition this + // on their being disabled also. + if ibytes > 0 { + ibytes = -1 + } + if err = setQuotaOnDir(path, id, ibytes); err == nil { + quotaPodMap[id] = poduid + quotaSizeMap[id] = ibytes + podQuotaMap[poduid] = id + dirQuotaMap[path] = id + dirPodMap[path] = poduid + podDirCountMap[poduid]++ + klog.V(4).Infof("Assigning quota ID %d (%d) to %s", id, ibytes, path) + return nil + } + removeProjectID(path, id) + } + return fmt.Errorf("assign quota FAILED %v", err) +} + +// GetConsumption -- retrieve the consumption (in bytes) of the directory +func GetConsumption(path string) (*resource.Quantity, error) { + // Note that we actually need to hold the lock at least through + // running the quota command, so it can't get recycled behind our back + quotaLock.Lock() + defer quotaLock.Unlock() + applier := getApplier(path) + // No applier means directory is not under quota management + if applier == nil { + return nil, nil + } + ibytes, err := applier.GetConsumption(path, dirQuotaMap[path]) + if err != nil { + return nil, err + } + return resource.NewQuantity(ibytes, resource.DecimalSI), nil +} + +// GetInodes -- retrieve the number of inodes in use under the directory +func GetInodes(path string) (*resource.Quantity, error) { + // Note that we actually need to hold the lock at least through + // running the quota command, so it can't get recycled behind our back + quotaLock.Lock() + defer quotaLock.Unlock() + applier := getApplier(path) + // No applier means directory is not under quota management + if applier == nil { + return nil, nil + } + inodes, err := applier.GetInodes(path, dirQuotaMap[path]) + if err != nil { + return nil, err + } + return resource.NewQuantity(inodes, resource.DecimalSI), nil +} + +// ClearQuota -- remove the quota assigned to a directory +func ClearQuota(m mount.Interface, path string) error { + klog.V(3).Infof("ClearQuota %s", path) + if !enabledQuotasForMonitoring() { + return fmt.Errorf("clearQuota called, but quotas disabled") + } + quotaLock.Lock() + defer quotaLock.Unlock() + poduid, ok := dirPodMap[path] + if !ok { + // Nothing in the map either means that there was no + // quota to begin with or that we're clearing a + // stale directory, so if we find a quota, just remove it. + // The process of clearing the quota requires that an applier + // be found, which needs to be cleaned up. + defer delete(supportsQuotasMap, path) + defer clearApplier(path) + return clearQuotaOnDir(m, path) + } + _, ok = podQuotaMap[poduid] + if !ok { + return fmt.Errorf("clearQuota: No quota available for %s", path) + } + projid, err := getQuotaOnDir(m, path) + if err != nil { + // Log-and-continue instead of returning an error for now + // due to unspecified backwards compatibility concerns (a subject to revise) + klog.V(3).Infof("Attempt to check quota ID %v on dir %s failed: %v", dirQuotaMap[path], path, err) + } + if projid != dirQuotaMap[path] { + return fmt.Errorf("expected quota ID %v on dir %s does not match actual %v", dirQuotaMap[path], path, projid) + } + count, ok := podDirCountMap[poduid] + if count <= 1 || !ok { + err = clearQuotaOnDir(m, path) + // This error should be noted; we still need to clean up + // and otherwise handle in the same way. + if err != nil { + klog.V(3).Infof("Unable to clear quota %v %s: %v", dirQuotaMap[path], path, err) + } + delete(quotaSizeMap, podQuotaMap[poduid]) + delete(quotaPodMap, podQuotaMap[poduid]) + delete(podDirCountMap, poduid) + delete(podQuotaMap, poduid) + } else { + err = removeProjectID(path, projid) + podDirCountMap[poduid]-- + klog.V(4).Infof("Not clearing quota for pod %s; still %v dirs outstanding", poduid, podDirCountMap[poduid]) + } + delete(dirPodMap, path) + delete(dirQuotaMap, path) + delete(supportsQuotasMap, path) + clearApplier(path) + if err != nil { + return fmt.Errorf("unable to clear quota for %s: %v", path, err) + } + return nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/quota_unsupported.go b/vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/quota_unsupported.go new file mode 100644 index 000000000..8579f5389 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/fsquota/quota_unsupported.go @@ -0,0 +1,59 @@ +//go:build !linux +// +build !linux + +/* +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 fsquota + +import ( + "errors" + + "k8s.io/mount-utils" + + "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/types" +) + +// Dummy quota implementation for systems that do not implement support +// for volume quotas + +var errNotImplemented = errors.New("not implemented") + +// SupportsQuotas -- dummy implementation +func SupportsQuotas(_ mount.Interface, _ string) (bool, error) { + return false, errNotImplemented +} + +// AssignQuota -- dummy implementation +func AssignQuota(_ mount.Interface, _ string, _ types.UID, _ *resource.Quantity) error { + return errNotImplemented +} + +// GetConsumption -- dummy implementation +func GetConsumption(_ string) (*resource.Quantity, error) { + return nil, errNotImplemented +} + +// GetInodes -- dummy implementation +func GetInodes(_ string) (*resource.Quantity, error) { + return nil, errNotImplemented +} + +// ClearQuota -- dummy implementation +func ClearQuota(_ mount.Interface, _ string) error { + return errNotImplemented +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/hostutil/fake_hostutil.go b/vendor/k8s.io/kubernetes/pkg/volume/util/hostutil/fake_hostutil.go new file mode 100644 index 000000000..0efccb3e3 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/hostutil/fake_hostutil.go @@ -0,0 +1,124 @@ +/* +Copyright 2015 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 hostutil + +import ( + "errors" + "os" + "sync" + + "k8s.io/mount-utils" +) + +// FakeHostUtil is a fake HostUtils implementation for testing +type FakeHostUtil struct { + MountPoints []mount.MountPoint + Filesystem map[string]FileType + + mutex sync.Mutex +} + +// NewFakeHostUtil returns a struct that implements the HostUtils interface +// for testing +// TODO: no callers were initializing the struct with any MountPoints. Check +// if those are still being used by any callers and if MountPoints still need +// to be a part of the struct. +func NewFakeHostUtil(fs map[string]FileType) *FakeHostUtil { + return &FakeHostUtil{ + Filesystem: fs, + } +} + +// Compile-time check to make sure FakeHostUtil implements interface +var _ HostUtils = &FakeHostUtil{} + +// DeviceOpened checks if block device referenced by pathname is in use by +// checking if is listed as a device in the in-memory mountpoint table. +func (hu *FakeHostUtil) DeviceOpened(pathname string) (bool, error) { + hu.mutex.Lock() + defer hu.mutex.Unlock() + + for _, mp := range hu.MountPoints { + if mp.Device == pathname { + return true, nil + } + } + return false, nil +} + +// PathIsDevice always returns true +func (hu *FakeHostUtil) PathIsDevice(pathname string) (bool, error) { + return true, nil +} + +// GetDeviceNameFromMount given a mount point, find the volume id +func (hu *FakeHostUtil) GetDeviceNameFromMount(mounter mount.Interface, mountPath, pluginMountDir string) (string, error) { + return getDeviceNameFromMount(mounter, mountPath, pluginMountDir) +} + +// MakeRShared checks if path is shared and bind-mounts it as rshared if needed. +// No-op for testing +func (hu *FakeHostUtil) MakeRShared(path string) error { + return nil +} + +// GetFileType checks for file/directory/socket/block/character devices. +// Defaults to Directory if otherwise unspecified. +func (hu *FakeHostUtil) GetFileType(pathname string) (FileType, error) { + if t, ok := hu.Filesystem[pathname]; ok { + return t, nil + } + return FileType("Directory"), nil +} + +// PathExists checks if pathname exists. +func (hu *FakeHostUtil) PathExists(pathname string) (bool, error) { + if _, ok := hu.Filesystem[pathname]; ok { + return true, nil + } + return false, nil +} + +// EvalHostSymlinks returns the path name after evaluating symlinks. +// No-op for testing +func (hu *FakeHostUtil) EvalHostSymlinks(pathname string) (string, error) { + return pathname, nil +} + +// GetOwner returns the integer ID for the user and group of the given path +// Not implemented for testing +func (hu *FakeHostUtil) GetOwner(pathname string) (int64, int64, error) { + return -1, -1, errors.New("GetOwner not implemented") +} + +// GetSELinuxSupport tests if pathname is on a mount that supports SELinux. +// Not implemented for testing +func (hu *FakeHostUtil) GetSELinuxSupport(pathname string) (bool, error) { + return false, nil +} + +// GetMode returns permissions of pathname. +// Not implemented for testing +func (hu *FakeHostUtil) GetMode(pathname string) (os.FileMode, error) { + return 0, errors.New("not implemented") +} + +// GetSELinuxMountContext returns value of -o context=XYZ mount option on +// given mount point. +func (hu *FakeHostUtil) GetSELinuxMountContext(pathname string) (string, error) { + return "", errors.New("not implemented") +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/hostutil/hostutil.go b/vendor/k8s.io/kubernetes/pkg/volume/util/hostutil/hostutil.go new file mode 100644 index 000000000..dfe165aae --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/hostutil/hostutil.go @@ -0,0 +1,112 @@ +/* +Copyright 2014 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 hostutil + +import ( + "fmt" + "os" + + "k8s.io/mount-utils" +) + +// FileType enumerates the known set of possible file types. +type FileType string + +const ( + // FileTypeBlockDev defines a constant for the block device FileType. + FileTypeBlockDev FileType = "BlockDevice" + // FileTypeCharDev defines a constant for the character device FileType. + FileTypeCharDev FileType = "CharDevice" + // FileTypeDirectory defines a constant for the directory FileType. + FileTypeDirectory FileType = "Directory" + // FileTypeFile defines a constant for the file FileType. + FileTypeFile FileType = "File" + // FileTypeSocket defines a constant for the socket FileType. + FileTypeSocket FileType = "Socket" + // FileTypeUnknown defines a constant for an unknown FileType. + FileTypeUnknown FileType = "" +) + +// HostUtils defines the set of methods for interacting with paths on a host. +type HostUtils interface { + // DeviceOpened determines if the device (e.g. /dev/sdc) is in use elsewhere + // on the system, i.e. still mounted. + DeviceOpened(pathname string) (bool, error) + // PathIsDevice determines if a path is a device. + PathIsDevice(pathname string) (bool, error) + // GetDeviceNameFromMount finds the device name by checking the mount path + // to get the global mount path within its plugin directory. + GetDeviceNameFromMount(mounter mount.Interface, mountPath, pluginMountDir string) (string, error) + // MakeRShared checks that given path is on a mount with 'rshared' mount + // propagation. If not, it bind-mounts the path as rshared. + MakeRShared(path string) error + // GetFileType checks for file/directory/socket/block/character devices. + GetFileType(pathname string) (FileType, error) + // PathExists tests if the given path already exists + // Error is returned on any other error than "file not found". + PathExists(pathname string) (bool, error) + // EvalHostSymlinks returns the path name after evaluating symlinks. + EvalHostSymlinks(pathname string) (string, error) + // GetOwner returns the integer ID for the user and group of the given path + GetOwner(pathname string) (int64, int64, error) + // GetSELinuxSupport returns true if given path is on a mount that supports + // SELinux. + GetSELinuxSupport(pathname string) (bool, error) + // GetMode returns permissions of the path. + GetMode(pathname string) (os.FileMode, error) + // GetSELinuxMountContext returns value of -o context=XYZ mount option on + // given mount point. + GetSELinuxMountContext(pathname string) (string, error) +} + +// Compile-time check to ensure all HostUtil implementations satisfy +// the Interface. +var _ HostUtils = &HostUtil{} + +// getFileType checks for file/directory/socket and block/character devices. +func getFileType(pathname string) (FileType, error) { + var pathType FileType + info, err := os.Stat(pathname) + if os.IsNotExist(err) { + return pathType, fmt.Errorf("path %q does not exist", pathname) + } + // err in call to os.Stat + if err != nil { + return pathType, err + } + + // checks whether the mode is the target mode. + isSpecificMode := func(mode, targetMode os.FileMode) bool { + return mode&targetMode == targetMode + } + + mode := info.Mode() + if mode.IsDir() { + return FileTypeDirectory, nil + } else if mode.IsRegular() { + return FileTypeFile, nil + } else if isSpecificMode(mode, os.ModeSocket) { + return FileTypeSocket, nil + } else if isSpecificMode(mode, os.ModeDevice) { + if isSpecificMode(mode, os.ModeCharDevice) { + return FileTypeCharDev, nil + } + return FileTypeBlockDev, nil + } + + return pathType, fmt.Errorf("only recognise file, directory, socket, block device and character device") +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/hostutil/hostutil_linux.go b/vendor/k8s.io/kubernetes/pkg/volume/util/hostutil/hostutil_linux.go new file mode 100644 index 000000000..5c687d9f4 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/hostutil/hostutil_linux.go @@ -0,0 +1,333 @@ +//go:build linux +// +build linux + +/* +Copyright 2014 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 hostutil + +import ( + "fmt" + "os" + "path" + "path/filepath" + "strings" + "syscall" + + "github.com/opencontainers/selinux/go-selinux" + "golang.org/x/sys/unix" + "k8s.io/klog/v2" + "k8s.io/mount-utils" + utilpath "k8s.io/utils/path" +) + +const ( + // Location of the mountinfo file + procMountInfoPath = "/proc/self/mountinfo" +) + +// HostUtil implements HostUtils for Linux platforms. +type HostUtil struct { +} + +// NewHostUtil returns a struct that implements the HostUtils interface on +// linux platforms +func NewHostUtil() *HostUtil { + return &HostUtil{} +} + +// DeviceOpened checks if block device in use by calling Open with O_EXCL flag. +// If pathname is not a device, log and return false with nil error. +// If open returns errno EBUSY, return true with nil error. +// If open returns nil, return false with nil error. +// Otherwise, return false with error +func (hu *HostUtil) DeviceOpened(pathname string) (bool, error) { + return ExclusiveOpenFailsOnDevice(pathname) +} + +// PathIsDevice uses FileInfo returned from os.Stat to check if path refers +// to a device. +func (hu *HostUtil) PathIsDevice(pathname string) (bool, error) { + pathType, err := hu.GetFileType(pathname) + isDevice := pathType == FileTypeCharDev || pathType == FileTypeBlockDev + return isDevice, err +} + +// ExclusiveOpenFailsOnDevice is shared with NsEnterMounter +func ExclusiveOpenFailsOnDevice(pathname string) (bool, error) { + var isDevice bool + finfo, err := os.Stat(pathname) + if os.IsNotExist(err) { + isDevice = false + } + // err in call to os.Stat + if err != nil { + return false, fmt.Errorf( + "PathIsDevice failed for path %q: %v", + pathname, + err) + } + // path refers to a device + if finfo.Mode()&os.ModeDevice != 0 { + isDevice = true + } + + if !isDevice { + klog.Errorf("Path %q is not referring to a device.", pathname) + return false, nil + } + fd, errno := unix.Open(pathname, unix.O_RDONLY|unix.O_EXCL|unix.O_CLOEXEC, 0) + // If the device is in use, open will return an invalid fd. + // When this happens, it is expected that Close will fail and throw an error. + defer unix.Close(fd) + if errno == nil { + // device not in use + return false, nil + } else if errno == unix.EBUSY { + // device is in use + return true, nil + } + // error during call to Open + return false, errno +} + +// GetDeviceNameFromMount given a mount point, find the device name from its global mount point +func (hu *HostUtil) GetDeviceNameFromMount(mounter mount.Interface, mountPath, pluginMountDir string) (string, error) { + return getDeviceNameFromMount(mounter, mountPath, pluginMountDir) +} + +// getDeviceNameFromMountLinux find the device name from /proc/mounts in which +// the mount path reference should match the given plugin mount directory. In case no mount path reference +// matches, returns the volume name taken from its given mountPath +func getDeviceNameFromMount(mounter mount.Interface, mountPath, pluginMountDir string) (string, error) { + refs, err := mounter.GetMountRefs(mountPath) + if err != nil { + klog.V(4).Infof("GetMountRefs failed for mount path %q: %v", mountPath, err) + return "", err + } + if len(refs) == 0 { + klog.V(4).Infof("Directory %s is not mounted", mountPath) + return "", fmt.Errorf("directory %s is not mounted", mountPath) + } + for _, ref := range refs { + if strings.HasPrefix(ref, pluginMountDir) { + volumeID, err := filepath.Rel(pluginMountDir, ref) + if err != nil { + klog.Errorf("Failed to get volume id from mount %s - %v", mountPath, err) + return "", err + } + return volumeID, nil + } + } + + return path.Base(mountPath), nil +} + +// MakeRShared checks that given path is on a mount with 'rshared' mount +// propagation. If not, it bind-mounts the path as rshared. +func (hu *HostUtil) MakeRShared(path string) error { + return DoMakeRShared(path, procMountInfoPath) +} + +// GetFileType checks for file/directory/socket/block/character devices. +func (hu *HostUtil) GetFileType(pathname string) (FileType, error) { + return getFileType(pathname) +} + +// PathExists tests if the given path already exists +// Error is returned on any other error than "file not found". +func (hu *HostUtil) PathExists(pathname string) (bool, error) { + return utilpath.Exists(utilpath.CheckFollowSymlink, pathname) +} + +// EvalHostSymlinks returns the path name after evaluating symlinks. +// TODO once the nsenter implementation is removed, this method can be removed +// from the interface and filepath.EvalSymlinks used directly +func (hu *HostUtil) EvalHostSymlinks(pathname string) (string, error) { + return filepath.EvalSymlinks(pathname) +} + +// FindMountInfo returns the mount info on the given path. +func (hu *HostUtil) FindMountInfo(path string) (mount.MountInfo, error) { + return findMountInfo(path, procMountInfoPath) +} + +// isShared returns true, if given path is on a mount point that has shared +// mount propagation. +func isShared(mount string, mountInfoPath string) (bool, error) { + info, err := findMountInfo(mount, mountInfoPath) + if err != nil { + return false, err + } + + // parse optional parameters + for _, opt := range info.OptionalFields { + if strings.HasPrefix(opt, "shared:") { + return true, nil + } + } + return false, nil +} + +func findMountInfo(path, mountInfoPath string) (mount.MountInfo, error) { + infos, err := mount.ParseMountInfo(mountInfoPath) + if err != nil { + return mount.MountInfo{}, err + } + + // process /proc/xxx/mountinfo in backward order and find the first mount + // point that is prefix of 'path' - that's the mount where path resides + var info *mount.MountInfo + for i := len(infos) - 1; i >= 0; i-- { + if mount.PathWithinBase(path, infos[i].MountPoint) { + info = &infos[i] + break + } + } + if info == nil { + return mount.MountInfo{}, fmt.Errorf("cannot find mount point for %q", path) + } + return *info, nil +} + +// DoMakeRShared is common implementation of MakeRShared on Linux. It checks if +// path is shared and bind-mounts it as rshared if needed. mountCmd and +// mountArgs are expected to contain mount-like command, DoMakeRShared will add +// '--bind ' and '--make-rshared ' to mountArgs. +func DoMakeRShared(path string, mountInfoFilename string) error { + shared, err := isShared(path, mountInfoFilename) + if err != nil { + return err + } + if shared { + klog.V(4).Infof("Directory %s is already on a shared mount", path) + return nil + } + + klog.V(2).Infof("Bind-mounting %q with shared mount propagation", path) + // mount --bind /var/lib/kubelet /var/lib/kubelet + if err := syscall.Mount(path, path, "" /*fstype*/, syscall.MS_BIND, "" /*data*/); err != nil { + return fmt.Errorf("failed to bind-mount %s: %v", path, err) + } + + // mount --make-rshared /var/lib/kubelet + if err := syscall.Mount(path, path, "" /*fstype*/, syscall.MS_SHARED|syscall.MS_REC, "" /*data*/); err != nil { + return fmt.Errorf("failed to make %s rshared: %v", path, err) + } + + return nil +} + +// selinux.SELinuxEnabled implementation for unit tests +type seLinuxEnabledFunc func() bool + +// GetSELinux is common implementation of GetSELinuxSupport on Linux. +func GetSELinux(path string, mountInfoFilename string, selinuxEnabled seLinuxEnabledFunc) (bool, error) { + // Skip /proc/mounts parsing if SELinux is disabled. + if !selinuxEnabled() { + return false, nil + } + + info, err := findMountInfo(path, mountInfoFilename) + if err != nil { + return false, err + } + + // "seclabel" can be both in mount options and super options. + for _, opt := range info.SuperOptions { + if opt == "seclabel" { + return true, nil + } + } + for _, opt := range info.MountOptions { + if opt == "seclabel" { + return true, nil + } + } + return false, nil +} + +// GetSELinuxSupport returns true if given path is on a mount that supports +// SELinux. +func (hu *HostUtil) GetSELinuxSupport(pathname string) (bool, error) { + return GetSELinux(pathname, procMountInfoPath, selinux.GetEnabled) +} + +// GetOwner returns the integer ID for the user and group of the given path +func (hu *HostUtil) GetOwner(pathname string) (int64, int64, error) { + realpath, err := filepath.EvalSymlinks(pathname) + if err != nil { + return -1, -1, err + } + return GetOwnerLinux(realpath) +} + +// GetMode returns permissions of the path. +func (hu *HostUtil) GetMode(pathname string) (os.FileMode, error) { + return GetModeLinux(pathname) +} + +// GetOwnerLinux is shared between Linux and NsEnterMounter +// pathname must already be evaluated for symlinks +func GetOwnerLinux(pathname string) (int64, int64, error) { + info, err := os.Stat(pathname) + if err != nil { + return -1, -1, err + } + stat := info.Sys().(*syscall.Stat_t) + return int64(stat.Uid), int64(stat.Gid), nil +} + +// GetModeLinux is shared between Linux and NsEnterMounter +func GetModeLinux(pathname string) (os.FileMode, error) { + info, err := os.Stat(pathname) + if err != nil { + return 0, err + } + return info.Mode(), nil +} + +// GetSELinuxMountContext returns value of -o context=XYZ mount option on +// given mount point. +func (hu *HostUtil) GetSELinuxMountContext(pathname string) (string, error) { + return getSELinuxMountContext(pathname, procMountInfoPath, selinux.GetEnabled) +} + +// getSELinux is common implementation of GetSELinuxSupport on Linux. +// Using an extra function for unit tests. +func getSELinuxMountContext(path string, mountInfoFilename string, selinuxEnabled seLinuxEnabledFunc) (string, error) { + // Skip /proc/mounts parsing if SELinux is disabled. + if !selinuxEnabled() { + return "", nil + } + + info, err := findMountInfo(path, mountInfoFilename) + if err != nil { + return "", err + } + + for _, opt := range info.SuperOptions { + if !strings.HasPrefix(opt, "context=") { + continue + } + // Remove context= + context := strings.TrimPrefix(opt, "context=") + // Remove double quotes + context = strings.Trim(context, "\"") + return context, nil + } + return "", nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/hostutil/hostutil_unsupported.go b/vendor/k8s.io/kubernetes/pkg/volume/util/hostutil/hostutil_unsupported.go new file mode 100644 index 000000000..c5ff9c0b5 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/hostutil/hostutil_unsupported.go @@ -0,0 +1,109 @@ +//go:build !linux && !windows +// +build !linux,!windows + +/* +Copyright 2014 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 hostutil + +import ( + "errors" + "os" + + "k8s.io/mount-utils" +) + +// HostUtil is an HostUtils implementation that allows compilation on +// unsupported platforms +type HostUtil struct{} + +// NewHostUtil returns a struct that implements the HostUtils interface on +// unsupported platforms +func NewHostUtil() *HostUtil { + return &HostUtil{} +} + +var errUnsupported = errors.New("volume/util/hostutil on this platform is not supported") + +// DeviceOpened always returns an error on unsupported platforms +func (hu *HostUtil) DeviceOpened(pathname string) (bool, error) { + return false, errUnsupported +} + +// PathIsDevice always returns an error on unsupported platforms +func (hu *HostUtil) PathIsDevice(pathname string) (bool, error) { + return true, errUnsupported +} + +// GetDeviceNameFromMount always returns an error on unsupported platforms +func (hu *HostUtil) GetDeviceNameFromMount(mounter mount.Interface, mountPath, pluginMountDir string) (string, error) { + return getDeviceNameFromMount(mounter, mountPath, pluginMountDir) +} + +// MakeRShared always returns an error on unsupported platforms +func (hu *HostUtil) MakeRShared(path string) error { + return errUnsupported +} + +// GetFileType always returns an error on unsupported platforms +func (hu *HostUtil) GetFileType(pathname string) (FileType, error) { + return FileType("fake"), errUnsupported +} + +// MakeFile always returns an error on unsupported platforms +func (hu *HostUtil) MakeFile(pathname string) error { + return errUnsupported +} + +// MakeDir always returns an error on unsupported platforms +func (hu *HostUtil) MakeDir(pathname string) error { + return errUnsupported +} + +// PathExists always returns an error on unsupported platforms +func (hu *HostUtil) PathExists(pathname string) (bool, error) { + return true, errUnsupported +} + +// EvalHostSymlinks always returns an error on unsupported platforms +func (hu *HostUtil) EvalHostSymlinks(pathname string) (string, error) { + return "", errUnsupported +} + +// GetOwner always returns an error on unsupported platforms +func (hu *HostUtil) GetOwner(pathname string) (int64, int64, error) { + return -1, -1, errUnsupported +} + +// GetSELinuxSupport always returns an error on unsupported platforms +func (hu *HostUtil) GetSELinuxSupport(pathname string) (bool, error) { + return false, errUnsupported +} + +// GetMode always returns an error on unsupported platforms +func (hu *HostUtil) GetMode(pathname string) (os.FileMode, error) { + return 0, errUnsupported +} + +func getDeviceNameFromMount(mounter mount.Interface, mountPath, pluginMountDir string) (string, error) { + return "", errUnsupported +} + +// GetSELinuxMountContext returns value of -o context=XYZ mount option on +// given mount point. +func (hu *HostUtil) GetSELinuxMountContext(pathname string) (string, error) { + return "", errUnsupported +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/hostutil/hostutil_windows.go b/vendor/k8s.io/kubernetes/pkg/volume/util/hostutil/hostutil_windows.go new file mode 100644 index 000000000..c039ada40 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/hostutil/hostutil_windows.go @@ -0,0 +1,131 @@ +//go:build windows +// +build windows + +/* +Copyright 2017 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 hostutil + +import ( + "fmt" + "os" + "path" + "path/filepath" + "strings" + + "k8s.io/klog/v2" + "k8s.io/mount-utils" + utilpath "k8s.io/utils/path" +) + +// HostUtil implements HostUtils for Windows platforms. +type HostUtil struct{} + +// NewHostUtil returns a struct that implements HostUtils on Windows platforms +func NewHostUtil() *HostUtil { + return &HostUtil{} +} + +// GetDeviceNameFromMount given a mnt point, find the device +func (hu *HostUtil) GetDeviceNameFromMount(mounter mount.Interface, mountPath, pluginMountDir string) (string, error) { + return getDeviceNameFromMount(mounter, mountPath, pluginMountDir) +} + +// getDeviceNameFromMount find the device(drive) name in which +// the mount path reference should match the given plugin mount directory. In case no mount path reference +// matches, returns the volume name taken from its given mountPath +func getDeviceNameFromMount(mounter mount.Interface, mountPath, pluginMountDir string) (string, error) { + refs, err := mounter.GetMountRefs(mountPath) + if err != nil { + klog.V(4).Infof("GetMountRefs failed for mount path %q: %v", mountPath, err) + return "", err + } + if len(refs) == 0 { + return "", fmt.Errorf("directory %s is not mounted", mountPath) + } + basemountPath := mount.NormalizeWindowsPath(pluginMountDir) + for _, ref := range refs { + if strings.Contains(ref, basemountPath) { + volumeID, err := filepath.Rel(mount.NormalizeWindowsPath(basemountPath), ref) + if err != nil { + klog.Errorf("Failed to get volume id from mount %s - %v", mountPath, err) + return "", err + } + return volumeID, nil + } + } + + return path.Base(mountPath), nil +} + +// DeviceOpened determines if the device is in use elsewhere +func (hu *HostUtil) DeviceOpened(pathname string) (bool, error) { + return false, nil +} + +// PathIsDevice determines if a path is a device. +func (hu *HostUtil) PathIsDevice(pathname string) (bool, error) { + return false, nil +} + +// MakeRShared checks that given path is on a mount with 'rshared' mount +// propagation. Empty implementation here. +func (hu *HostUtil) MakeRShared(path string) error { + return nil +} + +// GetFileType checks for sockets/block/character devices +func (hu *(HostUtil)) GetFileType(pathname string) (FileType, error) { + return getFileType(pathname) +} + +// PathExists checks whether the path exists +func (hu *HostUtil) PathExists(pathname string) (bool, error) { + return utilpath.Exists(utilpath.CheckFollowSymlink, pathname) +} + +// EvalHostSymlinks returns the path name after evaluating symlinks +func (hu *HostUtil) EvalHostSymlinks(pathname string) (string, error) { + return filepath.EvalSymlinks(pathname) +} + +// GetOwner returns the integer ID for the user and group of the given path +// Note that on windows, it always returns 0. We actually don't set Group on +// windows platform, see SetVolumeOwnership implementation. +func (hu *HostUtil) GetOwner(pathname string) (int64, int64, error) { + return -1, -1, nil +} + +// GetSELinuxSupport returns a boolean indicating support for SELinux. +// Windows does not support SELinux. +func (hu *HostUtil) GetSELinuxSupport(pathname string) (bool, error) { + return false, nil +} + +// GetMode returns permissions of the path. +func (hu *HostUtil) GetMode(pathname string) (os.FileMode, error) { + info, err := os.Stat(pathname) + if err != nil { + return 0, err + } + return info.Mode(), nil +} + +// GetSELinuxMountContext returns value of -o context=XYZ mount option on +// given mount point. +func (hu *HostUtil) GetSELinuxMountContext(pathname string) (string, error) { + return "", nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/io_util.go b/vendor/k8s.io/kubernetes/pkg/volume/util/io_util.go new file mode 100644 index 000000000..8d65a6e48 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/io_util.go @@ -0,0 +1,51 @@ +/* +Copyright 2016 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 util + +import ( + "io/ioutil" + "os" + "path/filepath" +) + +// IoUtil is a mockable util for common IO operations +type IoUtil interface { + ReadFile(filename string) ([]byte, error) + ReadDir(dirname string) ([]os.FileInfo, error) + Lstat(name string) (os.FileInfo, error) + EvalSymlinks(path string) (string, error) +} + +type osIOHandler struct{} + +// NewIOHandler Create a new IoHandler implementation +func NewIOHandler() IoUtil { + return &osIOHandler{} +} + +func (handler *osIOHandler) ReadFile(filename string) ([]byte, error) { + return ioutil.ReadFile(filename) +} +func (handler *osIOHandler) ReadDir(dirname string) ([]os.FileInfo, error) { + return ioutil.ReadDir(dirname) +} +func (handler *osIOHandler) Lstat(name string) (os.FileInfo, error) { + return os.Lstat(name) +} +func (handler *osIOHandler) EvalSymlinks(path string) (string, error) { + return filepath.EvalSymlinks(path) +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/metrics.go b/vendor/k8s.io/kubernetes/pkg/volume/util/metrics.go new file mode 100644 index 000000000..0eb030b35 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/metrics.go @@ -0,0 +1,161 @@ +/* +Copyright 2017 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 util + +import ( + "fmt" + "strconv" + "time" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "k8s.io/component-base/metrics" + "k8s.io/component-base/metrics/legacyregistry" + "k8s.io/kubernetes/pkg/volume" + "k8s.io/kubernetes/pkg/volume/util/types" +) + +const ( + statusSuccess = "success" + statusFailUnknown = "fail-unknown" +) + +/* + * By default, all the following metrics are defined as falling under + * ALPHA stability level https://github.com/kubernetes/enhancements/blob/master/keps/sig-instrumentation/1209-metrics-stability/kubernetes-control-plane-metrics-stability.md#stability-classes) + * + * Promoting the stability level of the metric is a responsibility of the component owner, since it + * involves explicitly acknowledging support for the metric across multiple releases, in accordance with + * the metric stability policy. + */ + +var StorageOperationMetric = metrics.NewHistogramVec( + &metrics.HistogramOpts{ + Name: "storage_operation_duration_seconds", + Help: "Storage operation duration", + Buckets: []float64{.1, .25, .5, 1, 2.5, 5, 10, 15, 25, 50, 120, 300, 600}, + StabilityLevel: metrics.ALPHA, + }, + []string{"volume_plugin", "operation_name", "status", "migrated"}, +) + +var storageOperationEndToEndLatencyMetric = metrics.NewHistogramVec( + &metrics.HistogramOpts{ + Name: "volume_operation_total_seconds", + Help: "Storage operation end to end duration in seconds", + Buckets: []float64{.1, .25, .5, 1, 2.5, 5, 10, 15, 25, 50, 120, 300, 600}, + StabilityLevel: metrics.ALPHA, + }, + []string{"plugin_name", "operation_name"}, +) + +var csiOperationsLatencyMetric = metrics.NewHistogramVec( + &metrics.HistogramOpts{ + Subsystem: "csi", + Name: "operations_seconds", + Help: "Container Storage Interface operation duration with gRPC error code status total", + Buckets: []float64{.1, .25, .5, 1, 2.5, 5, 10, 15, 25, 50, 120, 300, 600}, + StabilityLevel: metrics.ALPHA, + }, + []string{"driver_name", "method_name", "grpc_status_code", "migrated"}, +) + +func init() { + registerMetrics() +} + +func registerMetrics() { + // legacyregistry is the internal k8s wrapper around the prometheus + // global registry, used specifically for metric stability enforcement + legacyregistry.MustRegister(StorageOperationMetric) + legacyregistry.MustRegister(storageOperationEndToEndLatencyMetric) + legacyregistry.MustRegister(csiOperationsLatencyMetric) +} + +// OperationCompleteHook returns a hook to call when an operation is completed +func OperationCompleteHook(plugin, operationName string) func(types.CompleteFuncParam) { + requestTime := time.Now() + opComplete := func(c types.CompleteFuncParam) { + timeTaken := time.Since(requestTime).Seconds() + // Create metric with operation name and plugin name + status := statusSuccess + if *c.Err != nil { + // TODO: Establish well-known error codes to be able to distinguish + // user configuration errors from system errors. + status = statusFailUnknown + } + migrated := false + if c.Migrated != nil { + migrated = *c.Migrated + } + StorageOperationMetric.WithLabelValues(plugin, operationName, status, strconv.FormatBool(migrated)).Observe(timeTaken) + } + return opComplete +} + +// FSGroupCompleteHook returns a hook to call when volume recursive permission is changed +func FSGroupCompleteHook(plugin volume.VolumePlugin, spec *volume.Spec) func(types.CompleteFuncParam) { + return OperationCompleteHook(GetFullQualifiedPluginNameForVolume(plugin.GetPluginName(), spec), "volume_apply_access_control") +} + +// GetFullQualifiedPluginNameForVolume returns full qualified plugin name for +// given volume. For CSI plugin, it appends plugin driver name at the end of +// plugin name, e.g. kubernetes.io/csi:csi-hostpath. It helps to distinguish +// between metrics emitted for CSI volumes which may be handled by different +// CSI plugin drivers. +func GetFullQualifiedPluginNameForVolume(pluginName string, spec *volume.Spec) string { + if spec != nil { + if spec.Volume != nil && spec.Volume.CSI != nil { + return fmt.Sprintf("%s:%s", pluginName, spec.Volume.CSI.Driver) + } + if spec.PersistentVolume != nil && spec.PersistentVolume.Spec.CSI != nil { + return fmt.Sprintf("%s:%s", pluginName, spec.PersistentVolume.Spec.CSI.Driver) + } + } + return pluginName +} + +// RecordOperationLatencyMetric records the end to end latency for certain operation +// into metric volume_operation_total_seconds +func RecordOperationLatencyMetric(plugin, operationName string, secondsTaken float64) { + storageOperationEndToEndLatencyMetric.WithLabelValues(plugin, operationName).Observe(secondsTaken) +} + +// RecordCSIOperationLatencyMetrics records the CSI operation latency and grpc status +// into metric csi_kubelet_operations_seconds +func RecordCSIOperationLatencyMetrics(driverName string, + operationName string, + operationErr error, + operationDuration time.Duration, + migrated string) { + csiOperationsLatencyMetric.WithLabelValues(driverName, operationName, getErrorCode(operationErr), migrated).Observe(operationDuration.Seconds()) +} + +func getErrorCode(err error) string { + if err == nil { + return codes.OK.String() + } + + st, ok := status.FromError(err) + if !ok { + // This is not gRPC error. The operation must have failed before gRPC + // method was called, otherwise we would get gRPC error. + return "unknown-non-grpc" + } + + return st.Code().String() +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/nested_volumes.go b/vendor/k8s.io/kubernetes/pkg/volume/util/nested_volumes.go new file mode 100644 index 000000000..27a6c29cd --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/nested_volumes.go @@ -0,0 +1,114 @@ +/* +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 util + +import ( + "fmt" + "os" + "path/filepath" + "sort" + "strings" + + v1 "k8s.io/api/core/v1" + podutil "k8s.io/kubernetes/pkg/api/v1/pod" +) + +// getNestedMountpoints returns a list of mountpoint directories that should be created +// for the volume indicated by name. +// note: the returned list is relative to baseDir +func getNestedMountpoints(name, baseDir string, pod v1.Pod) ([]string, error) { + var retval []string + checkContainer := func(container *v1.Container) error { + var allMountPoints []string // all mount points in this container + var myMountPoints []string // mount points that match name + for _, vol := range container.VolumeMounts { + cleaned := filepath.Clean(vol.MountPath) + allMountPoints = append(allMountPoints, cleaned) + if vol.Name == name { + myMountPoints = append(myMountPoints, cleaned) + } + } + sort.Strings(allMountPoints) + parentPrefix := ".." + string(os.PathSeparator) + // Examine each place where this volume is mounted + for _, myMountPoint := range myMountPoints { + if strings.HasPrefix(myMountPoint, parentPrefix) { + // Don't let a container trick us into creating directories outside of its rootfs + return fmt.Errorf("invalid container mount point %v", myMountPoint) + } + myMPSlash := myMountPoint + string(os.PathSeparator) + // The previously found nested mountpoints. + // NOTE: We can't simply rely on sort.Strings to have all the mountpoints sorted and + // grouped. For example, the following strings are sorted in this exact order: + // /dir/nested, /dir/nested-vol, /dir/nested.vol, /dir/nested/double, /dir/nested2 + // The issue is a bit worse for Windows paths, since the \'s value is higher than /'s: + // \dir\nested, \dir\nested-vol, \dir\nested.vol, \dir\nested2, \dir\nested\double + // Because of this, we should use a list of previously mounted mountpoints, rather than only one. + prevNestedMPs := []string{} + // examine each mount point to see if it's nested beneath this volume + // (but skip any that are double-nested beneath this volume) + // For example, if this volume is mounted as /dir and other volumes are mounted + // as /dir/nested and /dir/nested/other, only create /dir/nested. + for _, mp := range allMountPoints { + if !strings.HasPrefix(mp, myMPSlash) { + continue // skip -- not nested beneath myMountPoint + } + + isNested := false + for _, prevNestedMP := range prevNestedMPs { + if strings.HasPrefix(mp, prevNestedMP) { + isNested = true + break + } + } + if isNested { + continue // skip -- double nested beneath myMountPoint + } + // since this mount point is nested, remember it so that we can check that following ones aren't nested beneath this one + prevNestedMPs = append(prevNestedMPs, mp+string(os.PathSeparator)) + retval = append(retval, mp[len(myMPSlash):]) + } + } + return nil + } + + var retErr error + podutil.VisitContainers(&pod.Spec, podutil.AllFeatureEnabledContainers(), func(c *v1.Container, containerType podutil.ContainerType) bool { + retErr = checkContainer(c) + return retErr == nil + }) + if retErr != nil { + return nil, retErr + } + + return retval, nil +} + +// MakeNestedMountpoints creates mount points in baseDir for volumes mounted beneath name +func MakeNestedMountpoints(name, baseDir string, pod v1.Pod) error { + dirs, err := getNestedMountpoints(name, baseDir, pod) + if err != nil { + return err + } + for _, dir := range dirs { + err := os.MkdirAll(filepath.Join(baseDir, dir), 0755) + if err != nil { + return fmt.Errorf("unable to create nested volume mountpoints: %v", err) + } + } + return nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/recyclerclient/recycler_client.go b/vendor/k8s.io/kubernetes/pkg/volume/util/recyclerclient/recycler_client.go new file mode 100644 index 000000000..b7197dbdf --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/recyclerclient/recycler_client.go @@ -0,0 +1,266 @@ +/* +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 recyclerclient + +import ( + "context" + "fmt" + "sync" + + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/watch" + clientset "k8s.io/client-go/kubernetes" + "k8s.io/klog/v2" +) + +// RecycleEventRecorder is a func that defines how to record RecycleEvent. +type RecycleEventRecorder func(eventtype, message string) + +// RecycleVolumeByWatchingPodUntilCompletion is intended for use with volume +// Recyclers. This function will save the given Pod to the API and watch it +// until it completes, fails, or the pod's ActiveDeadlineSeconds is exceeded, +// whichever comes first. An attempt to delete a recycler pod is always +// attempted before returning. +// +// In case there is a pod with the same namespace+name already running, this +// function deletes it as it is not able to judge if it is an old recycler +// or user has forged a fake recycler to block Kubernetes from recycling.// +// +// pod - the pod designed by a volume plugin to recycle the volume. pod.Name +// will be overwritten with unique name based on PV.Name. +// client - kube client for API operations. +func RecycleVolumeByWatchingPodUntilCompletion(pvName string, pod *v1.Pod, kubeClient clientset.Interface, recorder RecycleEventRecorder) error { + return internalRecycleVolumeByWatchingPodUntilCompletion(pvName, pod, newRecyclerClient(kubeClient, recorder)) +} + +// same as above func comments, except 'recyclerClient' is a narrower pod API +// interface to ease testing +func internalRecycleVolumeByWatchingPodUntilCompletion(pvName string, pod *v1.Pod, recyclerClient recyclerClient) error { + klog.V(5).Infof("creating recycler pod for volume %s\n", pod.Name) + + // Generate unique name for the recycler pod - we need to get "already + // exists" error when a previous controller has already started recycling + // the volume. Here we assume that pv.Name is already unique. + pod.Name = "recycler-for-" + pvName + pod.GenerateName = "" + + stopChannel := make(chan struct{}) + defer close(stopChannel) + podCh, err := recyclerClient.WatchPod(pod.Name, pod.Namespace, stopChannel) + if err != nil { + klog.V(4).Infof("cannot start watcher for pod %s/%s: %v", pod.Namespace, pod.Name, err) + return err + } + + // Start the pod + _, err = recyclerClient.CreatePod(pod) + if err != nil { + if errors.IsAlreadyExists(err) { + deleteErr := recyclerClient.DeletePod(pod.Name, pod.Namespace) + if deleteErr != nil { + return fmt.Errorf("failed to delete old recycler pod %s/%s: %s", pod.Namespace, pod.Name, deleteErr) + } + // Recycler will try again and the old pod will be hopefully deleted + // at that time. + return fmt.Errorf("old recycler pod found, will retry later") + } + return fmt.Errorf("unexpected error creating recycler pod: %+v", err) + } + err = waitForPod(pod, recyclerClient, podCh) + + // In all cases delete the recycler pod and log its result. + klog.V(2).Infof("deleting recycler pod %s/%s", pod.Namespace, pod.Name) + deleteErr := recyclerClient.DeletePod(pod.Name, pod.Namespace) + if deleteErr != nil { + klog.Errorf("failed to delete recycler pod %s/%s: %v", pod.Namespace, pod.Name, err) + } + + // Returning recycler error is preferred, the pod will be deleted again on + // the next retry. + if err != nil { + return fmt.Errorf("failed to recycle volume: %s", err) + } + + // Recycle succeeded but we failed to delete the recycler pod. Report it, + // the controller will re-try recycling the PV again shortly. + if deleteErr != nil { + return fmt.Errorf("failed to delete recycler pod: %s", deleteErr) + } + + return nil +} + +// waitForPod watches the pod it until it finishes and send all events on the +// pod to the PV. +func waitForPod(pod *v1.Pod, recyclerClient recyclerClient, podCh <-chan watch.Event) error { + for { + event, ok := <-podCh + if !ok { + return fmt.Errorf("recycler pod %q watch channel had been closed", pod.Name) + } + switch event.Object.(type) { + case *v1.Pod: + // POD changed + pod := event.Object.(*v1.Pod) + klog.V(4).Infof("recycler pod update received: %s %s/%s %s", event.Type, pod.Namespace, pod.Name, pod.Status.Phase) + switch event.Type { + case watch.Added, watch.Modified: + if pod.Status.Phase == v1.PodSucceeded { + // Recycle succeeded. + return nil + } + if pod.Status.Phase == v1.PodFailed { + if pod.Status.Message != "" { + return fmt.Errorf(pod.Status.Message) + } + return fmt.Errorf("pod failed, pod.Status.Message unknown") + } + + case watch.Deleted: + return fmt.Errorf("recycler pod was deleted") + + case watch.Error: + return fmt.Errorf("recycler pod watcher failed") + } + + case *v1.Event: + // Event received + podEvent := event.Object.(*v1.Event) + klog.V(4).Infof("recycler event received: %s %s/%s %s/%s %s", event.Type, podEvent.Namespace, podEvent.Name, podEvent.InvolvedObject.Namespace, podEvent.InvolvedObject.Name, podEvent.Message) + if event.Type == watch.Added { + recyclerClient.Event(podEvent.Type, podEvent.Message) + } + } + } +} + +// recyclerClient abstracts access to a Pod by providing a narrower interface. +// This makes it easier to mock a client for testing. +type recyclerClient interface { + CreatePod(pod *v1.Pod) (*v1.Pod, error) + GetPod(name, namespace string) (*v1.Pod, error) + DeletePod(name, namespace string) error + // WatchPod returns a ListWatch for watching a pod. The stopChannel is used + // to close the reflector backing the watch. The caller is responsible for + // derring a close on the channel to stop the reflector. + WatchPod(name, namespace string, stopChannel chan struct{}) (<-chan watch.Event, error) + // Event sends an event to the volume that is being recycled. + Event(eventtype, message string) +} + +func newRecyclerClient(client clientset.Interface, recorder RecycleEventRecorder) recyclerClient { + return &realRecyclerClient{ + client, + recorder, + } +} + +type realRecyclerClient struct { + client clientset.Interface + recorder RecycleEventRecorder +} + +func (c *realRecyclerClient) CreatePod(pod *v1.Pod) (*v1.Pod, error) { + return c.client.CoreV1().Pods(pod.Namespace).Create(context.TODO(), pod, metav1.CreateOptions{}) +} + +func (c *realRecyclerClient) GetPod(name, namespace string) (*v1.Pod, error) { + return c.client.CoreV1().Pods(namespace).Get(context.TODO(), name, metav1.GetOptions{}) +} + +func (c *realRecyclerClient) DeletePod(name, namespace string) error { + return c.client.CoreV1().Pods(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{}) +} + +func (c *realRecyclerClient) Event(eventtype, message string) { + c.recorder(eventtype, message) +} + +// WatchPod watches a pod and events related to it. It sends pod updates and events over the returned channel +// It will continue until stopChannel is closed +func (c *realRecyclerClient) WatchPod(name, namespace string, stopChannel chan struct{}) (<-chan watch.Event, error) { + podSelector, err := fields.ParseSelector("metadata.name=" + name) + if err != nil { + return nil, err + } + options := metav1.ListOptions{ + FieldSelector: podSelector.String(), + Watch: true, + } + + podWatch, err := c.client.CoreV1().Pods(namespace).Watch(context.TODO(), options) + if err != nil { + return nil, err + } + + eventSelector, _ := fields.ParseSelector("involvedObject.name=" + name) + eventWatch, err := c.client.CoreV1().Events(namespace).Watch(context.TODO(), metav1.ListOptions{ + FieldSelector: eventSelector.String(), + Watch: true, + }) + if err != nil { + podWatch.Stop() + return nil, err + } + + eventCh := make(chan watch.Event, 30) + var wg sync.WaitGroup + wg.Add(2) + + go func() { + defer close(eventCh) + wg.Wait() + }() + + go func() { + defer eventWatch.Stop() + defer wg.Done() + for { + select { + case <-stopChannel: + return + case eventEvent, ok := <-eventWatch.ResultChan(): + if !ok { + return + } + eventCh <- eventEvent + } + } + }() + + go func() { + defer podWatch.Stop() + defer wg.Done() + for { + select { + case <-stopChannel: + return + + case podEvent, ok := <-podWatch.ResultChan(): + if !ok { + return + } + eventCh <- podEvent + } + } + }() + + return eventCh, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/resize_util.go b/vendor/k8s.io/kubernetes/pkg/volume/util/resize_util.go new file mode 100644 index 000000000..d070f2f29 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/resize_util.go @@ -0,0 +1,389 @@ +/* +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 util + +import ( + "context" + "encoding/json" + "fmt" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/strategicpatch" + utilfeature "k8s.io/apiserver/pkg/util/feature" + clientset "k8s.io/client-go/kubernetes" + "k8s.io/kubernetes/pkg/features" + "k8s.io/kubernetes/pkg/volume" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" + "k8s.io/mount-utils" +) + +var ( + knownResizeConditions = map[v1.PersistentVolumeClaimConditionType]bool{ + v1.PersistentVolumeClaimFileSystemResizePending: true, + v1.PersistentVolumeClaimResizing: true, + } + + // AnnPreResizeCapacity annotation is added to a PV when expanding volume. + // Its value is status capacity of the PVC prior to the volume expansion + // Its value will be set by the external-resizer when it deems that filesystem resize is required after resizing volume. + // Its value will be used by pv_controller to determine pvc's status capacity when binding pvc and pv. + AnnPreResizeCapacity = "volume.alpha.kubernetes.io/pre-resize-capacity" +) + +type resizeProcessStatus struct { + condition v1.PersistentVolumeClaimCondition + processed bool +} + +// UpdatePVSize updates just pv size after cloudprovider resizing is successful +func UpdatePVSize( + pv *v1.PersistentVolume, + newSize resource.Quantity, + kubeClient clientset.Interface) (*v1.PersistentVolume, error) { + pvClone := pv.DeepCopy() + pvClone.Spec.Capacity[v1.ResourceStorage] = newSize + + return PatchPV(pv, pvClone, kubeClient) +} + +// AddAnnPreResizeCapacity adds volume.alpha.kubernetes.io/pre-resize-capacity from the pv +func AddAnnPreResizeCapacity( + pv *v1.PersistentVolume, + oldCapacity resource.Quantity, + kubeClient clientset.Interface) error { + // if the pv already has a resize annotation skip the process + if metav1.HasAnnotation(pv.ObjectMeta, AnnPreResizeCapacity) { + return nil + } + + pvClone := pv.DeepCopy() + if pvClone.ObjectMeta.Annotations == nil { + pvClone.ObjectMeta.Annotations = make(map[string]string) + } + pvClone.ObjectMeta.Annotations[AnnPreResizeCapacity] = oldCapacity.String() + + _, err := PatchPV(pv, pvClone, kubeClient) + return err +} + +// DeleteAnnPreResizeCapacity deletes volume.alpha.kubernetes.io/pre-resize-capacity from the pv +func DeleteAnnPreResizeCapacity( + pv *v1.PersistentVolume, + kubeClient clientset.Interface) error { + // if the pv does not have a resize annotation skip the entire process + if !metav1.HasAnnotation(pv.ObjectMeta, AnnPreResizeCapacity) { + return nil + } + pvClone := pv.DeepCopy() + delete(pvClone.ObjectMeta.Annotations, AnnPreResizeCapacity) + _, err := PatchPV(pv, pvClone, kubeClient) + return err +} + +// PatchPV creates and executes a patch for pv +func PatchPV( + oldPV *v1.PersistentVolume, + newPV *v1.PersistentVolume, + kubeClient clientset.Interface) (*v1.PersistentVolume, error) { + oldData, err := json.Marshal(oldPV) + if err != nil { + return oldPV, fmt.Errorf("unexpected error marshaling old PV %q with error : %v", oldPV.Name, err) + } + + newData, err := json.Marshal(newPV) + if err != nil { + return oldPV, fmt.Errorf("unexpected error marshaling new PV %q with error : %v", newPV.Name, err) + } + + patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, oldPV) + if err != nil { + return oldPV, fmt.Errorf("error Creating two way merge patch for PV %q with error : %v", oldPV.Name, err) + } + + updatedPV, err := kubeClient.CoreV1().PersistentVolumes().Patch(context.TODO(), oldPV.Name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{}) + if err != nil { + return oldPV, fmt.Errorf("error Patching PV %q with error : %v", oldPV.Name, err) + } + return updatedPV, nil +} + +// MarkResizeInProgressWithResizer marks cloudprovider resizing as in progress +// and also annotates the PVC with the name of the resizer. +func MarkResizeInProgressWithResizer( + pvc *v1.PersistentVolumeClaim, + resizerName string, + kubeClient clientset.Interface) (*v1.PersistentVolumeClaim, error) { + // Mark PVC as Resize Started + progressCondition := v1.PersistentVolumeClaimCondition{ + Type: v1.PersistentVolumeClaimResizing, + Status: v1.ConditionTrue, + LastTransitionTime: metav1.Now(), + } + conditions := []v1.PersistentVolumeClaimCondition{progressCondition} + newPVC := pvc.DeepCopy() + newPVC = MergeResizeConditionOnPVC(newPVC, conditions) + newPVC = setResizer(newPVC, resizerName) + return PatchPVCStatus(pvc /*oldPVC*/, newPVC, kubeClient) +} + +func MarkControllerReisizeInProgress(pvc *v1.PersistentVolumeClaim, resizerName string, newSize resource.Quantity, kubeClient clientset.Interface) (*v1.PersistentVolumeClaim, error) { + // Mark PVC as Resize Started + progressCondition := v1.PersistentVolumeClaimCondition{ + Type: v1.PersistentVolumeClaimResizing, + Status: v1.ConditionTrue, + LastTransitionTime: metav1.Now(), + } + controllerExpansionInProgress := v1.PersistentVolumeClaimControllerExpansionInProgress + conditions := []v1.PersistentVolumeClaimCondition{progressCondition} + newPVC := pvc.DeepCopy() + newPVC = MergeResizeConditionOnPVC(newPVC, conditions) + newPVC.Status.ResizeStatus = &controllerExpansionInProgress + newPVC.Status.AllocatedResources = v1.ResourceList{v1.ResourceStorage: newSize} + newPVC = setResizer(newPVC, resizerName) + return PatchPVCStatus(pvc /*oldPVC*/, newPVC, kubeClient) +} + +// SetClaimResizer sets resizer annotation on PVC +func SetClaimResizer( + pvc *v1.PersistentVolumeClaim, + resizerName string, + kubeClient clientset.Interface) (*v1.PersistentVolumeClaim, error) { + newPVC := pvc.DeepCopy() + newPVC = setResizer(newPVC, resizerName) + return PatchPVCStatus(pvc /*oldPVC*/, newPVC, kubeClient) +} + +func setResizer(pvc *v1.PersistentVolumeClaim, resizerName string) *v1.PersistentVolumeClaim { + if val, ok := pvc.Annotations[volumetypes.VolumeResizerKey]; ok && val == resizerName { + return pvc + } + metav1.SetMetaDataAnnotation(&pvc.ObjectMeta, volumetypes.VolumeResizerKey, resizerName) + return pvc +} + +// MarkForFSResize marks file system resizing as pending +func MarkForFSResize( + pvc *v1.PersistentVolumeClaim, + kubeClient clientset.Interface) (*v1.PersistentVolumeClaim, error) { + pvcCondition := v1.PersistentVolumeClaimCondition{ + Type: v1.PersistentVolumeClaimFileSystemResizePending, + Status: v1.ConditionTrue, + LastTransitionTime: metav1.Now(), + Message: "Waiting for user to (re-)start a pod to finish file system resize of volume on node.", + } + conditions := []v1.PersistentVolumeClaimCondition{pvcCondition} + newPVC := pvc.DeepCopy() + if utilfeature.DefaultFeatureGate.Enabled(features.RecoverVolumeExpansionFailure) { + expansionPendingOnNode := v1.PersistentVolumeClaimNodeExpansionPending + newPVC.Status.ResizeStatus = &expansionPendingOnNode + } + newPVC = MergeResizeConditionOnPVC(newPVC, conditions) + updatedPVC, err := PatchPVCStatus(pvc /*oldPVC*/, newPVC, kubeClient) + return updatedPVC, err +} + +// MarkResizeFinished marks all resizing as done +func MarkResizeFinished( + pvc *v1.PersistentVolumeClaim, + newSize resource.Quantity, + kubeClient clientset.Interface) (*v1.PersistentVolumeClaim, error) { + return MarkFSResizeFinished(pvc, newSize, kubeClient) +} + +// MarkFSResizeFinished marks file system resizing as done +func MarkFSResizeFinished( + pvc *v1.PersistentVolumeClaim, + newSize resource.Quantity, + kubeClient clientset.Interface) (*v1.PersistentVolumeClaim, error) { + newPVC := pvc.DeepCopy() + + newPVC.Status.Capacity[v1.ResourceStorage] = newSize + + // if RecoverVolumeExpansionFailure is enabled, we need to reset ResizeStatus back to nil + if utilfeature.DefaultFeatureGate.Enabled(features.RecoverVolumeExpansionFailure) { + expansionFinished := v1.PersistentVolumeClaimNoExpansionInProgress + newPVC.Status.ResizeStatus = &expansionFinished + } + + newPVC = MergeResizeConditionOnPVC(newPVC, []v1.PersistentVolumeClaimCondition{}) + updatedPVC, err := PatchPVCStatus(pvc /*oldPVC*/, newPVC, kubeClient) + return updatedPVC, err +} + +func MarkControllerExpansionFailed(pvc *v1.PersistentVolumeClaim, kubeClient clientset.Interface) (*v1.PersistentVolumeClaim, error) { + expansionFailedOnController := v1.PersistentVolumeClaimControllerExpansionFailed + newPVC := pvc.DeepCopy() + newPVC.Status.ResizeStatus = &expansionFailedOnController + patchBytes, err := createPVCPatch(pvc, newPVC, false /* addResourceVersionCheck */) + if err != nil { + return pvc, fmt.Errorf("patchPVCStatus failed to patch PVC %q: %v", pvc.Name, err) + } + + updatedClaim, updateErr := kubeClient.CoreV1().PersistentVolumeClaims(pvc.Namespace). + Patch(context.TODO(), pvc.Name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{}, "status") + if updateErr != nil { + return pvc, fmt.Errorf("patchPVCStatus failed to patch PVC %q: %v", pvc.Name, updateErr) + } + return updatedClaim, nil +} + +// MarkNodeExpansionFailed marks a PVC for node expansion as failed. Kubelet should not retry expansion +// of volumes which are in failed state. +func MarkNodeExpansionFailed(pvc *v1.PersistentVolumeClaim, kubeClient clientset.Interface) (*v1.PersistentVolumeClaim, error) { + expansionFailedOnNode := v1.PersistentVolumeClaimNodeExpansionFailed + newPVC := pvc.DeepCopy() + newPVC.Status.ResizeStatus = &expansionFailedOnNode + patchBytes, err := createPVCPatch(pvc, newPVC, false /* addResourceVersionCheck */) + if err != nil { + return pvc, fmt.Errorf("patchPVCStatus failed to patch PVC %q: %v", pvc.Name, err) + } + + updatedClaim, updateErr := kubeClient.CoreV1().PersistentVolumeClaims(pvc.Namespace). + Patch(context.TODO(), pvc.Name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{}, "status") + if updateErr != nil { + return pvc, fmt.Errorf("patchPVCStatus failed to patch PVC %q: %v", pvc.Name, updateErr) + } + return updatedClaim, nil +} + +// MarkNodeExpansionInProgress marks pvc expansion in progress on node +func MarkNodeExpansionInProgress(pvc *v1.PersistentVolumeClaim, kubeClient clientset.Interface) (*v1.PersistentVolumeClaim, error) { + nodeExpansionInProgress := v1.PersistentVolumeClaimNodeExpansionInProgress + newPVC := pvc.DeepCopy() + newPVC.Status.ResizeStatus = &nodeExpansionInProgress + updatedPVC, err := PatchPVCStatus(pvc /* oldPVC */, newPVC, kubeClient) + return updatedPVC, err +} + +// PatchPVCStatus updates PVC status using PATCH verb +// Don't use Update because this can be called from kubelet and if kubelet has an older client its +// Updates will overwrite new fields. And to avoid writing to a stale object, add ResourceVersion +// to the patch so that Patch will fail if the patch's RV != actual up-to-date RV like Update would +func PatchPVCStatus( + oldPVC *v1.PersistentVolumeClaim, + newPVC *v1.PersistentVolumeClaim, + kubeClient clientset.Interface) (*v1.PersistentVolumeClaim, error) { + patchBytes, err := createPVCPatch(oldPVC, newPVC, true /* addResourceVersionCheck */) + if err != nil { + return oldPVC, fmt.Errorf("patchPVCStatus failed to patch PVC %q: %v", oldPVC.Name, err) + } + + updatedClaim, updateErr := kubeClient.CoreV1().PersistentVolumeClaims(oldPVC.Namespace). + Patch(context.TODO(), oldPVC.Name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{}, "status") + if updateErr != nil { + return oldPVC, fmt.Errorf("patchPVCStatus failed to patch PVC %q: %v", oldPVC.Name, updateErr) + } + return updatedClaim, nil +} + +func createPVCPatch( + oldPVC *v1.PersistentVolumeClaim, + newPVC *v1.PersistentVolumeClaim, addResourceVersionCheck bool) ([]byte, error) { + oldData, err := json.Marshal(oldPVC) + if err != nil { + return nil, fmt.Errorf("failed to marshal old data: %v", err) + } + + newData, err := json.Marshal(newPVC) + if err != nil { + return nil, fmt.Errorf("failed to marshal new data: %v", err) + } + + patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, oldPVC) + if err != nil { + return nil, fmt.Errorf("failed to create 2 way merge patch: %v", err) + } + + if addResourceVersionCheck { + patchBytes, err = addResourceVersion(patchBytes, oldPVC.ResourceVersion) + if err != nil { + return nil, fmt.Errorf("failed to add resource version: %v", err) + } + } + + return patchBytes, nil +} + +func addResourceVersion(patchBytes []byte, resourceVersion string) ([]byte, error) { + var patchMap map[string]interface{} + err := json.Unmarshal(patchBytes, &patchMap) + if err != nil { + return nil, fmt.Errorf("error unmarshalling patch: %v", err) + } + u := unstructured.Unstructured{Object: patchMap} + a, err := meta.Accessor(&u) + if err != nil { + return nil, fmt.Errorf("error creating accessor: %v", err) + } + a.SetResourceVersion(resourceVersion) + versionBytes, err := json.Marshal(patchMap) + if err != nil { + return nil, fmt.Errorf("error marshalling json patch: %v", err) + } + return versionBytes, nil +} + +// MergeResizeConditionOnPVC updates pvc with requested resize conditions +// leaving other conditions untouched. +func MergeResizeConditionOnPVC( + pvc *v1.PersistentVolumeClaim, + resizeConditions []v1.PersistentVolumeClaimCondition) *v1.PersistentVolumeClaim { + resizeConditionMap := map[v1.PersistentVolumeClaimConditionType]*resizeProcessStatus{} + + for _, condition := range resizeConditions { + resizeConditionMap[condition.Type] = &resizeProcessStatus{condition, false} + } + + oldConditions := pvc.Status.Conditions + newConditions := []v1.PersistentVolumeClaimCondition{} + for _, condition := range oldConditions { + // If Condition is of not resize type, we keep it. + if _, ok := knownResizeConditions[condition.Type]; !ok { + newConditions = append(newConditions, condition) + continue + } + + if newCondition, ok := resizeConditionMap[condition.Type]; ok { + if newCondition.condition.Status != condition.Status { + newConditions = append(newConditions, newCondition.condition) + } else { + newConditions = append(newConditions, condition) + } + newCondition.processed = true + } + } + + // append all unprocessed conditions + for _, newCondition := range resizeConditionMap { + if !newCondition.processed { + newConditions = append(newConditions, newCondition.condition) + } + } + pvc.Status.Conditions = newConditions + return pvc +} + +// GenericResizeFS : call generic filesystem resizer for plugins that don't have any special filesystem resize requirements +func GenericResizeFS(host volume.VolumeHost, pluginName, devicePath, deviceMountPath string) (bool, error) { + resizer := mount.NewResizeFs(host.GetExec(pluginName)) + return resizer.Resize(devicePath, deviceMountPath) +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/selinux.go b/vendor/k8s.io/kubernetes/pkg/volume/util/selinux.go new file mode 100644 index 000000000..22854734f --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/selinux.go @@ -0,0 +1,198 @@ +/* +Copyright 2022 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 util + +import ( + "fmt" + + "github.com/opencontainers/selinux/go-selinux" + "github.com/opencontainers/selinux/go-selinux/label" + v1 "k8s.io/api/core/v1" + utilfeature "k8s.io/apiserver/pkg/util/feature" + v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" + "k8s.io/kubernetes/pkg/features" + "k8s.io/kubernetes/pkg/volume" +) + +// SELinuxLabelTranslator translates v1.SELinuxOptions of a process to SELinux file label. +type SELinuxLabelTranslator interface { + // SELinuxOptionsToFileLabel returns SELinux file label for given SELinuxOptions + // of a container process. + // When Role, User or Type are empty, they're read from the system defaults. + // It returns "" and no error on platforms that do not have SELinux enabled + // or don't support SELinux at all. + SELinuxOptionsToFileLabel(opts *v1.SELinuxOptions) (string, error) + + // SELinuxEnabled returns true when the OS has enabled SELinux support. + SELinuxEnabled() bool +} + +// Real implementation of the interface. +// On Linux with SELinux enabled it translates. Otherwise it always returns an empty string and no error. +type translator struct{} + +var _ SELinuxLabelTranslator = &translator{} + +// NewSELinuxLabelTranslator returns new SELinuxLabelTranslator for the platform. +func NewSELinuxLabelTranslator() SELinuxLabelTranslator { + return &translator{} +} + +// SELinuxOptionsToFileLabel returns SELinux file label for given SELinuxOptions +// of a container process. +// When Role, User or Type are empty, they're read from the system defaults. +// It returns "" and no error on platforms that do not have SELinux enabled +// or don't support SELinux at all. +func (l *translator) SELinuxOptionsToFileLabel(opts *v1.SELinuxOptions) (string, error) { + if opts == nil { + return "", nil + } + + args := contextOptions(opts) + if len(args) == 0 { + return "", nil + } + + processLabel, fileLabel, err := label.InitLabels(args) + if err != nil { + // In theory, this should be unreachable. InitLabels can fail only when args contain an unknown option, + // and all options returned by contextOptions are known. + return "", err + } + // InitLabels() may allocate a new unique SELinux label in kubelet memory. The label is *not* allocated + // in the container runtime. Clear it to avoid memory problems. + // ReleaseLabel on non-allocated label is NOOP. + selinux.ReleaseLabel(processLabel) + + return fileLabel, nil +} + +// Convert SELinuxOptions to []string accepted by label.InitLabels +func contextOptions(opts *v1.SELinuxOptions) []string { + if opts == nil { + return nil + } + args := make([]string, 0, 3) + if opts.User != "" { + args = append(args, "user:"+opts.User) + } + if opts.Role != "" { + args = append(args, "role:"+opts.Role) + } + if opts.Type != "" { + args = append(args, "type:"+opts.Type) + } + if opts.Level != "" { + args = append(args, "level:"+opts.Level) + } + return args +} + +func (l *translator) SELinuxEnabled() bool { + return selinux.GetEnabled() +} + +// Fake implementation of the interface for unit tests. +type fakeTranslator struct{} + +var _ SELinuxLabelTranslator = &fakeTranslator{} + +// NewFakeSELinuxLabelTranslator returns a fake translator for unit tests. +// It imitates a real translator on platforms that do not have SELinux enabled +// or don't support SELinux at all. +func NewFakeSELinuxLabelTranslator() SELinuxLabelTranslator { + return &fakeTranslator{} +} + +// SELinuxOptionsToFileLabel returns SELinux file label for given options. +func (l *fakeTranslator) SELinuxOptionsToFileLabel(opts *v1.SELinuxOptions) (string, error) { + if opts == nil { + return "", nil + } + // Fill empty values from "system defaults" (taken from Fedora Linux). + user := opts.User + if user == "" { + user = "system_u" + } + + role := opts.Role + if role == "" { + role = "object_r" + } + + // opts is context of the *process* to run in a container. Translate + // process type "container_t" to file label type "container_file_t". + // (The rest of the context is the same for processes and files). + fileType := opts.Type + if fileType == "" || fileType == "container_t" { + fileType = "container_file_t" + } + + level := opts.Level + if level == "" { + // If empty, level is allocated randomly. + level = "s0:c998,c999" + } + + ctx := fmt.Sprintf("%s:%s:%s:%s", user, role, fileType, level) + return ctx, nil +} + +func (l *fakeTranslator) SELinuxEnabled() bool { + return true +} + +// SupportsSELinuxContextMount checks if the given volumeSpec supports with mount -o context +func SupportsSELinuxContextMount(volumeSpec *volume.Spec, volumePluginMgr *volume.VolumePluginMgr) (bool, error) { + plugin, _ := volumePluginMgr.FindPluginBySpec(volumeSpec) + if plugin != nil { + return plugin.SupportsSELinuxContextMount(volumeSpec) + } + + return false, nil +} + +// VolumeSupportsSELinuxMount returns true if given volume access mode can support mount with SELinux mount options. +func VolumeSupportsSELinuxMount(volumeSpec *volume.Spec) bool { + // Right now, SELinux mount is supported only for ReadWriteOncePod volumes. + if !utilfeature.DefaultFeatureGate.Enabled(features.ReadWriteOncePod) { + return false + } + if !utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) { + return false + } + if volumeSpec.PersistentVolume == nil { + return false + } + if len(volumeSpec.PersistentVolume.Spec.AccessModes) != 1 { + return false + } + if !v1helper.ContainsAccessMode(volumeSpec.PersistentVolume.Spec.AccessModes, v1.ReadWriteOncePod) { + return false + } + return true +} + +// AddSELinuxMountOption adds -o context="XYZ" mount option to a given list +func AddSELinuxMountOption(options []string, seLinuxContext string) []string { + if !utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) { + return options + } + // Use double quotes to support a comma "," in the SELinux context string. + // For example: dirsync,context="system_u:object_r:container_file_t:s0:c15,c25",noatime + return append(options, fmt.Sprintf("context=%q", seLinuxContext)) +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/storageclass.go b/vendor/k8s.io/kubernetes/pkg/volume/util/storageclass.go new file mode 100644 index 000000000..d2098c258 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/storageclass.go @@ -0,0 +1,85 @@ +/* +Copyright 2022 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 util + +import ( + "sort" + + storagev1 "k8s.io/api/storage/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + storagev1listers "k8s.io/client-go/listers/storage/v1" + "k8s.io/klog/v2" +) + +const ( + // isDefaultStorageClassAnnotation represents a StorageClass annotation that + // marks a class as the default StorageClass + IsDefaultStorageClassAnnotation = "storageclass.kubernetes.io/is-default-class" + + // betaIsDefaultStorageClassAnnotation is the beta version of IsDefaultStorageClassAnnotation. + // TODO: remove Beta when no longer used + BetaIsDefaultStorageClassAnnotation = "storageclass.beta.kubernetes.io/is-default-class" +) + +// GetDefaultClass returns the default StorageClass from the store, or nil. +func GetDefaultClass(lister storagev1listers.StorageClassLister) (*storagev1.StorageClass, error) { + list, err := lister.List(labels.Everything()) + if err != nil { + return nil, err + } + + defaultClasses := []*storagev1.StorageClass{} + for _, class := range list { + if IsDefaultAnnotation(class.ObjectMeta) { + defaultClasses = append(defaultClasses, class) + klog.V(4).Infof("GetDefaultClass added: %s", class.Name) + } + } + + if len(defaultClasses) == 0 { + return nil, nil + } + + // Primary sort by creation timestamp, newest first + // Secondary sort by class name, ascending order + sort.Slice(defaultClasses, func(i, j int) bool { + if defaultClasses[i].CreationTimestamp.UnixNano() == defaultClasses[j].CreationTimestamp.UnixNano() { + return defaultClasses[i].Name < defaultClasses[j].Name + } + return defaultClasses[i].CreationTimestamp.UnixNano() > defaultClasses[j].CreationTimestamp.UnixNano() + }) + if len(defaultClasses) > 1 { + klog.V(4).Infof("%d default StorageClasses were found, choosing the newest: %s", len(defaultClasses), defaultClasses[0].Name) + } + + return defaultClasses[0], nil +} + +// IsDefaultAnnotation returns a boolean if the default storage class +// annotation is set +// TODO: remove Beta when no longer needed +func IsDefaultAnnotation(obj metav1.ObjectMeta) bool { + if obj.Annotations[IsDefaultStorageClassAnnotation] == "true" { + return true + } + if obj.Annotations[BetaIsDefaultStorageClassAnnotation] == "true" { + return true + } + + return false +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/subpath/OWNERS b/vendor/k8s.io/kubernetes/pkg/volume/util/subpath/OWNERS new file mode 100644 index 000000000..3514de0fc --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/subpath/OWNERS @@ -0,0 +1,12 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +reviewers: + - jingxu97 + - saad-ali + - jsafrane + - msau42 + - andyzhangx +approvers: + - jingxu97 + - saad-ali + - jsafrane diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/subpath/subpath.go b/vendor/k8s.io/kubernetes/pkg/volume/util/subpath/subpath.go new file mode 100644 index 000000000..c843f6cf8 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/subpath/subpath.go @@ -0,0 +1,92 @@ +/* +Copyright 2019 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 subpath + +import "os" + +// Interface defines the set of methods all subpathers must implement +type Interface interface { + // CleanSubPaths removes any bind-mounts created by PrepareSafeSubpath in given + // pod volume directory. + CleanSubPaths(poodDir string, volumeName string) error + + // PrepareSafeSubpath does everything that's necessary to prepare a subPath + // that's 1) inside given volumePath and 2) immutable after this call. + // + // newHostPath - location of prepared subPath. It should be used instead of + // hostName when running the container. + // cleanupAction - action to run when the container is running or it failed to start. + // + // CleanupAction must be called immediately after the container with given + // subpath starts. On the other hand, Interface.CleanSubPaths must be called + // when the pod finishes. + PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error) + + // SafeMakeDir creates subdir within given base. It makes sure that the + // created directory does not escape given base directory mis-using + // symlinks. Note that the function makes sure that it creates the directory + // somewhere under the base, nothing else. E.g. if the directory already + // exists, it may exist outside of the base due to symlinks. + // This method should be used if the directory to create is inside volume + // that's under user control. User must not be able to use symlinks to + // escape the volume to create directories somewhere else. + SafeMakeDir(subdir string, base string, perm os.FileMode) error +} + +// Subpath defines the attributes of a subpath +type Subpath struct { + // index of the VolumeMount for this container + VolumeMountIndex int + + // Full path to the subpath directory on the host + Path string + + // name of the volume that is a valid directory name. + VolumeName string + + // Full path to the volume path + VolumePath string + + // Path to the pod's directory, including pod UID + PodDir string + + // Name of the container + ContainerName string +} + +// Compile time-check for all implementers of subpath interface +var _ Interface = &subpath{} +var _ Interface = &FakeSubpath{} + +// FakeSubpath is a subpather implementation for testing +type FakeSubpath struct{} + +// PrepareSafeSubpath is a fake implementation of PrepareSafeSubpath. Always returns +// newHostPath == subPath.Path +func (fs *FakeSubpath) PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error) { + return subPath.Path, nil, nil +} + +// CleanSubPaths is a fake implementation of CleanSubPaths. It is a noop +func (fs *FakeSubpath) CleanSubPaths(podDir string, volumeName string) error { + return nil +} + +// SafeMakeDir is a fake implementation of SafeMakeDir. It is a noop +func (fs *FakeSubpath) SafeMakeDir(pathname string, base string, perm os.FileMode) error { + return nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/subpath/subpath_linux.go b/vendor/k8s.io/kubernetes/pkg/volume/util/subpath/subpath_linux.go new file mode 100644 index 000000000..583939bdc --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/subpath/subpath_linux.go @@ -0,0 +1,609 @@ +//go:build linux +// +build linux + +/* +Copyright 2014 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 subpath + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strconv" + "strings" + "syscall" + + "golang.org/x/sys/unix" + "k8s.io/klog/v2" + "k8s.io/mount-utils" +) + +const ( + // place for subpath mounts + // TODO: pass in directory using kubelet_getters instead + containerSubPathDirectoryName = "volume-subpaths" + // syscall.Openat flags used to traverse directories not following symlinks + nofollowFlags = unix.O_RDONLY | unix.O_NOFOLLOW + // flags for getting file descriptor without following the symlink + openFDFlags = unix.O_NOFOLLOW | unix.O_PATH +) + +type subpath struct { + mounter mount.Interface +} + +// New returns a subpath.Interface for the current system +func New(mounter mount.Interface) Interface { + return &subpath{ + mounter: mounter, + } +} + +func (sp *subpath) CleanSubPaths(podDir string, volumeName string) error { + return doCleanSubPaths(sp.mounter, podDir, volumeName) +} + +func (sp *subpath) SafeMakeDir(subdir string, base string, perm os.FileMode) error { + realBase, err := filepath.EvalSymlinks(base) + if err != nil { + return fmt.Errorf("error resolving symlinks in %s: %s", base, err) + } + + realFullPath := filepath.Join(realBase, subdir) + + return doSafeMakeDir(realFullPath, realBase, perm) +} + +func (sp *subpath) PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error) { + newHostPath, err = doBindSubPath(sp.mounter, subPath) + + // There is no action when the container starts. Bind-mount will be cleaned + // when container stops by CleanSubPaths. + cleanupAction = nil + return newHostPath, cleanupAction, err +} + +// This implementation is shared between Linux and NsEnter +func safeOpenSubPath(mounter mount.Interface, subpath Subpath) (int, error) { + if !mount.PathWithinBase(subpath.Path, subpath.VolumePath) { + return -1, fmt.Errorf("subpath %q not within volume path %q", subpath.Path, subpath.VolumePath) + } + fd, err := doSafeOpen(subpath.Path, subpath.VolumePath) + if err != nil { + return -1, fmt.Errorf("error opening subpath %v: %v", subpath.Path, err) + } + return fd, nil +} + +// prepareSubpathTarget creates target for bind-mount of subpath. It returns +// "true" when the target already exists and something is mounted there. +// Given Subpath must have all paths with already resolved symlinks and with +// paths relevant to kubelet (when it runs in a container). +// This function is called also by NsEnterMounter. It works because +// /var/lib/kubelet is mounted from the host into the container with Kubelet as +// /var/lib/kubelet too. +func prepareSubpathTarget(mounter mount.Interface, subpath Subpath) (bool, string, error) { + // Early check for already bind-mounted subpath. + bindPathTarget := getSubpathBindTarget(subpath) + notMount, err := mount.IsNotMountPoint(mounter, bindPathTarget) + if err != nil { + if !os.IsNotExist(err) { + return false, "", fmt.Errorf("error checking path %s for mount: %s", bindPathTarget, err) + } + // Ignore ErrorNotExist: the file/directory will be created below if it does not exist yet. + notMount = true + } + if !notMount { + // It's already mounted, so check if it's bind-mounted to the same path + samePath, err := checkSubPathFileEqual(subpath, bindPathTarget) + if err != nil { + return false, "", fmt.Errorf("error checking subpath mount info for %s: %s", bindPathTarget, err) + } + if !samePath { + // It's already mounted but not what we want, unmount it + if err = mounter.Unmount(bindPathTarget); err != nil { + return false, "", fmt.Errorf("error ummounting %s: %s", bindPathTarget, err) + } + } else { + // It's already mounted + klog.V(5).Infof("Skipping bind-mounting subpath %s: already mounted", bindPathTarget) + return true, bindPathTarget, nil + } + } + + // bindPathTarget is in /var/lib/kubelet and thus reachable without any + // translation even to containerized kubelet. + bindParent := filepath.Dir(bindPathTarget) + err = os.MkdirAll(bindParent, 0750) + if err != nil && !os.IsExist(err) { + return false, "", fmt.Errorf("error creating directory %s: %s", bindParent, err) + } + + t, err := os.Lstat(subpath.Path) + if err != nil { + return false, "", fmt.Errorf("lstat %s failed: %s", subpath.Path, err) + } + + if t.Mode()&os.ModeDir > 0 { + if err = os.Mkdir(bindPathTarget, 0750); err != nil && !os.IsExist(err) { + return false, "", fmt.Errorf("error creating directory %s: %s", bindPathTarget, err) + } + } else { + // "/bin/touch ". + // A file is enough for all possible targets (symlink, device, pipe, + // socket, ...), bind-mounting them into a file correctly changes type + // of the target file. + if err = ioutil.WriteFile(bindPathTarget, []byte{}, 0640); err != nil { + return false, "", fmt.Errorf("error creating file %s: %s", bindPathTarget, err) + } + } + return false, bindPathTarget, nil +} + +func checkSubPathFileEqual(subpath Subpath, bindMountTarget string) (bool, error) { + s, err := os.Lstat(subpath.Path) + if err != nil { + return false, fmt.Errorf("stat %s failed: %s", subpath.Path, err) + } + + t, err := os.Lstat(bindMountTarget) + if err != nil { + return false, fmt.Errorf("lstat %s failed: %s", bindMountTarget, err) + } + + if !os.SameFile(s, t) { + return false, nil + } + return true, nil +} + +func getSubpathBindTarget(subpath Subpath) string { + // containerName is DNS label, i.e. safe as a directory name. + return filepath.Join(subpath.PodDir, containerSubPathDirectoryName, subpath.VolumeName, subpath.ContainerName, strconv.Itoa(subpath.VolumeMountIndex)) +} + +func doBindSubPath(mounter mount.Interface, subpath Subpath) (hostPath string, err error) { + // Linux, kubelet runs on the host: + // - safely open the subpath + // - bind-mount /proc//fd/ to subpath target + // User can't change /proc//fd/ to point to a bad place. + + // Evaluate all symlinks here once for all subsequent functions. + newVolumePath, err := filepath.EvalSymlinks(subpath.VolumePath) + if err != nil { + return "", fmt.Errorf("error resolving symlinks in %q: %v", subpath.VolumePath, err) + } + newPath, err := filepath.EvalSymlinks(subpath.Path) + if err != nil { + return "", fmt.Errorf("error resolving symlinks in %q: %v", subpath.Path, err) + } + klog.V(5).Infof("doBindSubPath %q (%q) for volumepath %q", subpath.Path, newPath, subpath.VolumePath) + subpath.VolumePath = newVolumePath + subpath.Path = newPath + + fd, err := safeOpenSubPath(mounter, subpath) + if err != nil { + return "", err + } + defer syscall.Close(fd) + + alreadyMounted, bindPathTarget, err := prepareSubpathTarget(mounter, subpath) + if err != nil { + return "", err + } + if alreadyMounted { + return bindPathTarget, nil + } + + success := false + defer func() { + // Cleanup subpath on error + if !success { + klog.V(4).Infof("doBindSubPath() failed for %q, cleaning up subpath", bindPathTarget) + if cleanErr := cleanSubPath(mounter, subpath); cleanErr != nil { + klog.Errorf("Failed to clean subpath %q: %v", bindPathTarget, cleanErr) + } + } + }() + + kubeletPid := os.Getpid() + mountSource := fmt.Sprintf("/proc/%d/fd/%v", kubeletPid, fd) + + // Do the bind mount + options := []string{"bind"} + mountFlags := []string{"--no-canonicalize"} + klog.V(5).Infof("bind mounting %q at %q", mountSource, bindPathTarget) + if err = mounter.MountSensitiveWithoutSystemdWithMountFlags(mountSource, bindPathTarget, "" /*fstype*/, options, nil /* sensitiveOptions */, mountFlags); err != nil { + return "", fmt.Errorf("error mounting %s: %s", subpath.Path, err) + } + success = true + + klog.V(3).Infof("Bound SubPath %s into %s", subpath.Path, bindPathTarget) + return bindPathTarget, nil +} + +// This implementation is shared between Linux and NsEnter +func doCleanSubPaths(mounter mount.Interface, podDir string, volumeName string) error { + // scan /var/lib/kubelet/pods//volume-subpaths//* + subPathDir := filepath.Join(podDir, containerSubPathDirectoryName, volumeName) + klog.V(4).Infof("Cleaning up subpath mounts for %s", subPathDir) + + containerDirs, err := ioutil.ReadDir(subPathDir) + if err != nil { + if os.IsNotExist(err) { + return nil + } + return fmt.Errorf("error reading %s: %s", subPathDir, err) + } + + for _, containerDir := range containerDirs { + if !containerDir.IsDir() { + klog.V(4).Infof("Container file is not a directory: %s", containerDir.Name()) + continue + } + klog.V(4).Infof("Cleaning up subpath mounts for container %s", containerDir.Name()) + + // scan /var/lib/kubelet/pods//volume-subpaths///* + fullContainerDirPath := filepath.Join(subPathDir, containerDir.Name()) + // The original traversal method here was ReadDir, which was not so robust to handle some error such as "stale NFS file handle", + // so it was replaced with filepath.Walk in a later patch, which can pass through error and handled by the callback WalkFunc. + // After go 1.16, WalkDir was introduced, it's more effective than Walk because the callback WalkDirFunc is called before + // reading a directory, making it save some time when a container's subPath contains lots of dirs. + // See https://github.com/kubernetes/kubernetes/pull/71804 and https://github.com/kubernetes/kubernetes/issues/107667 for more details. + err = filepath.WalkDir(fullContainerDirPath, func(path string, info os.DirEntry, _ error) error { + if path == fullContainerDirPath { + // Skip top level directory + return nil + } + + // pass through errors and let doCleanSubPath handle them + if err = doCleanSubPath(mounter, fullContainerDirPath, filepath.Base(path)); err != nil { + return err + } + + // We need to check that info is not nil. This may happen when the incoming err is not nil due to stale mounts or permission errors. + if info != nil && info.IsDir() { + // skip subdirs of the volume: it only matters the first level to unmount, otherwise it would try to unmount subdir of the volume + return filepath.SkipDir + } + + return nil + }) + if err != nil { + return fmt.Errorf("error processing %s: %s", fullContainerDirPath, err) + } + + // Whole container has been processed, remove its directory. + if err := os.Remove(fullContainerDirPath); err != nil { + return fmt.Errorf("error deleting %s: %s", fullContainerDirPath, err) + } + klog.V(5).Infof("Removed %s", fullContainerDirPath) + } + // Whole pod volume subpaths have been cleaned up, remove its subpath directory. + if err := os.Remove(subPathDir); err != nil { + return fmt.Errorf("error deleting %s: %s", subPathDir, err) + } + klog.V(5).Infof("Removed %s", subPathDir) + + // Remove entire subpath directory if it's the last one + podSubPathDir := filepath.Join(podDir, containerSubPathDirectoryName) + if err := os.Remove(podSubPathDir); err != nil && !os.IsExist(err) { + return fmt.Errorf("error deleting %s: %s", podSubPathDir, err) + } + klog.V(5).Infof("Removed %s", podSubPathDir) + return nil +} + +// doCleanSubPath tears down the single subpath bind mount +func doCleanSubPath(mounter mount.Interface, fullContainerDirPath, subPathIndex string) error { + // process /var/lib/kubelet/pods//volume-subpaths/// + klog.V(4).Infof("Cleaning up subpath mounts for subpath %v", subPathIndex) + fullSubPath := filepath.Join(fullContainerDirPath, subPathIndex) + + if err := mount.CleanupMountPoint(fullSubPath, mounter, true); err != nil { + return fmt.Errorf("error cleaning subpath mount %s: %s", fullSubPath, err) + } + + klog.V(4).Infof("Successfully cleaned subpath directory %s", fullSubPath) + return nil +} + +// cleanSubPath will teardown the subpath bind mount and any remove any directories if empty +func cleanSubPath(mounter mount.Interface, subpath Subpath) error { + containerDir := filepath.Join(subpath.PodDir, containerSubPathDirectoryName, subpath.VolumeName, subpath.ContainerName) + + // Clean subdir bindmount + if err := doCleanSubPath(mounter, containerDir, strconv.Itoa(subpath.VolumeMountIndex)); err != nil && !os.IsNotExist(err) { + return err + } + + // Recusively remove directories if empty + if err := removeEmptyDirs(subpath.PodDir, containerDir); err != nil { + return err + } + + return nil +} + +// removeEmptyDirs works backwards from endDir to baseDir and removes each directory +// if it is empty. It stops once it encounters a directory that has content +func removeEmptyDirs(baseDir, endDir string) error { + if !mount.PathWithinBase(endDir, baseDir) { + return fmt.Errorf("endDir %q is not within baseDir %q", endDir, baseDir) + } + + for curDir := endDir; curDir != baseDir; curDir = filepath.Dir(curDir) { + s, err := os.Stat(curDir) + if err != nil { + if os.IsNotExist(err) { + klog.V(5).Infof("curDir %q doesn't exist, skipping", curDir) + continue + } + return fmt.Errorf("error stat %q: %v", curDir, err) + } + if !s.IsDir() { + return fmt.Errorf("path %q not a directory", curDir) + } + + err = os.Remove(curDir) + if os.IsExist(err) { + klog.V(5).Infof("Directory %q not empty, not removing", curDir) + break + } else if err != nil { + return fmt.Errorf("error removing directory %q: %v", curDir, err) + } + klog.V(5).Infof("Removed directory %q", curDir) + } + return nil +} + +// This implementation is shared between Linux and NsEnterMounter. Both pathname +// and base must be either already resolved symlinks or thet will be resolved in +// kubelet's mount namespace (in case it runs containerized). +func doSafeMakeDir(pathname string, base string, perm os.FileMode) error { + klog.V(4).Infof("Creating directory %q within base %q", pathname, base) + + if !mount.PathWithinBase(pathname, base) { + return fmt.Errorf("path %s is outside of allowed base %s", pathname, base) + } + + // Quick check if the directory already exists + s, err := os.Stat(pathname) + if err == nil { + // Path exists + if s.IsDir() { + // The directory already exists. It can be outside of the parent, + // but there is no race-proof check. + klog.V(4).Infof("Directory %s already exists", pathname) + return nil + } + return &os.PathError{Op: "mkdir", Path: pathname, Err: syscall.ENOTDIR} + } + + // Find all existing directories + existingPath, toCreate, err := findExistingPrefix(base, pathname) + if err != nil { + return fmt.Errorf("error opening directory %s: %s", pathname, err) + } + // Ensure the existing directory is inside allowed base + fullExistingPath, err := filepath.EvalSymlinks(existingPath) + if err != nil { + return fmt.Errorf("error opening directory %s: %s", existingPath, err) + } + if !mount.PathWithinBase(fullExistingPath, base) { + return fmt.Errorf("path %s is outside of allowed base %s", fullExistingPath, err) + } + + klog.V(4).Infof("%q already exists, %q to create", fullExistingPath, filepath.Join(toCreate...)) + parentFD, err := doSafeOpen(fullExistingPath, base) + if err != nil { + return fmt.Errorf("cannot open directory %s: %s", existingPath, err) + } + childFD := -1 + defer func() { + if parentFD != -1 { + if err = syscall.Close(parentFD); err != nil { + klog.V(4).Infof("Closing FD %v failed for safemkdir(%v): %v", parentFD, pathname, err) + } + } + if childFD != -1 { + if err = syscall.Close(childFD); err != nil { + klog.V(4).Infof("Closing FD %v failed for safemkdir(%v): %v", childFD, pathname, err) + } + } + }() + + currentPath := fullExistingPath + // create the directories one by one, making sure nobody can change + // created directory into symlink. + for _, dir := range toCreate { + currentPath = filepath.Join(currentPath, dir) + klog.V(4).Infof("Creating %s", dir) + err = syscall.Mkdirat(parentFD, currentPath, uint32(perm)) + if err != nil { + return fmt.Errorf("cannot create directory %s: %s", currentPath, err) + } + // Dive into the created directory + childFD, err = syscall.Openat(parentFD, dir, nofollowFlags|unix.O_CLOEXEC, 0) + if err != nil { + return fmt.Errorf("cannot open %s: %s", currentPath, err) + } + // We can be sure that childFD is safe to use. It could be changed + // by user after Mkdirat() and before Openat(), however: + // - it could not be changed to symlink - we use nofollowFlags + // - it could be changed to a file (or device, pipe, socket, ...) + // but either subsequent Mkdirat() fails or we mount this file + // to user's container. Security is no violated in both cases + // and user either gets error or the file that it can already access. + + if err = syscall.Close(parentFD); err != nil { + klog.V(4).Infof("Closing FD %v failed for safemkdir(%v): %v", parentFD, pathname, err) + } + parentFD = childFD + childFD = -1 + + // Everything was created. mkdirat(..., perm) above was affected by current + // umask and we must apply the right permissions to the all created directory. + // (that's the one that will be available to the container as subpath) + // so user can read/write it. + // parentFD is the last created directory. + + // Translate perm (os.FileMode) to uint32 that fchmod() expects + kernelPerm := uint32(perm & os.ModePerm) + if perm&os.ModeSetgid > 0 { + kernelPerm |= syscall.S_ISGID + } + if perm&os.ModeSetuid > 0 { + kernelPerm |= syscall.S_ISUID + } + if perm&os.ModeSticky > 0 { + kernelPerm |= syscall.S_ISVTX + } + if err = syscall.Fchmod(parentFD, kernelPerm); err != nil { + return fmt.Errorf("chmod %q failed: %s", currentPath, err) + } + } + + return nil +} + +// findExistingPrefix finds prefix of pathname that exists. In addition, it +// returns list of remaining directories that don't exist yet. +func findExistingPrefix(base, pathname string) (string, []string, error) { + rel, err := filepath.Rel(base, pathname) + if err != nil { + return base, nil, err + } + dirs := strings.Split(rel, string(filepath.Separator)) + + // Do OpenAt in a loop to find the first non-existing dir. Resolve symlinks. + // This should be faster than looping through all dirs and calling os.Stat() + // on each of them, as the symlinks are resolved only once with OpenAt(). + currentPath := base + fd, err := syscall.Open(currentPath, syscall.O_RDONLY|syscall.O_CLOEXEC, 0) + if err != nil { + return pathname, nil, fmt.Errorf("error opening %s: %s", currentPath, err) + } + defer func() { + if err = syscall.Close(fd); err != nil { + klog.V(4).Infof("Closing FD %v failed for findExistingPrefix(%v): %v", fd, pathname, err) + } + }() + for i, dir := range dirs { + // Using O_PATH here will prevent hangs in case user replaces directory with + // fifo + childFD, err := syscall.Openat(fd, dir, unix.O_PATH|unix.O_CLOEXEC, 0) + if err != nil { + if os.IsNotExist(err) { + return currentPath, dirs[i:], nil + } + return base, nil, err + } + if err = syscall.Close(fd); err != nil { + klog.V(4).Infof("Closing FD %v failed for findExistingPrefix(%v): %v", fd, pathname, err) + } + fd = childFD + currentPath = filepath.Join(currentPath, dir) + } + return pathname, []string{}, nil +} + +// This implementation is shared between Linux and NsEnterMounter +// Open path and return its fd. +// Symlinks are disallowed (pathname must already resolve symlinks), +// and the path must be within the base directory. +func doSafeOpen(pathname string, base string) (int, error) { + pathname = filepath.Clean(pathname) + base = filepath.Clean(base) + + // Calculate segments to follow + subpath, err := filepath.Rel(base, pathname) + if err != nil { + return -1, err + } + segments := strings.Split(subpath, string(filepath.Separator)) + + // Assumption: base is the only directory that we have under control. + // Base dir is not allowed to be a symlink. + parentFD, err := syscall.Open(base, nofollowFlags|unix.O_CLOEXEC, 0) + if err != nil { + return -1, fmt.Errorf("cannot open directory %s: %s", base, err) + } + defer func() { + if parentFD != -1 { + if err = syscall.Close(parentFD); err != nil { + klog.V(4).Infof("Closing FD %v failed for safeopen(%v): %v", parentFD, pathname, err) + } + } + }() + + childFD := -1 + defer func() { + if childFD != -1 { + if err = syscall.Close(childFD); err != nil { + klog.V(4).Infof("Closing FD %v failed for safeopen(%v): %v", childFD, pathname, err) + } + } + }() + + currentPath := base + + // Follow the segments one by one using openat() to make + // sure the user cannot change already existing directories into symlinks. + for _, seg := range segments { + var deviceStat unix.Stat_t + + currentPath = filepath.Join(currentPath, seg) + if !mount.PathWithinBase(currentPath, base) { + return -1, fmt.Errorf("path %s is outside of allowed base %s", currentPath, base) + } + + // Trigger auto mount if it's an auto-mounted directory, ignore error if not a directory. + // Notice the trailing slash is mandatory, see "automount" in openat(2) and open_by_handle_at(2). + unix.Fstatat(parentFD, seg+"/", &deviceStat, unix.AT_SYMLINK_NOFOLLOW) + + klog.V(5).Infof("Opening path %s", currentPath) + childFD, err = syscall.Openat(parentFD, seg, openFDFlags|unix.O_CLOEXEC, 0) + if err != nil { + return -1, fmt.Errorf("cannot open %s: %s", currentPath, err) + } + + err := unix.Fstat(childFD, &deviceStat) + if err != nil { + return -1, fmt.Errorf("error running fstat on %s with %v", currentPath, err) + } + fileFmt := deviceStat.Mode & syscall.S_IFMT + if fileFmt == syscall.S_IFLNK { + return -1, fmt.Errorf("unexpected symlink found %s", currentPath) + } + + // Close parentFD + if err = syscall.Close(parentFD); err != nil { + return -1, fmt.Errorf("closing fd for %q failed: %v", filepath.Dir(currentPath), err) + } + // Set child to new parent + parentFD = childFD + childFD = -1 + } + + // We made it to the end, return this fd, don't close it + finalFD := parentFD + parentFD = -1 + + return finalFD, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/subpath/subpath_unsupported.go b/vendor/k8s.io/kubernetes/pkg/volume/util/subpath/subpath_unsupported.go new file mode 100644 index 000000000..21493426d --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/subpath/subpath_unsupported.go @@ -0,0 +1,55 @@ +//go:build !linux && !windows +// +build !linux,!windows + +/* +Copyright 2014 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 subpath + +import ( + "errors" + "os" + + "k8s.io/mount-utils" + "k8s.io/utils/nsenter" +) + +type subpath struct{} + +var errUnsupported = errors.New("util/subpath on this platform is not supported") + +// New returns a subpath.Interface for the current system. +func New(mount.Interface) Interface { + return &subpath{} +} + +// NewNSEnter is to satisfy the compiler for having NewSubpathNSEnter exist for all +// OS choices. however, NSEnter is only valid on Linux +func NewNSEnter(mounter mount.Interface, ne *nsenter.Nsenter, rootDir string) Interface { + return nil +} + +func (sp *subpath) PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error) { + return subPath.Path, nil, errUnsupported +} + +func (sp *subpath) CleanSubPaths(podDir string, volumeName string) error { + return errUnsupported +} + +func (sp *subpath) SafeMakeDir(pathname string, base string, perm os.FileMode) error { + return errUnsupported +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/subpath/subpath_windows.go b/vendor/k8s.io/kubernetes/pkg/volume/util/subpath/subpath_windows.go new file mode 100644 index 000000000..7d40ce590 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/subpath/subpath_windows.go @@ -0,0 +1,379 @@ +//go:build windows +// +build windows + +/* +Copyright 2017 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 subpath + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + "syscall" + + "k8s.io/klog/v2" + "k8s.io/mount-utils" + "k8s.io/utils/nsenter" +) + +// MaxPathLength is the maximum length of Windows path. Normally, it is 260, but if long path is enable, +// the max number is 32,767 +const MaxPathLength = 32767 + +type subpath struct{} + +// New returns a subpath.Interface for the current system +func New(mount.Interface) Interface { + return &subpath{} +} + +// NewNSEnter is to satisfy the compiler for having NewSubpathNSEnter exist for all +// OS choices. however, NSEnter is only valid on Linux +func NewNSEnter(mounter mount.Interface, ne *nsenter.Nsenter, rootDir string) Interface { + return nil +} + +// isDriveLetterPath returns true if the given path is empty or it ends with ":" or ":\" or ":\\" +func isDriveLetterorEmptyPath(path string) bool { + if path == "" || strings.HasSuffix(path, ":\\\\") || strings.HasSuffix(path, ":") || strings.HasSuffix(path, ":\\") { + return true + } + return false +} + +// isVolumePrefix returns true if the given path name starts with "Volume" or volume prefix including +// "\\.\", "\\?\" for device path or "UNC" or "\\" for UNC path. Otherwise, it returns false. +func isDeviceOrUncPath(path string) bool { + if strings.HasPrefix(path, "Volume") || strings.HasPrefix(path, "\\\\?\\") || strings.HasPrefix(path, "\\\\.\\") || strings.HasPrefix(path, "UNC") { + return true + } + return false +} + +// getUpperPath removes the last level of directory. +func getUpperPath(path string) string { + sep := fmt.Sprintf("%c", filepath.Separator) + upperpath := strings.TrimSuffix(path, sep) + return filepath.Dir(upperpath) +} + +// Check whether a directory/file is a link type or not +// LinkType could be SymbolicLink, Junction, or HardLink +func isLinkPath(path string) (bool, error) { + cmd := fmt.Sprintf("(Get-Item -LiteralPath %q).LinkType", path) + output, err := exec.Command("powershell", "/c", cmd).CombinedOutput() + if err != nil { + return false, err + } + if strings.TrimSpace(string(output)) != "" { + return true, nil + } + return false, nil +} + +// evalSymlink returns the path name after the evaluation of any symbolic links. +// If the path after evaluation is a device path or network connection, the original path is returned +func evalSymlink(path string) (string, error) { + path = mount.NormalizeWindowsPath(path) + if isDeviceOrUncPath(path) || isDriveLetterorEmptyPath(path) { + klog.V(4).Infof("Path '%s' is not a symlink, return its original form.", path) + return path, nil + } + upperpath := path + base := "" + for i := 0; i < MaxPathLength; i++ { + isLink, err := isLinkPath(upperpath) + if err != nil { + return "", err + } + if isLink { + break + } + // continue to check next layer + base = filepath.Join(filepath.Base(upperpath), base) + upperpath = getUpperPath(upperpath) + if isDriveLetterorEmptyPath(upperpath) { + klog.V(4).Infof("Path '%s' is not a symlink, return its original form.", path) + return path, nil + } + } + // This command will give the target path of a given symlink + // The -Force parameter will allow Get-Item to also evaluate hidden folders, like AppData. + cmd := fmt.Sprintf("(Get-Item -Force -LiteralPath %q).Target", upperpath) + output, err := exec.Command("powershell", "/c", cmd).CombinedOutput() + if err != nil { + return "", err + } + klog.V(4).Infof("evaluate path %s: symlink from %s to %s", path, upperpath, string(output)) + linkedPath := strings.TrimSpace(string(output)) + if linkedPath == "" || isDeviceOrUncPath(linkedPath) { + klog.V(4).Infof("Path '%s' has a target %s. Return its original form.", path, linkedPath) + return path, nil + } + // If the target is not an absolute path, join iit with the current upperpath + if !filepath.IsAbs(linkedPath) { + linkedPath = filepath.Join(getUpperPath(upperpath), linkedPath) + } + nextLink, err := evalSymlink(linkedPath) + if err != nil { + return path, err + } + return filepath.Join(nextLink, base), nil +} + +// check whether hostPath is within volume path +// this func will lock all intermediate subpath directories, need to close handle outside of this func after container started +func lockAndCheckSubPath(volumePath, hostPath string) ([]uintptr, error) { + if len(volumePath) == 0 || len(hostPath) == 0 { + return []uintptr{}, nil + } + + finalSubPath, err := evalSymlink(hostPath) + if err != nil { + return []uintptr{}, fmt.Errorf("cannot evaluate link %s: %s", hostPath, err) + } + + finalVolumePath, err := evalSymlink(volumePath) + if err != nil { + return []uintptr{}, fmt.Errorf("cannot read link %s: %s", volumePath, err) + } + + return lockAndCheckSubPathWithoutSymlink(finalVolumePath, finalSubPath) +} + +// lock all intermediate subPath directories and check they are all within volumePath +// volumePath & subPath should not contain any symlink, otherwise it will return error +func lockAndCheckSubPathWithoutSymlink(volumePath, subPath string) ([]uintptr, error) { + if len(volumePath) == 0 || len(subPath) == 0 { + return []uintptr{}, nil + } + + // get relative path to volumePath + relSubPath, err := filepath.Rel(volumePath, subPath) + if err != nil { + return []uintptr{}, fmt.Errorf("Rel(%s, %s) error: %v", volumePath, subPath, err) + } + if mount.StartsWithBackstep(relSubPath) { + return []uintptr{}, fmt.Errorf("SubPath %q not within volume path %q", subPath, volumePath) + } + + if relSubPath == "." { + // volumePath and subPath are equal + return []uintptr{}, nil + } + + fileHandles := []uintptr{} + var errorResult error + + currentFullPath := volumePath + dirs := strings.Split(relSubPath, string(os.PathSeparator)) + for _, dir := range dirs { + // lock intermediate subPath directory first + currentFullPath = filepath.Join(currentFullPath, dir) + handle, err := lockPath(currentFullPath) + if err != nil { + errorResult = fmt.Errorf("cannot lock path %s: %s", currentFullPath, err) + break + } + fileHandles = append(fileHandles, handle) + + // make sure intermediate subPath directory does not contain symlink any more + stat, err := os.Lstat(currentFullPath) + if err != nil { + errorResult = fmt.Errorf("Lstat(%q) error: %v", currentFullPath, err) + break + } + if stat.Mode()&os.ModeSymlink != 0 { + errorResult = fmt.Errorf("subpath %q is an unexpected symlink after EvalSymlinks", currentFullPath) + break + } + + if !mount.PathWithinBase(currentFullPath, volumePath) { + errorResult = fmt.Errorf("SubPath %q not within volume path %q", currentFullPath, volumePath) + break + } + } + + return fileHandles, errorResult +} + +// unlockPath unlock directories +func unlockPath(fileHandles []uintptr) { + if fileHandles != nil { + for _, handle := range fileHandles { + syscall.CloseHandle(syscall.Handle(handle)) + } + } +} + +// lockPath locks a directory or symlink, return handle, exec "syscall.CloseHandle(handle)" to unlock the path +func lockPath(path string) (uintptr, error) { + if len(path) == 0 { + return uintptr(syscall.InvalidHandle), syscall.ERROR_FILE_NOT_FOUND + } + pathp, err := syscall.UTF16PtrFromString(path) + if err != nil { + return uintptr(syscall.InvalidHandle), err + } + access := uint32(syscall.GENERIC_READ) + sharemode := uint32(syscall.FILE_SHARE_READ) + createmode := uint32(syscall.OPEN_EXISTING) + flags := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS | syscall.FILE_FLAG_OPEN_REPARSE_POINT) + fd, err := syscall.CreateFile(pathp, access, sharemode, nil, createmode, flags, 0) + return uintptr(fd), err +} + +// Lock all directories in subPath and check they're not symlinks. +func (sp *subpath) PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error) { + handles, err := lockAndCheckSubPath(subPath.VolumePath, subPath.Path) + + // Unlock the directories when the container starts + cleanupAction = func() { + unlockPath(handles) + } + return subPath.Path, cleanupAction, err +} + +// No bind-mounts for subpaths are necessary on Windows +func (sp *subpath) CleanSubPaths(podDir string, volumeName string) error { + return nil +} + +// SafeMakeDir makes sure that the created directory does not escape given base directory mis-using symlinks. +func (sp *subpath) SafeMakeDir(subdir string, base string, perm os.FileMode) error { + realBase, err := evalSymlink(base) + if err != nil { + return fmt.Errorf("error resolving symlinks in %s: %s", base, err) + } + + realFullPath := filepath.Join(realBase, subdir) + return doSafeMakeDir(realFullPath, realBase, perm) +} + +func doSafeMakeDir(pathname string, base string, perm os.FileMode) error { + klog.V(4).Infof("Creating directory %q within base %q", pathname, base) + + if !mount.PathWithinBase(pathname, base) { + return fmt.Errorf("path %s is outside of allowed base %s", pathname, base) + } + + // Quick check if the directory already exists + s, err := os.Stat(pathname) + if err == nil { + // Path exists + if s.IsDir() { + // The directory already exists. It can be outside of the parent, + // but there is no race-proof check. + klog.V(4).Infof("Directory %s already exists", pathname) + return nil + } + return &os.PathError{Op: "mkdir", Path: pathname, Err: syscall.ENOTDIR} + } + + // Find all existing directories + existingPath, toCreate, err := findExistingPrefix(base, pathname) + if err != nil { + return fmt.Errorf("error opening directory %s: %s", pathname, err) + } + if len(toCreate) == 0 { + return nil + } + + // Ensure the existing directory is inside allowed base + fullExistingPath, err := evalSymlink(existingPath) + if err != nil { + return fmt.Errorf("error opening existing directory %s: %s", existingPath, err) + } + fullBasePath, err := evalSymlink(base) + if err != nil { + return fmt.Errorf("cannot read link %s: %s", base, err) + } + if !mount.PathWithinBase(fullExistingPath, fullBasePath) { + return fmt.Errorf("path %s is outside of allowed base %s", fullExistingPath, err) + } + + // lock all intermediate directories from fullBasePath to fullExistingPath (top to bottom) + fileHandles, err := lockAndCheckSubPathWithoutSymlink(fullBasePath, fullExistingPath) + defer unlockPath(fileHandles) + if err != nil { + return err + } + + klog.V(4).Infof("%q already exists, %q to create", fullExistingPath, filepath.Join(toCreate...)) + currentPath := fullExistingPath + // create the directories one by one, making sure nobody can change + // created directory into symlink by lock that directory immediately + for _, dir := range toCreate { + currentPath = filepath.Join(currentPath, dir) + klog.V(4).Infof("Creating %s", dir) + if err := os.Mkdir(currentPath, perm); err != nil { + return fmt.Errorf("cannot create directory %s: %s", currentPath, err) + } + handle, err := lockPath(currentPath) + if err != nil { + return fmt.Errorf("cannot lock path %s: %s", currentPath, err) + } + defer syscall.CloseHandle(syscall.Handle(handle)) + // make sure newly created directory does not contain symlink after lock + stat, err := os.Lstat(currentPath) + if err != nil { + return fmt.Errorf("Lstat(%q) error: %v", currentPath, err) + } + if stat.Mode()&os.ModeSymlink != 0 { + return fmt.Errorf("subpath %q is an unexpected symlink after Mkdir", currentPath) + } + } + + return nil +} + +// findExistingPrefix finds prefix of pathname that exists. In addition, it +// returns list of remaining directories that don't exist yet. +func findExistingPrefix(base, pathname string) (string, []string, error) { + rel, err := filepath.Rel(base, pathname) + if err != nil { + return base, nil, err + } + + if mount.StartsWithBackstep(rel) { + return base, nil, fmt.Errorf("pathname(%s) is not within base(%s)", pathname, base) + } + + if rel == "." { + // base and pathname are equal + return pathname, []string{}, nil + } + + dirs := strings.Split(rel, string(filepath.Separator)) + + var parent string + currentPath := base + for i, dir := range dirs { + parent = currentPath + currentPath = filepath.Join(parent, dir) + if _, err := os.Lstat(currentPath); err != nil { + if os.IsNotExist(err) { + return parent, dirs[i:], nil + } + return base, nil, err + } + } + + return pathname, []string{}, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/types/types.go b/vendor/k8s.io/kubernetes/pkg/volume/util/types/types.go new file mode 100644 index 000000000..af309353b --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/types/types.go @@ -0,0 +1,168 @@ +/* +Copyright 2016 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 types defines types used only by volume components +package types + +import ( + "errors" + + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/mount-utils" +) + +// UniquePodName defines the type to key pods off of +type UniquePodName types.UID + +// UniquePVCName defines the type to key pvc off +type UniquePVCName types.UID + +// GeneratedOperations contains the operation that is created as well as +// supporting functions required for the operation executor +type GeneratedOperations struct { + // Name of operation - could be used for resetting shared exponential backoff + OperationName string + OperationFunc func() (context OperationContext) + EventRecorderFunc func(*error) + CompleteFunc func(CompleteFuncParam) +} + +type OperationContext struct { + EventErr error + DetailedErr error + Migrated bool +} + +func NewOperationContext(eventErr, detailedErr error, migrated bool) OperationContext { + return OperationContext{ + EventErr: eventErr, + DetailedErr: detailedErr, + Migrated: migrated, + } +} + +type CompleteFuncParam struct { + Err *error + Migrated *bool +} + +// Run executes the operations and its supporting functions +func (o *GeneratedOperations) Run() (eventErr, detailedErr error) { + var context OperationContext + if o.CompleteFunc != nil { + c := CompleteFuncParam{ + Err: &context.DetailedErr, + Migrated: &context.Migrated, + } + defer o.CompleteFunc(c) + } + if o.EventRecorderFunc != nil { + defer o.EventRecorderFunc(&eventErr) + } + // Handle panic, if any, from operationFunc() + defer runtime.RecoverFromPanic(&detailedErr) + + context = o.OperationFunc() + return context.EventErr, context.DetailedErr +} + +// FailedPrecondition error indicates CSI operation returned failed precondition +// error +type FailedPrecondition struct { + msg string +} + +func (err *FailedPrecondition) Error() string { + return err.msg +} + +// NewFailedPreconditionError returns a new FailedPrecondition error instance +func NewFailedPreconditionError(msg string) *FailedPrecondition { + return &FailedPrecondition{msg: msg} +} + +// IsFailedPreconditionError checks if given error is of type that indicates +// operation failed with precondition +func IsFailedPreconditionError(err error) bool { + var failedPreconditionError *FailedPrecondition + return errors.As(err, &failedPreconditionError) +} + +// TransientOperationFailure indicates operation failed with a transient error +// and may fix itself when retried. +type TransientOperationFailure struct { + msg string +} + +func (err *TransientOperationFailure) Error() string { + return err.msg +} + +// NewTransientOperationFailure creates an instance of TransientOperationFailure error +func NewTransientOperationFailure(msg string) *TransientOperationFailure { + return &TransientOperationFailure{msg: msg} +} + +// UncertainProgressError indicates operation failed with a non-final error +// and operation may be in-progress in background. +type UncertainProgressError struct { + msg string +} + +func (err *UncertainProgressError) Error() string { + return err.msg +} + +// NewUncertainProgressError creates an instance of UncertainProgressError type +func NewUncertainProgressError(msg string) *UncertainProgressError { + return &UncertainProgressError{msg: msg} +} + +// IsOperationFinishedError checks if given error is of type that indicates +// operation is finished with a FINAL error. +func IsOperationFinishedError(err error) bool { + if _, ok := err.(*UncertainProgressError); ok { + return false + } + if _, ok := err.(*TransientOperationFailure); ok { + return false + } + return true +} + +// IsFilesystemMismatchError checks if mount failed because requested filesystem +// on PVC and actual filesystem on disk did not match +func IsFilesystemMismatchError(err error) bool { + mountError := mount.MountError{} + return errors.As(err, &mountError) && mountError.Type == mount.FilesystemMismatch +} + +// IsUncertainProgressError checks if given error is of type that indicates +// operation might be in-progress in background. +func IsUncertainProgressError(err error) bool { + if _, ok := err.(*UncertainProgressError); ok { + return true + } + return false +} + +const ( + // VolumeResizerKey is key that will be used to store resizer used + // for resizing PVC. The generated key/value pair will be added + // as a annotation to the PVC. + VolumeResizerKey = "volume.kubernetes.io/storage-resizer" +) diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/util.go b/vendor/k8s.io/kubernetes/pkg/volume/util/util.go new file mode 100644 index 000000000..f6f5a3f99 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/util.go @@ -0,0 +1,775 @@ +/* +Copyright 2015 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 util + +import ( + "context" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "reflect" + "runtime" + "strings" + "time" + + v1 "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + apiruntime "k8s.io/apimachinery/pkg/runtime" + utypes "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/wait" + utilfeature "k8s.io/apiserver/pkg/util/feature" + clientset "k8s.io/client-go/kubernetes" + storagehelpers "k8s.io/component-helpers/storage/volume" + "k8s.io/klog/v2" + "k8s.io/kubernetes/pkg/api/legacyscheme" + podutil "k8s.io/kubernetes/pkg/api/v1/pod" + "k8s.io/kubernetes/pkg/features" + "k8s.io/kubernetes/pkg/securitycontext" + "k8s.io/kubernetes/pkg/volume" + "k8s.io/kubernetes/pkg/volume/util/types" + "k8s.io/kubernetes/pkg/volume/util/volumepathhandler" + "k8s.io/mount-utils" + utilexec "k8s.io/utils/exec" + "k8s.io/utils/io" + utilstrings "k8s.io/utils/strings" +) + +const ( + readyFileName = "ready" + + // ControllerManagedAttachAnnotation is the key of the annotation on Node + // objects that indicates attach/detach operations for the node should be + // managed by the attach/detach controller + ControllerManagedAttachAnnotation string = "volumes.kubernetes.io/controller-managed-attach-detach" + + // KeepTerminatedPodVolumesAnnotation is the key of the annotation on Node + // that decides if pod volumes are unmounted when pod is terminated + KeepTerminatedPodVolumesAnnotation string = "volumes.kubernetes.io/keep-terminated-pod-volumes" + + // MountsInGlobalPDPath is name of the directory appended to a volume plugin + // name to create the place for volume mounts in the global PD path. + MountsInGlobalPDPath = "mounts" + + // VolumeGidAnnotationKey is the of the annotation on the PersistentVolume + // object that specifies a supplemental GID. + VolumeGidAnnotationKey = "pv.beta.kubernetes.io/gid" + + // VolumeDynamicallyCreatedByKey is the key of the annotation on PersistentVolume + // object created dynamically + VolumeDynamicallyCreatedByKey = "kubernetes.io/createdby" + + // kubernetesPluginPathPrefix is the prefix of kubernetes plugin mount paths. + kubernetesPluginPathPrefix = "/plugins/kubernetes.io/" +) + +// IsReady checks for the existence of a regular file +// called 'ready' in the given directory and returns +// true if that file exists. +func IsReady(dir string) bool { + readyFile := filepath.Join(dir, readyFileName) + s, err := os.Stat(readyFile) + if err != nil { + return false + } + + if !s.Mode().IsRegular() { + klog.Errorf("ready-file is not a file: %s", readyFile) + return false + } + + return true +} + +// SetReady creates a file called 'ready' in the given +// directory. It logs an error if the file cannot be +// created. +func SetReady(dir string) { + if err := os.MkdirAll(dir, 0750); err != nil && !os.IsExist(err) { + klog.Errorf("Can't mkdir %s: %v", dir, err) + return + } + + readyFile := filepath.Join(dir, readyFileName) + file, err := os.Create(readyFile) + if err != nil { + klog.Errorf("Can't touch %s: %v", readyFile, err) + return + } + file.Close() +} + +// GetSecretForPod locates secret by name in the pod's namespace and returns secret map +func GetSecretForPod(pod *v1.Pod, secretName string, kubeClient clientset.Interface) (map[string]string, error) { + secret := make(map[string]string) + if kubeClient == nil { + return secret, fmt.Errorf("cannot get kube client") + } + secrets, err := kubeClient.CoreV1().Secrets(pod.Namespace).Get(context.TODO(), secretName, metav1.GetOptions{}) + if err != nil { + return secret, err + } + for name, data := range secrets.Data { + secret[name] = string(data) + } + return secret, nil +} + +// GetSecretForPV locates secret by name and namespace, verifies the secret type, and returns secret map +func GetSecretForPV(secretNamespace, secretName, volumePluginName string, kubeClient clientset.Interface) (map[string]string, error) { + secret := make(map[string]string) + if kubeClient == nil { + return secret, fmt.Errorf("cannot get kube client") + } + secrets, err := kubeClient.CoreV1().Secrets(secretNamespace).Get(context.TODO(), secretName, metav1.GetOptions{}) + if err != nil { + return secret, err + } + if secrets.Type != v1.SecretType(volumePluginName) { + return secret, fmt.Errorf("cannot get secret of type %s", volumePluginName) + } + for name, data := range secrets.Data { + secret[name] = string(data) + } + return secret, nil +} + +// GetClassForVolume locates storage class by persistent volume +func GetClassForVolume(kubeClient clientset.Interface, pv *v1.PersistentVolume) (*storage.StorageClass, error) { + if kubeClient == nil { + return nil, fmt.Errorf("cannot get kube client") + } + className := storagehelpers.GetPersistentVolumeClass(pv) + if className == "" { + return nil, fmt.Errorf("volume has no storage class") + } + + class, err := kubeClient.StorageV1().StorageClasses().Get(context.TODO(), className, metav1.GetOptions{}) + if err != nil { + return nil, err + } + return class, nil +} + +// LoadPodFromFile will read, decode, and return a Pod from a file. +func LoadPodFromFile(filePath string) (*v1.Pod, error) { + if filePath == "" { + return nil, fmt.Errorf("file path not specified") + } + podDef, err := ioutil.ReadFile(filePath) + if err != nil { + return nil, fmt.Errorf("failed to read file path %s: %+v", filePath, err) + } + if len(podDef) == 0 { + return nil, fmt.Errorf("file was empty: %s", filePath) + } + pod := &v1.Pod{} + + codec := legacyscheme.Codecs.UniversalDecoder() + if err := apiruntime.DecodeInto(codec, podDef, pod); err != nil { + return nil, fmt.Errorf("failed decoding file: %v", err) + } + return pod, nil +} + +// CalculateTimeoutForVolume calculates time for a Recycler pod to complete a +// recycle operation. The calculation and return value is either the +// minimumTimeout or the timeoutIncrement per Gi of storage size, whichever is +// greater. +func CalculateTimeoutForVolume(minimumTimeout, timeoutIncrement int, pv *v1.PersistentVolume) int64 { + giQty := resource.MustParse("1Gi") + pvQty := pv.Spec.Capacity[v1.ResourceStorage] + giSize := giQty.Value() + pvSize := pvQty.Value() + timeout := (pvSize / giSize) * int64(timeoutIncrement) + if timeout < int64(minimumTimeout) { + return int64(minimumTimeout) + } + return timeout +} + +// GenerateVolumeName returns a PV name with clusterName prefix. The function +// should be used to generate a name of GCE PD or Cinder volume. It basically +// adds "-dynamic-" before the PV name, making sure the resulting +// string fits given length and cuts "dynamic" if not. +func GenerateVolumeName(clusterName, pvName string, maxLength int) string { + prefix := clusterName + "-dynamic" + pvLen := len(pvName) + + // cut the "-dynamic" to fit full pvName into maxLength + // +1 for the '-' dash + if pvLen+1+len(prefix) > maxLength { + prefix = prefix[:maxLength-pvLen-1] + } + return prefix + "-" + pvName +} + +// GetPath checks if the path from the mounter is empty. +func GetPath(mounter volume.Mounter) (string, error) { + path := mounter.GetPath() + if path == "" { + return "", fmt.Errorf("path is empty %s", reflect.TypeOf(mounter).String()) + } + return path, nil +} + +// UnmountViaEmptyDir delegates the tear down operation for secret, configmap, git_repo and downwardapi +// to empty_dir +func UnmountViaEmptyDir(dir string, host volume.VolumeHost, volName string, volSpec volume.Spec, podUID utypes.UID) error { + klog.V(3).Infof("Tearing down volume %v for pod %v at %v", volName, podUID, dir) + + // Wrap EmptyDir, let it do the teardown. + wrapped, err := host.NewWrapperUnmounter(volName, volSpec, podUID) + if err != nil { + return err + } + return wrapped.TearDownAt(dir) +} + +// MountOptionFromSpec extracts and joins mount options from volume spec with supplied options +func MountOptionFromSpec(spec *volume.Spec, options ...string) []string { + pv := spec.PersistentVolume + + if pv != nil { + // Use beta annotation first + if mo, ok := pv.Annotations[v1.MountOptionAnnotation]; ok { + moList := strings.Split(mo, ",") + return JoinMountOptions(moList, options) + } + + if len(pv.Spec.MountOptions) > 0 { + return JoinMountOptions(pv.Spec.MountOptions, options) + } + } + + return options +} + +// JoinMountOptions joins mount options eliminating duplicates +func JoinMountOptions(userOptions []string, systemOptions []string) []string { + allMountOptions := sets.NewString() + + for _, mountOption := range userOptions { + if len(mountOption) > 0 { + allMountOptions.Insert(mountOption) + } + } + + for _, mountOption := range systemOptions { + allMountOptions.Insert(mountOption) + } + return allMountOptions.List() +} + +// ContainsAccessMode returns whether the requested mode is contained by modes +func ContainsAccessMode(modes []v1.PersistentVolumeAccessMode, mode v1.PersistentVolumeAccessMode) bool { + for _, m := range modes { + if m == mode { + return true + } + } + return false +} + +// ContainsAllAccessModes returns whether all of the requested modes are contained by modes +func ContainsAllAccessModes(indexedModes []v1.PersistentVolumeAccessMode, requestedModes []v1.PersistentVolumeAccessMode) bool { + for _, mode := range requestedModes { + if !ContainsAccessMode(indexedModes, mode) { + return false + } + } + return true +} + +// GetWindowsPath get a windows path +func GetWindowsPath(path string) string { + windowsPath := strings.Replace(path, "/", "\\", -1) + if strings.HasPrefix(windowsPath, "\\") { + windowsPath = "c:" + windowsPath + } + return windowsPath +} + +// GetUniquePodName returns a unique identifier to reference a pod by +func GetUniquePodName(pod *v1.Pod) types.UniquePodName { + return types.UniquePodName(pod.UID) +} + +// GetUniqueVolumeName returns a unique name representing the volume/plugin. +// Caller should ensure that volumeName is a name/ID uniquely identifying the +// actual backing device, directory, path, etc. for a particular volume. +// The returned name can be used to uniquely reference the volume, for example, +// to prevent operations (attach/detach or mount/unmount) from being triggered +// on the same volume. +func GetUniqueVolumeName(pluginName, volumeName string) v1.UniqueVolumeName { + return v1.UniqueVolumeName(fmt.Sprintf("%s/%s", pluginName, volumeName)) +} + +// GetUniqueVolumeNameFromSpecWithPod returns a unique volume name with pod +// name included. This is useful to generate different names for different pods +// on same volume. +func GetUniqueVolumeNameFromSpecWithPod( + podName types.UniquePodName, volumePlugin volume.VolumePlugin, volumeSpec *volume.Spec) v1.UniqueVolumeName { + return v1.UniqueVolumeName( + fmt.Sprintf("%s/%v-%s", volumePlugin.GetPluginName(), podName, volumeSpec.Name())) +} + +// GetUniqueVolumeNameFromSpec uses the given VolumePlugin to generate a unique +// name representing the volume defined in the specified volume spec. +// This returned name can be used to uniquely reference the actual backing +// device, directory, path, etc. referenced by the given volumeSpec. +// If the given plugin does not support the volume spec, this returns an error. +func GetUniqueVolumeNameFromSpec( + volumePlugin volume.VolumePlugin, + volumeSpec *volume.Spec) (v1.UniqueVolumeName, error) { + if volumePlugin == nil { + return "", fmt.Errorf( + "volumePlugin should not be nil. volumeSpec.Name=%q", + volumeSpec.Name()) + } + + volumeName, err := volumePlugin.GetVolumeName(volumeSpec) + if err != nil || volumeName == "" { + return "", fmt.Errorf( + "failed to GetVolumeName from volumePlugin for volumeSpec %q err=%v", + volumeSpec.Name(), + err) + } + + return GetUniqueVolumeName( + volumePlugin.GetPluginName(), + volumeName), + nil +} + +// IsPodTerminated checks if pod is terminated +func IsPodTerminated(pod *v1.Pod, podStatus v1.PodStatus) bool { + // TODO: the guarantees provided by kubelet status are not sufficient to guarantee it's safe to ignore a deleted pod, + // even if everything is notRunning (kubelet does not guarantee that when pod status is waiting that it isn't trying + // to start a container). + return podStatus.Phase == v1.PodFailed || podStatus.Phase == v1.PodSucceeded || (pod.DeletionTimestamp != nil && notRunning(podStatus.InitContainerStatuses) && notRunning(podStatus.ContainerStatuses) && notRunning(podStatus.EphemeralContainerStatuses)) +} + +// notRunning returns true if every status is terminated or waiting, or the status list +// is empty. +func notRunning(statuses []v1.ContainerStatus) bool { + for _, status := range statuses { + if status.State.Terminated == nil && status.State.Waiting == nil { + return false + } + } + return true +} + +// SplitUniqueName splits the unique name to plugin name and volume name strings. It expects the uniqueName to follow +// the format plugin_name/volume_name and the plugin name must be namespaced as described by the plugin interface, +// i.e. namespace/plugin containing exactly one '/'. This means the unique name will always be in the form of +// plugin_namespace/plugin/volume_name, see k8s.io/kubernetes/pkg/volume/plugins.go VolumePlugin interface +// description and pkg/volume/util/volumehelper/volumehelper.go GetUniqueVolumeNameFromSpec that constructs +// the unique volume names. +func SplitUniqueName(uniqueName v1.UniqueVolumeName) (string, string, error) { + components := strings.SplitN(string(uniqueName), "/", 3) + if len(components) != 3 { + return "", "", fmt.Errorf("cannot split volume unique name %s to plugin/volume components", uniqueName) + } + pluginName := fmt.Sprintf("%s/%s", components[0], components[1]) + return pluginName, components[2], nil +} + +// NewSafeFormatAndMountFromHost creates a new SafeFormatAndMount with Mounter +// and Exec taken from given VolumeHost. +func NewSafeFormatAndMountFromHost(pluginName string, host volume.VolumeHost) *mount.SafeFormatAndMount { + mounter := host.GetMounter(pluginName) + exec := host.GetExec(pluginName) + return &mount.SafeFormatAndMount{Interface: mounter, Exec: exec} +} + +// GetVolumeMode retrieves VolumeMode from pv. +// If the volume doesn't have PersistentVolume, it's an inline volume, +// should return volumeMode as filesystem to keep existing behavior. +func GetVolumeMode(volumeSpec *volume.Spec) (v1.PersistentVolumeMode, error) { + if volumeSpec == nil || volumeSpec.PersistentVolume == nil { + return v1.PersistentVolumeFilesystem, nil + } + if volumeSpec.PersistentVolume.Spec.VolumeMode != nil { + return *volumeSpec.PersistentVolume.Spec.VolumeMode, nil + } + return "", fmt.Errorf("cannot get volumeMode for volume: %v", volumeSpec.Name()) +} + +// GetPersistentVolumeClaimQualifiedName returns a qualified name for pvc. +func GetPersistentVolumeClaimQualifiedName(claim *v1.PersistentVolumeClaim) string { + return utilstrings.JoinQualifiedName(claim.GetNamespace(), claim.GetName()) +} + +// CheckVolumeModeFilesystem checks VolumeMode. +// If the mode is Filesystem, return true otherwise return false. +func CheckVolumeModeFilesystem(volumeSpec *volume.Spec) (bool, error) { + volumeMode, err := GetVolumeMode(volumeSpec) + if err != nil { + return true, err + } + if volumeMode == v1.PersistentVolumeBlock { + return false, nil + } + return true, nil +} + +// CheckPersistentVolumeClaimModeBlock checks VolumeMode. +// If the mode is Block, return true otherwise return false. +func CheckPersistentVolumeClaimModeBlock(pvc *v1.PersistentVolumeClaim) bool { + return pvc.Spec.VolumeMode != nil && *pvc.Spec.VolumeMode == v1.PersistentVolumeBlock +} + +// IsWindowsUNCPath checks if path is prefixed with \\ +// This can be used to skip any processing of paths +// that point to SMB shares, local named pipes and local UNC path +func IsWindowsUNCPath(goos, path string) bool { + if goos != "windows" { + return false + } + // Check for UNC prefix \\ + if strings.HasPrefix(path, `\\`) { + return true + } + return false +} + +// IsWindowsLocalPath checks if path is a local path +// prefixed with "/" or "\" like "/foo/bar" or "\foo\bar" +func IsWindowsLocalPath(goos, path string) bool { + if goos != "windows" { + return false + } + if IsWindowsUNCPath(goos, path) { + return false + } + if strings.Contains(path, ":") { + return false + } + if !(strings.HasPrefix(path, `/`) || strings.HasPrefix(path, `\`)) { + return false + } + return true +} + +// MakeAbsolutePath convert path to absolute path according to GOOS +func MakeAbsolutePath(goos, path string) string { + if goos != "windows" { + return filepath.Clean("/" + path) + } + // These are all for windows + // If there is a colon, give up. + if strings.Contains(path, ":") { + return path + } + // If there is a slash, but no drive, add 'c:' + if strings.HasPrefix(path, "/") || strings.HasPrefix(path, "\\") { + return "c:" + path + } + // Otherwise, add 'c:\' + return "c:\\" + path +} + +// MapBlockVolume is a utility function to provide a common way of mapping +// block device path for a specified volume and pod. This function should be +// called by volume plugins that implements volume.BlockVolumeMapper.Map() method. +func MapBlockVolume( + blkUtil volumepathhandler.BlockVolumePathHandler, + devicePath, + globalMapPath, + podVolumeMapPath, + volumeMapName string, + podUID utypes.UID, +) error { + // map devicePath to global node path as bind mount + mapErr := blkUtil.MapDevice(devicePath, globalMapPath, string(podUID), true /* bindMount */) + if mapErr != nil { + return fmt.Errorf("blkUtil.MapDevice failed. devicePath: %s, globalMapPath:%s, podUID: %s, bindMount: %v: %v", + devicePath, globalMapPath, string(podUID), true, mapErr) + } + + // map devicePath to pod volume path + mapErr = blkUtil.MapDevice(devicePath, podVolumeMapPath, volumeMapName, false /* bindMount */) + if mapErr != nil { + return fmt.Errorf("blkUtil.MapDevice failed. devicePath: %s, podVolumeMapPath:%s, volumeMapName: %s, bindMount: %v: %v", + devicePath, podVolumeMapPath, volumeMapName, false, mapErr) + } + + // Take file descriptor lock to keep a block device opened. Otherwise, there is a case + // that the block device is silently removed and attached another device with the same name. + // Container runtime can't handle this problem. To avoid unexpected condition fd lock + // for the block device is required. + _, mapErr = blkUtil.AttachFileDevice(filepath.Join(globalMapPath, string(podUID))) + if mapErr != nil { + return fmt.Errorf("blkUtil.AttachFileDevice failed. globalMapPath:%s, podUID: %s: %v", + globalMapPath, string(podUID), mapErr) + } + + return nil +} + +// UnmapBlockVolume is a utility function to provide a common way of unmapping +// block device path for a specified volume and pod. This function should be +// called by volume plugins that implements volume.BlockVolumeMapper.Map() method. +func UnmapBlockVolume( + blkUtil volumepathhandler.BlockVolumePathHandler, + globalUnmapPath, + podDeviceUnmapPath, + volumeMapName string, + podUID utypes.UID, +) error { + // Release file descriptor lock. + err := blkUtil.DetachFileDevice(filepath.Join(globalUnmapPath, string(podUID))) + if err != nil { + return fmt.Errorf("blkUtil.DetachFileDevice failed. globalUnmapPath:%s, podUID: %s: %v", + globalUnmapPath, string(podUID), err) + } + + // unmap devicePath from pod volume path + unmapDeviceErr := blkUtil.UnmapDevice(podDeviceUnmapPath, volumeMapName, false /* bindMount */) + if unmapDeviceErr != nil { + return fmt.Errorf("blkUtil.DetachFileDevice failed. podDeviceUnmapPath:%s, volumeMapName: %s, bindMount: %v: %v", + podDeviceUnmapPath, volumeMapName, false, unmapDeviceErr) + } + + // unmap devicePath from global node path + unmapDeviceErr = blkUtil.UnmapDevice(globalUnmapPath, string(podUID), true /* bindMount */) + if unmapDeviceErr != nil { + return fmt.Errorf("blkUtil.DetachFileDevice failed. globalUnmapPath:%s, podUID: %s, bindMount: %v: %v", + globalUnmapPath, string(podUID), true, unmapDeviceErr) + } + return nil +} + +// GetPluginMountDir returns the global mount directory name appended +// to the given plugin name's plugin directory +func GetPluginMountDir(host volume.VolumeHost, name string) string { + mntDir := filepath.Join(host.GetPluginDir(name), MountsInGlobalPDPath) + return mntDir +} + +// IsLocalEphemeralVolume determines whether the argument is a local ephemeral +// volume vs. some other type +// Local means the volume is using storage from the local disk that is managed by kubelet. +// Ephemeral means the lifecycle of the volume is the same as the Pod. +func IsLocalEphemeralVolume(volume v1.Volume) bool { + return volume.GitRepo != nil || + (volume.EmptyDir != nil && volume.EmptyDir.Medium == v1.StorageMediumDefault) || + volume.ConfigMap != nil +} + +// GetPodVolumeNames returns names of volumes that are used in a pod, +// either as filesystem mount or raw block device, together with list +// of all SELinux contexts of all containers that use the volumes. +func GetPodVolumeNames(pod *v1.Pod) (mounts sets.String, devices sets.String, seLinuxContainerContexts map[string][]*v1.SELinuxOptions) { + mounts = sets.NewString() + devices = sets.NewString() + seLinuxContainerContexts = make(map[string][]*v1.SELinuxOptions) + + podutil.VisitContainers(&pod.Spec, podutil.AllFeatureEnabledContainers(), func(container *v1.Container, containerType podutil.ContainerType) bool { + var seLinuxOptions *v1.SELinuxOptions + if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) { + effectiveContainerSecurity := securitycontext.DetermineEffectiveSecurityContext(pod, container) + if effectiveContainerSecurity != nil { + // No DeepCopy, SELinuxOptions is already a copy of Pod's or container's SELinuxOptions + seLinuxOptions = effectiveContainerSecurity.SELinuxOptions + } + } + + if container.VolumeMounts != nil { + for _, mount := range container.VolumeMounts { + mounts.Insert(mount.Name) + if seLinuxOptions != nil { + seLinuxContainerContexts[mount.Name] = append(seLinuxContainerContexts[mount.Name], seLinuxOptions.DeepCopy()) + } + } + } + if container.VolumeDevices != nil { + for _, device := range container.VolumeDevices { + devices.Insert(device.Name) + } + } + return true + }) + return +} + +// FsUserFrom returns FsUser of pod, which is determined by the runAsUser +// attributes. +func FsUserFrom(pod *v1.Pod) *int64 { + var fsUser *int64 + // Exclude ephemeral containers because SecurityContext is not allowed. + podutil.VisitContainers(&pod.Spec, podutil.InitContainers|podutil.Containers, func(container *v1.Container, containerType podutil.ContainerType) bool { + runAsUser, ok := securitycontext.DetermineEffectiveRunAsUser(pod, container) + // One container doesn't specify user or there are more than one + // non-root UIDs. + if !ok || (fsUser != nil && *fsUser != *runAsUser) { + fsUser = nil + return false + } + if fsUser == nil { + fsUser = runAsUser + } + return true + }) + return fsUser +} + +// HasMountRefs checks if the given mountPath has mountRefs. +// TODO: this is a workaround for the unmount device issue caused by gci mounter. +// In GCI cluster, if gci mounter is used for mounting, the container started by mounter +// script will cause additional mounts created in the container. Since these mounts are +// irrelevant to the original mounts, they should be not considered when checking the +// mount references. The current solution is to filter out those mount paths that contain +// the k8s plugin suffix of original mount path. +func HasMountRefs(mountPath string, mountRefs []string) bool { + // A mountPath typically is like + // /var/lib/kubelet/plugins/kubernetes.io/some-plugin/mounts/volume-XXXX + // Mount refs can look like + // /home/somewhere/var/lib/kubelet/plugins/kubernetes.io/some-plugin/... + // but if /var/lib/kubelet is mounted to a different device a ref might be like + // /mnt/some-other-place/kubelet/plugins/kubernetes.io/some-plugin/... + // Neither of the above should be counted as a mount ref as those are handled + // by the kubelet. What we're concerned about is a path like + // /data/local/some/manual/mount + // As unmonting could interrupt usage from that mountpoint. + // + // So instead of looking for the entire /var/lib/... path, the plugins/kuberentes.io/ + // suffix is trimmed off and searched for. + // + // If there isn't a /plugins/... path, the whole mountPath is used instead. + pathToFind := mountPath + if i := strings.Index(mountPath, kubernetesPluginPathPrefix); i > -1 { + pathToFind = mountPath[i:] + } + for _, ref := range mountRefs { + if !strings.Contains(ref, pathToFind) { + return true + } + } + return false +} + +// WriteVolumeCache flush disk data given the spcified mount path +func WriteVolumeCache(deviceMountPath string, exec utilexec.Interface) error { + // If runtime os is windows, execute Write-VolumeCache powershell command on the disk + if runtime.GOOS == "windows" { + cmd := fmt.Sprintf("Get-Volume -FilePath %s | Write-Volumecache", deviceMountPath) + output, err := exec.Command("powershell", "/c", cmd).CombinedOutput() + klog.Infof("command (%q) execeuted: %v, output: %q", cmd, err, string(output)) + if err != nil { + return fmt.Errorf("command (%q) failed: %v, output: %q", cmd, err, string(output)) + } + } + // For linux runtime, it skips because unmount will automatically flush disk data + return nil +} + +// IsMultiAttachAllowed checks if attaching this volume to multiple nodes is definitely not allowed/possible. +// In its current form, this function can only reliably say for which volumes it's definitely forbidden. If it returns +// false, it is not guaranteed that multi-attach is actually supported by the volume type and we must rely on the +// attacher to fail fast in such cases. +// Please see https://github.com/kubernetes/kubernetes/issues/40669 and https://github.com/kubernetes/kubernetes/pull/40148#discussion_r98055047 +func IsMultiAttachAllowed(volumeSpec *volume.Spec) bool { + if volumeSpec == nil { + // we don't know if it's supported or not and let the attacher fail later in cases it's not supported + return true + } + + if volumeSpec.Volume != nil { + // Check for volume types which are known to fail slow or cause trouble when trying to multi-attach + if volumeSpec.Volume.AzureDisk != nil || + volumeSpec.Volume.Cinder != nil { + return false + } + } + + // Only if this volume is a persistent volume, we have reliable information on whether it's allowed or not to + // multi-attach. We trust in the individual volume implementations to not allow unsupported access modes + if volumeSpec.PersistentVolume != nil { + // Check for persistent volume types which do not fail when trying to multi-attach + if len(volumeSpec.PersistentVolume.Spec.AccessModes) == 0 { + // No access mode specified so we don't know for sure. Let the attacher fail if needed + return true + } + + // check if this volume is allowed to be attached to multiple PODs/nodes, if yes, return false + for _, accessMode := range volumeSpec.PersistentVolume.Spec.AccessModes { + if accessMode == v1.ReadWriteMany || accessMode == v1.ReadOnlyMany { + return true + } + } + return false + } + + // we don't know if it's supported or not and let the attacher fail later in cases it's not supported + return true +} + +// IsAttachableVolume checks if the given volumeSpec is an attachable volume or not +func IsAttachableVolume(volumeSpec *volume.Spec, volumePluginMgr *volume.VolumePluginMgr) bool { + attachableVolumePlugin, _ := volumePluginMgr.FindAttachablePluginBySpec(volumeSpec) + if attachableVolumePlugin != nil { + volumeAttacher, err := attachableVolumePlugin.NewAttacher() + if err == nil && volumeAttacher != nil { + return true + } + } + + return false +} + +// IsDeviceMountableVolume checks if the given volumeSpec is an device mountable volume or not +func IsDeviceMountableVolume(volumeSpec *volume.Spec, volumePluginMgr *volume.VolumePluginMgr) bool { + deviceMountableVolumePlugin, _ := volumePluginMgr.FindDeviceMountablePluginBySpec(volumeSpec) + if deviceMountableVolumePlugin != nil { + volumeDeviceMounter, err := deviceMountableVolumePlugin.NewDeviceMounter() + if err == nil && volumeDeviceMounter != nil { + return true + } + } + + return false +} + +// GetReliableMountRefs calls mounter.GetMountRefs and retries on IsInconsistentReadError. +// To be used in volume reconstruction of volume plugins that don't have any protection +// against mounting a single volume on multiple nodes (such as attach/detach). +func GetReliableMountRefs(mounter mount.Interface, mountPath string) ([]string, error) { + var paths []string + var lastErr error + err := wait.PollImmediate(10*time.Millisecond, time.Minute, func() (bool, error) { + var err error + paths, err = mounter.GetMountRefs(mountPath) + if io.IsInconsistentReadError(err) { + lastErr = err + return false, nil + } + if err != nil { + return false, err + } + return true, nil + }) + if err == wait.ErrWaitTimeout { + return nil, lastErr + } + return paths, err +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/volumepathhandler/volume_path_handler.go b/vendor/k8s.io/kubernetes/pkg/volume/util/volumepathhandler/volume_path_handler.go new file mode 100644 index 000000000..1de7c52a5 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/volumepathhandler/volume_path_handler.go @@ -0,0 +1,296 @@ +/* +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 volumepathhandler + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "k8s.io/klog/v2" + "k8s.io/mount-utils" + utilexec "k8s.io/utils/exec" + + "k8s.io/apimachinery/pkg/types" +) + +const ( + losetupPath = "losetup" + ErrDeviceNotFound = "device not found" +) + +// BlockVolumePathHandler defines a set of operations for handling block volume-related operations +type BlockVolumePathHandler interface { + // MapDevice creates a symbolic link to block device under specified map path + MapDevice(devicePath string, mapPath string, linkName string, bindMount bool) error + // UnmapDevice removes a symbolic link to block device under specified map path + UnmapDevice(mapPath string, linkName string, bindMount bool) error + // RemovePath removes a file or directory on specified map path + RemoveMapPath(mapPath string) error + // IsSymlinkExist returns true if specified symbolic link exists + IsSymlinkExist(mapPath string) (bool, error) + // IsDeviceBindMountExist returns true if specified bind mount exists + IsDeviceBindMountExist(mapPath string) (bool, error) + // GetDeviceBindMountRefs searches bind mounts under global map path + GetDeviceBindMountRefs(devPath string, mapPath string) ([]string, error) + // FindGlobalMapPathUUIDFromPod finds {pod uuid} symbolic link under globalMapPath + // corresponding to map path symlink, and then return global map path with pod uuid. + FindGlobalMapPathUUIDFromPod(pluginDir, mapPath string, podUID types.UID) (string, error) + // AttachFileDevice takes a path to a regular file and makes it available as an + // attached block device. + AttachFileDevice(path string) (string, error) + // DetachFileDevice takes a path to the attached block device and + // detach it from block device. + DetachFileDevice(path string) error + // GetLoopDevice returns the full path to the loop device associated with the given path. + GetLoopDevice(path string) (string, error) +} + +// NewBlockVolumePathHandler returns a new instance of BlockVolumeHandler. +func NewBlockVolumePathHandler() BlockVolumePathHandler { + var volumePathHandler VolumePathHandler + return volumePathHandler +} + +// VolumePathHandler is path related operation handlers for block volume +type VolumePathHandler struct { +} + +// MapDevice creates a symbolic link to block device under specified map path +func (v VolumePathHandler) MapDevice(devicePath string, mapPath string, linkName string, bindMount bool) error { + // Example of global map path: + // globalMapPath/linkName: plugins/kubernetes.io/{PluginName}/{DefaultKubeletVolumeDevicesDirName}/{volumePluginDependentPath}/{podUid} + // linkName: {podUid} + // + // Example of pod device map path: + // podDeviceMapPath/linkName: pods/{podUid}/{DefaultKubeletVolumeDevicesDirName}/{escapeQualifiedPluginName}/{volumeName} + // linkName: {volumeName} + if len(devicePath) == 0 { + return fmt.Errorf("failed to map device to map path. devicePath is empty") + } + if len(mapPath) == 0 { + return fmt.Errorf("failed to map device to map path. mapPath is empty") + } + if !filepath.IsAbs(mapPath) { + return fmt.Errorf("the map path should be absolute: map path: %s", mapPath) + } + klog.V(5).Infof("MapDevice: devicePath %s", devicePath) + klog.V(5).Infof("MapDevice: mapPath %s", mapPath) + klog.V(5).Infof("MapDevice: linkName %s", linkName) + + // Check and create mapPath + _, err := os.Stat(mapPath) + if err != nil && !os.IsNotExist(err) { + return fmt.Errorf("cannot validate map path: %s: %v", mapPath, err) + } + if err = os.MkdirAll(mapPath, 0750); err != nil { + return fmt.Errorf("failed to mkdir %s: %v", mapPath, err) + } + + if bindMount { + return mapBindMountDevice(v, devicePath, mapPath, linkName) + } + return mapSymlinkDevice(v, devicePath, mapPath, linkName) +} + +func mapBindMountDevice(v VolumePathHandler, devicePath string, mapPath string, linkName string) error { + // Check bind mount exists + linkPath := filepath.Join(mapPath, string(linkName)) + + file, err := os.Stat(linkPath) + if err != nil { + if !os.IsNotExist(err) { + return fmt.Errorf("failed to stat file %s: %v", linkPath, err) + } + + // Create file + newFile, err := os.OpenFile(linkPath, os.O_CREATE|os.O_RDWR, 0750) + if err != nil { + return fmt.Errorf("failed to open file %s: %v", linkPath, err) + } + if err := newFile.Close(); err != nil { + return fmt.Errorf("failed to close file %s: %v", linkPath, err) + } + } else { + // Check if device file + // TODO: Need to check if this device file is actually the expected bind mount + if file.Mode()&os.ModeDevice == os.ModeDevice { + klog.Warningf("Warning: Map skipped because bind mount already exist on the path: %v", linkPath) + return nil + } + + klog.Warningf("Warning: file %s is already exist but not mounted, skip creating file", linkPath) + } + + // Bind mount file + mounter := &mount.SafeFormatAndMount{Interface: mount.New(""), Exec: utilexec.New()} + if err := mounter.MountSensitiveWithoutSystemd(devicePath, linkPath, "" /* fsType */, []string{"bind"}, nil); err != nil { + return fmt.Errorf("failed to bind mount devicePath: %s to linkPath %s: %v", devicePath, linkPath, err) + } + + return nil +} + +func mapSymlinkDevice(v VolumePathHandler, devicePath string, mapPath string, linkName string) error { + // Remove old symbolic link(or file) then create new one. + // This should be done because current symbolic link is + // stale across node reboot. + linkPath := filepath.Join(mapPath, string(linkName)) + if err := os.Remove(linkPath); err != nil && !os.IsNotExist(err) { + return fmt.Errorf("failed to remove file %s: %v", linkPath, err) + } + return os.Symlink(devicePath, linkPath) +} + +// UnmapDevice removes a symbolic link associated to block device under specified map path +func (v VolumePathHandler) UnmapDevice(mapPath string, linkName string, bindMount bool) error { + if len(mapPath) == 0 { + return fmt.Errorf("failed to unmap device from map path. mapPath is empty") + } + klog.V(5).Infof("UnmapDevice: mapPath %s", mapPath) + klog.V(5).Infof("UnmapDevice: linkName %s", linkName) + + if bindMount { + return unmapBindMountDevice(v, mapPath, linkName) + } + return unmapSymlinkDevice(v, mapPath, linkName) +} + +func unmapBindMountDevice(v VolumePathHandler, mapPath string, linkName string) error { + // Check bind mount exists + linkPath := filepath.Join(mapPath, string(linkName)) + if isMountExist, checkErr := v.IsDeviceBindMountExist(linkPath); checkErr != nil { + return checkErr + } else if !isMountExist { + klog.Warningf("Warning: Unmap skipped because bind mount does not exist on the path: %v", linkPath) + + // Check if linkPath still exists + if _, err := os.Stat(linkPath); err != nil { + if !os.IsNotExist(err) { + return fmt.Errorf("failed to check if path %s exists: %v", linkPath, err) + } + // linkPath has already been removed + return nil + } + // Remove file + if err := os.Remove(linkPath); err != nil && !os.IsNotExist(err) { + return fmt.Errorf("failed to remove file %s: %v", linkPath, err) + } + return nil + } + + // Unmount file + mounter := &mount.SafeFormatAndMount{Interface: mount.New(""), Exec: utilexec.New()} + if err := mounter.Unmount(linkPath); err != nil { + return fmt.Errorf("failed to unmount linkPath %s: %v", linkPath, err) + } + + // Remove file + if err := os.Remove(linkPath); err != nil && !os.IsNotExist(err) { + return fmt.Errorf("failed to remove file %s: %v", linkPath, err) + } + + return nil +} + +func unmapSymlinkDevice(v VolumePathHandler, mapPath string, linkName string) error { + // Check symbolic link exists + linkPath := filepath.Join(mapPath, string(linkName)) + if islinkExist, checkErr := v.IsSymlinkExist(linkPath); checkErr != nil { + return checkErr + } else if !islinkExist { + klog.Warningf("Warning: Unmap skipped because symlink does not exist on the path: %v", linkPath) + return nil + } + return os.Remove(linkPath) +} + +// RemoveMapPath removes a file or directory on specified map path +func (v VolumePathHandler) RemoveMapPath(mapPath string) error { + if len(mapPath) == 0 { + return fmt.Errorf("failed to remove map path. mapPath is empty") + } + klog.V(5).Infof("RemoveMapPath: mapPath %s", mapPath) + err := os.RemoveAll(mapPath) + if err != nil && !os.IsNotExist(err) { + return fmt.Errorf("failed to remove directory %s: %v", mapPath, err) + } + return nil +} + +// IsSymlinkExist returns true if specified file exists and the type is symbolik link. +// If file doesn't exist, or file exists but not symbolic link, return false with no error. +// On other cases, return false with error from Lstat(). +func (v VolumePathHandler) IsSymlinkExist(mapPath string) (bool, error) { + fi, err := os.Lstat(mapPath) + if err != nil { + // If file doesn't exist, return false and no error + if os.IsNotExist(err) { + return false, nil + } + // Return error from Lstat() + return false, fmt.Errorf("failed to Lstat file %s: %v", mapPath, err) + } + // If file exits and it's symbolic link, return true and no error + if fi.Mode()&os.ModeSymlink == os.ModeSymlink { + return true, nil + } + // If file exits but it's not symbolic link, return false and no error + return false, nil +} + +// IsDeviceBindMountExist returns true if specified file exists and the type is device. +// If file doesn't exist, or file exists but not device, return false with no error. +// On other cases, return false with error from Lstat(). +func (v VolumePathHandler) IsDeviceBindMountExist(mapPath string) (bool, error) { + fi, err := os.Lstat(mapPath) + if err != nil { + // If file doesn't exist, return false and no error + if os.IsNotExist(err) { + return false, nil + } + + // Return error from Lstat() + return false, fmt.Errorf("failed to Lstat file %s: %v", mapPath, err) + } + // If file exits and it's device, return true and no error + if fi.Mode()&os.ModeDevice == os.ModeDevice { + return true, nil + } + // If file exits but it's not device, return false and no error + return false, nil +} + +// GetDeviceBindMountRefs searches bind mounts under global map path +func (v VolumePathHandler) GetDeviceBindMountRefs(devPath string, mapPath string) ([]string, error) { + var refs []string + files, err := ioutil.ReadDir(mapPath) + if err != nil { + return nil, err + } + for _, file := range files { + if file.Mode()&os.ModeDevice != os.ModeDevice { + continue + } + filename := file.Name() + // TODO: Might need to check if the file is actually linked to devPath + refs = append(refs, filepath.Join(mapPath, filename)) + } + klog.V(5).Infof("GetDeviceBindMountRefs: refs %v", refs) + return refs, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/volumepathhandler/volume_path_handler_linux.go b/vendor/k8s.io/kubernetes/pkg/volume/util/volumepathhandler/volume_path_handler_linux.go new file mode 100644 index 000000000..aae1b39ac --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/volumepathhandler/volume_path_handler_linux.go @@ -0,0 +1,229 @@ +//go:build linux +// +build linux + +/* +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 volumepathhandler + +import ( + "errors" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + + "golang.org/x/sys/unix" + + "k8s.io/apimachinery/pkg/types" + "k8s.io/klog/v2" +) + +// AttachFileDevice takes a path to a regular file and makes it available as an +// attached block device. +func (v VolumePathHandler) AttachFileDevice(path string) (string, error) { + blockDevicePath, err := v.GetLoopDevice(path) + if err != nil && err.Error() != ErrDeviceNotFound { + return "", fmt.Errorf("GetLoopDevice failed for path %s: %v", path, err) + } + + // If no existing loop device for the path, create one + if blockDevicePath == "" { + klog.V(4).Infof("Creating device for path: %s", path) + blockDevicePath, err = makeLoopDevice(path) + if err != nil { + return "", fmt.Errorf("makeLoopDevice failed for path %s: %v", path, err) + } + } + return blockDevicePath, nil +} + +// DetachFileDevice takes a path to the attached block device and +// detach it from block device. +func (v VolumePathHandler) DetachFileDevice(path string) error { + loopPath, err := v.GetLoopDevice(path) + if err != nil { + if err.Error() == ErrDeviceNotFound { + klog.Warningf("couldn't find loopback device which takes file descriptor lock. Skip detaching device. device path: %q", path) + } else { + return fmt.Errorf("GetLoopDevice failed for path %s: %v", path, err) + } + } else { + if len(loopPath) != 0 { + err = removeLoopDevice(loopPath) + if err != nil { + return fmt.Errorf("removeLoopDevice failed for path %s: %v", path, err) + } + } + } + return nil +} + +// GetLoopDevice returns the full path to the loop device associated with the given path. +func (v VolumePathHandler) GetLoopDevice(path string) (string, error) { + _, err := os.Stat(path) + if os.IsNotExist(err) { + return "", errors.New(ErrDeviceNotFound) + } + if err != nil { + return "", fmt.Errorf("not attachable: %v", err) + } + + return getLoopDeviceFromSysfs(path) +} + +func makeLoopDevice(path string) (string, error) { + args := []string{"-f", path} + cmd := exec.Command(losetupPath, args...) + + out, err := cmd.CombinedOutput() + if err != nil { + klog.V(2).Infof("Failed device create command for path: %s %v %s", path, err, out) + return "", fmt.Errorf("losetup %s failed: %v", strings.Join(args, " "), err) + } + + return getLoopDeviceFromSysfs(path) +} + +// removeLoopDevice removes specified loopback device +func removeLoopDevice(device string) error { + args := []string{"-d", device} + cmd := exec.Command(losetupPath, args...) + out, err := cmd.CombinedOutput() + if err != nil { + if _, err := os.Stat(device); os.IsNotExist(err) { + return nil + } + klog.V(2).Infof("Failed to remove loopback device: %s: %v %s", device, err, out) + return fmt.Errorf("losetup -d %s failed: %v", device, err) + } + return nil +} + +// getLoopDeviceFromSysfs finds the backing file for a loop +// device from sysfs via "/sys/block/loop*/loop/backing_file". +func getLoopDeviceFromSysfs(path string) (string, error) { + // If the file is a symlink. + realPath, err := filepath.EvalSymlinks(path) + if err != nil { + return "", fmt.Errorf("failed to evaluate path %s: %s", path, err) + } + + devices, err := filepath.Glob("/sys/block/loop*") + if err != nil { + return "", fmt.Errorf("failed to list loop devices in sysfs: %s", err) + } + + for _, device := range devices { + backingFile := fmt.Sprintf("%s/loop/backing_file", device) + + // The contents of this file is the absolute path of "path". + data, err := ioutil.ReadFile(backingFile) + if err != nil { + continue + } + + // Return the first match. + backingFilePath := strings.TrimSpace(string(data)) + if backingFilePath == path || backingFilePath == realPath { + return fmt.Sprintf("/dev/%s", filepath.Base(device)), nil + } + } + + return "", errors.New(ErrDeviceNotFound) +} + +// FindGlobalMapPathUUIDFromPod finds {pod uuid} bind mount under globalMapPath +// corresponding to map path symlink, and then return global map path with pod uuid. +// (See pkg/volume/volume.go for details on a global map path and a pod device map path.) +// ex. mapPath symlink: pods/{podUid}}/{DefaultKubeletVolumeDevicesDirName}/{escapeQualifiedPluginName}/{volumeName} -> /dev/sdX +// +// globalMapPath/{pod uuid} bind mount: plugins/kubernetes.io/{PluginName}/{DefaultKubeletVolumeDevicesDirName}/{volumePluginDependentPath}/{pod uuid} -> /dev/sdX +func (v VolumePathHandler) FindGlobalMapPathUUIDFromPod(pluginDir, mapPath string, podUID types.UID) (string, error) { + var globalMapPathUUID string + // Find symbolic link named pod uuid under plugin dir + err := filepath.Walk(pluginDir, func(path string, fi os.FileInfo, err error) error { + if err != nil { + return err + } + if (fi.Mode()&os.ModeDevice == os.ModeDevice) && (fi.Name() == string(podUID)) { + klog.V(5).Infof("FindGlobalMapPathFromPod: path %s, mapPath %s", path, mapPath) + if res, err := compareBindMountAndSymlinks(path, mapPath); err == nil && res { + globalMapPathUUID = path + } + } + return nil + }) + if err != nil { + return "", fmt.Errorf("FindGlobalMapPathUUIDFromPod failed: %v", err) + } + klog.V(5).Infof("FindGlobalMapPathFromPod: globalMapPathUUID %s", globalMapPathUUID) + // Return path contains global map path + {pod uuid} + return globalMapPathUUID, nil +} + +// compareBindMountAndSymlinks returns if global path (bind mount) and +// pod path (symlink) are pointing to the same device. +// If there is an error in checking it returns error. +func compareBindMountAndSymlinks(global, pod string) (bool, error) { + // To check if bind mount and symlink are pointing to the same device, + // we need to check if they are pointing to the devices that have same major/minor number. + + // Get the major/minor number for global path + devNumGlobal, err := getDeviceMajorMinor(global) + if err != nil { + return false, fmt.Errorf("getDeviceMajorMinor failed for path %s: %v", global, err) + } + + // Get the symlinked device from the pod path + devPod, err := os.Readlink(pod) + if err != nil { + return false, fmt.Errorf("failed to readlink path %s: %v", pod, err) + } + // Get the major/minor number for the symlinked device from the pod path + devNumPod, err := getDeviceMajorMinor(devPod) + if err != nil { + return false, fmt.Errorf("getDeviceMajorMinor failed for path %s: %v", devPod, err) + } + klog.V(5).Infof("CompareBindMountAndSymlinks: devNumGlobal %s, devNumPod %s", devNumGlobal, devNumPod) + + // Check if the major/minor number are the same + if devNumGlobal == devNumPod { + return true, nil + } + return false, nil +} + +// getDeviceMajorMinor returns major/minor number for the path with below format: +// major:minor (in hex) +// ex) +// +// fc:10 +func getDeviceMajorMinor(path string) (string, error) { + var stat unix.Stat_t + + if err := unix.Stat(path, &stat); err != nil { + return "", fmt.Errorf("failed to stat path %s: %v", path, err) + } + + devNumber := uint64(stat.Rdev) + major := unix.Major(devNumber) + minor := unix.Minor(devNumber) + + return fmt.Sprintf("%x:%x", major, minor), nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/volumepathhandler/volume_path_handler_unsupported.go b/vendor/k8s.io/kubernetes/pkg/volume/util/volumepathhandler/volume_path_handler_unsupported.go new file mode 100644 index 000000000..66fb2fe1f --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/volumepathhandler/volume_path_handler_unsupported.go @@ -0,0 +1,49 @@ +//go:build !linux +// +build !linux + +/* +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 volumepathhandler + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/types" +) + +// AttachFileDevice takes a path to a regular file and makes it available as an +// attached block device. +func (v VolumePathHandler) AttachFileDevice(path string) (string, error) { + return "", fmt.Errorf("AttachFileDevice not supported for this build.") +} + +// DetachFileDevice takes a path to the attached block device and +// detach it from block device. +func (v VolumePathHandler) DetachFileDevice(path string) error { + return fmt.Errorf("DetachFileDevice not supported for this build.") +} + +// GetLoopDevice returns the full path to the loop device associated with the given path. +func (v VolumePathHandler) GetLoopDevice(path string) (string, error) { + return "", fmt.Errorf("GetLoopDevice not supported for this build.") +} + +// FindGlobalMapPathUUIDFromPod finds {pod uuid} bind mount under globalMapPath +// corresponding to map path symlink, and then return global map path with pod uuid. +func (v VolumePathHandler) FindGlobalMapPathUUIDFromPod(pluginDir, mapPath string, podUID types.UID) (string, error) { + return "", fmt.Errorf("FindGlobalMapPathUUIDFromPod not supported for this build.") +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/volume.go b/vendor/k8s.io/kubernetes/pkg/volume/volume.go new file mode 100644 index 000000000..1905f0854 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/volume.go @@ -0,0 +1,310 @@ +/* +Copyright 2014 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 volume + +import ( + "time" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" +) + +// Volume represents a directory used by pods or hosts on a node. All method +// implementations of methods in the volume interface must be idempotent. +type Volume interface { + // GetPath returns the path to which the volume should be mounted for the + // pod. + GetPath() string + + // MetricsProvider embeds methods for exposing metrics (e.g. + // used, available space). + MetricsProvider +} + +// BlockVolume interface provides methods to generate global map path +// and pod device map path. +type BlockVolume interface { + // GetGlobalMapPath returns a global map path which contains + // bind mount associated to a block device. + // ex. plugins/kubernetes.io/{PluginName}/{DefaultKubeletVolumeDevicesDirName}/{volumePluginDependentPath}/{pod uuid} + GetGlobalMapPath(spec *Spec) (string, error) + // GetPodDeviceMapPath returns a pod device map path + // and name of a symbolic link associated to a block device. + // ex. pods/{podUid}/{DefaultKubeletVolumeDevicesDirName}/{escapeQualifiedPluginName}/, {volumeName} + GetPodDeviceMapPath() (string, string) + + // SupportsMetrics should return true if the MetricsProvider is + // initialized + SupportsMetrics() bool + + // MetricsProvider embeds methods for exposing metrics (e.g. + // used, available space). + MetricsProvider +} + +// MetricsProvider exposes metrics (e.g. used,available space) related to a +// Volume. +type MetricsProvider interface { + // GetMetrics returns the Metrics for the Volume. Maybe expensive for + // some implementations. + GetMetrics() (*Metrics, error) +} + +// Metrics represents the used and available bytes of the Volume. +type Metrics struct { + // The time at which these stats were updated. + Time metav1.Time + + // Used represents the total bytes used by the Volume. + // Note: For block devices this maybe more than the total size of the files. + Used *resource.Quantity + + // Capacity represents the total capacity (bytes) of the volume's + // underlying storage. For Volumes that share a filesystem with the host + // (e.g. emptydir, hostpath) this is the size of the underlying storage, + // and will not equal Used + Available as the fs is shared. + Capacity *resource.Quantity + + // Available represents the storage space available (bytes) for the + // Volume. For Volumes that share a filesystem with the host (e.g. + // emptydir, hostpath), this is the available space on the underlying + // storage, and is shared with host processes and other Volumes. + Available *resource.Quantity + + // InodesUsed represents the total inodes used by the Volume. + InodesUsed *resource.Quantity + + // Inodes represents the total number of inodes available in the volume. + // For volumes that share a filesystem with the host (e.g. emptydir, hostpath), + // this is the inodes available in the underlying storage, + // and will not equal InodesUsed + InodesFree as the fs is shared. + Inodes *resource.Quantity + + // InodesFree represent the inodes available for the volume. For Volumes that share + // a filesystem with the host (e.g. emptydir, hostpath), this is the free inodes + // on the underlying storage, and is shared with host processes and other volumes + InodesFree *resource.Quantity + + // Normal volumes are available for use and operating optimally. + // An abnormal volume does not meet these criteria. + // This field is OPTIONAL. Only some csi drivers which support NodeServiceCapability_RPC_VOLUME_CONDITION + // need to fill it. + Abnormal *bool + + // The message describing the condition of the volume. + // This field is OPTIONAL. Only some csi drivers which support capability_RPC_VOLUME_CONDITION + // need to fill it. + Message *string +} + +// Attributes represents the attributes of this mounter. +type Attributes struct { + ReadOnly bool + Managed bool + SELinuxRelabel bool +} + +// MounterArgs provides more easily extensible arguments to Mounter +type MounterArgs struct { + // When FsUser is set, the ownership of the volume will be modified to be + // owned and writable by FsUser. Otherwise, there is no side effects. + // Currently only supported with projected service account tokens. + FsUser *int64 + FsGroup *int64 + FSGroupChangePolicy *v1.PodFSGroupChangePolicy + DesiredSize *resource.Quantity + SELinuxLabel string +} + +// Mounter interface provides methods to set up/mount the volume. +type Mounter interface { + // Uses Interface to provide the path for Docker binds. + Volume + + // SetUp prepares and mounts/unpacks the volume to a + // self-determined directory path. The mount point and its + // content should be owned by `fsUser` or 'fsGroup' so that it can be + // accessed by the pod. This may be called more than once, so + // implementations must be idempotent. + // It could return following types of errors: + // - TransientOperationFailure + // - UncertainProgressError + // - Error of any other type should be considered a final error + SetUp(mounterArgs MounterArgs) error + + // SetUpAt prepares and mounts/unpacks the volume to the + // specified directory path, which may or may not exist yet. + // The mount point and its content should be owned by `fsUser` + // 'fsGroup' so that it can be accessed by the pod. This may + // be called more than once, so implementations must be + // idempotent. + SetUpAt(dir string, mounterArgs MounterArgs) error + // GetAttributes returns the attributes of the mounter. + // This function is called after SetUp()/SetUpAt(). + GetAttributes() Attributes +} + +// Unmounter interface provides methods to cleanup/unmount the volumes. +type Unmounter interface { + Volume + // TearDown unmounts the volume from a self-determined directory and + // removes traces of the SetUp procedure. + TearDown() error + // TearDown unmounts the volume from the specified directory and + // removes traces of the SetUp procedure. + TearDownAt(dir string) error +} + +// BlockVolumeMapper interface is a mapper interface for block volume. +type BlockVolumeMapper interface { + BlockVolume +} + +// CustomBlockVolumeMapper interface provides custom methods to set up/map the volume. +type CustomBlockVolumeMapper interface { + BlockVolumeMapper + // SetUpDevice prepares the volume to the node by the plugin specific way. + // For most in-tree plugins, attacher.Attach() and attacher.WaitForAttach() + // will do necessary works. + // This may be called more than once, so implementations must be idempotent. + // SetUpDevice returns stagingPath if device setup was successful + SetUpDevice() (stagingPath string, err error) + + // MapPodDevice maps the block device to a path and return the path. + // Unique device path across kubelet node reboot is required to avoid + // unexpected block volume destruction. + // If empty string is returned, the path returned by attacher.Attach() and + // attacher.WaitForAttach() will be used. + MapPodDevice() (publishPath string, err error) + + // GetStagingPath returns path that was used for staging the volume + // it is mainly used by CSI plugins + GetStagingPath() string +} + +// BlockVolumeUnmapper interface is an unmapper interface for block volume. +type BlockVolumeUnmapper interface { + BlockVolume +} + +// CustomBlockVolumeUnmapper interface provides custom methods to cleanup/unmap the volumes. +type CustomBlockVolumeUnmapper interface { + BlockVolumeUnmapper + // TearDownDevice removes traces of the SetUpDevice procedure. + // If the plugin is non-attachable, this method detaches the volume + // from a node. + TearDownDevice(mapPath string, devicePath string) error + + // UnmapPodDevice removes traces of the MapPodDevice procedure. + UnmapPodDevice() error +} + +// Provisioner is an interface that creates templates for PersistentVolumes +// and can create the volume as a new resource in the infrastructure provider. +type Provisioner interface { + // Provision creates the resource by allocating the underlying volume in a + // storage system. This method should block until completion and returns + // PersistentVolume representing the created storage resource. + Provision(selectedNode *v1.Node, allowedTopologies []v1.TopologySelectorTerm) (*v1.PersistentVolume, error) +} + +// Deleter removes the resource from the underlying storage provider. Calls +// to this method should block until the deletion is complete. Any error +// returned indicates the volume has failed to be reclaimed. A nil return +// indicates success. +type Deleter interface { + Volume + // This method should block until completion. + // deletedVolumeInUseError returned from this function will not be reported + // as error and it will be sent as "Info" event to the PV being deleted. The + // volume controller will retry deleting the volume in the next periodic + // sync. This can be used to postpone deletion of a volume that is being + // detached from a node. Deletion of such volume would fail anyway and such + // error would confuse users. + Delete() error +} + +// Attacher can attach a volume to a node. +type Attacher interface { + DeviceMounter + + // Attaches the volume specified by the given spec to the node with the given Name. + // On success, returns the device path where the device was attached on the + // node. + Attach(spec *Spec, nodeName types.NodeName) (string, error) + + // VolumesAreAttached checks whether the list of volumes still attached to the specified + // node. It returns a map which maps from the volume spec to the checking result. + // If an error is occurred during checking, the error will be returned + VolumesAreAttached(specs []*Spec, nodeName types.NodeName) (map[*Spec]bool, error) + + // WaitForAttach blocks until the device is attached to this + // node. If it successfully attaches, the path to the device + // is returned. Otherwise, if the device does not attach after + // the given timeout period, an error will be returned. + WaitForAttach(spec *Spec, devicePath string, pod *v1.Pod, timeout time.Duration) (string, error) +} + +// DeviceMounterArgs provides auxiliary, optional arguments to DeviceMounter. +type DeviceMounterArgs struct { + FsGroup *int64 + SELinuxLabel string +} + +// DeviceMounter can mount a block volume to a global path. +type DeviceMounter interface { + // GetDeviceMountPath returns a path where the device should + // be mounted after it is attached. This is a global mount + // point which should be bind mounted for individual volumes. + GetDeviceMountPath(spec *Spec) (string, error) + + // MountDevice mounts the disk to a global path which + // individual pods can then bind mount + // Note that devicePath can be empty if the volume plugin does not implement any of Attach and WaitForAttach methods. + // It could return following types of errors: + // - TransientOperationFailure + // - UncertainProgressError + // - Error of any other type should be considered a final error + MountDevice(spec *Spec, devicePath string, deviceMountPath string, deviceMounterArgs DeviceMounterArgs) error +} + +type BulkVolumeVerifier interface { + // BulkVerifyVolumes checks whether the list of volumes still attached to the + // clusters in the node. It returns a map which maps from the volume spec to the checking result. + // If an error occurs during check - error should be returned and volume on nodes + // should be assumed as still attached. + BulkVerifyVolumes(volumesByNode map[types.NodeName][]*Spec) (map[types.NodeName]map[*Spec]bool, error) +} + +// Detacher can detach a volume from a node. +type Detacher interface { + DeviceUnmounter + // Detach the given volume from the node with the given Name. + // volumeName is name of the volume as returned from plugin's + // GetVolumeName(). + Detach(volumeName string, nodeName types.NodeName) error +} + +// DeviceUnmounter can unmount a block volume from the global path. +type DeviceUnmounter interface { + // UnmountDevice unmounts the global mount of the disk. This + // should only be called once all bind mounts have been + // unmounted. + UnmountDevice(deviceMountPath string) error +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/volume_linux.go b/vendor/k8s.io/kubernetes/pkg/volume/volume_linux.go new file mode 100644 index 000000000..57c028150 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/volume_linux.go @@ -0,0 +1,212 @@ +//go:build linux +// +build linux + +/* +Copyright 2016 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 volume + +import ( + "path/filepath" + "syscall" + + "os" + "time" + + v1 "k8s.io/api/core/v1" + "k8s.io/klog/v2" + "k8s.io/kubernetes/pkg/volume/util/types" +) + +const ( + rwMask = os.FileMode(0660) + roMask = os.FileMode(0440) + execMask = os.FileMode(0110) +) + +// SetVolumeOwnership modifies the given volume to be owned by +// fsGroup, and sets SetGid so that newly created files are owned by +// fsGroup. If fsGroup is nil nothing is done. +func SetVolumeOwnership(mounter Mounter, fsGroup *int64, fsGroupChangePolicy *v1.PodFSGroupChangePolicy, completeFunc func(types.CompleteFuncParam)) error { + if fsGroup == nil { + return nil + } + + timer := time.AfterFunc(30*time.Second, func() { + klog.Warningf("Setting volume ownership for %s and fsGroup set. If the volume has a lot of files then setting volume ownership could be slow, see https://github.com/kubernetes/kubernetes/issues/69699", mounter.GetPath()) + }) + defer timer.Stop() + + if skipPermissionChange(mounter, fsGroup, fsGroupChangePolicy) { + klog.V(3).InfoS("Skipping permission and ownership change for volume", "path", mounter.GetPath()) + return nil + } + + err := walkDeep(mounter.GetPath(), func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + return changeFilePermission(path, fsGroup, mounter.GetAttributes().ReadOnly, info) + }) + if completeFunc != nil { + completeFunc(types.CompleteFuncParam{ + Err: &err, + }) + } + return err +} + +func changeFilePermission(filename string, fsGroup *int64, readonly bool, info os.FileInfo) error { + err := os.Lchown(filename, -1, int(*fsGroup)) + if err != nil { + klog.ErrorS(err, "Lchown failed", "path", filename) + } + + // chmod passes through to the underlying file for symlinks. + // Symlinks have a mode of 777 but this really doesn't mean anything. + // The permissions of the underlying file are what matter. + // However, if one reads the mode of a symlink then chmods the symlink + // with that mode, it changes the mode of the underlying file, overridden + // the defaultMode and permissions initialized by the volume plugin, which + // is not what we want; thus, we skip chmod for symlinks. + if info.Mode()&os.ModeSymlink != 0 { + return nil + } + + mask := rwMask + if readonly { + mask = roMask + } + + if info.IsDir() { + mask |= os.ModeSetgid + mask |= execMask + } + + err = os.Chmod(filename, info.Mode()|mask) + if err != nil { + klog.ErrorS(err, "chmod failed", "path", filename) + } + + return nil +} + +func skipPermissionChange(mounter Mounter, fsGroup *int64, fsGroupChangePolicy *v1.PodFSGroupChangePolicy) bool { + dir := mounter.GetPath() + + if fsGroupChangePolicy == nil || *fsGroupChangePolicy != v1.FSGroupChangeOnRootMismatch { + klog.V(4).InfoS("Perform recursive ownership change for directory", "path", dir) + return false + } + return !requiresPermissionChange(mounter.GetPath(), fsGroup, mounter.GetAttributes().ReadOnly) +} + +func requiresPermissionChange(rootDir string, fsGroup *int64, readonly bool) bool { + fsInfo, err := os.Stat(rootDir) + if err != nil { + klog.ErrorS(err, "Performing recursive ownership change on rootDir because reading permissions of root volume failed", "path", rootDir) + return true + } + stat, ok := fsInfo.Sys().(*syscall.Stat_t) + if !ok || stat == nil { + klog.ErrorS(nil, "Performing recursive ownership change on rootDir because reading permissions of root volume failed", "path", rootDir) + return true + } + + if int(stat.Gid) != int(*fsGroup) { + klog.V(4).InfoS("Expected group ownership of volume did not match with Gid", "path", rootDir, "GID", stat.Gid) + return true + } + unixPerms := rwMask + + if readonly { + unixPerms = roMask + } + + // if rootDir is not a directory then we should apply permission change anyways + if !fsInfo.IsDir() { + return true + } + unixPerms |= execMask + filePerm := fsInfo.Mode().Perm() + + // We need to check if actual permissions of root directory is a superset of permissions required by unixPerms. + // This is done by checking if permission bits expected in unixPerms is set in actual permissions of the directory. + // We use bitwise AND operation to check set bits. For example: + // unixPerms: 770, filePerms: 775 : 770&775 = 770 (perms on directory is a superset) + // unixPerms: 770, filePerms: 770 : 770&770 = 770 (perms on directory is a superset) + // unixPerms: 770, filePerms: 750 : 770&750 = 750 (perms on directory is NOT a superset) + // We also need to check if setgid bits are set in permissions of the directory. + if (unixPerms&filePerm != unixPerms) || (fsInfo.Mode()&os.ModeSetgid == 0) { + klog.V(4).InfoS("Performing recursive ownership change on rootDir because of mismatching mode", "path", rootDir) + return true + } + return false +} + +// readDirNames reads the directory named by dirname and returns +// a list of directory entries. +// We are not using filepath.readDirNames because we do not want to sort files found in a directory before changing +// permissions for performance reasons. +func readDirNames(dirname string) ([]string, error) { + f, err := os.Open(dirname) + if err != nil { + return nil, err + } + names, err := f.Readdirnames(-1) + f.Close() + if err != nil { + return nil, err + } + return names, nil +} + +// walkDeep can be used to traverse directories and has two minor differences +// from filepath.Walk: +// - List of files/dirs is not sorted for performance reasons +// - callback walkFunc is invoked on root directory after visiting children dirs and files +func walkDeep(root string, walkFunc filepath.WalkFunc) error { + info, err := os.Lstat(root) + if err != nil { + return walkFunc(root, nil, err) + } + return walk(root, info, walkFunc) +} + +func walk(path string, info os.FileInfo, walkFunc filepath.WalkFunc) error { + if !info.IsDir() { + return walkFunc(path, info, nil) + } + names, err := readDirNames(path) + if err != nil { + return err + } + for _, name := range names { + filename := filepath.Join(path, name) + fileInfo, err := os.Lstat(filename) + if err != nil { + if err := walkFunc(filename, fileInfo, err); err != nil { + return err + } + } else { + err = walk(filename, fileInfo, walkFunc) + if err != nil { + return err + } + } + } + return walkFunc(path, info, nil) +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/volume_unsupported.go b/vendor/k8s.io/kubernetes/pkg/volume/volume_unsupported.go new file mode 100644 index 000000000..20c56d4b6 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/volume_unsupported.go @@ -0,0 +1,29 @@ +//go:build !linux +// +build !linux + +/* +Copyright 2016 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 volume + +import ( + v1 "k8s.io/api/core/v1" + "k8s.io/kubernetes/pkg/volume/util/types" +) + +func SetVolumeOwnership(mounter Mounter, fsGroup *int64, fsGroupChangePolicy *v1.PodFSGroupChangePolicy, completeFunc func(types.CompleteFuncParam)) error { + return nil +} diff --git a/vendor/k8s.io/mount-utils/LICENSE b/vendor/k8s.io/mount-utils/LICENSE new file mode 100644 index 000000000..8dada3eda --- /dev/null +++ b/vendor/k8s.io/mount-utils/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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. diff --git a/vendor/k8s.io/mount-utils/OWNERS b/vendor/k8s.io/mount-utils/OWNERS new file mode 100644 index 000000000..64fb63c1e --- /dev/null +++ b/vendor/k8s.io/mount-utils/OWNERS @@ -0,0 +1,15 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +reviewers: + - jingxu97 + - saad-ali + - jsafrane + - msau42 + - andyzhangx + - gnufied +approvers: + - jingxu97 + - saad-ali + - jsafrane +labels: + - sig/storage diff --git a/vendor/k8s.io/mount-utils/README.md b/vendor/k8s.io/mount-utils/README.md new file mode 100644 index 000000000..ee7c8e89a --- /dev/null +++ b/vendor/k8s.io/mount-utils/README.md @@ -0,0 +1,31 @@ +## Purpose + +This repository defines an interface to mounting filesystems to be consumed by +various Kubernetes and out-of-tree CSI components. + +Consumers of this repository can make use of functions like 'Mount' to mount +source to target as fstype with given options, 'Unmount' to unmount a target. +Other useful functions include 'List' all mounted file systems and find all +mount references to a path using 'GetMountRefs' + +## Community, discussion, contribution, and support + +Learn how to engage with the Kubernetes community on the [community +page](http://kubernetes.io/community/). + +You can reach the maintainers of this repository at: + +- Slack: #sig-storage (on https://kubernetes.slack.com -- get an + invite at slack.kubernetes.io) +- Mailing List: + https://groups.google.com/forum/#!forum/kubernetes-sig-storage + +### Code of Conduct + +Participation in the Kubernetes community is governed by the [Kubernetes +Code of Conduct](code-of-conduct.md). + +### Contibution Guidelines + +See [CONTRIBUTING.md](CONTRIBUTING.md) for more information. + diff --git a/vendor/k8s.io/mount-utils/SECURITY_CONTACTS b/vendor/k8s.io/mount-utils/SECURITY_CONTACTS new file mode 100644 index 000000000..14fe23e18 --- /dev/null +++ b/vendor/k8s.io/mount-utils/SECURITY_CONTACTS @@ -0,0 +1,18 @@ +# Defined below are the security contacts for this repo. +# +# They are the contact point for the Product Security Committee to reach out +# to for triaging and handling of incoming issues. +# +# The below names agree to abide by the +# [Embargo Policy](https://git.k8s.io/security/private-distributors-list.md#embargo-policy) +# and will be removed and replaced if they violate that agreement. +# +# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE +# INSTRUCTIONS AT https://kubernetes.io/security/ + +saad-ali +cjcullen +joelsmith +liggitt +philips +tallclair diff --git a/vendor/k8s.io/mount-utils/code-of-conduct.md b/vendor/k8s.io/mount-utils/code-of-conduct.md new file mode 100644 index 000000000..0d15c00cf --- /dev/null +++ b/vendor/k8s.io/mount-utils/code-of-conduct.md @@ -0,0 +1,3 @@ +# Kubernetes Community Code of Conduct + +Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md) diff --git a/vendor/k8s.io/mount-utils/doc.go b/vendor/k8s.io/mount-utils/doc.go new file mode 100644 index 000000000..b7cac03a5 --- /dev/null +++ b/vendor/k8s.io/mount-utils/doc.go @@ -0,0 +1,18 @@ +/* +Copyright 2014 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 mount defines an interface to mounting filesystems. +package mount // import "k8s.io/mount-utils" diff --git a/vendor/k8s.io/mount-utils/fake_mounter.go b/vendor/k8s.io/mount-utils/fake_mounter.go new file mode 100644 index 000000000..5a5701598 --- /dev/null +++ b/vendor/k8s.io/mount-utils/fake_mounter.go @@ -0,0 +1,242 @@ +/* +Copyright 2015 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 mount + +import ( + "os" + "path/filepath" + "sync" + + "k8s.io/klog/v2" +) + +// FakeMounter implements mount.Interface for tests. +type FakeMounter struct { + MountPoints []MountPoint + log []FakeAction + // Error to return for a path when calling IsLikelyNotMountPoint + MountCheckErrors map[string]error + // Some tests run things in parallel, make sure the mounter does not produce + // any golang's DATA RACE warnings. + mutex sync.Mutex + UnmountFunc UnmountFunc + skipMountPointCheck bool +} + +// UnmountFunc is a function callback to be executed during the Unmount() call. +type UnmountFunc func(path string) error + +var _ Interface = &FakeMounter{} + +const ( + // FakeActionMount is the string for specifying mount as FakeAction.Action + FakeActionMount = "mount" + // FakeActionUnmount is the string for specifying unmount as FakeAction.Action + FakeActionUnmount = "unmount" +) + +// FakeAction objects are logged every time a fake mount or unmount is called. +type FakeAction struct { + Action string // "mount" or "unmount" + Target string // applies to both mount and unmount actions + Source string // applies only to "mount" actions + FSType string // applies only to "mount" actions +} + +// NewFakeMounter returns a FakeMounter struct that implements Interface and is +// suitable for testing purposes. +func NewFakeMounter(mps []MountPoint) *FakeMounter { + return &FakeMounter{ + MountPoints: mps, + } +} + +func (f *FakeMounter) WithSkipMountPointCheck() *FakeMounter { + f.skipMountPointCheck = true + return f +} + +// ResetLog clears all the log entries in FakeMounter +func (f *FakeMounter) ResetLog() { + f.mutex.Lock() + defer f.mutex.Unlock() + + f.log = []FakeAction{} +} + +// GetLog returns the slice of FakeActions taken by the mounter +func (f *FakeMounter) GetLog() []FakeAction { + f.mutex.Lock() + defer f.mutex.Unlock() + + return f.log +} + +// Mount records the mount event and updates the in-memory mount points for FakeMounter +func (f *FakeMounter) Mount(source string, target string, fstype string, options []string) error { + return f.MountSensitive(source, target, fstype, options, nil /* sensitiveOptions */) +} + +// Mount records the mount event and updates the in-memory mount points for FakeMounter +// sensitiveOptions to be passed in a separate parameter from the normal +// mount options and ensures the sensitiveOptions are never logged. This +// method should be used by callers that pass sensitive material (like +// passwords) as mount options. +func (f *FakeMounter) MountSensitive(source string, target string, fstype string, options []string, sensitiveOptions []string) error { + f.mutex.Lock() + defer f.mutex.Unlock() + + opts := []string{} + + for _, option := range options { + // find 'bind' option + if option == "bind" { + // This is a bind-mount. In order to mimic linux behaviour, we must + // use the original device of the bind-mount as the real source. + // E.g. when mounted /dev/sda like this: + // $ mount /dev/sda /mnt/test + // $ mount -o bind /mnt/test /mnt/bound + // then /proc/mount contains: + // /dev/sda /mnt/test + // /dev/sda /mnt/bound + // (and not /mnt/test /mnt/bound) + // I.e. we must use /dev/sda as source instead of /mnt/test in the + // bind mount. + for _, mnt := range f.MountPoints { + if source == mnt.Path { + source = mnt.Device + break + } + } + } + // reuse MountPoint.Opts field to mark mount as readonly + opts = append(opts, option) + } + + // If target is a symlink, get its absolute path + absTarget, err := filepath.EvalSymlinks(target) + if err != nil { + absTarget = target + } + f.MountPoints = append(f.MountPoints, MountPoint{Device: source, Path: absTarget, Type: fstype, Opts: append(opts, sensitiveOptions...)}) + klog.V(5).Infof("Fake mounter: mounted %s to %s", source, absTarget) + f.log = append(f.log, FakeAction{Action: FakeActionMount, Target: absTarget, Source: source, FSType: fstype}) + return nil +} + +func (f *FakeMounter) MountSensitiveWithoutSystemd(source string, target string, fstype string, options []string, sensitiveOptions []string) error { + return f.MountSensitive(source, target, fstype, options, nil /* sensitiveOptions */) +} + +func (f *FakeMounter) MountSensitiveWithoutSystemdWithMountFlags(source string, target string, fstype string, options []string, sensitiveOptions []string, mountFlags []string) error { + return f.MountSensitive(source, target, fstype, options, nil /* sensitiveOptions */) +} + +// Unmount records the unmount event and updates the in-memory mount points for FakeMounter +func (f *FakeMounter) Unmount(target string) error { + f.mutex.Lock() + defer f.mutex.Unlock() + + // If target is a symlink, get its absolute path + absTarget, err := filepath.EvalSymlinks(target) + if err != nil { + absTarget = target + } + + newMountpoints := []MountPoint{} + for _, mp := range f.MountPoints { + if mp.Path == absTarget { + if f.UnmountFunc != nil { + err := f.UnmountFunc(absTarget) + if err != nil { + return err + } + } + klog.V(5).Infof("Fake mounter: unmounted %s from %s", mp.Device, absTarget) + // Don't copy it to newMountpoints + continue + } + newMountpoints = append(newMountpoints, MountPoint{Device: mp.Device, Path: mp.Path, Type: mp.Type}) + } + f.MountPoints = newMountpoints + f.log = append(f.log, FakeAction{Action: FakeActionUnmount, Target: absTarget}) + delete(f.MountCheckErrors, target) + return nil +} + +// List returns all the in-memory mountpoints for FakeMounter +func (f *FakeMounter) List() ([]MountPoint, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + return f.MountPoints, nil +} + +// IsLikelyNotMountPoint determines whether a path is a mountpoint by checking +// if the absolute path to file is in the in-memory mountpoints +func (f *FakeMounter) IsLikelyNotMountPoint(file string) (bool, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + err := f.MountCheckErrors[file] + if err != nil { + return false, err + } + + _, err = os.Stat(file) + if err != nil { + return true, err + } + + // If file is a symlink, get its absolute path + absFile, err := filepath.EvalSymlinks(file) + if err != nil { + absFile = file + } + + for _, mp := range f.MountPoints { + if mp.Path == absFile { + klog.V(5).Infof("isLikelyNotMountPoint for %s: mounted %s, false", file, mp.Path) + return false, nil + } + } + klog.V(5).Infof("isLikelyNotMountPoint for %s: true", file) + return true, nil +} + +func (f *FakeMounter) canSafelySkipMountPointCheck() bool { + return f.skipMountPointCheck +} + +func (f *FakeMounter) IsMountPoint(file string) (bool, error) { + notMnt, err := f.IsLikelyNotMountPoint(file) + if err != nil { + return false, err + } + return !notMnt, nil +} + +// GetMountRefs finds all mount references to the path, returns a +// list of paths. +func (f *FakeMounter) GetMountRefs(pathname string) ([]string, error) { + realpath, err := filepath.EvalSymlinks(pathname) + if err != nil { + // Ignore error in FakeMounter, because we actually didn't create files. + realpath = pathname + } + return getMountRefsByDev(f, realpath) +} diff --git a/vendor/k8s.io/mount-utils/mount.go b/vendor/k8s.io/mount-utils/mount.go new file mode 100644 index 000000000..57abb6919 --- /dev/null +++ b/vendor/k8s.io/mount-utils/mount.go @@ -0,0 +1,370 @@ +/* +Copyright 2014 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. +*/ + +// TODO(thockin): This whole pkg is pretty linux-centric. As soon as we have +// an alternate platform, we will need to abstract further. + +package mount + +import ( + "fmt" + "path/filepath" + "strings" + "time" + + utilexec "k8s.io/utils/exec" +) + +const ( + // Default mount command if mounter path is not specified. + defaultMountCommand = "mount" + // Log message where sensitive mount options were removed + sensitiveOptionsRemoved = "" +) + +// Interface defines the set of methods to allow for mount operations on a system. +type Interface interface { + // Mount mounts source to target as fstype with given options. + // options MUST not contain sensitive material (like passwords). + Mount(source string, target string, fstype string, options []string) error + // MountSensitive is the same as Mount() but this method allows + // sensitiveOptions to be passed in a separate parameter from the normal + // mount options and ensures the sensitiveOptions are never logged. This + // method should be used by callers that pass sensitive material (like + // passwords) as mount options. + MountSensitive(source string, target string, fstype string, options []string, sensitiveOptions []string) error + // MountSensitiveWithoutSystemd is the same as MountSensitive() but this method disable using systemd mount. + MountSensitiveWithoutSystemd(source string, target string, fstype string, options []string, sensitiveOptions []string) error + // MountSensitiveWithoutSystemdWithMountFlags is the same as MountSensitiveWithoutSystemd() with additional mount flags + MountSensitiveWithoutSystemdWithMountFlags(source string, target string, fstype string, options []string, sensitiveOptions []string, mountFlags []string) error + // Unmount unmounts given target. + Unmount(target string) error + // List returns a list of all mounted filesystems. This can be large. + // On some platforms, reading mounts directly from the OS is not guaranteed + // consistent (i.e. it could change between chunked reads). This is guaranteed + // to be consistent. + List() ([]MountPoint, error) + // IsLikelyNotMountPoint uses heuristics to determine if a directory + // is not a mountpoint. + // It should return ErrNotExist when the directory does not exist. + // IsLikelyNotMountPoint does NOT properly detect all mountpoint types + // most notably linux bind mounts and symbolic link. For callers that do not + // care about such situations, this is a faster alternative to calling List() + // and scanning that output. + IsLikelyNotMountPoint(file string) (bool, error) + // canSafelySkipMountPointCheck indicates whether this mounter returns errors on + // operations for targets that are not mount points. If this returns true, no such + // errors will be returned. + canSafelySkipMountPointCheck() bool + // IsMountPoint determines if a directory is a mountpoint. + // It should return ErrNotExist when the directory does not exist. + // IsMountPoint is more expensive than IsLikelyNotMountPoint. + // IsMountPoint detects bind mounts in linux. + // IsMountPoint may enumerate all the mountpoints using List() and + // the list of mountpoints may be large, then it uses + // isMountPointMatch to evaluate whether the directory is a mountpoint. + IsMountPoint(file string) (bool, error) + // GetMountRefs finds all mount references to pathname, returning a slice of + // paths. Pathname can be a mountpoint path or a normal directory + // (for bind mount). On Linux, pathname is excluded from the slice. + // For example, if /dev/sdc was mounted at /path/a and /path/b, + // GetMountRefs("/path/a") would return ["/path/b"] + // GetMountRefs("/path/b") would return ["/path/a"] + // On Windows there is no way to query all mount points; as long as pathname is + // a valid mount, it will be returned. + GetMountRefs(pathname string) ([]string, error) +} + +// Compile-time check to ensure all Mounter implementations satisfy +// the mount interface. +var _ Interface = &Mounter{} + +type MounterForceUnmounter interface { + Interface + // UnmountWithForce unmounts given target but will retry unmounting with force option + // after given timeout. + UnmountWithForce(target string, umountTimeout time.Duration) error +} + +// MountPoint represents a single line in /proc/mounts or /etc/fstab. +type MountPoint struct { // nolint: golint + Device string + Path string + Type string + Opts []string // Opts may contain sensitive mount options (like passwords) and MUST be treated as such (e.g. not logged). + Freq int + Pass int +} + +type MountErrorType string // nolint: golint + +const ( + FilesystemMismatch MountErrorType = "FilesystemMismatch" + HasFilesystemErrors MountErrorType = "HasFilesystemErrors" + UnformattedReadOnly MountErrorType = "UnformattedReadOnly" + FormatFailed MountErrorType = "FormatFailed" + GetDiskFormatFailed MountErrorType = "GetDiskFormatFailed" + UnknownMountError MountErrorType = "UnknownMountError" +) + +type MountError struct { // nolint: golint + Type MountErrorType + Message string +} + +func (mountError MountError) String() string { + return mountError.Message +} + +func (mountError MountError) Error() string { + return mountError.Message +} + +func NewMountError(mountErrorValue MountErrorType, format string, args ...interface{}) error { + mountError := MountError{ + Type: mountErrorValue, + Message: fmt.Sprintf(format, args...), + } + return mountError +} + +// SafeFormatAndMount probes a device to see if it is formatted. +// Namely it checks to see if a file system is present. If so it +// mounts it otherwise the device is formatted first then mounted. +type SafeFormatAndMount struct { + Interface + Exec utilexec.Interface +} + +// FormatAndMount formats the given disk, if needed, and mounts it. +// That is if the disk is not formatted and it is not being mounted as +// read-only it will format it first then mount it. Otherwise, if the +// disk is already formatted or it is being mounted as read-only, it +// will be mounted without formatting. +// options MUST not contain sensitive material (like passwords). +func (mounter *SafeFormatAndMount) FormatAndMount(source string, target string, fstype string, options []string) error { + return mounter.FormatAndMountSensitive(source, target, fstype, options, nil /* sensitiveOptions */) +} + +// FormatAndMountSensitive is the same as FormatAndMount but this method allows +// sensitiveOptions to be passed in a separate parameter from the normal mount +// options and ensures the sensitiveOptions are never logged. This method should +// be used by callers that pass sensitive material (like passwords) as mount +// options. +func (mounter *SafeFormatAndMount) FormatAndMountSensitive(source string, target string, fstype string, options []string, sensitiveOptions []string) error { + return mounter.FormatAndMountSensitiveWithFormatOptions(source, target, fstype, options, sensitiveOptions, nil /* formatOptions */) +} + +// FormatAndMountSensitiveWithFormatOptions behaves exactly the same as +// FormatAndMountSensitive, but allows for options to be passed when the disk +// is formatted. These options are NOT validated in any way and should never +// come directly from untrusted user input as that would be an injection risk. +func (mounter *SafeFormatAndMount) FormatAndMountSensitiveWithFormatOptions(source string, target string, fstype string, options []string, sensitiveOptions []string, formatOptions []string) error { + return mounter.formatAndMountSensitive(source, target, fstype, options, sensitiveOptions, formatOptions) +} + +// getMountRefsByDev finds all references to the device provided +// by mountPath; returns a list of paths. +// Note that mountPath should be path after the evaluation of any symblolic links. +func getMountRefsByDev(mounter Interface, mountPath string) ([]string, error) { + mps, err := mounter.List() + if err != nil { + return nil, err + } + + // Finding the device mounted to mountPath. + diskDev := "" + for i := range mps { + if mountPath == mps[i].Path { + diskDev = mps[i].Device + break + } + } + + // Find all references to the device. + var refs []string + for i := range mps { + if mps[i].Device == diskDev || mps[i].Device == mountPath { + if mps[i].Path != mountPath { + refs = append(refs, mps[i].Path) + } + } + } + return refs, nil +} + +// IsNotMountPoint determines if a directory is a mountpoint. +// It should return ErrNotExist when the directory does not exist. +// IsNotMountPoint is more expensive than IsLikelyNotMountPoint +// and depends on IsMountPoint. +// +// If an error occurs, it returns true (assuming it is not a mountpoint) +// when ErrNotExist is returned for callers similar to IsLikelyNotMountPoint. +// +// Deprecated: This function is kept to keep changes backward compatible with +// previous library version. Callers should prefer mounter.IsMountPoint. +func IsNotMountPoint(mounter Interface, file string) (bool, error) { + isMnt, err := mounter.IsMountPoint(file) + if err != nil { + return true, err + } + return !isMnt, nil +} + +// GetDeviceNameFromMount given a mnt point, find the device from /proc/mounts +// returns the device name, reference count, and error code. +func GetDeviceNameFromMount(mounter Interface, mountPath string) (string, int, error) { + mps, err := mounter.List() + if err != nil { + return "", 0, err + } + + // Find the device name. + // FIXME if multiple devices mounted on the same mount path, only the first one is returned. + device := "" + // If mountPath is symlink, need get its target path. + slTarget, err := filepath.EvalSymlinks(mountPath) + if err != nil { + slTarget = mountPath + } + for i := range mps { + if mps[i].Path == slTarget { + device = mps[i].Device + break + } + } + + // Find all references to the device. + refCount := 0 + for i := range mps { + if mps[i].Device == device { + refCount++ + } + } + return device, refCount, nil +} + +// MakeBindOpts detects whether a bind mount is being requested and makes the remount options to +// use in case of bind mount, due to the fact that bind mount doesn't respect mount options. +// The list equals: +// +// options - 'bind' + 'remount' (no duplicate) +func MakeBindOpts(options []string) (bool, []string, []string) { + bind, bindOpts, bindRemountOpts, _ := MakeBindOptsSensitive(options, nil /* sensitiveOptions */) + return bind, bindOpts, bindRemountOpts +} + +// MakeBindOptsSensitive is the same as MakeBindOpts but this method allows +// sensitiveOptions to be passed in a separate parameter from the normal mount +// options and ensures the sensitiveOptions are never logged. This method should +// be used by callers that pass sensitive material (like passwords) as mount +// options. +func MakeBindOptsSensitive(options []string, sensitiveOptions []string) (bool, []string, []string, []string) { + // Because we have an FD opened on the subpath bind mount, the "bind" option + // needs to be included, otherwise the mount target will error as busy if you + // remount as readonly. + // + // As a consequence, all read only bind mounts will no longer change the underlying + // volume mount to be read only. + bindRemountOpts := []string{"bind", "remount"} + bindRemountSensitiveOpts := []string{} + bind := false + bindOpts := []string{"bind"} + + // _netdev is a userspace mount option and does not automatically get added when + // bind mount is created and hence we must carry it over. + if checkForNetDev(options, sensitiveOptions) { + bindOpts = append(bindOpts, "_netdev") + } + + for _, option := range options { + switch option { + case "bind": + bind = true + case "remount": + default: + bindRemountOpts = append(bindRemountOpts, option) + } + } + + for _, sensitiveOption := range sensitiveOptions { + switch sensitiveOption { + case "bind": + bind = true + case "remount": + default: + bindRemountSensitiveOpts = append(bindRemountSensitiveOpts, sensitiveOption) + } + } + + return bind, bindOpts, bindRemountOpts, bindRemountSensitiveOpts +} + +func checkForNetDev(options []string, sensitiveOptions []string) bool { + for _, option := range options { + if option == "_netdev" { + return true + } + } + for _, sensitiveOption := range sensitiveOptions { + if sensitiveOption == "_netdev" { + return true + } + } + return false +} + +// PathWithinBase checks if give path is within given base directory. +func PathWithinBase(fullPath, basePath string) bool { + rel, err := filepath.Rel(basePath, fullPath) + if err != nil { + return false + } + if StartsWithBackstep(rel) { + // Needed to escape the base path. + return false + } + return true +} + +// StartsWithBackstep checks if the given path starts with a backstep segment. +func StartsWithBackstep(rel string) bool { + // normalize to / and check for ../ + return rel == ".." || strings.HasPrefix(filepath.ToSlash(rel), "../") +} + +// sanitizedOptionsForLogging will return a comma separated string containing +// options and sensitiveOptions. Each entry in sensitiveOptions will be +// replaced with the string sensitiveOptionsRemoved +// e.g. o1,o2,, +func sanitizedOptionsForLogging(options []string, sensitiveOptions []string) string { + separator := "" + if len(options) > 0 && len(sensitiveOptions) > 0 { + separator = "," + } + + sensitiveOptionsStart := "" + sensitiveOptionsEnd := "" + if len(sensitiveOptions) > 0 { + sensitiveOptionsStart = strings.Repeat(sensitiveOptionsRemoved+",", len(sensitiveOptions)-1) + sensitiveOptionsEnd = sensitiveOptionsRemoved + } + + return strings.Join(options, ",") + + separator + + sensitiveOptionsStart + + sensitiveOptionsEnd +} diff --git a/vendor/k8s.io/mount-utils/mount_helper_common.go b/vendor/k8s.io/mount-utils/mount_helper_common.go new file mode 100644 index 000000000..dc4131d78 --- /dev/null +++ b/vendor/k8s.io/mount-utils/mount_helper_common.go @@ -0,0 +1,157 @@ +/* +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 mount + +import ( + "fmt" + "os" + "time" + + "k8s.io/klog/v2" +) + +// CleanupMountPoint unmounts the given path and deletes the remaining directory +// if successful. If extensiveMountPointCheck is true IsNotMountPoint will be +// called instead of IsLikelyNotMountPoint. IsNotMountPoint is more expensive +// but properly handles bind mounts within the same fs. +func CleanupMountPoint(mountPath string, mounter Interface, extensiveMountPointCheck bool) error { + pathExists, pathErr := PathExists(mountPath) + if !pathExists && pathErr == nil { + klog.Warningf("Warning: mount cleanup skipped because path does not exist: %v", mountPath) + return nil + } + corruptedMnt := IsCorruptedMnt(pathErr) + if pathErr != nil && !corruptedMnt { + return fmt.Errorf("Error checking path: %v", pathErr) + } + return doCleanupMountPoint(mountPath, mounter, extensiveMountPointCheck, corruptedMnt) +} + +func CleanupMountWithForce(mountPath string, mounter MounterForceUnmounter, extensiveMountPointCheck bool, umountTimeout time.Duration) error { + pathExists, pathErr := PathExists(mountPath) + if !pathExists && pathErr == nil { + klog.Warningf("Warning: mount cleanup skipped because path does not exist: %v", mountPath) + return nil + } + corruptedMnt := IsCorruptedMnt(pathErr) + if pathErr != nil && !corruptedMnt { + return fmt.Errorf("Error checking path: %v", pathErr) + } + + if corruptedMnt || mounter.canSafelySkipMountPointCheck() { + klog.V(4).Infof("unmounting %q (corruptedMount: %t, mounterCanSkipMountPointChecks: %t)", + mountPath, corruptedMnt, mounter.canSafelySkipMountPointCheck()) + if err := mounter.UnmountWithForce(mountPath, umountTimeout); err != nil { + return err + } + return removePath(mountPath) + } + + notMnt, err := removePathIfNotMountPoint(mountPath, mounter, extensiveMountPointCheck) + // if mountPath is not a mount point, it's just been removed or there was an error + if err != nil || notMnt { + return err + } + + klog.V(4).Infof("%q is a mountpoint, unmounting", mountPath) + if err := mounter.UnmountWithForce(mountPath, umountTimeout); err != nil { + return err + } + + notMnt, err = removePathIfNotMountPoint(mountPath, mounter, extensiveMountPointCheck) + // if mountPath is not a mount point, it's either just been removed or there was an error + if notMnt { + return err + } + // mountPath is still a mount point + return fmt.Errorf("failed to cleanup mount point %v", mountPath) +} + +// doCleanupMountPoint unmounts the given path and +// deletes the remaining directory if successful. +// if extensiveMountPointCheck is true +// IsNotMountPoint will be called instead of IsLikelyNotMountPoint. +// IsNotMountPoint is more expensive but properly handles bind mounts within the same fs. +// if corruptedMnt is true, it means that the mountPath is a corrupted mountpoint, and the mount point check +// will be skipped. The mount point check will also be skipped if the mounter supports it. +func doCleanupMountPoint(mountPath string, mounter Interface, extensiveMountPointCheck bool, corruptedMnt bool) error { + if corruptedMnt || mounter.canSafelySkipMountPointCheck() { + klog.V(4).Infof("unmounting %q (corruptedMount: %t, mounterCanSkipMountPointChecks: %t)", + mountPath, corruptedMnt, mounter.canSafelySkipMountPointCheck()) + if err := mounter.Unmount(mountPath); err != nil { + return err + } + return removePath(mountPath) + } + + notMnt, err := removePathIfNotMountPoint(mountPath, mounter, extensiveMountPointCheck) + // if mountPath is not a mount point, it's just been removed or there was an error + if err != nil || notMnt { + return err + } + + klog.V(4).Infof("%q is a mountpoint, unmounting", mountPath) + if err := mounter.Unmount(mountPath); err != nil { + return err + } + + notMnt, err = removePathIfNotMountPoint(mountPath, mounter, extensiveMountPointCheck) + // if mountPath is not a mount point, it's either just been removed or there was an error + if notMnt { + return err + } + // mountPath is still a mount point + return fmt.Errorf("failed to cleanup mount point %v", mountPath) +} + +// removePathIfNotMountPoint verifies if given mountPath is a mount point if not it attempts +// to remove the directory. Returns true and nil if directory was not a mount point and removed. +func removePathIfNotMountPoint(mountPath string, mounter Interface, extensiveMountPointCheck bool) (bool, error) { + var notMnt bool + var err error + + if extensiveMountPointCheck { + notMnt, err = IsNotMountPoint(mounter, mountPath) + } else { + notMnt, err = mounter.IsLikelyNotMountPoint(mountPath) + } + + if err != nil { + if os.IsNotExist(err) { + klog.V(4).Infof("%q does not exist", mountPath) + return true, nil + } + return notMnt, err + } + + if notMnt { + klog.Warningf("Warning: %q is not a mountpoint, deleting", mountPath) + return notMnt, os.Remove(mountPath) + } + return notMnt, nil +} + +// removePath attempts to remove the directory. Returns nil if the directory was removed or does not exist. +func removePath(mountPath string) error { + klog.V(4).Infof("Warning: deleting path %q", mountPath) + err := os.Remove(mountPath) + if os.IsNotExist(err) { + klog.V(4).Infof("%q does not exist", mountPath) + return nil + } + return err +} diff --git a/vendor/k8s.io/mount-utils/mount_helper_unix.go b/vendor/k8s.io/mount-utils/mount_helper_unix.go new file mode 100644 index 000000000..cb8732fce --- /dev/null +++ b/vendor/k8s.io/mount-utils/mount_helper_unix.go @@ -0,0 +1,201 @@ +//go:build !windows +// +build !windows + +/* +Copyright 2019 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 mount + +import ( + "errors" + "fmt" + "io/fs" + "os" + "strconv" + "strings" + "syscall" + + "k8s.io/klog/v2" + utilio "k8s.io/utils/io" +) + +const ( + // At least number of fields per line in /proc//mountinfo. + expectedAtLeastNumFieldsPerMountInfo = 10 + // How many times to retry for a consistent read of /proc/mounts. + maxListTries = 10 +) + +// IsCorruptedMnt return true if err is about corrupted mount point +func IsCorruptedMnt(err error) bool { + if err == nil { + return false + } + var underlyingError error + switch pe := err.(type) { + case nil: + return false + case *os.PathError: + underlyingError = pe.Err + case *os.LinkError: + underlyingError = pe.Err + case *os.SyscallError: + underlyingError = pe.Err + case syscall.Errno: + underlyingError = err + } + + return underlyingError == syscall.ENOTCONN || underlyingError == syscall.ESTALE || underlyingError == syscall.EIO || underlyingError == syscall.EACCES || underlyingError == syscall.EHOSTDOWN +} + +// MountInfo represents a single line in /proc//mountinfo. +type MountInfo struct { // nolint: golint + // Unique ID for the mount (maybe reused after umount). + ID int + // The ID of the parent mount (or of self for the root of this mount namespace's mount tree). + ParentID int + // Major indicates one half of the device ID which identifies the device class + // (parsed from `st_dev` for files on this filesystem). + Major int + // Minor indicates one half of the device ID which identifies a specific + // instance of device (parsed from `st_dev` for files on this filesystem). + Minor int + // The pathname of the directory in the filesystem which forms the root of this mount. + Root string + // Mount source, filesystem-specific information. e.g. device, tmpfs name. + Source string + // Mount point, the pathname of the mount point. + MountPoint string + // Optional fieds, zero or more fields of the form "tag[:value]". + OptionalFields []string + // The filesystem type in the form "type[.subtype]". + FsType string + // Per-mount options. + MountOptions []string + // Per-superblock options. + SuperOptions []string +} + +// ParseMountInfo parses /proc/xxx/mountinfo. +func ParseMountInfo(filename string) ([]MountInfo, error) { + content, err := utilio.ConsistentRead(filename, maxListTries) + if err != nil { + return []MountInfo{}, err + } + contentStr := string(content) + infos := []MountInfo{} + + for _, line := range strings.Split(contentStr, "\n") { + if line == "" { + // the last split() item is empty string following the last \n + continue + } + // See `man proc` for authoritative description of format of the file. + fields := strings.Fields(line) + if len(fields) < expectedAtLeastNumFieldsPerMountInfo { + return nil, fmt.Errorf("wrong number of fields in (expected at least %d, got %d): %s", expectedAtLeastNumFieldsPerMountInfo, len(fields), line) + } + id, err := strconv.Atoi(fields[0]) + if err != nil { + return nil, err + } + parentID, err := strconv.Atoi(fields[1]) + if err != nil { + return nil, err + } + mm := strings.Split(fields[2], ":") + if len(mm) != 2 { + return nil, fmt.Errorf("parsing '%s' failed: unexpected minor:major pair %s", line, mm) + } + major, err := strconv.Atoi(mm[0]) + if err != nil { + return nil, fmt.Errorf("parsing '%s' failed: unable to parse major device id, err:%v", mm[0], err) + } + minor, err := strconv.Atoi(mm[1]) + if err != nil { + return nil, fmt.Errorf("parsing '%s' failed: unable to parse minor device id, err:%v", mm[1], err) + } + + info := MountInfo{ + ID: id, + ParentID: parentID, + Major: major, + Minor: minor, + Root: fields[3], + MountPoint: fields[4], + MountOptions: splitMountOptions(fields[5]), + } + // All fields until "-" are "optional fields". + i := 6 + for ; i < len(fields) && fields[i] != "-"; i++ { + info.OptionalFields = append(info.OptionalFields, fields[i]) + } + // Parse the rest 3 fields. + i++ + if len(fields)-i < 3 { + return nil, fmt.Errorf("expect 3 fields in %s, got %d", line, len(fields)-i) + } + info.FsType = fields[i] + info.Source = fields[i+1] + info.SuperOptions = splitMountOptions(fields[i+2]) + infos = append(infos, info) + } + return infos, nil +} + +// splitMountOptions parses comma-separated list of mount options into an array. +// It respects double quotes - commas in them are not considered as the option separator. +func splitMountOptions(s string) []string { + inQuotes := false + list := strings.FieldsFunc(s, func(r rune) bool { + if r == '"' { + inQuotes = !inQuotes + } + // Report a new field only when outside of double quotes. + return r == ',' && !inQuotes + }) + return list +} + +// isMountPointMatch returns true if the path in mp is the same as dir. +// Handles case where mountpoint dir has been renamed due to stale NFS mount. +func isMountPointMatch(mp MountPoint, dir string) bool { + deletedDir := fmt.Sprintf("%s\\040(deleted)", dir) + return ((mp.Path == dir) || (mp.Path == deletedDir)) +} + +// PathExists returns true if the specified path exists. +// TODO: clean this up to use pkg/util/file/FileExists +func PathExists(path string) (bool, error) { + _, err := os.Stat(path) + if err == nil { + return true, nil + } else if errors.Is(err, fs.ErrNotExist) { + err = syscall.Access(path, syscall.F_OK) + if err == nil { + // The access syscall says the file exists, the stat syscall says it + // doesn't. This was observed on CIFS when the path was removed at + // the server somehow. POSIX calls this a stale file handle, let's fake + // that error and treat the path as existing but corrupted. + klog.Warningf("Potential stale file handle detected: %s", path) + return true, syscall.ESTALE + } + return false, nil + } else if IsCorruptedMnt(err) { + return true, err + } + return false, err +} diff --git a/vendor/k8s.io/mount-utils/mount_helper_windows.go b/vendor/k8s.io/mount-utils/mount_helper_windows.go new file mode 100644 index 000000000..995fd5a0c --- /dev/null +++ b/vendor/k8s.io/mount-utils/mount_helper_windows.go @@ -0,0 +1,111 @@ +//go:build windows +// +build windows + +/* +Copyright 2019 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 mount + +import ( + "fmt" + "os" + "strconv" + "strings" + "syscall" + + "k8s.io/klog/v2" +) + +// following failure codes are from https://docs.microsoft.com/en-us/windows/desktop/debug/system-error-codes--1300-1699- +// ERROR_BAD_NETPATH = 53 +// ERROR_NETWORK_BUSY = 54 +// ERROR_UNEXP_NET_ERR = 59 +// ERROR_NETNAME_DELETED = 64 +// ERROR_NETWORK_ACCESS_DENIED = 65 +// ERROR_BAD_DEV_TYPE = 66 +// ERROR_BAD_NET_NAME = 67 +// ERROR_SESSION_CREDENTIAL_CONFLICT = 1219 +// ERROR_LOGON_FAILURE = 1326 +// WSAEHOSTDOWN = 10064 +var errorNoList = [...]int{53, 54, 59, 64, 65, 66, 67, 1219, 1326, 10064} + +// IsCorruptedMnt return true if err is about corrupted mount point +func IsCorruptedMnt(err error) bool { + if err == nil { + return false + } + + var underlyingError error + switch pe := err.(type) { + case nil: + return false + case *os.PathError: + underlyingError = pe.Err + case *os.LinkError: + underlyingError = pe.Err + case *os.SyscallError: + underlyingError = pe.Err + } + + if ee, ok := underlyingError.(syscall.Errno); ok { + for _, errno := range errorNoList { + if int(ee) == errno { + klog.Warningf("IsCorruptedMnt failed with error: %v, error code: %v", err, errno) + return true + } + } + } + + return false +} + +// NormalizeWindowsPath makes sure the given path is a valid path on Windows +// systems by making sure all instances of `/` are replaced with `\\`, and the +// path beings with `c:` +func NormalizeWindowsPath(path string) string { + normalizedPath := strings.Replace(path, "/", "\\", -1) + if strings.HasPrefix(normalizedPath, "\\") { + normalizedPath = "c:" + normalizedPath + } + return normalizedPath +} + +// ValidateDiskNumber : disk number should be a number in [0, 99] +func ValidateDiskNumber(disk string) error { + if _, err := strconv.Atoi(disk); err != nil { + return fmt.Errorf("wrong disk number format: %q, err: %v", disk, err) + } + return nil +} + +// isMountPointMatch determines if the mountpoint matches the dir +func isMountPointMatch(mp MountPoint, dir string) bool { + return mp.Path == dir +} + +// PathExists returns true if the specified path exists. +// TODO: clean this up to use pkg/util/file/FileExists +func PathExists(path string) (bool, error) { + _, err := os.Stat(path) + if err == nil { + return true, nil + } else if os.IsNotExist(err) { + return false, nil + } else if IsCorruptedMnt(err) { + return true, err + } + return false, err +} diff --git a/vendor/k8s.io/mount-utils/mount_linux.go b/vendor/k8s.io/mount-utils/mount_linux.go new file mode 100644 index 000000000..1752d11f6 --- /dev/null +++ b/vendor/k8s.io/mount-utils/mount_linux.go @@ -0,0 +1,805 @@ +//go:build linux +// +build linux + +/* +Copyright 2014 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 mount + +import ( + "context" + "errors" + "fmt" + "github.com/moby/sys/mountinfo" + "io/fs" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strconv" + "strings" + "syscall" + "time" + + "k8s.io/klog/v2" + utilexec "k8s.io/utils/exec" + utilio "k8s.io/utils/io" +) + +const ( + // Number of fields per line in /proc/mounts as per the fstab man page. + expectedNumFieldsPerLine = 6 + // Location of the mount file to use + procMountsPath = "/proc/mounts" + // Location of the mountinfo file + procMountInfoPath = "/proc/self/mountinfo" + // 'fsck' found errors and corrected them + fsckErrorsCorrected = 1 + // 'fsck' found errors but exited without correcting them + fsckErrorsUncorrected = 4 + // Error thrown by exec cmd.Run() when process spawned by cmd.Start() completes before cmd.Wait() is called (see - k/k issue #103753) + errNoChildProcesses = "wait: no child processes" + // Error returned by some `umount` implementations when the specified path is not a mount point + errNotMounted = "not mounted" +) + +// Mounter provides the default implementation of mount.Interface +// for the linux platform. This implementation assumes that the +// kubelet is running in the host's root mount namespace. +type Mounter struct { + mounterPath string + withSystemd *bool + trySystemd bool + withSafeNotMountedBehavior bool +} + +var _ MounterForceUnmounter = &Mounter{} + +// New returns a mount.Interface for the current system. +// It provides options to override the default mounter behavior. +// mounterPath allows using an alternative to `/bin/mount` for mounting. +func New(mounterPath string) Interface { + return &Mounter{ + mounterPath: mounterPath, + trySystemd: true, + withSafeNotMountedBehavior: detectSafeNotMountedBehavior(), + } +} + +// NewWithoutSystemd returns a Linux specific mount.Interface for the current +// system. It provides options to override the default mounter behavior. +// mounterPath allows using an alternative to `/bin/mount` for mounting. Any +// detection for systemd functionality is disabled with this Mounter. +func NewWithoutSystemd(mounterPath string) Interface { + return &Mounter{ + mounterPath: mounterPath, + trySystemd: false, + withSafeNotMountedBehavior: detectSafeNotMountedBehavior(), + } +} + +// hasSystemd validates that the withSystemd bool is set, if it is not, +// detectSystemd will be called once for this Mounter instance. +func (mounter *Mounter) hasSystemd() bool { + if !mounter.trySystemd { + mounter.withSystemd = &mounter.trySystemd + } + + if mounter.withSystemd == nil { + withSystemd := detectSystemd() + mounter.withSystemd = &withSystemd + } + + return *mounter.withSystemd +} + +// Mount mounts source to target as fstype with given options. 'source' and 'fstype' must +// be an empty string in case it's not required, e.g. for remount, or for auto filesystem +// type, where kernel handles fstype for you. The mount 'options' is a list of options, +// currently come from mount(8), e.g. "ro", "remount", "bind", etc. If no more option is +// required, call Mount with an empty string list or nil. +func (mounter *Mounter) Mount(source string, target string, fstype string, options []string) error { + return mounter.MountSensitive(source, target, fstype, options, nil) +} + +// MountSensitive is the same as Mount() but this method allows +// sensitiveOptions to be passed in a separate parameter from the normal +// mount options and ensures the sensitiveOptions are never logged. This +// method should be used by callers that pass sensitive material (like +// passwords) as mount options. +func (mounter *Mounter) MountSensitive(source string, target string, fstype string, options []string, sensitiveOptions []string) error { + // Path to mounter binary if containerized mounter is needed. Otherwise, it is set to empty. + // All Linux distros are expected to be shipped with a mount utility that a support bind mounts. + mounterPath := "" + bind, bindOpts, bindRemountOpts, bindRemountOptsSensitive := MakeBindOptsSensitive(options, sensitiveOptions) + if bind { + err := mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindOpts, bindRemountOptsSensitive, nil /* mountFlags */, mounter.trySystemd) + if err != nil { + return err + } + return mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindRemountOpts, bindRemountOptsSensitive, nil /* mountFlags */, mounter.trySystemd) + } + // The list of filesystems that require containerized mounter on GCI image cluster + fsTypesNeedMounter := map[string]struct{}{ + "nfs": {}, + "glusterfs": {}, + "ceph": {}, + "cifs": {}, + } + if _, ok := fsTypesNeedMounter[fstype]; ok { + mounterPath = mounter.mounterPath + } + return mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, options, sensitiveOptions, nil /* mountFlags */, mounter.trySystemd) +} + +// MountSensitiveWithoutSystemd is the same as MountSensitive() but disable using systemd mount. +func (mounter *Mounter) MountSensitiveWithoutSystemd(source string, target string, fstype string, options []string, sensitiveOptions []string) error { + return mounter.MountSensitiveWithoutSystemdWithMountFlags(source, target, fstype, options, sensitiveOptions, nil /* mountFlags */) +} + +// MountSensitiveWithoutSystemdWithMountFlags is the same as MountSensitiveWithoutSystemd with additional mount flags. +func (mounter *Mounter) MountSensitiveWithoutSystemdWithMountFlags(source string, target string, fstype string, options []string, sensitiveOptions []string, mountFlags []string) error { + mounterPath := "" + bind, bindOpts, bindRemountOpts, bindRemountOptsSensitive := MakeBindOptsSensitive(options, sensitiveOptions) + if bind { + err := mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindOpts, bindRemountOptsSensitive, mountFlags, false) + if err != nil { + return err + } + return mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindRemountOpts, bindRemountOptsSensitive, mountFlags, false) + } + // The list of filesystems that require containerized mounter on GCI image cluster + fsTypesNeedMounter := map[string]struct{}{ + "nfs": {}, + "glusterfs": {}, + "ceph": {}, + "cifs": {}, + } + if _, ok := fsTypesNeedMounter[fstype]; ok { + mounterPath = mounter.mounterPath + } + return mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, options, sensitiveOptions, mountFlags, false) +} + +// doMount runs the mount command. mounterPath is the path to mounter binary if containerized mounter is used. +// sensitiveOptions is an extension of options except they will not be logged (because they may contain sensitive material) +// systemdMountRequired is an extension of option to decide whether uses systemd mount. +func (mounter *Mounter) doMount(mounterPath string, mountCmd string, source string, target string, fstype string, options []string, sensitiveOptions []string, mountFlags []string, systemdMountRequired bool) error { + mountArgs, mountArgsLogStr := MakeMountArgsSensitiveWithMountFlags(source, target, fstype, options, sensitiveOptions, mountFlags) + if len(mounterPath) > 0 { + mountArgs = append([]string{mountCmd}, mountArgs...) + mountArgsLogStr = mountCmd + " " + mountArgsLogStr + mountCmd = mounterPath + } + + if systemdMountRequired && mounter.hasSystemd() { + // Try to run mount via systemd-run --scope. This will escape the + // service where kubelet runs and any fuse daemons will be started in a + // specific scope. kubelet service than can be restarted without killing + // these fuse daemons. + // + // Complete command line (when mounterPath is not used): + // systemd-run --description=... --scope -- mount -t + // + // Expected flow: + // * systemd-run creates a transient scope (=~ cgroup) and executes its + // argument (/bin/mount) there. + // * mount does its job, forks a fuse daemon if necessary and finishes. + // (systemd-run --scope finishes at this point, returning mount's exit + // code and stdout/stderr - thats one of --scope benefits). + // * systemd keeps the fuse daemon running in the scope (i.e. in its own + // cgroup) until the fuse daemon dies (another --scope benefit). + // Kubelet service can be restarted and the fuse daemon survives. + // * When the fuse daemon dies (e.g. during unmount) systemd removes the + // scope automatically. + // + // systemd-mount is not used because it's too new for older distros + // (CentOS 7, Debian Jessie). + mountCmd, mountArgs, mountArgsLogStr = AddSystemdScopeSensitive("systemd-run", target, mountCmd, mountArgs, mountArgsLogStr) + // } else { + // No systemd-run on the host (or we failed to check it), assume kubelet + // does not run as a systemd service. + // No code here, mountCmd and mountArgs are already populated. + } + + // Logging with sensitive mount options removed. + klog.V(4).Infof("Mounting cmd (%s) with arguments (%s)", mountCmd, mountArgsLogStr) + command := exec.Command(mountCmd, mountArgs...) + output, err := command.CombinedOutput() + if err != nil { + if err.Error() == errNoChildProcesses { + if command.ProcessState.Success() { + // We don't consider errNoChildProcesses an error if the process itself succeeded (see - k/k issue #103753). + return nil + } + // Rewrite err with the actual exit error of the process. + err = &exec.ExitError{ProcessState: command.ProcessState} + } + klog.Errorf("Mount failed: %v\nMounting command: %s\nMounting arguments: %s\nOutput: %s\n", err, mountCmd, mountArgsLogStr, string(output)) + return fmt.Errorf("mount failed: %v\nMounting command: %s\nMounting arguments: %s\nOutput: %s", + err, mountCmd, mountArgsLogStr, string(output)) + } + return err +} + +// detectSystemd returns true if OS runs with systemd as init. When not sure +// (permission errors, ...), it returns false. +// There may be different ways how to detect systemd, this one makes sure that +// systemd-runs (needed by Mount()) works. +func detectSystemd() bool { + if _, err := exec.LookPath("systemd-run"); err != nil { + klog.V(2).Infof("Detected OS without systemd") + return false + } + // Try to run systemd-run --scope /bin/true, that should be enough + // to make sure that systemd is really running and not just installed, + // which happens when running in a container with a systemd-based image + // but with different pid 1. + cmd := exec.Command("systemd-run", "--description=Kubernetes systemd probe", "--scope", "true") + output, err := cmd.CombinedOutput() + if err != nil { + klog.V(2).Infof("Cannot run systemd-run, assuming non-systemd OS") + klog.V(4).Infof("systemd-run output: %s, failed with: %v", string(output), err) + return false + } + klog.V(2).Infof("Detected OS with systemd") + return true +} + +// detectSafeNotMountedBehavior returns true if the umount implementation replies "not mounted" +// when the specified path is not mounted. When not sure (permission errors, ...), it returns false. +// When possible, we will trust umount's message and avoid doing our own mount point checks. +// More info: https://github.com/util-linux/util-linux/blob/v2.2/mount/umount.c#L179 +func detectSafeNotMountedBehavior() bool { + return detectSafeNotMountedBehaviorWithExec(utilexec.New()) +} + +// detectSafeNotMountedBehaviorWithExec is for testing with FakeExec. +func detectSafeNotMountedBehaviorWithExec(exec utilexec.Interface) bool { + // create a temp dir and try to umount it + path, err := ioutil.TempDir("", "kubelet-detect-safe-umount") + if err != nil { + klog.V(4).Infof("Cannot create temp dir to detect safe 'not mounted' behavior: %v", err) + return false + } + defer os.RemoveAll(path) + cmd := exec.Command("umount", path) + output, err := cmd.CombinedOutput() + if err != nil { + if strings.Contains(string(output), errNotMounted) { + klog.V(4).Infof("Detected umount with safe 'not mounted' behavior") + return true + } + klog.V(4).Infof("'umount %s' failed with: %v, output: %s", path, err, string(output)) + } + klog.V(4).Infof("Detected umount with unsafe 'not mounted' behavior") + return false +} + +// MakeMountArgs makes the arguments to the mount(8) command. +// options MUST not contain sensitive material (like passwords). +func MakeMountArgs(source, target, fstype string, options []string) (mountArgs []string) { + mountArgs, _ = MakeMountArgsSensitive(source, target, fstype, options, nil /* sensitiveOptions */) + return mountArgs +} + +// MakeMountArgsSensitive makes the arguments to the mount(8) command. +// sensitiveOptions is an extension of options except they will not be logged (because they may contain sensitive material) +func MakeMountArgsSensitive(source, target, fstype string, options []string, sensitiveOptions []string) (mountArgs []string, mountArgsLogStr string) { + return MakeMountArgsSensitiveWithMountFlags(source, target, fstype, options, sensitiveOptions, nil /* mountFlags */) +} + +// MakeMountArgsSensitiveWithMountFlags makes the arguments to the mount(8) command. +// sensitiveOptions is an extension of options except they will not be logged (because they may contain sensitive material) +// mountFlags are additional mount flags that are not related with the fstype +// and mount options +func MakeMountArgsSensitiveWithMountFlags(source, target, fstype string, options []string, sensitiveOptions []string, mountFlags []string) (mountArgs []string, mountArgsLogStr string) { + // Build mount command as follows: + // mount [$mountFlags] [-t $fstype] [-o $options] [$source] $target + mountArgs = []string{} + mountArgsLogStr = "" + + mountArgs = append(mountArgs, mountFlags...) + mountArgsLogStr += strings.Join(mountFlags, " ") + + if len(fstype) > 0 { + mountArgs = append(mountArgs, "-t", fstype) + mountArgsLogStr += strings.Join(mountArgs, " ") + } + if len(options) > 0 || len(sensitiveOptions) > 0 { + combinedOptions := []string{} + combinedOptions = append(combinedOptions, options...) + combinedOptions = append(combinedOptions, sensitiveOptions...) + mountArgs = append(mountArgs, "-o", strings.Join(combinedOptions, ",")) + // exclude sensitiveOptions from log string + mountArgsLogStr += " -o " + sanitizedOptionsForLogging(options, sensitiveOptions) + } + if len(source) > 0 { + mountArgs = append(mountArgs, source) + mountArgsLogStr += " " + source + } + mountArgs = append(mountArgs, target) + mountArgsLogStr += " " + target + + return mountArgs, mountArgsLogStr +} + +// AddSystemdScope adds "system-run --scope" to given command line +// If args contains sensitive material, use AddSystemdScopeSensitive to construct +// a safe to log string. +func AddSystemdScope(systemdRunPath, mountName, command string, args []string) (string, []string) { + descriptionArg := fmt.Sprintf("--description=Kubernetes transient mount for %s", mountName) + systemdRunArgs := []string{descriptionArg, "--scope", "--", command} + return systemdRunPath, append(systemdRunArgs, args...) +} + +// AddSystemdScopeSensitive adds "system-run --scope" to given command line +// It also accepts takes a sanitized string containing mount arguments, mountArgsLogStr, +// and returns the string appended to the systemd command for logging. +func AddSystemdScopeSensitive(systemdRunPath, mountName, command string, args []string, mountArgsLogStr string) (string, []string, string) { + descriptionArg := fmt.Sprintf("--description=Kubernetes transient mount for %s", mountName) + systemdRunArgs := []string{descriptionArg, "--scope", "--", command} + return systemdRunPath, append(systemdRunArgs, args...), strings.Join(systemdRunArgs, " ") + " " + mountArgsLogStr +} + +// Unmount unmounts the target. +// If the mounter has safe "not mounted" behavior, no error will be returned when the target is not a mount point. +func (mounter *Mounter) Unmount(target string) error { + klog.V(4).Infof("Unmounting %s", target) + command := exec.Command("umount", target) + output, err := command.CombinedOutput() + if err != nil { + if err.Error() == errNoChildProcesses { + if command.ProcessState.Success() { + // We don't consider errNoChildProcesses an error if the process itself succeeded (see - k/k issue #103753). + return nil + } + // Rewrite err with the actual exit error of the process. + err = &exec.ExitError{ProcessState: command.ProcessState} + } + if mounter.withSafeNotMountedBehavior && strings.Contains(string(output), errNotMounted) { + klog.V(4).Infof("ignoring 'not mounted' error for %s", target) + return nil + } + return fmt.Errorf("unmount failed: %v\nUnmounting arguments: %s\nOutput: %s", err, target, string(output)) + } + return nil +} + +// UnmountWithForce unmounts given target but will retry unmounting with force option +// after given timeout. +func (mounter *Mounter) UnmountWithForce(target string, umountTimeout time.Duration) error { + err := tryUnmount(target, umountTimeout) + if err != nil { + if err == context.DeadlineExceeded { + klog.V(2).Infof("Timed out waiting for unmount of %s, trying with -f", target) + err = forceUmount(target) + } + return err + } + return nil +} + +// List returns a list of all mounted filesystems. +func (*Mounter) List() ([]MountPoint, error) { + return ListProcMounts(procMountsPath) +} + +// IsLikelyNotMountPoint determines if a directory is not a mountpoint. +// It is fast but not necessarily ALWAYS correct. If the path is in fact +// a bind mount from one part of a mount to another it will not be detected. +// It also can not distinguish between mountpoints and symbolic links. +// mkdir /tmp/a /tmp/b; mount --bind /tmp/a /tmp/b; IsLikelyNotMountPoint("/tmp/b") +// will return true. When in fact /tmp/b is a mount point. If this situation +// is of interest to you, don't use this function... +func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) { + stat, err := os.Stat(file) + if err != nil { + return true, err + } + rootStat, err := os.Stat(filepath.Dir(strings.TrimSuffix(file, "/"))) + if err != nil { + return true, err + } + // If the directory has a different device as parent, then it is a mountpoint. + if stat.Sys().(*syscall.Stat_t).Dev != rootStat.Sys().(*syscall.Stat_t).Dev { + return false, nil + } + + return true, nil +} + +// canSafelySkipMountPointCheck relies on the detected behavior of umount when given a target that is not a mount point. +func (mounter *Mounter) canSafelySkipMountPointCheck() bool { + return mounter.withSafeNotMountedBehavior +} + +// GetMountRefs finds all mount references to pathname, returns a +// list of paths. Path could be a mountpoint or a normal +// directory (for bind mount). +func (mounter *Mounter) GetMountRefs(pathname string) ([]string, error) { + pathExists, pathErr := PathExists(pathname) + if !pathExists { + return []string{}, nil + } else if IsCorruptedMnt(pathErr) { + klog.Warningf("GetMountRefs found corrupted mount at %s, treating as unmounted path", pathname) + return []string{}, nil + } else if pathErr != nil { + return nil, fmt.Errorf("error checking path %s: %v", pathname, pathErr) + } + realpath, err := filepath.EvalSymlinks(pathname) + if err != nil { + return nil, err + } + return SearchMountPoints(realpath, procMountInfoPath) +} + +// checkAndRepairFileSystem checks and repairs filesystems using command fsck. +func (mounter *SafeFormatAndMount) checkAndRepairFilesystem(source string) error { + klog.V(4).Infof("Checking for issues with fsck on disk: %s", source) + args := []string{"-a", source} + out, err := mounter.Exec.Command("fsck", args...).CombinedOutput() + if err != nil { + ee, isExitError := err.(utilexec.ExitError) + switch { + case err == utilexec.ErrExecutableNotFound: + klog.Warningf("'fsck' not found on system; continuing mount without running 'fsck'.") + case isExitError && ee.ExitStatus() == fsckErrorsCorrected: + klog.Infof("Device %s has errors which were corrected by fsck.", source) + case isExitError && ee.ExitStatus() == fsckErrorsUncorrected: + return NewMountError(HasFilesystemErrors, "'fsck' found errors on device %s but could not correct them: %s", source, string(out)) + case isExitError && ee.ExitStatus() > fsckErrorsUncorrected: + klog.Infof("`fsck` error %s", string(out)) + default: + klog.Warningf("fsck on device %s failed with error %v, output: %v", source, err, string(out)) + } + } + return nil +} + +// formatAndMount uses unix utils to format and mount the given disk +func (mounter *SafeFormatAndMount) formatAndMountSensitive(source string, target string, fstype string, options []string, sensitiveOptions []string, formatOptions []string) error { + readOnly := false + for _, option := range options { + if option == "ro" { + readOnly = true + break + } + } + if !readOnly { + // Check sensitiveOptions for ro + for _, option := range sensitiveOptions { + if option == "ro" { + readOnly = true + break + } + } + } + + options = append(options, "defaults") + mountErrorValue := UnknownMountError + + // Check if the disk is already formatted + existingFormat, err := mounter.GetDiskFormat(source) + if err != nil { + return NewMountError(GetDiskFormatFailed, "failed to get disk format of disk %s: %v", source, err) + } + + // Use 'ext4' as the default + if len(fstype) == 0 { + fstype = "ext4" + } + + if existingFormat == "" { + // Do not attempt to format the disk if mounting as readonly, return an error to reflect this. + if readOnly { + return NewMountError(UnformattedReadOnly, "cannot mount unformatted disk %s as we are manipulating it in read-only mode", source) + } + + // Disk is unformatted so format it. + args := []string{source} + if fstype == "ext4" || fstype == "ext3" { + args = []string{ + "-F", // Force flag + "-m0", // Zero blocks reserved for super-user + source, + } + } else if fstype == "xfs" { + args = []string{ + "-f", // force flag + source, + } + } + args = append(formatOptions, args...) + + klog.Infof("Disk %q appears to be unformatted, attempting to format as type: %q with options: %v", source, fstype, args) + output, err := mounter.Exec.Command("mkfs."+fstype, args...).CombinedOutput() + if err != nil { + // Do not log sensitiveOptions only options + sensitiveOptionsLog := sanitizedOptionsForLogging(options, sensitiveOptions) + detailedErr := fmt.Sprintf("format of disk %q failed: type:(%q) target:(%q) options:(%q) errcode:(%v) output:(%v) ", source, fstype, target, sensitiveOptionsLog, err, string(output)) + klog.Error(detailedErr) + return NewMountError(FormatFailed, detailedErr) + } + + klog.Infof("Disk successfully formatted (mkfs): %s - %s %s", fstype, source, target) + } else { + if fstype != existingFormat { + // Verify that the disk is formatted with filesystem type we are expecting + mountErrorValue = FilesystemMismatch + klog.Warningf("Configured to mount disk %s as %s but current format is %s, things might break", source, existingFormat, fstype) + } + + if !readOnly { + // Run check tools on the disk to fix repairable issues, only do this for formatted volumes requested as rw. + err := mounter.checkAndRepairFilesystem(source) + if err != nil { + return err + } + } + } + + // Mount the disk + klog.V(4).Infof("Attempting to mount disk %s in %s format at %s", source, fstype, target) + if err := mounter.MountSensitive(source, target, fstype, options, sensitiveOptions); err != nil { + return NewMountError(mountErrorValue, err.Error()) + } + + return nil +} + +func getDiskFormat(exec utilexec.Interface, disk string) (string, error) { + args := []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", disk} + klog.V(4).Infof("Attempting to determine if disk %q is formatted using blkid with args: (%v)", disk, args) + dataOut, err := exec.Command("blkid", args...).CombinedOutput() + output := string(dataOut) + klog.V(4).Infof("Output: %q", output) + + if err != nil { + if exit, ok := err.(utilexec.ExitError); ok { + if exit.ExitStatus() == 2 { + // Disk device is unformatted. + // For `blkid`, if the specified token (TYPE/PTTYPE, etc) was + // not found, or no (specified) devices could be identified, an + // exit code of 2 is returned. + return "", nil + } + } + klog.Errorf("Could not determine if disk %q is formatted (%v)", disk, err) + return "", err + } + + var fstype, pttype string + + lines := strings.Split(output, "\n") + for _, l := range lines { + if len(l) <= 0 { + // Ignore empty line. + continue + } + cs := strings.Split(l, "=") + if len(cs) != 2 { + return "", fmt.Errorf("blkid returns invalid output: %s", output) + } + // TYPE is filesystem type, and PTTYPE is partition table type, according + // to https://www.kernel.org/pub/linux/utils/util-linux/v2.21/libblkid-docs/. + if cs[0] == "TYPE" { + fstype = cs[1] + } else if cs[0] == "PTTYPE" { + pttype = cs[1] + } + } + + if len(pttype) > 0 { + klog.V(4).Infof("Disk %s detected partition table type: %s", disk, pttype) + // Returns a special non-empty string as filesystem type, then kubelet + // will not format it. + return "unknown data, probably partitions", nil + } + + return fstype, nil +} + +// GetDiskFormat uses 'blkid' to see if the given disk is unformatted +func (mounter *SafeFormatAndMount) GetDiskFormat(disk string) (string, error) { + return getDiskFormat(mounter.Exec, disk) +} + +// ListProcMounts is shared with NsEnterMounter +func ListProcMounts(mountFilePath string) ([]MountPoint, error) { + content, err := utilio.ConsistentRead(mountFilePath, maxListTries) + if err != nil { + return nil, err + } + return parseProcMounts(content) +} + +func parseProcMounts(content []byte) ([]MountPoint, error) { + out := []MountPoint{} + lines := strings.Split(string(content), "\n") + for _, line := range lines { + if line == "" { + // the last split() item is empty string following the last \n + continue + } + fields := strings.Fields(line) + if len(fields) != expectedNumFieldsPerLine { + // Do not log line in case it contains sensitive Mount options + return nil, fmt.Errorf("wrong number of fields (expected %d, got %d)", expectedNumFieldsPerLine, len(fields)) + } + + mp := MountPoint{ + Device: fields[0], + Path: fields[1], + Type: fields[2], + Opts: strings.Split(fields[3], ","), + } + + freq, err := strconv.Atoi(fields[4]) + if err != nil { + return nil, err + } + mp.Freq = freq + + pass, err := strconv.Atoi(fields[5]) + if err != nil { + return nil, err + } + mp.Pass = pass + + out = append(out, mp) + } + return out, nil +} + +// SearchMountPoints finds all mount references to the source, returns a list of +// mountpoints. +// The source can be a mount point or a normal directory (bind mount). We +// didn't support device because there is no use case by now. +// Some filesystems may share a source name, e.g. tmpfs. And for bind mounting, +// it's possible to mount a non-root path of a filesystem, so we need to use +// root path and major:minor to represent mount source uniquely. +// This implementation is shared between Linux and NsEnterMounter +func SearchMountPoints(hostSource, mountInfoPath string) ([]string, error) { + mis, err := ParseMountInfo(mountInfoPath) + if err != nil { + return nil, err + } + + mountID := 0 + rootPath := "" + major := -1 + minor := -1 + + // Finding the underlying root path and major:minor if possible. + // We need search in backward order because it's possible for later mounts + // to overlap earlier mounts. + for i := len(mis) - 1; i >= 0; i-- { + if hostSource == mis[i].MountPoint || PathWithinBase(hostSource, mis[i].MountPoint) { + // If it's a mount point or path under a mount point. + mountID = mis[i].ID + rootPath = filepath.Join(mis[i].Root, strings.TrimPrefix(hostSource, mis[i].MountPoint)) + major = mis[i].Major + minor = mis[i].Minor + break + } + } + + if rootPath == "" || major == -1 || minor == -1 { + return nil, fmt.Errorf("failed to get root path and major:minor for %s", hostSource) + } + + var refs []string + for i := range mis { + if mis[i].ID == mountID { + // Ignore mount entry for mount source itself. + continue + } + if mis[i].Root == rootPath && mis[i].Major == major && mis[i].Minor == minor { + refs = append(refs, mis[i].MountPoint) + } + } + + return refs, nil +} + +// IsMountPoint determines if a file is a mountpoint. +// It first detects bind & any other mountpoints using +// MountedFast function. If the MountedFast function returns +// sure as true and err as nil, then a mountpoint is detected +// successfully. When an error is returned by MountedFast, the +// following is true: +// 1. All errors are returned with IsMountPoint as false +// except os.IsPermission. +// 2. When os.IsPermission is returned by MountedFast, List() +// is called to confirm if the given file is a mountpoint are not. +// +// os.ErrNotExist should always be returned if a file does not exist +// as callers have in past relied on this error and not fallback. +// +// When MountedFast returns sure as false and err as nil (eg: in +// case of bindmounts on kernel version 5.10- ); mounter.List() +// endpoint is called to enumerate all the mountpoints and check if +// it is mountpoint match or not. +func (mounter *Mounter) IsMountPoint(file string) (bool, error) { + isMnt, sure, isMntErr := mountinfo.MountedFast(file) + if sure && isMntErr == nil { + return isMnt, nil + } + if isMntErr != nil { + if errors.Is(isMntErr, fs.ErrNotExist) { + return false, fs.ErrNotExist + } + // We were not allowed to do the simple stat() check, e.g. on NFS with + // root_squash. Fall back to /proc/mounts check below when + // fs.ErrPermission is returned. + if !errors.Is(isMntErr, fs.ErrPermission) { + return false, isMntErr + } + } + // Resolve any symlinks in file, kernel would do the same and use the resolved path in /proc/mounts. + resolvedFile, err := filepath.EvalSymlinks(file) + if err != nil { + if errors.Is(isMntErr, fs.ErrNotExist) { + return false, fs.ErrNotExist + } + return false, err + } + + // check all mountpoints since MountedFast is not sure. + // is not reliable for some mountpoint types. + mountPoints, mountPointsErr := mounter.List() + if mountPointsErr != nil { + return false, mountPointsErr + } + for _, mp := range mountPoints { + if isMountPointMatch(mp, resolvedFile) { + return true, nil + } + } + return false, nil +} + +// tryUnmount calls plain "umount" and waits for unmountTimeout for it to finish. +func tryUnmount(path string, unmountTimeout time.Duration) error { + klog.V(4).Infof("Unmounting %s", path) + ctx, cancel := context.WithTimeout(context.Background(), unmountTimeout) + defer cancel() + + cmd := exec.CommandContext(ctx, "umount", path) + out, cmderr := cmd.CombinedOutput() + + // CombinedOutput() does not return DeadlineExceeded, make sure it's + // propagated on timeout. + if ctx.Err() != nil { + return ctx.Err() + } + + if cmderr != nil { + return fmt.Errorf("unmount failed: %v\nUnmounting arguments: %s\nOutput: %s", cmderr, path, string(out)) + } + return nil +} + +func forceUmount(path string) error { + cmd := exec.Command("umount", "-f", path) + out, cmderr := cmd.CombinedOutput() + + if cmderr != nil { + return fmt.Errorf("unmount failed: %v\nUnmounting arguments: %s\nOutput: %s", cmderr, path, string(out)) + } + return nil +} diff --git a/vendor/k8s.io/mount-utils/mount_unsupported.go b/vendor/k8s.io/mount-utils/mount_unsupported.go new file mode 100644 index 000000000..8e03d643b --- /dev/null +++ b/vendor/k8s.io/mount-utils/mount_unsupported.go @@ -0,0 +1,105 @@ +//go:build !linux && !windows +// +build !linux,!windows + +/* +Copyright 2014 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 mount + +import ( + "errors" +) + +// Mounter implements mount.Interface for unsupported platforms +type Mounter struct { + mounterPath string +} + +var errUnsupported = errors.New("util/mount on this platform is not supported") + +// New returns a mount.Interface for the current system. +// It provides options to override the default mounter behavior. +// mounterPath allows using an alternative to `/bin/mount` for mounting. +func New(mounterPath string) Interface { + return &Mounter{ + mounterPath: mounterPath, + } +} + +// Mount always returns an error on unsupported platforms +func (mounter *Mounter) Mount(source string, target string, fstype string, options []string) error { + return errUnsupported +} + +// MountSensitive always returns an error on unsupported platforms +func (mounter *Mounter) MountSensitive(source string, target string, fstype string, options []string, sensitiveOptions []string) error { + return errUnsupported +} + +// MountSensitiveWithoutSystemd always returns an error on unsupported platforms +func (mounter *Mounter) MountSensitiveWithoutSystemd(source string, target string, fstype string, options []string, sensitiveOptions []string) error { + return errUnsupported +} + +// MountSensitiveWithoutSystemdWithMountFlags always returns an error on unsupported platforms +func (mounter *Mounter) MountSensitiveWithoutSystemdWithMountFlags(source string, target string, fstype string, options []string, sensitiveOptions []string, mountFlags []string) error { + return errUnsupported +} + +// Unmount always returns an error on unsupported platforms +func (mounter *Mounter) Unmount(target string) error { + return errUnsupported +} + +// List always returns an error on unsupported platforms +func (mounter *Mounter) List() ([]MountPoint, error) { + return []MountPoint{}, errUnsupported +} + +// IsLikelyNotMountPoint always returns an error on unsupported platforms +func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) { + return true, errUnsupported +} + +// canSafelySkipMountPointCheck always returns false on unsupported platforms +func (mounter *Mounter) canSafelySkipMountPointCheck() bool { + return false +} + +// IsMountPoint determines if a directory is a mountpoint. +// It always returns an error on unsupported platforms. +func (mounter *Mounter) IsMountPoint(file string) (bool, error) { + return false, errUnsupported +} + +// GetMountRefs always returns an error on unsupported platforms +func (mounter *Mounter) GetMountRefs(pathname string) ([]string, error) { + return nil, errUnsupported +} + +func (mounter *SafeFormatAndMount) formatAndMountSensitive(source string, target string, fstype string, options []string, sensitiveOptions []string, formatOptions []string) error { + return mounter.Interface.Mount(source, target, fstype, options) +} + +func (mounter *SafeFormatAndMount) diskLooksUnformatted(disk string) (bool, error) { + return true, errUnsupported +} + +// IsMountPoint determines if a directory is a mountpoint. +// It always returns an error on unsupported platforms. +func (mounter *SafeFormatAndMount) IsMountPoint(file string) (bool, error) { + return false, errUnsupported +} diff --git a/vendor/k8s.io/mount-utils/mount_windows.go b/vendor/k8s.io/mount-utils/mount_windows.go new file mode 100644 index 000000000..7c7b396e5 --- /dev/null +++ b/vendor/k8s.io/mount-utils/mount_windows.go @@ -0,0 +1,355 @@ +//go:build windows +// +build windows + +/* +Copyright 2017 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 mount + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + + "k8s.io/klog/v2" + "k8s.io/utils/keymutex" +) + +const ( + accessDenied string = "access is denied" +) + +// Mounter provides the default implementation of mount.Interface +// for the windows platform. This implementation assumes that the +// kubelet is running in the host's root mount namespace. +type Mounter struct { + mounterPath string +} + +// New returns a mount.Interface for the current system. +// It provides options to override the default mounter behavior. +// mounterPath allows using an alternative to `/bin/mount` for mounting. +func New(mounterPath string) Interface { + return &Mounter{ + mounterPath: mounterPath, + } +} + +// acquire lock for smb mount +var getSMBMountMutex = keymutex.NewHashed(0) + +// Mount : mounts source to target with given options. +// currently only supports cifs(smb), bind mount(for disk) +func (mounter *Mounter) Mount(source string, target string, fstype string, options []string) error { + return mounter.MountSensitive(source, target, fstype, options, nil /* sensitiveOptions */) +} + +// MountSensitiveWithoutSystemd is the same as MountSensitive() but disable using ssytemd mount. +// Windows not supported systemd mount, this function degrades to MountSensitive(). +func (mounter *Mounter) MountSensitiveWithoutSystemd(source string, target string, fstype string, options []string, sensitiveOptions []string) error { + return mounter.MountSensitive(source, target, fstype, options, sensitiveOptions /* sensitiveOptions */) +} + +// MountSensitiveWithoutSystemdWithMountFlags is the same as MountSensitiveWithoutSystemd with additional mount flags +// Windows not supported systemd mount, this function degrades to MountSensitive(). +func (mounter *Mounter) MountSensitiveWithoutSystemdWithMountFlags(source string, target string, fstype string, options []string, sensitiveOptions []string, mountFlags []string) error { + return mounter.MountSensitive(source, target, fstype, options, sensitiveOptions /* sensitiveOptions */) +} + +// MountSensitive is the same as Mount() but this method allows +// sensitiveOptions to be passed in a separate parameter from the normal +// mount options and ensures the sensitiveOptions are never logged. This +// method should be used by callers that pass sensitive material (like +// passwords) as mount options. +func (mounter *Mounter) MountSensitive(source string, target string, fstype string, options []string, sensitiveOptions []string) error { + target = NormalizeWindowsPath(target) + sanitizedOptionsForLogging := sanitizedOptionsForLogging(options, sensitiveOptions) + + if source == "tmpfs" { + klog.V(3).Infof("mounting source (%q), target (%q), with options (%q)", source, target, sanitizedOptionsForLogging) + return os.MkdirAll(target, 0755) + } + + parentDir := filepath.Dir(target) + if err := os.MkdirAll(parentDir, 0755); err != nil { + return err + } + + klog.V(4).Infof("mount options(%q) source:%q, target:%q, fstype:%q, begin to mount", + sanitizedOptionsForLogging, source, target, fstype) + bindSource := source + + if bind, _, _, _ := MakeBindOptsSensitive(options, sensitiveOptions); bind { + bindSource = NormalizeWindowsPath(source) + } else { + allOptions := []string{} + allOptions = append(allOptions, options...) + allOptions = append(allOptions, sensitiveOptions...) + if len(allOptions) < 2 { + return fmt.Errorf("mount options(%q) should have at least 2 options, current number:%d, source:%q, target:%q", + sanitizedOptionsForLogging, len(allOptions), source, target) + } + + // currently only cifs mount is supported + if strings.ToLower(fstype) != "cifs" { + return fmt.Errorf("only cifs mount is supported now, fstype: %q, mounting source (%q), target (%q), with options (%q)", fstype, source, target, sanitizedOptionsForLogging) + } + + // lock smb mount for the same source + getSMBMountMutex.LockKey(source) + defer getSMBMountMutex.UnlockKey(source) + + username := allOptions[0] + password := allOptions[1] + if output, err := newSMBMapping(username, password, source); err != nil { + klog.Warningf("SMB Mapping(%s) returned with error(%v), output(%s)", source, err, string(output)) + if isSMBMappingExist(source) { + valid, err := isValidPath(source) + if !valid { + if err == nil || isAccessDeniedError(err) { + klog.V(2).Infof("SMB Mapping(%s) already exists while it's not valid, return error: %v, now begin to remove and remount", source, err) + if output, err = removeSMBMapping(source); err != nil { + return fmt.Errorf("Remove-SmbGlobalMapping failed: %v, output: %q", err, output) + } + if output, err := newSMBMapping(username, password, source); err != nil { + return fmt.Errorf("New-SmbGlobalMapping(%s) failed: %v, output: %q", source, err, output) + } + } + } else { + klog.V(2).Infof("SMB Mapping(%s) already exists and is still valid, skip error(%v)", source, err) + } + } else { + return fmt.Errorf("New-SmbGlobalMapping(%s) failed: %v, output: %q", source, err, output) + } + } + } + + // There is an issue in golang where EvalSymlinks fails on Windows when passed a + // UNC share root path without a trailing backslash. + // Ex: \\SERVER\share will fail to resolve but \\SERVER\share\ will resolve + // containerD on Windows calls EvalSymlinks so we'll add the backslash when making the symlink if it is missing. + // https://github.com/golang/go/pull/42096 fixes this issue in golang but a fix will not be available until + // golang v1.16 + mklinkSource := bindSource + if !strings.HasSuffix(mklinkSource, "\\") { + mklinkSource = mklinkSource + "\\" + } + + output, err := exec.Command("cmd", "/c", "mklink", "/D", target, mklinkSource).CombinedOutput() + if err != nil { + klog.Errorf("mklink failed: %v, source(%q) target(%q) output: %q", err, mklinkSource, target, string(output)) + return err + } + klog.V(2).Infof("mklink source(%q) on target(%q) successfully, output: %q", mklinkSource, target, string(output)) + + return nil +} + +// do the SMB mount with username, password, remotepath +// return (output, error) +func newSMBMapping(username, password, remotepath string) (string, error) { + if username == "" || password == "" || remotepath == "" { + return "", fmt.Errorf("invalid parameter(username: %s, password: %s, remoteapth: %s)", username, sensitiveOptionsRemoved, remotepath) + } + + // use PowerShell Environment Variables to store user input string to prevent command line injection + // https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables?view=powershell-5.1 + cmdLine := `$PWord = ConvertTo-SecureString -String $Env:smbpassword -AsPlainText -Force` + + `;$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Env:smbuser, $PWord` + + `;New-SmbGlobalMapping -RemotePath $Env:smbremotepath -Credential $Credential -RequirePrivacy $true` + cmd := exec.Command("powershell", "/c", cmdLine) + cmd.Env = append(os.Environ(), + fmt.Sprintf("smbuser=%s", username), + fmt.Sprintf("smbpassword=%s", password), + fmt.Sprintf("smbremotepath=%s", remotepath)) + + output, err := cmd.CombinedOutput() + return string(output), err +} + +// check whether remotepath is already mounted +func isSMBMappingExist(remotepath string) bool { + cmd := exec.Command("powershell", "/c", `Get-SmbGlobalMapping -RemotePath $Env:smbremotepath`) + cmd.Env = append(os.Environ(), fmt.Sprintf("smbremotepath=%s", remotepath)) + _, err := cmd.CombinedOutput() + return err == nil +} + +// check whether remotepath is valid +// return (true, nil) if remotepath is valid +func isValidPath(remotepath string) (bool, error) { + cmd := exec.Command("powershell", "/c", `Test-Path $Env:remoteapth`) + cmd.Env = append(os.Environ(), fmt.Sprintf("remoteapth=%s", remotepath)) + output, err := cmd.CombinedOutput() + if err != nil { + return false, fmt.Errorf("returned output: %s, error: %v", string(output), err) + } + + return strings.HasPrefix(strings.ToLower(string(output)), "true"), nil +} + +func isAccessDeniedError(err error) bool { + return err != nil && strings.Contains(strings.ToLower(err.Error()), accessDenied) +} + +// remove SMB mapping +func removeSMBMapping(remotepath string) (string, error) { + cmd := exec.Command("powershell", "/c", `Remove-SmbGlobalMapping -RemotePath $Env:smbremotepath -Force`) + cmd.Env = append(os.Environ(), fmt.Sprintf("smbremotepath=%s", remotepath)) + output, err := cmd.CombinedOutput() + return string(output), err +} + +// Unmount unmounts the target. +func (mounter *Mounter) Unmount(target string) error { + klog.V(4).Infof("Unmount target (%q)", target) + target = NormalizeWindowsPath(target) + if output, err := exec.Command("cmd", "/c", "rmdir", target).CombinedOutput(); err != nil { + klog.Errorf("rmdir failed: %v, output: %q", err, string(output)) + return err + } + return nil +} + +// List returns a list of all mounted filesystems. todo +func (mounter *Mounter) List() ([]MountPoint, error) { + return []MountPoint{}, nil +} + +// IsLikelyNotMountPoint determines if a directory is not a mountpoint. +func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) { + stat, err := os.Lstat(file) + if err != nil { + return true, err + } + + if stat.Mode()&os.ModeSymlink != 0 { + return false, err + } + return true, nil +} + +// canSafelySkipMountPointCheck always returns false on Windows +func (mounter *Mounter) canSafelySkipMountPointCheck() bool { + return false +} + +// IsMountPoint: determines if a directory is a mountpoint. +func (mounter *Mounter) IsMountPoint(file string) (bool, error) { + isNotMnt, err := mounter.IsLikelyNotMountPoint(file) + if err != nil { + return false, err + } + return !isNotMnt, nil +} + +// GetMountRefs : empty implementation here since there is no place to query all mount points on Windows +func (mounter *Mounter) GetMountRefs(pathname string) ([]string, error) { + windowsPath := NormalizeWindowsPath(pathname) + pathExists, pathErr := PathExists(windowsPath) + if !pathExists { + return []string{}, nil + } else if IsCorruptedMnt(pathErr) { + klog.Warningf("GetMountRefs found corrupted mount at %s, treating as unmounted path", windowsPath) + return []string{}, nil + } else if pathErr != nil { + return nil, fmt.Errorf("error checking path %s: %v", windowsPath, pathErr) + } + return []string{pathname}, nil +} + +func (mounter *SafeFormatAndMount) formatAndMountSensitive(source string, target string, fstype string, options []string, sensitiveOptions []string, formatOptions []string) error { + // Try to mount the disk + klog.V(4).Infof("Attempting to formatAndMount disk: %s %s %s", fstype, source, target) + + if err := ValidateDiskNumber(source); err != nil { + klog.Errorf("diskMount: formatAndMount failed, err: %v", err) + return err + } + + if len(fstype) == 0 { + // Use 'NTFS' as the default + fstype = "NTFS" + } + + // format disk if it is unformatted(raw) + formatOptionsUnwrapped := "" + if len(formatOptions) > 0 { + formatOptionsUnwrapped = " " + strings.Join(formatOptions, " ") + } + cmd := fmt.Sprintf("Get-Disk -Number %s | Where partitionstyle -eq 'raw' | Initialize-Disk -PartitionStyle GPT -PassThru"+ + " | New-Partition -UseMaximumSize | Format-Volume -FileSystem %s -Confirm:$false%s", source, fstype, formatOptionsUnwrapped) + if output, err := mounter.Exec.Command("powershell", "/c", cmd).CombinedOutput(); err != nil { + return fmt.Errorf("diskMount: format disk failed, error: %v, output: %q", err, string(output)) + } + klog.V(4).Infof("diskMount: Disk successfully formatted, disk: %q, fstype: %q", source, fstype) + + volumeIds, err := listVolumesOnDisk(source) + if err != nil { + return err + } + driverPath := volumeIds[0] + target = NormalizeWindowsPath(target) + output, err := mounter.Exec.Command("cmd", "/c", "mklink", "/D", target, driverPath).CombinedOutput() + if err != nil { + klog.Errorf("mklink(%s, %s) failed: %v, output: %q", target, driverPath, err, string(output)) + return err + } + klog.V(2).Infof("formatAndMount disk(%s) fstype(%s) on(%s) with output(%s) successfully", driverPath, fstype, target, string(output)) + return nil +} + +// ListVolumesOnDisk - returns back list of volumes(volumeIDs) in the disk (requested in diskID). +func listVolumesOnDisk(diskID string) (volumeIDs []string, err error) { + cmd := fmt.Sprintf("(Get-Disk -DeviceId %s | Get-Partition | Get-Volume).UniqueId", diskID) + output, err := exec.Command("powershell", "/c", cmd).CombinedOutput() + klog.V(4).Infof("listVolumesOnDisk id from %s: %s", diskID, string(output)) + if err != nil { + return []string{}, fmt.Errorf("error list volumes on disk. cmd: %s, output: %s, error: %v", cmd, string(output), err) + } + + volumeIds := strings.Split(strings.TrimSpace(string(output)), "\r\n") + return volumeIds, nil +} + +// getAllParentLinks walks all symbolic links and return all the parent targets recursively +func getAllParentLinks(path string) ([]string, error) { + const maxIter = 255 + links := []string{} + for { + links = append(links, path) + if len(links) > maxIter { + return links, fmt.Errorf("unexpected length of parent links: %v", links) + } + + fi, err := os.Lstat(path) + if err != nil { + return links, fmt.Errorf("Lstat: %v", err) + } + if fi.Mode()&os.ModeSymlink == 0 { + break + } + + path, err = os.Readlink(path) + if err != nil { + return links, fmt.Errorf("Readlink error: %v", err) + } + } + + return links, nil +} diff --git a/vendor/k8s.io/mount-utils/resizefs_linux.go b/vendor/k8s.io/mount-utils/resizefs_linux.go new file mode 100644 index 000000000..929d061e5 --- /dev/null +++ b/vendor/k8s.io/mount-utils/resizefs_linux.go @@ -0,0 +1,266 @@ +//go:build linux +// +build linux + +/* +Copyright 2021 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 mount + +import ( + "fmt" + "strconv" + "strings" + + "k8s.io/klog/v2" + utilexec "k8s.io/utils/exec" +) + +// ResizeFs Provides support for resizing file systems +type ResizeFs struct { + exec utilexec.Interface +} + +// NewResizeFs returns new instance of resizer +func NewResizeFs(exec utilexec.Interface) *ResizeFs { + return &ResizeFs{exec: exec} +} + +// Resize perform resize of file system +func (resizefs *ResizeFs) Resize(devicePath string, deviceMountPath string) (bool, error) { + format, err := getDiskFormat(resizefs.exec, devicePath) + + if err != nil { + formatErr := fmt.Errorf("ResizeFS.Resize - error checking format for device %s: %v", devicePath, err) + return false, formatErr + } + + // If disk has no format, there is no need to resize the disk because mkfs.* + // by default will use whole disk anyways. + if format == "" { + return false, nil + } + + klog.V(3).Infof("ResizeFS.Resize - Expanding mounted volume %s", devicePath) + switch format { + case "ext3", "ext4": + return resizefs.extResize(devicePath) + case "xfs": + return resizefs.xfsResize(deviceMountPath) + case "btrfs": + return resizefs.btrfsResize(deviceMountPath) + } + return false, fmt.Errorf("ResizeFS.Resize - resize of format %s is not supported for device %s mounted at %s", format, devicePath, deviceMountPath) +} + +func (resizefs *ResizeFs) extResize(devicePath string) (bool, error) { + output, err := resizefs.exec.Command("resize2fs", devicePath).CombinedOutput() + if err == nil { + klog.V(2).Infof("Device %s resized successfully", devicePath) + return true, nil + } + + resizeError := fmt.Errorf("resize of device %s failed: %v. resize2fs output: %s", devicePath, err, string(output)) + return false, resizeError + +} + +func (resizefs *ResizeFs) xfsResize(deviceMountPath string) (bool, error) { + args := []string{"-d", deviceMountPath} + output, err := resizefs.exec.Command("xfs_growfs", args...).CombinedOutput() + + if err == nil { + klog.V(2).Infof("Device %s resized successfully", deviceMountPath) + return true, nil + } + + resizeError := fmt.Errorf("resize of device %s failed: %v. xfs_growfs output: %s", deviceMountPath, err, string(output)) + return false, resizeError +} + +func (resizefs *ResizeFs) btrfsResize(deviceMountPath string) (bool, error) { + args := []string{"filesystem", "resize", "max", deviceMountPath} + output, err := resizefs.exec.Command("btrfs", args...).CombinedOutput() + + if err == nil { + klog.V(2).Infof("Device %s resized successfully", deviceMountPath) + return true, nil + } + + resizeError := fmt.Errorf("resize of device %s failed: %v. btrfs output: %s", deviceMountPath, err, string(output)) + return false, resizeError +} + +func (resizefs *ResizeFs) NeedResize(devicePath string, deviceMountPath string) (bool, error) { + deviceSize, err := resizefs.getDeviceSize(devicePath) + if err != nil { + return false, err + } + var fsSize, blockSize uint64 + format, err := getDiskFormat(resizefs.exec, devicePath) + if err != nil { + formatErr := fmt.Errorf("ResizeFS.Resize - error checking format for device %s: %v", devicePath, err) + return false, formatErr + } + + // If disk has no format, there is no need to resize the disk because mkfs.* + // by default will use whole disk anyways. + if format == "" { + return false, nil + } + + klog.V(3).Infof("ResizeFs.needResize - checking mounted volume %s", devicePath) + switch format { + case "ext3", "ext4": + blockSize, fsSize, err = resizefs.getExtSize(devicePath) + klog.V(5).Infof("Ext size: filesystem size=%d, block size=%d", fsSize, blockSize) + case "xfs": + blockSize, fsSize, err = resizefs.getXFSSize(deviceMountPath) + klog.V(5).Infof("Xfs size: filesystem size=%d, block size=%d, err=%v", fsSize, blockSize, err) + case "btrfs": + blockSize, fsSize, err = resizefs.getBtrfsSize(devicePath) + klog.V(5).Infof("Btrfs size: filesystem size=%d, block size=%d, err=%v", fsSize, blockSize, err) + default: + klog.Errorf("Not able to parse given filesystem info. fsType: %s, will not resize", format) + return false, fmt.Errorf("Could not parse fs info on given filesystem format: %s. Supported fs types are: xfs, ext3, ext4", format) + } + if err != nil { + return false, err + } + // Tolerate one block difference, just in case of rounding errors somewhere. + klog.V(5).Infof("Volume %s: device size=%d, filesystem size=%d, block size=%d", devicePath, deviceSize, fsSize, blockSize) + if deviceSize <= fsSize+blockSize { + return false, nil + } + return true, nil +} +func (resizefs *ResizeFs) getDeviceSize(devicePath string) (uint64, error) { + output, err := resizefs.exec.Command("blockdev", "--getsize64", devicePath).CombinedOutput() + outStr := strings.TrimSpace(string(output)) + if err != nil { + return 0, fmt.Errorf("failed to read size of device %s: %s: %s", devicePath, err, outStr) + } + size, err := strconv.ParseUint(outStr, 10, 64) + if err != nil { + return 0, fmt.Errorf("failed to parse size of device %s %s: %s", devicePath, outStr, err) + } + return size, nil +} + +func (resizefs *ResizeFs) getExtSize(devicePath string) (uint64, uint64, error) { + output, err := resizefs.exec.Command("dumpe2fs", "-h", devicePath).CombinedOutput() + if err != nil { + return 0, 0, fmt.Errorf("failed to read size of filesystem on %s: %s: %s", devicePath, err, string(output)) + } + + blockSize, blockCount, _ := resizefs.parseFsInfoOutput(string(output), ":", "block size", "block count") + + if blockSize == 0 { + return 0, 0, fmt.Errorf("could not find block size of device %s", devicePath) + } + if blockCount == 0 { + return 0, 0, fmt.Errorf("could not find block count of device %s", devicePath) + } + return blockSize, blockSize * blockCount, nil +} + +func (resizefs *ResizeFs) getXFSSize(devicePath string) (uint64, uint64, error) { + output, err := resizefs.exec.Command("xfs_io", "-c", "statfs", devicePath).CombinedOutput() + if err != nil { + return 0, 0, fmt.Errorf("failed to read size of filesystem on %s: %s: %s", devicePath, err, string(output)) + } + + blockSize, blockCount, _ := resizefs.parseFsInfoOutput(string(output), "=", "geom.bsize", "geom.datablocks") + + if blockSize == 0 { + return 0, 0, fmt.Errorf("could not find block size of device %s", devicePath) + } + if blockCount == 0 { + return 0, 0, fmt.Errorf("could not find block count of device %s", devicePath) + } + return blockSize, blockSize * blockCount, nil +} + +func (resizefs *ResizeFs) getBtrfsSize(devicePath string) (uint64, uint64, error) { + output, err := resizefs.exec.Command("btrfs", "inspect-internal", "dump-super", "-f", devicePath).CombinedOutput() + if err != nil { + return 0, 0, fmt.Errorf("failed to read size of filesystem on %s: %s: %s", devicePath, err, string(output)) + } + + blockSize, totalBytes, _ := resizefs.parseBtrfsInfoOutput(string(output), "sectorsize", "total_bytes") + + if blockSize == 0 { + return 0, 0, fmt.Errorf("could not find block size of device %s", devicePath) + } + if totalBytes == 0 { + return 0, 0, fmt.Errorf("could not find total size of device %s", devicePath) + } + return blockSize, totalBytes, nil +} + +func (resizefs *ResizeFs) parseBtrfsInfoOutput(cmdOutput string, blockSizeKey string, totalBytesKey string) (uint64, uint64, error) { + lines := strings.Split(cmdOutput, "\n") + var blockSize, blockCount uint64 + var err error + + for _, line := range lines { + tokens := strings.Fields(line) + if len(tokens) != 2 { + continue + } + key, value := strings.ToLower(strings.TrimSpace(tokens[0])), strings.ToLower(strings.TrimSpace(tokens[1])) + + if key == blockSizeKey { + blockSize, err = strconv.ParseUint(value, 10, 64) + if err != nil { + return 0, 0, fmt.Errorf("failed to parse block size %s: %s", value, err) + } + } + if key == totalBytesKey { + blockCount, err = strconv.ParseUint(value, 10, 64) + if err != nil { + return 0, 0, fmt.Errorf("failed to parse total size %s: %s", value, err) + } + } + } + return blockSize, blockCount, err +} + +func (resizefs *ResizeFs) parseFsInfoOutput(cmdOutput string, spliter string, blockSizeKey string, blockCountKey string) (uint64, uint64, error) { + lines := strings.Split(cmdOutput, "\n") + var blockSize, blockCount uint64 + var err error + + for _, line := range lines { + tokens := strings.Split(line, spliter) + if len(tokens) != 2 { + continue + } + key, value := strings.ToLower(strings.TrimSpace(tokens[0])), strings.ToLower(strings.TrimSpace(tokens[1])) + if key == blockSizeKey { + blockSize, err = strconv.ParseUint(value, 10, 64) + if err != nil { + return 0, 0, fmt.Errorf("failed to parse block size %s: %s", value, err) + } + } + if key == blockCountKey { + blockCount, err = strconv.ParseUint(value, 10, 64) + if err != nil { + return 0, 0, fmt.Errorf("failed to parse block count %s: %s", value, err) + } + } + } + return blockSize, blockCount, err +} diff --git a/vendor/k8s.io/mount-utils/resizefs_unsupported.go b/vendor/k8s.io/mount-utils/resizefs_unsupported.go new file mode 100644 index 000000000..88b8b2410 --- /dev/null +++ b/vendor/k8s.io/mount-utils/resizefs_unsupported.go @@ -0,0 +1,46 @@ +//go:build !linux +// +build !linux + +/* +Copyright 2021 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 mount + +import ( + "fmt" + + utilexec "k8s.io/utils/exec" +) + +// ResizeFs Provides support for resizing file systems +type ResizeFs struct { + exec utilexec.Interface +} + +// NewResizeFs returns new instance of resizer +func NewResizeFs(exec utilexec.Interface) *ResizeFs { + return &ResizeFs{exec: exec} +} + +// Resize perform resize of file system +func (resizefs *ResizeFs) Resize(devicePath string, deviceMountPath string) (bool, error) { + return false, fmt.Errorf("Resize is not supported for this build") +} + +// NeedResize check whether mounted volume needs resize +func (resizefs *ResizeFs) NeedResize(devicePath string, deviceMountPath string) (bool, error) { + return false, fmt.Errorf("NeedResize is not supported for this build") +} diff --git a/vendor/k8s.io/utils/io/README.md b/vendor/k8s.io/utils/io/README.md new file mode 100644 index 000000000..aa4cc4104 --- /dev/null +++ b/vendor/k8s.io/utils/io/README.md @@ -0,0 +1,4 @@ +# IO + +This package provides interfaces for working with file IO. Currently it +provides functionality for consistently reading a file. diff --git a/vendor/k8s.io/utils/io/read.go b/vendor/k8s.io/utils/io/read.go new file mode 100644 index 000000000..f0af3c8ec --- /dev/null +++ b/vendor/k8s.io/utils/io/read.go @@ -0,0 +1,98 @@ +/* +Copyright 2017 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 io + +import ( + "bytes" + "errors" + "fmt" + "io" + "io/ioutil" +) + +// ErrLimitReached means that the read limit is reached. +var ErrLimitReached = errors.New("the read limit is reached") + +// ConsistentRead repeatedly reads a file until it gets the same content twice. +// This is useful when reading files in /proc that are larger than page size +// and kernel may modify them between individual read() syscalls. +// It returns InconsistentReadError when it cannot get a consistent read in +// given nr. of attempts. Caller should retry, kernel is probably under heavy +// mount/unmount load. +func ConsistentRead(filename string, attempts int) ([]byte, error) { + return consistentReadSync(filename, attempts, nil) +} + +// consistentReadSync is the main functionality of ConsistentRead but +// introduces a sync callback that can be used by the tests to mutate the file +// from which the test data is being read +func consistentReadSync(filename string, attempts int, sync func(int)) ([]byte, error) { + oldContent, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + for i := 0; i < attempts; i++ { + if sync != nil { + sync(i) + } + newContent, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + if bytes.Compare(oldContent, newContent) == 0 { + return newContent, nil + } + // Files are different, continue reading + oldContent = newContent + } + return nil, InconsistentReadError{filename, attempts} +} + +// InconsistentReadError is returned from ConsistentRead when it cannot get +// a consistent read in given nr. of attempts. Caller should retry, kernel is +// probably under heavy mount/unmount load. +type InconsistentReadError struct { + filename string + attempts int +} + +func (i InconsistentReadError) Error() string { + return fmt.Sprintf("could not get consistent content of %s after %d attempts", i.filename, i.attempts) +} + +var _ error = InconsistentReadError{} + +func IsInconsistentReadError(err error) bool { + if _, ok := err.(InconsistentReadError); ok { + return true + } + return false +} + +// ReadAtMost reads up to `limit` bytes from `r`, and reports an error +// when `limit` bytes are read. +func ReadAtMost(r io.Reader, limit int64) ([]byte, error) { + limitedReader := &io.LimitedReader{R: r, N: limit} + data, err := ioutil.ReadAll(limitedReader) + if err != nil { + return data, err + } + if limitedReader.N <= 0 { + return data, ErrLimitReached + } + return data, nil +} diff --git a/vendor/k8s.io/utils/keymutex/hashed.go b/vendor/k8s.io/utils/keymutex/hashed.go new file mode 100644 index 000000000..4ddb00867 --- /dev/null +++ b/vendor/k8s.io/utils/keymutex/hashed.go @@ -0,0 +1,58 @@ +/* +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 keymutex + +import ( + "hash/fnv" + "runtime" + "sync" +) + +// NewHashed returns a new instance of KeyMutex which hashes arbitrary keys to +// a fixed set of locks. `n` specifies number of locks, if n <= 0, we use +// number of cpus. +// Note that because it uses fixed set of locks, different keys may share same +// lock, so it's possible to wait on same lock. +func NewHashed(n int) KeyMutex { + if n <= 0 { + n = runtime.NumCPU() + } + return &hashedKeyMutex{ + mutexes: make([]sync.Mutex, n), + } +} + +type hashedKeyMutex struct { + mutexes []sync.Mutex +} + +// Acquires a lock associated with the specified ID. +func (km *hashedKeyMutex) LockKey(id string) { + km.mutexes[km.hash(id)%uint32(len(km.mutexes))].Lock() +} + +// Releases the lock associated with the specified ID. +func (km *hashedKeyMutex) UnlockKey(id string) error { + km.mutexes[km.hash(id)%uint32(len(km.mutexes))].Unlock() + return nil +} + +func (km *hashedKeyMutex) hash(id string) uint32 { + h := fnv.New32a() + h.Write([]byte(id)) + return h.Sum32() +} diff --git a/vendor/k8s.io/utils/keymutex/keymutex.go b/vendor/k8s.io/utils/keymutex/keymutex.go new file mode 100644 index 000000000..89dc02239 --- /dev/null +++ b/vendor/k8s.io/utils/keymutex/keymutex.go @@ -0,0 +1,27 @@ +/* +Copyright 2015 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 keymutex + +// KeyMutex is a thread-safe interface for acquiring locks on arbitrary strings. +type KeyMutex interface { + // Acquires a lock associated with the specified ID, creates the lock if one doesn't already exist. + LockKey(id string) + + // Releases the lock associated with the specified ID. + // Returns an error if the specified ID doesn't exist. + UnlockKey(id string) error +} diff --git a/vendor/k8s.io/utils/nsenter/OWNERS b/vendor/k8s.io/utils/nsenter/OWNERS new file mode 100644 index 000000000..46895cbda --- /dev/null +++ b/vendor/k8s.io/utils/nsenter/OWNERS @@ -0,0 +1,10 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +reviewers: + - jsafrane + - msau42 + - cofyc +approvers: + - jsafrane + - msau42 + - cofyc diff --git a/vendor/k8s.io/utils/nsenter/README.md b/vendor/k8s.io/utils/nsenter/README.md new file mode 100644 index 000000000..aaacf8e3d --- /dev/null +++ b/vendor/k8s.io/utils/nsenter/README.md @@ -0,0 +1,4 @@ +# NSEnter + +This package provides interfaces for executing and interacting with processes +running within a namespace. diff --git a/vendor/k8s.io/utils/nsenter/nsenter.go b/vendor/k8s.io/utils/nsenter/nsenter.go new file mode 100644 index 000000000..237b636bc --- /dev/null +++ b/vendor/k8s.io/utils/nsenter/nsenter.go @@ -0,0 +1,259 @@ +//go:build linux +// +build linux + +/* +Copyright 2017 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 nsenter + +import ( + "context" + "errors" + "fmt" + "os" + "path/filepath" + "strings" + + "k8s.io/klog/v2" + "k8s.io/utils/exec" +) + +const ( + // DefaultHostRootFsPath is path to host's filesystem mounted into container + // with kubelet. + DefaultHostRootFsPath = "/rootfs" + // mountNsPath is the default mount namespace of the host + mountNsPath = "/proc/1/ns/mnt" + // nsenterPath is the default nsenter command + nsenterPath = "nsenter" +) + +// Nsenter is a type alias for backward compatibility +type Nsenter = NSEnter + +// NSEnter is part of experimental support for running the kubelet +// in a container. +// +// NSEnter requires: +// +// 1. Docker >= 1.6 due to the dependency on the slave propagation mode +// of the bind-mount of the kubelet root directory in the container. +// Docker 1.5 used a private propagation mode for bind-mounts, so mounts +// performed in the host's mount namespace do not propagate out to the +// bind-mount in this docker version. +// 2. The host's root filesystem must be available at /rootfs +// 3. The nsenter binary must be on the Kubelet process' PATH in the container's +// filesystem. +// 4. The Kubelet process must have CAP_SYS_ADMIN (required by nsenter); at +// the present, this effectively means that the kubelet is running in a +// privileged container. +// 5. The volume path used by the Kubelet must be the same inside and outside +// the container and be writable by the container (to initialize volume) +// contents. TODO: remove this requirement. +// 6. The host image must have "mount", "findmnt", "umount", "stat", "touch", +// "mkdir", "ls", "sh" and "chmod" binaries in /bin, /usr/sbin, or /usr/bin +// 7. The host image should have systemd-run in /bin, /usr/sbin, or /usr/bin if +// systemd is installed/enabled in the operating system. +// For more information about mount propagation modes, see: +// https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt +type NSEnter struct { + // a map of commands to their paths on the host filesystem + paths map[string]string + + // Path to the host filesystem, typically "/rootfs". Used only for testing. + hostRootFsPath string + + // Exec implementation + executor exec.Interface +} + +// NewNsenter constructs a new instance of NSEnter +func NewNsenter(hostRootFsPath string, executor exec.Interface) (*NSEnter, error) { + ne := &NSEnter{ + hostRootFsPath: hostRootFsPath, + executor: executor, + } + if err := ne.initPaths(); err != nil { + return nil, err + } + return ne, nil +} + +func (ne *NSEnter) initPaths() error { + ne.paths = map[string]string{} + binaries := []string{ + "mount", + "findmnt", + "umount", + "systemd-run", + "stat", + "touch", + "mkdir", + "sh", + "chmod", + "realpath", + } + // search for the required commands in other locations besides /usr/bin + for _, binary := range binaries { + // check for binary under the following directories + for _, path := range []string{"/", "/bin", "/usr/sbin", "/usr/bin"} { + binPath := filepath.Join(path, binary) + if _, err := os.Stat(filepath.Join(ne.hostRootFsPath, binPath)); err != nil { + continue + } + ne.paths[binary] = binPath + break + } + // systemd-run is optional, bailout if we don't find any of the other binaries + if ne.paths[binary] == "" && binary != "systemd-run" { + return fmt.Errorf("unable to find %v", binary) + } + } + return nil +} + +// Exec executes nsenter commands in hostProcMountNsPath mount namespace +func (ne *NSEnter) Exec(cmd string, args []string) exec.Cmd { + hostProcMountNsPath := filepath.Join(ne.hostRootFsPath, mountNsPath) + fullArgs := append([]string{fmt.Sprintf("--mount=%s", hostProcMountNsPath), "--"}, + append([]string{ne.AbsHostPath(cmd)}, args...)...) + klog.V(5).Infof("Running nsenter command: %v %v", nsenterPath, fullArgs) + return ne.executor.Command(nsenterPath, fullArgs...) +} + +// Command returns a command wrapped with nsenter +func (ne *NSEnter) Command(cmd string, args ...string) exec.Cmd { + return ne.Exec(cmd, args) +} + +// CommandContext returns a CommandContext wrapped with nsenter +func (ne *NSEnter) CommandContext(ctx context.Context, cmd string, args ...string) exec.Cmd { + hostProcMountNsPath := filepath.Join(ne.hostRootFsPath, mountNsPath) + fullArgs := append([]string{fmt.Sprintf("--mount=%s", hostProcMountNsPath), "--"}, + append([]string{ne.AbsHostPath(cmd)}, args...)...) + klog.V(5).Infof("Running nsenter command: %v %v", nsenterPath, fullArgs) + return ne.executor.CommandContext(ctx, nsenterPath, fullArgs...) +} + +// LookPath returns a LookPath wrapped with nsenter +func (ne *NSEnter) LookPath(file string) (string, error) { + return "", fmt.Errorf("not implemented, error looking up : %s", file) +} + +// AbsHostPath returns the absolute runnable path for a specified command +func (ne *NSEnter) AbsHostPath(command string) string { + path, ok := ne.paths[command] + if !ok { + return command + } + return path +} + +// SupportsSystemd checks whether command systemd-run exists +func (ne *NSEnter) SupportsSystemd() (string, bool) { + systemdRunPath, ok := ne.paths["systemd-run"] + return systemdRunPath, ok && systemdRunPath != "" +} + +// EvalSymlinks returns the path name on the host after evaluating symlinks on the +// host. +// mustExist makes EvalSymlinks to return error when the path does not +// exist. When it's false, it evaluates symlinks of the existing part and +// blindly adds the non-existing part: +// pathname: /mnt/volume/non/existing/directory +// /mnt/volume exists +// non/existing/directory does not exist +// -> It resolves symlinks in /mnt/volume to say /mnt/foo and returns +// /mnt/foo/non/existing/directory. +// +// BEWARE! EvalSymlinks is not able to detect symlink looks with mustExist=false! +// If /tmp/link is symlink to /tmp/link, EvalSymlinks(/tmp/link/foo) returns /tmp/link/foo. +func (ne *NSEnter) EvalSymlinks(pathname string, mustExist bool) (string, error) { + var args []string + if mustExist { + // "realpath -e: all components of the path must exist" + args = []string{"-e", pathname} + } else { + // "realpath -m: no path components need exist or be a directory" + args = []string{"-m", pathname} + } + outBytes, err := ne.Exec("realpath", args).CombinedOutput() + if err != nil { + klog.Infof("failed to resolve symbolic links on %s: %v", pathname, err) + return "", err + } + return strings.TrimSpace(string(outBytes)), nil +} + +// KubeletPath returns the path name that can be accessed by containerized +// kubelet. It is recommended to resolve symlinks on the host by EvalSymlinks +// before calling this function +func (ne *NSEnter) KubeletPath(pathname string) string { + return filepath.Join(ne.hostRootFsPath, pathname) +} + +// NewFakeNsenter returns a NSEnter that does not run "nsenter --mount=... --", +// but runs everything in the same mount namespace as the unit test binary. +// rootfsPath is supposed to be a symlink, e.g. /tmp/xyz/rootfs -> /. +// This fake NSEnter is enough for most operations, e.g. to resolve symlinks, +// but it's not enough to call /bin/mount - unit tests don't run as root. +func NewFakeNsenter(rootfsPath string) (*NSEnter, error) { + executor := &fakeExec{ + rootfsPath: rootfsPath, + } + // prepare /rootfs/bin, usr/bin and usr/sbin + bin := filepath.Join(rootfsPath, "bin") + if err := os.Symlink("/bin", bin); err != nil { + return nil, err + } + + usr := filepath.Join(rootfsPath, "usr") + if err := os.Mkdir(usr, 0755); err != nil { + return nil, err + } + usrbin := filepath.Join(usr, "bin") + if err := os.Symlink("/usr/bin", usrbin); err != nil { + return nil, err + } + usrsbin := filepath.Join(usr, "sbin") + if err := os.Symlink("/usr/sbin", usrsbin); err != nil { + return nil, err + } + + return NewNsenter(rootfsPath, executor) +} + +type fakeExec struct { + rootfsPath string +} + +func (f fakeExec) Command(cmd string, args ...string) exec.Cmd { + // This will intentionaly panic if NSEnter does not provide enough arguments. + realCmd := args[2] + realArgs := args[3:] + return exec.New().Command(realCmd, realArgs...) +} + +func (fakeExec) LookPath(file string) (string, error) { + return "", errors.New("not implemented") +} + +func (fakeExec) CommandContext(ctx context.Context, cmd string, args ...string) exec.Cmd { + return nil +} + +var _ exec.Interface = fakeExec{} +var _ exec.Interface = &NSEnter{} diff --git a/vendor/k8s.io/utils/nsenter/nsenter_unsupported.go b/vendor/k8s.io/utils/nsenter/nsenter_unsupported.go new file mode 100644 index 000000000..8b56e91d2 --- /dev/null +++ b/vendor/k8s.io/utils/nsenter/nsenter_unsupported.go @@ -0,0 +1,80 @@ +//go:build !linux +// +build !linux + +/* +Copyright 2017 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 nsenter + +import ( + "context" + "fmt" + + "k8s.io/utils/exec" +) + +const ( + // DefaultHostRootFsPath is path to host's filesystem mounted into container + // with kubelet. + DefaultHostRootFsPath = "/rootfs" +) + +// Nsenter is a type alias for backward compatibility +type Nsenter = NSEnter + +// NSEnter is part of experimental support for running the kubelet +// in a container. +type NSEnter struct { + // a map of commands to their paths on the host filesystem + Paths map[string]string +} + +// NewNsenter constructs a new instance of NSEnter +func NewNsenter(hostRootFsPath string, executor exec.Interface) (*Nsenter, error) { + return &Nsenter{}, nil +} + +// Exec executes nsenter commands in hostProcMountNsPath mount namespace +func (ne *NSEnter) Exec(cmd string, args []string) exec.Cmd { + return nil +} + +// AbsHostPath returns the absolute runnable path for a specified command +func (ne *NSEnter) AbsHostPath(command string) string { + return "" +} + +// SupportsSystemd checks whether command systemd-run exists +func (ne *NSEnter) SupportsSystemd() (string, bool) { + return "", false +} + +// Command returns a command wrapped with nenter +func (ne *NSEnter) Command(cmd string, args ...string) exec.Cmd { + return nil +} + +// CommandContext returns a CommandContext wrapped with nsenter +func (ne *NSEnter) CommandContext(ctx context.Context, cmd string, args ...string) exec.Cmd { + return nil +} + +// LookPath returns a LookPath wrapped with nsenter +func (ne *NSEnter) LookPath(file string) (string, error) { + return "", fmt.Errorf("not implemented, error looking up : %s", file) +} + +var _ exec.Interface = &NSEnter{} diff --git a/vendor/k8s.io/utils/strings/escape.go b/vendor/k8s.io/utils/strings/escape.go new file mode 100644 index 000000000..bae8d81a1 --- /dev/null +++ b/vendor/k8s.io/utils/strings/escape.go @@ -0,0 +1,36 @@ +/* +Copyright 2014 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 strings + +import ( + "strings" +) + +// EscapeQualifiedName converts a plugin name, which might contain a / into a +// string that is safe to use on-disk. This assumes that the input has already +// been validates as a qualified name. we use "~" rather than ":" here in case +// we ever use a filesystem that doesn't allow ":". +func EscapeQualifiedName(in string) string { + return strings.Replace(in, "/", "~", -1) +} + +// UnescapeQualifiedName converts an escaped plugin name (as per EscapeQualifiedName) +// back to its normal form. This assumes that the input has already been +// validates as a qualified name. +func UnescapeQualifiedName(in string) string { + return strings.Replace(in, "~", "/", -1) +} diff --git a/vendor/k8s.io/utils/strings/line_delimiter.go b/vendor/k8s.io/utils/strings/line_delimiter.go new file mode 100644 index 000000000..8907869c9 --- /dev/null +++ b/vendor/k8s.io/utils/strings/line_delimiter.go @@ -0,0 +1,64 @@ +/* +Copyright 2015 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 strings + +import ( + "bytes" + "io" + "strings" +) + +// LineDelimiter is a filter that will split input on lines +// and bracket each line with the delimiter string. +type LineDelimiter struct { + output io.Writer + delimiter []byte + buf bytes.Buffer +} + +// NewLineDelimiter allocates a new io.Writer that will split input on lines +// and bracket each line with the delimiter string. This can be useful in +// output tests where it is difficult to see and test trailing whitespace. +func NewLineDelimiter(output io.Writer, delimiter string) *LineDelimiter { + return &LineDelimiter{output: output, delimiter: []byte(delimiter)} +} + +// Write writes buf to the LineDelimiter ld. The only errors returned are ones +// encountered while writing to the underlying output stream. +func (ld *LineDelimiter) Write(buf []byte) (n int, err error) { + return ld.buf.Write(buf) +} + +// Flush all lines up until now. This will assume insert a linebreak at the current point of the stream. +func (ld *LineDelimiter) Flush() (err error) { + lines := strings.Split(ld.buf.String(), "\n") + for _, line := range lines { + if _, err = ld.output.Write(ld.delimiter); err != nil { + return + } + if _, err = ld.output.Write([]byte(line)); err != nil { + return + } + if _, err = ld.output.Write(ld.delimiter); err != nil { + return + } + if _, err = ld.output.Write([]byte("\n")); err != nil { + return + } + } + return +} diff --git a/vendor/k8s.io/utils/strings/strings.go b/vendor/k8s.io/utils/strings/strings.go new file mode 100644 index 000000000..8a9f2eced --- /dev/null +++ b/vendor/k8s.io/utils/strings/strings.go @@ -0,0 +1,46 @@ +/* +Copyright 2014 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 strings + +import ( + "path" + "strings" +) + +// SplitQualifiedName Splits a fully qualified name and returns its namespace and name. +// Assumes that the input 'str' has been validated. +func SplitQualifiedName(str string) (string, string) { + parts := strings.Split(str, "/") + if len(parts) < 2 { + return "", str + } + return parts[0], parts[1] +} + +// JoinQualifiedName joins 'namespace' and 'name' and returns a fully qualified name +// Assumes that the input is valid. +func JoinQualifiedName(namespace, name string) string { + return path.Join(namespace, name) +} + +// ShortenString returns the first N slice of a string. +func ShortenString(str string, n int) string { + if len(str) <= n { + return str + } + return str[:n] +} diff --git a/vendor/modules.txt b/vendor/modules.txt index f77416dd4..5ba852945 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -49,6 +49,10 @@ github.com/coreos/go-systemd/v22/journal # github.com/davecgh/go-spew v1.1.1 ## explicit github.com/davecgh/go-spew/spew +# github.com/docker/distribution v2.8.1+incompatible +## explicit +github.com/docker/distribution/digestset +github.com/docker/distribution/reference # github.com/emicklei/go-restful/v3 v3.9.0 ## explicit; go 1.13 github.com/emicklei/go-restful/v3 @@ -174,6 +178,7 @@ github.com/google/gnostic/openapiv3 # github.com/google/go-cmp v0.5.9 ## explicit; go 1.13 github.com/google/go-cmp/cmp +github.com/google/go-cmp/cmp/cmpopts github.com/google/go-cmp/cmp/internal/diff github.com/google/go-cmp/cmp/internal/flags github.com/google/go-cmp/cmp/internal/function @@ -243,6 +248,9 @@ github.com/mitchellh/go-wordwrap ## explicit; go 1.13 github.com/moby/spdystream github.com/moby/spdystream/spdy +# github.com/moby/sys/mountinfo v0.6.2 +## explicit; go 1.16 +github.com/moby/sys/mountinfo # github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae ## explicit; go 1.13 github.com/moby/term @@ -299,6 +307,15 @@ github.com/onsi/gomega/matchers/support/goraph/edge github.com/onsi/gomega/matchers/support/goraph/node github.com/onsi/gomega/matchers/support/goraph/util github.com/onsi/gomega/types +# github.com/opencontainers/go-digest v1.0.0 +## explicit; go 1.13 +github.com/opencontainers/go-digest +# github.com/opencontainers/selinux v1.10.0 +## explicit; go 1.13 +github.com/opencontainers/selinux/go-selinux +github.com/opencontainers/selinux/go-selinux/label +github.com/opencontainers/selinux/pkg/pwalk +github.com/opencontainers/selinux/pkg/pwalkdir # github.com/peterbourgon/diskv v2.0.1+incompatible ## explicit github.com/peterbourgon/diskv @@ -717,7 +734,7 @@ gopkg.in/yaml.v2 # gopkg.in/yaml.v3 v3.0.1 ## explicit gopkg.in/yaml.v3 -# k8s.io/api v0.26.3 +# k8s.io/api v0.26.3 => k8s.io/api v0.26.3 ## explicit; go 1.19 k8s.io/api/admission/v1 k8s.io/api/admission/v1beta1 @@ -773,7 +790,7 @@ k8s.io/api/scheduling/v1beta1 k8s.io/api/storage/v1 k8s.io/api/storage/v1alpha1 k8s.io/api/storage/v1beta1 -# k8s.io/apiextensions-apiserver v0.26.3 +# k8s.io/apiextensions-apiserver v0.26.3 => k8s.io/apiextensions-apiserver v0.26.3 ## explicit; go 1.19 k8s.io/apiextensions-apiserver/pkg/apis/apiextensions k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1 @@ -782,7 +799,7 @@ k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/scheme k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1 k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1beta1 -# k8s.io/apimachinery v0.26.3 +# k8s.io/apimachinery v0.26.3 => k8s.io/apimachinery v0.26.3 ## explicit; go 1.19 k8s.io/apimachinery/pkg/api/equality k8s.io/apimachinery/pkg/api/errors @@ -844,7 +861,7 @@ k8s.io/apimachinery/pkg/watch k8s.io/apimachinery/third_party/forked/golang/json k8s.io/apimachinery/third_party/forked/golang/netutil k8s.io/apimachinery/third_party/forked/golang/reflect -# k8s.io/apiserver v0.26.3 +# k8s.io/apiserver v0.26.3 => k8s.io/apiserver v0.26.3 ## explicit; go 1.19 k8s.io/apiserver/pkg/admission k8s.io/apiserver/pkg/admission/cel @@ -983,12 +1000,12 @@ k8s.io/apiserver/plugin/pkg/audit/truncate k8s.io/apiserver/plugin/pkg/audit/webhook k8s.io/apiserver/plugin/pkg/authenticator/token/webhook k8s.io/apiserver/plugin/pkg/authorizer/webhook -# k8s.io/cli-runtime v0.26.3 +# k8s.io/cli-runtime v0.26.3 => k8s.io/cli-runtime v0.26.3 ## explicit; go 1.19 k8s.io/cli-runtime/pkg/genericclioptions k8s.io/cli-runtime/pkg/printers k8s.io/cli-runtime/pkg/resource -# k8s.io/client-go v0.26.3 +# k8s.io/client-go v0.26.3 => k8s.io/client-go v0.26.3 ## explicit; go 1.19 k8s.io/client-go/applyconfigurations/admissionregistration/v1 k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1 @@ -1111,57 +1128,108 @@ k8s.io/client-go/informers/storage/v1 k8s.io/client-go/informers/storage/v1alpha1 k8s.io/client-go/informers/storage/v1beta1 k8s.io/client-go/kubernetes +k8s.io/client-go/kubernetes/fake k8s.io/client-go/kubernetes/scheme k8s.io/client-go/kubernetes/typed/admissionregistration/v1 +k8s.io/client-go/kubernetes/typed/admissionregistration/v1/fake k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1 +k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1 +k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/fake k8s.io/client-go/kubernetes/typed/apiserverinternal/v1alpha1 +k8s.io/client-go/kubernetes/typed/apiserverinternal/v1alpha1/fake k8s.io/client-go/kubernetes/typed/apps/v1 +k8s.io/client-go/kubernetes/typed/apps/v1/fake k8s.io/client-go/kubernetes/typed/apps/v1beta1 +k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake k8s.io/client-go/kubernetes/typed/apps/v1beta2 +k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake k8s.io/client-go/kubernetes/typed/authentication/v1 +k8s.io/client-go/kubernetes/typed/authentication/v1/fake k8s.io/client-go/kubernetes/typed/authentication/v1alpha1 +k8s.io/client-go/kubernetes/typed/authentication/v1alpha1/fake k8s.io/client-go/kubernetes/typed/authentication/v1beta1 +k8s.io/client-go/kubernetes/typed/authentication/v1beta1/fake k8s.io/client-go/kubernetes/typed/authorization/v1 +k8s.io/client-go/kubernetes/typed/authorization/v1/fake k8s.io/client-go/kubernetes/typed/authorization/v1beta1 +k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake k8s.io/client-go/kubernetes/typed/autoscaling/v1 +k8s.io/client-go/kubernetes/typed/autoscaling/v1/fake k8s.io/client-go/kubernetes/typed/autoscaling/v2 +k8s.io/client-go/kubernetes/typed/autoscaling/v2/fake k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1 +k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1/fake k8s.io/client-go/kubernetes/typed/autoscaling/v2beta2 +k8s.io/client-go/kubernetes/typed/autoscaling/v2beta2/fake k8s.io/client-go/kubernetes/typed/batch/v1 +k8s.io/client-go/kubernetes/typed/batch/v1/fake k8s.io/client-go/kubernetes/typed/batch/v1beta1 +k8s.io/client-go/kubernetes/typed/batch/v1beta1/fake k8s.io/client-go/kubernetes/typed/certificates/v1 +k8s.io/client-go/kubernetes/typed/certificates/v1/fake k8s.io/client-go/kubernetes/typed/certificates/v1beta1 +k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake k8s.io/client-go/kubernetes/typed/coordination/v1 +k8s.io/client-go/kubernetes/typed/coordination/v1/fake k8s.io/client-go/kubernetes/typed/coordination/v1beta1 +k8s.io/client-go/kubernetes/typed/coordination/v1beta1/fake k8s.io/client-go/kubernetes/typed/core/v1 +k8s.io/client-go/kubernetes/typed/core/v1/fake k8s.io/client-go/kubernetes/typed/discovery/v1 +k8s.io/client-go/kubernetes/typed/discovery/v1/fake k8s.io/client-go/kubernetes/typed/discovery/v1beta1 +k8s.io/client-go/kubernetes/typed/discovery/v1beta1/fake k8s.io/client-go/kubernetes/typed/events/v1 +k8s.io/client-go/kubernetes/typed/events/v1/fake k8s.io/client-go/kubernetes/typed/events/v1beta1 +k8s.io/client-go/kubernetes/typed/events/v1beta1/fake k8s.io/client-go/kubernetes/typed/extensions/v1beta1 +k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1 +k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1/fake k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1 +k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1/fake k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2 +k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2/fake k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3 +k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3/fake k8s.io/client-go/kubernetes/typed/networking/v1 +k8s.io/client-go/kubernetes/typed/networking/v1/fake k8s.io/client-go/kubernetes/typed/networking/v1alpha1 +k8s.io/client-go/kubernetes/typed/networking/v1alpha1/fake k8s.io/client-go/kubernetes/typed/networking/v1beta1 +k8s.io/client-go/kubernetes/typed/networking/v1beta1/fake k8s.io/client-go/kubernetes/typed/node/v1 +k8s.io/client-go/kubernetes/typed/node/v1/fake k8s.io/client-go/kubernetes/typed/node/v1alpha1 +k8s.io/client-go/kubernetes/typed/node/v1alpha1/fake k8s.io/client-go/kubernetes/typed/node/v1beta1 +k8s.io/client-go/kubernetes/typed/node/v1beta1/fake k8s.io/client-go/kubernetes/typed/policy/v1 +k8s.io/client-go/kubernetes/typed/policy/v1/fake k8s.io/client-go/kubernetes/typed/policy/v1beta1 +k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake k8s.io/client-go/kubernetes/typed/rbac/v1 +k8s.io/client-go/kubernetes/typed/rbac/v1/fake k8s.io/client-go/kubernetes/typed/rbac/v1alpha1 +k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake k8s.io/client-go/kubernetes/typed/rbac/v1beta1 +k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake k8s.io/client-go/kubernetes/typed/resource/v1alpha1 +k8s.io/client-go/kubernetes/typed/resource/v1alpha1/fake k8s.io/client-go/kubernetes/typed/scheduling/v1 +k8s.io/client-go/kubernetes/typed/scheduling/v1/fake k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1 +k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1/fake k8s.io/client-go/kubernetes/typed/scheduling/v1beta1 +k8s.io/client-go/kubernetes/typed/scheduling/v1beta1/fake k8s.io/client-go/kubernetes/typed/storage/v1 +k8s.io/client-go/kubernetes/typed/storage/v1/fake k8s.io/client-go/kubernetes/typed/storage/v1alpha1 +k8s.io/client-go/kubernetes/typed/storage/v1alpha1/fake k8s.io/client-go/kubernetes/typed/storage/v1beta1 +k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake k8s.io/client-go/listers/admissionregistration/v1 k8s.io/client-go/listers/admissionregistration/v1alpha1 k8s.io/client-go/listers/admissionregistration/v1beta1 @@ -1221,6 +1289,7 @@ k8s.io/client-go/plugin/pkg/client/auth/exec k8s.io/client-go/plugin/pkg/client/auth/gcp k8s.io/client-go/plugin/pkg/client/auth/oidc k8s.io/client-go/rest +k8s.io/client-go/rest/fake k8s.io/client-go/rest/watch k8s.io/client-go/restmapper k8s.io/client-go/scale @@ -1260,10 +1329,15 @@ k8s.io/client-go/util/jsonpath k8s.io/client-go/util/keyutil k8s.io/client-go/util/retry k8s.io/client-go/util/workqueue -# k8s.io/cluster-bootstrap v0.26.3 +# k8s.io/cloud-provider v0.23.3 => k8s.io/cloud-provider v0.26.3 +## explicit; go 1.19 +k8s.io/cloud-provider +k8s.io/cloud-provider/volume +k8s.io/cloud-provider/volume/helpers +# k8s.io/cluster-bootstrap v0.26.3 => k8s.io/cluster-bootstrap v0.26.3 ## explicit; go 1.19 k8s.io/cluster-bootstrap/token/api -# k8s.io/code-generator v0.26.3 +# k8s.io/code-generator v0.26.3 => k8s.io/code-generator v0.26.3 ## explicit; go 1.19 k8s.io/code-generator k8s.io/code-generator/cmd/client-gen @@ -1298,12 +1372,16 @@ k8s.io/code-generator/cmd/set-gen k8s.io/code-generator/pkg/namer k8s.io/code-generator/pkg/util k8s.io/code-generator/third_party/forked/golang/reflect -# k8s.io/component-base v0.26.3 +# k8s.io/component-base v0.26.3 => k8s.io/component-base v0.26.3 ## explicit; go 1.19 k8s.io/component-base/cli k8s.io/component-base/cli/flag +k8s.io/component-base/cli/globalflag k8s.io/component-base/config +k8s.io/component-base/config/options k8s.io/component-base/config/v1alpha1 +k8s.io/component-base/config/validation +k8s.io/component-base/configz k8s.io/component-base/featuregate k8s.io/component-base/logs k8s.io/component-base/logs/api/v1 @@ -1320,6 +1398,22 @@ k8s.io/component-base/term k8s.io/component-base/tracing k8s.io/component-base/tracing/api/v1 k8s.io/component-base/version +k8s.io/component-base/version/verflag +# k8s.io/component-helpers v0.26.3 => k8s.io/component-helpers v0.26.3 +## explicit; go 1.19 +k8s.io/component-helpers/node/topology +k8s.io/component-helpers/node/util/sysctl +k8s.io/component-helpers/scheduling/corev1 +k8s.io/component-helpers/scheduling/corev1/nodeaffinity +k8s.io/component-helpers/storage/ephemeral +k8s.io/component-helpers/storage/volume +# k8s.io/csi-translation-lib v0.23.3 => k8s.io/csi-translation-lib v0.26.3 +## explicit; go 1.19 +k8s.io/csi-translation-lib +k8s.io/csi-translation-lib/plugins +# k8s.io/dynamic-resource-allocation v0.0.0 => k8s.io/dynamic-resource-allocation v0.26.3 +## explicit; go 1.19 +k8s.io/dynamic-resource-allocation/resourceclaim # k8s.io/gengo v0.0.0-20220902162205-c0856e24416d ## explicit; go 1.13 k8s.io/gengo/args @@ -1344,7 +1438,7 @@ k8s.io/klog/v2/internal/severity ## explicit; go 1.19 k8s.io/kms/apis/v1beta1 k8s.io/kms/apis/v2alpha1 -# k8s.io/kube-aggregator v0.26.3 +# k8s.io/kube-aggregator v0.26.3 => k8s.io/kube-aggregator v0.26.3 ## explicit; go 1.19 k8s.io/kube-aggregator/pkg/apis/apiregistration k8s.io/kube-aggregator/pkg/apis/apiregistration/v1 @@ -1377,7 +1471,13 @@ k8s.io/kube-openapi/pkg/util/proto k8s.io/kube-openapi/pkg/util/proto/validation k8s.io/kube-openapi/pkg/util/sets k8s.io/kube-openapi/pkg/validation/spec -# k8s.io/kubectl v0.26.3 +# k8s.io/kube-scheduler v0.0.0 => k8s.io/kube-scheduler v0.26.3 +## explicit; go 1.19 +k8s.io/kube-scheduler/config/v1 +k8s.io/kube-scheduler/config/v1beta2 +k8s.io/kube-scheduler/config/v1beta3 +k8s.io/kube-scheduler/extender/v1 +# k8s.io/kubectl v0.26.3 => k8s.io/kubectl v0.26.3 ## explicit; go 1.19 k8s.io/kubectl/pkg/cmd/get k8s.io/kubectl/pkg/cmd/util @@ -1391,6 +1491,88 @@ k8s.io/kubectl/pkg/util/slice k8s.io/kubectl/pkg/util/templates k8s.io/kubectl/pkg/util/term k8s.io/kubectl/pkg/validation +# k8s.io/kubernetes v0.0.0-00010101000000-000000000000 => k8s.io/kubernetes v1.26.3 +## explicit; go 1.19 +k8s.io/kubernetes/cmd/kube-scheduler/app +k8s.io/kubernetes/cmd/kube-scheduler/app/config +k8s.io/kubernetes/cmd/kube-scheduler/app/options +k8s.io/kubernetes/pkg/api/legacyscheme +k8s.io/kubernetes/pkg/api/service +k8s.io/kubernetes/pkg/api/v1/pod +k8s.io/kubernetes/pkg/api/v1/resource +k8s.io/kubernetes/pkg/apis/apps +k8s.io/kubernetes/pkg/apis/autoscaling +k8s.io/kubernetes/pkg/apis/core +k8s.io/kubernetes/pkg/apis/core/helper +k8s.io/kubernetes/pkg/apis/core/pods +k8s.io/kubernetes/pkg/apis/core/v1 +k8s.io/kubernetes/pkg/apis/core/v1/helper +k8s.io/kubernetes/pkg/apis/core/validation +k8s.io/kubernetes/pkg/capabilities +k8s.io/kubernetes/pkg/cluster/ports +k8s.io/kubernetes/pkg/features +k8s.io/kubernetes/pkg/fieldpath +k8s.io/kubernetes/pkg/kubelet/server/metrics +k8s.io/kubernetes/pkg/proxy/util +k8s.io/kubernetes/pkg/scheduler +k8s.io/kubernetes/pkg/scheduler/apis/config +k8s.io/kubernetes/pkg/scheduler/apis/config/latest +k8s.io/kubernetes/pkg/scheduler/apis/config/scheme +k8s.io/kubernetes/pkg/scheduler/apis/config/v1 +k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2 +k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3 +k8s.io/kubernetes/pkg/scheduler/apis/config/validation +k8s.io/kubernetes/pkg/scheduler/framework +k8s.io/kubernetes/pkg/scheduler/framework/parallelize +k8s.io/kubernetes/pkg/scheduler/framework/plugins +k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultbinder +k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultpreemption +k8s.io/kubernetes/pkg/scheduler/framework/plugins/dynamicresources +k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature +k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper +k8s.io/kubernetes/pkg/scheduler/framework/plugins/imagelocality +k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity +k8s.io/kubernetes/pkg/scheduler/framework/plugins/names +k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeaffinity +k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodename +k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeports +k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources +k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeunschedulable +k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodevolumelimits +k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread +k8s.io/kubernetes/pkg/scheduler/framework/plugins/queuesort +k8s.io/kubernetes/pkg/scheduler/framework/plugins/schedulinggates +k8s.io/kubernetes/pkg/scheduler/framework/plugins/selectorspread +k8s.io/kubernetes/pkg/scheduler/framework/plugins/tainttoleration +k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding +k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/metrics +k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumerestrictions +k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumezone +k8s.io/kubernetes/pkg/scheduler/framework/preemption +k8s.io/kubernetes/pkg/scheduler/framework/runtime +k8s.io/kubernetes/pkg/scheduler/internal/cache +k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger +k8s.io/kubernetes/pkg/scheduler/internal/heap +k8s.io/kubernetes/pkg/scheduler/internal/queue +k8s.io/kubernetes/pkg/scheduler/metrics +k8s.io/kubernetes/pkg/scheduler/metrics/resources +k8s.io/kubernetes/pkg/scheduler/profile +k8s.io/kubernetes/pkg/scheduler/util +k8s.io/kubernetes/pkg/securitycontext +k8s.io/kubernetes/pkg/util/parsers +k8s.io/kubernetes/pkg/volume +k8s.io/kubernetes/pkg/volume/util +k8s.io/kubernetes/pkg/volume/util/fs +k8s.io/kubernetes/pkg/volume/util/fsquota +k8s.io/kubernetes/pkg/volume/util/fsquota/common +k8s.io/kubernetes/pkg/volume/util/hostutil +k8s.io/kubernetes/pkg/volume/util/recyclerclient +k8s.io/kubernetes/pkg/volume/util/subpath +k8s.io/kubernetes/pkg/volume/util/types +k8s.io/kubernetes/pkg/volume/util/volumepathhandler +# k8s.io/mount-utils v0.23.3 => k8s.io/mount-utils v0.26.3 +## explicit; go 1.19 +k8s.io/mount-utils # k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 ## explicit; go 1.18 k8s.io/utils/buffer @@ -1401,10 +1583,14 @@ k8s.io/utils/exec k8s.io/utils/integer k8s.io/utils/internal/third_party/forked/golang/golang-lru k8s.io/utils/internal/third_party/forked/golang/net +k8s.io/utils/io +k8s.io/utils/keymutex k8s.io/utils/lru k8s.io/utils/net +k8s.io/utils/nsenter k8s.io/utils/path k8s.io/utils/pointer +k8s.io/utils/strings k8s.io/utils/strings/slices k8s.io/utils/trace # sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.36 @@ -1555,9 +1741,30 @@ sigs.k8s.io/structured-merge-diff/v4/value ## explicit; go 1.12 sigs.k8s.io/yaml # golang.org/x/oauth2 => golang.org/x/oauth2 v0.1.0 +# k8s.io/api => k8s.io/api v0.26.3 +# k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.26.3 +# k8s.io/apimachinery => k8s.io/apimachinery v0.26.3 +# k8s.io/apiserver => k8s.io/apiserver v0.26.3 +# k8s.io/cli-runtime => k8s.io/cli-runtime v0.26.3 +# k8s.io/client-go => k8s.io/client-go v0.26.3 +# k8s.io/cloud-provider => k8s.io/cloud-provider v0.26.3 +# k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.26.3 +# k8s.io/code-generator => k8s.io/code-generator v0.26.3 +# k8s.io/component-base => k8s.io/component-base v0.26.3 +# k8s.io/component-helpers => k8s.io/component-helpers v0.26.3 +# k8s.io/controller-manager => k8s.io/controller-manager v0.26.3 # k8s.io/cri-api => k8s.io/cri-api v0.26.3 +# k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.26.3 +# k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.26.3 +# k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.26.3 +# k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.26.3 # k8s.io/kube-proxy => k8s.io/kube-proxy v0.26.3 # k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.26.3 +# k8s.io/kubectl => k8s.io/kubectl v0.26.3 # k8s.io/kubelet => k8s.io/kubelet v0.26.3 -# k8s.io/kubernetes => k8s.io/kubernetes v0.26.3 +# k8s.io/kubernetes => k8s.io/kubernetes v1.26.3 # k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.26.3 +# k8s.io/metrics => k8s.io/metrics v0.26.3 +# k8s.io/mount-utils => k8s.io/mount-utils v0.26.3 +# k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.26.3 +# k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.26.3