Update go dependencies
This commit is contained in:
parent
c8a3710fb8
commit
fcb1b6217b
162 changed files with 6806 additions and 7275 deletions
22
vendor/k8s.io/kubernetes/pkg/api/legacyscheme/scheme.go
generated
vendored
22
vendor/k8s.io/kubernetes/pkg/api/legacyscheme/scheme.go
generated
vendored
|
|
@ -21,15 +21,17 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
)
|
||||
|
||||
// Scheme is the default instance of runtime.Scheme to which types in the Kubernetes API are already registered.
|
||||
// NOTE: If you are copying this file to start a new api group, STOP! Copy the
|
||||
// extensions group instead. This Scheme is special and should appear ONLY in
|
||||
// the api group, unless you really know what you're doing.
|
||||
// TODO(lavalamp): make the above error impossible.
|
||||
var Scheme = runtime.NewScheme()
|
||||
var (
|
||||
// Scheme is the default instance of runtime.Scheme to which types in the Kubernetes API are already registered.
|
||||
// NOTE: If you are copying this file to start a new api group, STOP! Copy the
|
||||
// extensions group instead. This Scheme is special and should appear ONLY in
|
||||
// the api group, unless you really know what you're doing.
|
||||
// TODO(lavalamp): make the above error impossible.
|
||||
Scheme = runtime.NewScheme()
|
||||
|
||||
// Codecs provides access to encoding and decoding for the scheme
|
||||
var Codecs = serializer.NewCodecFactory(Scheme)
|
||||
// Codecs provides access to encoding and decoding for the scheme
|
||||
Codecs = serializer.NewCodecFactory(Scheme)
|
||||
|
||||
// ParameterCodec handles versioning of objects that are converted to query parameters.
|
||||
var ParameterCodec = runtime.NewParameterCodec(Scheme)
|
||||
// ParameterCodec handles versioning of objects that are converted to query parameters.
|
||||
ParameterCodec = runtime.NewParameterCodec(Scheme)
|
||||
)
|
||||
|
|
|
|||
32
vendor/k8s.io/kubernetes/pkg/features/BUILD
generated
vendored
Normal file
32
vendor/k8s.io/kubernetes/pkg/features/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["kube_features.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/features",
|
||||
deps = [
|
||||
"//staging/src/k8s.io/apiextensions-apiserver/pkg/features:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/features:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//staging/src/k8s.io/component-base/featuregate:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
4
vendor/k8s.io/kubernetes/pkg/features/OWNERS
generated
vendored
Normal file
4
vendor/k8s.io/kubernetes/pkg/features/OWNERS
generated
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# See the OWNERS docs at https://go.k8s.io/owners
|
||||
|
||||
approvers:
|
||||
- feature-approvers
|
||||
585
vendor/k8s.io/kubernetes/pkg/features/kube_features.go
generated
vendored
Normal file
585
vendor/k8s.io/kubernetes/pkg/features/kube_features.go
generated
vendored
Normal file
|
|
@ -0,0 +1,585 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package features
|
||||
|
||||
import (
|
||||
apiextensionsfeatures "k8s.io/apiextensions-apiserver/pkg/features"
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
genericfeatures "k8s.io/apiserver/pkg/features"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/component-base/featuregate"
|
||||
)
|
||||
|
||||
const (
|
||||
// Every feature gate should add method here following this template:
|
||||
//
|
||||
// // owner: @username
|
||||
// // alpha: v1.X
|
||||
// MyFeature featuregate.Feature = "MyFeature"
|
||||
|
||||
// owner: @tallclair
|
||||
// beta: v1.4
|
||||
AppArmor featuregate.Feature = "AppArmor"
|
||||
|
||||
// owner: @mtaufen
|
||||
// alpha: v1.4
|
||||
// beta: v1.11
|
||||
DynamicKubeletConfig featuregate.Feature = "DynamicKubeletConfig"
|
||||
|
||||
// owner: @pweil-
|
||||
// alpha: v1.5
|
||||
//
|
||||
// Default userns=host for containers that are using other host namespaces, host mounts, the pod
|
||||
// contains a privileged container, or specific non-namespaced capabilities (MKNOD, SYS_MODULE,
|
||||
// SYS_TIME). This should only be enabled if user namespace remapping is enabled in the docker daemon.
|
||||
ExperimentalHostUserNamespaceDefaultingGate featuregate.Feature = "ExperimentalHostUserNamespaceDefaulting"
|
||||
|
||||
// owner: @vishh
|
||||
// alpha: v1.5
|
||||
//
|
||||
// DEPRECATED - This feature is deprecated by Pod Priority and Preemption as of Kubernetes 1.13.
|
||||
// Ensures guaranteed scheduling of pods marked with a special pod annotation `scheduler.alpha.kubernetes.io/critical-pod`
|
||||
// and also prevents them from being evicted from a node.
|
||||
// Note: This feature is not supported for `BestEffort` pods.
|
||||
ExperimentalCriticalPodAnnotation featuregate.Feature = "ExperimentalCriticalPodAnnotation"
|
||||
|
||||
// owner: @jiayingz
|
||||
// beta: v1.10
|
||||
//
|
||||
// Enables support for Device Plugins
|
||||
DevicePlugins featuregate.Feature = "DevicePlugins"
|
||||
|
||||
// owner: @Huang-Wei
|
||||
// beta: v1.13
|
||||
//
|
||||
// Changes the logic behind evicting Pods from not ready Nodes
|
||||
// to take advantage of NoExecute Taints and Tolerations.
|
||||
TaintBasedEvictions featuregate.Feature = "TaintBasedEvictions"
|
||||
|
||||
// owner: @mikedanese
|
||||
// alpha: v1.7
|
||||
// beta: v1.12
|
||||
//
|
||||
// Gets a server certificate for the kubelet from the Certificate Signing
|
||||
// Request API instead of generating one self signed and auto rotates the
|
||||
// certificate as expiration approaches.
|
||||
RotateKubeletServerCertificate featuregate.Feature = "RotateKubeletServerCertificate"
|
||||
|
||||
// owner: @mikedanese
|
||||
// beta: v1.8
|
||||
//
|
||||
// Automatically renews the client certificate used for communicating with
|
||||
// the API server as the certificate approaches expiration.
|
||||
RotateKubeletClientCertificate featuregate.Feature = "RotateKubeletClientCertificate"
|
||||
|
||||
// owner: @msau42
|
||||
// alpha: v1.7
|
||||
// beta: v1.10
|
||||
// ga: v1.14
|
||||
//
|
||||
// A new volume type that supports local disks on a node.
|
||||
PersistentLocalVolumes featuregate.Feature = "PersistentLocalVolumes"
|
||||
|
||||
// owner: @jinxu
|
||||
// beta: v1.10
|
||||
//
|
||||
// New local storage types to support local storage capacity isolation
|
||||
LocalStorageCapacityIsolation featuregate.Feature = "LocalStorageCapacityIsolation"
|
||||
|
||||
// owner: @gnufied
|
||||
// beta: v1.11
|
||||
// Ability to Expand persistent volumes
|
||||
ExpandPersistentVolumes featuregate.Feature = "ExpandPersistentVolumes"
|
||||
|
||||
// owner: @mlmhl
|
||||
// beta: v1.15
|
||||
// Ability to expand persistent volumes' file system without unmounting volumes.
|
||||
ExpandInUsePersistentVolumes featuregate.Feature = "ExpandInUsePersistentVolumes"
|
||||
|
||||
// owner: @gnufied
|
||||
// alpha: v1.14
|
||||
// Ability to expand CSI volumes
|
||||
ExpandCSIVolumes featuregate.Feature = "ExpandCSIVolumes"
|
||||
|
||||
// owner: @verb
|
||||
// alpha: v1.10
|
||||
//
|
||||
// Allows running a "debug container" in a pod namespaces to troubleshoot a running pod.
|
||||
DebugContainers featuregate.Feature = "DebugContainers"
|
||||
|
||||
// owner: @verb
|
||||
// beta: v1.12
|
||||
//
|
||||
// Allows all containers in a pod to share a process namespace.
|
||||
PodShareProcessNamespace featuregate.Feature = "PodShareProcessNamespace"
|
||||
|
||||
// owner: @bsalamat
|
||||
// alpha: v1.8
|
||||
// beta: v1.11
|
||||
// GA: v1.14
|
||||
//
|
||||
// Add priority to pods. Priority affects scheduling and preemption of pods.
|
||||
PodPriority featuregate.Feature = "PodPriority"
|
||||
|
||||
// owner: @k82cn
|
||||
// beta: v1.12
|
||||
//
|
||||
// Taint nodes based on their condition status for 'NetworkUnavailable',
|
||||
// 'MemoryPressure', 'PIDPressure' and 'DiskPressure'.
|
||||
TaintNodesByCondition featuregate.Feature = "TaintNodesByCondition"
|
||||
|
||||
// owner: @sjenning
|
||||
// alpha: v1.11
|
||||
//
|
||||
// Allows resource reservations at the QoS level preventing pods at lower QoS levels from
|
||||
// bursting into resources requested at higher QoS levels (memory only for now)
|
||||
QOSReserved featuregate.Feature = "QOSReserved"
|
||||
|
||||
// owner: @ConnorDoyle
|
||||
// alpha: v1.8
|
||||
// beta: v1.10
|
||||
//
|
||||
// Alternative container-level CPU affinity policies.
|
||||
CPUManager featuregate.Feature = "CPUManager"
|
||||
|
||||
// owner: @szuecs
|
||||
// alpha: v1.12
|
||||
//
|
||||
// Enable nodes to change CPUCFSQuotaPeriod
|
||||
CPUCFSQuotaPeriod featuregate.Feature = "CustomCPUCFSQuotaPeriod"
|
||||
|
||||
// owner: @derekwaynecarr
|
||||
// beta: v1.10
|
||||
// GA: v1.14
|
||||
//
|
||||
// Enable pods to consume pre-allocated huge pages of varying page sizes
|
||||
HugePages featuregate.Feature = "HugePages"
|
||||
|
||||
// owner: @sjenning
|
||||
// beta: v1.11
|
||||
//
|
||||
// Enable pods to set sysctls on a pod
|
||||
Sysctls featuregate.Feature = "Sysctls"
|
||||
|
||||
// owner @brendandburns
|
||||
// alpha: v1.9
|
||||
//
|
||||
// Enable nodes to exclude themselves from service load balancers
|
||||
ServiceNodeExclusion featuregate.Feature = "ServiceNodeExclusion"
|
||||
|
||||
// owner: @jsafrane
|
||||
// alpha: v1.9
|
||||
//
|
||||
// Enable running mount utilities in containers.
|
||||
MountContainers featuregate.Feature = "MountContainers"
|
||||
|
||||
// owner: @msau42
|
||||
// GA: v1.13
|
||||
//
|
||||
// Extend the default scheduler to be aware of PV topology and handle PV binding
|
||||
VolumeScheduling featuregate.Feature = "VolumeScheduling"
|
||||
|
||||
// owner: @vladimirvivien
|
||||
// GA: v1.13
|
||||
//
|
||||
// Enable mount/attachment of Container Storage Interface (CSI) backed PVs
|
||||
CSIPersistentVolume featuregate.Feature = "CSIPersistentVolume"
|
||||
|
||||
// owner: @saad-ali
|
||||
// alpha: v1.12
|
||||
// beta: v1.14
|
||||
// Enable all logic related to the CSIDriver API object in storage.k8s.io
|
||||
CSIDriverRegistry featuregate.Feature = "CSIDriverRegistry"
|
||||
|
||||
// owner: @verult
|
||||
// alpha: v1.12
|
||||
// beta: v1.14
|
||||
// Enable all logic related to the CSINode API object in storage.k8s.io
|
||||
CSINodeInfo featuregate.Feature = "CSINodeInfo"
|
||||
|
||||
// owner @MrHohn
|
||||
// GA: v1.14
|
||||
//
|
||||
// Support configurable pod DNS parameters.
|
||||
CustomPodDNS featuregate.Feature = "CustomPodDNS"
|
||||
|
||||
// owner: @screeley44
|
||||
// alpha: v1.9
|
||||
// beta: v1.13
|
||||
//
|
||||
// Enable Block volume support in containers.
|
||||
BlockVolume featuregate.Feature = "BlockVolume"
|
||||
|
||||
// owner: @pospispa
|
||||
// GA: v1.11
|
||||
//
|
||||
// Postpone deletion of a PV or a PVC when they are being used
|
||||
StorageObjectInUseProtection featuregate.Feature = "StorageObjectInUseProtection"
|
||||
|
||||
// owner: @aveshagarwal
|
||||
// alpha: v1.9
|
||||
//
|
||||
// Enable resource limits priority function
|
||||
ResourceLimitsPriorityFunction featuregate.Feature = "ResourceLimitsPriorityFunction"
|
||||
|
||||
// owner: @m1093782566
|
||||
// GA: v1.11
|
||||
//
|
||||
// Implement IPVS-based in-cluster service load balancing
|
||||
SupportIPVSProxyMode featuregate.Feature = "SupportIPVSProxyMode"
|
||||
|
||||
// owner: @dims, @derekwaynecarr
|
||||
// alpha: v1.10
|
||||
// beta: v1.14
|
||||
//
|
||||
// Implement support for limiting pids in pods
|
||||
SupportPodPidsLimit featuregate.Feature = "SupportPodPidsLimit"
|
||||
|
||||
// owner: @feiskyer
|
||||
// alpha: v1.10
|
||||
//
|
||||
// Enable Hyper-V containers on Windows
|
||||
HyperVContainer featuregate.Feature = "HyperVContainer"
|
||||
|
||||
// owner: @k82cn
|
||||
// beta: v1.12
|
||||
//
|
||||
// Schedule DaemonSet Pods by default scheduler instead of DaemonSet controller
|
||||
ScheduleDaemonSetPods featuregate.Feature = "ScheduleDaemonSetPods"
|
||||
|
||||
// owner: @mikedanese
|
||||
// beta: v1.12
|
||||
//
|
||||
// Implement TokenRequest endpoint on service account resources.
|
||||
TokenRequest featuregate.Feature = "TokenRequest"
|
||||
|
||||
// owner: @mikedanese
|
||||
// beta: v1.12
|
||||
//
|
||||
// Enable ServiceAccountTokenVolumeProjection support in ProjectedVolumes.
|
||||
TokenRequestProjection featuregate.Feature = "TokenRequestProjection"
|
||||
|
||||
// owner: @mikedanese
|
||||
// alpha: v1.13
|
||||
//
|
||||
// Migrate ServiceAccount volumes to use a projected volume consisting of a
|
||||
// ServiceAccountTokenVolumeProjection. This feature adds new required flags
|
||||
// to the API server.
|
||||
BoundServiceAccountTokenVolume featuregate.Feature = "BoundServiceAccountTokenVolume"
|
||||
|
||||
// owner: @Random-Liu
|
||||
// beta: v1.11
|
||||
//
|
||||
// Enable container log rotation for cri container runtime
|
||||
CRIContainerLogRotation featuregate.Feature = "CRIContainerLogRotation"
|
||||
|
||||
// owner: @krmayankk
|
||||
// beta: v1.14
|
||||
//
|
||||
// Enables control over the primary group ID of containers' init processes.
|
||||
RunAsGroup featuregate.Feature = "RunAsGroup"
|
||||
|
||||
// owner: @saad-ali
|
||||
// ga
|
||||
//
|
||||
// Allow mounting a subpath of a volume in a container
|
||||
// Do not remove this feature gate even though it's GA
|
||||
VolumeSubpath featuregate.Feature = "VolumeSubpath"
|
||||
|
||||
// owner: @gnufied
|
||||
// beta : v1.12
|
||||
//
|
||||
// Add support for volume plugins to report node specific
|
||||
// volume limits
|
||||
AttachVolumeLimit featuregate.Feature = "AttachVolumeLimit"
|
||||
|
||||
// owner: @ravig
|
||||
// alpha: v1.11
|
||||
//
|
||||
// Include volume count on node to be considered for balanced resource allocation while scheduling.
|
||||
// A node which has closer cpu,memory utilization and volume count is favoured by scheduler
|
||||
// while making decisions.
|
||||
BalanceAttachedNodeVolumes featuregate.Feature = "BalanceAttachedNodeVolumes"
|
||||
|
||||
// owner @freehan
|
||||
// GA: v1.14
|
||||
//
|
||||
// Allow user to specify additional conditions to be evaluated for Pod readiness.
|
||||
PodReadinessGates featuregate.Feature = "PodReadinessGates"
|
||||
|
||||
// owner: @kevtaylor
|
||||
// beta: v1.15
|
||||
//
|
||||
// Allow subpath environment variable substitution
|
||||
// Only applicable if the VolumeSubpath feature is also enabled
|
||||
VolumeSubpathEnvExpansion featuregate.Feature = "VolumeSubpathEnvExpansion"
|
||||
|
||||
// owner: @vikaschoudhary16
|
||||
// GA: v1.13
|
||||
//
|
||||
//
|
||||
// Enable probe based plugin watcher utility for discovering Kubelet plugins
|
||||
KubeletPluginsWatcher featuregate.Feature = "KubeletPluginsWatcher"
|
||||
|
||||
// owner: @vikaschoudhary16
|
||||
// beta: v1.12
|
||||
//
|
||||
//
|
||||
// Enable resource quota scope selectors
|
||||
ResourceQuotaScopeSelectors featuregate.Feature = "ResourceQuotaScopeSelectors"
|
||||
|
||||
// owner: @vladimirvivien
|
||||
// alpha: v1.11
|
||||
// beta: v1.14
|
||||
//
|
||||
// Enables CSI to use raw block storage volumes
|
||||
CSIBlockVolume featuregate.Feature = "CSIBlockVolume"
|
||||
|
||||
// owner: @vladimirvivien
|
||||
// alpha: v1.14
|
||||
//
|
||||
// Enables CSI Inline volumes support for pods
|
||||
CSIInlineVolume featuregate.Feature = "CSIInlineVolume"
|
||||
|
||||
// owner: @tallclair
|
||||
// alpha: v1.12
|
||||
// beta: v1.14
|
||||
//
|
||||
// Enables RuntimeClass, for selecting between multiple runtimes to run a pod.
|
||||
RuntimeClass featuregate.Feature = "RuntimeClass"
|
||||
|
||||
// owner: @mtaufen
|
||||
// alpha: v1.12
|
||||
// beta: v1.14
|
||||
//
|
||||
// Kubelet uses the new Lease API to report node heartbeats,
|
||||
// (Kube) Node Lifecycle Controller uses these heartbeats as a node health signal.
|
||||
NodeLease featuregate.Feature = "NodeLease"
|
||||
|
||||
// owner: @janosi
|
||||
// alpha: v1.12
|
||||
//
|
||||
// Enables SCTP as new protocol for Service ports, NetworkPolicy, and ContainerPort in Pod/Containers definition
|
||||
SCTPSupport featuregate.Feature = "SCTPSupport"
|
||||
|
||||
// owner: @xing-yang
|
||||
// alpha: v1.12
|
||||
//
|
||||
// Enable volume snapshot data source support.
|
||||
VolumeSnapshotDataSource featuregate.Feature = "VolumeSnapshotDataSource"
|
||||
|
||||
// owner: @jessfraz
|
||||
// alpha: v1.12
|
||||
//
|
||||
// Enables control over ProcMountType for containers.
|
||||
ProcMountType featuregate.Feature = "ProcMountType"
|
||||
|
||||
// owner: @janetkuo
|
||||
// alpha: v1.12
|
||||
//
|
||||
// Allow TTL controller to clean up Pods and Jobs after they finish.
|
||||
TTLAfterFinished featuregate.Feature = "TTLAfterFinished"
|
||||
|
||||
// owner: @dashpole
|
||||
// alpha: v1.13
|
||||
// beta: v1.15
|
||||
//
|
||||
// Enables the kubelet's pod resources grpc endpoint
|
||||
KubeletPodResources featuregate.Feature = "KubeletPodResources"
|
||||
|
||||
// owner: @davidz627
|
||||
// alpha: v1.14
|
||||
//
|
||||
// Enables the in-tree storage to CSI Plugin migration feature.
|
||||
CSIMigration featuregate.Feature = "CSIMigration"
|
||||
|
||||
// owner: @davidz627
|
||||
// alpha: v1.14
|
||||
//
|
||||
// Enables the GCE PD in-tree driver to GCE CSI Driver migration feature.
|
||||
CSIMigrationGCE featuregate.Feature = "CSIMigrationGCE"
|
||||
|
||||
// owner: @leakingtapan
|
||||
// alpha: v1.14
|
||||
//
|
||||
// Enables the AWS EBS in-tree driver to AWS EBS CSI Driver migration feature.
|
||||
CSIMigrationAWS featuregate.Feature = "CSIMigrationAWS"
|
||||
|
||||
// owner: @andyzhangx
|
||||
// alpha: v1.15
|
||||
//
|
||||
// Enables the Azure Disk in-tree driver to Azure Disk Driver migration feature.
|
||||
CSIMigrationAzureDisk featuregate.Feature = "CSIMigrationAzureDisk"
|
||||
|
||||
// owner: @andyzhangx
|
||||
// alpha: v1.15
|
||||
//
|
||||
// Enables the Azure File in-tree driver to Azure File Driver migration feature.
|
||||
CSIMigrationAzureFile featuregate.Feature = "CSIMigrationAzureFile"
|
||||
|
||||
// owner: @RobertKrawitz
|
||||
// beta: v1.15
|
||||
//
|
||||
// Implement support for limiting pids in nodes
|
||||
SupportNodePidsLimit featuregate.Feature = "SupportNodePidsLimit"
|
||||
|
||||
// owner: @wk8
|
||||
// alpha: v1.14
|
||||
//
|
||||
// Enables GMSA support for Windows workloads.
|
||||
WindowsGMSA featuregate.Feature = "WindowsGMSA"
|
||||
|
||||
// owner: @adisky
|
||||
// alpha: v1.14
|
||||
//
|
||||
// Enables the OpenStack Cinder in-tree driver to OpenStack Cinder CSI Driver migration feature.
|
||||
CSIMigrationOpenStack featuregate.Feature = "CSIMigrationOpenStack"
|
||||
|
||||
// owner: @verult
|
||||
// GA: v1.13
|
||||
//
|
||||
// Enables the regional PD feature on GCE.
|
||||
deprecatedGCERegionalPersistentDisk featuregate.Feature = "GCERegionalPersistentDisk"
|
||||
|
||||
// owner: @MrHohn
|
||||
// alpha: v1.15
|
||||
//
|
||||
// Enables Finalizer Protection for Service LoadBalancers.
|
||||
ServiceLoadBalancerFinalizer featuregate.Feature = "ServiceLoadBalancerFinalizer"
|
||||
|
||||
// owner: @RobertKrawitz
|
||||
// alpha: v1.15
|
||||
//
|
||||
// Allow use of filesystems for ephemeral storage monitoring.
|
||||
// Only applies if LocalStorageCapacityIsolation is set.
|
||||
LocalStorageCapacityIsolationFSQuotaMonitoring featuregate.Feature = "LocalStorageCapacityIsolationFSQuotaMonitoring"
|
||||
|
||||
// owner: @denkensk
|
||||
// alpha: v1.15
|
||||
//
|
||||
// Enables NonPreempting option for priorityClass and pod.
|
||||
NonPreemptingPriority featuregate.Feature = "NonPreemptingPriority"
|
||||
|
||||
// owner: @j-griffith
|
||||
// alpha: v1.15
|
||||
//
|
||||
// Enable support for specifying an existing PVC as a DataSource
|
||||
VolumePVCDataSource featuregate.Feature = "VolumePVCDataSource"
|
||||
)
|
||||
|
||||
func init() {
|
||||
runtime.Must(utilfeature.DefaultMutableFeatureGate.Add(defaultKubernetesFeatureGates))
|
||||
}
|
||||
|
||||
// defaultKubernetesFeatureGates consists of all known Kubernetes-specific feature keys.
|
||||
// To add a new feature, define a key for it above and add it here. The features will be
|
||||
// available throughout Kubernetes binaries.
|
||||
var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
|
||||
AppArmor: {Default: true, PreRelease: featuregate.Beta},
|
||||
DynamicKubeletConfig: {Default: true, PreRelease: featuregate.Beta},
|
||||
ExperimentalHostUserNamespaceDefaultingGate: {Default: false, PreRelease: featuregate.Beta},
|
||||
ExperimentalCriticalPodAnnotation: {Default: false, PreRelease: featuregate.Alpha},
|
||||
DevicePlugins: {Default: true, PreRelease: featuregate.Beta},
|
||||
TaintBasedEvictions: {Default: true, PreRelease: featuregate.Beta},
|
||||
RotateKubeletServerCertificate: {Default: true, PreRelease: featuregate.Beta},
|
||||
RotateKubeletClientCertificate: {Default: true, PreRelease: featuregate.Beta},
|
||||
PersistentLocalVolumes: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.17
|
||||
LocalStorageCapacityIsolation: {Default: true, PreRelease: featuregate.Beta},
|
||||
HugePages: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.16
|
||||
Sysctls: {Default: true, PreRelease: featuregate.Beta},
|
||||
DebugContainers: {Default: false, PreRelease: featuregate.Alpha},
|
||||
PodShareProcessNamespace: {Default: true, PreRelease: featuregate.Beta},
|
||||
PodPriority: {Default: true, PreRelease: featuregate.GA},
|
||||
TaintNodesByCondition: {Default: true, PreRelease: featuregate.Beta},
|
||||
QOSReserved: {Default: false, PreRelease: featuregate.Alpha},
|
||||
ExpandPersistentVolumes: {Default: true, PreRelease: featuregate.Beta},
|
||||
ExpandInUsePersistentVolumes: {Default: true, PreRelease: featuregate.Beta},
|
||||
ExpandCSIVolumes: {Default: false, PreRelease: featuregate.Alpha},
|
||||
AttachVolumeLimit: {Default: true, PreRelease: featuregate.Beta},
|
||||
CPUManager: {Default: true, PreRelease: featuregate.Beta},
|
||||
CPUCFSQuotaPeriod: {Default: false, PreRelease: featuregate.Alpha},
|
||||
ServiceNodeExclusion: {Default: false, PreRelease: featuregate.Alpha},
|
||||
MountContainers: {Default: false, PreRelease: featuregate.Alpha},
|
||||
VolumeScheduling: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.16
|
||||
CSIPersistentVolume: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.16
|
||||
CSIDriverRegistry: {Default: true, PreRelease: featuregate.Beta},
|
||||
CSINodeInfo: {Default: true, PreRelease: featuregate.Beta},
|
||||
CustomPodDNS: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.16
|
||||
BlockVolume: {Default: true, PreRelease: featuregate.Beta},
|
||||
StorageObjectInUseProtection: {Default: true, PreRelease: featuregate.GA},
|
||||
ResourceLimitsPriorityFunction: {Default: false, PreRelease: featuregate.Alpha},
|
||||
SupportIPVSProxyMode: {Default: true, PreRelease: featuregate.GA},
|
||||
SupportPodPidsLimit: {Default: true, PreRelease: featuregate.Beta},
|
||||
SupportNodePidsLimit: {Default: true, PreRelease: featuregate.Beta},
|
||||
HyperVContainer: {Default: false, PreRelease: featuregate.Alpha},
|
||||
ScheduleDaemonSetPods: {Default: true, PreRelease: featuregate.Beta},
|
||||
TokenRequest: {Default: true, PreRelease: featuregate.Beta},
|
||||
TokenRequestProjection: {Default: true, PreRelease: featuregate.Beta},
|
||||
BoundServiceAccountTokenVolume: {Default: false, PreRelease: featuregate.Alpha},
|
||||
CRIContainerLogRotation: {Default: true, PreRelease: featuregate.Beta},
|
||||
deprecatedGCERegionalPersistentDisk: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.17
|
||||
CSIMigration: {Default: false, PreRelease: featuregate.Alpha},
|
||||
CSIMigrationGCE: {Default: false, PreRelease: featuregate.Alpha},
|
||||
CSIMigrationAWS: {Default: false, PreRelease: featuregate.Alpha},
|
||||
CSIMigrationAzureDisk: {Default: false, PreRelease: featuregate.Alpha},
|
||||
CSIMigrationAzureFile: {Default: false, PreRelease: featuregate.Alpha},
|
||||
RunAsGroup: {Default: true, PreRelease: featuregate.Beta},
|
||||
CSIMigrationOpenStack: {Default: false, PreRelease: featuregate.Alpha},
|
||||
VolumeSubpath: {Default: true, PreRelease: featuregate.GA},
|
||||
BalanceAttachedNodeVolumes: {Default: false, PreRelease: featuregate.Alpha},
|
||||
PodReadinessGates: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.16
|
||||
VolumeSubpathEnvExpansion: {Default: true, PreRelease: featuregate.Beta},
|
||||
KubeletPluginsWatcher: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.16
|
||||
ResourceQuotaScopeSelectors: {Default: true, PreRelease: featuregate.Beta},
|
||||
CSIBlockVolume: {Default: true, PreRelease: featuregate.Beta},
|
||||
CSIInlineVolume: {Default: false, PreRelease: featuregate.Alpha},
|
||||
RuntimeClass: {Default: true, PreRelease: featuregate.Beta},
|
||||
NodeLease: {Default: true, PreRelease: featuregate.Beta},
|
||||
SCTPSupport: {Default: false, PreRelease: featuregate.Alpha},
|
||||
VolumeSnapshotDataSource: {Default: false, PreRelease: featuregate.Alpha},
|
||||
ProcMountType: {Default: false, PreRelease: featuregate.Alpha},
|
||||
TTLAfterFinished: {Default: false, PreRelease: featuregate.Alpha},
|
||||
KubeletPodResources: {Default: true, PreRelease: featuregate.Beta},
|
||||
WindowsGMSA: {Default: false, PreRelease: featuregate.Alpha},
|
||||
ServiceLoadBalancerFinalizer: {Default: false, PreRelease: featuregate.Alpha},
|
||||
LocalStorageCapacityIsolationFSQuotaMonitoring: {Default: false, PreRelease: featuregate.Alpha},
|
||||
NonPreemptingPriority: {Default: false, PreRelease: featuregate.Alpha},
|
||||
VolumePVCDataSource: {Default: false, PreRelease: featuregate.Alpha},
|
||||
|
||||
// inherited features from generic apiserver, relisted here to get a conflict if it is changed
|
||||
// unintentionally on either side:
|
||||
genericfeatures.StreamingProxyRedirects: {Default: true, PreRelease: featuregate.Beta},
|
||||
genericfeatures.ValidateProxyRedirects: {Default: true, PreRelease: featuregate.Beta},
|
||||
genericfeatures.AdvancedAuditing: {Default: true, PreRelease: featuregate.GA},
|
||||
genericfeatures.DynamicAuditing: {Default: false, PreRelease: featuregate.Alpha},
|
||||
genericfeatures.APIResponseCompression: {Default: false, PreRelease: featuregate.Alpha},
|
||||
genericfeatures.APIListChunking: {Default: true, PreRelease: featuregate.Beta},
|
||||
genericfeatures.DryRun: {Default: true, PreRelease: featuregate.Beta},
|
||||
genericfeatures.ServerSideApply: {Default: false, PreRelease: featuregate.Alpha},
|
||||
genericfeatures.RequestManagement: {Default: false, PreRelease: featuregate.Alpha},
|
||||
|
||||
// inherited features from apiextensions-apiserver, relisted here to get a conflict if it is changed
|
||||
// unintentionally on either side:
|
||||
apiextensionsfeatures.CustomResourceValidation: {Default: true, PreRelease: featuregate.Beta},
|
||||
apiextensionsfeatures.CustomResourceSubresources: {Default: true, PreRelease: featuregate.Beta},
|
||||
apiextensionsfeatures.CustomResourceWebhookConversion: {Default: true, PreRelease: featuregate.Beta},
|
||||
apiextensionsfeatures.CustomResourcePublishOpenAPI: {Default: true, PreRelease: featuregate.Beta},
|
||||
apiextensionsfeatures.CustomResourceDefaulting: {Default: false, PreRelease: featuregate.Alpha},
|
||||
|
||||
// features that enable backwards compatibility but are scheduled to be removed
|
||||
// ...
|
||||
}
|
||||
35
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2/BUILD
generated
vendored
35
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2/BUILD
generated
vendored
|
|
@ -1,35 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"api.pb.go",
|
||||
"constants.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2",
|
||||
deps = [
|
||||
"//vendor/github.com/gogo/protobuf/gogoproto:go_default_library",
|
||||
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
|
||||
"//vendor/github.com/gogo/protobuf/sortkeys:go_default_library",
|
||||
"//vendor/golang.org/x/net/context:go_default_library",
|
||||
"//vendor/google.golang.org/grpc:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
27259
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2/api.pb.go
generated
vendored
27259
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2/api.pb.go
generated
vendored
File diff suppressed because it is too large
Load diff
1271
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2/api.proto
generated
vendored
1271
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2/api.proto
generated
vendored
File diff suppressed because it is too large
Load diff
55
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2/constants.go
generated
vendored
55
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2/constants.go
generated
vendored
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha2
|
||||
|
||||
// This file contains all constants defined in CRI.
|
||||
|
||||
// Required runtime condition type.
|
||||
const (
|
||||
// RuntimeReady means the runtime is up and ready to accept basic containers.
|
||||
RuntimeReady = "RuntimeReady"
|
||||
// NetworkReady means the runtime network is up and ready to accept containers which require network.
|
||||
NetworkReady = "NetworkReady"
|
||||
)
|
||||
|
||||
// LogStreamType is the type of the stream in CRI container log.
|
||||
type LogStreamType string
|
||||
|
||||
const (
|
||||
// Stdout is the stream type for stdout.
|
||||
Stdout LogStreamType = "stdout"
|
||||
// Stderr is the stream type for stderr.
|
||||
Stderr LogStreamType = "stderr"
|
||||
)
|
||||
|
||||
// LogTag is the tag of a log line in CRI container log.
|
||||
// Currently defined log tags:
|
||||
// * First tag: Partial/Full - P/F.
|
||||
// The field in the container log format can be extended to include multiple
|
||||
// tags by using a delimiter, but changes should be rare. If it becomes clear
|
||||
// that better extensibility is desired, a more extensible format (e.g., json)
|
||||
// should be adopted as a replacement and/or addition.
|
||||
type LogTag string
|
||||
|
||||
const (
|
||||
// LogTagPartial means the line is part of multiple lines.
|
||||
LogTagPartial LogTag = "P"
|
||||
// LogTagFull means the line is a single full line or the end of multiple lines.
|
||||
LogTagFull LogTag = "F"
|
||||
// LogTagDelimiter is the delimiter for different log tags.
|
||||
LogTagDelimiter = ":"
|
||||
)
|
||||
2
vendor/k8s.io/kubernetes/pkg/kubelet/container/BUILD
generated
vendored
2
vendor/k8s.io/kubernetes/pkg/kubelet/container/BUILD
generated
vendored
|
|
@ -19,7 +19,6 @@ go_library(
|
|||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/api/legacyscheme:go_default_library",
|
||||
"//pkg/kubelet/apis/cri/runtime/v1alpha2:go_default_library",
|
||||
"//pkg/kubelet/util/format:go_default_library",
|
||||
"//pkg/util/hash:go_default_library",
|
||||
"//pkg/volume:go_default_library",
|
||||
|
|
@ -34,6 +33,7 @@ go_library(
|
|||
"//staging/src/k8s.io/client-go/tools/reference:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/remotecommand:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/flowcontrol:go_default_library",
|
||||
"//staging/src/k8s.io/cri-api/pkg/apis/runtime/v1alpha2:go_default_library",
|
||||
"//third_party/forked/golang/expansion:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
|
|
|
|||
2
vendor/k8s.io/kubernetes/pkg/kubelet/container/helpers.go
generated
vendored
2
vendor/k8s.io/kubernetes/pkg/kubelet/container/helpers.go
generated
vendored
|
|
@ -29,7 +29,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/client-go/tools/record"
|
||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2"
|
||||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
||||
"k8s.io/kubernetes/pkg/kubelet/util/format"
|
||||
hashutil "k8s.io/kubernetes/pkg/util/hash"
|
||||
"k8s.io/kubernetes/third_party/forked/golang/expansion"
|
||||
|
|
|
|||
8
vendor/k8s.io/kubernetes/pkg/kubelet/container/ref.go
generated
vendored
8
vendor/k8s.io/kubernetes/pkg/kubelet/container/ref.go
generated
vendored
|
|
@ -54,9 +54,8 @@ func fieldPath(pod *v1.Pod, container *v1.Container) (string, error) {
|
|||
if here.Name == container.Name {
|
||||
if here.Name == "" {
|
||||
return fmt.Sprintf("spec.containers[%d]", i), nil
|
||||
} else {
|
||||
return fmt.Sprintf("spec.containers{%s}", here.Name), nil
|
||||
}
|
||||
return fmt.Sprintf("spec.containers{%s}", here.Name), nil
|
||||
}
|
||||
}
|
||||
for i := range pod.Spec.InitContainers {
|
||||
|
|
@ -64,10 +63,9 @@ func fieldPath(pod *v1.Pod, container *v1.Container) (string, error) {
|
|||
if here.Name == container.Name {
|
||||
if here.Name == "" {
|
||||
return fmt.Sprintf("spec.initContainers[%d]", i), nil
|
||||
} else {
|
||||
return fmt.Sprintf("spec.initContainers{%s}", here.Name), nil
|
||||
}
|
||||
return fmt.Sprintf("spec.initContainers{%s}", here.Name), nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("container %#v not found in pod %#v", container, pod)
|
||||
return "", fmt.Errorf("container %q not found in pod %s/%s", container.Name, pod.Namespace, pod.Name)
|
||||
}
|
||||
|
|
|
|||
2
vendor/k8s.io/kubernetes/pkg/kubelet/container/runtime.go
generated
vendored
2
vendor/k8s.io/kubernetes/pkg/kubelet/container/runtime.go
generated
vendored
|
|
@ -29,8 +29,8 @@ import (
|
|||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/tools/remotecommand"
|
||||
"k8s.io/client-go/util/flowcontrol"
|
||||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
||||
"k8s.io/klog"
|
||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
)
|
||||
|
||||
|
|
|
|||
37
vendor/k8s.io/kubernetes/pkg/util/mount/BUILD
generated
vendored
37
vendor/k8s.io/kubernetes/pkg/util/mount/BUILD
generated
vendored
|
|
@ -5,8 +5,6 @@ go_library(
|
|||
srcs = [
|
||||
"doc.go",
|
||||
"exec.go",
|
||||
"exec_mount.go",
|
||||
"exec_mount_unsupported.go",
|
||||
"fake.go",
|
||||
"mount.go",
|
||||
"mount_helper_common.go",
|
||||
|
|
@ -15,8 +13,6 @@ go_library(
|
|||
"mount_linux.go",
|
||||
"mount_unsupported.go",
|
||||
"mount_windows.go",
|
||||
"nsenter_mount.go",
|
||||
"nsenter_mount_unsupported.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/util/mount",
|
||||
visibility = ["//visibility:public"],
|
||||
|
|
@ -24,43 +20,13 @@ go_library(
|
|||
"//vendor/k8s.io/klog:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:android": [
|
||||
"//vendor/k8s.io/utils/nsenter:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:darwin": [
|
||||
"//vendor/k8s.io/utils/nsenter:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:dragonfly": [
|
||||
"//vendor/k8s.io/utils/nsenter:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:freebsd": [
|
||||
"//vendor/k8s.io/utils/nsenter:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:linux": [
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/golang.org/x/sys/unix:go_default_library",
|
||||
"//vendor/k8s.io/utils/io:go_default_library",
|
||||
"//vendor/k8s.io/utils/nsenter:go_default_library",
|
||||
"//vendor/k8s.io/utils/path:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:nacl": [
|
||||
"//vendor/k8s.io/utils/nsenter:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:netbsd": [
|
||||
"//vendor/k8s.io/utils/nsenter:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:openbsd": [
|
||||
"//vendor/k8s.io/utils/nsenter:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:plan9": [
|
||||
"//vendor/k8s.io/utils/nsenter:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:solaris": [
|
||||
"//vendor/k8s.io/utils/nsenter:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:windows": [
|
||||
"//vendor/k8s.io/utils/keymutex:go_default_library",
|
||||
"//vendor/k8s.io/utils/nsenter:go_default_library",
|
||||
"//vendor/k8s.io/utils/path:go_default_library",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
|
|
@ -70,12 +36,10 @@ go_library(
|
|||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"exec_mount_test.go",
|
||||
"mount_helper_test.go",
|
||||
"mount_linux_test.go",
|
||||
"mount_test.go",
|
||||
"mount_windows_test.go",
|
||||
"nsenter_mount_test.go",
|
||||
"safe_format_and_mount_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
|
|
@ -84,7 +48,6 @@ go_test(
|
|||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:linux": [
|
||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||
"//vendor/k8s.io/utils/nsenter:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:windows": [
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
|
|
|
|||
161
vendor/k8s.io/kubernetes/pkg/util/mount/exec_mount.go
generated
vendored
161
vendor/k8s.io/kubernetes/pkg/util/mount/exec_mount.go
generated
vendored
|
|
@ -1,161 +0,0 @@
|
|||
// +build linux
|
||||
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package mount
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
// ExecMounter is a mounter that uses provided Exec interface to mount and
|
||||
// unmount a filesystem. For all other calls it uses a wrapped mounter.
|
||||
type execMounter struct {
|
||||
wrappedMounter Interface
|
||||
exec Exec
|
||||
}
|
||||
|
||||
func NewExecMounter(exec Exec, wrapped Interface) Interface {
|
||||
return &execMounter{
|
||||
wrappedMounter: wrapped,
|
||||
exec: exec,
|
||||
}
|
||||
}
|
||||
|
||||
// execMounter implements mount.Interface
|
||||
var _ Interface = &execMounter{}
|
||||
|
||||
// Mount runs mount(8) using given exec interface.
|
||||
func (m *execMounter) Mount(source string, target string, fstype string, options []string) error {
|
||||
bind, bindOpts, bindRemountOpts := isBind(options)
|
||||
|
||||
if bind {
|
||||
err := m.doExecMount(source, target, fstype, bindOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return m.doExecMount(source, target, fstype, bindRemountOpts)
|
||||
}
|
||||
|
||||
return m.doExecMount(source, target, fstype, options)
|
||||
}
|
||||
|
||||
// doExecMount calls exec(mount <what> <where>) using given exec interface.
|
||||
func (m *execMounter) doExecMount(source, target, fstype string, options []string) error {
|
||||
klog.V(5).Infof("Exec Mounting %s %s %s %v", source, target, fstype, options)
|
||||
mountArgs := makeMountArgs(source, target, fstype, options)
|
||||
output, err := m.exec.Run("mount", mountArgs...)
|
||||
klog.V(5).Infof("Exec mounted %v: %v: %s", mountArgs, err, string(output))
|
||||
if err != nil {
|
||||
return fmt.Errorf("mount failed: %v\nMounting command: %s\nMounting arguments: %s %s %s %v\nOutput: %s\n",
|
||||
err, "mount", source, target, fstype, options, string(output))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Unmount runs umount(8) using given exec interface.
|
||||
func (m *execMounter) Unmount(target string) error {
|
||||
outputBytes, err := m.exec.Run("umount", target)
|
||||
if err == nil {
|
||||
klog.V(5).Infof("Exec unmounted %s: %s", target, string(outputBytes))
|
||||
} else {
|
||||
klog.V(5).Infof("Failed to exec unmount %s: err: %q, umount output: %s", target, err, string(outputBytes))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// List returns a list of all mounted filesystems.
|
||||
func (m *execMounter) List() ([]MountPoint, error) {
|
||||
return m.wrappedMounter.List()
|
||||
}
|
||||
|
||||
// IsLikelyNotMountPoint determines whether a path is a mountpoint.
|
||||
func (m *execMounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
||||
return m.wrappedMounter.IsLikelyNotMountPoint(file)
|
||||
}
|
||||
|
||||
// DeviceOpened checks if block device in use by calling Open with O_EXCL flag.
|
||||
// Returns true if open returns errno EBUSY, and false if errno is nil.
|
||||
// Returns an error if errno is any error other than EBUSY.
|
||||
// Returns with error if pathname is not a device.
|
||||
func (m *execMounter) DeviceOpened(pathname string) (bool, error) {
|
||||
return m.wrappedMounter.DeviceOpened(pathname)
|
||||
}
|
||||
|
||||
// PathIsDevice uses FileInfo returned from os.Stat to check if path refers
|
||||
// to a device.
|
||||
func (m *execMounter) PathIsDevice(pathname string) (bool, error) {
|
||||
return m.wrappedMounter.PathIsDevice(pathname)
|
||||
}
|
||||
|
||||
//GetDeviceNameFromMount given a mount point, find the volume id from checking /proc/mounts
|
||||
func (m *execMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
|
||||
return m.wrappedMounter.GetDeviceNameFromMount(mountPath, pluginDir)
|
||||
}
|
||||
|
||||
func (m *execMounter) IsMountPointMatch(mp MountPoint, dir string) bool {
|
||||
return m.wrappedMounter.IsMountPointMatch(mp, dir)
|
||||
}
|
||||
|
||||
func (m *execMounter) IsNotMountPoint(dir string) (bool, error) {
|
||||
return m.wrappedMounter.IsNotMountPoint(dir)
|
||||
}
|
||||
|
||||
func (m *execMounter) MakeRShared(path string) error {
|
||||
return m.wrappedMounter.MakeRShared(path)
|
||||
}
|
||||
|
||||
func (m *execMounter) GetFileType(pathname string) (FileType, error) {
|
||||
return m.wrappedMounter.GetFileType(pathname)
|
||||
}
|
||||
|
||||
func (m *execMounter) MakeFile(pathname string) error {
|
||||
return m.wrappedMounter.MakeFile(pathname)
|
||||
}
|
||||
|
||||
func (m *execMounter) MakeDir(pathname string) error {
|
||||
return m.wrappedMounter.MakeDir(pathname)
|
||||
}
|
||||
|
||||
func (m *execMounter) ExistsPath(pathname string) (bool, error) {
|
||||
return m.wrappedMounter.ExistsPath(pathname)
|
||||
}
|
||||
|
||||
func (m *execMounter) EvalHostSymlinks(pathname string) (string, error) {
|
||||
return m.wrappedMounter.EvalHostSymlinks(pathname)
|
||||
}
|
||||
|
||||
func (m *execMounter) GetMountRefs(pathname string) ([]string, error) {
|
||||
return m.wrappedMounter.GetMountRefs(pathname)
|
||||
}
|
||||
|
||||
func (m *execMounter) GetFSGroup(pathname string) (int64, error) {
|
||||
return m.wrappedMounter.GetFSGroup(pathname)
|
||||
}
|
||||
|
||||
func (m *execMounter) GetSELinuxSupport(pathname string) (bool, error) {
|
||||
return m.wrappedMounter.GetSELinuxSupport(pathname)
|
||||
}
|
||||
|
||||
func (m *execMounter) GetMode(pathname string) (os.FileMode, error) {
|
||||
return m.wrappedMounter.GetMode(pathname)
|
||||
}
|
||||
108
vendor/k8s.io/kubernetes/pkg/util/mount/exec_mount_unsupported.go
generated
vendored
108
vendor/k8s.io/kubernetes/pkg/util/mount/exec_mount_unsupported.go
generated
vendored
|
|
@ -1,108 +0,0 @@
|
|||
// +build !linux
|
||||
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package mount
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
)
|
||||
|
||||
type execMounter struct{}
|
||||
|
||||
// ExecMounter is a mounter that uses provided Exec interface to mount and
|
||||
// unmount a filesystem. For all other calls it uses a wrapped mounter.
|
||||
func NewExecMounter(exec Exec, wrapped Interface) Interface {
|
||||
return &execMounter{}
|
||||
}
|
||||
|
||||
func (mounter *execMounter) Mount(source string, target string, fstype string, options []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mounter *execMounter) Unmount(target string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mounter *execMounter) List() ([]MountPoint, error) {
|
||||
return []MountPoint{}, nil
|
||||
}
|
||||
|
||||
func (mounter *execMounter) IsMountPointMatch(mp MountPoint, dir string) bool {
|
||||
return (mp.Path == dir)
|
||||
}
|
||||
|
||||
func (mounter *execMounter) IsNotMountPoint(dir string) (bool, error) {
|
||||
return isNotMountPoint(mounter, dir)
|
||||
}
|
||||
|
||||
func (mounter *execMounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (mounter *execMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (mounter *execMounter) DeviceOpened(pathname string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (mounter *execMounter) PathIsDevice(pathname string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (mounter *execMounter) MakeRShared(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mounter *execMounter) GetFileType(pathname string) (FileType, error) {
|
||||
return FileType("fake"), errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (mounter *execMounter) MakeDir(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mounter *execMounter) MakeFile(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mounter *execMounter) ExistsPath(pathname string) (bool, error) {
|
||||
return true, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (m *execMounter) EvalHostSymlinks(pathname string) (string, error) {
|
||||
return "", errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (mounter *execMounter) GetMountRefs(pathname string) ([]string, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (mounter *execMounter) GetFSGroup(pathname string) (int64, error) {
|
||||
return -1, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (mounter *execMounter) GetSELinuxSupport(pathname string) (bool, error) {
|
||||
return false, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (mounter *execMounter) GetMode(pathname string) (os.FileMode, error) {
|
||||
return 0, errors.New("not implemented")
|
||||
}
|
||||
8
vendor/k8s.io/kubernetes/pkg/util/mount/fake.go
generated
vendored
8
vendor/k8s.io/kubernetes/pkg/util/mount/fake.go
generated
vendored
|
|
@ -136,10 +136,6 @@ func (f *FakeMounter) IsMountPointMatch(mp MountPoint, dir string) bool {
|
|||
return mp.Path == dir
|
||||
}
|
||||
|
||||
func (f *FakeMounter) IsNotMountPoint(dir string) (bool, error) {
|
||||
return isNotMountPoint(f, dir)
|
||||
}
|
||||
|
||||
func (f *FakeMounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
||||
f.mutex.Lock()
|
||||
defer f.mutex.Unlock()
|
||||
|
|
@ -186,8 +182,8 @@ func (f *FakeMounter) PathIsDevice(pathname string) (bool, error) {
|
|||
return true, nil
|
||||
}
|
||||
|
||||
func (f *FakeMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
|
||||
return getDeviceNameFromMount(f, mountPath, pluginDir)
|
||||
func (f *FakeMounter) GetDeviceNameFromMount(mountPath, pluginMountDir string) (string, error) {
|
||||
return getDeviceNameFromMount(f, mountPath, pluginMountDir)
|
||||
}
|
||||
|
||||
func (f *FakeMounter) MakeRShared(path string) error {
|
||||
|
|
|
|||
42
vendor/k8s.io/kubernetes/pkg/util/mount/mount.go
generated
vendored
42
vendor/k8s.io/kubernetes/pkg/util/mount/mount.go
generated
vendored
|
|
@ -29,13 +29,12 @@ type FileType string
|
|||
|
||||
const (
|
||||
// Default mount command if mounter path is not specified
|
||||
defaultMountCommand = "mount"
|
||||
MountsInGlobalPDPath = "mounts"
|
||||
FileTypeDirectory FileType = "Directory"
|
||||
FileTypeFile FileType = "File"
|
||||
FileTypeSocket FileType = "Socket"
|
||||
FileTypeCharDev FileType = "CharDevice"
|
||||
FileTypeBlockDev FileType = "BlockDevice"
|
||||
defaultMountCommand = "mount"
|
||||
FileTypeDirectory FileType = "Directory"
|
||||
FileTypeFile FileType = "File"
|
||||
FileTypeSocket FileType = "Socket"
|
||||
FileTypeCharDev FileType = "CharDevice"
|
||||
FileTypeBlockDev FileType = "BlockDevice"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
|
|
@ -50,19 +49,11 @@ type Interface interface {
|
|||
List() ([]MountPoint, error)
|
||||
// IsMountPointMatch determines if the mountpoint matches the dir
|
||||
IsMountPointMatch(mp MountPoint, dir string) bool
|
||||
// IsNotMountPoint determines if a directory is a mountpoint.
|
||||
// It should return ErrNotExist when the directory does not exist.
|
||||
// IsNotMountPoint is more expensive than IsLikelyNotMountPoint.
|
||||
// IsNotMountPoint detects bind mounts in linux.
|
||||
// IsNotMountPoint enumerates all the mountpoints using List() and
|
||||
// the list of mountpoints may be large, then it uses
|
||||
// IsMountPointMatch to evaluate whether the directory is a mountpoint
|
||||
IsNotMountPoint(file string) (bool, error)
|
||||
// IsLikelyNotMountPoint uses heuristics to determine if a directory
|
||||
// is a mountpoint.
|
||||
// It should return ErrNotExist when the directory does not exist.
|
||||
// IsLikelyNotMountPoint does NOT properly detect all mountpoint types
|
||||
// most notably linux bind mounts.
|
||||
// most notably linux bind mounts and symbolic link.
|
||||
IsLikelyNotMountPoint(file string) (bool, error)
|
||||
// DeviceOpened determines if the device is in use elsewhere
|
||||
// on the system, i.e. still mounted.
|
||||
|
|
@ -70,8 +61,8 @@ type Interface interface {
|
|||
// PathIsDevice determines if a path is a device.
|
||||
PathIsDevice(pathname string) (bool, error)
|
||||
// GetDeviceNameFromMount finds the device name by checking the mount path
|
||||
// to get the global mount path which matches its plugin directory
|
||||
GetDeviceNameFromMount(mountPath, pluginDir string) (string, error)
|
||||
// to get the global mount path within its plugin directory
|
||||
GetDeviceNameFromMount(mountPath, pluginMountDir string) (string, error)
|
||||
// MakeRShared checks that given path is on a mount with 'rshared' mount
|
||||
// propagation. If not, it bind-mounts the path as rshared.
|
||||
MakeRShared(path string) error
|
||||
|
|
@ -222,9 +213,14 @@ func GetDeviceNameFromMount(mounter Interface, mountPath string) (string, int, e
|
|||
return device, refCount, nil
|
||||
}
|
||||
|
||||
// isNotMountPoint implements Mounter.IsNotMountPoint and is shared by mounter
|
||||
// implementations.
|
||||
func isNotMountPoint(mounter Interface, file string) (bool, error) {
|
||||
// IsNotMountPoint determines if a directory is a mountpoint.
|
||||
// It should return ErrNotExist when the directory does not exist.
|
||||
// IsNotMountPoint is more expensive than IsLikelyNotMountPoint.
|
||||
// IsNotMountPoint detects bind mounts in linux.
|
||||
// IsNotMountPoint enumerates all the mountpoints using List() and
|
||||
// the list of mountpoints may be large, then it uses
|
||||
// IsMountPointMatch to evaluate whether the directory is a mountpoint
|
||||
func IsNotMountPoint(mounter Interface, file string) (bool, error) {
|
||||
// IsLikelyNotMountPoint provides a quick check
|
||||
// to determine whether file IS A mountpoint
|
||||
notMnt, notMntErr := mounter.IsLikelyNotMountPoint(file)
|
||||
|
|
@ -263,11 +259,11 @@ func isNotMountPoint(mounter Interface, file string) (bool, error) {
|
|||
return notMnt, nil
|
||||
}
|
||||
|
||||
// isBind detects whether a bind mount is being requested and makes the remount options to
|
||||
// IsBind detects whether a bind mount is being requested and makes the remount options to
|
||||
// use in case of bind mount, due to the fact that bind mount doesn't respect mount options.
|
||||
// The list equals:
|
||||
// options - 'bind' + 'remount' (no duplicate)
|
||||
func isBind(options []string) (bool, []string, []string) {
|
||||
func IsBind(options []string) (bool, []string, []string) {
|
||||
// Because we have an FD opened on the subpath bind mount, the "bind" option
|
||||
// needs to be included, otherwise the mount target will error as busy if you
|
||||
// remount as readonly.
|
||||
|
|
|
|||
2
vendor/k8s.io/kubernetes/pkg/util/mount/mount_helper_common.go
generated
vendored
2
vendor/k8s.io/kubernetes/pkg/util/mount/mount_helper_common.go
generated
vendored
|
|
@ -55,7 +55,7 @@ func doCleanupMountPoint(mountPath string, mounter Interface, extensiveMountPoin
|
|||
var notMnt bool
|
||||
var err error
|
||||
if extensiveMountPointCheck {
|
||||
notMnt, err = mounter.IsNotMountPoint(mountPath)
|
||||
notMnt, err = IsNotMountPoint(mounter, mountPath)
|
||||
} else {
|
||||
notMnt, err = mounter.IsLikelyNotMountPoint(mountPath)
|
||||
}
|
||||
|
|
|
|||
100
vendor/k8s.io/kubernetes/pkg/util/mount/mount_linux.go
generated
vendored
100
vendor/k8s.io/kubernetes/pkg/util/mount/mount_linux.go
generated
vendored
|
|
@ -30,7 +30,6 @@ import (
|
|||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/klog"
|
||||
utilexec "k8s.io/utils/exec"
|
||||
utilio "k8s.io/utils/io"
|
||||
|
|
@ -81,7 +80,7 @@ func (mounter *Mounter) Mount(source string, target string, fstype string, optio
|
|||
// Path to mounter binary if containerized mounter is needed. Otherwise, it is set to empty.
|
||||
// All Linux distros are expected to be shipped with a mount utility that a support bind mounts.
|
||||
mounterPath := ""
|
||||
bind, bindOpts, bindRemountOpts := isBind(options)
|
||||
bind, bindOpts, bindRemountOpts := IsBind(options)
|
||||
if bind {
|
||||
err := mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindOpts)
|
||||
if err != nil {
|
||||
|
|
@ -90,8 +89,13 @@ func (mounter *Mounter) Mount(source string, target string, fstype string, optio
|
|||
return mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindRemountOpts)
|
||||
}
|
||||
// The list of filesystems that require containerized mounter on GCI image cluster
|
||||
fsTypesNeedMounter := sets.NewString("nfs", "glusterfs", "ceph", "cifs")
|
||||
if fsTypesNeedMounter.Has(fstype) {
|
||||
fsTypesNeedMounter := map[string]struct{}{
|
||||
"nfs": {},
|
||||
"glusterfs": {},
|
||||
"ceph": {},
|
||||
"cifs": {},
|
||||
}
|
||||
if _, ok := fsTypesNeedMounter[fstype]; ok {
|
||||
mounterPath = mounter.mounterPath
|
||||
}
|
||||
return mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, options)
|
||||
|
|
@ -99,7 +103,7 @@ func (mounter *Mounter) Mount(source string, target string, fstype string, optio
|
|||
|
||||
// doMount runs the mount command. mounterPath is the path to mounter binary if containerized mounter is used.
|
||||
func (m *Mounter) doMount(mounterPath string, mountCmd string, source string, target string, fstype string, options []string) error {
|
||||
mountArgs := makeMountArgs(source, target, fstype, options)
|
||||
mountArgs := MakeMountArgs(source, target, fstype, options)
|
||||
if len(mounterPath) > 0 {
|
||||
mountArgs = append([]string{mountCmd}, mountArgs...)
|
||||
mountCmd = mounterPath
|
||||
|
|
@ -128,7 +132,7 @@ func (m *Mounter) doMount(mounterPath string, mountCmd string, source string, ta
|
|||
//
|
||||
// systemd-mount is not used because it's too new for older distros
|
||||
// (CentOS 7, Debian Jessie).
|
||||
mountCmd, mountArgs = addSystemdScope("systemd-run", target, mountCmd, mountArgs)
|
||||
mountCmd, mountArgs = AddSystemdScope("systemd-run", target, mountCmd, mountArgs)
|
||||
} else {
|
||||
// No systemd-run on the host (or we failed to check it), assume kubelet
|
||||
// does not run as a systemd service.
|
||||
|
|
@ -172,8 +176,9 @@ func detectSystemd() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// makeMountArgs makes the arguments to the mount(8) command.
|
||||
func makeMountArgs(source, target, fstype string, options []string) []string {
|
||||
// MakeMountArgs makes the arguments to the mount(8) command.
|
||||
// Implementation is shared with NsEnterMounter
|
||||
func MakeMountArgs(source, target, fstype string, options []string) []string {
|
||||
// Build mount command as follows:
|
||||
// mount [-t $fstype] [-o $options] [$source] $target
|
||||
mountArgs := []string{}
|
||||
|
|
@ -191,8 +196,9 @@ func makeMountArgs(source, target, fstype string, options []string) []string {
|
|||
return mountArgs
|
||||
}
|
||||
|
||||
// addSystemdScope adds "system-run --scope" to given command line
|
||||
func addSystemdScope(systemdRunPath, mountName, command string, args []string) (string, []string) {
|
||||
// AddSystemdScope adds "system-run --scope" to given command line
|
||||
// implementation is shared with NsEnterMounter
|
||||
func AddSystemdScope(systemdRunPath, mountName, command string, args []string) (string, []string) {
|
||||
descriptionArg := fmt.Sprintf("--description=Kubernetes transient mount for %s", mountName)
|
||||
systemdRunArgs := []string{descriptionArg, "--scope", "--", command}
|
||||
return systemdRunPath, append(systemdRunArgs, args...)
|
||||
|
|
@ -211,7 +217,7 @@ func (mounter *Mounter) Unmount(target string) error {
|
|||
|
||||
// List returns a list of all mounted filesystems.
|
||||
func (*Mounter) List() ([]MountPoint, error) {
|
||||
return listProcMounts(procMountsPath)
|
||||
return ListProcMounts(procMountsPath)
|
||||
}
|
||||
|
||||
func (mounter *Mounter) IsMountPointMatch(mp MountPoint, dir string) bool {
|
||||
|
|
@ -219,14 +225,11 @@ func (mounter *Mounter) IsMountPointMatch(mp MountPoint, dir string) bool {
|
|||
return ((mp.Path == dir) || (mp.Path == deletedDir))
|
||||
}
|
||||
|
||||
func (mounter *Mounter) IsNotMountPoint(dir string) (bool, error) {
|
||||
return isNotMountPoint(mounter, dir)
|
||||
}
|
||||
|
||||
// IsLikelyNotMountPoint determines if a directory is not a mountpoint.
|
||||
// It is fast but not necessarily ALWAYS correct. If the path is in fact
|
||||
// a bind mount from one part of a mount to another it will not be detected.
|
||||
// mkdir /tmp/a /tmp/b; mount --bin /tmp/a /tmp/b; IsLikelyNotMountPoint("/tmp/b")
|
||||
// It also can not distinguish between mountpoints and symbolic links.
|
||||
// mkdir /tmp/a /tmp/b; mount --bind /tmp/a /tmp/b; IsLikelyNotMountPoint("/tmp/b")
|
||||
// will return true. When in fact /tmp/b is a mount point. If this situation
|
||||
// if of interest to you, don't use this function...
|
||||
func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
||||
|
|
@ -234,7 +237,7 @@ func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
|||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
rootStat, err := os.Lstat(filepath.Dir(strings.TrimSuffix(file, "/")))
|
||||
rootStat, err := os.Stat(filepath.Dir(strings.TrimSuffix(file, "/")))
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
|
|
@ -252,7 +255,7 @@ func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
|||
// If open returns nil, return false with nil error.
|
||||
// Otherwise, return false with error
|
||||
func (mounter *Mounter) DeviceOpened(pathname string) (bool, error) {
|
||||
return exclusiveOpenFailsOnDevice(pathname)
|
||||
return ExclusiveOpenFailsOnDevice(pathname)
|
||||
}
|
||||
|
||||
// PathIsDevice uses FileInfo returned from os.Stat to check if path refers
|
||||
|
|
@ -263,7 +266,8 @@ func (mounter *Mounter) PathIsDevice(pathname string) (bool, error) {
|
|||
return isDevice, err
|
||||
}
|
||||
|
||||
func exclusiveOpenFailsOnDevice(pathname string) (bool, error) {
|
||||
// ExclusiveOpenFailsOnDevice is shared with NsEnterMounter
|
||||
func ExclusiveOpenFailsOnDevice(pathname string) (bool, error) {
|
||||
var isDevice bool
|
||||
finfo, err := os.Stat(pathname)
|
||||
if os.IsNotExist(err) {
|
||||
|
|
@ -301,14 +305,19 @@ func exclusiveOpenFailsOnDevice(pathname string) (bool, error) {
|
|||
}
|
||||
|
||||
//GetDeviceNameFromMount: given a mount point, find the device name from its global mount point
|
||||
func (mounter *Mounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
|
||||
return getDeviceNameFromMount(mounter, mountPath, pluginDir)
|
||||
func (mounter *Mounter) GetDeviceNameFromMount(mountPath, pluginMountDir string) (string, error) {
|
||||
return GetDeviceNameFromMountLinux(mounter, mountPath, pluginMountDir)
|
||||
}
|
||||
|
||||
// getDeviceNameFromMount find the device name from /proc/mounts in which
|
||||
// the mount path reference should match the given plugin directory. In case no mount path reference
|
||||
func getDeviceNameFromMount(mounter Interface, mountPath, pluginMountDir string) (string, error) {
|
||||
return GetDeviceNameFromMountLinux(mounter, mountPath, pluginMountDir)
|
||||
}
|
||||
|
||||
// GetDeviceNameFromMountLinux find the device name from /proc/mounts in which
|
||||
// the mount path reference should match the given plugin mount directory. In case no mount path reference
|
||||
// matches, returns the volume name taken from its given mountPath
|
||||
func getDeviceNameFromMount(mounter Interface, mountPath, pluginDir string) (string, error) {
|
||||
// This implementation is shared with NsEnterMounter
|
||||
func GetDeviceNameFromMountLinux(mounter Interface, mountPath, pluginMountDir string) (string, error) {
|
||||
refs, err := mounter.GetMountRefs(mountPath)
|
||||
if err != nil {
|
||||
klog.V(4).Infof("GetMountRefs failed for mount path %q: %v", mountPath, err)
|
||||
|
|
@ -318,10 +327,9 @@ func getDeviceNameFromMount(mounter Interface, mountPath, pluginDir string) (str
|
|||
klog.V(4).Infof("Directory %s is not mounted", mountPath)
|
||||
return "", fmt.Errorf("directory %s is not mounted", mountPath)
|
||||
}
|
||||
basemountPath := path.Join(pluginDir, MountsInGlobalPDPath)
|
||||
for _, ref := range refs {
|
||||
if strings.HasPrefix(ref, basemountPath) {
|
||||
volumeID, err := filepath.Rel(basemountPath, ref)
|
||||
if strings.HasPrefix(ref, pluginMountDir) {
|
||||
volumeID, err := filepath.Rel(pluginMountDir, ref)
|
||||
if err != nil {
|
||||
klog.Errorf("Failed to get volume id from mount %s - %v", mountPath, err)
|
||||
return "", err
|
||||
|
|
@ -333,7 +341,8 @@ func getDeviceNameFromMount(mounter Interface, mountPath, pluginDir string) (str
|
|||
return path.Base(mountPath), nil
|
||||
}
|
||||
|
||||
func listProcMounts(mountFilePath string) ([]MountPoint, error) {
|
||||
// ListProcMounts is shared with NsEnterMounter
|
||||
func ListProcMounts(mountFilePath string) ([]MountPoint, error) {
|
||||
content, err := utilio.ConsistentRead(mountFilePath, maxListTries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -379,7 +388,7 @@ func parseProcMounts(content []byte) ([]MountPoint, error) {
|
|||
}
|
||||
|
||||
func (mounter *Mounter) MakeRShared(path string) error {
|
||||
return doMakeRShared(path, procMountInfoPath)
|
||||
return DoMakeRShared(path, procMountInfoPath)
|
||||
}
|
||||
|
||||
func (mounter *Mounter) GetFileType(pathname string) (FileType, error) {
|
||||
|
|
@ -500,7 +509,7 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
|
|||
return mountErr
|
||||
}
|
||||
|
||||
// GetDiskFormat uses 'blkid' to see if the given disk is unformated
|
||||
// GetDiskFormat uses 'blkid' to see if the given disk is unformatted
|
||||
func (mounter *SafeFormatAndMount) GetDiskFormat(disk string) (string, error) {
|
||||
args := []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", disk}
|
||||
klog.V(4).Infof("Attempting to determine if disk %q is formatted using blkid with args: (%v)", disk, args)
|
||||
|
|
@ -668,11 +677,11 @@ func findMountInfo(path, mountInfoPath string) (mountInfo, error) {
|
|||
return *info, nil
|
||||
}
|
||||
|
||||
// doMakeRShared is common implementation of MakeRShared on Linux. It checks if
|
||||
// DoMakeRShared is common implementation of MakeRShared on Linux. It checks if
|
||||
// path is shared and bind-mounts it as rshared if needed. mountCmd and
|
||||
// mountArgs are expected to contain mount-like command, doMakeRShared will add
|
||||
// mountArgs are expected to contain mount-like command, DoMakeRShared will add
|
||||
// '--bind <path> <path>' and '--make-rshared <path>' to mountArgs.
|
||||
func doMakeRShared(path string, mountInfoFilename string) error {
|
||||
func DoMakeRShared(path string, mountInfoFilename string) error {
|
||||
shared, err := isShared(path, mountInfoFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -696,8 +705,8 @@ func doMakeRShared(path string, mountInfoFilename string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// getSELinuxSupport is common implementation of GetSELinuxSupport on Linux.
|
||||
func getSELinuxSupport(path string, mountInfoFilename string) (bool, error) {
|
||||
// GetSELinux is common implementation of GetSELinuxSupport on Linux.
|
||||
func GetSELinux(path string, mountInfoFilename string) (bool, error) {
|
||||
info, err := findMountInfo(path, mountInfoFilename)
|
||||
if err != nil {
|
||||
return false, err
|
||||
|
|
@ -731,11 +740,11 @@ func (mounter *Mounter) GetMountRefs(pathname string) ([]string, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return searchMountPoints(realpath, procMountInfoPath)
|
||||
return SearchMountPoints(realpath, procMountInfoPath)
|
||||
}
|
||||
|
||||
func (mounter *Mounter) GetSELinuxSupport(pathname string) (bool, error) {
|
||||
return getSELinuxSupport(pathname, procMountInfoPath)
|
||||
return GetSELinux(pathname, procMountInfoPath)
|
||||
}
|
||||
|
||||
func (mounter *Mounter) GetFSGroup(pathname string) (int64, error) {
|
||||
|
|
@ -743,15 +752,16 @@ func (mounter *Mounter) GetFSGroup(pathname string) (int64, error) {
|
|||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return getFSGroup(realpath)
|
||||
return GetFSGroupLinux(realpath)
|
||||
}
|
||||
|
||||
func (mounter *Mounter) GetMode(pathname string) (os.FileMode, error) {
|
||||
return getMode(pathname)
|
||||
return GetModeLinux(pathname)
|
||||
}
|
||||
|
||||
// This implementation is shared between Linux and NsEnterMounter
|
||||
func getFSGroup(pathname string) (int64, error) {
|
||||
// GetFSGroupLinux is shared between Linux and NsEnterMounter
|
||||
// pathname must already be evaluated for symlinks
|
||||
func GetFSGroupLinux(pathname string) (int64, error) {
|
||||
info, err := os.Stat(pathname)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
@ -759,8 +769,8 @@ func getFSGroup(pathname string) (int64, error) {
|
|||
return int64(info.Sys().(*syscall.Stat_t).Gid), nil
|
||||
}
|
||||
|
||||
// This implementation is shared between Linux and NsEnterMounter
|
||||
func getMode(pathname string) (os.FileMode, error) {
|
||||
// GetModeLinux is shared between Linux and NsEnterMounter
|
||||
func GetModeLinux(pathname string) (os.FileMode, error) {
|
||||
info, err := os.Stat(pathname)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
@ -768,14 +778,14 @@ func getMode(pathname string) (os.FileMode, error) {
|
|||
return info.Mode(), nil
|
||||
}
|
||||
|
||||
// searchMountPoints finds all mount references to the source, returns a list of
|
||||
// SearchMountPoints finds all mount references to the source, returns a list of
|
||||
// mountpoints.
|
||||
// This function assumes source cannot be device.
|
||||
// Some filesystems may share a source name, e.g. tmpfs. And for bind mounting,
|
||||
// it's possible to mount a non-root path of a filesystem, so we need to use
|
||||
// root path and major:minor to represent mount source uniquely.
|
||||
// This implementation is shared between Linux and NsEnterMounter
|
||||
func searchMountPoints(hostSource, mountInfoPath string) ([]string, error) {
|
||||
func SearchMountPoints(hostSource, mountInfoPath string) ([]string, error) {
|
||||
mis, err := parseMountInfo(mountInfoPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
8
vendor/k8s.io/kubernetes/pkg/util/mount/mount_unsupported.go
generated
vendored
8
vendor/k8s.io/kubernetes/pkg/util/mount/mount_unsupported.go
generated
vendored
|
|
@ -54,19 +54,15 @@ func (mounter *Mounter) IsMountPointMatch(mp MountPoint, dir string) bool {
|
|||
return (mp.Path == dir)
|
||||
}
|
||||
|
||||
func (mounter *Mounter) IsNotMountPoint(dir string) (bool, error) {
|
||||
return isNotMountPoint(mounter, dir)
|
||||
}
|
||||
|
||||
func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
||||
return true, unsupportedErr
|
||||
}
|
||||
|
||||
func (mounter *Mounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
|
||||
func (mounter *Mounter) GetDeviceNameFromMount(mountPath, pluginMountDir string) (string, error) {
|
||||
return "", unsupportedErr
|
||||
}
|
||||
|
||||
func getDeviceNameFromMount(mounter Interface, mountPath, pluginDir string) (string, error) {
|
||||
func getDeviceNameFromMount(mounter Interface, mountPath, pluginMountDir string) (string, error) {
|
||||
return "", unsupportedErr
|
||||
}
|
||||
|
||||
|
|
|
|||
17
vendor/k8s.io/kubernetes/pkg/util/mount/mount_windows.go
generated
vendored
17
vendor/k8s.io/kubernetes/pkg/util/mount/mount_windows.go
generated
vendored
|
|
@ -72,7 +72,7 @@ func (mounter *Mounter) Mount(source string, target string, fstype string, optio
|
|||
bindSource := source
|
||||
|
||||
// tell it's going to mount azure disk or azure file according to options
|
||||
if bind, _, _ := isBind(options); bind {
|
||||
if bind, _, _ := IsBind(options); bind {
|
||||
// mount azure disk
|
||||
bindSource = normalizeWindowsPath(source)
|
||||
} else {
|
||||
|
|
@ -173,11 +173,6 @@ func (mounter *Mounter) IsMountPointMatch(mp MountPoint, dir string) bool {
|
|||
return mp.Path == dir
|
||||
}
|
||||
|
||||
// IsNotMountPoint determines if a directory is a mountpoint.
|
||||
func (mounter *Mounter) IsNotMountPoint(dir string) (bool, error) {
|
||||
return isNotMountPoint(mounter, dir)
|
||||
}
|
||||
|
||||
// IsLikelyNotMountPoint determines if a directory is not a mountpoint.
|
||||
func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
||||
stat, err := os.Lstat(file)
|
||||
|
|
@ -201,14 +196,14 @@ func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
|||
}
|
||||
|
||||
// GetDeviceNameFromMount given a mnt point, find the device
|
||||
func (mounter *Mounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
|
||||
return getDeviceNameFromMount(mounter, mountPath, pluginDir)
|
||||
func (mounter *Mounter) GetDeviceNameFromMount(mountPath, pluginMountDir string) (string, error) {
|
||||
return getDeviceNameFromMount(mounter, mountPath, pluginMountDir)
|
||||
}
|
||||
|
||||
// getDeviceNameFromMount find the device(drive) name in which
|
||||
// the mount path reference should match the given plugin directory. In case no mount path reference
|
||||
// the mount path reference should match the given plugin mount directory. In case no mount path reference
|
||||
// matches, returns the volume name taken from its given mountPath
|
||||
func getDeviceNameFromMount(mounter Interface, mountPath, pluginDir string) (string, error) {
|
||||
func getDeviceNameFromMount(mounter Interface, mountPath, pluginMountDir string) (string, error) {
|
||||
refs, err := mounter.GetMountRefs(mountPath)
|
||||
if err != nil {
|
||||
klog.V(4).Infof("GetMountRefs failed for mount path %q: %v", mountPath, err)
|
||||
|
|
@ -217,7 +212,7 @@ func getDeviceNameFromMount(mounter Interface, mountPath, pluginDir string) (str
|
|||
if len(refs) == 0 {
|
||||
return "", fmt.Errorf("directory %s is not mounted", mountPath)
|
||||
}
|
||||
basemountPath := normalizeWindowsPath(path.Join(pluginDir, MountsInGlobalPDPath))
|
||||
basemountPath := normalizeWindowsPath(pluginMountDir)
|
||||
for _, ref := range refs {
|
||||
if strings.Contains(ref, basemountPath) {
|
||||
volumeID, err := filepath.Rel(normalizeWindowsPath(basemountPath), ref)
|
||||
|
|
|
|||
333
vendor/k8s.io/kubernetes/pkg/util/mount/nsenter_mount.go
generated
vendored
333
vendor/k8s.io/kubernetes/pkg/util/mount/nsenter_mount.go
generated
vendored
|
|
@ -1,333 +0,0 @@
|
|||
// +build linux
|
||||
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package mount
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"k8s.io/klog"
|
||||
"k8s.io/utils/nsenter"
|
||||
utilpath "k8s.io/utils/path"
|
||||
)
|
||||
|
||||
const (
|
||||
// hostProcMountsPath is the default mount path for rootfs
|
||||
hostProcMountsPath = "/rootfs/proc/1/mounts"
|
||||
// hostProcMountinfoPath is the default mount info path for rootfs
|
||||
hostProcMountinfoPath = "/rootfs/proc/1/mountinfo"
|
||||
)
|
||||
|
||||
// Currently, all docker containers receive their own mount namespaces.
|
||||
// NsenterMounter works by executing nsenter to run commands in
|
||||
// the host's mount namespace.
|
||||
type NsenterMounter struct {
|
||||
ne *nsenter.Nsenter
|
||||
// rootDir is location of /var/lib/kubelet directory.
|
||||
rootDir string
|
||||
}
|
||||
|
||||
// NewNsenterMounter creates a new mounter for kubelet that runs as a container.
|
||||
func NewNsenterMounter(rootDir string, ne *nsenter.Nsenter) *NsenterMounter {
|
||||
return &NsenterMounter{
|
||||
rootDir: rootDir,
|
||||
ne: ne,
|
||||
}
|
||||
}
|
||||
|
||||
// NsenterMounter implements mount.Interface
|
||||
var _ = Interface(&NsenterMounter{})
|
||||
|
||||
// Mount runs mount(8) in the host's root mount namespace. Aside from this
|
||||
// aspect, Mount has the same semantics as the mounter returned by mount.New()
|
||||
func (n *NsenterMounter) Mount(source string, target string, fstype string, options []string) error {
|
||||
bind, bindOpts, bindRemountOpts := isBind(options)
|
||||
|
||||
if bind {
|
||||
err := n.doNsenterMount(source, target, fstype, bindOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return n.doNsenterMount(source, target, fstype, bindRemountOpts)
|
||||
}
|
||||
|
||||
return n.doNsenterMount(source, target, fstype, options)
|
||||
}
|
||||
|
||||
// doNsenterMount nsenters the host's mount namespace and performs the
|
||||
// requested mount.
|
||||
func (n *NsenterMounter) doNsenterMount(source, target, fstype string, options []string) error {
|
||||
klog.V(5).Infof("nsenter mount %s %s %s %v", source, target, fstype, options)
|
||||
cmd, args := n.makeNsenterArgs(source, target, fstype, options)
|
||||
outputBytes, err := n.ne.Exec(cmd, args).CombinedOutput()
|
||||
if len(outputBytes) != 0 {
|
||||
klog.V(5).Infof("Output of mounting %s to %s: %v", source, target, string(outputBytes))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// makeNsenterArgs makes a list of argument to nsenter in order to do the
|
||||
// requested mount.
|
||||
func (n *NsenterMounter) makeNsenterArgs(source, target, fstype string, options []string) (string, []string) {
|
||||
mountCmd := n.ne.AbsHostPath("mount")
|
||||
mountArgs := makeMountArgs(source, target, fstype, options)
|
||||
|
||||
if systemdRunPath, hasSystemd := n.ne.SupportsSystemd(); hasSystemd {
|
||||
// Complete command line:
|
||||
// nsenter --mount=/rootfs/proc/1/ns/mnt -- /bin/systemd-run --description=... --scope -- /bin/mount -t <type> <what> <where>
|
||||
// Expected flow is:
|
||||
// * nsenter breaks out of container's mount namespace and executes
|
||||
// host's systemd-run.
|
||||
// * systemd-run creates a transient scope (=~ cgroup) and executes its
|
||||
// argument (/bin/mount) there.
|
||||
// * mount does its job, forks a fuse daemon if necessary and finishes.
|
||||
// (systemd-run --scope finishes at this point, returning mount's exit
|
||||
// code and stdout/stderr - thats one of --scope benefits).
|
||||
// * systemd keeps the fuse daemon running in the scope (i.e. in its own
|
||||
// cgroup) until the fuse daemon dies (another --scope benefit).
|
||||
// Kubelet container can be restarted and the fuse daemon survives.
|
||||
// * When the daemon dies (e.g. during unmount) systemd removes the
|
||||
// scope automatically.
|
||||
mountCmd, mountArgs = addSystemdScope(systemdRunPath, target, mountCmd, mountArgs)
|
||||
} else {
|
||||
// Fall back to simple mount when the host has no systemd.
|
||||
// Complete command line:
|
||||
// nsenter --mount=/rootfs/proc/1/ns/mnt -- /bin/mount -t <type> <what> <where>
|
||||
// Expected flow is:
|
||||
// * nsenter breaks out of container's mount namespace and executes host's /bin/mount.
|
||||
// * mount does its job, forks a fuse daemon if necessary and finishes.
|
||||
// * Any fuse daemon runs in cgroup of kubelet docker container,
|
||||
// restart of kubelet container will kill it!
|
||||
|
||||
// No code here, mountCmd and mountArgs use /bin/mount
|
||||
}
|
||||
|
||||
return mountCmd, mountArgs
|
||||
}
|
||||
|
||||
// Unmount runs umount(8) in the host's mount namespace.
|
||||
func (n *NsenterMounter) Unmount(target string) error {
|
||||
args := []string{target}
|
||||
// No need to execute systemd-run here, it's enough that unmount is executed
|
||||
// in the host's mount namespace. It will finish appropriate fuse daemon(s)
|
||||
// running in any scope.
|
||||
klog.V(5).Infof("nsenter unmount args: %v", args)
|
||||
outputBytes, err := n.ne.Exec("umount", args).CombinedOutput()
|
||||
if len(outputBytes) != 0 {
|
||||
klog.V(5).Infof("Output of unmounting %s: %v", target, string(outputBytes))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// List returns a list of all mounted filesystems in the host's mount namespace.
|
||||
func (*NsenterMounter) List() ([]MountPoint, error) {
|
||||
return listProcMounts(hostProcMountsPath)
|
||||
}
|
||||
|
||||
func (m *NsenterMounter) IsNotMountPoint(dir string) (bool, error) {
|
||||
return isNotMountPoint(m, dir)
|
||||
}
|
||||
|
||||
func (*NsenterMounter) IsMountPointMatch(mp MountPoint, dir string) bool {
|
||||
deletedDir := fmt.Sprintf("%s\\040(deleted)", dir)
|
||||
return (mp.Path == dir) || (mp.Path == deletedDir)
|
||||
}
|
||||
|
||||
// IsLikelyNotMountPoint determines whether a path is a mountpoint by calling findmnt
|
||||
// in the host's root mount namespace.
|
||||
func (n *NsenterMounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
||||
file, err := filepath.Abs(file)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
|
||||
// Check the directory exists
|
||||
if _, err = os.Stat(file); os.IsNotExist(err) {
|
||||
klog.V(5).Infof("findmnt: directory %s does not exist", file)
|
||||
return true, err
|
||||
}
|
||||
|
||||
// Resolve any symlinks in file, kernel would do the same and use the resolved path in /proc/mounts
|
||||
resolvedFile, err := n.EvalHostSymlinks(file)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
|
||||
// Add --first-only option: since we are testing for the absence of a mountpoint, it is sufficient to get only
|
||||
// the first of multiple possible mountpoints using --first-only.
|
||||
// Also add fstype output to make sure that the output of target file will give the full path
|
||||
// TODO: Need more refactoring for this function. Track the solution with issue #26996
|
||||
args := []string{"-o", "target,fstype", "--noheadings", "--first-only", "--target", resolvedFile}
|
||||
klog.V(5).Infof("nsenter findmnt args: %v", args)
|
||||
out, err := n.ne.Exec("findmnt", args).CombinedOutput()
|
||||
if err != nil {
|
||||
klog.V(2).Infof("Failed findmnt command for path %s: %s %v", resolvedFile, out, err)
|
||||
// Different operating systems behave differently for paths which are not mount points.
|
||||
// On older versions (e.g. 2.20.1) we'd get error, on newer ones (e.g. 2.26.2) we'd get "/".
|
||||
// It's safer to assume that it's not a mount point.
|
||||
return true, nil
|
||||
}
|
||||
mountTarget, err := parseFindMnt(string(out))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
klog.V(5).Infof("IsLikelyNotMountPoint findmnt output for path %s: %v:", resolvedFile, mountTarget)
|
||||
|
||||
if mountTarget == resolvedFile {
|
||||
klog.V(5).Infof("IsLikelyNotMountPoint: %s is a mount point", resolvedFile)
|
||||
return false, nil
|
||||
}
|
||||
klog.V(5).Infof("IsLikelyNotMountPoint: %s is not a mount point", resolvedFile)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// parse output of "findmnt -o target,fstype" and return just the target
|
||||
func parseFindMnt(out string) (string, error) {
|
||||
// cut trailing newline
|
||||
out = strings.TrimSuffix(out, "\n")
|
||||
// cut everything after the last space - it's the filesystem type
|
||||
i := strings.LastIndex(out, " ")
|
||||
if i == -1 {
|
||||
return "", fmt.Errorf("error parsing findmnt output, expected at least one space: %q", out)
|
||||
}
|
||||
return out[:i], nil
|
||||
}
|
||||
|
||||
// DeviceOpened checks if block device in use by calling Open with O_EXCL flag.
|
||||
// Returns true if open returns errno EBUSY, and false if errno is nil.
|
||||
// Returns an error if errno is any error other than EBUSY.
|
||||
// Returns with error if pathname is not a device.
|
||||
func (n *NsenterMounter) DeviceOpened(pathname string) (bool, error) {
|
||||
return exclusiveOpenFailsOnDevice(pathname)
|
||||
}
|
||||
|
||||
// PathIsDevice uses FileInfo returned from os.Stat to check if path refers
|
||||
// to a device.
|
||||
func (n *NsenterMounter) PathIsDevice(pathname string) (bool, error) {
|
||||
pathType, err := n.GetFileType(pathname)
|
||||
isDevice := pathType == FileTypeCharDev || pathType == FileTypeBlockDev
|
||||
return isDevice, err
|
||||
}
|
||||
|
||||
//GetDeviceNameFromMount given a mount point, find the volume id from checking /proc/mounts
|
||||
func (n *NsenterMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
|
||||
return getDeviceNameFromMount(n, mountPath, pluginDir)
|
||||
}
|
||||
|
||||
func (n *NsenterMounter) MakeRShared(path string) error {
|
||||
return doMakeRShared(path, hostProcMountinfoPath)
|
||||
}
|
||||
|
||||
func (mounter *NsenterMounter) GetFileType(pathname string) (FileType, error) {
|
||||
var pathType FileType
|
||||
outputBytes, err := mounter.ne.Exec("stat", []string{"-L", "--printf=%F", pathname}).CombinedOutput()
|
||||
if err != nil {
|
||||
if strings.Contains(string(outputBytes), "No such file") {
|
||||
err = fmt.Errorf("%s does not exist", pathname)
|
||||
} else {
|
||||
err = fmt.Errorf("stat %s error: %v", pathname, string(outputBytes))
|
||||
}
|
||||
return pathType, err
|
||||
}
|
||||
|
||||
switch string(outputBytes) {
|
||||
case "socket":
|
||||
return FileTypeSocket, nil
|
||||
case "character special file":
|
||||
return FileTypeCharDev, nil
|
||||
case "block special file":
|
||||
return FileTypeBlockDev, nil
|
||||
case "directory":
|
||||
return FileTypeDirectory, nil
|
||||
case "regular file":
|
||||
return FileTypeFile, nil
|
||||
}
|
||||
|
||||
return pathType, fmt.Errorf("only recognise file, directory, socket, block device and character device")
|
||||
}
|
||||
|
||||
func (mounter *NsenterMounter) MakeDir(pathname string) error {
|
||||
args := []string{"-p", pathname}
|
||||
if _, err := mounter.ne.Exec("mkdir", args).CombinedOutput(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mounter *NsenterMounter) MakeFile(pathname string) error {
|
||||
args := []string{pathname}
|
||||
if _, err := mounter.ne.Exec("touch", args).CombinedOutput(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mounter *NsenterMounter) ExistsPath(pathname string) (bool, error) {
|
||||
// Resolve the symlinks but allow the target not to exist. EvalSymlinks
|
||||
// would return an generic error when the target does not exist.
|
||||
hostPath, err := mounter.ne.EvalSymlinks(pathname, false /* mustExist */)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
kubeletpath := mounter.ne.KubeletPath(hostPath)
|
||||
return utilpath.Exists(utilpath.CheckFollowSymlink, kubeletpath)
|
||||
}
|
||||
|
||||
func (mounter *NsenterMounter) EvalHostSymlinks(pathname string) (string, error) {
|
||||
return mounter.ne.EvalSymlinks(pathname, true)
|
||||
}
|
||||
|
||||
func (mounter *NsenterMounter) GetMountRefs(pathname string) ([]string, error) {
|
||||
pathExists, pathErr := PathExists(pathname)
|
||||
if !pathExists || IsCorruptedMnt(pathErr) {
|
||||
return []string{}, nil
|
||||
} else if pathErr != nil {
|
||||
return nil, fmt.Errorf("Error checking path %s: %v", pathname, pathErr)
|
||||
}
|
||||
hostpath, err := mounter.ne.EvalSymlinks(pathname, true /* mustExist */)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return searchMountPoints(hostpath, hostProcMountinfoPath)
|
||||
}
|
||||
|
||||
func (mounter *NsenterMounter) GetFSGroup(pathname string) (int64, error) {
|
||||
hostPath, err := mounter.ne.EvalSymlinks(pathname, true /* mustExist */)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
kubeletpath := mounter.ne.KubeletPath(hostPath)
|
||||
return getFSGroup(kubeletpath)
|
||||
}
|
||||
|
||||
func (mounter *NsenterMounter) GetSELinuxSupport(pathname string) (bool, error) {
|
||||
return getSELinuxSupport(pathname, hostProcMountsPath)
|
||||
}
|
||||
|
||||
func (mounter *NsenterMounter) GetMode(pathname string) (os.FileMode, error) {
|
||||
hostPath, err := mounter.ne.EvalSymlinks(pathname, true /* mustExist */)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
kubeletpath := mounter.ne.KubeletPath(hostPath)
|
||||
return getMode(kubeletpath)
|
||||
}
|
||||
110
vendor/k8s.io/kubernetes/pkg/util/mount/nsenter_mount_unsupported.go
generated
vendored
110
vendor/k8s.io/kubernetes/pkg/util/mount/nsenter_mount_unsupported.go
generated
vendored
|
|
@ -1,110 +0,0 @@
|
|||
// +build !linux
|
||||
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package mount
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"k8s.io/utils/nsenter"
|
||||
)
|
||||
|
||||
type NsenterMounter struct{}
|
||||
|
||||
func NewNsenterMounter(rootDir string, ne *nsenter.Nsenter) *NsenterMounter {
|
||||
return &NsenterMounter{}
|
||||
}
|
||||
|
||||
var _ = Interface(&NsenterMounter{})
|
||||
|
||||
func (*NsenterMounter) Mount(source string, target string, fstype string, options []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*NsenterMounter) Unmount(target string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*NsenterMounter) List() ([]MountPoint, error) {
|
||||
return []MountPoint{}, nil
|
||||
}
|
||||
|
||||
func (m *NsenterMounter) IsNotMountPoint(dir string) (bool, error) {
|
||||
return isNotMountPoint(m, dir)
|
||||
}
|
||||
|
||||
func (*NsenterMounter) IsMountPointMatch(mp MountPoint, dir string) bool {
|
||||
return (mp.Path == dir)
|
||||
}
|
||||
|
||||
func (*NsenterMounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (*NsenterMounter) DeviceOpened(pathname string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (*NsenterMounter) PathIsDevice(pathname string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (*NsenterMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (*NsenterMounter) MakeRShared(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*NsenterMounter) GetFileType(_ string) (FileType, error) {
|
||||
return FileType("fake"), errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (*NsenterMounter) MakeDir(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*NsenterMounter) MakeFile(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*NsenterMounter) ExistsPath(pathname string) (bool, error) {
|
||||
return true, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (*NsenterMounter) EvalHostSymlinks(pathname string) (string, error) {
|
||||
return "", errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (*NsenterMounter) GetMountRefs(pathname string) ([]string, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (*NsenterMounter) GetFSGroup(pathname string) (int64, error) {
|
||||
return -1, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (*NsenterMounter) GetSELinuxSupport(pathname string) (bool, error) {
|
||||
return false, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (*NsenterMounter) GetMode(pathname string) (os.FileMode, error) {
|
||||
return 0, errors.New("not implemented")
|
||||
}
|
||||
6
vendor/k8s.io/kubernetes/pkg/volume/BUILD
generated
vendored
6
vendor/k8s.io/kubernetes/pkg/volume/BUILD
generated
vendored
|
|
@ -18,6 +18,7 @@ go_library(
|
|||
importpath = "k8s.io/kubernetes/pkg/volume",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/features:go_default_library",
|
||||
"//pkg/util/mount:go_default_library",
|
||||
"//pkg/volume/util/fs:go_default_library",
|
||||
"//pkg/volume/util/recyclerclient:go_default_library",
|
||||
|
|
@ -29,8 +30,11 @@ go_library(
|
|||
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/validation:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/informers:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/listers/storage/v1beta1:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/record:go_default_library",
|
||||
"//staging/src/k8s.io/cloud-provider:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
|
|
@ -86,7 +90,7 @@ filegroup(
|
|||
"//pkg/volume/gcepd:all-srcs",
|
||||
"//pkg/volume/git_repo:all-srcs",
|
||||
"//pkg/volume/glusterfs:all-srcs",
|
||||
"//pkg/volume/host_path:all-srcs",
|
||||
"//pkg/volume/hostpath:all-srcs",
|
||||
"//pkg/volume/iscsi:all-srcs",
|
||||
"//pkg/volume/local:all-srcs",
|
||||
"//pkg/volume/nfs:all-srcs",
|
||||
|
|
|
|||
86
vendor/k8s.io/kubernetes/pkg/volume/plugins.go
generated
vendored
86
vendor/k8s.io/kubernetes/pkg/volume/plugins.go
generated
vendored
|
|
@ -29,11 +29,15 @@ import (
|
|||
"k8s.io/apimachinery/pkg/types"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/client-go/informers"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
storagelisters "k8s.io/client-go/listers/storage/v1beta1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/tools/record"
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
"k8s.io/kubernetes/pkg/volume/util/recyclerclient"
|
||||
"k8s.io/kubernetes/pkg/volume/util/subpath"
|
||||
|
|
@ -231,7 +235,7 @@ type AttachableVolumePlugin interface {
|
|||
NewAttacher() (Attacher, error)
|
||||
NewDetacher() (Detacher, error)
|
||||
// CanAttach tests if provided volume spec is attachable
|
||||
CanAttach(spec *Spec) bool
|
||||
CanAttach(spec *Spec) (bool, error)
|
||||
}
|
||||
|
||||
// DeviceMountableVolumePlugin is an extended interface of VolumePlugin and is used
|
||||
|
|
@ -241,6 +245,8 @@ type DeviceMountableVolumePlugin interface {
|
|||
NewDeviceMounter() (DeviceMounter, error)
|
||||
NewDeviceUnmounter() (DeviceUnmounter, error)
|
||||
GetDeviceMountRefs(deviceMountPath string) ([]string, error)
|
||||
// CanDeviceMount determines if device in volume.Spec is mountable
|
||||
CanDeviceMount(spec *Spec) (bool, error)
|
||||
}
|
||||
|
||||
// ExpandableVolumePlugin is an extended interface of VolumePlugin and is used for volumes that can be
|
||||
|
|
@ -319,6 +325,15 @@ type KubeletVolumeHost interface {
|
|||
// SetKubeletError lets plugins set an error on the Kubelet runtime status
|
||||
// that will cause the Kubelet to post NotReady status with the error message provided
|
||||
SetKubeletError(err error)
|
||||
|
||||
// GetInformerFactory returns the informer factory for CSIDriverLister
|
||||
GetInformerFactory() informers.SharedInformerFactory
|
||||
// CSIDriverLister returns the informer lister for the CSIDriver API Object
|
||||
CSIDriverLister() storagelisters.CSIDriverLister
|
||||
// CSIDriverSynced returns the informer synced for the CSIDriver API Object
|
||||
CSIDriversSynced() cache.InformerSynced
|
||||
// WaitForCacheSync is a helper function that waits for cache sync for CSIDriverLister
|
||||
WaitForCacheSync() error
|
||||
}
|
||||
|
||||
// AttachDetachVolumeHost is a AttachDetach Controller specific interface that plugins can use
|
||||
|
|
@ -327,6 +342,9 @@ type AttachDetachVolumeHost interface {
|
|||
// CSINodeLister returns the informer lister for the CSINode API Object
|
||||
CSINodeLister() storagelisters.CSINodeLister
|
||||
|
||||
// CSIDriverLister returns the informer lister for the CSIDriver API Object
|
||||
CSIDriverLister() storagelisters.CSIDriverLister
|
||||
|
||||
// IsAttachDetachController is an interface marker to strictly tie AttachDetachVolumeHost
|
||||
// to the attachDetachController
|
||||
IsAttachDetachController() bool
|
||||
|
|
@ -434,9 +452,10 @@ type VolumePluginMgr struct {
|
|||
|
||||
// Spec is an internal representation of a volume. All API volume types translate to Spec.
|
||||
type Spec struct {
|
||||
Volume *v1.Volume
|
||||
PersistentVolume *v1.PersistentVolume
|
||||
ReadOnly bool
|
||||
Volume *v1.Volume
|
||||
PersistentVolume *v1.PersistentVolume
|
||||
ReadOnly bool
|
||||
InlineVolumeSpecForCSIMigration bool
|
||||
}
|
||||
|
||||
// Name returns the name of either Volume or PersistentVolume, one of which must not be nil.
|
||||
|
|
@ -629,11 +648,9 @@ func (pm *VolumePluginMgr) FindPluginBySpec(spec *Spec) (VolumePlugin, error) {
|
|||
return nil, fmt.Errorf("Could not find plugin because volume spec is nil")
|
||||
}
|
||||
|
||||
matchedPluginNames := []string{}
|
||||
matches := []VolumePlugin{}
|
||||
for k, v := range pm.plugins {
|
||||
for _, v := range pm.plugins {
|
||||
if v.CanSupport(spec) {
|
||||
matchedPluginNames = append(matchedPluginNames, k)
|
||||
matches = append(matches, v)
|
||||
}
|
||||
}
|
||||
|
|
@ -641,7 +658,6 @@ func (pm *VolumePluginMgr) FindPluginBySpec(spec *Spec) (VolumePlugin, error) {
|
|||
pm.refreshProbedPlugins()
|
||||
for _, plugin := range pm.probedPlugins {
|
||||
if plugin.CanSupport(spec) {
|
||||
matchedPluginNames = append(matchedPluginNames, plugin.GetPluginName())
|
||||
matches = append(matches, plugin)
|
||||
}
|
||||
}
|
||||
|
|
@ -650,6 +666,10 @@ func (pm *VolumePluginMgr) FindPluginBySpec(spec *Spec) (VolumePlugin, error) {
|
|||
return nil, fmt.Errorf("no volume plugin matched")
|
||||
}
|
||||
if len(matches) > 1 {
|
||||
matchedPluginNames := []string{}
|
||||
for _, plugin := range matches {
|
||||
matchedPluginNames = append(matchedPluginNames, plugin.GetPluginName())
|
||||
}
|
||||
return nil, fmt.Errorf("multiple volume plugins matched: %s", strings.Join(matchedPluginNames, ","))
|
||||
}
|
||||
return matches[0], nil
|
||||
|
|
@ -666,11 +686,9 @@ func (pm *VolumePluginMgr) IsPluginMigratableBySpec(spec *Spec) (bool, error) {
|
|||
return false, fmt.Errorf("could not find if plugin is migratable because volume spec is nil")
|
||||
}
|
||||
|
||||
matchedPluginNames := []string{}
|
||||
matches := []VolumePlugin{}
|
||||
for k, v := range pm.plugins {
|
||||
for _, v := range pm.plugins {
|
||||
if v.CanSupport(spec) {
|
||||
matchedPluginNames = append(matchedPluginNames, k)
|
||||
matches = append(matches, v)
|
||||
}
|
||||
}
|
||||
|
|
@ -680,6 +698,10 @@ func (pm *VolumePluginMgr) IsPluginMigratableBySpec(spec *Spec) (bool, error) {
|
|||
return false, nil
|
||||
}
|
||||
if len(matches) > 1 {
|
||||
matchedPluginNames := []string{}
|
||||
for _, plugin := range matches {
|
||||
matchedPluginNames = append(matchedPluginNames, plugin.GetPluginName())
|
||||
}
|
||||
return false, fmt.Errorf("multiple volume plugins matched: %s", strings.Join(matchedPluginNames, ","))
|
||||
}
|
||||
|
||||
|
|
@ -693,27 +715,24 @@ func (pm *VolumePluginMgr) FindPluginByName(name string) (VolumePlugin, error) {
|
|||
defer pm.mutex.Unlock()
|
||||
|
||||
// Once we can get rid of legacy names we can reduce this to a map lookup.
|
||||
matchedPluginNames := []string{}
|
||||
matches := []VolumePlugin{}
|
||||
for k, v := range pm.plugins {
|
||||
if v.GetPluginName() == name {
|
||||
matchedPluginNames = append(matchedPluginNames, k)
|
||||
matches = append(matches, v)
|
||||
}
|
||||
if v, found := pm.plugins[name]; found {
|
||||
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 plugin, found := pm.probedPlugins[name]; found {
|
||||
matches = append(matches, plugin)
|
||||
}
|
||||
|
||||
if len(matches) == 0 {
|
||||
return nil, fmt.Errorf("no volume plugin matched")
|
||||
}
|
||||
if len(matches) > 1 {
|
||||
matchedPluginNames := []string{}
|
||||
for _, plugin := range matches {
|
||||
matchedPluginNames = append(matchedPluginNames, plugin.GetPluginName())
|
||||
}
|
||||
return nil, fmt.Errorf("multiple volume plugins matched: %s", strings.Join(matchedPluginNames, ","))
|
||||
}
|
||||
return matches[0], nil
|
||||
|
|
@ -824,7 +843,7 @@ func (pm *VolumePluginMgr) FindProvisionablePluginByName(name string) (Provision
|
|||
return nil, fmt.Errorf("no provisionable volume plugin matched")
|
||||
}
|
||||
|
||||
// FindDeletablePluginBySppec fetches a persistent volume plugin by spec. If
|
||||
// FindDeletablePluginBySpec fetches a persistent volume plugin by spec. If
|
||||
// no plugin is found, returns error.
|
||||
func (pm *VolumePluginMgr) FindDeletablePluginBySpec(spec *Spec) (DeletableVolumePlugin, error) {
|
||||
volumePlugin, err := pm.FindPluginBySpec(spec)
|
||||
|
|
@ -873,7 +892,9 @@ func (pm *VolumePluginMgr) FindAttachablePluginBySpec(spec *Spec) (AttachableVol
|
|||
return nil, err
|
||||
}
|
||||
if attachableVolumePlugin, ok := volumePlugin.(AttachableVolumePlugin); ok {
|
||||
if attachableVolumePlugin.CanAttach(spec) {
|
||||
if canAttach, err := attachableVolumePlugin.CanAttach(spec); err != nil {
|
||||
return nil, err
|
||||
} else if canAttach {
|
||||
return attachableVolumePlugin, nil
|
||||
}
|
||||
}
|
||||
|
|
@ -902,7 +923,11 @@ func (pm *VolumePluginMgr) FindDeviceMountablePluginBySpec(spec *Spec) (DeviceMo
|
|||
return nil, err
|
||||
}
|
||||
if deviceMountableVolumePlugin, ok := volumePlugin.(DeviceMountableVolumePlugin); ok {
|
||||
return deviceMountableVolumePlugin, nil
|
||||
if canMount, err := deviceMountableVolumePlugin.CanDeviceMount(spec); err != nil {
|
||||
return nil, err
|
||||
} else if canMount {
|
||||
return deviceMountableVolumePlugin, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
|
@ -1004,6 +1029,17 @@ func (pm *VolumePluginMgr) FindNodeExpandablePluginByName(name string) (NodeExpa
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func (pm *VolumePluginMgr) Run(stopCh <-chan struct{}) {
|
||||
kletHost, ok := pm.Host.(KubeletVolumeHost)
|
||||
if ok {
|
||||
// start informer for CSIDriver
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.CSIDriverRegistry) {
|
||||
informerFactory := kletHost.GetInformerFactory()
|
||||
informerFactory.Start(stopCh)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewPersistentVolumeRecyclerPodTemplate creates a template for a recycler
|
||||
// pod. By default, a recycler pod simply runs "rm -rf" on a volume and tests
|
||||
// for emptiness. Most attributes of the template will be correct for most
|
||||
|
|
|
|||
2
vendor/k8s.io/kubernetes/pkg/volume/util/fs/BUILD
generated
vendored
2
vendor/k8s.io/kubernetes/pkg/volume/util/fs/BUILD
generated
vendored
|
|
@ -14,6 +14,7 @@ go_library(
|
|||
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:darwin": [
|
||||
"//pkg/volume/util/quota:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//vendor/golang.org/x/sys/unix:go_default_library",
|
||||
],
|
||||
|
|
@ -24,6 +25,7 @@ go_library(
|
|||
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:linux": [
|
||||
"//pkg/volume/util/quota:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//vendor/golang.org/x/sys/unix:go_default_library",
|
||||
],
|
||||
|
|
|
|||
19
vendor/k8s.io/kubernetes/pkg/volume/util/fs/fs.go
generated
vendored
19
vendor/k8s.io/kubernetes/pkg/volume/util/fs/fs.go
generated
vendored
|
|
@ -27,6 +27,7 @@ import (
|
|||
"golang.org/x/sys/unix"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"k8s.io/kubernetes/pkg/volume/util/quota"
|
||||
)
|
||||
|
||||
// FSInfo linux returns (available bytes, byte capacity, byte usage, total inodes, inodes free, inode usage, error)
|
||||
|
|
@ -56,6 +57,15 @@ func FsInfo(path string) (int64, int64, int64, int64, int64, int64, error) {
|
|||
|
||||
// DiskUsage gets disk usage of specified path.
|
||||
func DiskUsage(path string) (*resource.Quantity, error) {
|
||||
// First check whether the quota system knows about this directory
|
||||
// A nil quantity with no error means that the path does not support quotas
|
||||
// and we should use other mechanisms.
|
||||
data, err := quota.GetConsumption(path)
|
||||
if data != nil {
|
||||
return data, nil
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("unable to retrieve disk consumption via quota for %s: %v", path, err)
|
||||
}
|
||||
// Uses the same niceness level as cadvisor.fs does when running du
|
||||
// Uses -B 1 to always scale to a blocksize of 1 byte
|
||||
out, err := exec.Command("nice", "-n", "19", "du", "-s", "-B", "1", path).CombinedOutput()
|
||||
|
|
@ -76,6 +86,15 @@ func Find(path string) (int64, error) {
|
|||
if path == "" {
|
||||
return 0, fmt.Errorf("invalid directory")
|
||||
}
|
||||
// First check whether the quota system knows about this directory
|
||||
// A nil quantity with no error means that the path does not support quotas
|
||||
// and we should use other mechanisms.
|
||||
inodes, err := quota.GetInodes(path)
|
||||
if inodes != nil {
|
||||
return inodes.Value(), nil
|
||||
} else if err != nil {
|
||||
return 0, fmt.Errorf("unable to retrieve inode consumption via quota for %s: %v", path, err)
|
||||
}
|
||||
var counter byteCounter
|
||||
var stderr bytes.Buffer
|
||||
findCmd := exec.Command("find", path, "-xdev", "-printf", ".")
|
||||
|
|
|
|||
61
vendor/k8s.io/kubernetes/pkg/volume/util/quota/BUILD
generated
vendored
Normal file
61
vendor/k8s.io/kubernetes/pkg/volume/util/quota/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"project.go",
|
||||
"quota.go",
|
||||
"quota_linux.go",
|
||||
"quota_unsupported.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/volume/util/quota",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/features:go_default_library",
|
||||
"//pkg/util/mount:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:linux": [
|
||||
"//pkg/volume/util/quota/common:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
|
||||
"//vendor/golang.org/x/sys/unix:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["quota_linux_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = select({
|
||||
"@io_bazel_rules_go//go/platform:linux": [
|
||||
"//pkg/features:go_default_library",
|
||||
"//pkg/util/mount:go_default_library",
|
||||
"//pkg/volume/util/quota/common:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//staging/src/k8s.io/component-base/featuregate/testing:go_default_library",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/volume/util/quota/common:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
31
vendor/k8s.io/kubernetes/pkg/volume/util/quota/common/BUILD
generated
vendored
Normal file
31
vendor/k8s.io/kubernetes/pkg/volume/util/quota/common/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"quota_linux_common.go",
|
||||
"quota_linux_common_impl.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/volume/util/quota/common",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = select({
|
||||
"@io_bazel_rules_go//go/platform:linux": [
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
105
vendor/k8s.io/kubernetes/pkg/volume/util/quota/common/quota_linux_common.go
generated
vendored
Normal file
105
vendor/k8s.io/kubernetes/pkg/volume/util/quota/common/quota_linux_common.go
generated
vendored
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
// +build linux
|
||||
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// QuotaID is generic quota identifier.
|
||||
// Data type based on quotactl(2).
|
||||
type QuotaID int32
|
||||
|
||||
const (
|
||||
// UnknownQuotaID -- cannot determine whether a quota is in force
|
||||
UnknownQuotaID QuotaID = -1
|
||||
// BadQuotaID -- Invalid quota
|
||||
BadQuotaID QuotaID = 0
|
||||
)
|
||||
|
||||
const (
|
||||
acct = iota
|
||||
enforcing = iota
|
||||
)
|
||||
|
||||
// QuotaType -- type of quota to be applied
|
||||
type QuotaType int
|
||||
|
||||
const (
|
||||
// FSQuotaAccounting for quotas for accounting only
|
||||
FSQuotaAccounting QuotaType = 1 << iota
|
||||
// FSQuotaEnforcing for quotas for enforcement
|
||||
FSQuotaEnforcing QuotaType = 1 << iota
|
||||
)
|
||||
|
||||
// FirstQuota is the quota ID we start with.
|
||||
// XXXXXXX Need a better way of doing this...
|
||||
var FirstQuota QuotaID = 1048577
|
||||
|
||||
// MountsFile is the location of the system mount data
|
||||
var MountsFile = "/proc/self/mounts"
|
||||
|
||||
// MountParseRegexp parses out /proc/sys/self/mounts
|
||||
var MountParseRegexp = regexp.MustCompilePOSIX("^([^ ]*)[ \t]*([^ ]*)[ \t]*([^ ]*)") // Ignore options etc.
|
||||
|
||||
// LinuxVolumeQuotaProvider returns an appropriate quota applier
|
||||
// object if we can support quotas on this device
|
||||
type LinuxVolumeQuotaProvider interface {
|
||||
// GetQuotaApplier retrieves an object that can apply
|
||||
// quotas (or nil if this provider cannot support quotas
|
||||
// on the device)
|
||||
GetQuotaApplier(mountpoint string, backingDev string) LinuxVolumeQuotaApplier
|
||||
}
|
||||
|
||||
// LinuxVolumeQuotaApplier is a generic interface to any quota
|
||||
// mechanism supported by Linux
|
||||
type LinuxVolumeQuotaApplier interface {
|
||||
// GetQuotaOnDir gets the quota ID (if any) that applies to
|
||||
// this directory
|
||||
GetQuotaOnDir(path string) (QuotaID, error)
|
||||
|
||||
// SetQuotaOnDir applies the specified quota ID to a directory.
|
||||
// Negative value for bytes means that a non-enforcing quota
|
||||
// should be applied (perhaps by setting a quota too large to
|
||||
// be hit)
|
||||
SetQuotaOnDir(path string, id QuotaID, bytes int64) error
|
||||
|
||||
// QuotaIDIsInUse determines whether the quota ID is in use.
|
||||
// Implementations should not check /etc/project or /etc/projid,
|
||||
// only whether their underlying mechanism already has the ID in
|
||||
// use.
|
||||
// Return value of false with no error means that the ID is not
|
||||
// in use; true means that it is already in use. An error
|
||||
// return means that any quota ID will fail.
|
||||
QuotaIDIsInUse(id QuotaID) (bool, error)
|
||||
|
||||
// GetConsumption returns the consumption (in bytes) of the
|
||||
// directory, determined by the implementation's quota-based
|
||||
// mechanism. If it is unable to do so using that mechanism,
|
||||
// it should return an error and allow higher layers to
|
||||
// enumerate the directory.
|
||||
GetConsumption(path string, id QuotaID) (int64, error)
|
||||
|
||||
// GetInodes returns the number of inodes used by the
|
||||
// directory, determined by the implementation's quota-based
|
||||
// mechanism. If it is unable to do so using that mechanism,
|
||||
// it should return an error and allow higher layers to
|
||||
// enumerate the directory.
|
||||
GetInodes(path string, id QuotaID) (int64, error)
|
||||
}
|
||||
286
vendor/k8s.io/kubernetes/pkg/volume/util/quota/common/quota_linux_common_impl.go
generated
vendored
Normal file
286
vendor/k8s.io/kubernetes/pkg/volume/util/quota/common/quota_linux_common_impl.go
generated
vendored
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
// +build linux
|
||||
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
var quotaCmd string
|
||||
var quotaCmdInitialized bool
|
||||
var quotaCmdLock sync.RWMutex
|
||||
|
||||
// If we later get a filesystem that uses project quota semantics other than
|
||||
// XFS, we'll need to change this.
|
||||
// Higher levels don't need to know what's inside
|
||||
type linuxFilesystemType struct {
|
||||
name string
|
||||
typeMagic int64 // Filesystem magic number, per statfs(2)
|
||||
maxQuota int64
|
||||
allowEmptyOutput bool // Accept empty output from "quota" command
|
||||
}
|
||||
|
||||
const (
|
||||
bitsPerWord = 32 << (^uint(0) >> 63) // either 32 or 64
|
||||
)
|
||||
|
||||
var (
|
||||
linuxSupportedFilesystems = []linuxFilesystemType{
|
||||
{
|
||||
name: "XFS",
|
||||
typeMagic: 0x58465342,
|
||||
maxQuota: 1<<(bitsPerWord-1) - 1,
|
||||
allowEmptyOutput: true, // XFS filesystems report nothing if a quota is not present
|
||||
}, {
|
||||
name: "ext4fs",
|
||||
typeMagic: 0xef53,
|
||||
maxQuota: (1<<(bitsPerWord-1) - 1) & (1<<58 - 1),
|
||||
allowEmptyOutput: false, // ext4 filesystems always report something even if a quota is not present
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// VolumeProvider supplies a quota applier to the generic code.
|
||||
type VolumeProvider struct {
|
||||
}
|
||||
|
||||
var quotaCmds = []string{"/sbin/xfs_quota",
|
||||
"/usr/sbin/xfs_quota",
|
||||
"/bin/xfs_quota"}
|
||||
|
||||
var quotaParseRegexp = regexp.MustCompilePOSIX("^[^ \t]*[ \t]*([0-9]+)")
|
||||
|
||||
var lsattrCmd = "/usr/bin/lsattr"
|
||||
var lsattrParseRegexp = regexp.MustCompilePOSIX("^ *([0-9]+) [^ ]+ (.*)$")
|
||||
|
||||
// GetQuotaApplier -- does this backing device support quotas that
|
||||
// can be applied to directories?
|
||||
func (*VolumeProvider) GetQuotaApplier(mountpoint string, backingDev string) LinuxVolumeQuotaApplier {
|
||||
for _, fsType := range linuxSupportedFilesystems {
|
||||
if isFilesystemOfType(mountpoint, backingDev, fsType.typeMagic) {
|
||||
return linuxVolumeQuotaApplier{mountpoint: mountpoint,
|
||||
maxQuota: fsType.maxQuota,
|
||||
allowEmptyOutput: fsType.allowEmptyOutput,
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type linuxVolumeQuotaApplier struct {
|
||||
mountpoint string
|
||||
maxQuota int64
|
||||
allowEmptyOutput bool
|
||||
}
|
||||
|
||||
func getXFSQuotaCmd() (string, error) {
|
||||
quotaCmdLock.Lock()
|
||||
defer quotaCmdLock.Unlock()
|
||||
if quotaCmdInitialized {
|
||||
return quotaCmd, nil
|
||||
}
|
||||
for _, program := range quotaCmds {
|
||||
fileinfo, err := os.Stat(program)
|
||||
if err == nil && ((fileinfo.Mode().Perm() & (1 << 6)) != 0) {
|
||||
klog.V(3).Infof("Found xfs_quota program %s", program)
|
||||
quotaCmd = program
|
||||
quotaCmdInitialized = true
|
||||
return quotaCmd, nil
|
||||
}
|
||||
}
|
||||
quotaCmdInitialized = true
|
||||
return "", fmt.Errorf("No xfs_quota program found")
|
||||
}
|
||||
|
||||
func doRunXFSQuotaCommand(mountpoint string, mountsFile, command string) (string, error) {
|
||||
quotaCmd, err := getXFSQuotaCmd()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// We're using numeric project IDs directly; no need to scan
|
||||
// /etc/projects or /etc/projid
|
||||
klog.V(4).Infof("runXFSQuotaCommand %s -t %s -P/dev/null -D/dev/null -x -f %s -c %s", quotaCmd, mountsFile, mountpoint, command)
|
||||
cmd := exec.Command(quotaCmd, "-t", mountsFile, "-P/dev/null", "-D/dev/null", "-x", "-f", mountpoint, "-c", command)
|
||||
|
||||
data, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
klog.V(4).Infof("runXFSQuotaCommand output %q", string(data))
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
// Extract the mountpoint we care about into a temporary mounts file so that xfs_quota does
|
||||
// not attempt to scan every mount on the filesystem, which could hang if e. g.
|
||||
// a stuck NFS mount is present.
|
||||
// See https://bugzilla.redhat.com/show_bug.cgi?id=237120 for an example
|
||||
// of the problem that could be caused if this were to happen.
|
||||
func runXFSQuotaCommand(mountpoint string, command string) (string, error) {
|
||||
tmpMounts, err := ioutil.TempFile("", "mounts")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Cannot create temporary mount file: %v", err)
|
||||
}
|
||||
tmpMountsFileName := tmpMounts.Name()
|
||||
defer tmpMounts.Close()
|
||||
defer os.Remove(tmpMountsFileName)
|
||||
|
||||
mounts, err := os.Open(MountsFile)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Cannot open mounts file %s: %v", MountsFile, err)
|
||||
}
|
||||
defer mounts.Close()
|
||||
|
||||
scanner := bufio.NewScanner(mounts)
|
||||
for scanner.Scan() {
|
||||
match := MountParseRegexp.FindStringSubmatch(scanner.Text())
|
||||
if match != nil {
|
||||
mount := match[2]
|
||||
if mount == mountpoint {
|
||||
if _, err := tmpMounts.WriteString(fmt.Sprintf("%s\n", scanner.Text())); err != nil {
|
||||
return "", fmt.Errorf("Cannot write temporary mounts file: %v", err)
|
||||
}
|
||||
if err := tmpMounts.Sync(); err != nil {
|
||||
return "", fmt.Errorf("Cannot sync temporary mounts file: %v", err)
|
||||
}
|
||||
return doRunXFSQuotaCommand(mountpoint, tmpMountsFileName, command)
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("Cannot run xfs_quota: cannot find mount point %s in %s", mountpoint, MountsFile)
|
||||
}
|
||||
|
||||
// SupportsQuotas determines whether the filesystem supports quotas.
|
||||
func SupportsQuotas(mountpoint string, qType QuotaType) (bool, error) {
|
||||
data, err := runXFSQuotaCommand(mountpoint, "state -p")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if qType == FSQuotaEnforcing {
|
||||
return strings.Contains(data, "Enforcement: ON"), nil
|
||||
}
|
||||
return strings.Contains(data, "Accounting: ON"), nil
|
||||
}
|
||||
|
||||
func isFilesystemOfType(mountpoint string, backingDev string, typeMagic int64) bool {
|
||||
var buf syscall.Statfs_t
|
||||
err := syscall.Statfs(mountpoint, &buf)
|
||||
if err != nil {
|
||||
klog.Warningf("Warning: Unable to statfs %s: %v", mountpoint, err)
|
||||
return false
|
||||
}
|
||||
if int64(buf.Type) != typeMagic {
|
||||
return false
|
||||
}
|
||||
if answer, _ := SupportsQuotas(mountpoint, FSQuotaAccounting); answer {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetQuotaOnDir retrieves the quota ID (if any) associated with the specified directory
|
||||
// If we can't make system calls, all we can say is that we don't know whether
|
||||
// it has a quota, and higher levels have to make the call.
|
||||
func (v linuxVolumeQuotaApplier) GetQuotaOnDir(path string) (QuotaID, error) {
|
||||
cmd := exec.Command(lsattrCmd, "-pd", path)
|
||||
data, err := cmd.Output()
|
||||
if err != nil {
|
||||
return BadQuotaID, fmt.Errorf("cannot run lsattr: %v", err)
|
||||
}
|
||||
match := lsattrParseRegexp.FindStringSubmatch(string(data))
|
||||
if match == nil {
|
||||
return BadQuotaID, fmt.Errorf("Unable to parse lsattr -pd %s output %s", path, string(data))
|
||||
}
|
||||
if match[2] != path {
|
||||
return BadQuotaID, fmt.Errorf("Mismatch between supplied and returned path (%s != %s)", path, match[2])
|
||||
}
|
||||
projid, err := strconv.ParseInt(match[1], 10, 32)
|
||||
if err != nil {
|
||||
return BadQuotaID, fmt.Errorf("Unable to parse project ID from %s (%v)", match[1], err)
|
||||
}
|
||||
return QuotaID(projid), nil
|
||||
}
|
||||
|
||||
// SetQuotaOnDir applies a quota to the specified directory under the specified mountpoint.
|
||||
func (v linuxVolumeQuotaApplier) SetQuotaOnDir(path string, id QuotaID, bytes int64) error {
|
||||
if bytes < 0 || bytes > v.maxQuota {
|
||||
bytes = v.maxQuota
|
||||
}
|
||||
_, err := runXFSQuotaCommand(v.mountpoint, fmt.Sprintf("limit -p bhard=%v bsoft=%v %v", bytes, bytes, id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = runXFSQuotaCommand(v.mountpoint, fmt.Sprintf("project -s -p %s %v", path, id))
|
||||
return err
|
||||
}
|
||||
|
||||
func getQuantity(mountpoint string, id QuotaID, xfsQuotaArg string, multiplier int64, allowEmptyOutput bool) (int64, error) {
|
||||
data, err := runXFSQuotaCommand(mountpoint, fmt.Sprintf("quota -p -N -n -v %s %v", xfsQuotaArg, id))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("Unable to run xfs_quota: %v", err)
|
||||
}
|
||||
if data == "" && allowEmptyOutput {
|
||||
return 0, nil
|
||||
}
|
||||
match := quotaParseRegexp.FindStringSubmatch(data)
|
||||
if match == nil {
|
||||
return 0, fmt.Errorf("Unable to parse quota output '%s'", data)
|
||||
}
|
||||
size, err := strconv.ParseInt(match[1], 10, 64)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("Unable to parse data size '%s' from '%s': %v", match[1], data, err)
|
||||
}
|
||||
klog.V(4).Infof("getQuantity %s %d %s %d => %d %v", mountpoint, id, xfsQuotaArg, multiplier, size, err)
|
||||
return size * multiplier, nil
|
||||
}
|
||||
|
||||
// GetConsumption returns the consumption in bytes if available via quotas
|
||||
func (v linuxVolumeQuotaApplier) GetConsumption(_ string, id QuotaID) (int64, error) {
|
||||
return getQuantity(v.mountpoint, id, "-b", 1024, v.allowEmptyOutput)
|
||||
}
|
||||
|
||||
// GetInodes returns the inodes in use if available via quotas
|
||||
func (v linuxVolumeQuotaApplier) GetInodes(_ string, id QuotaID) (int64, error) {
|
||||
return getQuantity(v.mountpoint, id, "-i", 1, v.allowEmptyOutput)
|
||||
}
|
||||
|
||||
// QuotaIDIsInUse checks whether the specified quota ID is in use on the specified
|
||||
// filesystem
|
||||
func (v linuxVolumeQuotaApplier) QuotaIDIsInUse(id QuotaID) (bool, error) {
|
||||
bytes, err := v.GetConsumption(v.mountpoint, id)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if bytes > 0 {
|
||||
return true, nil
|
||||
}
|
||||
inodes, err := v.GetInodes(v.mountpoint, id)
|
||||
return inodes > 0, err
|
||||
}
|
||||
357
vendor/k8s.io/kubernetes/pkg/volume/util/quota/project.go
generated
vendored
Normal file
357
vendor/k8s.io/kubernetes/pkg/volume/util/quota/project.go
generated
vendored
Normal file
|
|
@ -0,0 +1,357 @@
|
|||
// +build linux
|
||||
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package quota
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"k8s.io/kubernetes/pkg/volume/util/quota/common"
|
||||
)
|
||||
|
||||
var projectsFile = "/etc/projects"
|
||||
var projidFile = "/etc/projid"
|
||||
|
||||
var projectsParseRegexp = regexp.MustCompilePOSIX("^([[:digit:]]+):(.*)$")
|
||||
var projidParseRegexp = regexp.MustCompilePOSIX("^([^#][^:]*):([[:digit:]]+)$")
|
||||
|
||||
var quotaIDLock sync.RWMutex
|
||||
|
||||
const maxUnusedQuotasToSearch = 128 // Don't go into an infinite loop searching for an unused quota
|
||||
|
||||
type projectType struct {
|
||||
isValid bool // False if we need to remove this line
|
||||
id common.QuotaID
|
||||
data string // Project name (projid) or directory (projects)
|
||||
line string
|
||||
}
|
||||
|
||||
type projectsList struct {
|
||||
projects []projectType
|
||||
projid []projectType
|
||||
}
|
||||
|
||||
func projFilesAreOK() error {
|
||||
if sf, err := os.Lstat(projectsFile); err != nil || sf.Mode().IsRegular() {
|
||||
if sf, err := os.Lstat(projidFile); err != nil || sf.Mode().IsRegular() {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("%s exists but is not a plain file, cannot continue", projidFile)
|
||||
}
|
||||
return fmt.Errorf("%s exists but is not a plain file, cannot continue", projectsFile)
|
||||
}
|
||||
|
||||
func lockFile(file *os.File) error {
|
||||
return unix.Flock(int(file.Fd()), unix.LOCK_EX)
|
||||
}
|
||||
|
||||
func unlockFile(file *os.File) error {
|
||||
return unix.Flock(int(file.Fd()), unix.LOCK_UN)
|
||||
}
|
||||
|
||||
// openAndLockProjectFiles opens /etc/projects and /etc/projid locked.
|
||||
// Creates them if they don't exist
|
||||
func openAndLockProjectFiles() (*os.File, *os.File, error) {
|
||||
// Make sure neither project-related file is a symlink!
|
||||
if err := projFilesAreOK(); err != nil {
|
||||
return nil, nil, fmt.Errorf("system project files failed verification: %v", err)
|
||||
}
|
||||
// We don't actually modify the original files; we create temporaries and
|
||||
// move them over the originals
|
||||
fProjects, err := os.OpenFile(projectsFile, os.O_RDONLY|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("unable to open %s: %v", projectsFile, err)
|
||||
return nil, nil, err
|
||||
}
|
||||
fProjid, err := os.OpenFile(projidFile, os.O_RDONLY|os.O_CREATE, 0644)
|
||||
if err == nil {
|
||||
// Check once more, to ensure nothing got changed out from under us
|
||||
if err := projFilesAreOK(); err == nil {
|
||||
err = lockFile(fProjects)
|
||||
if err == nil {
|
||||
err = lockFile(fProjid)
|
||||
if err == nil {
|
||||
return fProjects, fProjid, nil
|
||||
}
|
||||
// Nothing useful we can do if we get an error here
|
||||
err = fmt.Errorf("unable to lock %s: %v", projidFile, err)
|
||||
unlockFile(fProjects)
|
||||
} else {
|
||||
err = fmt.Errorf("unable to lock %s: %v", projectsFile, err)
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("system project files failed re-verification: %v", err)
|
||||
}
|
||||
fProjid.Close()
|
||||
} else {
|
||||
err = fmt.Errorf("unable to open %s: %v", projidFile, err)
|
||||
}
|
||||
fProjects.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
func closeProjectFiles(fProjects *os.File, fProjid *os.File) error {
|
||||
// Nothing useful we can do if either of these fail,
|
||||
// but we have to close (and thereby unlock) the files anyway.
|
||||
var err error
|
||||
var err1 error
|
||||
if fProjid != nil {
|
||||
err = fProjid.Close()
|
||||
}
|
||||
if fProjects != nil {
|
||||
err1 = fProjects.Close()
|
||||
}
|
||||
if err == nil {
|
||||
return err1
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func parseProject(l string) projectType {
|
||||
if match := projectsParseRegexp.FindStringSubmatch(l); match != nil {
|
||||
i, err := strconv.Atoi(match[1])
|
||||
if err == nil {
|
||||
return projectType{true, common.QuotaID(i), match[2], l}
|
||||
}
|
||||
}
|
||||
return projectType{true, common.BadQuotaID, "", l}
|
||||
}
|
||||
|
||||
func parseProjid(l string) projectType {
|
||||
if match := projidParseRegexp.FindStringSubmatch(l); match != nil {
|
||||
i, err := strconv.Atoi(match[2])
|
||||
if err == nil {
|
||||
return projectType{true, common.QuotaID(i), match[1], l}
|
||||
}
|
||||
}
|
||||
return projectType{true, common.BadQuotaID, "", l}
|
||||
}
|
||||
|
||||
func parseProjFile(f *os.File, parser func(l string) projectType) []projectType {
|
||||
var answer []projectType
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
answer = append(answer, parser(scanner.Text()))
|
||||
}
|
||||
return answer
|
||||
}
|
||||
|
||||
func readProjectFiles(projects *os.File, projid *os.File) projectsList {
|
||||
return projectsList{parseProjFile(projects, parseProject), parseProjFile(projid, parseProjid)}
|
||||
}
|
||||
|
||||
func findAvailableQuota(path string, idMap map[common.QuotaID]bool) (common.QuotaID, error) {
|
||||
unusedQuotasSearched := 0
|
||||
for id := common.FirstQuota; id == id; id++ {
|
||||
if _, ok := idMap[id]; !ok {
|
||||
isInUse, err := getApplier(path).QuotaIDIsInUse(id)
|
||||
if err != nil {
|
||||
return common.BadQuotaID, err
|
||||
} else if !isInUse {
|
||||
return id, nil
|
||||
}
|
||||
unusedQuotasSearched++
|
||||
if unusedQuotasSearched > maxUnusedQuotasToSearch {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return common.BadQuotaID, fmt.Errorf("Cannot find available quota ID")
|
||||
}
|
||||
|
||||
func addDirToProject(path string, id common.QuotaID, list *projectsList) (common.QuotaID, bool, error) {
|
||||
idMap := make(map[common.QuotaID]bool)
|
||||
for _, project := range list.projects {
|
||||
if project.data == path {
|
||||
if id != project.id {
|
||||
return common.BadQuotaID, false, fmt.Errorf("Attempt to reassign project ID for %s", path)
|
||||
}
|
||||
// Trying to reassign a directory to the project it's
|
||||
// already in. Maybe this should be an error, but for
|
||||
// now treat it as an idempotent operation
|
||||
return id, false, nil
|
||||
}
|
||||
idMap[project.id] = true
|
||||
}
|
||||
var needToAddProjid = true
|
||||
for _, projid := range list.projid {
|
||||
idMap[projid.id] = true
|
||||
if projid.id == id && id != common.BadQuotaID {
|
||||
needToAddProjid = false
|
||||
}
|
||||
}
|
||||
var err error
|
||||
if id == common.BadQuotaID {
|
||||
id, err = findAvailableQuota(path, idMap)
|
||||
if err != nil {
|
||||
return common.BadQuotaID, false, err
|
||||
}
|
||||
needToAddProjid = true
|
||||
}
|
||||
if needToAddProjid {
|
||||
name := fmt.Sprintf("volume%v", id)
|
||||
line := fmt.Sprintf("%s:%v", name, id)
|
||||
list.projid = append(list.projid, projectType{true, id, name, line})
|
||||
}
|
||||
line := fmt.Sprintf("%v:%s", id, path)
|
||||
list.projects = append(list.projects, projectType{true, id, path, line})
|
||||
return id, needToAddProjid, nil
|
||||
}
|
||||
|
||||
func removeDirFromProject(path string, id common.QuotaID, list *projectsList) (bool, error) {
|
||||
if id == common.BadQuotaID {
|
||||
return false, fmt.Errorf("Attempt to remove invalid quota ID from %s", path)
|
||||
}
|
||||
foundAt := -1
|
||||
countByID := make(map[common.QuotaID]int)
|
||||
for i, project := range list.projects {
|
||||
if project.data == path {
|
||||
if id != project.id {
|
||||
return false, fmt.Errorf("Attempting to remove quota ID %v from path %s, but expecting ID %v", id, path, project.id)
|
||||
} else if foundAt != -1 {
|
||||
return false, fmt.Errorf("Found multiple quota IDs for path %s", path)
|
||||
}
|
||||
// Faster and easier than deleting an element
|
||||
list.projects[i].isValid = false
|
||||
foundAt = i
|
||||
}
|
||||
countByID[project.id]++
|
||||
}
|
||||
if foundAt == -1 {
|
||||
return false, fmt.Errorf("Cannot find quota associated with path %s", path)
|
||||
}
|
||||
if countByID[id] <= 1 {
|
||||
// Removing the last entry means that we're no longer using
|
||||
// the quota ID, so remove that as well
|
||||
for i, projid := range list.projid {
|
||||
if projid.id == id {
|
||||
list.projid[i].isValid = false
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func writeProjectFile(base *os.File, projects []projectType) (string, error) {
|
||||
oname := base.Name()
|
||||
stat, err := base.Stat()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
mode := stat.Mode() & os.ModePerm
|
||||
f, err := ioutil.TempFile(filepath.Dir(oname), filepath.Base(oname))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
filename := f.Name()
|
||||
if err := os.Chmod(filename, mode); err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, proj := range projects {
|
||||
if proj.isValid {
|
||||
if _, err := f.WriteString(fmt.Sprintf("%s\n", proj.line)); err != nil {
|
||||
f.Close()
|
||||
os.Remove(filename)
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
os.Remove(filename)
|
||||
return "", err
|
||||
}
|
||||
return filename, nil
|
||||
}
|
||||
|
||||
func writeProjectFiles(fProjects *os.File, fProjid *os.File, writeProjid bool, list projectsList) error {
|
||||
tmpProjects, err := writeProjectFile(fProjects, list.projects)
|
||||
if err == nil {
|
||||
// Ensure that both files are written before we try to rename either.
|
||||
if writeProjid {
|
||||
tmpProjid, err := writeProjectFile(fProjid, list.projid)
|
||||
if err == nil {
|
||||
err = os.Rename(tmpProjid, fProjid.Name())
|
||||
if err != nil {
|
||||
os.Remove(tmpProjid)
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
err = os.Rename(tmpProjects, fProjects.Name())
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
// We're in a bit of trouble here; at this
|
||||
// point we've successfully renamed tmpProjid
|
||||
// to the real thing, but renaming tmpProject
|
||||
// to the real file failed. There's not much we
|
||||
// can do in this position. Anything we could do
|
||||
// to try to undo it would itself be likely to fail.
|
||||
}
|
||||
os.Remove(tmpProjects)
|
||||
}
|
||||
return fmt.Errorf("Unable to write project files: %v", err)
|
||||
}
|
||||
|
||||
func createProjectID(path string, ID common.QuotaID) (common.QuotaID, error) {
|
||||
quotaIDLock.Lock()
|
||||
defer quotaIDLock.Unlock()
|
||||
fProjects, fProjid, err := openAndLockProjectFiles()
|
||||
if err == nil {
|
||||
defer closeProjectFiles(fProjects, fProjid)
|
||||
list := readProjectFiles(fProjects, fProjid)
|
||||
writeProjid := true
|
||||
ID, writeProjid, err = addDirToProject(path, ID, &list)
|
||||
if err == nil && ID != common.BadQuotaID {
|
||||
if err = writeProjectFiles(fProjects, fProjid, writeProjid, list); err == nil {
|
||||
return ID, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return common.BadQuotaID, fmt.Errorf("createProjectID %s %v failed %v", path, ID, err)
|
||||
}
|
||||
|
||||
func removeProjectID(path string, ID common.QuotaID) error {
|
||||
if ID == common.BadQuotaID {
|
||||
return fmt.Errorf("attempting to remove invalid quota ID %v", ID)
|
||||
}
|
||||
quotaIDLock.Lock()
|
||||
defer quotaIDLock.Unlock()
|
||||
fProjects, fProjid, err := openAndLockProjectFiles()
|
||||
if err == nil {
|
||||
defer closeProjectFiles(fProjects, fProjid)
|
||||
list := readProjectFiles(fProjects, fProjid)
|
||||
writeProjid := true
|
||||
writeProjid, err = removeDirFromProject(path, ID, &list)
|
||||
if err == nil {
|
||||
if err = writeProjectFiles(fProjects, fProjid, writeProjid, list); err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("removeProjectID %s %v failed %v", path, ID, err)
|
||||
}
|
||||
48
vendor/k8s.io/kubernetes/pkg/volume/util/quota/quota.go
generated
vendored
Normal file
48
vendor/k8s.io/kubernetes/pkg/volume/util/quota/quota.go
generated
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package quota
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
)
|
||||
|
||||
// Interface -- quota interface
|
||||
type Interface interface {
|
||||
// Does the path provided support quotas, and if so, what types
|
||||
SupportsQuotas(m mount.Interface, path string) (bool, error)
|
||||
// Assign a quota (picked by the quota mechanism) to a path,
|
||||
// and return it.
|
||||
AssignQuota(m mount.Interface, path string, poduid string, bytes *resource.Quantity) error
|
||||
|
||||
// Get the quota-based storage consumption for the path
|
||||
GetConsumption(path string) (*resource.Quantity, error)
|
||||
|
||||
// Get the quota-based inode consumption for the path
|
||||
GetInodes(path string) (*resource.Quantity, error)
|
||||
|
||||
// Remove the quota from a path
|
||||
// Implementations may assume that any data covered by the
|
||||
// quota has already been removed.
|
||||
ClearQuota(m mount.Interface, path string, poduid string) error
|
||||
}
|
||||
|
||||
func enabledQuotasForMonitoring() bool {
|
||||
return utilfeature.DefaultFeatureGate.Enabled(features.LocalStorageCapacityIsolationFSQuotaMonitoring)
|
||||
}
|
||||
440
vendor/k8s.io/kubernetes/pkg/volume/util/quota/quota_linux.go
generated
vendored
Normal file
440
vendor/k8s.io/kubernetes/pkg/volume/util/quota/quota_linux.go
generated
vendored
Normal file
|
|
@ -0,0 +1,440 @@
|
|||
// +build linux
|
||||
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package quota
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
"k8s.io/kubernetes/pkg/volume/util/quota/common"
|
||||
)
|
||||
|
||||
// Pod -> ID
|
||||
var podQuotaMap = make(map[string]common.QuotaID)
|
||||
|
||||
// Dir -> ID (for convenience)
|
||||
var dirQuotaMap = make(map[string]common.QuotaID)
|
||||
|
||||
// ID -> pod
|
||||
var quotaPodMap = make(map[common.QuotaID]string)
|
||||
|
||||
// Directory -> pod
|
||||
var dirPodMap = make(map[string]string)
|
||||
|
||||
// Backing device -> applier
|
||||
// This is *not* cleaned up; its size will be bounded.
|
||||
var devApplierMap = make(map[string]common.LinuxVolumeQuotaApplier)
|
||||
|
||||
// Directory -> applier
|
||||
var dirApplierMap = make(map[string]common.LinuxVolumeQuotaApplier)
|
||||
var dirApplierLock sync.RWMutex
|
||||
|
||||
// Pod -> refcount
|
||||
var podDirCountMap = make(map[string]int)
|
||||
|
||||
// ID -> size
|
||||
var quotaSizeMap = make(map[common.QuotaID]int64)
|
||||
var quotaLock sync.RWMutex
|
||||
|
||||
var supportsQuotasMap = make(map[string]bool)
|
||||
var supportsQuotasLock sync.RWMutex
|
||||
|
||||
// Directory -> backingDev
|
||||
var backingDevMap = make(map[string]string)
|
||||
var backingDevLock sync.RWMutex
|
||||
|
||||
var mountpointMap = make(map[string]string)
|
||||
var mountpointLock sync.RWMutex
|
||||
|
||||
var providers = []common.LinuxVolumeQuotaProvider{
|
||||
&common.VolumeProvider{},
|
||||
}
|
||||
|
||||
// Separate the innards for ease of testing
|
||||
func detectBackingDevInternal(mountpoint string, mounts string) (string, error) {
|
||||
file, err := os.Open(mounts)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer file.Close()
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
match := common.MountParseRegexp.FindStringSubmatch(scanner.Text())
|
||||
if match != nil {
|
||||
device := match[1]
|
||||
mount := match[2]
|
||||
if mount == mountpoint {
|
||||
return device, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("couldn't find backing device for %s", mountpoint)
|
||||
}
|
||||
|
||||
// detectBackingDev assumes that the mount point provided is valid
|
||||
func detectBackingDev(_ mount.Interface, mountpoint string) (string, error) {
|
||||
return detectBackingDevInternal(mountpoint, common.MountsFile)
|
||||
}
|
||||
|
||||
func clearBackingDev(path string) {
|
||||
backingDevLock.Lock()
|
||||
defer backingDevLock.Unlock()
|
||||
delete(backingDevMap, path)
|
||||
}
|
||||
|
||||
// Assumes that the path has been fully canonicalized
|
||||
// Breaking this up helps with testing
|
||||
func detectMountpointInternal(m mount.Interface, path string) (string, error) {
|
||||
for path != "" && path != "/" {
|
||||
// per pkg/util/mount/mount_linux this detects all but
|
||||
// a bind mount from one part of a mount to another.
|
||||
// For our purposes that's fine; we simply want the "true"
|
||||
// mount point
|
||||
//
|
||||
// IsNotMountPoint proved much more troublesome; it actually
|
||||
// scans the mounts, and when a lot of mount/unmount
|
||||
// activity takes place, it is not able to get a consistent
|
||||
// view of /proc/self/mounts, causing it to time out and
|
||||
// report incorrectly.
|
||||
isNotMount, err := m.IsLikelyNotMountPoint(path)
|
||||
if err != nil {
|
||||
return "/", err
|
||||
}
|
||||
if !isNotMount {
|
||||
return path, nil
|
||||
}
|
||||
path = filepath.Dir(path)
|
||||
}
|
||||
return "/", nil
|
||||
}
|
||||
|
||||
func detectMountpoint(m mount.Interface, path string) (string, error) {
|
||||
xpath, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
return "/", err
|
||||
}
|
||||
xpath, err = filepath.EvalSymlinks(xpath)
|
||||
if err != nil {
|
||||
return "/", err
|
||||
}
|
||||
if xpath, err = detectMountpointInternal(m, xpath); err == nil {
|
||||
return xpath, nil
|
||||
}
|
||||
return "/", err
|
||||
}
|
||||
|
||||
func clearMountpoint(path string) {
|
||||
mountpointLock.Lock()
|
||||
defer mountpointLock.Unlock()
|
||||
delete(mountpointMap, path)
|
||||
}
|
||||
|
||||
// getFSInfo Returns mountpoint and backing device
|
||||
// getFSInfo should cache the mountpoint and backing device for the
|
||||
// path.
|
||||
func getFSInfo(m mount.Interface, path string) (string, string, error) {
|
||||
mountpointLock.Lock()
|
||||
defer mountpointLock.Unlock()
|
||||
|
||||
backingDevLock.Lock()
|
||||
defer backingDevLock.Unlock()
|
||||
|
||||
var err error
|
||||
|
||||
mountpoint, okMountpoint := mountpointMap[path]
|
||||
if !okMountpoint {
|
||||
mountpoint, err = detectMountpoint(m, path)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("Cannot determine mountpoint for %s: %v", path, err)
|
||||
}
|
||||
}
|
||||
|
||||
backingDev, okBackingDev := backingDevMap[path]
|
||||
if !okBackingDev {
|
||||
backingDev, err = detectBackingDev(m, mountpoint)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("Cannot determine backing device for %s: %v", path, err)
|
||||
}
|
||||
}
|
||||
mountpointMap[path] = mountpoint
|
||||
backingDevMap[path] = backingDev
|
||||
return mountpoint, backingDev, nil
|
||||
}
|
||||
|
||||
func clearFSInfo(path string) {
|
||||
clearMountpoint(path)
|
||||
clearBackingDev(path)
|
||||
}
|
||||
|
||||
func getApplier(path string) common.LinuxVolumeQuotaApplier {
|
||||
dirApplierLock.Lock()
|
||||
defer dirApplierLock.Unlock()
|
||||
return dirApplierMap[path]
|
||||
}
|
||||
|
||||
func setApplier(path string, applier common.LinuxVolumeQuotaApplier) {
|
||||
dirApplierLock.Lock()
|
||||
defer dirApplierLock.Unlock()
|
||||
dirApplierMap[path] = applier
|
||||
}
|
||||
|
||||
func clearApplier(path string) {
|
||||
dirApplierLock.Lock()
|
||||
defer dirApplierLock.Unlock()
|
||||
delete(dirApplierMap, path)
|
||||
}
|
||||
|
||||
func setQuotaOnDir(path string, id common.QuotaID, bytes int64) error {
|
||||
return getApplier(path).SetQuotaOnDir(path, id, bytes)
|
||||
}
|
||||
|
||||
func getQuotaOnDir(m mount.Interface, path string) (common.QuotaID, error) {
|
||||
_, _, err := getFSInfo(m, path)
|
||||
if err != nil {
|
||||
return common.BadQuotaID, err
|
||||
}
|
||||
return getApplier(path).GetQuotaOnDir(path)
|
||||
}
|
||||
|
||||
func clearQuotaOnDir(m mount.Interface, path string) error {
|
||||
// Since we may be called without path being in the map,
|
||||
// we explicitly have to check in this case.
|
||||
klog.V(4).Infof("clearQuotaOnDir %s", path)
|
||||
supportsQuotas, err := SupportsQuotas(m, path)
|
||||
if !supportsQuotas {
|
||||
return nil
|
||||
}
|
||||
projid, err := getQuotaOnDir(m, path)
|
||||
if err == nil && projid != common.BadQuotaID {
|
||||
// This means that we have a quota on the directory but
|
||||
// we can't clear it. That's not good.
|
||||
err = setQuotaOnDir(path, projid, 0)
|
||||
if err != nil {
|
||||
klog.V(3).Infof("Attempt to clear quota failed: %v", err)
|
||||
}
|
||||
// Even if clearing the quota failed, we still need to
|
||||
// try to remove the project ID, or that may be left dangling.
|
||||
err1 := removeProjectID(path, projid)
|
||||
if err1 != nil {
|
||||
klog.V(3).Infof("Attempt to remove quota ID from system files failed: %v", err1)
|
||||
}
|
||||
clearFSInfo(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err1
|
||||
}
|
||||
// If we couldn't get a quota, that's fine -- there may
|
||||
// never have been one, and we have no way to know otherwise
|
||||
klog.V(3).Infof("clearQuotaOnDir fails %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SupportsQuotas -- Does the path support quotas
|
||||
// Cache the applier for paths that support quotas. For paths that don't,
|
||||
// don't cache the result because nothing will clean it up.
|
||||
// However, do cache the device->applier map; the number of devices
|
||||
// is bounded.
|
||||
func SupportsQuotas(m mount.Interface, path string) (bool, error) {
|
||||
if !enabledQuotasForMonitoring() {
|
||||
klog.V(3).Info("SupportsQuotas called, but quotas disabled")
|
||||
return false, nil
|
||||
}
|
||||
supportsQuotasLock.Lock()
|
||||
defer supportsQuotasLock.Unlock()
|
||||
if supportsQuotas, ok := supportsQuotasMap[path]; ok {
|
||||
return supportsQuotas, nil
|
||||
}
|
||||
mount, dev, err := getFSInfo(m, path)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// Do we know about this device?
|
||||
applier, ok := devApplierMap[mount]
|
||||
if !ok {
|
||||
for _, provider := range providers {
|
||||
if applier = provider.GetQuotaApplier(mount, dev); applier != nil {
|
||||
devApplierMap[mount] = applier
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if applier != nil {
|
||||
supportsQuotasMap[path] = true
|
||||
setApplier(path, applier)
|
||||
return true, nil
|
||||
}
|
||||
delete(backingDevMap, path)
|
||||
delete(mountpointMap, path)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// AssignQuota -- assign a quota to the specified directory.
|
||||
// AssignQuota chooses the quota ID based on the pod UID and path.
|
||||
// If the pod UID is identical to another one known, it may (but presently
|
||||
// doesn't) choose the same quota ID as other volumes in the pod.
|
||||
func AssignQuota(m mount.Interface, path string, poduid string, bytes *resource.Quantity) error {
|
||||
if bytes == nil {
|
||||
return fmt.Errorf("Attempting to assign null quota to %s", path)
|
||||
}
|
||||
ibytes := bytes.Value()
|
||||
if ok, err := SupportsQuotas(m, path); !ok {
|
||||
return fmt.Errorf("Quotas not supported on %s: %v", path, err)
|
||||
}
|
||||
quotaLock.Lock()
|
||||
defer quotaLock.Unlock()
|
||||
// Current policy is to set individual quotas on each volumes.
|
||||
// If we decide later that we want to assign one quota for all
|
||||
// volumes in a pod, we can simply remove this line of code.
|
||||
// If and when we decide permanently that we're going to adop
|
||||
// one quota per volume, we can rip all of the pod code out.
|
||||
poduid = string(uuid.NewUUID())
|
||||
if pod, ok := dirPodMap[path]; ok && pod != poduid {
|
||||
return fmt.Errorf("Requesting quota on existing directory %s but different pod %s %s", path, pod, poduid)
|
||||
}
|
||||
oid, ok := podQuotaMap[poduid]
|
||||
if ok {
|
||||
if quotaSizeMap[oid] != ibytes {
|
||||
return fmt.Errorf("Requesting quota of different size: old %v new %v", quotaSizeMap[oid], bytes)
|
||||
}
|
||||
} else {
|
||||
oid = common.BadQuotaID
|
||||
}
|
||||
id, err := createProjectID(path, oid)
|
||||
if err == nil {
|
||||
if oid != common.BadQuotaID && oid != id {
|
||||
return fmt.Errorf("Attempt to reassign quota %v to %v", oid, id)
|
||||
}
|
||||
// When enforcing quotas are enabled, we'll condition this
|
||||
// on their being disabled also.
|
||||
if ibytes > 0 {
|
||||
ibytes = -1
|
||||
}
|
||||
if err = setQuotaOnDir(path, id, ibytes); err == nil {
|
||||
quotaPodMap[id] = poduid
|
||||
quotaSizeMap[id] = ibytes
|
||||
podQuotaMap[poduid] = id
|
||||
dirQuotaMap[path] = id
|
||||
dirPodMap[path] = poduid
|
||||
podDirCountMap[poduid]++
|
||||
klog.V(4).Infof("Assigning quota ID %d (%d) to %s", id, ibytes, path)
|
||||
return nil
|
||||
}
|
||||
removeProjectID(path, id)
|
||||
}
|
||||
return fmt.Errorf("Assign quota FAILED %v", err)
|
||||
}
|
||||
|
||||
// GetConsumption -- retrieve the consumption (in bytes) of the directory
|
||||
func GetConsumption(path string) (*resource.Quantity, error) {
|
||||
// Note that we actually need to hold the lock at least through
|
||||
// running the quota command, so it can't get recycled behind our back
|
||||
quotaLock.Lock()
|
||||
defer quotaLock.Unlock()
|
||||
applier := getApplier(path)
|
||||
// No applier means directory is not under quota management
|
||||
if applier == nil {
|
||||
return nil, nil
|
||||
}
|
||||
ibytes, err := applier.GetConsumption(path, dirQuotaMap[path])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resource.NewQuantity(ibytes, resource.DecimalSI), nil
|
||||
}
|
||||
|
||||
// GetInodes -- retrieve the number of inodes in use under the directory
|
||||
func GetInodes(path string) (*resource.Quantity, error) {
|
||||
// Note that we actually need to hold the lock at least through
|
||||
// running the quota command, so it can't get recycled behind our back
|
||||
quotaLock.Lock()
|
||||
defer quotaLock.Unlock()
|
||||
applier := getApplier(path)
|
||||
// No applier means directory is not under quota management
|
||||
if applier == nil {
|
||||
return nil, nil
|
||||
}
|
||||
inodes, err := applier.GetInodes(path, dirQuotaMap[path])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resource.NewQuantity(inodes, resource.DecimalSI), nil
|
||||
}
|
||||
|
||||
// ClearQuota -- remove the quota assigned to a directory
|
||||
func ClearQuota(m mount.Interface, path string) error {
|
||||
klog.V(3).Infof("ClearQuota %s", path)
|
||||
if !enabledQuotasForMonitoring() {
|
||||
return fmt.Errorf("ClearQuota called, but quotas disabled")
|
||||
}
|
||||
quotaLock.Lock()
|
||||
defer quotaLock.Unlock()
|
||||
poduid, ok := dirPodMap[path]
|
||||
if !ok {
|
||||
// Nothing in the map either means that there was no
|
||||
// quota to begin with or that we're clearing a
|
||||
// stale directory, so if we find a quota, just remove it.
|
||||
// The process of clearing the quota requires that an applier
|
||||
// be found, which needs to be cleaned up.
|
||||
defer delete(supportsQuotasMap, path)
|
||||
defer clearApplier(path)
|
||||
return clearQuotaOnDir(m, path)
|
||||
}
|
||||
_, ok = podQuotaMap[poduid]
|
||||
if !ok {
|
||||
return fmt.Errorf("ClearQuota: No quota available for %s", path)
|
||||
}
|
||||
var err error
|
||||
projid, err := getQuotaOnDir(m, path)
|
||||
if projid != dirQuotaMap[path] {
|
||||
return fmt.Errorf("Expected quota ID %v on dir %s does not match actual %v", dirQuotaMap[path], path, projid)
|
||||
}
|
||||
count, ok := podDirCountMap[poduid]
|
||||
if count <= 1 || !ok {
|
||||
err = clearQuotaOnDir(m, path)
|
||||
// This error should be noted; we still need to clean up
|
||||
// and otherwise handle in the same way.
|
||||
if err != nil {
|
||||
klog.V(3).Infof("Unable to clear quota %v %s: %v", dirQuotaMap[path], path, err)
|
||||
}
|
||||
delete(quotaSizeMap, podQuotaMap[poduid])
|
||||
delete(quotaPodMap, podQuotaMap[poduid])
|
||||
delete(podDirCountMap, poduid)
|
||||
delete(podQuotaMap, poduid)
|
||||
} else {
|
||||
err = removeProjectID(path, projid)
|
||||
podDirCountMap[poduid]--
|
||||
klog.V(4).Infof("Not clearing quota for pod %s; still %v dirs outstanding", poduid, podDirCountMap[poduid])
|
||||
}
|
||||
delete(dirPodMap, path)
|
||||
delete(dirQuotaMap, path)
|
||||
delete(supportsQuotasMap, path)
|
||||
clearApplier(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to clear quota for %s: %v", path, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
55
vendor/k8s.io/kubernetes/pkg/volume/util/quota/quota_unsupported.go
generated
vendored
Normal file
55
vendor/k8s.io/kubernetes/pkg/volume/util/quota/quota_unsupported.go
generated
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
// +build !linux
|
||||
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package quota
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
)
|
||||
|
||||
// Dummy quota implementation for systems that do not implement support
|
||||
// for volume quotas
|
||||
|
||||
var errNotImplemented = errors.New("not implemented")
|
||||
|
||||
// SupportsQuotas -- dummy implementation
|
||||
func SupportsQuotas(_ mount.Interface, _ string) (bool, error) {
|
||||
return false, errNotImplemented
|
||||
}
|
||||
|
||||
// AssignQuota -- dummy implementation
|
||||
func AssignQuota(_ mount.Interface, _ string, _ string, _ *resource.Quantity) error {
|
||||
return errNotImplemented
|
||||
}
|
||||
|
||||
// GetConsumption -- dummy implementation
|
||||
func GetConsumption(_ string) (*resource.Quantity, error) {
|
||||
return nil, errNotImplemented
|
||||
}
|
||||
|
||||
// GetInodes -- dummy implementation
|
||||
func GetInodes(_ string) (*resource.Quantity, error) {
|
||||
return nil, errNotImplemented
|
||||
}
|
||||
|
||||
// ClearQuota -- dummy implementation
|
||||
func ClearQuota(_ mount.Interface, _ string) error {
|
||||
return errNotImplemented
|
||||
}
|
||||
10
vendor/k8s.io/kubernetes/pkg/volume/util/recyclerclient/recycler_client.go
generated
vendored
10
vendor/k8s.io/kubernetes/pkg/volume/util/recyclerclient/recycler_client.go
generated
vendored
|
|
@ -29,6 +29,7 @@ import (
|
|||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
// RecycleEventRecorder is a func that defines how to record RecycleEvent.
|
||||
type RecycleEventRecorder func(eventtype, message string)
|
||||
|
||||
// RecycleVolumeByWatchingPodUntilCompletion is intended for use with volume
|
||||
|
|
@ -127,9 +128,8 @@ func waitForPod(pod *v1.Pod, recyclerClient recyclerClient, podCh <-chan watch.E
|
|||
if pod.Status.Phase == v1.PodFailed {
|
||||
if pod.Status.Message != "" {
|
||||
return fmt.Errorf(pod.Status.Message)
|
||||
} else {
|
||||
return fmt.Errorf("pod failed, pod.Status.Message unknown.")
|
||||
}
|
||||
return fmt.Errorf("pod failed, pod.Status.Message unknown")
|
||||
}
|
||||
|
||||
case watch.Deleted:
|
||||
|
|
@ -238,9 +238,8 @@ func (c *realRecyclerClient) WatchPod(name, namespace string, stopChannel chan s
|
|||
case eventEvent, ok := <-eventWatch.ResultChan():
|
||||
if !ok {
|
||||
return
|
||||
} else {
|
||||
eventCh <- eventEvent
|
||||
}
|
||||
eventCh <- eventEvent
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
|
@ -256,9 +255,8 @@ func (c *realRecyclerClient) WatchPod(name, namespace string, stopChannel chan s
|
|||
case podEvent, ok := <-podWatch.ResultChan():
|
||||
if !ok {
|
||||
return
|
||||
} else {
|
||||
eventCh <- podEvent
|
||||
}
|
||||
eventCh <- podEvent
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
|
|
|||
1
vendor/k8s.io/kubernetes/pkg/volume/util/subpath/BUILD
generated
vendored
1
vendor/k8s.io/kubernetes/pkg/volume/util/subpath/BUILD
generated
vendored
|
|
@ -74,6 +74,7 @@ go_test(
|
|||
deps = select({
|
||||
"@io_bazel_rules_go//go/platform:linux": [
|
||||
"//pkg/util/mount:go_default_library",
|
||||
"//pkg/volume/util/nsenter:go_default_library",
|
||||
"//vendor/golang.org/x/sys/unix:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
"//vendor/k8s.io/utils/nsenter:go_default_library",
|
||||
|
|
|
|||
4
vendor/k8s.io/kubernetes/pkg/volume/util/subpath/subpath_linux.go
generated
vendored
4
vendor/k8s.io/kubernetes/pkg/volume/util/subpath/subpath_linux.go
generated
vendored
|
|
@ -101,7 +101,7 @@ func safeOpenSubPath(mounter mount.Interface, subpath Subpath) (int, error) {
|
|||
func prepareSubpathTarget(mounter mount.Interface, subpath Subpath) (bool, string, error) {
|
||||
// Early check for already bind-mounted subpath.
|
||||
bindPathTarget := getSubpathBindTarget(subpath)
|
||||
notMount, err := mounter.IsNotMountPoint(bindPathTarget)
|
||||
notMount, err := mount.IsNotMountPoint(mounter, bindPathTarget)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return false, "", fmt.Errorf("error checking path %s for mount: %s", bindPathTarget, err)
|
||||
|
|
@ -398,7 +398,7 @@ func doSafeMakeDir(pathname string, base string, perm os.FileMode) error {
|
|||
return fmt.Errorf("cannot create directory %s: %s", currentPath, err)
|
||||
}
|
||||
// Dive into the created directory
|
||||
childFD, err := syscall.Openat(parentFD, dir, nofollowFlags, 0)
|
||||
childFD, err = syscall.Openat(parentFD, dir, nofollowFlags, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot open %s: %s", currentPath, err)
|
||||
}
|
||||
|
|
|
|||
11
vendor/k8s.io/kubernetes/pkg/volume/volume.go
generated
vendored
11
vendor/k8s.io/kubernetes/pkg/volume/volume.go
generated
vendored
|
|
@ -101,6 +101,13 @@ type Attributes struct {
|
|||
SupportsSELinux bool
|
||||
}
|
||||
|
||||
// MounterArgs provides more easily extensible arguments to Mounter
|
||||
type MounterArgs struct {
|
||||
FsGroup *int64
|
||||
DesiredSize *resource.Quantity
|
||||
PodUID string
|
||||
}
|
||||
|
||||
// Mounter interface provides methods to set up/mount the volume.
|
||||
type Mounter interface {
|
||||
// Uses Interface to provide the path for Docker binds.
|
||||
|
|
@ -122,14 +129,14 @@ type Mounter interface {
|
|||
// content should be owned by 'fsGroup' so that it can be
|
||||
// accessed by the pod. This may be called more than once, so
|
||||
// implementations must be idempotent.
|
||||
SetUp(fsGroup *int64) error
|
||||
SetUp(mounterArgs MounterArgs) error
|
||||
// SetUpAt prepares and mounts/unpacks the volume to the
|
||||
// specified directory path, which may or may not exist yet.
|
||||
// The mount point and its content should be owned by
|
||||
// 'fsGroup' so that it can be accessed by the pod. This may
|
||||
// be called more than once, so implementations must be
|
||||
// idempotent.
|
||||
SetUpAt(dir string, fsGroup *int64) error
|
||||
SetUpAt(dir string, mounterArgs MounterArgs) error
|
||||
// GetAttributes returns the attributes of the mounter.
|
||||
// This function is called after SetUp()/SetUpAt().
|
||||
GetAttributes() Attributes
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue