Unverified Commit ed89907b authored by Lars Lehtonen's avatar Lars Lehtonen

Merge branch 'fix-aws-ebs-swallowed-errors' into fix-storageos-swallowed-err

parents 76a21a41 09f4ecff
...@@ -25,23 +25,23 @@ filegroup( ...@@ -25,23 +25,23 @@ filegroup(
# in build/common.sh. # in build/common.sh.
DOCKERIZED_BINARIES = { DOCKERIZED_BINARIES = {
"cloud-controller-manager": { "cloud-controller-manager": {
"base": "@official_busybox//image:image.tar", "base": "@official_busybox//image",
"target": "//cmd/cloud-controller-manager:cloud-controller-manager", "target": "//cmd/cloud-controller-manager:cloud-controller-manager",
}, },
"kube-apiserver": { "kube-apiserver": {
"base": "@official_busybox//image:image.tar", "base": "@official_busybox//image",
"target": "//cmd/kube-apiserver:kube-apiserver", "target": "//cmd/kube-apiserver:kube-apiserver",
}, },
"kube-controller-manager": { "kube-controller-manager": {
"base": "@official_busybox//image:image.tar", "base": "@official_busybox//image",
"target": "//cmd/kube-controller-manager:kube-controller-manager", "target": "//cmd/kube-controller-manager:kube-controller-manager",
}, },
"kube-scheduler": { "kube-scheduler": {
"base": "@official_busybox//image:image.tar", "base": "@official_busybox//image",
"target": "//plugin/cmd/kube-scheduler:kube-scheduler", "target": "//plugin/cmd/kube-scheduler:kube-scheduler",
}, },
"kube-proxy": { "kube-proxy": {
"base": "@debian-iptables-amd64//image:image.tar", "base": "@debian-iptables-amd64//image",
"target": "//cmd/kube-proxy:kube-proxy", "target": "//cmd/kube-proxy:kube-proxy",
}, },
} }
......
...@@ -65,7 +65,7 @@ func main() { ...@@ -65,7 +65,7 @@ func main() {
if s.AllowUntaggedCloud == true { if s.AllowUntaggedCloud == true {
glog.Warning("detected a cluster without a ClusterID. A ClusterID will be required in the future. Please tag your cluster to avoid any future issues") glog.Warning("detected a cluster without a ClusterID. A ClusterID will be required in the future. Please tag your cluster to avoid any future issues")
} else { } else {
glog.Fatalf("no ClusterID Found. A ClusterID is required for the cloud provider to function properly. This check can be bypassed by setting the allow-untagged-cloud option") glog.Fatalf("no ClusterID found. A ClusterID is required for the cloud provider to function properly. This check can be bypassed by setting the allow-untagged-cloud option")
} }
} }
......
...@@ -175,7 +175,8 @@ func startAttachDetachController(ctx ControllerContext) (bool, error) { ...@@ -175,7 +175,8 @@ func startAttachDetachController(ctx ControllerContext) (bool, error) {
ctx.InformerFactory.Core().V1().PersistentVolumeClaims(), ctx.InformerFactory.Core().V1().PersistentVolumeClaims(),
ctx.InformerFactory.Core().V1().PersistentVolumes(), ctx.InformerFactory.Core().V1().PersistentVolumes(),
ctx.Cloud, ctx.Cloud,
ProbeAttachableVolumePlugins(ctx.Options.VolumeConfiguration), ProbeAttachableVolumePlugins(),
GetDynamicPluginProber(ctx.Options.VolumeConfiguration),
ctx.Options.DisableAttachDetachReconcilerSync, ctx.Options.DisableAttachDetachReconcilerSync,
ctx.Options.ReconcilerSyncLoopPeriod.Duration, ctx.Options.ReconcilerSyncLoopPeriod.Duration,
attachdetach.DefaultTimerConfig, attachdetach.DefaultTimerConfig,
......
...@@ -60,18 +60,15 @@ import ( ...@@ -60,18 +60,15 @@ import (
) )
// ProbeAttachableVolumePlugins collects all volume plugins for the attach/ // ProbeAttachableVolumePlugins collects all volume plugins for the attach/
// detach controller. VolumeConfiguration is used ot get FlexVolumePluginDir // detach controller.
// which specifies the directory to search for additional third party volume
// plugins.
// The list of plugins is manually compiled. This code and the plugin // The list of plugins is manually compiled. This code and the plugin
// initialization code for kubelet really, really need a through refactor. // initialization code for kubelet really, really need a through refactor.
func ProbeAttachableVolumePlugins(config componentconfig.VolumeConfiguration) []volume.VolumePlugin { func ProbeAttachableVolumePlugins() []volume.VolumePlugin {
allPlugins := []volume.VolumePlugin{} allPlugins := []volume.VolumePlugin{}
allPlugins = append(allPlugins, aws_ebs.ProbeVolumePlugins()...) allPlugins = append(allPlugins, aws_ebs.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, gce_pd.ProbeVolumePlugins()...) allPlugins = append(allPlugins, gce_pd.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, cinder.ProbeVolumePlugins()...) allPlugins = append(allPlugins, cinder.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, flexvolume.ProbeVolumePlugins(config.FlexVolumePluginDir)...)
allPlugins = append(allPlugins, portworx.ProbeVolumePlugins()...) allPlugins = append(allPlugins, portworx.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, vsphere_volume.ProbeVolumePlugins()...) allPlugins = append(allPlugins, vsphere_volume.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, azure_dd.ProbeVolumePlugins()...) allPlugins = append(allPlugins, azure_dd.ProbeVolumePlugins()...)
...@@ -82,6 +79,13 @@ func ProbeAttachableVolumePlugins(config componentconfig.VolumeConfiguration) [] ...@@ -82,6 +79,13 @@ func ProbeAttachableVolumePlugins(config componentconfig.VolumeConfiguration) []
return allPlugins return allPlugins
} }
// GetDynamicPluginProber gets the probers of dynamically discoverable plugins
// for the attach/detach controller.
// Currently only Flexvolume plugins are dynamically discoverable.
func GetDynamicPluginProber(config componentconfig.VolumeConfiguration) volume.DynamicPluginProber {
return flexvolume.GetDynamicPluginProber(config.FlexVolumePluginDir)
}
// ProbeControllerVolumePlugins collects all persistent volume plugins into an // ProbeControllerVolumePlugins collects all persistent volume plugins into an
// easy to use list. Only volume plugins that implement any of // easy to use list. Only volume plugins that implement any of
// provisioner/recycler/deleter interface should be returned. // provisioner/recycler/deleter interface should be returned.
......
...@@ -327,6 +327,13 @@ func (i *Init) Run(out io.Writer) error { ...@@ -327,6 +327,13 @@ func (i *Init) Run(out io.Writer) error {
return err return err
} }
// Upload currently used configuration to the cluster
// Note: This is done right in the beginning of cluster initialization; as we might want to make other phases
// depend on centralized information from this source in the future
if err := uploadconfigphase.UploadConfiguration(i.cfg, client); err != nil {
return err
}
// PHASE 4: Mark the master with the right label/taint // PHASE 4: Mark the master with the right label/taint
if err := markmasterphase.MarkMaster(client, i.cfg.NodeName); err != nil { if err := markmasterphase.MarkMaster(client, i.cfg.NodeName); err != nil {
return err return err
...@@ -361,11 +368,6 @@ func (i *Init) Run(out io.Writer) error { ...@@ -361,11 +368,6 @@ func (i *Init) Run(out io.Writer) error {
// PHASE 6: Install and deploy all addons, and configure things as necessary // PHASE 6: Install and deploy all addons, and configure things as necessary
// Upload currently used configuration to the cluster
if err := uploadconfigphase.UploadConfiguration(i.cfg, client); err != nil {
return err
}
if err := apiconfigphase.CreateRBACRules(client, k8sVersion); err != nil { if err := apiconfigphase.CreateRBACRules(client, k8sVersion); err != nil {
return err return err
} }
......
...@@ -30,9 +30,11 @@ import ( ...@@ -30,9 +30,11 @@ import (
) )
const ( const (
caCertsVolumeName = "ca-certs" caCertsVolumeName = "ca-certs"
caCertsVolumePath = "/etc/ssl/certs" caCertsVolumePath = "/etc/ssl/certs"
caCertsPkiVolumeName = "ca-certs-etc-pki" caCertsPkiVolumeName = "ca-certs-etc-pki"
flexvolumeDirVolumeName = "flexvolume-dir"
flexvolumeDirVolumePath = "/usr/libexec/kubernetes/kubelet-plugins/volume/exec"
) )
// caCertsPkiVolumePath specifies the path that can be conditionally mounted into the apiserver and controller-manager containers // caCertsPkiVolumePath specifies the path that can be conditionally mounted into the apiserver and controller-manager containers
...@@ -68,6 +70,9 @@ func getHostPathVolumesForTheControlPlane(cfg *kubeadmapi.MasterConfiguration) c ...@@ -68,6 +70,9 @@ func getHostPathVolumesForTheControlPlane(cfg *kubeadmapi.MasterConfiguration) c
// Read-only mount for the controller manager kubeconfig file // Read-only mount for the controller manager kubeconfig file
controllerManagerKubeConfigFile := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ControllerManagerKubeConfigFileName) controllerManagerKubeConfigFile := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ControllerManagerKubeConfigFileName)
mounts.NewHostPathMount(kubeadmconstants.KubeControllerManager, kubeadmconstants.KubeConfigVolumeName, controllerManagerKubeConfigFile, controllerManagerKubeConfigFile, true, &hostPathFileOrCreate) mounts.NewHostPathMount(kubeadmconstants.KubeControllerManager, kubeadmconstants.KubeConfigVolumeName, controllerManagerKubeConfigFile, controllerManagerKubeConfigFile, true, &hostPathFileOrCreate)
// Mount for the flexvolume directory (/usr/libexec/kubernetes/kubelet-plugins/volume/exec) directory
// Flexvolume dir must NOT be readonly as it is used for third-party plugins to integrate with their storage backends via unix domain socket.
mounts.NewHostPathMount(kubeadmconstants.KubeControllerManager, flexvolumeDirVolumeName, flexvolumeDirVolumePath, flexvolumeDirVolumePath, false, &hostPathDirectoryOrCreate)
// HostPath volumes for the scheduler // HostPath volumes for the scheduler
// Read-only mount for the scheduler kubeconfig file // Read-only mount for the scheduler kubeconfig file
......
...@@ -309,6 +309,15 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) { ...@@ -309,6 +309,15 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
}, },
}, },
}, },
{
Name: "flexvolume-dir",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/usr/libexec/kubernetes/kubelet-plugins/volume/exec",
Type: &hostPathDirectoryOrCreate,
},
},
},
}, },
kubeadmconstants.KubeScheduler: { kubeadmconstants.KubeScheduler: {
{ {
...@@ -351,6 +360,11 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) { ...@@ -351,6 +360,11 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
MountPath: "/etc/kubernetes/controller-manager.conf", MountPath: "/etc/kubernetes/controller-manager.conf",
ReadOnly: true, ReadOnly: true,
}, },
{
Name: "flexvolume-dir",
MountPath: "/usr/libexec/kubernetes/kubelet-plugins/volume/exec",
ReadOnly: false,
},
}, },
kubeadmconstants.KubeScheduler: { kubeadmconstants.KubeScheduler: {
{ {
...@@ -439,6 +453,15 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) { ...@@ -439,6 +453,15 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
}, },
}, },
}, },
{
Name: "flexvolume-dir",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{
Path: "/usr/libexec/kubernetes/kubelet-plugins/volume/exec",
Type: &hostPathDirectoryOrCreate,
},
},
},
}, },
kubeadmconstants.KubeScheduler: { kubeadmconstants.KubeScheduler: {
{ {
...@@ -491,6 +514,11 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) { ...@@ -491,6 +514,11 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
MountPath: "/etc/kubernetes/controller-manager.conf", MountPath: "/etc/kubernetes/controller-manager.conf",
ReadOnly: true, ReadOnly: true,
}, },
{
Name: "flexvolume-dir",
MountPath: "/usr/libexec/kubernetes/kubelet-plugins/volume/exec",
ReadOnly: false,
},
}, },
kubeadmconstants.KubeScheduler: { kubeadmconstants.KubeScheduler: {
{ {
......
...@@ -61,9 +61,7 @@ import ( ...@@ -61,9 +61,7 @@ import (
) )
// ProbeVolumePlugins collects all volume plugins into an easy to use list. // ProbeVolumePlugins collects all volume plugins into an easy to use list.
// PluginDir specifies the directory to search for additional third party func ProbeVolumePlugins() []volume.VolumePlugin {
// volume plugins.
func ProbeVolumePlugins(pluginDir string) []volume.VolumePlugin {
allPlugins := []volume.VolumePlugin{} allPlugins := []volume.VolumePlugin{}
// The list of plugins to probe is decided by the kubelet binary, not // The list of plugins to probe is decided by the kubelet binary, not
...@@ -88,7 +86,6 @@ func ProbeVolumePlugins(pluginDir string) []volume.VolumePlugin { ...@@ -88,7 +86,6 @@ func ProbeVolumePlugins(pluginDir string) []volume.VolumePlugin {
allPlugins = append(allPlugins, downwardapi.ProbeVolumePlugins()...) allPlugins = append(allPlugins, downwardapi.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, fc.ProbeVolumePlugins()...) allPlugins = append(allPlugins, fc.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, flocker.ProbeVolumePlugins()...) allPlugins = append(allPlugins, flocker.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, flexvolume.ProbeVolumePlugins(pluginDir)...)
allPlugins = append(allPlugins, azure_file.ProbeVolumePlugins()...) allPlugins = append(allPlugins, azure_file.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, configmap.ProbeVolumePlugins()...) allPlugins = append(allPlugins, configmap.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, vsphere_volume.ProbeVolumePlugins()...) allPlugins = append(allPlugins, vsphere_volume.ProbeVolumePlugins()...)
...@@ -102,6 +99,13 @@ func ProbeVolumePlugins(pluginDir string) []volume.VolumePlugin { ...@@ -102,6 +99,13 @@ func ProbeVolumePlugins(pluginDir string) []volume.VolumePlugin {
return allPlugins return allPlugins
} }
// GetDynamicPluginProber gets the probers of dynamically discoverable plugins
// for kubelet.
// Currently only Flexvolume plugins are dynamically discoverable.
func GetDynamicPluginProber(pluginDir string) volume.DynamicPluginProber {
return flexvolume.GetDynamicPluginProber(pluginDir)
}
// ProbeNetworkPlugins collects all compiled-in plugins // ProbeNetworkPlugins collects all compiled-in plugins
func ProbeNetworkPlugins(pluginDir, cniConfDir, cniBinDir string) []network.NetworkPlugin { func ProbeNetworkPlugins(pluginDir, cniConfDir, cniBinDir string) []network.NetworkPlugin {
allPlugins := []network.NetworkPlugin{} allPlugins := []network.NetworkPlugin{}
......
...@@ -151,22 +151,22 @@ func UnsecuredDependencies(s *options.KubeletServer) (*kubelet.Dependencies, err ...@@ -151,22 +151,22 @@ func UnsecuredDependencies(s *options.KubeletServer) (*kubelet.Dependencies, err
} }
return &kubelet.Dependencies{ return &kubelet.Dependencies{
Auth: nil, // default does not enforce auth[nz] Auth: nil, // default does not enforce auth[nz]
CAdvisorInterface: nil, // cadvisor.New launches background processes (bg http.ListenAndServe, and some bg cleaners), not set here CAdvisorInterface: nil, // cadvisor.New launches background processes (bg http.ListenAndServe, and some bg cleaners), not set here
Cloud: nil, // cloud provider might start background processes Cloud: nil, // cloud provider might start background processes
ContainerManager: nil, ContainerManager: nil,
DockerClient: dockerClient, DockerClient: dockerClient,
KubeClient: nil, KubeClient: nil,
ExternalKubeClient: nil, ExternalKubeClient: nil,
EventClient: nil, EventClient: nil,
Mounter: mounter, Mounter: mounter,
NetworkPlugins: ProbeNetworkPlugins(s.NetworkPluginDir, s.CNIConfDir, s.CNIBinDir), NetworkPlugins: ProbeNetworkPlugins(s.NetworkPluginDir, s.CNIConfDir, s.CNIBinDir),
OOMAdjuster: oom.NewOOMAdjuster(), OOMAdjuster: oom.NewOOMAdjuster(),
OSInterface: kubecontainer.RealOS{}, OSInterface: kubecontainer.RealOS{},
Writer: writer, Writer: writer,
VolumePlugins: ProbeVolumePlugins(s.VolumePluginDir), VolumePlugins: ProbeVolumePlugins(),
TLSOptions: tlsOptions, DynamicPluginProber: GetDynamicPluginProber(s.VolumePluginDir),
}, nil TLSOptions: tlsOptions}, nil
} }
// Run runs the specified KubeletServer with the given Dependencies. This should never exit. // Run runs the specified KubeletServer with the given Dependencies. This should never exit.
...@@ -745,7 +745,7 @@ func parseResourceList(m kubeletconfiginternal.ConfigurationMap) (v1.ResourceLis ...@@ -745,7 +745,7 @@ func parseResourceList(m kubeletconfiginternal.ConfigurationMap) (v1.ResourceLis
for k, v := range m { for k, v := range m {
switch v1.ResourceName(k) { switch v1.ResourceName(k) {
// CPU, memory and local storage resources are supported. // CPU, memory and local storage resources are supported.
case v1.ResourceCPU, v1.ResourceMemory, v1.ResourceStorage: case v1.ResourceCPU, v1.ResourceMemory, v1.ResourceEphemeralStorage:
q, err := resource.ParseQuantity(v) q, err := resource.ParseQuantity(v)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -753,12 +753,7 @@ func parseResourceList(m kubeletconfiginternal.ConfigurationMap) (v1.ResourceLis ...@@ -753,12 +753,7 @@ func parseResourceList(m kubeletconfiginternal.ConfigurationMap) (v1.ResourceLis
if q.Sign() == -1 { if q.Sign() == -1 {
return nil, fmt.Errorf("resource quantity for %q cannot be negative: %v", k, v) return nil, fmt.Errorf("resource quantity for %q cannot be negative: %v", k, v)
} }
// storage specified in configuration map is mapped to ResourceStorageScratch API rl[v1.ResourceName(k)] = q
if v1.ResourceName(k) == v1.ResourceStorage {
rl[v1.ResourceStorageScratch] = q
} else {
rl[v1.ResourceName(k)] = q
}
default: default:
return nil, fmt.Errorf("cannot reserve %q resource", k) return nil, fmt.Errorf("cannot reserve %q resource", k)
} }
......
...@@ -31,6 +31,8 @@ KUBELET_AUTHORIZATION_WEBHOOK=${KUBELET_AUTHORIZATION_WEBHOOK:-""} ...@@ -31,6 +31,8 @@ KUBELET_AUTHORIZATION_WEBHOOK=${KUBELET_AUTHORIZATION_WEBHOOK:-""}
KUBELET_AUTHENTICATION_WEBHOOK=${KUBELET_AUTHENTICATION_WEBHOOK:-""} KUBELET_AUTHENTICATION_WEBHOOK=${KUBELET_AUTHENTICATION_WEBHOOK:-""}
POD_MANIFEST_PATH=${POD_MANIFEST_PATH:-"/var/run/kubernetes/static-pods"} POD_MANIFEST_PATH=${POD_MANIFEST_PATH:-"/var/run/kubernetes/static-pods"}
KUBELET_FLAGS=${KUBELET_FLAGS:-""} KUBELET_FLAGS=${KUBELET_FLAGS:-""}
# many dev environments run with swap on, so we don't fail in this env
FAIL_SWAP_ON=${FAIL_SWAP_ON:-"false"}
# Name of the network plugin, eg: "kubenet" # Name of the network plugin, eg: "kubenet"
NET_PLUGIN=${NET_PLUGIN:-""} NET_PLUGIN=${NET_PLUGIN:-""}
# Place the config files and binaries required by NET_PLUGIN in these directory, # Place the config files and binaries required by NET_PLUGIN in these directory,
...@@ -112,6 +114,11 @@ if [ "${CLOUD_PROVIDER}" == "openstack" ]; then ...@@ -112,6 +114,11 @@ if [ "${CLOUD_PROVIDER}" == "openstack" ]; then
fi fi
fi fi
# warn if users are running with swap allowed
if [ "${FAIL_SWAP_ON}" == "false" ]; then
echo "WARNING : The kubelet is configured to not fail if swap is enabled; production deployments should disable swap."
fi
if [ "$(id -u)" != "0" ]; then if [ "$(id -u)" != "0" ]; then
echo "WARNING : This script MAY be run as root for docker socket / iptables functionality; if failures occur, retry as root." 2>&1 echo "WARNING : This script MAY be run as root for docker socket / iptables functionality; if failures occur, retry as root." 2>&1
fi fi
...@@ -665,6 +672,7 @@ function start_kubelet { ...@@ -665,6 +672,7 @@ function start_kubelet {
--eviction-soft=${EVICTION_SOFT} \ --eviction-soft=${EVICTION_SOFT} \
--eviction-pressure-transition-period=${EVICTION_PRESSURE_TRANSITION_PERIOD} \ --eviction-pressure-transition-period=${EVICTION_PRESSURE_TRANSITION_PERIOD} \
--pod-manifest-path="${POD_MANIFEST_PATH}" \ --pod-manifest-path="${POD_MANIFEST_PATH}" \
--fail-swap-on="${FAIL_SWAP_ON}" \
${auth_args} \ ${auth_args} \
${dns_args} \ ${dns_args} \
${cni_conf_dir_args} \ ${cni_conf_dir_args} \
......
...@@ -107,6 +107,7 @@ func IsResourceQuotaScopeValidForResource(scope api.ResourceQuotaScope, resource ...@@ -107,6 +107,7 @@ func IsResourceQuotaScopeValidForResource(scope api.ResourceQuotaScope, resource
var standardContainerResources = sets.NewString( var standardContainerResources = sets.NewString(
string(api.ResourceCPU), string(api.ResourceCPU),
string(api.ResourceMemory), string(api.ResourceMemory),
string(api.ResourceEphemeralStorage),
) )
// IsStandardContainerResourceName returns true if the container can make a resource request // IsStandardContainerResourceName returns true if the container can make a resource request
...@@ -194,10 +195,13 @@ func IsStandardQuotaResourceName(str string) bool { ...@@ -194,10 +195,13 @@ func IsStandardQuotaResourceName(str string) bool {
var standardResources = sets.NewString( var standardResources = sets.NewString(
string(api.ResourceCPU), string(api.ResourceCPU),
string(api.ResourceMemory), string(api.ResourceMemory),
string(api.ResourceEphemeralStorage),
string(api.ResourceRequestsCPU), string(api.ResourceRequestsCPU),
string(api.ResourceRequestsMemory), string(api.ResourceRequestsMemory),
string(api.ResourceRequestsEphemeralStorage),
string(api.ResourceLimitsCPU), string(api.ResourceLimitsCPU),
string(api.ResourceLimitsMemory), string(api.ResourceLimitsMemory),
string(api.ResourceLimitsEphemeralStorage),
string(api.ResourcePods), string(api.ResourcePods),
string(api.ResourceQuotas), string(api.ResourceQuotas),
string(api.ResourceServices), string(api.ResourceServices),
......
...@@ -166,6 +166,7 @@ func addConversionFuncs(scheme *runtime.Scheme) error { ...@@ -166,6 +166,7 @@ func addConversionFuncs(scheme *runtime.Scheme) error {
"spec.nodeName", "spec.nodeName",
"spec.restartPolicy", "spec.restartPolicy",
"spec.serviceAccountName", "spec.serviceAccountName",
"spec.schedulerName",
"status.phase", "status.phase",
"status.hostIP", "status.hostIP",
"status.podIP": "status.podIP":
......
...@@ -3817,8 +3817,8 @@ func ValidateResourceRequirements(requirements *api.ResourceRequirements, fldPat ...@@ -3817,8 +3817,8 @@ func ValidateResourceRequirements(requirements *api.ResourceRequirements, fldPat
// Validate resource quantity. // Validate resource quantity.
allErrs = append(allErrs, ValidateResourceQuantityValue(string(resourceName), quantity, fldPath)...) allErrs = append(allErrs, ValidateResourceQuantityValue(string(resourceName), quantity, fldPath)...)
if resourceName == api.ResourceStorageOverlay && !utilfeature.DefaultFeatureGate.Enabled(features.LocalStorageCapacityIsolation) { if resourceName == api.ResourceEphemeralStorage && !utilfeature.DefaultFeatureGate.Enabled(features.LocalStorageCapacityIsolation) {
allErrs = append(allErrs, field.Forbidden(limPath, "ResourceStorageOverlay field disabled by feature-gate for ResourceRequirements")) allErrs = append(allErrs, field.Forbidden(limPath, "ResourceEphemeralStorage field disabled by feature-gate for ResourceRequirements"))
} }
} }
for resourceName, quantity := range requirements.Requests { for resourceName, quantity := range requirements.Requests {
......
...@@ -2683,7 +2683,7 @@ func TestAlphaLocalStorageCapacityIsolation(t *testing.T) { ...@@ -2683,7 +2683,7 @@ func TestAlphaLocalStorageCapacityIsolation(t *testing.T) {
containerLimitCase := api.ResourceRequirements{ containerLimitCase := api.ResourceRequirements{
Limits: api.ResourceList{ Limits: api.ResourceList{
api.ResourceStorageOverlay: *resource.NewMilliQuantity( api.ResourceEphemeralStorage: *resource.NewMilliQuantity(
int64(40000), int64(40000),
resource.BinarySI), resource.BinarySI),
}, },
......
...@@ -124,7 +124,7 @@ type Instances interface { ...@@ -124,7 +124,7 @@ type Instances interface {
// ProviderID is a unique identifier of the node. This will not be called // 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 // from the node whose nodeaddresses are being queried. i.e. local metadata
// services cannot be used in this method to obtain nodeaddresses // services cannot be used in this method to obtain nodeaddresses
NodeAddressesByProviderID(providerId string) ([]v1.NodeAddress, error) NodeAddressesByProviderID(providerID string) ([]v1.NodeAddress, error)
// ExternalID returns the cloud provider ID of the node with the specified NodeName. // ExternalID returns the cloud provider ID of the node with the specified NodeName.
// Note that if the instance does not exist or is no longer running, we must return ("", cloudprovider.InstanceNotFound) // Note that if the instance does not exist or is no longer running, we must return ("", cloudprovider.InstanceNotFound)
ExternalID(nodeName types.NodeName) (string, error) ExternalID(nodeName types.NodeName) (string, error)
...@@ -140,6 +140,9 @@ type Instances interface { ...@@ -140,6 +140,9 @@ type Instances interface {
// CurrentNodeName returns the name of the node we are currently running on // 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 // On most clouds (e.g. GCE) this is the hostname, so we provide the hostname
CurrentNodeName(hostname string) (types.NodeName, error) CurrentNodeName(hostname string) (types.NodeName, error)
// InstanceExistsByProviderID returns true if the instance for the given provider id still is running.
// If false is returned with no error, the instance will be immediately deleted by the cloud controller manager.
InstanceExistsByProviderID(providerID string) (bool, error)
} }
// Route is a representation of an advanced routing rule. // Route is a representation of an advanced routing rule.
......
...@@ -1101,6 +1101,12 @@ func (c *Cloud) ExternalID(nodeName types.NodeName) (string, error) { ...@@ -1101,6 +1101,12 @@ func (c *Cloud) ExternalID(nodeName types.NodeName) (string, error) {
return orEmpty(instance.InstanceId), nil return orEmpty(instance.InstanceId), nil
} }
// InstanceExistsByProviderID returns true if the instance with the given provider id still exists and is running.
// If false is returned with no error, the instance will be immediately deleted by the cloud controller manager.
func (c *Cloud) InstanceExistsByProviderID(providerID string) (bool, error) {
return false, errors.New("unimplemented")
}
// InstanceID returns the cloud provider ID of the node with the specified nodeName. // InstanceID returns the cloud provider ID of the node with the specified nodeName.
func (c *Cloud) InstanceID(nodeName types.NodeName) (string, error) { func (c *Cloud) InstanceID(nodeName types.NodeName) (string, error) {
// In the future it is possible to also return an endpoint as: // In the future it is possible to also return an endpoint as:
......
...@@ -17,6 +17,7 @@ limitations under the License. ...@@ -17,6 +17,7 @@ limitations under the License.
package azure package azure
import ( import (
"errors"
"fmt" "fmt"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
...@@ -86,6 +87,12 @@ func (az *Cloud) ExternalID(name types.NodeName) (string, error) { ...@@ -86,6 +87,12 @@ func (az *Cloud) ExternalID(name types.NodeName) (string, error) {
return az.InstanceID(name) return az.InstanceID(name)
} }
// InstanceExistsByProviderID returns true if the instance with the given provider id still exists and is running.
// If false is returned with no error, the instance will be immediately deleted by the cloud controller manager.
func (az *Cloud) InstanceExistsByProviderID(providerID string) (bool, error) {
return false, errors.New("unimplemented")
}
func (az *Cloud) isCurrentInstance(name types.NodeName) (bool, error) { func (az *Cloud) isCurrentInstance(name types.NodeName) (bool, error) {
nodeName := mapNodeNameToVMName(name) nodeName := mapNodeNameToVMName(name)
metadataName, err := az.metadata.Text("instance/compute/name") metadataName, err := az.metadata.Text("instance/compute/name")
......
...@@ -47,8 +47,12 @@ type FakeUpdateBalancerCall struct { ...@@ -47,8 +47,12 @@ type FakeUpdateBalancerCall struct {
// FakeCloud is a test-double implementation of Interface, LoadBalancer, Instances, and Routes. It is useful for testing. // FakeCloud is a test-double implementation of Interface, LoadBalancer, Instances, and Routes. It is useful for testing.
type FakeCloud struct { type FakeCloud struct {
Exists bool Exists bool
Err error Err error
ExistsByProviderID bool
ErrByProviderID error
Calls []string Calls []string
Addresses []v1.NodeAddress Addresses []v1.NodeAddress
ExtID map[types.NodeName]string ExtID map[types.NodeName]string
...@@ -234,6 +238,13 @@ func (f *FakeCloud) InstanceTypeByProviderID(providerID string) (string, error) ...@@ -234,6 +238,13 @@ func (f *FakeCloud) InstanceTypeByProviderID(providerID string) (string, error)
return f.InstanceTypes[types.NodeName(providerID)], nil return f.InstanceTypes[types.NodeName(providerID)], nil
} }
// InstanceExistsByProviderID returns true if the instance with the given provider id still exists and is running.
// If false is returned with no error, the instance will be immediately deleted by the cloud controller manager.
func (f *FakeCloud) InstanceExistsByProviderID(providerID string) (bool, error) {
f.addCall("instance-exists-by-provider-id")
return f.ExistsByProviderID, f.ErrByProviderID
}
// List is a test-spy implementation of Instances.List. // List is a test-spy implementation of Instances.List.
// It adds an entry "list" into the internal method call record. // It adds an entry "list" into the internal method call record.
func (f *FakeCloud) List(filter string) ([]types.NodeName, error) { func (f *FakeCloud) List(filter string) ([]types.NodeName, error) {
......
...@@ -27,38 +27,38 @@ func newFirewallMetricContext(request string) *metricContext { ...@@ -27,38 +27,38 @@ func newFirewallMetricContext(request string) *metricContext {
// GetFirewall returns the Firewall by name. // GetFirewall returns the Firewall by name.
func (gce *GCECloud) GetFirewall(name string) (*compute.Firewall, error) { func (gce *GCECloud) GetFirewall(name string) (*compute.Firewall, error) {
mc := newFirewallMetricContext("get") mc := newFirewallMetricContext("get")
v, err := gce.service.Firewalls.Get(gce.NetworkProjectID(), name).Do() v, err := gce.service.Firewalls.Get(gce.projectID, name).Do()
return v, mc.Observe(err) return v, mc.Observe(err)
} }
// CreateFirewall creates the passed firewall // CreateFirewall creates the passed firewall
func (gce *GCECloud) CreateFirewall(f *compute.Firewall) error { func (gce *GCECloud) CreateFirewall(f *compute.Firewall) error {
mc := newFirewallMetricContext("create") mc := newFirewallMetricContext("create")
op, err := gce.service.Firewalls.Insert(gce.NetworkProjectID(), f).Do() op, err := gce.service.Firewalls.Insert(gce.projectID, f).Do()
if err != nil { if err != nil {
return mc.Observe(err) return mc.Observe(err)
} }
return gce.waitForGlobalOpInProject(op, gce.NetworkProjectID(), mc) return gce.waitForGlobalOp(op, mc)
} }
// DeleteFirewall deletes the given firewall rule. // DeleteFirewall deletes the given firewall rule.
func (gce *GCECloud) DeleteFirewall(name string) error { func (gce *GCECloud) DeleteFirewall(name string) error {
mc := newFirewallMetricContext("delete") mc := newFirewallMetricContext("delete")
op, err := gce.service.Firewalls.Delete(gce.NetworkProjectID(), name).Do() op, err := gce.service.Firewalls.Delete(gce.projectID, name).Do()
if err != nil { if err != nil {
return mc.Observe(err) return mc.Observe(err)
} }
return gce.waitForGlobalOpInProject(op, gce.NetworkProjectID(), mc) return gce.waitForGlobalOp(op, mc)
} }
// UpdateFirewall applies the given firewall as an update to an existing service. // UpdateFirewall applies the given firewall as an update to an existing service.
func (gce *GCECloud) UpdateFirewall(f *compute.Firewall) error { func (gce *GCECloud) UpdateFirewall(f *compute.Firewall) error {
mc := newFirewallMetricContext("update") mc := newFirewallMetricContext("update")
op, err := gce.service.Firewalls.Update(gce.NetworkProjectID(), f.Name, f).Do() op, err := gce.service.Firewalls.Update(gce.projectID, f.Name, f).Do()
if err != nil { if err != nil {
return mc.Observe(err) return mc.Observe(err)
} }
return gce.waitForGlobalOpInProject(op, gce.NetworkProjectID(), mc) return gce.waitForGlobalOp(op, mc)
} }
...@@ -17,6 +17,7 @@ limitations under the License. ...@@ -17,6 +17,7 @@ limitations under the License.
package gce package gce
import ( import (
"errors"
"fmt" "fmt"
"net" "net"
"net/http" "net/http"
...@@ -153,6 +154,12 @@ func (gce *GCECloud) ExternalID(nodeName types.NodeName) (string, error) { ...@@ -153,6 +154,12 @@ func (gce *GCECloud) ExternalID(nodeName types.NodeName) (string, error) {
return strconv.FormatUint(inst.ID, 10), nil return strconv.FormatUint(inst.ID, 10), nil
} }
// InstanceExistsByProviderID returns true if the instance with the given provider id still exists and is running.
// If false is returned with no error, the instance will be immediately deleted by the cloud controller manager.
func (gce *GCECloud) InstanceExistsByProviderID(providerID string) (bool, error) {
return false, errors.New("unimplemented")
}
// InstanceID returns the cloud provider ID of the node with the specified NodeName. // InstanceID returns the cloud provider ID of the node with the specified NodeName.
func (gce *GCECloud) InstanceID(nodeName types.NodeName) (string, error) { func (gce *GCECloud) InstanceID(nodeName types.NodeName) (string, error) {
instanceName := mapNodeNameToInstanceName(nodeName) instanceName := mapNodeNameToInstanceName(nodeName)
......
...@@ -729,7 +729,7 @@ func (gce *GCECloud) firewallNeedsUpdate(name, serviceName, region, ipAddress st ...@@ -729,7 +729,7 @@ func (gce *GCECloud) firewallNeedsUpdate(name, serviceName, region, ipAddress st
return false, false, nil return false, false, nil
} }
fw, err := gce.service.Firewalls.Get(gce.NetworkProjectID(), makeFirewallName(name)).Do() fw, err := gce.service.Firewalls.Get(gce.projectID, makeFirewallName(name)).Do()
if err != nil { if err != nil {
if isHTTPErrorCode(err, http.StatusNotFound) { if isHTTPErrorCode(err, http.StatusNotFound) {
return false, true, nil return false, true, nil
...@@ -776,7 +776,7 @@ func (gce *GCECloud) ensureHttpHealthCheckFirewall(serviceName, ipAddress, regio ...@@ -776,7 +776,7 @@ func (gce *GCECloud) ensureHttpHealthCheckFirewall(serviceName, ipAddress, regio
ports := []v1.ServicePort{{Protocol: "tcp", Port: hcPort}} ports := []v1.ServicePort{{Protocol: "tcp", Port: hcPort}}
fwName := MakeHealthCheckFirewallName(clusterID, hcName, isNodesHealthCheck) fwName := MakeHealthCheckFirewallName(clusterID, hcName, isNodesHealthCheck)
fw, err := gce.service.Firewalls.Get(gce.NetworkProjectID(), fwName).Do() fw, err := gce.service.Firewalls.Get(gce.projectID, fwName).Do()
if err != nil { if err != nil {
if !isHTTPErrorCode(err, http.StatusNotFound) { if !isHTTPErrorCode(err, http.StatusNotFound) {
return fmt.Errorf("error getting firewall for health checks: %v", err) return fmt.Errorf("error getting firewall for health checks: %v", err)
......
...@@ -93,74 +93,62 @@ func getErrorFromOp(op *computev1.Operation) error { ...@@ -93,74 +93,62 @@ func getErrorFromOp(op *computev1.Operation) error {
} }
func (gce *GCECloud) waitForGlobalOp(op gceObject, mc *metricContext) error { func (gce *GCECloud) waitForGlobalOp(op gceObject, mc *metricContext) error {
return gce.waitForGlobalOpInProject(op, gce.ProjectID(), mc)
}
func (gce *GCECloud) waitForRegionOp(op gceObject, region string, mc *metricContext) error {
return gce.waitForRegionOpInProject(op, gce.ProjectID(), region, mc)
}
func (gce *GCECloud) waitForZoneOp(op gceObject, zone string, mc *metricContext) error {
return gce.waitForZoneOpInProject(op, gce.ProjectID(), zone, mc)
}
func (gce *GCECloud) waitForGlobalOpInProject(op gceObject, projectID string, mc *metricContext) error {
switch v := op.(type) { switch v := op.(type) {
case *computealpha.Operation: case *computealpha.Operation:
return gce.waitForOp(convertToV1Operation(op), func(operationName string) (*computev1.Operation, error) { return gce.waitForOp(convertToV1Operation(op), func(operationName string) (*computev1.Operation, error) {
op, err := gce.serviceAlpha.GlobalOperations.Get(projectID, operationName).Do() op, err := gce.serviceAlpha.GlobalOperations.Get(gce.projectID, operationName).Do()
return convertToV1Operation(op), err return convertToV1Operation(op), err
}, mc) }, mc)
case *computebeta.Operation: case *computebeta.Operation:
return gce.waitForOp(convertToV1Operation(op), func(operationName string) (*computev1.Operation, error) { return gce.waitForOp(convertToV1Operation(op), func(operationName string) (*computev1.Operation, error) {
op, err := gce.serviceBeta.GlobalOperations.Get(projectID, operationName).Do() op, err := gce.serviceBeta.GlobalOperations.Get(gce.projectID, operationName).Do()
return convertToV1Operation(op), err return convertToV1Operation(op), err
}, mc) }, mc)
case *computev1.Operation: case *computev1.Operation:
return gce.waitForOp(op.(*computev1.Operation), func(operationName string) (*computev1.Operation, error) { return gce.waitForOp(op.(*computev1.Operation), func(operationName string) (*computev1.Operation, error) {
return gce.service.GlobalOperations.Get(projectID, operationName).Do() return gce.service.GlobalOperations.Get(gce.projectID, operationName).Do()
}, mc) }, mc)
default: default:
return fmt.Errorf("unexpected type: %T", v) return fmt.Errorf("unexpected type: %T", v)
} }
} }
func (gce *GCECloud) waitForRegionOpInProject(op gceObject, projectID, region string, mc *metricContext) error { func (gce *GCECloud) waitForRegionOp(op gceObject, region string, mc *metricContext) error {
switch v := op.(type) { switch v := op.(type) {
case *computealpha.Operation: case *computealpha.Operation:
return gce.waitForOp(convertToV1Operation(op), func(operationName string) (*computev1.Operation, error) { return gce.waitForOp(convertToV1Operation(op), func(operationName string) (*computev1.Operation, error) {
op, err := gce.serviceAlpha.RegionOperations.Get(projectID, region, operationName).Do() op, err := gce.serviceAlpha.RegionOperations.Get(gce.projectID, region, operationName).Do()
return convertToV1Operation(op), err return convertToV1Operation(op), err
}, mc) }, mc)
case *computebeta.Operation: case *computebeta.Operation:
return gce.waitForOp(convertToV1Operation(op), func(operationName string) (*computev1.Operation, error) { return gce.waitForOp(convertToV1Operation(op), func(operationName string) (*computev1.Operation, error) {
op, err := gce.serviceBeta.RegionOperations.Get(projectID, region, operationName).Do() op, err := gce.serviceBeta.RegionOperations.Get(gce.projectID, region, operationName).Do()
return convertToV1Operation(op), err return convertToV1Operation(op), err
}, mc) }, mc)
case *computev1.Operation: case *computev1.Operation:
return gce.waitForOp(op.(*computev1.Operation), func(operationName string) (*computev1.Operation, error) { return gce.waitForOp(op.(*computev1.Operation), func(operationName string) (*computev1.Operation, error) {
return gce.service.RegionOperations.Get(projectID, region, operationName).Do() return gce.service.RegionOperations.Get(gce.projectID, region, operationName).Do()
}, mc) }, mc)
default: default:
return fmt.Errorf("unexpected type: %T", v) return fmt.Errorf("unexpected type: %T", v)
} }
} }
func (gce *GCECloud) waitForZoneOpInProject(op gceObject, projectID, zone string, mc *metricContext) error { func (gce *GCECloud) waitForZoneOp(op gceObject, zone string, mc *metricContext) error {
switch v := op.(type) { switch v := op.(type) {
case *computealpha.Operation: case *computealpha.Operation:
return gce.waitForOp(convertToV1Operation(op), func(operationName string) (*computev1.Operation, error) { return gce.waitForOp(convertToV1Operation(op), func(operationName string) (*computev1.Operation, error) {
op, err := gce.serviceAlpha.ZoneOperations.Get(projectID, zone, operationName).Do() op, err := gce.serviceAlpha.ZoneOperations.Get(gce.projectID, zone, operationName).Do()
return convertToV1Operation(op), err return convertToV1Operation(op), err
}, mc) }, mc)
case *computebeta.Operation: case *computebeta.Operation:
return gce.waitForOp(convertToV1Operation(op), func(operationName string) (*computev1.Operation, error) { return gce.waitForOp(convertToV1Operation(op), func(operationName string) (*computev1.Operation, error) {
op, err := gce.serviceBeta.ZoneOperations.Get(projectID, zone, operationName).Do() op, err := gce.serviceBeta.ZoneOperations.Get(gce.projectID, zone, operationName).Do()
return convertToV1Operation(op), err return convertToV1Operation(op), err
}, mc) }, mc)
case *computev1.Operation: case *computev1.Operation:
return gce.waitForOp(op.(*computev1.Operation), func(operationName string) (*computev1.Operation, error) { return gce.waitForOp(op.(*computev1.Operation), func(operationName string) (*computev1.Operation, error) {
return gce.service.ZoneOperations.Get(projectID, zone, operationName).Do() return gce.service.ZoneOperations.Get(gce.projectID, zone, operationName).Do()
}, mc) }, mc)
default: default:
return fmt.Errorf("unexpected type: %T", v) return fmt.Errorf("unexpected type: %T", v)
......
...@@ -38,13 +38,13 @@ func (gce *GCECloud) ListRoutes(clusterName string) ([]*cloudprovider.Route, err ...@@ -38,13 +38,13 @@ func (gce *GCECloud) ListRoutes(clusterName string) ([]*cloudprovider.Route, err
page := 0 page := 0
for ; page == 0 || (pageToken != "" && page < maxPages); page++ { for ; page == 0 || (pageToken != "" && page < maxPages); page++ {
mc := newRoutesMetricContext("list_page") mc := newRoutesMetricContext("list_page")
listCall := gce.service.Routes.List(gce.NetworkProjectID()) listCall := gce.service.Routes.List(gce.projectID)
prefix := truncateClusterName(clusterName) prefix := truncateClusterName(clusterName)
// Filter for routes starting with clustername AND belonging to the // Filter for routes starting with clustername AND belonging to the
// relevant gcp network AND having description = "k8s-node-route". // relevant gcp network AND having description = "k8s-node-route".
filter := "(name eq " + prefix + "-.*) " filter := "(name eq " + prefix + "-.*) "
filter = filter + "(network eq " + gce.NetworkURL() + ") " filter = filter + "(network eq " + gce.networkURL + ") "
filter = filter + "(description eq " + k8sNodeRouteTag + ")" filter = filter + "(description eq " + k8sNodeRouteTag + ")"
listCall = listCall.Filter(filter) listCall = listCall.Filter(filter)
if pageToken != "" { if pageToken != "" {
...@@ -80,11 +80,11 @@ func (gce *GCECloud) CreateRoute(clusterName string, nameHint string, route *clo ...@@ -80,11 +80,11 @@ func (gce *GCECloud) CreateRoute(clusterName string, nameHint string, route *clo
} }
mc := newRoutesMetricContext("create") mc := newRoutesMetricContext("create")
insertOp, err := gce.service.Routes.Insert(gce.NetworkProjectID(), &compute.Route{ insertOp, err := gce.service.Routes.Insert(gce.projectID, &compute.Route{
Name: routeName, Name: routeName,
DestRange: route.DestinationCIDR, DestRange: route.DestinationCIDR,
NextHopInstance: fmt.Sprintf("zones/%s/instances/%s", targetInstance.Zone, targetInstance.Name), NextHopInstance: fmt.Sprintf("zones/%s/instances/%s", targetInstance.Zone, targetInstance.Name),
Network: gce.NetworkURL(), Network: gce.networkURL,
Priority: 1000, Priority: 1000,
Description: k8sNodeRouteTag, Description: k8sNodeRouteTag,
}).Do() }).Do()
...@@ -96,16 +96,16 @@ func (gce *GCECloud) CreateRoute(clusterName string, nameHint string, route *clo ...@@ -96,16 +96,16 @@ func (gce *GCECloud) CreateRoute(clusterName string, nameHint string, route *clo
return mc.Observe(err) return mc.Observe(err)
} }
} }
return gce.waitForGlobalOpInProject(insertOp, gce.NetworkProjectID(), mc) return gce.waitForGlobalOp(insertOp, mc)
} }
func (gce *GCECloud) DeleteRoute(clusterName string, route *cloudprovider.Route) error { func (gce *GCECloud) DeleteRoute(clusterName string, route *cloudprovider.Route) error {
mc := newRoutesMetricContext("delete") mc := newRoutesMetricContext("delete")
deleteOp, err := gce.service.Routes.Delete(gce.NetworkProjectID(), route.Name).Do() deleteOp, err := gce.service.Routes.Delete(gce.projectID, route.Name).Do()
if err != nil { if err != nil {
return mc.Observe(err) return mc.Observe(err)
} }
return gce.waitForGlobalOpInProject(deleteOp, gce.NetworkProjectID(), mc) return gce.waitForGlobalOp(deleteOp, mc)
} }
func truncateClusterName(clusterName string) string { func truncateClusterName(clusterName string) string {
......
...@@ -110,6 +110,12 @@ func (i *Instances) ExternalID(name types.NodeName) (string, error) { ...@@ -110,6 +110,12 @@ func (i *Instances) ExternalID(name types.NodeName) (string, error) {
return srv.ID, nil return srv.ID, nil
} }
// InstanceExistsByProviderID returns true if the instance with the given provider id still exists and is running.
// If false is returned with no error, the instance will be immediately deleted by the cloud controller manager.
func (i *Instances) InstanceExistsByProviderID(providerID string) (bool, error) {
return false, errors.New("unimplemented")
}
// InstanceID returns the kubelet's cloud provider ID. // InstanceID returns the kubelet's cloud provider ID.
func (os *OpenStack) InstanceID() (string, error) { func (os *OpenStack) InstanceID() (string, error) {
if len(os.localInstanceID) == 0 { if len(os.localInstanceID) == 0 {
......
...@@ -211,6 +211,12 @@ func (v *OVirtCloud) ExternalID(nodeName types.NodeName) (string, error) { ...@@ -211,6 +211,12 @@ func (v *OVirtCloud) ExternalID(nodeName types.NodeName) (string, error) {
return instance.UUID, nil return instance.UUID, nil
} }
// InstanceExistsByProviderID returns true if the instance with the given provider id still exists and is running.
// If false is returned with no error, the instance will be immediately deleted by the cloud controller manager.
func (v *OVirtCloud) InstanceExistsByProviderID(providerID string) (bool, error) {
return false, errors.New("unimplemented")
}
// InstanceID returns the cloud provider ID of the node with the specified NodeName. // InstanceID returns the cloud provider ID of the node with the specified NodeName.
func (v *OVirtCloud) InstanceID(nodeName types.NodeName) (string, error) { func (v *OVirtCloud) InstanceID(nodeName types.NodeName) (string, error) {
name := mapNodeNameToInstanceName(nodeName) name := mapNodeNameToInstanceName(nodeName)
......
...@@ -470,6 +470,12 @@ func (pc *PCCloud) ExternalID(nodeName k8stypes.NodeName) (string, error) { ...@@ -470,6 +470,12 @@ func (pc *PCCloud) ExternalID(nodeName k8stypes.NodeName) (string, error) {
} }
} }
// InstanceExistsByProviderID returns true if the instance with the given provider id still exists and is running.
// If false is returned with no error, the instance will be immediately deleted by the cloud controller manager.
func (pc *PCCloud) InstanceExistsByProviderID(providerID string) (bool, error) {
return false, errors.New("unimplemented")
}
// InstanceID returns the cloud provider ID of the specified instance. // InstanceID returns the cloud provider ID of the specified instance.
func (pc *PCCloud) InstanceID(nodeName k8stypes.NodeName) (string, error) { func (pc *PCCloud) InstanceID(nodeName k8stypes.NodeName) (string, error) {
name := string(nodeName) name := string(nodeName)
......
...@@ -436,6 +436,12 @@ func (i *Instances) ExternalID(nodeName types.NodeName) (string, error) { ...@@ -436,6 +436,12 @@ func (i *Instances) ExternalID(nodeName types.NodeName) (string, error) {
return probeInstanceID(i.compute, serverName) return probeInstanceID(i.compute, serverName)
} }
// InstanceExistsByProviderID returns true if the instance with the given provider id still exists and is running.
// If false is returned with no error, the instance will be immediately deleted by the cloud controller manager.
func (i *Instances) InstanceExistsByProviderID(providerID string) (bool, error) {
return false, errors.New("unimplemented")
}
// InstanceID returns the cloud provider ID of the kubelet's instance. // InstanceID returns the cloud provider ID of the kubelet's instance.
func (rs *Rackspace) InstanceID() (string, error) { func (rs *Rackspace) InstanceID() (string, error) {
return readInstanceID() return readInstanceID()
......
...@@ -376,6 +376,12 @@ func (vs *VSphere) ExternalID(nodeName k8stypes.NodeName) (string, error) { ...@@ -376,6 +376,12 @@ func (vs *VSphere) ExternalID(nodeName k8stypes.NodeName) (string, error) {
return vs.InstanceID(nodeName) return vs.InstanceID(nodeName)
} }
// InstanceExistsByProviderID returns true if the instance with the given provider id still exists and is running.
// If false is returned with no error, the instance will be immediately deleted by the cloud controller manager.
func (vs *VSphere) InstanceExistsByProviderID(providerID string) (bool, error) {
return false, errors.New("unimplemented")
}
// InstanceID returns the cloud provider ID of the node with the specified Name. // InstanceID returns the cloud provider ID of the node with the specified Name.
func (vs *VSphere) InstanceID(nodeName k8stypes.NodeName) (string, error) { func (vs *VSphere) InstanceID(nodeName k8stypes.NodeName) (string, error) {
if vs.localInstanceID == nodeNameToVMName(nodeName) { if vs.localInstanceID == nodeNameToVMName(nodeName) {
......
...@@ -237,26 +237,36 @@ func (cnc *CloudNodeController) MonitorNode() { ...@@ -237,26 +237,36 @@ func (cnc *CloudNodeController) MonitorNode() {
if currentReadyCondition.Status != v1.ConditionTrue { if currentReadyCondition.Status != v1.ConditionTrue {
// Check with the cloud provider to see if the node still exists. If it // Check with the cloud provider to see if the node still exists. If it
// doesn't, delete the node immediately. // doesn't, delete the node immediately.
if _, err := instances.ExternalID(types.NodeName(node.Name)); err != nil { exists, err := ensureNodeExistsByProviderIDOrExternalID(instances, node)
if err == cloudprovider.InstanceNotFound { if err != nil {
glog.V(2).Infof("Deleting node no longer present in cloud provider: %s", node.Name) glog.Errorf("Error getting data for node %s from cloud: %v", node.Name, err)
ref := &v1.ObjectReference{ continue
Kind: "Node", }
Name: node.Name,
UID: types.UID(node.UID), if exists {
Namespace: "", // Continue checking the remaining nodes since the current one is fine.
} continue
glog.V(2).Infof("Recording %s event message for node %s", "DeletingNode", node.Name) }
cnc.recorder.Eventf(ref, v1.EventTypeNormal, fmt.Sprintf("Deleting Node %v because it's not present according to cloud provider", node.Name), "Node %s event: %s", node.Name, "DeletingNode")
go func(nodeName string) { glog.V(2).Infof("Deleting node since it is no longer present in cloud provider: %s", node.Name)
defer utilruntime.HandleCrash()
if err := cnc.kubeClient.CoreV1().Nodes().Delete(node.Name, nil); err != nil { ref := &v1.ObjectReference{
glog.Errorf("unable to delete node %q: %v", node.Name, err) Kind: "Node",
} Name: node.Name,
}(node.Name) UID: types.UID(node.UID),
} Namespace: "",
glog.Errorf("Error getting node data from cloud: %v", err)
} }
glog.V(2).Infof("Recording %s event message for node %s", "DeletingNode", node.Name)
cnc.recorder.Eventf(ref, v1.EventTypeNormal, fmt.Sprintf("Deleting Node %v because it's not present according to cloud provider", node.Name), "Node %s event: %s", node.Name, "DeletingNode")
go func(nodeName string) {
defer utilruntime.HandleCrash()
if err := cnc.kubeClient.CoreV1().Nodes().Delete(nodeName, nil); err != nil {
glog.Errorf("unable to delete node %q: %v", nodeName, err)
}
}(node.Name)
} }
} }
} }
...@@ -384,6 +394,25 @@ func excludeTaintFromList(taints []v1.Taint, toExclude v1.Taint) []v1.Taint { ...@@ -384,6 +394,25 @@ func excludeTaintFromList(taints []v1.Taint, toExclude v1.Taint) []v1.Taint {
return newTaints return newTaints
} }
// ensureNodeExistsByProviderIDOrExternalID first checks if the instance exists by the provider id and then by calling external id with node name
func ensureNodeExistsByProviderIDOrExternalID(instances cloudprovider.Instances, node *v1.Node) (bool, error) {
exists, err := instances.InstanceExistsByProviderID(node.Spec.ProviderID)
if err != nil {
providerIDErr := err
_, err = instances.ExternalID(types.NodeName(node.Name))
if err == nil {
return true, nil
}
if err == cloudprovider.InstanceNotFound {
return false, nil
}
return false, fmt.Errorf("InstanceExistsByProviderID: Error fetching by providerID: %v Error fetching by NodeName: %v", providerIDErr, err)
}
return exists, nil
}
func getNodeAddressesByProviderIDOrName(instances cloudprovider.Instances, node *v1.Node) ([]v1.NodeAddress, error) { func getNodeAddressesByProviderIDOrName(instances cloudprovider.Instances, node *v1.Node) ([]v1.NodeAddress, error) {
nodeAddresses, err := instances.NodeAddressesByProviderID(node.Spec.ProviderID) nodeAddresses, err := instances.NodeAddressesByProviderID(node.Spec.ProviderID)
if err != nil { if err != nil {
......
...@@ -17,6 +17,8 @@ limitations under the License. ...@@ -17,6 +17,8 @@ limitations under the License.
package cloud package cloud
import ( import (
"errors"
"reflect"
"testing" "testing"
"time" "time"
...@@ -39,6 +41,119 @@ import ( ...@@ -39,6 +41,119 @@ import (
"k8s.io/kubernetes/plugin/pkg/scheduler/algorithm" "k8s.io/kubernetes/plugin/pkg/scheduler/algorithm"
) )
func TestEnsureNodeExistsByProviderIDOrNodeName(t *testing.T) {
testCases := []struct {
testName string
node *v1.Node
expectedCalls []string
existsByNodeName bool
existsByProviderID bool
nodeNameErr error
providerIDErr error
}{
{
testName: "node exists by provider id",
existsByProviderID: true,
providerIDErr: nil,
existsByNodeName: false,
nodeNameErr: errors.New("unimplemented"),
expectedCalls: []string{"instance-exists-by-provider-id"},
node: &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: "node0",
},
Spec: v1.NodeSpec{
ProviderID: "node0",
},
},
},
{
testName: "does not exist by provider id",
existsByProviderID: false,
providerIDErr: nil,
existsByNodeName: false,
nodeNameErr: errors.New("unimplemented"),
expectedCalls: []string{"instance-exists-by-provider-id"},
node: &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: "node0",
},
Spec: v1.NodeSpec{
ProviderID: "node0",
},
},
},
{
testName: "node exists by node name",
existsByProviderID: false,
providerIDErr: errors.New("unimplemented"),
existsByNodeName: true,
nodeNameErr: nil,
expectedCalls: []string{"instance-exists-by-provider-id", "external-id"},
node: &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: "node0",
},
Spec: v1.NodeSpec{
ProviderID: "node0",
},
},
},
{
testName: "does not exist by node name",
existsByProviderID: false,
providerIDErr: errors.New("unimplemented"),
existsByNodeName: false,
nodeNameErr: cloudprovider.InstanceNotFound,
expectedCalls: []string{"instance-exists-by-provider-id", "external-id"},
node: &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: "node0",
},
Spec: v1.NodeSpec{
ProviderID: "node0",
},
},
},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
fc := &fakecloud.FakeCloud{
Exists: tc.existsByNodeName,
ExistsByProviderID: tc.existsByProviderID,
Err: tc.nodeNameErr,
ErrByProviderID: tc.providerIDErr,
}
instances, _ := fc.Instances()
exists, err := ensureNodeExistsByProviderIDOrExternalID(instances, tc.node)
if err != nil {
t.Error(err)
}
if !reflect.DeepEqual(fc.Calls, tc.expectedCalls) {
t.Errorf("expected cloud provider methods `%v` to be called but `%v` was called ", tc.expectedCalls, fc.Calls)
}
if tc.existsByProviderID && tc.existsByProviderID != exists {
t.Errorf("expected exist by provider id to be `%t` but got `%t`", tc.existsByProviderID, exists)
}
if tc.existsByNodeName && tc.existsByNodeName != exists {
t.Errorf("expected exist by node name to be `%t` but got `%t`", tc.existsByNodeName, exists)
}
if !tc.existsByNodeName && !tc.existsByProviderID && exists {
t.Error("node is not supposed to exist")
}
})
}
}
// This test checks that the node is deleted when kubelet stops reporting // This test checks that the node is deleted when kubelet stops reporting
// and cloud provider says node is gone // and cloud provider says node is gone
func TestNodeDeleted(t *testing.T) { func TestNodeDeleted(t *testing.T) {
...@@ -105,9 +220,12 @@ func TestNodeDeleted(t *testing.T) { ...@@ -105,9 +220,12 @@ func TestNodeDeleted(t *testing.T) {
eventBroadcaster := record.NewBroadcaster() eventBroadcaster := record.NewBroadcaster()
cloudNodeController := &CloudNodeController{ cloudNodeController := &CloudNodeController{
kubeClient: fnh, kubeClient: fnh,
nodeInformer: factory.Core().V1().Nodes(), nodeInformer: factory.Core().V1().Nodes(),
cloud: &fakecloud.FakeCloud{Err: cloudprovider.InstanceNotFound}, cloud: &fakecloud.FakeCloud{
ExistsByProviderID: false,
Err: nil,
},
nodeMonitorPeriod: 1 * time.Second, nodeMonitorPeriod: 1 * time.Second,
recorder: eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "cloud-controller-manager"}), recorder: eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "cloud-controller-manager"}),
nodeStatusUpdateFrequency: 1 * time.Second, nodeStatusUpdateFrequency: 1 * time.Second,
...@@ -520,7 +638,8 @@ func TestNodeAddresses(t *testing.T) { ...@@ -520,7 +638,8 @@ func TestNodeAddresses(t *testing.T) {
FailureDomain: "us-west-1a", FailureDomain: "us-west-1a",
Region: "us-west", Region: "us-west",
}, },
Err: nil, ExistsByProviderID: true,
Err: nil,
} }
eventBroadcaster := record.NewBroadcaster() eventBroadcaster := record.NewBroadcaster()
...@@ -639,7 +758,8 @@ func TestNodeProvidedIPAddresses(t *testing.T) { ...@@ -639,7 +758,8 @@ func TestNodeProvidedIPAddresses(t *testing.T) {
FailureDomain: "us-west-1a", FailureDomain: "us-west-1a",
Region: "us-west", Region: "us-west",
}, },
Err: nil, ExistsByProviderID: true,
Err: nil,
} }
eventBroadcaster := record.NewBroadcaster() eventBroadcaster := record.NewBroadcaster()
......
...@@ -183,14 +183,16 @@ func (nm *NamespaceController) Run(workers int, stopCh <-chan struct{}) { ...@@ -183,14 +183,16 @@ func (nm *NamespaceController) Run(workers int, stopCh <-chan struct{}) {
defer utilruntime.HandleCrash() defer utilruntime.HandleCrash()
defer nm.queue.ShutDown() defer nm.queue.ShutDown()
glog.Infof("Starting namespace controller")
defer glog.Infof("Shutting down namespace controller")
if !controller.WaitForCacheSync("namespace", stopCh, nm.listerSynced) { if !controller.WaitForCacheSync("namespace", stopCh, nm.listerSynced) {
return return
} }
glog.V(5).Info("Starting workers") glog.V(5).Info("Starting workers of namespace controller")
for i := 0; i < workers; i++ { for i := 0; i < workers; i++ {
go wait.Until(nm.worker, time.Second, stopCh) go wait.Until(nm.worker, time.Second, stopCh)
} }
<-stopCh <-stopCh
glog.V(1).Infof("Shutting down")
} }
...@@ -45,6 +45,7 @@ go_test( ...@@ -45,6 +45,7 @@ go_test(
"//pkg/controller:go_default_library", "//pkg/controller:go_default_library",
"//pkg/controller/volume/attachdetach/cache:go_default_library", "//pkg/controller/volume/attachdetach/cache:go_default_library",
"//pkg/controller/volume/attachdetach/testing:go_default_library", "//pkg/controller/volume/attachdetach/testing:go_default_library",
"//pkg/volume:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library", "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
......
...@@ -97,6 +97,7 @@ func NewAttachDetachController( ...@@ -97,6 +97,7 @@ func NewAttachDetachController(
pvInformer coreinformers.PersistentVolumeInformer, pvInformer coreinformers.PersistentVolumeInformer,
cloud cloudprovider.Interface, cloud cloudprovider.Interface,
plugins []volume.VolumePlugin, plugins []volume.VolumePlugin,
prober volume.DynamicPluginProber,
disableReconciliationSync bool, disableReconciliationSync bool,
reconcilerSyncDuration time.Duration, reconcilerSyncDuration time.Duration,
timerConfig TimerConfig) (AttachDetachController, error) { timerConfig TimerConfig) (AttachDetachController, error) {
...@@ -127,7 +128,7 @@ func NewAttachDetachController( ...@@ -127,7 +128,7 @@ func NewAttachDetachController(
cloud: cloud, cloud: cloud,
} }
if err := adc.volumePluginMgr.InitPlugins(plugins, adc); err != nil { if err := adc.volumePluginMgr.InitPlugins(plugins, prober, adc); err != nil {
return nil, fmt.Errorf("Could not initialize volume plugins for Attach/Detach Controller: %+v", err) return nil, fmt.Errorf("Could not initialize volume plugins for Attach/Detach Controller: %+v", err)
} }
......
...@@ -29,6 +29,7 @@ import ( ...@@ -29,6 +29,7 @@ import (
"k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/controller"
"k8s.io/kubernetes/pkg/controller/volume/attachdetach/cache" "k8s.io/kubernetes/pkg/controller/volume/attachdetach/cache"
controllervolumetesting "k8s.io/kubernetes/pkg/controller/volume/attachdetach/testing" controllervolumetesting "k8s.io/kubernetes/pkg/controller/volume/attachdetach/testing"
"k8s.io/kubernetes/pkg/volume"
) )
func Test_NewAttachDetachController_Positive(t *testing.T) { func Test_NewAttachDetachController_Positive(t *testing.T) {
...@@ -45,6 +46,7 @@ func Test_NewAttachDetachController_Positive(t *testing.T) { ...@@ -45,6 +46,7 @@ func Test_NewAttachDetachController_Positive(t *testing.T) {
informerFactory.Core().V1().PersistentVolumes(), informerFactory.Core().V1().PersistentVolumes(),
nil, /* cloud */ nil, /* cloud */
nil, /* plugins */ nil, /* plugins */
nil, /* prober */
false, false,
5*time.Second, 5*time.Second,
DefaultTimerConfig) DefaultTimerConfig)
...@@ -79,8 +81,9 @@ func Test_AttachDetachControllerStateOfWolrdPopulators_Positive(t *testing.T) { ...@@ -79,8 +81,9 @@ func Test_AttachDetachControllerStateOfWolrdPopulators_Positive(t *testing.T) {
// Act // Act
plugins := controllervolumetesting.CreateTestPlugin() plugins := controllervolumetesting.CreateTestPlugin()
var prober volume.DynamicPluginProber = nil // TODO (#51147) inject mock
if err := adc.volumePluginMgr.InitPlugins(plugins, adc); err != nil { if err := adc.volumePluginMgr.InitPlugins(plugins, prober, adc); err != nil {
t.Fatalf("Could not initialize volume plugins for Attach/Detach Controller: %+v", err) t.Fatalf("Could not initialize volume plugins for Attach/Detach Controller: %+v", err)
} }
...@@ -141,6 +144,7 @@ func attachDetachRecoveryTestCase(t *testing.T, extraPods1 []*v1.Pod, extraPods2 ...@@ -141,6 +144,7 @@ func attachDetachRecoveryTestCase(t *testing.T, extraPods1 []*v1.Pod, extraPods2
informerFactory := informers.NewSharedInformerFactory(fakeKubeClient, time.Second*1) informerFactory := informers.NewSharedInformerFactory(fakeKubeClient, time.Second*1)
//informerFactory := informers.NewSharedInformerFactory(fakeKubeClient, time.Second*1) //informerFactory := informers.NewSharedInformerFactory(fakeKubeClient, time.Second*1)
plugins := controllervolumetesting.CreateTestPlugin() plugins := controllervolumetesting.CreateTestPlugin()
var prober volume.DynamicPluginProber = nil // TODO (#51147) inject mock
nodeInformer := informerFactory.Core().V1().Nodes().Informer() nodeInformer := informerFactory.Core().V1().Nodes().Informer()
podInformer := informerFactory.Core().V1().Pods().Informer() podInformer := informerFactory.Core().V1().Pods().Informer()
var podsNum, extraPodsNum, nodesNum, i int var podsNum, extraPodsNum, nodesNum, i int
...@@ -212,6 +216,7 @@ func attachDetachRecoveryTestCase(t *testing.T, extraPods1 []*v1.Pod, extraPods2 ...@@ -212,6 +216,7 @@ func attachDetachRecoveryTestCase(t *testing.T, extraPods1 []*v1.Pod, extraPods2
informerFactory.Core().V1().PersistentVolumes(), informerFactory.Core().V1().PersistentVolumes(),
nil, /* cloud */ nil, /* cloud */
plugins, plugins,
prober,
false, false,
1*time.Second, 1*time.Second,
DefaultTimerConfig) DefaultTimerConfig)
......
...@@ -827,7 +827,7 @@ func wrapTestWithPluginCalls(expectedRecycleCalls, expectedDeleteCalls []error, ...@@ -827,7 +827,7 @@ func wrapTestWithPluginCalls(expectedRecycleCalls, expectedDeleteCalls []error,
deleteCalls: expectedDeleteCalls, deleteCalls: expectedDeleteCalls,
provisionCalls: expectedProvisionCalls, provisionCalls: expectedProvisionCalls,
} }
ctrl.volumePluginMgr.InitPlugins([]vol.VolumePlugin{plugin}, ctrl) ctrl.volumePluginMgr.InitPlugins([]vol.VolumePlugin{plugin}, nil /* prober */, ctrl)
return toWrap(ctrl, reactor, test) return toWrap(ctrl, reactor, test)
} }
} }
......
...@@ -90,7 +90,8 @@ func NewController(p ControllerParameters) (*PersistentVolumeController, error) ...@@ -90,7 +90,8 @@ func NewController(p ControllerParameters) (*PersistentVolumeController, error)
resyncPeriod: p.SyncPeriod, resyncPeriod: p.SyncPeriod,
} }
if err := controller.volumePluginMgr.InitPlugins(p.VolumePlugins, controller); err != nil { // Prober is nil because PV is not aware of Flexvolume.
if err := controller.volumePluginMgr.InitPlugins(p.VolumePlugins, nil /* prober */, controller); err != nil {
return nil, fmt.Errorf("Could not initialize volume plugins for PersistentVolume Controller: %v", err) return nil, fmt.Errorf("Could not initialize volume plugins for PersistentVolume Controller: %v", err)
} }
......
...@@ -214,7 +214,7 @@ func (s *PodDisruptionBudgetV2Generator) validate() error { ...@@ -214,7 +214,7 @@ func (s *PodDisruptionBudgetV2Generator) validate() error {
return fmt.Errorf("a selector must be specified") return fmt.Errorf("a selector must be specified")
} }
if len(s.MaxUnavailable) > 0 && len(s.MinAvailable) > 0 { if len(s.MaxUnavailable) > 0 && len(s.MinAvailable) > 0 {
return fmt.Errorf("exactly one of min-available and max-available must be specified") return fmt.Errorf("min-available and max-unavailable cannot be both specified")
} }
return nil return nil
} }
...@@ -35,18 +35,9 @@ func CapacityFromMachineInfo(info *cadvisorapi.MachineInfo) v1.ResourceList { ...@@ -35,18 +35,9 @@ func CapacityFromMachineInfo(info *cadvisorapi.MachineInfo) v1.ResourceList {
return c return c
} }
func StorageScratchCapacityFromFsInfo(info cadvisorapi2.FsInfo) v1.ResourceList { func EphemeralStorageCapacityFromFsInfo(info cadvisorapi2.FsInfo) v1.ResourceList {
c := v1.ResourceList{ c := v1.ResourceList{
v1.ResourceStorageScratch: *resource.NewQuantity( v1.ResourceEphemeralStorage: *resource.NewQuantity(
int64(info.Capacity),
resource.BinarySI),
}
return c
}
func StorageOverlayCapacityFromFsInfo(info cadvisorapi2.FsInfo) v1.ResourceList {
c := v1.ResourceList{
v1.ResourceStorageOverlay: *resource.NewQuantity(
int64(info.Capacity), int64(info.Capacity),
resource.BinarySI), resource.BinarySI),
} }
......
...@@ -55,7 +55,6 @@ go_library( ...@@ -55,7 +55,6 @@ go_library(
"//pkg/util/procfs:go_default_library", "//pkg/util/procfs:go_default_library",
"//pkg/util/sysctl:go_default_library", "//pkg/util/sysctl:go_default_library",
"//pkg/util/version:go_default_library", "//pkg/util/version:go_default_library",
"//vendor/github.com/google/cadvisor/info/v2:go_default_library",
"//vendor/github.com/opencontainers/runc/libcontainer/cgroups:go_default_library", "//vendor/github.com/opencontainers/runc/libcontainer/cgroups:go_default_library",
"//vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs:go_default_library", "//vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs:go_default_library",
"//vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd:go_default_library", "//vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd:go_default_library",
......
...@@ -233,7 +233,7 @@ func (m *cgroupManagerImpl) Exists(name CgroupName) bool { ...@@ -233,7 +233,7 @@ func (m *cgroupManagerImpl) Exists(name CgroupName) bool {
// scoped to the set control groups it understands. this is being discussed // scoped to the set control groups it understands. this is being discussed
// in https://github.com/opencontainers/runc/issues/1440 // in https://github.com/opencontainers/runc/issues/1440
// once resolved, we can remove this code. // once resolved, we can remove this code.
whitelistControllers := sets.NewString("cpu", "cpuacct", "cpuset", "memory", "hugetlb", "systemd") whitelistControllers := sets.NewString("cpu", "cpuacct", "cpuset", "memory", "systemd")
// If even one cgroup path doesn't exist, then the cgroup doesn't exist. // If even one cgroup path doesn't exist, then the cgroup doesn't exist.
for controller, path := range cgroupPaths { for controller, path := range cgroupPaths {
......
...@@ -30,7 +30,6 @@ import ( ...@@ -30,7 +30,6 @@ import (
"time" "time"
"github.com/golang/glog" "github.com/golang/glog"
cadvisorapiv2 "github.com/google/cadvisor/info/v2"
"github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/cgroups/fs" "github.com/opencontainers/runc/libcontainer/cgroups/fs"
"github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/configs"
...@@ -552,24 +551,11 @@ func (cm *containerManagerImpl) setFsCapacity() error { ...@@ -552,24 +551,11 @@ func (cm *containerManagerImpl) setFsCapacity() error {
if err != nil { if err != nil {
return fmt.Errorf("Fail to get rootfs information %v", err) return fmt.Errorf("Fail to get rootfs information %v", err)
} }
hasDedicatedImageFs, _ := cm.cadvisorInterface.HasDedicatedImageFs()
var imagesfs cadvisorapiv2.FsInfo
if hasDedicatedImageFs {
imagesfs, err = cm.cadvisorInterface.ImagesFsInfo()
if err != nil {
return fmt.Errorf("Fail to get imagefs information %v", err)
}
}
cm.Lock() cm.Lock()
for rName, rCap := range cadvisor.StorageScratchCapacityFromFsInfo(rootfs) { for rName, rCap := range cadvisor.EphemeralStorageCapacityFromFsInfo(rootfs) {
cm.capacity[rName] = rCap cm.capacity[rName] = rCap
} }
if hasDedicatedImageFs {
for rName, rCap := range cadvisor.StorageOverlayCapacityFromFsInfo(imagesfs) {
cm.capacity[rName] = rCap
}
}
cm.Unlock() cm.Unlock()
return nil return nil
} }
......
...@@ -218,9 +218,9 @@ func hardEvictionReservation(thresholds []evictionapi.Threshold, capacity v1.Res ...@@ -218,9 +218,9 @@ func hardEvictionReservation(thresholds []evictionapi.Threshold, capacity v1.Res
value := evictionapi.GetThresholdQuantity(threshold.Value, &memoryCapacity) value := evictionapi.GetThresholdQuantity(threshold.Value, &memoryCapacity)
ret[v1.ResourceMemory] = *value ret[v1.ResourceMemory] = *value
case evictionapi.SignalNodeFsAvailable: case evictionapi.SignalNodeFsAvailable:
storageCapacity := capacity[v1.ResourceStorageScratch] storageCapacity := capacity[v1.ResourceEphemeralStorage]
value := evictionapi.GetThresholdQuantity(threshold.Value, &storageCapacity) value := evictionapi.GetThresholdQuantity(threshold.Value, &storageCapacity)
ret[v1.ResourceStorageScratch] = *value ret[v1.ResourceEphemeralStorage] = *value
} }
} }
return ret return ret
......
...@@ -316,17 +316,17 @@ func TestNodeAllocatableInputValidation(t *testing.T) { ...@@ -316,17 +316,17 @@ func TestNodeAllocatableInputValidation(t *testing.T) {
invalidConfiguration bool invalidConfiguration bool
}{ }{
{ {
kubeReserved: getScratchResourceList("100Mi"), kubeReserved: getEphemeralStorageResourceList("100Mi"),
systemReserved: getScratchResourceList("50Mi"), systemReserved: getEphemeralStorageResourceList("50Mi"),
capacity: getScratchResourceList("500Mi"), capacity: getEphemeralStorageResourceList("500Mi"),
}, },
{ {
kubeReserved: getScratchResourceList("10Gi"), kubeReserved: getEphemeralStorageResourceList("10Gi"),
systemReserved: getScratchResourceList("10Gi"), systemReserved: getEphemeralStorageResourceList("10Gi"),
hardThreshold: evictionapi.ThresholdValue{ hardThreshold: evictionapi.ThresholdValue{
Quantity: &storageEvictionThreshold, Quantity: &storageEvictionThreshold,
}, },
capacity: getScratchResourceList("20Gi"), capacity: getEphemeralStorageResourceList("20Gi"),
invalidConfiguration: true, invalidConfiguration: true,
}, },
} }
...@@ -359,12 +359,12 @@ func TestNodeAllocatableInputValidation(t *testing.T) { ...@@ -359,12 +359,12 @@ func TestNodeAllocatableInputValidation(t *testing.T) {
} }
} }
// getScratchResourceList returns a ResourceList with the // getEphemeralStorageResourceList returns a ResourceList with the
// specified scratch storage resource values // specified ephemeral storage resource values
func getScratchResourceList(storage string) v1.ResourceList { func getEphemeralStorageResourceList(storage string) v1.ResourceList {
res := v1.ResourceList{} res := v1.ResourceList{}
if storage != "" { if storage != "" {
res[v1.ResourceStorageScratch] = resource.MustParse(storage) res[v1.ResourceEphemeralStorage] = resource.MustParse(storage)
} }
return res return res
} }
...@@ -48,6 +48,7 @@ go_library( ...@@ -48,6 +48,7 @@ go_library(
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/api/v1/helper/qos:go_default_library", "//pkg/api/v1/helper/qos:go_default_library",
"//pkg/api/v1/resource:go_default_library",
"//pkg/features:go_default_library", "//pkg/features:go_default_library",
"//pkg/kubelet/apis/stats/v1alpha1:go_default_library", "//pkg/kubelet/apis/stats/v1alpha1:go_default_library",
"//pkg/kubelet/cm:go_default_library", "//pkg/kubelet/cm:go_default_library",
......
...@@ -31,6 +31,7 @@ import ( ...@@ -31,6 +31,7 @@ import (
utilfeature "k8s.io/apiserver/pkg/util/feature" utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/tools/record" "k8s.io/client-go/tools/record"
v1qos "k8s.io/kubernetes/pkg/api/v1/helper/qos" v1qos "k8s.io/kubernetes/pkg/api/v1/helper/qos"
apiv1resource "k8s.io/kubernetes/pkg/api/v1/resource"
"k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/features"
statsapi "k8s.io/kubernetes/pkg/kubelet/apis/stats/v1alpha1" statsapi "k8s.io/kubernetes/pkg/kubelet/apis/stats/v1alpha1"
"k8s.io/kubernetes/pkg/kubelet/cm" "k8s.io/kubernetes/pkg/kubelet/cm"
...@@ -472,7 +473,12 @@ func (m *managerImpl) localStorageEviction(pods []*v1.Pod) []*v1.Pod { ...@@ -472,7 +473,12 @@ func (m *managerImpl) localStorageEviction(pods []*v1.Pod) []*v1.Pod {
continue continue
} }
if m.containerOverlayLimitEviction(podStats, pod) { if m.podEphemeralStorageLimitEviction(podStats, pod) {
evicted = append(evicted, pod)
continue
}
if m.containerEphemeralStorageLimitEviction(podStats, pod) {
evicted = append(evicted, pod) evicted = append(evicted, pod)
} }
} }
...@@ -496,23 +502,56 @@ func (m *managerImpl) emptyDirLimitEviction(podStats statsapi.PodStats, pod *v1. ...@@ -496,23 +502,56 @@ func (m *managerImpl) emptyDirLimitEviction(podStats statsapi.PodStats, pod *v1.
} }
} }
} }
return false
}
func (m *managerImpl) podEphemeralStorageLimitEviction(podStats statsapi.PodStats, pod *v1.Pod) bool {
_, podLimits := apiv1resource.PodRequestsAndLimits(pod)
_, found := podLimits[v1.ResourceEphemeralStorage]
if !found {
return false
}
podEphemeralStorageTotalUsage := &resource.Quantity{}
fsStatsSet := []fsStatsType{}
if *m.dedicatedImageFs {
fsStatsSet = []fsStatsType{fsStatsLogs, fsStatsLocalVolumeSource}
} else {
fsStatsSet = []fsStatsType{fsStatsRoot, fsStatsLogs, fsStatsLocalVolumeSource}
}
podUsage, err := podDiskUsage(podStats, pod, fsStatsSet)
if err != nil {
glog.Errorf("eviction manager: error getting pod disk usage %v", err)
return false
}
podEphemeralStorageTotalUsage.Add(podUsage[resourceDisk])
if podEphemeralStorageTotalUsage.Cmp(podLimits[v1.ResourceEphemeralStorage]) > 0 {
// the total usage of pod exceeds the total size limit of containers, evict the pod
return m.evictPod(pod, v1.ResourceEphemeralStorage, fmt.Sprintf("pod ephemeral local storage usage exceeds the total limit of containers %v", podLimits[v1.ResourceEphemeralStorage]))
}
return false return false
} }
func (m *managerImpl) containerOverlayLimitEviction(podStats statsapi.PodStats, pod *v1.Pod) bool { func (m *managerImpl) containerEphemeralStorageLimitEviction(podStats statsapi.PodStats, pod *v1.Pod) bool {
thresholdsMap := make(map[string]*resource.Quantity) thresholdsMap := make(map[string]*resource.Quantity)
for _, container := range pod.Spec.Containers { for _, container := range pod.Spec.Containers {
overlayLimit := container.Resources.Limits.StorageOverlay() ephemeralLimit := container.Resources.Limits.StorageEphemeral()
if overlayLimit != nil && overlayLimit.Value() != 0 { if ephemeralLimit != nil && ephemeralLimit.Value() != 0 {
thresholdsMap[container.Name] = overlayLimit thresholdsMap[container.Name] = ephemeralLimit
} }
} }
for _, containerStat := range podStats.Containers { for _, containerStat := range podStats.Containers {
rootfs := diskUsage(containerStat.Rootfs) containerUsed := diskUsage(containerStat.Logs)
if overlayThreshold, ok := thresholdsMap[containerStat.Name]; ok { if !*m.dedicatedImageFs {
if overlayThreshold.Cmp(*rootfs) < 0 { containerUsed.Add(*diskUsage(containerStat.Rootfs))
return m.evictPod(pod, v1.ResourceName("containerOverlay"), fmt.Sprintf("container's overlay usage exceeds the limit %q", overlayThreshold.String())) }
if ephemeralStorageThreshold, ok := thresholdsMap[containerStat.Name]; ok {
if ephemeralStorageThreshold.Cmp(*containerUsed) < 0 {
return m.evictPod(pod, v1.ResourceEphemeralStorage, fmt.Sprintf("container's ephemeral local storage usage exceeds the limit %q", ephemeralStorageThreshold.String()))
} }
} }
......
...@@ -54,8 +54,6 @@ const ( ...@@ -54,8 +54,6 @@ const (
resourceNodeFs v1.ResourceName = "nodefs" resourceNodeFs v1.ResourceName = "nodefs"
// nodefs inodes, number. internal to this module, used to account for local node root filesystem inodes. // nodefs inodes, number. internal to this module, used to account for local node root filesystem inodes.
resourceNodeFsInodes v1.ResourceName = "nodefsInodes" resourceNodeFsInodes v1.ResourceName = "nodefsInodes"
// container overlay storage, in bytes. internal to this module, used to account for local disk usage for container overlay.
resourceOverlay v1.ResourceName = "overlay"
) )
var ( var (
...@@ -400,12 +398,10 @@ func localVolumeNames(pod *v1.Pod) []string { ...@@ -400,12 +398,10 @@ func localVolumeNames(pod *v1.Pod) []string {
func podDiskUsage(podStats statsapi.PodStats, pod *v1.Pod, statsToMeasure []fsStatsType) (v1.ResourceList, error) { func podDiskUsage(podStats statsapi.PodStats, pod *v1.Pod, statsToMeasure []fsStatsType) (v1.ResourceList, error) {
disk := resource.Quantity{Format: resource.BinarySI} disk := resource.Quantity{Format: resource.BinarySI}
inodes := resource.Quantity{Format: resource.BinarySI} inodes := resource.Quantity{Format: resource.BinarySI}
overlay := resource.Quantity{Format: resource.BinarySI}
for _, container := range podStats.Containers { for _, container := range podStats.Containers {
if hasFsStatsType(statsToMeasure, fsStatsRoot) { if hasFsStatsType(statsToMeasure, fsStatsRoot) {
disk.Add(*diskUsage(container.Rootfs)) disk.Add(*diskUsage(container.Rootfs))
inodes.Add(*inodeUsage(container.Rootfs)) inodes.Add(*inodeUsage(container.Rootfs))
overlay.Add(*diskUsage(container.Rootfs))
} }
if hasFsStatsType(statsToMeasure, fsStatsLogs) { if hasFsStatsType(statsToMeasure, fsStatsLogs) {
disk.Add(*diskUsage(container.Logs)) disk.Add(*diskUsage(container.Logs))
...@@ -425,9 +421,8 @@ func podDiskUsage(podStats statsapi.PodStats, pod *v1.Pod, statsToMeasure []fsSt ...@@ -425,9 +421,8 @@ func podDiskUsage(podStats statsapi.PodStats, pod *v1.Pod, statsToMeasure []fsSt
} }
} }
return v1.ResourceList{ return v1.ResourceList{
resourceDisk: disk, resourceDisk: disk,
resourceInodes: inodes, resourceInodes: inodes,
resourceOverlay: overlay,
}, nil }, nil
} }
...@@ -727,7 +722,7 @@ func makeSignalObservations(summaryProvider stats.SummaryProvider, capacityProvi ...@@ -727,7 +722,7 @@ func makeSignalObservations(summaryProvider stats.SummaryProvider, capacityProvi
} }
} }
storageScratchCapacity, storageScratchAllocatable, exist := getResourceAllocatable(nodeCapacity, allocatableReservation, v1.ResourceStorageScratch) ephemeralStorageCapacity, ephemeralStorageAllocatable, exist := getResourceAllocatable(nodeCapacity, allocatableReservation, v1.ResourceEphemeralStorage)
if exist { if exist {
for _, pod := range pods { for _, pod := range pods {
podStat, ok := statsFunc(pod) podStat, ok := statsFunc(pod)
...@@ -735,25 +730,23 @@ func makeSignalObservations(summaryProvider stats.SummaryProvider, capacityProvi ...@@ -735,25 +730,23 @@ func makeSignalObservations(summaryProvider stats.SummaryProvider, capacityProvi
continue continue
} }
usage, err := podDiskUsage(podStat, pod, []fsStatsType{fsStatsLogs, fsStatsLocalVolumeSource, fsStatsRoot}) fsStatsSet := []fsStatsType{}
if withImageFs {
fsStatsSet = []fsStatsType{fsStatsLogs, fsStatsLocalVolumeSource}
} else {
fsStatsSet = []fsStatsType{fsStatsRoot, fsStatsLogs, fsStatsLocalVolumeSource}
}
usage, err := podDiskUsage(podStat, pod, fsStatsSet)
if err != nil { if err != nil {
glog.Warningf("eviction manager: error getting pod disk usage %v", err) glog.Warningf("eviction manager: error getting pod disk usage %v", err)
continue continue
} }
// If there is a seperate imagefs set up for container runtimes, the scratch disk usage from nodefs should exclude the overlay usage ephemeralStorageAllocatable.Sub(usage[resourceDisk])
if withImageFs {
diskUsage := usage[resourceDisk]
diskUsageP := &diskUsage
diskUsagep := diskUsageP.Copy()
diskUsagep.Sub(usage[resourceOverlay])
storageScratchAllocatable.Sub(*diskUsagep)
} else {
storageScratchAllocatable.Sub(usage[resourceDisk])
}
} }
result[evictionapi.SignalAllocatableNodeFsAvailable] = signalObservation{ result[evictionapi.SignalAllocatableNodeFsAvailable] = signalObservation{
available: storageScratchAllocatable, available: ephemeralStorageAllocatable,
capacity: storageScratchCapacity, capacity: ephemeralStorageCapacity,
} }
} }
......
...@@ -243,6 +243,7 @@ type Dependencies struct { ...@@ -243,6 +243,7 @@ type Dependencies struct {
Recorder record.EventRecorder Recorder record.EventRecorder
Writer kubeio.Writer Writer kubeio.Writer
VolumePlugins []volume.VolumePlugin VolumePlugins []volume.VolumePlugin
DynamicPluginProber volume.DynamicPluginProber
TLSOptions *server.TLSOptions TLSOptions *server.TLSOptions
KubeletConfigController *kubeletconfig.Controller KubeletConfigController *kubeletconfig.Controller
} }
...@@ -736,7 +737,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration, ...@@ -736,7 +737,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
kubeDeps.Recorder) kubeDeps.Recorder)
klet.volumePluginMgr, err = klet.volumePluginMgr, err =
NewInitializedVolumePluginMgr(klet, secretManager, configMapManager, kubeDeps.VolumePlugins) NewInitializedVolumePluginMgr(klet, secretManager, configMapManager, kubeDeps.VolumePlugins, kubeDeps.DynamicPluginProber)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -564,11 +564,7 @@ func (kl *Kubelet) setNodeStatusMachineInfo(node *v1.Node) { ...@@ -564,11 +564,7 @@ func (kl *Kubelet) setNodeStatusMachineInfo(node *v1.Node) {
// capacity for every node status request // capacity for every node status request
initialCapacity := kl.containerManager.GetCapacity() initialCapacity := kl.containerManager.GetCapacity()
if initialCapacity != nil { if initialCapacity != nil {
node.Status.Capacity[v1.ResourceStorageScratch] = initialCapacity[v1.ResourceStorageScratch] node.Status.Capacity[v1.ResourceEphemeralStorage] = initialCapacity[v1.ResourceEphemeralStorage]
imageCapacity, ok := initialCapacity[v1.ResourceStorageOverlay]
if ok {
node.Status.Capacity[v1.ResourceStorageOverlay] = imageCapacity
}
} }
} }
} }
......
...@@ -30,6 +30,7 @@ import ( ...@@ -30,6 +30,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
kubetypes "k8s.io/apimachinery/pkg/types" kubetypes "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/util/flowcontrol" "k8s.io/client-go/util/flowcontrol"
"k8s.io/kubernetes/pkg/credentialprovider" "k8s.io/kubernetes/pkg/credentialprovider"
apitest "k8s.io/kubernetes/pkg/kubelet/apis/cri/testing" apitest "k8s.io/kubernetes/pkg/kubelet/apis/cri/testing"
...@@ -216,15 +217,12 @@ func verifyPods(a, b []*kubecontainer.Pod) bool { ...@@ -216,15 +217,12 @@ func verifyPods(a, b []*kubecontainer.Pod) bool {
return reflect.DeepEqual(a, b) return reflect.DeepEqual(a, b)
} }
func verifyFakeContainerList(fakeRuntime *apitest.FakeRuntimeService, expected []string) ([]string, bool) { func verifyFakeContainerList(fakeRuntime *apitest.FakeRuntimeService, expected sets.String) (sets.String, bool) {
actual := []string{} actual := sets.NewString()
for _, c := range fakeRuntime.Containers { for _, c := range fakeRuntime.Containers {
actual = append(actual, c.Id) actual.Insert(c.Id)
} }
sort.Sort(sort.StringSlice(actual)) return actual, actual.Equal(expected)
sort.Sort(sort.StringSlice(expected))
return actual, reflect.DeepEqual(expected, actual)
} }
type containerRecord struct { type containerRecord struct {
...@@ -618,9 +616,9 @@ func TestPruneInitContainers(t *testing.T) { ...@@ -618,9 +616,9 @@ func TestPruneInitContainers(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
m.pruneInitContainersBeforeStart(pod, podStatus) m.pruneInitContainersBeforeStart(pod, podStatus)
expectedContainers := []string{fakes[0].Id, fakes[2].Id} expectedContainers := sets.NewString(fakes[0].Id, fakes[2].Id)
if actual, ok := verifyFakeContainerList(fakeRuntime, expectedContainers); !ok { if actual, ok := verifyFakeContainerList(fakeRuntime, expectedContainers); !ok {
t.Errorf("expected %q, got %q", expectedContainers, actual) t.Errorf("expected %v, got %v", expectedContainers, actual)
} }
} }
......
...@@ -187,6 +187,11 @@ func (a *noNewPrivsAdmitHandler) Admit(attrs *PodAdmitAttributes) PodAdmitResult ...@@ -187,6 +187,11 @@ func (a *noNewPrivsAdmitHandler) Admit(attrs *PodAdmitAttributes) PodAdmitResult
return PodAdmitResult{Admit: true} return PodAdmitResult{Admit: true}
} }
// Always admit for remote runtime.
if a.Runtime.Type() == kubetypes.RemoteContainerRuntime {
return PodAdmitResult{Admit: true}
}
// Make sure it is either docker or rkt runtimes. // Make sure it is either docker or rkt runtimes.
if a.Runtime.Type() != kubetypes.DockerContainerRuntime && a.Runtime.Type() != kubetypes.RktContainerRuntime { if a.Runtime.Type() != kubetypes.DockerContainerRuntime && a.Runtime.Type() != kubetypes.RktContainerRuntime {
return PodAdmitResult{ return PodAdmitResult{
...@@ -196,7 +201,7 @@ func (a *noNewPrivsAdmitHandler) Admit(attrs *PodAdmitAttributes) PodAdmitResult ...@@ -196,7 +201,7 @@ func (a *noNewPrivsAdmitHandler) Admit(attrs *PodAdmitAttributes) PodAdmitResult
} }
} }
if a.Runtime.Type() != kubetypes.DockerContainerRuntime { if a.Runtime.Type() == kubetypes.DockerContainerRuntime {
// Make sure docker api version is valid. // Make sure docker api version is valid.
rversion, err := a.Runtime.APIVersion() rversion, err := a.Runtime.APIVersion()
if err != nil { if err != nil {
...@@ -206,7 +211,7 @@ func (a *noNewPrivsAdmitHandler) Admit(attrs *PodAdmitAttributes) PodAdmitResult ...@@ -206,7 +211,7 @@ func (a *noNewPrivsAdmitHandler) Admit(attrs *PodAdmitAttributes) PodAdmitResult
Message: fmt.Sprintf("Cannot enforce NoNewPrivs: %v", err), Message: fmt.Sprintf("Cannot enforce NoNewPrivs: %v", err),
} }
} }
v, err := rversion.Compare("1.23") v, err := rversion.Compare("1.23.0")
if err != nil { if err != nil {
return PodAdmitResult{ return PodAdmitResult{
Admit: false, Admit: false,
......
...@@ -92,7 +92,7 @@ func TestRunOnce(t *testing.T) { ...@@ -92,7 +92,7 @@ func TestRunOnce(t *testing.T) {
plug := &volumetest.FakeVolumePlugin{PluginName: "fake", Host: nil} plug := &volumetest.FakeVolumePlugin{PluginName: "fake", Host: nil}
kb.volumePluginMgr, err = kb.volumePluginMgr, err =
NewInitializedVolumePluginMgr(kb, fakeSecretManager, fakeConfigMapManager, []volume.VolumePlugin{plug}) NewInitializedVolumePluginMgr(kb, fakeSecretManager, fakeConfigMapManager, []volume.VolumePlugin{plug}, nil /* prober */)
if err != nil { if err != nil {
t.Fatalf("failed to initialize VolumePluginMgr: %v", err) t.Fatalf("failed to initialize VolumePluginMgr: %v", err)
} }
......
...@@ -41,7 +41,8 @@ func NewInitializedVolumePluginMgr( ...@@ -41,7 +41,8 @@ func NewInitializedVolumePluginMgr(
kubelet *Kubelet, kubelet *Kubelet,
secretManager secret.Manager, secretManager secret.Manager,
configMapManager configmap.Manager, configMapManager configmap.Manager,
plugins []volume.VolumePlugin) (*volume.VolumePluginMgr, error) { plugins []volume.VolumePlugin,
prober volume.DynamicPluginProber) (*volume.VolumePluginMgr, error) {
kvh := &kubeletVolumeHost{ kvh := &kubeletVolumeHost{
kubelet: kubelet, kubelet: kubelet,
volumePluginMgr: volume.VolumePluginMgr{}, volumePluginMgr: volume.VolumePluginMgr{},
...@@ -49,7 +50,7 @@ func NewInitializedVolumePluginMgr( ...@@ -49,7 +50,7 @@ func NewInitializedVolumePluginMgr(
configMapManager: configMapManager, configMapManager: configMapManager,
} }
if err := kvh.volumePluginMgr.InitPlugins(plugins, kvh); err != nil { if err := kvh.volumePluginMgr.InitPlugins(plugins, prober, kvh); err != nil {
return nil, fmt.Errorf( return nil, fmt.Errorf(
"Could not initialize volume plugins for KubeletVolumePluginMgr: %v", "Could not initialize volume plugins for KubeletVolumePluginMgr: %v",
err) err)
......
...@@ -217,7 +217,8 @@ func newTestVolumeManager(tmpDir string, podManager pod.Manager, kubeClient clie ...@@ -217,7 +217,8 @@ func newTestVolumeManager(tmpDir string, podManager pod.Manager, kubeClient clie
plug := &volumetest.FakeVolumePlugin{PluginName: "fake", Host: nil} plug := &volumetest.FakeVolumePlugin{PluginName: "fake", Host: nil}
fakeRecorder := &record.FakeRecorder{} fakeRecorder := &record.FakeRecorder{}
plugMgr := &volume.VolumePluginMgr{} plugMgr := &volume.VolumePluginMgr{}
plugMgr.InitPlugins([]volume.VolumePlugin{plug}, volumetest.NewFakeVolumeHost(tmpDir, kubeClient, nil)) // TODO (#51147) inject mock prober
plugMgr.InitPlugins([]volume.VolumePlugin{plug}, nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, kubeClient, nil))
statusManager := status.NewManager(kubeClient, podManager, &statustest.FakePodDeletionSafetyProvider{}) statusManager := status.NewManager(kubeClient, podManager, &statustest.FakePodDeletionSafetyProvider{})
vm := NewVolumeManager( vm := NewVolumeManager(
......
...@@ -2470,7 +2470,11 @@ func describeNode(node *api.Node, nodeNonTerminatedPodsList *api.PodList, events ...@@ -2470,7 +2470,11 @@ func describeNode(node *api.Node, nodeNonTerminatedPodsList *api.PodList, events
return tabbedString(func(out io.Writer) error { return tabbedString(func(out io.Writer) error {
w := NewPrefixWriter(out) w := NewPrefixWriter(out)
w.Write(LEVEL_0, "Name:\t%s\n", node.Name) w.Write(LEVEL_0, "Name:\t%s\n", node.Name)
w.Write(LEVEL_0, "Role:\t%s\n", findNodeRole(node)) if roles := findNodeRoles(node); len(roles) > 0 {
w.Write(LEVEL_0, "Roles:\t%s\n", strings.Join(roles, ","))
} else {
w.Write(LEVEL_0, "Roles:\t%s\n", "<none>")
}
printLabelsMultiline(w, "Labels", node.Labels) printLabelsMultiline(w, "Labels", node.Labels)
printAnnotationsMultiline(w, "Annotations", node.Annotations) printAnnotationsMultiline(w, "Annotations", node.Annotations)
printNodeTaintsMultiline(w, "Taints", node.Spec.Taints) printNodeTaintsMultiline(w, "Taints", node.Spec.Taints)
......
...@@ -62,16 +62,12 @@ import ( ...@@ -62,16 +62,12 @@ import (
const ( const (
loadBalancerWidth = 16 loadBalancerWidth = 16
// LabelNodeRoleMaster specifies that a node is a master // labelNodeRolePrefix is a label prefix for node roles
// It's copied over to here until it's merged in core: https://github.com/kubernetes/kubernetes/pull/39112 // It's copied over to here until it's merged in core: https://github.com/kubernetes/kubernetes/pull/39112
LabelNodeRoleMaster = "node-role.kubernetes.io/master" labelNodeRolePrefix = "node-role.kubernetes.io/"
// NodeLabelRole specifies the role of a node // nodeLabelRole specifies the role of a node
NodeLabelRole = "kubernetes.io/role" nodeLabelRole = "kubernetes.io/role"
// NodeLabelKubeadmAlphaRole is a label that kubeadm applies to a Node as a hint that it has a particular purpose.
// Use of NodeLabelRole is preferred.
NodeLabelKubeadmAlphaRole = "kubeadm.alpha.kubernetes.io/role"
) )
// AddHandlers adds print handlers for default Kubernetes types dealing with internal versions. // AddHandlers adds print handlers for default Kubernetes types dealing with internal versions.
...@@ -221,6 +217,7 @@ func AddHandlers(h printers.PrintHandler) { ...@@ -221,6 +217,7 @@ func AddHandlers(h printers.PrintHandler) {
nodeColumnDefinitions := []metav1alpha1.TableColumnDefinition{ nodeColumnDefinitions := []metav1alpha1.TableColumnDefinition{
{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]}, {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
{Name: "Status", Type: "string", Description: "The status of the node"}, {Name: "Status", Type: "string", Description: "The status of the node"},
{Name: "Roles", Type: "string", Description: "The roles of the node"},
{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]}, {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
{Name: "Version", Type: "string", Description: apiv1.NodeSystemInfo{}.SwaggerDoc()["kubeletVersion"]}, {Name: "Version", Type: "string", Description: apiv1.NodeSystemInfo{}.SwaggerDoc()["kubeletVersion"]},
{Name: "External-IP", Type: "string", Priority: 1, Description: apiv1.NodeStatus{}.SwaggerDoc()["addresses"]}, {Name: "External-IP", Type: "string", Priority: 1, Description: apiv1.NodeStatus{}.SwaggerDoc()["addresses"]},
...@@ -1167,12 +1164,13 @@ func printNode(obj *api.Node, options printers.PrintOptions) ([]metav1alpha1.Tab ...@@ -1167,12 +1164,13 @@ func printNode(obj *api.Node, options printers.PrintOptions) ([]metav1alpha1.Tab
if obj.Spec.Unschedulable { if obj.Spec.Unschedulable {
status = append(status, "SchedulingDisabled") status = append(status, "SchedulingDisabled")
} }
role := findNodeRole(obj)
if role != "" { roles := strings.Join(findNodeRoles(obj), ",")
status = append(status, role) if len(roles) == 0 {
roles = "<none>"
} }
row.Cells = append(row.Cells, obj.Name, strings.Join(status, ","), translateTimestamp(obj.CreationTimestamp), obj.Status.NodeInfo.KubeletVersion) row.Cells = append(row.Cells, obj.Name, strings.Join(status, ","), roles, translateTimestamp(obj.CreationTimestamp), obj.Status.NodeInfo.KubeletVersion)
if options.Wide { if options.Wide {
osImage, kernelVersion, crVersion := obj.Status.NodeInfo.OSImage, obj.Status.NodeInfo.KernelVersion, obj.Status.NodeInfo.ContainerRuntimeVersion osImage, kernelVersion, crVersion := obj.Status.NodeInfo.OSImage, obj.Status.NodeInfo.KernelVersion, obj.Status.NodeInfo.ContainerRuntimeVersion
if osImage == "" { if osImage == "" {
...@@ -1201,22 +1199,24 @@ func getNodeExternalIP(node *api.Node) string { ...@@ -1201,22 +1199,24 @@ func getNodeExternalIP(node *api.Node) string {
return "<none>" return "<none>"
} }
// findNodeRole returns the role of a given node, or "" if none found. // findNodeRoles returns the roles of a given node.
// The role is determined by looking in order for: // The roles are determined by looking for:
// * a node-role.kubernetes.io/master label // * a node-role.kubernetes.io/<role>="" label
// * a kubernetes.io/role label // * a kubernetes.io/role="<role>" label
// * a kubeadm.alpha.kubernetes.io/role label func findNodeRoles(node *api.Node) []string {
func findNodeRole(node *api.Node) string { roles := sets.NewString()
if _, ok := node.Labels[LabelNodeRoleMaster]; ok { for k, v := range node.Labels {
return "Master" switch {
} case strings.HasPrefix(k, labelNodeRolePrefix):
if role := node.Labels[NodeLabelRole]; role != "" { if role := strings.TrimPrefix(k, labelNodeRolePrefix); len(role) > 0 {
return strings.Title(role) roles.Insert(role)
} }
if role := node.Labels[NodeLabelKubeadmAlphaRole]; role != "" {
return strings.Title(role) case k == nodeLabelRole && v != "":
roles.Insert(v)
}
} }
return "" return roles.List()
} }
func printNodeList(list *api.NodeList, options printers.PrintOptions) ([]metav1alpha1.TableRow, error) { func printNodeList(list *api.NodeList, options printers.PrintOptions) ([]metav1alpha1.TableRow, error) {
......
...@@ -825,33 +825,50 @@ func TestPrintNodeStatus(t *testing.T) { ...@@ -825,33 +825,50 @@ func TestPrintNodeStatus(t *testing.T) {
}, },
status: "Unknown,SchedulingDisabled", status: "Unknown,SchedulingDisabled",
}, },
}
for _, test := range table {
buffer := &bytes.Buffer{}
err := printer.PrintObj(&test.node, buffer)
if err != nil {
t.Fatalf("An error occurred printing Node: %#v", err)
}
if !contains(strings.Fields(buffer.String()), test.status) {
t.Fatalf("Expect printing node %s with status %#v, got: %#v", test.node.Name, test.status, buffer.String())
}
}
}
func TestPrintNodeRole(t *testing.T) {
printer := printers.NewHumanReadablePrinter(nil, nil, printers.PrintOptions{})
AddHandlers(printer)
table := []struct {
node api.Node
expected string
}{
{ {
node: api.Node{ node: api.Node{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{Name: "foo9"},
Name: "foo10",
Labels: map[string]string{"node-role.kubernetes.io/master": "", "kubernetes.io/role": "node", "kubeadm.alpha.kubernetes.io/role": "node"},
},
}, },
status: "Unknown,Master", expected: "<none>",
}, },
{ {
node: api.Node{ node: api.Node{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo11", Name: "foo10",
Labels: map[string]string{"kubernetes.io/role": "node", "kubeadm.alpha.kubernetes.io/role": "node"}, Labels: map[string]string{"node-role.kubernetes.io/master": "", "node-role.kubernetes.io/proxy": "", "kubernetes.io/role": "node"},
}, },
}, },
status: "Unknown,Node", expected: "master,node,proxy",
}, },
{ {
node: api.Node{ node: api.Node{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo12", Name: "foo11",
Labels: map[string]string{"kubeadm.alpha.kubernetes.io/role": "node"}, Labels: map[string]string{"kubernetes.io/role": "node"},
}, },
Status: api.NodeStatus{Conditions: []api.NodeCondition{{Type: api.NodeReady, Status: api.ConditionTrue}}},
}, },
status: "Ready,Node", expected: "node",
}, },
} }
...@@ -861,8 +878,8 @@ func TestPrintNodeStatus(t *testing.T) { ...@@ -861,8 +878,8 @@ func TestPrintNodeStatus(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("An error occurred printing Node: %#v", err) t.Fatalf("An error occurred printing Node: %#v", err)
} }
if !contains(strings.Fields(buffer.String()), test.status) { if !contains(strings.Fields(buffer.String()), test.expected) {
t.Fatalf("Expect printing node %s with status %#v, got: %#v", test.node.Name, test.status, buffer.String()) t.Fatalf("Expect printing node %s with role %#v, got: %#v", test.node.Name, test.expected, buffer.String())
} }
} }
} }
......
...@@ -25,6 +25,7 @@ go_library( ...@@ -25,6 +25,7 @@ go_library(
"//pkg/api/helper/qos:go_default_library", "//pkg/api/helper/qos:go_default_library",
"//pkg/api/v1:go_default_library", "//pkg/api/v1:go_default_library",
"//pkg/api/validation:go_default_library", "//pkg/api/validation:go_default_library",
"//pkg/kubeapiserver/admission/util:go_default_library",
"//pkg/quota:go_default_library", "//pkg/quota:go_default_library",
"//pkg/quota/generic:go_default_library", "//pkg/quota/generic:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library",
......
...@@ -32,6 +32,7 @@ import ( ...@@ -32,6 +32,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/helper" "k8s.io/kubernetes/pkg/api/helper"
k8s_api_v1 "k8s.io/kubernetes/pkg/api/v1" k8s_api_v1 "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/kubeapiserver/admission/util"
"k8s.io/kubernetes/pkg/quota" "k8s.io/kubernetes/pkg/quota"
"k8s.io/kubernetes/pkg/quota/generic" "k8s.io/kubernetes/pkg/quota/generic"
) )
...@@ -141,8 +142,18 @@ func (p *pvcEvaluator) GroupKind() schema.GroupKind { ...@@ -141,8 +142,18 @@ func (p *pvcEvaluator) GroupKind() schema.GroupKind {
} }
// Handles returns true if the evaluator should handle the specified operation. // Handles returns true if the evaluator should handle the specified operation.
func (p *pvcEvaluator) Handles(operation admission.Operation) bool { func (p *pvcEvaluator) Handles(a admission.Attributes) bool {
return admission.Create == operation op := a.GetOperation()
if op == admission.Create {
return true
}
updateUninitialized, err := util.IsUpdatingUninitializedObject(a)
if err != nil {
// fail closed, will try to give an evaluation.
return true
}
// only uninitialized pvc might be updated.
return updateUninitialized
} }
// Matches returns true if the evaluator matches the specified quota with the provided input item // Matches returns true if the evaluator matches the specified quota with the provided input item
......
...@@ -34,6 +34,7 @@ import ( ...@@ -34,6 +34,7 @@ import (
"k8s.io/kubernetes/pkg/api/helper/qos" "k8s.io/kubernetes/pkg/api/helper/qos"
k8s_api_v1 "k8s.io/kubernetes/pkg/api/v1" k8s_api_v1 "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/api/validation" "k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/kubeapiserver/admission/util"
"k8s.io/kubernetes/pkg/quota" "k8s.io/kubernetes/pkg/quota"
"k8s.io/kubernetes/pkg/quota/generic" "k8s.io/kubernetes/pkg/quota/generic"
) )
...@@ -131,10 +132,19 @@ func (p *podEvaluator) GroupKind() schema.GroupKind { ...@@ -131,10 +132,19 @@ func (p *podEvaluator) GroupKind() schema.GroupKind {
return api.Kind("Pod") return api.Kind("Pod")
} }
// Handles returns true of the evaluator should handle the specified operation. // Handles returns true of the evaluator should handle the specified attributes.
func (p *podEvaluator) Handles(operation admission.Operation) bool { func (p *podEvaluator) Handles(a admission.Attributes) bool {
// TODO: update this if/when pods support resizing resource requirements. op := a.GetOperation()
return admission.Create == operation if op == admission.Create {
return true
}
updateUninitialized, err := util.IsUpdatingUninitializedObject(a)
if err != nil {
// fail closed, will try to give an evaluation.
return true
}
// only uninitialized pods might be updated.
return updateUninitialized
} }
// Matches returns true if the evaluator matches the specified quota with the provided input item // Matches returns true if the evaluator matches the specified quota with the provided input item
......
...@@ -108,7 +108,8 @@ func (p *serviceEvaluator) GroupKind() schema.GroupKind { ...@@ -108,7 +108,8 @@ func (p *serviceEvaluator) GroupKind() schema.GroupKind {
} }
// Handles returns true of the evaluator should handle the specified operation. // Handles returns true of the evaluator should handle the specified operation.
func (p *serviceEvaluator) Handles(operation admission.Operation) bool { func (p *serviceEvaluator) Handles(a admission.Attributes) bool {
operation := a.GetOperation()
// We handle create and update because a service type can change. // We handle create and update because a service type can change.
return admission.Create == operation || admission.Update == operation return admission.Create == operation || admission.Update == operation
} }
......
...@@ -150,8 +150,9 @@ func (o *ObjectCountEvaluator) GroupKind() schema.GroupKind { ...@@ -150,8 +150,9 @@ func (o *ObjectCountEvaluator) GroupKind() schema.GroupKind {
return o.InternalGroupKind return o.InternalGroupKind
} }
// Handles returns true if the object count evaluator needs to track this operation. // Handles returns true if the object count evaluator needs to track this attributes.
func (o *ObjectCountEvaluator) Handles(operation admission.Operation) bool { func (o *ObjectCountEvaluator) Handles(a admission.Attributes) bool {
operation := a.GetOperation()
return operation == admission.Create || (o.AllowCreateOnUpdate && operation == admission.Update) return operation == admission.Create || (o.AllowCreateOnUpdate && operation == admission.Update)
} }
......
...@@ -45,9 +45,9 @@ type Evaluator interface { ...@@ -45,9 +45,9 @@ type Evaluator interface {
Constraints(required []api.ResourceName, item runtime.Object) error Constraints(required []api.ResourceName, item runtime.Object) error
// GroupKind returns the groupKind that this object knows how to evaluate // GroupKind returns the groupKind that this object knows how to evaluate
GroupKind() schema.GroupKind GroupKind() schema.GroupKind
// Handles determines if quota could be impacted by the specified operation. // Handles determines if quota could be impacted by the specified attribute.
// If true, admission control must perform quota processing for the operation, otherwise it is safe to ignore quota. // If true, admission control must perform quota processing for the operation, otherwise it is safe to ignore quota.
Handles(operation admission.Operation) bool Handles(operation admission.Attributes) bool
// Matches returns true if the specified quota matches the input item // Matches returns true if the specified quota matches the input item
Matches(resourceQuota *api.ResourceQuota, item runtime.Object) (bool, error) Matches(resourceQuota *api.ResourceQuota, item runtime.Object) (bool, error)
// MatchingResources takes the input specified list of resources and returns the set of resources evaluator matches. // MatchingResources takes the input specified list of resources and returns the set of resources evaluator matches.
......
...@@ -196,9 +196,10 @@ func PodToSelectableFields(pod *api.Pod) fields.Set { ...@@ -196,9 +196,10 @@ func PodToSelectableFields(pod *api.Pod) fields.Set {
// amount of allocations needed to create the fields.Set. If you add any // amount of allocations needed to create the fields.Set. If you add any
// field here or the number of object-meta related fields changes, this should // field here or the number of object-meta related fields changes, this should
// be adjusted. // be adjusted.
podSpecificFieldsSet := make(fields.Set, 6) podSpecificFieldsSet := make(fields.Set, 7)
podSpecificFieldsSet["spec.nodeName"] = pod.Spec.NodeName podSpecificFieldsSet["spec.nodeName"] = pod.Spec.NodeName
podSpecificFieldsSet["spec.restartPolicy"] = string(pod.Spec.RestartPolicy) podSpecificFieldsSet["spec.restartPolicy"] = string(pod.Spec.RestartPolicy)
podSpecificFieldsSet["spec.schedulerName"] = string(pod.Spec.SchedulerName)
podSpecificFieldsSet["status.phase"] = string(pod.Status.Phase) podSpecificFieldsSet["status.phase"] = string(pod.Status.Phase)
podSpecificFieldsSet["status.podIP"] = string(pod.Status.PodIP) podSpecificFieldsSet["status.podIP"] = string(pod.Status.PodIP)
return generic.AddObjectMetaFieldsSet(podSpecificFieldsSet, &pod.ObjectMeta, true) return generic.AddObjectMetaFieldsSet(podSpecificFieldsSet, &pod.ObjectMeta, true)
......
...@@ -73,6 +73,20 @@ func TestMatchPod(t *testing.T) { ...@@ -73,6 +73,20 @@ func TestMatchPod(t *testing.T) {
}, },
{ {
in: &api.Pod{ in: &api.Pod{
Spec: api.PodSpec{SchedulerName: "scheduler1"},
},
fieldSelector: fields.ParseSelectorOrDie("spec.schedulerName=scheduler1"),
expectMatch: true,
},
{
in: &api.Pod{
Spec: api.PodSpec{SchedulerName: "scheduler1"},
},
fieldSelector: fields.ParseSelectorOrDie("spec.schedulerName=scheduler2"),
expectMatch: false,
},
{
in: &api.Pod{
Status: api.PodStatus{Phase: api.PodRunning}, Status: api.PodStatus{Phase: api.PodRunning},
}, },
fieldSelector: fields.ParseSelectorOrDie("status.phase=Running"), fieldSelector: fields.ParseSelectorOrDie("status.phase=Running"),
......
...@@ -40,7 +40,7 @@ func TestCanSupport(t *testing.T) { ...@@ -40,7 +40,7 @@ func TestCanSupport(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/aws-ebs") plug, err := plugMgr.FindPluginByName("kubernetes.io/aws-ebs")
if err != nil { if err != nil {
...@@ -64,7 +64,7 @@ func TestGetAccessModes(t *testing.T) { ...@@ -64,7 +64,7 @@ func TestGetAccessModes(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/aws-ebs") plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/aws-ebs")
if err != nil { if err != nil {
...@@ -113,7 +113,7 @@ func TestPlugin(t *testing.T) { ...@@ -113,7 +113,7 @@ func TestPlugin(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/aws-ebs") plug, err := plugMgr.FindPluginByName("kubernetes.io/aws-ebs")
if err != nil { if err != nil {
...@@ -186,6 +186,9 @@ func TestPlugin(t *testing.T) { ...@@ -186,6 +186,9 @@ func TestPlugin(t *testing.T) {
PersistentVolumeReclaimPolicy: v1.PersistentVolumeReclaimDelete, PersistentVolumeReclaimPolicy: v1.PersistentVolumeReclaimDelete,
} }
provisioner, err := plug.(*awsElasticBlockStorePlugin).newProvisionerInternal(options, &fakePDManager{}) provisioner, err := plug.(*awsElasticBlockStorePlugin).newProvisionerInternal(options, &fakePDManager{})
if err != nil {
t.Errorf("Error creating new provisioner:%v", err)
}
persistentSpec, err := provisioner.Provision() persistentSpec, err := provisioner.Provision()
if err != nil { if err != nil {
t.Errorf("Provision() failed: %v", err) t.Errorf("Provision() failed: %v", err)
...@@ -209,6 +212,9 @@ func TestPlugin(t *testing.T) { ...@@ -209,6 +212,9 @@ func TestPlugin(t *testing.T) {
PersistentVolume: persistentSpec, PersistentVolume: persistentSpec,
} }
deleter, err := plug.(*awsElasticBlockStorePlugin).newDeleterInternal(volSpec, &fakePDManager{}) deleter, err := plug.(*awsElasticBlockStorePlugin).newDeleterInternal(volSpec, &fakePDManager{})
if err != nil {
t.Errorf("Error creating new deleter:%v", err)
}
err = deleter.Delete() err = deleter.Delete()
if err != nil { if err != nil {
t.Errorf("Deleter() failed: %v", err) t.Errorf("Deleter() failed: %v", err)
...@@ -251,7 +257,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) { ...@@ -251,7 +257,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, clientset, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, clientset, nil))
plug, _ := plugMgr.FindPluginByName(awsElasticBlockStorePluginName) plug, _ := plugMgr.FindPluginByName(awsElasticBlockStorePluginName)
// readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes // readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes
...@@ -271,7 +277,7 @@ func TestMounterAndUnmounterTypeAssert(t *testing.T) { ...@@ -271,7 +277,7 @@ func TestMounterAndUnmounterTypeAssert(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/aws-ebs") plug, err := plugMgr.FindPluginByName("kubernetes.io/aws-ebs")
if err != nil { if err != nil {
...@@ -288,11 +294,17 @@ func TestMounterAndUnmounterTypeAssert(t *testing.T) { ...@@ -288,11 +294,17 @@ func TestMounterAndUnmounterTypeAssert(t *testing.T) {
} }
mounter, err := plug.(*awsElasticBlockStorePlugin).newMounterInternal(volume.NewSpecFromVolume(spec), types.UID("poduid"), &fakePDManager{}, &mount.FakeMounter{}) mounter, err := plug.(*awsElasticBlockStorePlugin).newMounterInternal(volume.NewSpecFromVolume(spec), types.UID("poduid"), &fakePDManager{}, &mount.FakeMounter{})
if err != nil {
t.Errorf("Error creating new mounter:%v", err)
}
if _, ok := mounter.(volume.Unmounter); ok { if _, ok := mounter.(volume.Unmounter); ok {
t.Errorf("Volume Mounter can be type-assert to Unmounter") t.Errorf("Volume Mounter can be type-assert to Unmounter")
} }
unmounter, err := plug.(*awsElasticBlockStorePlugin).newUnmounterInternal("vol1", types.UID("poduid"), &fakePDManager{}, &mount.FakeMounter{}) unmounter, err := plug.(*awsElasticBlockStorePlugin).newUnmounterInternal("vol1", types.UID("poduid"), &fakePDManager{}, &mount.FakeMounter{})
if err != nil {
t.Errorf("Error creating new unmounter:%v", err)
}
if _, ok := unmounter.(volume.Mounter); ok { if _, ok := unmounter.(volume.Mounter); ok {
t.Errorf("Volume Unmounter can be type-assert to Mounter") t.Errorf("Volume Unmounter can be type-assert to Mounter")
} }
......
...@@ -33,7 +33,7 @@ func TestCanSupport(t *testing.T) { ...@@ -33,7 +33,7 @@ func TestCanSupport(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName(azureDataDiskPluginName) plug, err := plugMgr.FindPluginByName(azureDataDiskPluginName)
if err != nil { if err != nil {
......
...@@ -41,7 +41,7 @@ func TestCanSupport(t *testing.T) { ...@@ -41,7 +41,7 @@ func TestCanSupport(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/azure-file") plug, err := plugMgr.FindPluginByName("kubernetes.io/azure-file")
if err != nil { if err != nil {
...@@ -65,7 +65,7 @@ func TestGetAccessModes(t *testing.T) { ...@@ -65,7 +65,7 @@ func TestGetAccessModes(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/azure-file") plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/azure-file")
if err != nil { if err != nil {
...@@ -131,7 +131,7 @@ func TestPluginWithOtherCloudProvider(t *testing.T) { ...@@ -131,7 +131,7 @@ func TestPluginWithOtherCloudProvider(t *testing.T) {
func testPlugin(t *testing.T, tmpDir string, volumeHost volume.VolumeHost) { func testPlugin(t *testing.T, tmpDir string, volumeHost volume.VolumeHost) {
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumeHost) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumeHost)
plug, err := plugMgr.FindPluginByName("kubernetes.io/azure-file") plug, err := plugMgr.FindPluginByName("kubernetes.io/azure-file")
if err != nil { if err != nil {
...@@ -228,7 +228,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) { ...@@ -228,7 +228,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) {
client := fake.NewSimpleClientset(pv, claim) client := fake.NewSimpleClientset(pv, claim)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost("/tmp/fake", client, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost("/tmp/fake", client, nil))
plug, _ := plugMgr.FindPluginByName(azureFilePluginName) plug, _ := plugMgr.FindPluginByName(azureFilePluginName)
// readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes // readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes
...@@ -260,7 +260,7 @@ func TestMounterAndUnmounterTypeAssert(t *testing.T) { ...@@ -260,7 +260,7 @@ func TestMounterAndUnmounterTypeAssert(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/azure-file") plug, err := plugMgr.FindPluginByName("kubernetes.io/azure-file")
if err != nil { if err != nil {
......
...@@ -36,7 +36,7 @@ func TestCanSupport(t *testing.T) { ...@@ -36,7 +36,7 @@ func TestCanSupport(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/cephfs") plug, err := plugMgr.FindPluginByName("kubernetes.io/cephfs")
if err != nil { if err != nil {
t.Errorf("Can't find the plugin by name") t.Errorf("Can't find the plugin by name")
...@@ -59,7 +59,7 @@ func TestPlugin(t *testing.T) { ...@@ -59,7 +59,7 @@ func TestPlugin(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/cephfs") plug, err := plugMgr.FindPluginByName("kubernetes.io/cephfs")
if err != nil { if err != nil {
t.Errorf("Can't find the plugin by name") t.Errorf("Can't find the plugin by name")
...@@ -123,7 +123,7 @@ func TestConstructVolumeSpec(t *testing.T) { ...@@ -123,7 +123,7 @@ func TestConstructVolumeSpec(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/cephfs") plug, err := plugMgr.FindPluginByName("kubernetes.io/cephfs")
if err != nil { if err != nil {
t.Errorf("can't find cephfs plugin by name") t.Errorf("can't find cephfs plugin by name")
......
...@@ -650,6 +650,10 @@ func (instances *instances) InstanceTypeByProviderID(providerID string) (string, ...@@ -650,6 +650,10 @@ func (instances *instances) InstanceTypeByProviderID(providerID string) (string,
return "", errors.New("Not implemented") return "", errors.New("Not implemented")
} }
func (instances *instances) InstanceExistsByProviderID(providerID string) (bool, error) {
return false, errors.New("unimplemented")
}
func (instances *instances) List(filter string) ([]types.NodeName, error) { func (instances *instances) List(filter string) ([]types.NodeName, error) {
return []types.NodeName{}, errors.New("Not implemented") return []types.NodeName{}, errors.New("Not implemented")
} }
......
...@@ -38,7 +38,7 @@ func TestCanSupport(t *testing.T) { ...@@ -38,7 +38,7 @@ func TestCanSupport(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/cinder") plug, err := plugMgr.FindPluginByName("kubernetes.io/cinder")
if err != nil { if err != nil {
...@@ -134,7 +134,7 @@ func TestPlugin(t *testing.T) { ...@@ -134,7 +134,7 @@ func TestPlugin(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/cinder") plug, err := plugMgr.FindPluginByName("kubernetes.io/cinder")
if err != nil { if err != nil {
......
...@@ -272,7 +272,7 @@ func TestCanSupport(t *testing.T) { ...@@ -272,7 +272,7 @@ func TestCanSupport(t *testing.T) {
pluginMgr := volume.VolumePluginMgr{} pluginMgr := volume.VolumePluginMgr{}
tempDir, host := newTestHost(t, nil) tempDir, host := newTestHost(t, nil)
defer os.RemoveAll(tempDir) defer os.RemoveAll(tempDir)
pluginMgr.InitPlugins(ProbeVolumePlugins(), host) pluginMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, host)
plugin, err := pluginMgr.FindPluginByName(configMapPluginName) plugin, err := pluginMgr.FindPluginByName(configMapPluginName)
if err != nil { if err != nil {
...@@ -304,7 +304,7 @@ func TestPlugin(t *testing.T) { ...@@ -304,7 +304,7 @@ func TestPlugin(t *testing.T) {
) )
defer os.RemoveAll(tempDir) defer os.RemoveAll(tempDir)
pluginMgr.InitPlugins(ProbeVolumePlugins(), host) pluginMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, host)
plugin, err := pluginMgr.FindPluginByName(configMapPluginName) plugin, err := pluginMgr.FindPluginByName(configMapPluginName)
if err != nil { if err != nil {
...@@ -368,7 +368,7 @@ func TestPluginReboot(t *testing.T) { ...@@ -368,7 +368,7 @@ func TestPluginReboot(t *testing.T) {
) )
defer os.RemoveAll(rootDir) defer os.RemoveAll(rootDir)
pluginMgr.InitPlugins(ProbeVolumePlugins(), host) pluginMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, host)
plugin, err := pluginMgr.FindPluginByName(configMapPluginName) plugin, err := pluginMgr.FindPluginByName(configMapPluginName)
if err != nil { if err != nil {
...@@ -424,7 +424,7 @@ func TestPluginOptional(t *testing.T) { ...@@ -424,7 +424,7 @@ func TestPluginOptional(t *testing.T) {
volumeSpec.VolumeSource.ConfigMap.Optional = &trueVal volumeSpec.VolumeSource.ConfigMap.Optional = &trueVal
defer os.RemoveAll(tempDir) defer os.RemoveAll(tempDir)
pluginMgr.InitPlugins(ProbeVolumePlugins(), host) pluginMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, host)
plugin, err := pluginMgr.FindPluginByName(configMapPluginName) plugin, err := pluginMgr.FindPluginByName(configMapPluginName)
if err != nil { if err != nil {
...@@ -499,7 +499,7 @@ func TestPluginKeysOptional(t *testing.T) { ...@@ -499,7 +499,7 @@ func TestPluginKeysOptional(t *testing.T) {
volumeSpec.VolumeSource.ConfigMap.Optional = &trueVal volumeSpec.VolumeSource.ConfigMap.Optional = &trueVal
defer os.RemoveAll(tempDir) defer os.RemoveAll(tempDir)
pluginMgr.InitPlugins(ProbeVolumePlugins(), host) pluginMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, host)
plugin, err := pluginMgr.FindPluginByName(configMapPluginName) plugin, err := pluginMgr.FindPluginByName(configMapPluginName)
if err != nil { if err != nil {
......
...@@ -54,7 +54,7 @@ func TestCanSupport(t *testing.T) { ...@@ -54,7 +54,7 @@ func TestCanSupport(t *testing.T) {
pluginMgr := volume.VolumePluginMgr{} pluginMgr := volume.VolumePluginMgr{}
tmpDir, host := newTestHost(t, nil) tmpDir, host := newTestHost(t, nil)
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
pluginMgr.InitPlugins(ProbeVolumePlugins(), host) pluginMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, host)
plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName) plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName)
if err != nil { if err != nil {
...@@ -219,7 +219,7 @@ func newDownwardAPITest(t *testing.T, name string, volumeFiles, podLabels, podAn ...@@ -219,7 +219,7 @@ func newDownwardAPITest(t *testing.T, name string, volumeFiles, podLabels, podAn
pluginMgr := volume.VolumePluginMgr{} pluginMgr := volume.VolumePluginMgr{}
rootDir, host := newTestHost(t, clientset) rootDir, host := newTestHost(t, clientset)
pluginMgr.InitPlugins(ProbeVolumePlugins(), host) pluginMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, host)
plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName) plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName)
if err != nil { if err != nil {
t.Errorf("Can't find the plugin by name") t.Errorf("Can't find the plugin by name")
......
...@@ -36,7 +36,7 @@ import ( ...@@ -36,7 +36,7 @@ import (
// Construct an instance of a plugin, by name. // Construct an instance of a plugin, by name.
func makePluginUnderTest(t *testing.T, plugName, basePath string) volume.VolumePlugin { func makePluginUnderTest(t *testing.T, plugName, basePath string) volume.VolumePlugin {
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(basePath, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(basePath, nil, nil))
plug, err := plugMgr.FindPluginByName(plugName) plug, err := plugMgr.FindPluginByName(plugName)
if err != nil { if err != nil {
......
...@@ -39,7 +39,7 @@ func TestCanSupport(t *testing.T) { ...@@ -39,7 +39,7 @@ func TestCanSupport(t *testing.T) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/fc") plug, err := plugMgr.FindPluginByName("kubernetes.io/fc")
if err != nil { if err != nil {
...@@ -61,7 +61,7 @@ func TestGetAccessModes(t *testing.T) { ...@@ -61,7 +61,7 @@ func TestGetAccessModes(t *testing.T) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/fc") plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/fc")
if err != nil { if err != nil {
...@@ -132,7 +132,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) { ...@@ -132,7 +132,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/fc") plug, err := plugMgr.FindPluginByName("kubernetes.io/fc")
if err != nil { if err != nil {
...@@ -202,7 +202,7 @@ func doTestPluginNilMounter(t *testing.T, spec *volume.Spec) { ...@@ -202,7 +202,7 @@ func doTestPluginNilMounter(t *testing.T, spec *volume.Spec) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/fc") plug, err := plugMgr.FindPluginByName("kubernetes.io/fc")
if err != nil { if err != nil {
...@@ -355,7 +355,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) { ...@@ -355,7 +355,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) {
client := fake.NewSimpleClientset(pv, claim) client := fake.NewSimpleClientset(pv, claim)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, client, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, client, nil))
plug, _ := plugMgr.FindPluginByName(fcPluginName) plug, _ := plugMgr.FindPluginByName(fcPluginName)
// readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes // readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes
......
...@@ -29,9 +29,11 @@ go_library( ...@@ -29,9 +29,11 @@ go_library(
"//pkg/util/strings:go_default_library", "//pkg/util/strings:go_default_library",
"//pkg/volume:go_default_library", "//pkg/volume:go_default_library",
"//pkg/volume/util:go_default_library", "//pkg/volume/util:go_default_library",
"//vendor/github.com/fsnotify/fsnotify:go_default_library",
"//vendor/github.com/golang/glog:go_default_library", "//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library", "//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library", "//vendor/k8s.io/utils/exec:go_default_library",
], ],
) )
......
...@@ -174,7 +174,7 @@ func TestCanSupport(t *testing.T) { ...@@ -174,7 +174,7 @@ func TestCanSupport(t *testing.T) {
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
installPluginUnderTest(t, "kubernetes.io", "fakeAttacher", tmpDir, execScriptTempl1, nil) installPluginUnderTest(t, "kubernetes.io", "fakeAttacher", tmpDir, execScriptTempl1, nil)
plugMgr.InitPlugins(ProbeVolumePlugins(tmpDir), volumetest.NewFakeVolumeHost("fake", nil, nil)) plugMgr.InitPlugins(nil, GetDynamicPluginProber(tmpDir), volumetest.NewFakeVolumeHost("fake", nil, nil))
plugin, err := plugMgr.FindPluginByName("flexvolume-kubernetes.io/fakeAttacher") plugin, err := plugMgr.FindPluginByName("flexvolume-kubernetes.io/fakeAttacher")
if err != nil { if err != nil {
t.Fatalf("Can't find the plugin by name") t.Fatalf("Can't find the plugin by name")
...@@ -202,7 +202,7 @@ func TestGetAccessModes(t *testing.T) { ...@@ -202,7 +202,7 @@ func TestGetAccessModes(t *testing.T) {
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
installPluginUnderTest(t, "kubernetes.io", "fakeAttacher", tmpDir, execScriptTempl1, nil) installPluginUnderTest(t, "kubernetes.io", "fakeAttacher", tmpDir, execScriptTempl1, nil)
plugMgr.InitPlugins(ProbeVolumePlugins(tmpDir), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(nil, GetDynamicPluginProber(tmpDir), volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plugin, err := plugMgr.FindPersistentPluginByName("flexvolume-kubernetes.io/fakeAttacher") plugin, err := plugMgr.FindPersistentPluginByName("flexvolume-kubernetes.io/fakeAttacher")
if err != nil { if err != nil {
......
...@@ -19,28 +19,217 @@ package flexvolume ...@@ -19,28 +19,217 @@ package flexvolume
import ( import (
"io/ioutil" "io/ioutil"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume"
"os"
"fmt"
"path/filepath"
"sync"
"time"
"github.com/fsnotify/fsnotify"
"k8s.io/apimachinery/pkg/util/errors"
)
type flexVolumeProber struct {
mutex sync.Mutex
pluginDir string // Flexvolume driver directory
watcher *fsnotify.Watcher
probeNeeded bool // Must only read and write this through testAndSetProbeNeeded.
lastUpdated time.Time // Last time probeNeeded was updated.
watchEventCount int
}
const (
// TODO (cxing) Tune these params based on test results.
// watchEventLimit is the max allowable number of processed watches within watchEventInterval.
watchEventInterval = 5 * time.Second
watchEventLimit = 20
) )
// This is the primary entrypoint for volume plugins. func GetDynamicPluginProber(pluginDir string) volume.DynamicPluginProber {
func ProbeVolumePlugins(pluginDir string) []volume.VolumePlugin { return &flexVolumeProber{pluginDir: pluginDir}
plugins := []volume.VolumePlugin{} }
func (prober *flexVolumeProber) Init() error {
prober.testAndSetProbeNeeded(true)
prober.lastUpdated = time.Now()
if err := prober.createPluginDir(); err != nil {
return err
}
if err := prober.initWatcher(); err != nil {
return err
}
go func() {
defer prober.watcher.Close()
for {
select {
case event := <-prober.watcher.Events:
if err := prober.handleWatchEvent(event); err != nil {
glog.Errorf("Flexvolume prober watch: %s", err)
}
case err := <-prober.watcher.Errors:
glog.Errorf("Received an error from watcher: %s", err)
}
}
}()
files, _ := ioutil.ReadDir(pluginDir) return nil
}
// Probes for Flexvolume drivers.
// If a filesystem update has occurred since the last probe, updated = true
// and the list of probed plugins is returned.
// Otherwise, update = false and probedPlugins = nil.
//
// If an error occurs, updated and plugins are set arbitrarily.
func (prober *flexVolumeProber) Probe() (updated bool, plugins []volume.VolumePlugin, err error) {
probeNeeded := prober.testAndSetProbeNeeded(false)
if !probeNeeded {
return false, nil, nil
}
files, err := ioutil.ReadDir(prober.pluginDir)
if err != nil {
return false, nil, fmt.Errorf("Error reading the Flexvolume directory: %s", err)
}
plugins = []volume.VolumePlugin{}
allErrs := []error{}
for _, f := range files { for _, f := range files {
// only directories are counted as plugins // only directories with names that do not begin with '.' are counted as plugins
// and pluginDir/dirname/dirname should be an executable // and pluginDir/dirname/dirname should be an executable
// unless dirname contains '~' for escaping namespace // unless dirname contains '~' for escaping namespace
// e.g. dirname = vendor~cifs // e.g. dirname = vendor~cifs
// then, executable will be pluginDir/dirname/cifs // then, executable will be pluginDir/dirname/cifs
if f.IsDir() { if f.IsDir() && filepath.Base(f.Name())[0] != '.' {
plugin, err := NewFlexVolumePlugin(pluginDir, f.Name()) plugin, pluginErr := NewFlexVolumePlugin(prober.pluginDir, f.Name())
if err != nil { if pluginErr != nil {
pluginErr = fmt.Errorf(
"Error creating Flexvolume plugin from directory %s, skipping. Error: %s",
f.Name(), pluginErr)
allErrs = append(allErrs, pluginErr)
continue continue
} }
plugins = append(plugins, plugin) plugins = append(plugins, plugin)
} }
} }
return plugins
return true, plugins, errors.NewAggregate(allErrs)
}
func (prober *flexVolumeProber) handleWatchEvent(event fsnotify.Event) error {
// event.Name is the watched path.
if filepath.Base(event.Name)[0] == '.' {
// Ignore files beginning with '.'
return nil
}
eventPathAbs, err := filepath.Abs(event.Name)
if err != nil {
return err
}
pluginDirAbs, err := filepath.Abs(prober.pluginDir)
if err != nil {
return err
}
// If the Flexvolume plugin directory is removed, need to recreate it
// in order to keep it under watch.
if eventOpIs(event, fsnotify.Remove) && eventPathAbs == pluginDirAbs {
glog.Warningf("Flexvolume plugin directory at %s is removed. Recreating.", pluginDirAbs)
if err := prober.createPluginDir(); err != nil {
return err
}
if err := prober.addWatchRecursive(pluginDirAbs); err != nil {
return err
}
} else if eventOpIs(event, fsnotify.Create) {
if err := prober.addWatchRecursive(eventPathAbs); err != nil {
return err
}
}
prober.updateProbeNeeded()
return nil
}
func (prober *flexVolumeProber) updateProbeNeeded() {
// Within 'watchEventInterval' seconds, a max of 'watchEventLimit' watch events is processed.
// The watch event will not be registered if the limit is reached.
// This prevents increased disk usage from Probe() being triggered too frequently (either
// accidentally or maliciously).
if time.Since(prober.lastUpdated) > watchEventInterval {
// Update, then reset the timer and watch count.
prober.testAndSetProbeNeeded(true)
prober.lastUpdated = time.Now()
prober.watchEventCount = 1
} else if prober.watchEventCount < watchEventLimit {
prober.testAndSetProbeNeeded(true)
prober.watchEventCount++
}
}
// Recursively adds to watch all directories inside and including the file specified by the given filename.
// If the file is a symlink to a directory, it will watch the symlink but not any of the subdirectories.
//
// Each file or directory change triggers two events: one from the watch on itself, another from the watch
// on its parent directory.
func (prober *flexVolumeProber) addWatchRecursive(filename string) error {
addWatch := func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
if err := prober.watcher.Add(path); err != nil {
glog.Errorf("Error recursively adding watch: %v", err)
}
}
return nil
}
return filepath.Walk(filename, addWatch)
}
// Creates a new filesystem watcher and adds watches for the plugin directory
// and all of its subdirectories.
func (prober *flexVolumeProber) initWatcher() error {
var err error
if prober.watcher, err = fsnotify.NewWatcher(); err != nil {
return fmt.Errorf("Error creating new watcher: %s", err)
}
if err = prober.addWatchRecursive(prober.pluginDir); err != nil {
return fmt.Errorf("Error adding watch on Flexvolume directory: %s", err)
}
return nil
}
// Creates the plugin directory, if it doesn't already exist.
func (prober *flexVolumeProber) createPluginDir() error {
if _, err := os.Stat(prober.pluginDir); os.IsNotExist(err) {
err := os.MkdirAll(prober.pluginDir, 0755)
if err != nil {
return fmt.Errorf("Error (re-)creating driver directory: %s", err)
}
}
return nil
}
func (prober *flexVolumeProber) testAndSetProbeNeeded(newval bool) (oldval bool) {
prober.mutex.Lock()
defer prober.mutex.Unlock()
oldval, prober.probeNeeded = prober.probeNeeded, newval
return
}
func eventOpIs(event fsnotify.Event, op fsnotify.Op) bool {
return event.Op&op == op
} }
...@@ -127,7 +127,7 @@ func newInitializedVolumePlugMgr(t *testing.T) (*volume.VolumePluginMgr, string) ...@@ -127,7 +127,7 @@ func newInitializedVolumePlugMgr(t *testing.T) (*volume.VolumePluginMgr, string)
plugMgr := &volume.VolumePluginMgr{} plugMgr := &volume.VolumePluginMgr{}
dir, err := utiltesting.MkTmpdir("flocker") dir, err := utiltesting.MkTmpdir("flocker")
assert.NoError(t, err) assert.NoError(t, err)
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(dir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(dir, nil, nil))
return plugMgr, dir return plugMgr, dir
} }
...@@ -138,7 +138,7 @@ func TestPlugin(t *testing.T) { ...@@ -138,7 +138,7 @@ func TestPlugin(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/flocker") plug, err := plugMgr.FindPluginByName("kubernetes.io/flocker")
if err != nil { if err != nil {
......
...@@ -35,7 +35,7 @@ func newTestableProvisioner(assert *assert.Assertions, options volume.VolumeOpti ...@@ -35,7 +35,7 @@ func newTestableProvisioner(assert *assert.Assertions, options volume.VolumeOpti
assert.NoError(err, fmt.Sprintf("can't make a temp dir: %v", err)) assert.NoError(err, fmt.Sprintf("can't make a temp dir: %v", err))
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName(pluginName) plug, err := plugMgr.FindPluginByName(pluginName)
assert.NoError(err, "Can't find the plugin by name") assert.NoError(err, "Can't find the plugin by name")
......
...@@ -202,7 +202,8 @@ func newPlugin() *gcePersistentDiskPlugin { ...@@ -202,7 +202,8 @@ func newPlugin() *gcePersistentDiskPlugin {
host := volumetest.NewFakeVolumeHost( host := volumetest.NewFakeVolumeHost(
"/tmp", /* rootDir */ "/tmp", /* rootDir */
nil, /* kubeClient */ nil, /* kubeClient */
nil /* plugins */) nil, /* plugins */
)
plugins := ProbeVolumePlugins() plugins := ProbeVolumePlugins()
plugin := plugins[0] plugin := plugins[0]
plugin.Init(host) plugin.Init(host)
......
...@@ -39,7 +39,7 @@ func TestCanSupport(t *testing.T) { ...@@ -39,7 +39,7 @@ func TestCanSupport(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/gce-pd") plug, err := plugMgr.FindPluginByName("kubernetes.io/gce-pd")
if err != nil { if err != nil {
...@@ -63,7 +63,7 @@ func TestGetAccessModes(t *testing.T) { ...@@ -63,7 +63,7 @@ func TestGetAccessModes(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/gce-pd") plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/gce-pd")
if err != nil { if err != nil {
...@@ -106,7 +106,7 @@ func TestPlugin(t *testing.T) { ...@@ -106,7 +106,7 @@ func TestPlugin(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/gce-pd") plug, err := plugMgr.FindPluginByName("kubernetes.io/gce-pd")
if err != nil { if err != nil {
...@@ -250,7 +250,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) { ...@@ -250,7 +250,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, client, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, client, nil))
plug, _ := plugMgr.FindPluginByName(gcePersistentDiskPluginName) plug, _ := plugMgr.FindPluginByName(gcePersistentDiskPluginName)
// readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes // readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes
......
...@@ -47,7 +47,7 @@ func TestCanSupport(t *testing.T) { ...@@ -47,7 +47,7 @@ func TestCanSupport(t *testing.T) {
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
tempDir, host := newTestHost(t) tempDir, host := newTestHost(t)
defer os.RemoveAll(tempDir) defer os.RemoveAll(tempDir)
plugMgr.InitPlugins(ProbeVolumePlugins(), host) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, host)
plug, err := plugMgr.FindPluginByName("kubernetes.io/git-repo") plug, err := plugMgr.FindPluginByName("kubernetes.io/git-repo")
if err != nil { if err != nil {
...@@ -225,7 +225,7 @@ func doTestPlugin(scenario struct { ...@@ -225,7 +225,7 @@ func doTestPlugin(scenario struct {
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
rootDir, host := newTestHost(t) rootDir, host := newTestHost(t)
defer os.RemoveAll(rootDir) defer os.RemoveAll(rootDir)
plugMgr.InitPlugins(ProbeVolumePlugins(), host) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, host)
plug, err := plugMgr.FindPluginByName("kubernetes.io/git-repo") plug, err := plugMgr.FindPluginByName("kubernetes.io/git-repo")
if err != nil { if err != nil {
......
...@@ -43,7 +43,7 @@ func TestCanSupport(t *testing.T) { ...@@ -43,7 +43,7 @@ func TestCanSupport(t *testing.T) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/glusterfs") plug, err := plugMgr.FindPluginByName("kubernetes.io/glusterfs")
if err != nil { if err != nil {
t.Errorf("Can't find the plugin by name") t.Errorf("Can't find the plugin by name")
...@@ -67,7 +67,7 @@ func TestGetAccessModes(t *testing.T) { ...@@ -67,7 +67,7 @@ func TestGetAccessModes(t *testing.T) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/glusterfs") plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/glusterfs")
if err != nil { if err != nil {
...@@ -95,7 +95,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) { ...@@ -95,7 +95,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/glusterfs") plug, err := plugMgr.FindPluginByName("kubernetes.io/glusterfs")
if err != nil { if err != nil {
t.Errorf("Can't find the plugin by name") t.Errorf("Can't find the plugin by name")
...@@ -213,7 +213,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) { ...@@ -213,7 +213,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) {
client := fake.NewSimpleClientset(pv, claim, ep) client := fake.NewSimpleClientset(pv, claim, ep)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, client, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, client, nil))
plug, _ := plugMgr.FindPluginByName(glusterfsPluginName) plug, _ := plugMgr.FindPluginByName(glusterfsPluginName)
// readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes // readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes
......
...@@ -51,7 +51,7 @@ func newHostPathTypeList(pathType ...string) []*v1.HostPathType { ...@@ -51,7 +51,7 @@ func newHostPathTypeList(pathType ...string) []*v1.HostPathType {
func TestCanSupport(t *testing.T) { func TestCanSupport(t *testing.T) {
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{}), volumetest.NewFakeVolumeHost("fake", nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{}), nil /* prober */, volumetest.NewFakeVolumeHost("fake", nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/host-path") plug, err := plugMgr.FindPluginByName("kubernetes.io/host-path")
if err != nil { if err != nil {
...@@ -73,7 +73,7 @@ func TestCanSupport(t *testing.T) { ...@@ -73,7 +73,7 @@ func TestCanSupport(t *testing.T) {
func TestGetAccessModes(t *testing.T) { func TestGetAccessModes(t *testing.T) {
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{}), volumetest.NewFakeVolumeHost("/tmp/fake", nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{}), nil /* prober */, volumetest.NewFakeVolumeHost("/tmp/fake", nil, nil))
plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/host-path") plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/host-path")
if err != nil { if err != nil {
...@@ -87,7 +87,7 @@ func TestGetAccessModes(t *testing.T) { ...@@ -87,7 +87,7 @@ func TestGetAccessModes(t *testing.T) {
func TestRecycler(t *testing.T) { func TestRecycler(t *testing.T) {
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
pluginHost := volumetest.NewFakeVolumeHost("/tmp/fake", nil, nil) pluginHost := volumetest.NewFakeVolumeHost("/tmp/fake", nil, nil)
plugMgr.InitPlugins([]volume.VolumePlugin{&hostPathPlugin{nil, volume.VolumeConfig{}}}, pluginHost) plugMgr.InitPlugins([]volume.VolumePlugin{&hostPathPlugin{nil, volume.VolumeConfig{}}}, nil, pluginHost)
spec := &volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{HostPath: &v1.HostPathVolumeSource{Path: "/foo"}}}}} spec := &volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{HostPath: &v1.HostPathVolumeSource{Path: "/foo"}}}}}
_, err := plugMgr.FindRecyclablePluginBySpec(spec) _, err := plugMgr.FindRecyclablePluginBySpec(spec)
...@@ -106,7 +106,7 @@ func TestDeleter(t *testing.T) { ...@@ -106,7 +106,7 @@ func TestDeleter(t *testing.T) {
} }
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{}), volumetest.NewFakeVolumeHost("/tmp/fake", nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{}), nil /* prober */, volumetest.NewFakeVolumeHost("/tmp/fake", nil, nil))
spec := &volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{HostPath: &v1.HostPathVolumeSource{Path: tempPath}}}}} spec := &volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{HostPath: &v1.HostPathVolumeSource{Path: tempPath}}}}}
plug, err := plugMgr.FindDeletablePluginBySpec(spec) plug, err := plugMgr.FindDeletablePluginBySpec(spec)
...@@ -140,7 +140,7 @@ func TestDeleterTempDir(t *testing.T) { ...@@ -140,7 +140,7 @@ func TestDeleterTempDir(t *testing.T) {
for name, test := range tests { for name, test := range tests {
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{}), volumetest.NewFakeVolumeHost("/tmp/fake", nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{}), nil /* prober */, volumetest.NewFakeVolumeHost("/tmp/fake", nil, nil))
spec := &volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{HostPath: &v1.HostPathVolumeSource{Path: test.path}}}}} spec := &volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{HostPath: &v1.HostPathVolumeSource{Path: test.path}}}}}
plug, _ := plugMgr.FindDeletablePluginBySpec(spec) plug, _ := plugMgr.FindDeletablePluginBySpec(spec)
deleter, _ := plug.NewDeleter(spec) deleter, _ := plug.NewDeleter(spec)
...@@ -161,6 +161,7 @@ func TestProvisioner(t *testing.T) { ...@@ -161,6 +161,7 @@ func TestProvisioner(t *testing.T) {
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{ProvisioningEnabled: true}), plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{ProvisioningEnabled: true}),
nil,
volumetest.NewFakeVolumeHost("/tmp/fake", nil, nil)) volumetest.NewFakeVolumeHost("/tmp/fake", nil, nil))
spec := &volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{HostPath: &v1.HostPathVolumeSource{Path: tempPath}}}}} spec := &volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{HostPath: &v1.HostPathVolumeSource{Path: tempPath}}}}}
plug, err := plugMgr.FindCreatablePluginBySpec(spec) plug, err := plugMgr.FindCreatablePluginBySpec(spec)
...@@ -199,7 +200,7 @@ func TestProvisioner(t *testing.T) { ...@@ -199,7 +200,7 @@ func TestProvisioner(t *testing.T) {
func TestInvalidHostPath(t *testing.T) { func TestInvalidHostPath(t *testing.T) {
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{}), volumetest.NewFakeVolumeHost("fake", nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{}), nil /* prober */, volumetest.NewFakeVolumeHost("fake", nil, nil))
plug, err := plugMgr.FindPluginByName(hostPathPluginName) plug, err := plugMgr.FindPluginByName(hostPathPluginName)
if err != nil { if err != nil {
...@@ -224,7 +225,7 @@ func TestInvalidHostPath(t *testing.T) { ...@@ -224,7 +225,7 @@ func TestInvalidHostPath(t *testing.T) {
func TestPlugin(t *testing.T) { func TestPlugin(t *testing.T) {
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{}), volumetest.NewFakeVolumeHost("fake", nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{}), nil /* prober */, volumetest.NewFakeVolumeHost("fake", nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/host-path") plug, err := plugMgr.FindPluginByName("kubernetes.io/host-path")
if err != nil { if err != nil {
...@@ -300,7 +301,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) { ...@@ -300,7 +301,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) {
client := fake.NewSimpleClientset(pv, claim) client := fake.NewSimpleClientset(pv, claim)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{}), volumetest.NewFakeVolumeHost("/tmp/fake", client, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{}), nil /* prober */, volumetest.NewFakeVolumeHost("/tmp/fake", client, nil))
plug, _ := plugMgr.FindPluginByName(hostPathPluginName) plug, _ := plugMgr.FindPluginByName(hostPathPluginName)
// readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes // readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes
......
...@@ -39,7 +39,7 @@ func TestCanSupport(t *testing.T) { ...@@ -39,7 +39,7 @@ func TestCanSupport(t *testing.T) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/iscsi") plug, err := plugMgr.FindPluginByName("kubernetes.io/iscsi")
if err != nil { if err != nil {
...@@ -61,7 +61,7 @@ func TestGetAccessModes(t *testing.T) { ...@@ -61,7 +61,7 @@ func TestGetAccessModes(t *testing.T) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/iscsi") plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/iscsi")
if err != nil { if err != nil {
...@@ -132,7 +132,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) { ...@@ -132,7 +132,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/iscsi") plug, err := plugMgr.FindPluginByName("kubernetes.io/iscsi")
if err != nil { if err != nil {
...@@ -276,7 +276,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) { ...@@ -276,7 +276,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) {
client := fake.NewSimpleClientset(pv, claim) client := fake.NewSimpleClientset(pv, claim)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, client, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, client, nil))
plug, _ := plugMgr.FindPluginByName(iscsiPluginName) plug, _ := plugMgr.FindPluginByName(iscsiPluginName)
// readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes // readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes
......
...@@ -294,6 +294,9 @@ func (util *ISCSIUtil) AttachDisk(b iscsiDiskMounter) error { ...@@ -294,6 +294,9 @@ func (util *ISCSIUtil) AttachDisk(b iscsiDiskMounter) error {
// mount it // mount it
globalPDPath := b.manager.MakeGlobalPDName(*b.iscsiDisk) globalPDPath := b.manager.MakeGlobalPDName(*b.iscsiDisk)
notMnt, err := b.mounter.IsLikelyNotMountPoint(globalPDPath) notMnt, err := b.mounter.IsLikelyNotMountPoint(globalPDPath)
if err != nil {
return fmt.Errorf("Heuristic determination of mount point failed:%v", err)
}
if !notMnt { if !notMnt {
glog.Infof("iscsi: %s already mounted", globalPDPath) glog.Infof("iscsi: %s already mounted", globalPDPath)
return nil return nil
......
...@@ -44,7 +44,7 @@ func getPlugin(t *testing.T) (string, volume.VolumePlugin) { ...@@ -44,7 +44,7 @@ func getPlugin(t *testing.T) (string, volume.VolumePlugin) {
} }
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName(localVolumePluginName) plug, err := plugMgr.FindPluginByName(localVolumePluginName)
if err != nil { if err != nil {
...@@ -64,7 +64,7 @@ func getPersistentPlugin(t *testing.T) (string, volume.PersistentVolumePlugin) { ...@@ -64,7 +64,7 @@ func getPersistentPlugin(t *testing.T) (string, volume.PersistentVolumePlugin) {
} }
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPersistentPluginByName(localVolumePluginName) plug, err := plugMgr.FindPersistentPluginByName(localVolumePluginName)
if err != nil { if err != nil {
...@@ -337,7 +337,7 @@ func TestUnsupportedPlugins(t *testing.T) { ...@@ -337,7 +337,7 @@ func TestUnsupportedPlugins(t *testing.T) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
spec := getTestVolume(false, tmpDir) spec := getTestVolume(false, tmpDir)
recyclePlug, err := plugMgr.FindRecyclablePluginBySpec(spec) recyclePlug, err := plugMgr.FindRecyclablePluginBySpec(spec)
......
...@@ -39,7 +39,7 @@ func TestCanSupport(t *testing.T) { ...@@ -39,7 +39,7 @@ func TestCanSupport(t *testing.T) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{}), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{}), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/nfs") plug, err := plugMgr.FindPluginByName("kubernetes.io/nfs")
if err != nil { if err != nil {
t.Errorf("Can't find the plugin by name") t.Errorf("Can't find the plugin by name")
...@@ -67,7 +67,7 @@ func TestGetAccessModes(t *testing.T) { ...@@ -67,7 +67,7 @@ func TestGetAccessModes(t *testing.T) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{}), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{}), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/nfs") plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/nfs")
if err != nil { if err != nil {
...@@ -86,7 +86,7 @@ func TestRecycler(t *testing.T) { ...@@ -86,7 +86,7 @@ func TestRecycler(t *testing.T) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins([]volume.VolumePlugin{&nfsPlugin{nil, volume.VolumeConfig{}}}, volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins([]volume.VolumePlugin{&nfsPlugin{nil, volume.VolumeConfig{}}}, nil, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
spec := &volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{NFS: &v1.NFSVolumeSource{Path: "/foo"}}}}} spec := &volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{NFS: &v1.NFSVolumeSource{Path: "/foo"}}}}}
_, plugin_err := plugMgr.FindRecyclablePluginBySpec(spec) _, plugin_err := plugMgr.FindRecyclablePluginBySpec(spec)
...@@ -112,7 +112,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) { ...@@ -112,7 +112,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{}), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{}), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/nfs") plug, err := plugMgr.FindPluginByName("kubernetes.io/nfs")
if err != nil { if err != nil {
t.Errorf("Can't find the plugin by name") t.Errorf("Can't find the plugin by name")
...@@ -240,7 +240,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) { ...@@ -240,7 +240,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) {
client := fake.NewSimpleClientset(pv, claim) client := fake.NewSimpleClientset(pv, claim)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{}), volumetest.NewFakeVolumeHost(tmpDir, client, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(volume.VolumeConfig{}), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, client, nil))
plug, _ := plugMgr.FindPluginByName(nfsPluginName) plug, _ := plugMgr.FindPluginByName(nfsPluginName)
// readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes // readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes
......
...@@ -37,7 +37,7 @@ func TestCanSupport(t *testing.T) { ...@@ -37,7 +37,7 @@ func TestCanSupport(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/photon-pd") plug, err := plugMgr.FindPluginByName("kubernetes.io/photon-pd")
if err != nil { if err != nil {
...@@ -61,7 +61,7 @@ func TestGetAccessModes(t *testing.T) { ...@@ -61,7 +61,7 @@ func TestGetAccessModes(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/photon-pd") plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/photon-pd")
if err != nil { if err != nil {
...@@ -106,7 +106,7 @@ func TestPlugin(t *testing.T) { ...@@ -106,7 +106,7 @@ func TestPlugin(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/photon-pd") plug, err := plugMgr.FindPluginByName("kubernetes.io/photon-pd")
if err != nil { if err != nil {
...@@ -179,6 +179,9 @@ func TestPlugin(t *testing.T) { ...@@ -179,6 +179,9 @@ func TestPlugin(t *testing.T) {
PersistentVolumeReclaimPolicy: v1.PersistentVolumeReclaimDelete, PersistentVolumeReclaimPolicy: v1.PersistentVolumeReclaimDelete,
} }
provisioner, err := plug.(*photonPersistentDiskPlugin).newProvisionerInternal(options, &fakePDManager{}) provisioner, err := plug.(*photonPersistentDiskPlugin).newProvisionerInternal(options, &fakePDManager{})
if err != nil {
t.Fatalf("Error creating new provisioner:%v", err)
}
persistentSpec, err := provisioner.Provision() persistentSpec, err := provisioner.Provision()
if err != nil { if err != nil {
t.Errorf("Provision() failed: %v", err) t.Errorf("Provision() failed: %v", err)
...@@ -198,6 +201,9 @@ func TestPlugin(t *testing.T) { ...@@ -198,6 +201,9 @@ func TestPlugin(t *testing.T) {
PersistentVolume: persistentSpec, PersistentVolume: persistentSpec,
} }
deleter, err := plug.(*photonPersistentDiskPlugin).newDeleterInternal(volSpec, &fakePDManager{}) deleter, err := plug.(*photonPersistentDiskPlugin).newDeleterInternal(volSpec, &fakePDManager{})
if err != nil {
t.Fatalf("Error creating new deleter:%v", err)
}
err = deleter.Delete() err = deleter.Delete()
if err != nil { if err != nil {
t.Errorf("Deleter() failed: %v", err) t.Errorf("Deleter() failed: %v", err)
...@@ -211,7 +217,7 @@ func TestMounterAndUnmounterTypeAssert(t *testing.T) { ...@@ -211,7 +217,7 @@ func TestMounterAndUnmounterTypeAssert(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/photon-pd") plug, err := plugMgr.FindPluginByName("kubernetes.io/photon-pd")
if err != nil { if err != nil {
...@@ -228,11 +234,17 @@ func TestMounterAndUnmounterTypeAssert(t *testing.T) { ...@@ -228,11 +234,17 @@ func TestMounterAndUnmounterTypeAssert(t *testing.T) {
} }
mounter, err := plug.(*photonPersistentDiskPlugin).newMounterInternal(volume.NewSpecFromVolume(spec), types.UID("poduid"), &fakePDManager{}, &mount.FakeMounter{}) mounter, err := plug.(*photonPersistentDiskPlugin).newMounterInternal(volume.NewSpecFromVolume(spec), types.UID("poduid"), &fakePDManager{}, &mount.FakeMounter{})
if err != nil {
t.Fatalf("Error creating new mounter:%v", err)
}
if _, ok := mounter.(volume.Unmounter); ok { if _, ok := mounter.(volume.Unmounter); ok {
t.Errorf("Volume Mounter can be type-assert to Unmounter") t.Errorf("Volume Mounter can be type-assert to Unmounter")
} }
unmounter, err := plug.(*photonPersistentDiskPlugin).newUnmounterInternal("vol1", types.UID("poduid"), &fakePDManager{}, &mount.FakeMounter{}) unmounter, err := plug.(*photonPersistentDiskPlugin).newUnmounterInternal("vol1", types.UID("poduid"), &fakePDManager{}, &mount.FakeMounter{})
if err != nil {
t.Fatalf("Error creating new unmounter:%v", err)
}
if _, ok := unmounter.(volume.Mounter); ok { if _, ok := unmounter.(volume.Mounter); ok {
t.Errorf("Volume Unmounter can be type-assert to Mounter") t.Errorf("Volume Unmounter can be type-assert to Mounter")
} }
......
...@@ -70,6 +70,17 @@ type VolumeOptions struct { ...@@ -70,6 +70,17 @@ type VolumeOptions struct {
Containerized bool Containerized bool
} }
type DynamicPluginProber interface {
Init() error
// If an update has occurred since the last probe, updated = true
// and the list of probed plugins is returned.
// Otherwise, update = false and probedPlugins = nil.
//
// If an error occurs, updated and probedPlugins are undefined.
Probe() (updated bool, probedPlugins []VolumePlugin, err error)
}
// VolumePlugin is an interface to volume plugins that can be used on a // VolumePlugin is an interface to volume plugins that can be used on a
// kubernetes node (e.g. by kubelet) to instantiate and manage volumes. // kubernetes node (e.g. by kubelet) to instantiate and manage volumes.
type VolumePlugin interface { type VolumePlugin interface {
...@@ -255,9 +266,11 @@ type VolumeHost interface { ...@@ -255,9 +266,11 @@ type VolumeHost interface {
// VolumePluginMgr tracks registered plugins. // VolumePluginMgr tracks registered plugins.
type VolumePluginMgr struct { type VolumePluginMgr struct {
mutex sync.Mutex mutex sync.Mutex
plugins map[string]VolumePlugin plugins map[string]VolumePlugin
Host VolumeHost prober DynamicPluginProber
probedPlugins []VolumePlugin
Host VolumeHost
} }
// Spec is an internal representation of a volume. All API volume types translate to Spec. // Spec is an internal representation of a volume. All API volume types translate to Spec.
...@@ -352,11 +365,24 @@ func NewSpecFromPersistentVolume(pv *v1.PersistentVolume, readOnly bool) *Spec { ...@@ -352,11 +365,24 @@ func NewSpecFromPersistentVolume(pv *v1.PersistentVolume, readOnly bool) *Spec {
// InitPlugins initializes each plugin. All plugins must have unique names. // InitPlugins initializes each plugin. All plugins must have unique names.
// This must be called exactly once before any New* methods are called on any // This must be called exactly once before any New* methods are called on any
// plugins. // plugins.
func (pm *VolumePluginMgr) InitPlugins(plugins []VolumePlugin, host VolumeHost) error { func (pm *VolumePluginMgr) InitPlugins(plugins []VolumePlugin, prober DynamicPluginProber, host VolumeHost) error {
pm.mutex.Lock() pm.mutex.Lock()
defer pm.mutex.Unlock() defer pm.mutex.Unlock()
pm.Host = host pm.Host = host
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.
glog.Errorf("Error initializing dynamic plugin prober: %s", err)
pm.prober = &dummyPluginProber{}
}
if pm.plugins == nil { if pm.plugins == nil {
pm.plugins = map[string]VolumePlugin{} pm.plugins = map[string]VolumePlugin{}
} }
...@@ -385,6 +411,21 @@ func (pm *VolumePluginMgr) InitPlugins(plugins []VolumePlugin, host VolumeHost) ...@@ -385,6 +411,21 @@ func (pm *VolumePluginMgr) InitPlugins(plugins []VolumePlugin, host VolumeHost)
return utilerrors.NewAggregate(allErrs) 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())
}
glog.V(1).Infof("Loaded volume plugin %q", name)
return nil
}
// FindPluginBySpec looks for a plugin that can support a given volume // FindPluginBySpec looks for a plugin that can support a given volume
// specification. If no plugins can support or more than one plugin can // specification. If no plugins can support or more than one plugin can
// support it, return error. // support it, return error.
...@@ -396,19 +437,30 @@ func (pm *VolumePluginMgr) FindPluginBySpec(spec *Spec) (VolumePlugin, error) { ...@@ -396,19 +437,30 @@ func (pm *VolumePluginMgr) FindPluginBySpec(spec *Spec) (VolumePlugin, error) {
return nil, fmt.Errorf("Could not find plugin because volume spec is nil") return nil, fmt.Errorf("Could not find plugin because volume spec is nil")
} }
matches := []string{} matchedPluginNames := []string{}
matches := []VolumePlugin{}
for k, v := range pm.plugins { for k, v := range pm.plugins {
if v.CanSupport(spec) { if v.CanSupport(spec) {
matches = append(matches, k) matchedPluginNames = append(matchedPluginNames, k)
matches = append(matches, v)
} }
} }
pm.refreshProbedPlugins()
for _, plugin := range pm.probedPlugins {
if plugin.CanSupport(spec) {
matchedPluginNames = append(matchedPluginNames, plugin.GetPluginName())
matches = append(matches, plugin)
}
}
if len(matches) == 0 { if len(matches) == 0 {
return nil, fmt.Errorf("no volume plugin matched") return nil, fmt.Errorf("no volume plugin matched")
} }
if len(matches) > 1 { if len(matches) > 1 {
return nil, fmt.Errorf("multiple volume plugins matched: %s", strings.Join(matches, ",")) return nil, fmt.Errorf("multiple volume plugins matched: %s", strings.Join(matchedPluginNames, ","))
} }
return pm.plugins[matches[0]], nil return matches[0], nil
} }
// FindPluginByName fetches a plugin by name or by legacy name. If no plugin // FindPluginByName fetches a plugin by name or by legacy name. If no plugin
...@@ -418,19 +470,52 @@ func (pm *VolumePluginMgr) FindPluginByName(name string) (VolumePlugin, error) { ...@@ -418,19 +470,52 @@ func (pm *VolumePluginMgr) FindPluginByName(name string) (VolumePlugin, error) {
defer pm.mutex.Unlock() defer pm.mutex.Unlock()
// Once we can get rid of legacy names we can reduce this to a map lookup. // Once we can get rid of legacy names we can reduce this to a map lookup.
matches := []string{} matchedPluginNames := []string{}
matches := []VolumePlugin{}
for k, v := range pm.plugins { for k, v := range pm.plugins {
if v.GetPluginName() == name { if v.GetPluginName() == name {
matches = append(matches, k) matchedPluginNames = append(matchedPluginNames, k)
matches = append(matches, v)
} }
} }
pm.refreshProbedPlugins()
for _, plugin := range pm.probedPlugins {
if plugin.GetPluginName() == name {
matchedPluginNames = append(matchedPluginNames, plugin.GetPluginName())
matches = append(matches, plugin)
}
}
if len(matches) == 0 { if len(matches) == 0 {
return nil, fmt.Errorf("no volume plugin matched") return nil, fmt.Errorf("no volume plugin matched")
} }
if len(matches) > 1 { if len(matches) > 1 {
return nil, fmt.Errorf("multiple volume plugins matched: %s", strings.Join(matches, ",")) return nil, fmt.Errorf("multiple volume plugins matched: %s", strings.Join(matchedPluginNames, ","))
}
return matches[0], 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() {
updated, plugins, err := pm.prober.Probe()
if err != nil {
glog.Errorf("Error dynamically probing plugins: %s", err)
return // Use cached plugins upon failure.
}
if updated {
pm.probedPlugins = []VolumePlugin{}
for _, plugin := range plugins {
if err := pm.initProbedPlugin(plugin); err != nil {
glog.Errorf("Error initializing dynamically probed plugin %s; error: %s",
plugin.GetPluginName(), err)
continue
}
pm.probedPlugins = append(pm.probedPlugins, plugin)
}
} }
return pm.plugins[matches[0]], nil
} }
// FindPersistentPluginBySpec looks for a persistent volume plugin that can // FindPersistentPluginBySpec looks for a persistent volume plugin that can
...@@ -618,3 +703,8 @@ func ValidateRecyclerPodTemplate(pod *v1.Pod) error { ...@@ -618,3 +703,8 @@ func ValidateRecyclerPodTemplate(pod *v1.Pod) error {
} }
return nil return nil
} }
type dummyPluginProber struct{}
func (*dummyPluginProber) Init() error { return nil }
func (*dummyPluginProber) Probe() (bool, []VolumePlugin, error) { return false, nil, nil }
...@@ -103,7 +103,8 @@ func newTestPlugin() []VolumePlugin { ...@@ -103,7 +103,8 @@ func newTestPlugin() []VolumePlugin {
func TestVolumePluginMgrFunc(t *testing.T) { func TestVolumePluginMgrFunc(t *testing.T) {
vpm := VolumePluginMgr{} vpm := VolumePluginMgr{}
vpm.InitPlugins(newTestPlugin(), nil) var prober DynamicPluginProber = nil // TODO (#51147) inject mock
vpm.InitPlugins(newTestPlugin(), prober, nil)
plug, err := vpm.FindPluginByName("testPlugin") plug, err := vpm.FindPluginByName("testPlugin")
if err != nil { if err != nil {
......
...@@ -41,7 +41,7 @@ func TestCanSupport(t *testing.T) { ...@@ -41,7 +41,7 @@ func TestCanSupport(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/portworx-volume") plug, err := plugMgr.FindPluginByName("kubernetes.io/portworx-volume")
if err != nil { if err != nil {
...@@ -65,7 +65,7 @@ func TestGetAccessModes(t *testing.T) { ...@@ -65,7 +65,7 @@ func TestGetAccessModes(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/portworx-volume") plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/portworx-volume")
if err != nil { if err != nil {
...@@ -135,7 +135,7 @@ func TestPlugin(t *testing.T) { ...@@ -135,7 +135,7 @@ func TestPlugin(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/portworx-volume") plug, err := plugMgr.FindPluginByName("kubernetes.io/portworx-volume")
if err != nil { if err != nil {
......
...@@ -670,7 +670,7 @@ func TestCanSupport(t *testing.T) { ...@@ -670,7 +670,7 @@ func TestCanSupport(t *testing.T) {
pluginMgr := volume.VolumePluginMgr{} pluginMgr := volume.VolumePluginMgr{}
tempDir, host := newTestHost(t, nil) tempDir, host := newTestHost(t, nil)
defer os.RemoveAll(tempDir) defer os.RemoveAll(tempDir)
pluginMgr.InitPlugins(ProbeVolumePlugins(), host) pluginMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, host)
plugin, err := pluginMgr.FindPluginByName(projectedPluginName) plugin, err := pluginMgr.FindPluginByName(projectedPluginName)
if err != nil { if err != nil {
...@@ -701,7 +701,7 @@ func TestPlugin(t *testing.T) { ...@@ -701,7 +701,7 @@ func TestPlugin(t *testing.T) {
rootDir, host = newTestHost(t, client) rootDir, host = newTestHost(t, client)
) )
defer os.RemoveAll(rootDir) defer os.RemoveAll(rootDir)
pluginMgr.InitPlugins(ProbeVolumePlugins(), host) pluginMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, host)
plugin, err := pluginMgr.FindPluginByName(projectedPluginName) plugin, err := pluginMgr.FindPluginByName(projectedPluginName)
if err != nil { if err != nil {
...@@ -765,7 +765,7 @@ func TestPluginReboot(t *testing.T) { ...@@ -765,7 +765,7 @@ func TestPluginReboot(t *testing.T) {
rootDir, host = newTestHost(t, client) rootDir, host = newTestHost(t, client)
) )
defer os.RemoveAll(rootDir) defer os.RemoveAll(rootDir)
pluginMgr.InitPlugins(ProbeVolumePlugins(), host) pluginMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, host)
plugin, err := pluginMgr.FindPluginByName(projectedPluginName) plugin, err := pluginMgr.FindPluginByName(projectedPluginName)
if err != nil { if err != nil {
...@@ -819,7 +819,7 @@ func TestPluginOptional(t *testing.T) { ...@@ -819,7 +819,7 @@ func TestPluginOptional(t *testing.T) {
) )
volumeSpec.VolumeSource.Projected.Sources[0].Secret.Optional = &trueVal volumeSpec.VolumeSource.Projected.Sources[0].Secret.Optional = &trueVal
defer os.RemoveAll(rootDir) defer os.RemoveAll(rootDir)
pluginMgr.InitPlugins(ProbeVolumePlugins(), host) pluginMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, host)
plugin, err := pluginMgr.FindPluginByName(projectedPluginName) plugin, err := pluginMgr.FindPluginByName(projectedPluginName)
if err != nil { if err != nil {
...@@ -896,7 +896,7 @@ func TestPluginOptionalKeys(t *testing.T) { ...@@ -896,7 +896,7 @@ func TestPluginOptionalKeys(t *testing.T) {
} }
volumeSpec.VolumeSource.Projected.Sources[0].Secret.Optional = &trueVal volumeSpec.VolumeSource.Projected.Sources[0].Secret.Optional = &trueVal
defer os.RemoveAll(rootDir) defer os.RemoveAll(rootDir)
pluginMgr.InitPlugins(ProbeVolumePlugins(), host) pluginMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, host)
plugin, err := pluginMgr.FindPluginByName(projectedPluginName) plugin, err := pluginMgr.FindPluginByName(projectedPluginName)
if err != nil { if err != nil {
......
...@@ -39,7 +39,7 @@ func TestCanSupport(t *testing.T) { ...@@ -39,7 +39,7 @@ func TestCanSupport(t *testing.T) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/quobyte") plug, err := plugMgr.FindPluginByName("kubernetes.io/quobyte")
if err != nil { if err != nil {
t.Errorf("Can't find the plugin by name") t.Errorf("Can't find the plugin by name")
...@@ -63,7 +63,7 @@ func TestGetAccessModes(t *testing.T) { ...@@ -63,7 +63,7 @@ func TestGetAccessModes(t *testing.T) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/quobyte") plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/quobyte")
if err != nil { if err != nil {
...@@ -91,7 +91,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) { ...@@ -91,7 +91,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/quobyte") plug, err := plugMgr.FindPluginByName("kubernetes.io/quobyte")
if err != nil { if err != nil {
t.Errorf("Can't find the plugin by name") t.Errorf("Can't find the plugin by name")
...@@ -187,7 +187,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) { ...@@ -187,7 +187,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) {
client := fake.NewSimpleClientset(pv, claim) client := fake.NewSimpleClientset(pv, claim)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, client, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, client, nil))
plug, _ := plugMgr.FindPluginByName(quobytePluginName) plug, _ := plugMgr.FindPluginByName(quobytePluginName)
// readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes // readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes
......
...@@ -39,7 +39,7 @@ func TestCanSupport(t *testing.T) { ...@@ -39,7 +39,7 @@ func TestCanSupport(t *testing.T) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/rbd") plug, err := plugMgr.FindPluginByName("kubernetes.io/rbd")
if err != nil { if err != nil {
...@@ -104,7 +104,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) { ...@@ -104,7 +104,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/rbd") plug, err := plugMgr.FindPluginByName("kubernetes.io/rbd")
if err != nil { if err != nil {
...@@ -229,7 +229,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) { ...@@ -229,7 +229,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) {
client := fake.NewSimpleClientset(pv, claim) client := fake.NewSimpleClientset(pv, claim)
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, client, nil)) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, client, nil))
plug, _ := plugMgr.FindPluginByName(rbdPluginName) plug, _ := plugMgr.FindPluginByName(rbdPluginName)
// readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes // readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes
......
...@@ -212,10 +212,13 @@ func TestUtilLoadConfig(t *testing.T) { ...@@ -212,10 +212,13 @@ func TestUtilLoadConfig(t *testing.T) {
configFile := path.Join(tmpDir, sioConfigFileName) configFile := path.Join(tmpDir, sioConfigFileName)
if err := saveConfig(configFile, config); err != nil { if err := saveConfig(configFile, config); err != nil {
t.Fatal("failed while saving data", err) t.Fatalf("failed to save configFile %s error:%v", configFile, err)
} }
dataRcvd, err := loadConfig(configFile) dataRcvd, err := loadConfig(configFile)
if err != nil {
t.Fatalf("failed to load configFile %s error:%v", configFile, err)
}
if dataRcvd[confKey.gateway] != config[confKey.gateway] || if dataRcvd[confKey.gateway] != config[confKey.gateway] ||
dataRcvd[confKey.system] != config[confKey.system] { dataRcvd[confKey.system] != config[confKey.system] {
t.Fatal("loaded config data not matching saved config data") t.Fatal("loaded config data not matching saved config data")
......
...@@ -63,7 +63,7 @@ func newPluginMgr(t *testing.T) (*volume.VolumePluginMgr, string) { ...@@ -63,7 +63,7 @@ func newPluginMgr(t *testing.T) (*volume.VolumePluginMgr, string) {
fakeClient := fakeclient.NewSimpleClientset(config) fakeClient := fakeclient.NewSimpleClientset(config)
host := volumetest.NewFakeVolumeHost(tmpDir, fakeClient, nil) host := volumetest.NewFakeVolumeHost(tmpDir, fakeClient, nil)
plugMgr := &volume.VolumePluginMgr{} plugMgr := &volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), host) plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, host)
return plugMgr, tmpDir return plugMgr, tmpDir
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment