Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
f8661d62
Commit
f8661d62
authored
Nov 19, 2018
by
Robert Krawitz
Committed by
Robert Krawitz
May 29, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use xfs_quota command to apply quotas
parent
448e0c44
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
168 additions
and
503 deletions
+168
-503
kube_features.go
pkg/features/kube_features.go
+2
-2
BUILD
pkg/kubelet/eviction/BUILD
+1
-0
helpers.go
pkg/kubelet/eviction/helpers.go
+2
-17
BUILD
pkg/kubelet/volumemanager/cache/BUILD
+1
-1
desired_state_of_world.go
pkg/kubelet/volumemanager/cache/desired_state_of_world.go
+8
-11
empty_dir.go
pkg/volume/emptydir/empty_dir.go
+10
-7
fs.go
pkg/volume/util/fs/fs.go
+12
-6
BUILD
pkg/volume/util/operationexecutor/BUILD
+1
-0
operation_executor.go
pkg/volume/util/operationexecutor/operation_executor.go
+2
-1
BUILD
pkg/volume/util/quota/BUILD
+3
-4
BUILD
pkg/volume/util/quota/common/BUILD
+0
-2
quota_linux_common.go
pkg/volume/util/quota/common/quota_linux_common.go
+30
-2
quota_linux_common_impl.go
pkg/volume/util/quota/common/quota_linux_common_impl.go
+0
-0
BUILD
pkg/volume/util/quota/extfs/BUILD
+0
-31
quota_extfs.go
pkg/volume/util/quota/extfs/quota_extfs.go
+0
-153
project.go
pkg/volume/util/quota/project.go
+15
-11
quota.go
pkg/volume/util/quota/quota.go
+5
-4
quota_linux.go
pkg/volume/util/quota/quota_linux.go
+54
-46
quota_linux_test.go
pkg/volume/util/quota/quota_linux_test.go
+7
-15
quota_unsupported.go
pkg/volume/util/quota/quota_unsupported.go
+6
-5
BUILD
pkg/volume/util/quota/xfs/BUILD
+0
-31
quota_xfs.go
pkg/volume/util/quota/xfs/quota_xfs.go
+0
-153
util.go
pkg/volume/util/util.go
+8
-0
volume.go
pkg/volume/volume.go
+1
-1
No files found.
pkg/features/kube_features.go
View file @
f8661d62
...
@@ -446,7 +446,7 @@ const (
...
@@ -446,7 +446,7 @@ const (
//
//
// Allow use of filesystems for ephemeral storage monitoring.
// Allow use of filesystems for ephemeral storage monitoring.
// Only applies if LocalStorageCapacityIsolation is set.
// Only applies if LocalStorageCapacityIsolation is set.
FSQuotaForLSCIMonitoring
=
"FSQuotaForLSCI
Monitoring"
LocalStorageCapacityIsolationFSQuotaMonitoring
featuregate
.
Feature
=
"LocalStorageCapacityIsolationFSQuota
Monitoring"
)
)
func
init
()
{
func
init
()
{
...
@@ -521,7 +521,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
...
@@ -521,7 +521,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
TTLAfterFinished
:
{
Default
:
false
,
PreRelease
:
featuregate
.
Alpha
},
TTLAfterFinished
:
{
Default
:
false
,
PreRelease
:
featuregate
.
Alpha
},
KubeletPodResources
:
{
Default
:
false
,
PreRelease
:
featuregate
.
Alpha
},
KubeletPodResources
:
{
Default
:
false
,
PreRelease
:
featuregate
.
Alpha
},
WindowsGMSA
:
{
Default
:
false
,
PreRelease
:
featuregate
.
Alpha
},
WindowsGMSA
:
{
Default
:
false
,
PreRelease
:
featuregate
.
Alpha
},
FSQuotaForLSCIMonitoring
:
{
Default
:
false
,
PreRelease
:
utilfeatur
e
.
Alpha
},
LocalStorageCapacityIsolationFSQuotaMonitoring
:
{
Default
:
false
,
PreRelease
:
featuregat
e
.
Alpha
},
// inherited features from generic apiserver, relisted here to get a conflict if it is changed
// inherited features from generic apiserver, relisted here to get a conflict if it is changed
// unintentionally on either side:
// unintentionally on either side:
...
...
pkg/kubelet/eviction/BUILD
View file @
f8661d62
...
@@ -62,6 +62,7 @@ go_library(
...
@@ -62,6 +62,7 @@ go_library(
"//pkg/kubelet/util/format:go_default_library",
"//pkg/kubelet/util/format:go_default_library",
"//pkg/scheduler/api:go_default_library",
"//pkg/scheduler/api:go_default_library",
"//pkg/scheduler/util:go_default_library",
"//pkg/scheduler/util:go_default_library",
"//pkg/volume/util:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
...
...
pkg/kubelet/eviction/helpers.go
View file @
f8661d62
...
@@ -32,6 +32,7 @@ import (
...
@@ -32,6 +32,7 @@ import (
evictionapi
"k8s.io/kubernetes/pkg/kubelet/eviction/api"
evictionapi
"k8s.io/kubernetes/pkg/kubelet/eviction/api"
kubetypes
"k8s.io/kubernetes/pkg/kubelet/types"
kubetypes
"k8s.io/kubernetes/pkg/kubelet/types"
schedulerutils
"k8s.io/kubernetes/pkg/scheduler/util"
schedulerutils
"k8s.io/kubernetes/pkg/scheduler/util"
volumeutils
"k8s.io/kubernetes/pkg/volume/util"
)
)
const
(
const
(
...
@@ -395,27 +396,11 @@ func podDiskUsage(podStats statsapi.PodStats, pod *v1.Pod, statsToMeasure []fsSt
...
@@ -395,27 +396,11 @@ func podDiskUsage(podStats statsapi.PodStats, pod *v1.Pod, statsToMeasure []fsSt
},
nil
},
nil
}
}
func
internalIsLocalEphemeralVolume
(
pod
*
v1
.
Pod
,
volume
v1
.
Volume
)
bool
{
return
volume
.
GitRepo
!=
nil
||
(
volume
.
EmptyDir
!=
nil
&&
volume
.
EmptyDir
.
Medium
!=
v1
.
StorageMediumMemory
)
||
volume
.
ConfigMap
!=
nil
||
volume
.
DownwardAPI
!=
nil
}
// IsLocalEphemeralVolume determines whether a given volume name is ephemeral
func
IsLocalEphemeralVolume
(
pod
*
v1
.
Pod
,
volumeName
string
)
(
bool
,
error
)
{
for
_
,
volume
:=
range
pod
.
Spec
.
Volumes
{
if
volume
.
Name
==
volumeName
{
return
internalIsLocalEphemeralVolume
(
pod
,
volume
),
nil
}
}
return
false
,
fmt
.
Errorf
(
"Volume %s not found in pod %v"
,
volumeName
,
pod
)
}
// localEphemeralVolumeNames returns the set of ephemeral volumes for the pod that are local
// localEphemeralVolumeNames returns the set of ephemeral volumes for the pod that are local
func
localEphemeralVolumeNames
(
pod
*
v1
.
Pod
)
[]
string
{
func
localEphemeralVolumeNames
(
pod
*
v1
.
Pod
)
[]
string
{
result
:=
[]
string
{}
result
:=
[]
string
{}
for
_
,
volume
:=
range
pod
.
Spec
.
Volumes
{
for
_
,
volume
:=
range
pod
.
Spec
.
Volumes
{
if
internalIsLocalEphemeralVolume
(
pod
,
volume
)
{
if
volumeutils
.
IsLocalEphemeralVolume
(
volume
)
{
result
=
append
(
result
,
volume
.
Name
)
result
=
append
(
result
,
volume
.
Name
)
}
}
}
}
...
...
pkg/kubelet/volumemanager/cache/BUILD
View file @
f8661d62
...
@@ -16,12 +16,12 @@ go_library(
...
@@ -16,12 +16,12 @@ go_library(
deps = [
deps = [
"//pkg/api/v1/resource:go_default_library",
"//pkg/api/v1/resource:go_default_library",
"//pkg/features:go_default_library",
"//pkg/features:go_default_library",
"//pkg/kubelet/eviction:go_default_library",
"//pkg/volume:go_default_library",
"//pkg/volume:go_default_library",
"//pkg/volume/util:go_default_library",
"//pkg/volume/util:go_default_library",
"//pkg/volume/util/operationexecutor:go_default_library",
"//pkg/volume/util/operationexecutor:go_default_library",
"//pkg/volume/util/types:go_default_library",
"//pkg/volume/util/types:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
...
...
pkg/kubelet/volumemanager/cache/desired_state_of_world.go
View file @
f8661d62
...
@@ -25,8 +25,8 @@ import (
...
@@ -25,8 +25,8 @@ import (
"sync"
"sync"
"k8s.io/api/core/v1"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
apiv1resource
"k8s.io/kubernetes/pkg/api/v1/resource"
apiv1resource
"k8s.io/kubernetes/pkg/api/v1/resource"
limits
"k8s.io/kubernetes/pkg/kubelet/eviction"
"k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/util"
"k8s.io/kubernetes/pkg/volume/util"
"k8s.io/kubernetes/pkg/volume/util/operationexecutor"
"k8s.io/kubernetes/pkg/volume/util/operationexecutor"
...
@@ -165,7 +165,7 @@ type volumeToMount struct {
...
@@ -165,7 +165,7 @@ type volumeToMount struct {
// desiredSizeLimit indicates the desired upper bound on the size of the volume
// desiredSizeLimit indicates the desired upper bound on the size of the volume
// (if so implemented)
// (if so implemented)
desiredSizeLimit
int64
desiredSizeLimit
*
resource
.
Quantity
}
}
// The pod object represents a pod that references the underlying volume and
// The pod object represents a pod that references the underlying volume and
...
@@ -232,15 +232,12 @@ func (dsw *desiredStateOfWorld) AddPodToVolume(
...
@@ -232,15 +232,12 @@ func (dsw *desiredStateOfWorld) AddPodToVolume(
}
}
if
_
,
volumeExists
:=
dsw
.
volumesToMount
[
volumeName
];
!
volumeExists
{
if
_
,
volumeExists
:=
dsw
.
volumesToMount
[
volumeName
];
!
volumeExists
{
var
sizeLimit
int64
var
sizeLimit
*
resource
.
Quantity
sizeLimit
=
0
if
volumeSpec
.
Volume
!=
nil
{
isLocal
,
_
:=
limits
.
IsLocalEphemeralVolume
(
pod
,
volumeSpec
.
Name
())
if
util
.
IsLocalEphemeralVolume
(
*
volumeSpec
.
Volume
)
{
if
isLocal
{
_
,
podLimits
:=
apiv1resource
.
PodRequestsAndLimits
(
pod
)
_
,
podLimits
:=
apiv1resource
.
PodRequestsAndLimits
(
pod
)
ephemeralStorageLimit
:=
podLimits
[
v1
.
ResourceEphemeralStorage
]
ephemeralStorageLimit
:=
podLimits
[
v1
.
ResourceEphemeralStorage
]
sizeLimit
=
resource
.
NewQuantity
(
ephemeralStorageLimit
.
Value
(),
resource
.
BinarySI
)
sizeLimit
=
ephemeralStorageLimit
.
Value
()
if
sizeLimit
==
0
{
sizeLimit
=
-
1
}
}
}
}
dsw
.
volumesToMount
[
volumeName
]
=
volumeToMount
{
dsw
.
volumesToMount
[
volumeName
]
=
volumeToMount
{
...
...
pkg/volume/emptydir/empty_dir.go
View file @
f8661d62
...
@@ -236,17 +236,20 @@ func (ed *emptyDir) SetUpAt(dir string, mounterArgs volume.MounterArgs) error {
...
@@ -236,17 +236,20 @@ func (ed *emptyDir) SetUpAt(dir string, mounterArgs volume.MounterArgs) error {
if
err
==
nil
{
if
err
==
nil
{
volumeutil
.
SetReady
(
ed
.
getMetaDir
())
volumeutil
.
SetReady
(
ed
.
getMetaDir
())
}
}
if
mounterArgs
.
DesiredSize
!=
0
{
if
mounterArgs
.
DesiredSize
!=
nil
{
if
hasQuotas
,
_
:=
quota
.
SupportsQuotas
(
ed
.
mounter
,
dir
);
hasQuotas
{
hasQuotas
,
err
:=
quota
.
SupportsQuotas
(
ed
.
mounter
,
dir
)
klog
.
V
(
3
)
.
Infof
(
"emptydir trying to assign quota"
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"Unable to check for quota support on %s: %s"
,
dir
,
err
.
Error
())
}
if
hasQuotas
{
klog
.
V
(
4
)
.
Infof
(
"emptydir trying to assign quota %v on %s"
,
mounterArgs
.
DesiredSize
,
dir
)
err
:=
quota
.
AssignQuota
(
ed
.
mounter
,
dir
,
mounterArgs
.
PodUID
,
mounterArgs
.
DesiredSize
)
err
:=
quota
.
AssignQuota
(
ed
.
mounter
,
dir
,
mounterArgs
.
PodUID
,
mounterArgs
.
DesiredSize
)
if
err
!=
nil
{
if
err
!=
nil
{
klog
.
V
(
3
)
.
Infof
(
"Set quota failed %v"
,
err
)
return
fmt
.
Errorf
(
"Set quota on %s failed %s"
,
dir
,
err
.
Error
()
)
}
}
}
}
}
}
return
nil
return
err
}
}
// setupTmpfs creates a tmpfs mount at the specified directory.
// setupTmpfs creates a tmpfs mount at the specified directory.
...
@@ -411,7 +414,7 @@ func (ed *emptyDir) teardownDefault(dir string) error {
...
@@ -411,7 +414,7 @@ func (ed *emptyDir) teardownDefault(dir string) error {
// Remove any quota
// Remove any quota
err
:=
quota
.
ClearQuota
(
ed
.
mounter
,
dir
)
err
:=
quota
.
ClearQuota
(
ed
.
mounter
,
dir
)
if
err
!=
nil
{
if
err
!=
nil
{
klog
.
V
(
3
)
.
Infof
(
"
Failed to clear quota on %s: %v"
,
dir
,
err
)
klog
.
Warningf
(
"Warning:
Failed to clear quota on %s: %v"
,
dir
,
err
)
}
}
// Renaming the directory is not required anymore because the operation executor
// Renaming the directory is not required anymore because the operation executor
// now handles duplicate operations on the same volume
// now handles duplicate operations on the same volume
...
...
pkg/volume/util/fs/fs.go
View file @
f8661d62
...
@@ -58,11 +58,13 @@ func FsInfo(path string) (int64, int64, int64, int64, int64, int64, error) {
...
@@ -58,11 +58,13 @@ func FsInfo(path string) (int64, int64, int64, int64, int64, int64, error) {
// DiskUsage gets disk usage of specified path.
// DiskUsage gets disk usage of specified path.
func
DiskUsage
(
path
string
)
(
*
resource
.
Quantity
,
error
)
{
func
DiskUsage
(
path
string
)
(
*
resource
.
Quantity
,
error
)
{
// First check whether the quota system knows about this 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.
data
,
err
:=
quota
.
GetConsumption
(
path
)
data
,
err
:=
quota
.
GetConsumption
(
path
)
if
err
=
=
nil
{
if
data
!
=
nil
{
var
q
resource
.
Quantity
return
data
,
nil
q
.
Set
(
data
)
}
else
if
err
!=
nil
{
return
&
q
,
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 the same niceness level as cadvisor.fs does when running du
// Uses -B 1 to always scale to a blocksize of 1 byte
// Uses -B 1 to always scale to a blocksize of 1 byte
...
@@ -85,9 +87,13 @@ func Find(path string) (int64, error) {
...
@@ -85,9 +87,13 @@ func Find(path string) (int64, error) {
return
0
,
fmt
.
Errorf
(
"invalid directory"
)
return
0
,
fmt
.
Errorf
(
"invalid directory"
)
}
}
// First check whether the quota system knows about this 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
)
inodes
,
err
:=
quota
.
GetInodes
(
path
)
if
err
==
nil
{
if
inodes
!=
nil
{
return
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
counter
byteCounter
var
stderr
bytes
.
Buffer
var
stderr
bytes
.
Buffer
...
...
pkg/volume/util/operationexecutor/BUILD
View file @
f8661d62
...
@@ -25,6 +25,7 @@ go_library(
...
@@ -25,6 +25,7 @@ go_library(
"//pkg/volume/util/volumepathhandler:go_default_library",
"//pkg/volume/util/volumepathhandler:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
...
...
pkg/volume/util/operationexecutor/operation_executor.go
View file @
f8661d62
...
@@ -27,6 +27,7 @@ import (
...
@@ -27,6 +27,7 @@ import (
"k8s.io/klog"
"k8s.io/klog"
"k8s.io/api/core/v1"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume"
...
@@ -349,7 +350,7 @@ type VolumeToMount struct {
...
@@ -349,7 +350,7 @@ type VolumeToMount struct {
// DesiredSizeLimit indicates the desired upper bound on the size of the volume
// DesiredSizeLimit indicates the desired upper bound on the size of the volume
// (if so implemented)
// (if so implemented)
DesiredSizeLimit
int64
DesiredSizeLimit
*
resource
.
Quantity
}
}
// GenerateMsgDetailed returns detailed msgs for volumes to mount
// GenerateMsgDetailed returns detailed msgs for volumes to mount
...
...
pkg/volume/util/quota/BUILD
View file @
f8661d62
...
@@ -13,12 +13,11 @@ go_library(
...
@@ -13,12 +13,11 @@ go_library(
deps = [
deps = [
"//pkg/features:go_default_library",
"//pkg/features:go_default_library",
"//pkg/util/mount: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",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
] + select({
] + select({
"@io_bazel_rules_go//go/platform:linux": [
"@io_bazel_rules_go//go/platform:linux": [
"//pkg/volume/util/quota/common:go_default_library",
"//pkg/volume/util/quota/common:go_default_library",
"//pkg/volume/util/quota/extfs:go_default_library",
"//pkg/volume/util/quota/xfs:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
...
@@ -36,7 +35,9 @@ go_test(
...
@@ -36,7 +35,9 @@ go_test(
"//pkg/features:go_default_library",
"//pkg/features:go_default_library",
"//pkg/util/mount:go_default_library",
"//pkg/util/mount:go_default_library",
"//pkg/volume/util/quota/common: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/apiserver/pkg/util/feature:go_default_library",
"//staging/src/k8s.io/component-base/featuregate/testing:go_default_library",
],
],
"//conditions:default": [],
"//conditions:default": [],
}),
}),
...
@@ -54,8 +55,6 @@ filegroup(
...
@@ -54,8 +55,6 @@ filegroup(
srcs = [
srcs = [
":package-srcs",
":package-srcs",
"//pkg/volume/util/quota/common:all-srcs",
"//pkg/volume/util/quota/common:all-srcs",
"//pkg/volume/util/quota/extfs:all-srcs",
"//pkg/volume/util/quota/xfs:all-srcs",
],
],
tags = ["automanaged"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
visibility = ["//visibility:public"],
...
...
pkg/volume/util/quota/common/BUILD
View file @
f8661d62
...
@@ -6,12 +6,10 @@ go_library(
...
@@ -6,12 +6,10 @@ go_library(
"quota_linux_common.go",
"quota_linux_common.go",
"quota_linux_common_impl.go",
"quota_linux_common_impl.go",
],
],
cgo = True,
importpath = "k8s.io/kubernetes/pkg/volume/util/quota/common",
importpath = "k8s.io/kubernetes/pkg/volume/util/quota/common",
visibility = ["//visibility:public"],
visibility = ["//visibility:public"],
deps = select({
deps = select({
"@io_bazel_rules_go//go/platform:linux": [
"@io_bazel_rules_go//go/platform:linux": [
"//vendor/golang.org/x/sys/unix:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
],
],
"//conditions:default": [],
"//conditions:default": [],
...
...
pkg/volume/util/quota/common/quota_linux_common.go
View file @
f8661d62
...
@@ -18,18 +18,46 @@ limitations under the License.
...
@@ -18,18 +18,46 @@ limitations under the License.
package
common
package
common
// QuotaID -- generic quota identifier
import
(
"regexp"
)
// QuotaID is generic quota identifier.
// Data type based on quotactl(2).
type
QuotaID
int32
type
QuotaID
int32
const
(
const
(
// UnknownQuotaID -- cannot determine whether a quota is in force
UnknownQuotaID
QuotaID
=
-
1
// BadQuotaID -- Invalid quota
// BadQuotaID -- Invalid quota
BadQuotaID
QuotaID
=
0
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.
// FirstQuota is the quota ID we start with.
// XXXXXXX Need a better way of doing this...
// XXXXXXX Need a better way of doing this...
var
FirstQuota
QuotaID
=
1048577
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
// LinuxVolumeQuotaProvider returns an appropriate quota applier
// object if we can support quotas on this device
// object if we can support quotas on this device
type
LinuxVolumeQuotaProvider
interface
{
type
LinuxVolumeQuotaProvider
interface
{
...
@@ -59,7 +87,7 @@ type LinuxVolumeQuotaApplier interface {
...
@@ -59,7 +87,7 @@ type LinuxVolumeQuotaApplier interface {
// Return value of false with no error means that the ID is not
// 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
// in use; true means that it is already in use. An error
// return means that any quota ID will fail.
// return means that any quota ID will fail.
QuotaIDIsInUse
(
path
string
,
id
QuotaID
)
(
bool
,
error
)
QuotaIDIsInUse
(
id
QuotaID
)
(
bool
,
error
)
// GetConsumption returns the consumption (in bytes) of the
// GetConsumption returns the consumption (in bytes) of the
// directory, determined by the implementation's quota-based
// directory, determined by the implementation's quota-based
...
...
pkg/volume/util/quota/common/quota_linux_common_impl.go
View file @
f8661d62
This diff is collapsed.
Click to expand it.
pkg/volume/util/quota/extfs/BUILD
deleted
100644 → 0
View file @
448e0c44
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["quota_extfs.go"],
cgo = True,
importpath = "k8s.io/kubernetes/pkg/volume/util/quota/extfs",
visibility = ["//visibility:public"],
deps = select({
"@io_bazel_rules_go//go/platform:linux": [
"//pkg/volume/util/quota/common:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",
"//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"],
)
pkg/volume/util/quota/extfs/quota_extfs.go
deleted
100644 → 0
View file @
448e0c44
// +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
extfs
/*
#include <stdlib.h>
#include <dirent.h>
#include <linux/fs.h>
#include <linux/quota.h>
#include <errno.h>
#ifndef PRJQUOTA
#define PRJQUOTA 2
#endif
#ifndef Q_SETPQUOTA
#define Q_SETPQUOTA (unsigned) QCMD(Q_SETQUOTA, PRJQUOTA)
#endif
#ifndef Q_GETPQUOTA
#define Q_GETPQUOTA (unsigned) QCMD(Q_GETQUOTA, PRJQUOTA)
#endif
*/
import
"C"
import
(
"fmt"
"syscall"
"unsafe"
"golang.org/x/sys/unix"
"k8s.io/klog"
"k8s.io/kubernetes/pkg/volume/util/quota/common"
)
// ext4fs empirically has a maximum quota size of 2^48 - 1 1KiB blocks (256 petabytes)
const
(
linuxExtfsMagic
=
0xef53
quotaBsize
=
1024
// extfs specific
bitsPerWord
=
32
<<
(
^
uint
(
0
)
>>
63
)
// either 32 or 64
maxQuota
int64
=
(
1
<<
(
bitsPerWord
-
1
)
-
1
)
&
(
1
<<
58
-
1
)
// either 1<<31 - 1 or 1<<58 - 1
)
// VolumeProvider supplies a quota applier to the generic code.
type
VolumeProvider
struct
{
}
// GetQuotaApplier -- does this backing device support quotas that
// can be applied to directories?
func
(
*
VolumeProvider
)
GetQuotaApplier
(
mountpoint
string
,
backingDev
string
)
common
.
LinuxVolumeQuotaApplier
{
if
common
.
IsFilesystemOfType
(
mountpoint
,
backingDev
,
linuxExtfsMagic
)
{
return
extfsVolumeQuota
{
backingDev
}
}
return
nil
}
type
extfsVolumeQuota
struct
{
backingDev
string
}
// GetQuotaOnDir -- get the quota ID that applies to this directory.
func
(
v
extfsVolumeQuota
)
GetQuotaOnDir
(
path
string
)
(
common
.
QuotaID
,
error
)
{
return
common
.
GetQuotaOnDir
(
path
)
}
// SetQuotaOnDir -- apply the specified quota to the directory. If
// bytes is not greater than zero, the quota should be applied in a
// way that is non-enforcing (either explicitly so or by setting a
// quota larger than anything the user may possibly create)
func
(
v
extfsVolumeQuota
)
SetQuotaOnDir
(
path
string
,
id
common
.
QuotaID
,
bytes
int64
)
error
{
klog
.
V
(
3
)
.
Infof
(
"extfsSetQuotaOn %s ID %v bytes %v"
,
path
,
id
,
bytes
)
if
bytes
<
0
||
bytes
>
maxQuota
{
bytes
=
maxQuota
}
var
d
C
.
struct_if_dqblk
d
.
dqb_bhardlimit
=
C
.
__u64
(
bytes
/
quotaBsize
)
d
.
dqb_bsoftlimit
=
d
.
dqb_bhardlimit
d
.
dqb_ihardlimit
=
0
d
.
dqb_isoftlimit
=
0
d
.
dqb_valid
=
C
.
QIF_LIMITS
var
cs
=
C
.
CString
(
v
.
backingDev
)
defer
C
.
free
(
unsafe
.
Pointer
(
cs
))
_
,
_
,
errno
:=
unix
.
Syscall6
(
unix
.
SYS_QUOTACTL
,
C
.
Q_SETPQUOTA
,
uintptr
(
unsafe
.
Pointer
(
cs
)),
uintptr
(
id
),
uintptr
(
unsafe
.
Pointer
(
&
d
)),
0
,
0
)
if
errno
!=
0
{
return
fmt
.
Errorf
(
"Failed to set quota limit for ID %d on %s: %v"
,
id
,
path
,
errno
.
Error
())
}
return
common
.
ApplyProjectToDir
(
path
,
id
)
}
func
(
v
extfsVolumeQuota
)
getQuotaInfo
(
path
string
,
id
common
.
QuotaID
)
(
C
.
struct_if_dqblk
,
syscall
.
Errno
)
{
var
d
C
.
struct_if_dqblk
var
cs
=
C
.
CString
(
v
.
backingDev
)
defer
C
.
free
(
unsafe
.
Pointer
(
cs
))
_
,
_
,
errno
:=
unix
.
Syscall6
(
unix
.
SYS_QUOTACTL
,
C
.
Q_GETPQUOTA
,
uintptr
(
unsafe
.
Pointer
(
cs
)),
uintptr
(
C
.
__u32
(
id
)),
uintptr
(
unsafe
.
Pointer
(
&
d
)),
0
,
0
)
return
d
,
errno
}
// QuotaIDIsInUse -- determine whether the quota ID is already in use.
func
(
v
extfsVolumeQuota
)
QuotaIDIsInUse
(
path
string
,
id
common
.
QuotaID
)
(
bool
,
error
)
{
d
,
errno
:=
v
.
getQuotaInfo
(
path
,
id
)
isInUse
:=
!
(
d
.
dqb_bhardlimit
==
0
&&
d
.
dqb_bsoftlimit
==
0
&&
d
.
dqb_curspace
==
0
&&
d
.
dqb_ihardlimit
==
0
&&
d
.
dqb_isoftlimit
==
0
&&
d
.
dqb_curinodes
==
0
&&
d
.
dqb_btime
==
0
&&
d
.
dqb_itime
==
0
)
return
errno
==
0
&&
isInUse
,
nil
}
// GetConsumption -- retrieve the consumption (in bytes) of the directory
// Note that with ext[[:digit:]]fs the quota consumption is in bytes
// per man quotactl
func
(
v
extfsVolumeQuota
)
GetConsumption
(
path
string
,
id
common
.
QuotaID
)
(
int64
,
error
)
{
d
,
errno
:=
v
.
getQuotaInfo
(
path
,
id
)
if
errno
!=
0
{
return
0
,
fmt
.
Errorf
(
"Failed to get quota for %s: %s"
,
path
,
errno
.
Error
())
}
klog
.
V
(
3
)
.
Infof
(
"Consumption for %s is %v"
,
path
,
d
.
dqb_curspace
)
return
int64
(
d
.
dqb_curspace
),
nil
}
// GetInodes -- retrieve the number of inodes in use under the directory
func
(
v
extfsVolumeQuota
)
GetInodes
(
path
string
,
id
common
.
QuotaID
)
(
int64
,
error
)
{
d
,
errno
:=
v
.
getQuotaInfo
(
path
,
id
)
if
errno
!=
0
{
return
0
,
fmt
.
Errorf
(
"Failed to get quota for %s: %s"
,
path
,
errno
.
Error
())
}
klog
.
V
(
3
)
.
Infof
(
"Inode consumption for %s is %v"
,
path
,
d
.
dqb_curinodes
)
return
int64
(
d
.
dqb_curinodes
),
nil
}
pkg/volume/util/quota/project.go
View file @
f8661d62
...
@@ -29,15 +29,14 @@ import (
...
@@ -29,15 +29,14 @@ import (
"sync"
"sync"
"golang.org/x/sys/unix"
"golang.org/x/sys/unix"
"k8s.io/klog"
"k8s.io/kubernetes/pkg/volume/util/quota/common"
"k8s.io/kubernetes/pkg/volume/util/quota/common"
)
)
var
projectsFile
=
"/etc/projects"
var
projectsFile
=
"/etc/projects"
var
projidFile
=
"/etc/projid"
var
projidFile
=
"/etc/projid"
var
projectsParseRegexp
*
regexp
.
Regexp
=
regexp
.
MustCompilePOSIX
(
"^([[:digit:]]+):(.*)$"
)
var
projectsParseRegexp
=
regexp
.
MustCompilePOSIX
(
"^([[:digit:]]+):(.*)$"
)
var
projidParseRegexp
*
regexp
.
Regexp
=
regexp
.
MustCompilePOSIX
(
"^([^#][^:]*):([[:digit:]]+)$"
)
var
projidParseRegexp
=
regexp
.
MustCompilePOSIX
(
"^([^#][^:]*):([[:digit:]]+)$"
)
var
quotaIDLock
sync
.
RWMutex
var
quotaIDLock
sync
.
RWMutex
...
@@ -78,12 +77,13 @@ func unlockFile(file *os.File) error {
...
@@ -78,12 +77,13 @@ func unlockFile(file *os.File) error {
func
openAndLockProjectFiles
()
(
*
os
.
File
,
*
os
.
File
,
error
)
{
func
openAndLockProjectFiles
()
(
*
os
.
File
,
*
os
.
File
,
error
)
{
// Make sure neither project-related file is a symlink!
// Make sure neither project-related file is a symlink!
if
err
:=
projFilesAreOK
();
err
!=
nil
{
if
err
:=
projFilesAreOK
();
err
!=
nil
{
return
nil
,
nil
,
err
return
nil
,
nil
,
fmt
.
Errorf
(
"system project files failed verification: %v"
,
err
)
}
}
// We don't actually modify the original files; we create temporaries and
// We don't actually modify the original files; we create temporaries and
// move them over the originals
// move them over the originals
fProjects
,
err
:=
os
.
OpenFile
(
projectsFile
,
os
.
O_RDONLY
|
os
.
O_CREATE
,
0644
)
fProjects
,
err
:=
os
.
OpenFile
(
projectsFile
,
os
.
O_RDONLY
|
os
.
O_CREATE
,
0644
)
if
err
!=
nil
{
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"unable to open %s: %v"
,
projectsFile
,
err
)
return
nil
,
nil
,
err
return
nil
,
nil
,
err
}
}
fProjid
,
err
:=
os
.
OpenFile
(
projidFile
,
os
.
O_RDONLY
|
os
.
O_CREATE
,
0644
)
fProjid
,
err
:=
os
.
OpenFile
(
projidFile
,
os
.
O_RDONLY
|
os
.
O_CREATE
,
0644
)
...
@@ -97,10 +97,17 @@ func openAndLockProjectFiles() (*os.File, *os.File, error) {
...
@@ -97,10 +97,17 @@ func openAndLockProjectFiles() (*os.File, *os.File, error) {
return
fProjects
,
fProjid
,
nil
return
fProjects
,
fProjid
,
nil
}
}
// Nothing useful we can do if we get an error here
// Nothing useful we can do if we get an error here
err
=
fmt
.
Errorf
(
"unable to lock %s: %v"
,
projidFile
,
err
)
unlockFile
(
fProjects
)
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
()
fProjid
.
Close
()
}
else
{
err
=
fmt
.
Errorf
(
"unable to open %s: %v"
,
projidFile
,
err
)
}
}
fProjects
.
Close
()
fProjects
.
Close
()
return
nil
,
nil
,
err
return
nil
,
nil
,
err
...
@@ -160,7 +167,7 @@ func findAvailableQuota(path string, idMap map[common.QuotaID]bool) (common.Quot
...
@@ -160,7 +167,7 @@ func findAvailableQuota(path string, idMap map[common.QuotaID]bool) (common.Quot
unusedQuotasSearched
:=
0
unusedQuotasSearched
:=
0
for
id
:=
common
.
FirstQuota
;
id
==
id
;
id
++
{
for
id
:=
common
.
FirstQuota
;
id
==
id
;
id
++
{
if
_
,
ok
:=
idMap
[
id
];
!
ok
{
if
_
,
ok
:=
idMap
[
id
];
!
ok
{
isInUse
,
err
:=
getApplier
(
path
)
.
QuotaIDIsInUse
(
path
,
id
)
isInUse
,
err
:=
getApplier
(
path
)
.
QuotaIDIsInUse
(
id
)
if
err
!=
nil
{
if
err
!=
nil
{
return
common
.
BadQuotaID
,
err
return
common
.
BadQuotaID
,
err
}
else
if
!
isInUse
{
}
else
if
!
isInUse
{
...
@@ -307,8 +314,7 @@ func writeProjectFiles(fProjects *os.File, fProjid *os.File, writeProjid bool, l
...
@@ -307,8 +314,7 @@ func writeProjectFiles(fProjects *os.File, fProjid *os.File, writeProjid bool, l
}
}
os
.
Remove
(
tmpProjects
)
os
.
Remove
(
tmpProjects
)
}
}
klog
.
V
(
3
)
.
Infof
(
"Unable to write project files: %v"
,
err
)
return
fmt
.
Errorf
(
"Unable to write project files: %v"
,
err
)
return
err
}
}
func
createProjectID
(
path
string
,
ID
common
.
QuotaID
)
(
common
.
QuotaID
,
error
)
{
func
createProjectID
(
path
string
,
ID
common
.
QuotaID
)
(
common
.
QuotaID
,
error
)
{
...
@@ -326,8 +332,7 @@ func createProjectID(path string, ID common.QuotaID) (common.QuotaID, error) {
...
@@ -326,8 +332,7 @@ func createProjectID(path string, ID common.QuotaID) (common.QuotaID, error) {
}
}
}
}
}
}
klog
.
V
(
3
)
.
Infof
(
"addQuotaID %s %v failed %v"
,
path
,
ID
,
err
)
return
common
.
BadQuotaID
,
fmt
.
Errorf
(
"createProjectID %s %v failed %v"
,
path
,
ID
,
err
)
return
common
.
BadQuotaID
,
err
}
}
func
removeProjectID
(
path
string
,
ID
common
.
QuotaID
)
error
{
func
removeProjectID
(
path
string
,
ID
common
.
QuotaID
)
error
{
...
@@ -348,6 +353,5 @@ func removeProjectID(path string, ID common.QuotaID) error {
...
@@ -348,6 +353,5 @@ func removeProjectID(path string, ID common.QuotaID) error {
}
}
}
}
}
}
klog
.
V
(
3
)
.
Infof
(
"removeQuotaID %s %v failed %v"
,
path
,
ID
,
err
)
return
fmt
.
Errorf
(
"removeProjectID %s %v failed %v"
,
path
,
ID
,
err
)
return
err
}
}
pkg/volume/util/quota/quota.go
View file @
f8661d62
...
@@ -17,6 +17,7 @@ limitations under the License.
...
@@ -17,6 +17,7 @@ limitations under the License.
package
quota
package
quota
import
(
import
(
"k8s.io/apimachinery/pkg/api/resource"
utilfeature
"k8s.io/apiserver/pkg/util/feature"
utilfeature
"k8s.io/apiserver/pkg/util/feature"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/util/mount"
...
@@ -28,13 +29,13 @@ type Interface interface {
...
@@ -28,13 +29,13 @@ type Interface interface {
SupportsQuotas
(
m
mount
.
Interface
,
path
string
)
(
bool
,
error
)
SupportsQuotas
(
m
mount
.
Interface
,
path
string
)
(
bool
,
error
)
// Assign a quota (picked by the quota mechanism) to a path,
// Assign a quota (picked by the quota mechanism) to a path,
// and return it.
// and return it.
AssignQuota
(
m
mount
.
Interface
,
path
string
,
poduid
string
,
bytes
int64
)
error
AssignQuota
(
m
mount
.
Interface
,
path
string
,
poduid
string
,
bytes
*
resource
.
Quantity
)
error
// Get the quota-based storage consumption for the path
// Get the quota-based storage consumption for the path
GetConsumption
(
path
string
)
(
int64
,
error
)
GetConsumption
(
path
string
)
(
*
resource
.
Quantity
,
error
)
// Get the quota-based inode consumption for the path
// Get the quota-based inode consumption for the path
GetInodes
(
path
string
)
(
int64
,
error
)
GetInodes
(
path
string
)
(
*
resource
.
Quantity
,
error
)
// Remove the quota from a path
// Remove the quota from a path
// Implementations may assume that any data covered by the
// Implementations may assume that any data covered by the
...
@@ -43,5 +44,5 @@ type Interface interface {
...
@@ -43,5 +44,5 @@ type Interface interface {
}
}
func
enabledQuotasForMonitoring
()
bool
{
func
enabledQuotasForMonitoring
()
bool
{
return
utilfeature
.
DefaultFeatureGate
.
Enabled
(
features
.
FSQuotaForLSCI
Monitoring
)
return
utilfeature
.
DefaultFeatureGate
.
Enabled
(
features
.
LocalStorageCapacityIsolationFSQuota
Monitoring
)
}
}
pkg/volume/util/quota/quota_linux.go
View file @
f8661d62
This diff is collapsed.
Click to expand it.
pkg/volume/util/quota/quota_linux_test.go
View file @
f8661d62
...
@@ -21,7 +21,9 @@ package quota
...
@@ -21,7 +21,9 @@ package quota
import
(
import
(
"fmt"
"fmt"
"io/ioutil"
"io/ioutil"
"k8s.io/apimachinery/pkg/api/resource"
utilfeature
"k8s.io/apiserver/pkg/util/feature"
utilfeature
"k8s.io/apiserver/pkg/util/feature"
featuregatetesting
"k8s.io/component-base/featuregate/testing"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume/util/quota/common"
"k8s.io/kubernetes/pkg/volume/util/quota/common"
...
@@ -74,13 +76,13 @@ func dummyFakeMount1() mount.Interface {
...
@@ -74,13 +76,13 @@ func dummyFakeMount1() mount.Interface {
Opts
:
[]
string
{
"rw"
,
"relatime"
},
Opts
:
[]
string
{
"rw"
,
"relatime"
},
},
},
{
{
Device
:
"dev/mapper/fedora-root"
,
Device
:
"
/
dev/mapper/fedora-root"
,
Path
:
"/"
,
Path
:
"/"
,
Type
:
"ext4"
,
Type
:
"ext4"
,
Opts
:
[]
string
{
"rw"
,
"relatime"
},
Opts
:
[]
string
{
"rw"
,
"relatime"
},
},
},
{
{
Device
:
"dev/mapper/fedora-home"
,
Device
:
"
/
dev/mapper/fedora-home"
,
Path
:
"/home"
,
Path
:
"/home"
,
Type
:
"ext4"
,
Type
:
"ext4"
,
Opts
:
[]
string
{
"rw"
,
"relatime"
},
Opts
:
[]
string
{
"rw"
,
"relatime"
},
...
@@ -363,7 +365,7 @@ func (v testVolumeQuota) GetQuotaOnDir(path string) (common.QuotaID, error) {
...
@@ -363,7 +365,7 @@ func (v testVolumeQuota) GetQuotaOnDir(path string) (common.QuotaID, error) {
return
common
.
BadQuotaID
,
fmt
.
Errorf
(
"No quota available for %s"
,
path
)
return
common
.
BadQuotaID
,
fmt
.
Errorf
(
"No quota available for %s"
,
path
)
}
}
func
(
v
testVolumeQuota
)
QuotaIDIsInUse
(
_
string
,
id
common
.
QuotaID
)
(
bool
,
error
)
{
func
(
v
testVolumeQuota
)
QuotaIDIsInUse
(
id
common
.
QuotaID
)
(
bool
,
error
)
{
if
_
,
ok
:=
testIDQuotaMap
[
id
];
ok
{
if
_
,
ok
:=
testIDQuotaMap
[
id
];
ok
{
return
true
,
nil
return
true
,
nil
}
}
...
@@ -389,7 +391,7 @@ func fakeSupportsQuotas(path string) (bool, error) {
...
@@ -389,7 +391,7 @@ func fakeSupportsQuotas(path string) (bool, error) {
func
fakeAssignQuota
(
path
string
,
poduid
string
,
bytes
int64
)
error
{
func
fakeAssignQuota
(
path
string
,
poduid
string
,
bytes
int64
)
error
{
dummySetFSInfo
(
path
)
dummySetFSInfo
(
path
)
return
AssignQuota
(
dummyQuotaTest
(),
path
,
poduid
,
bytes
)
return
AssignQuota
(
dummyQuotaTest
(),
path
,
poduid
,
resource
.
NewQuantity
(
bytes
,
resource
.
DecimalSI
)
)
}
}
func
fakeClearQuota
(
path
string
)
error
{
func
fakeClearQuota
(
path
string
)
error
{
...
@@ -529,14 +531,6 @@ func compareProjectsFiles(t *testing.T, testcase quotaTestCase, projectsFile str
...
@@ -529,14 +531,6 @@ func compareProjectsFiles(t *testing.T, testcase quotaTestCase, projectsFile str
}
}
}
}
func
setFeature
(
feature
utilfeature
.
Feature
,
value
bool
)
error
{
v
:=
"true"
if
!
value
{
v
=
"false"
}
return
utilfeature
.
DefaultFeatureGate
.
Set
(
fmt
.
Sprintf
(
"%s=%s"
,
string
(
feature
),
v
))
}
func
runCaseEnabled
(
t
*
testing
.
T
,
testcase
quotaTestCase
,
seq
int
)
bool
{
func
runCaseEnabled
(
t
*
testing
.
T
,
testcase
quotaTestCase
,
seq
int
)
bool
{
fail
:=
false
fail
:=
false
var
err
error
var
err
error
...
@@ -604,9 +598,7 @@ func runCaseDisabled(t *testing.T, testcase quotaTestCase, seq int) bool {
...
@@ -604,9 +598,7 @@ func runCaseDisabled(t *testing.T, testcase quotaTestCase, seq int) bool {
}
}
func
testAddRemoveQuotas
(
t
*
testing
.
T
,
enabled
bool
)
{
func
testAddRemoveQuotas
(
t
*
testing
.
T
,
enabled
bool
)
{
if
err
:=
setFeature
(
features
.
FSQuotaForLSCIMonitoring
,
enabled
);
err
!=
nil
{
defer
featuregatetesting
.
SetFeatureGateDuringTest
(
t
,
utilfeature
.
DefaultFeatureGate
,
features
.
LocalStorageCapacityIsolationFSQuotaMonitoring
,
enabled
)()
t
.
Errorf
(
"Unable to enable LSCI monitoring: %v"
,
err
)
}
tmpProjectsFile
,
err
:=
ioutil
.
TempFile
(
""
,
"projects"
)
tmpProjectsFile
,
err
:=
ioutil
.
TempFile
(
""
,
"projects"
)
if
err
==
nil
{
if
err
==
nil
{
_
,
err
=
tmpProjectsFile
.
WriteString
(
projectsHeader
)
_
,
err
=
tmpProjectsFile
.
WriteString
(
projectsHeader
)
...
...
pkg/volume/util/quota/quota_unsupported.go
View file @
f8661d62
...
@@ -20,6 +20,7 @@ package quota
...
@@ -20,6 +20,7 @@ package quota
import
(
import
(
"errors"
"errors"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/util/mount"
)
)
...
@@ -34,18 +35,18 @@ func SupportsQuotas(_ mount.Interface, _ string) (bool, error) {
...
@@ -34,18 +35,18 @@ func SupportsQuotas(_ mount.Interface, _ string) (bool, error) {
}
}
// AssignQuota -- dummy implementation
// AssignQuota -- dummy implementation
func
AssignQuota
(
_
mount
.
Interface
,
_
string
,
_
string
,
_
int64
)
error
{
func
AssignQuota
(
_
mount
.
Interface
,
_
string
,
_
string
,
_
*
resource
.
Quantity
)
error
{
return
errNotImplemented
return
errNotImplemented
}
}
// GetConsumption -- dummy implementation
// GetConsumption -- dummy implementation
func
GetConsumption
(
_
string
)
(
int64
,
error
)
{
func
GetConsumption
(
_
string
)
(
*
resource
.
Quantity
,
error
)
{
return
0
,
errNotImplemented
return
nil
,
errNotImplemented
}
}
// GetInodes -- dummy implementation
// GetInodes -- dummy implementation
func
GetInodes
(
_
string
)
(
int64
,
error
)
{
func
GetInodes
(
_
string
)
(
*
resource
.
Quantity
,
error
)
{
return
0
,
errNotImplemented
return
nil
,
errNotImplemented
}
}
// ClearQuota -- dummy implementation
// ClearQuota -- dummy implementation
...
...
pkg/volume/util/quota/xfs/BUILD
deleted
100644 → 0
View file @
448e0c44
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["quota_xfs.go"],
cgo = True,
importpath = "k8s.io/kubernetes/pkg/volume/util/quota/xfs",
visibility = ["//visibility:public"],
deps = select({
"@io_bazel_rules_go//go/platform:linux": [
"//pkg/volume/util/quota/common:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",
"//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"],
)
pkg/volume/util/quota/xfs/quota_xfs.go
deleted
100644 → 0
View file @
448e0c44
// +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
xfs
/*
#include <stdlib.h>
#include <dirent.h>
#include <linux/fs.h>
#include <linux/quota.h>
#include <linux/dqblk_xfs.h>
#include <errno.h>
#ifndef PRJQUOTA
#define PRJQUOTA 2
#endif
#ifndef XFS_PROJ_QUOTA
#define XFS_PROJ_QUOTA 2
#endif
#ifndef Q_XSETPQLIM
#define Q_XSETPQLIM QCMD(Q_XSETQLIM, PRJQUOTA)
#endif
#ifndef Q_XGETPQUOTA
#define Q_XGETPQUOTA QCMD(Q_XGETQUOTA, PRJQUOTA)
#endif
*/
import
"C"
import
(
"fmt"
"syscall"
"unsafe"
"golang.org/x/sys/unix"
"k8s.io/klog"
"k8s.io/kubernetes/pkg/volume/util/quota/common"
)
const
(
linuxXfsMagic
=
0x58465342
// Documented in man xfs_quota(8); not necessarily the same
// as the filesystem blocksize
quotaBsize
=
512
bitsPerWord
=
32
<<
(
^
uint
(
0
)
>>
63
)
// either 32 or 64
maxQuota
int64
=
1
<<
(
bitsPerWord
-
1
)
-
1
// either 1<<31 - 1 or 1<<63 - 1
)
// VolumeProvider supplies a quota applier to the generic code.
type
VolumeProvider
struct
{
}
// GetQuotaApplier -- does this backing device support quotas that
// can be applied to directories?
func
(
*
VolumeProvider
)
GetQuotaApplier
(
mountpoint
string
,
backingDev
string
)
common
.
LinuxVolumeQuotaApplier
{
if
common
.
IsFilesystemOfType
(
mountpoint
,
backingDev
,
linuxXfsMagic
)
{
return
xfsVolumeQuota
{
backingDev
}
}
return
nil
}
type
xfsVolumeQuota
struct
{
backingDev
string
}
// GetQuotaOnDir -- get the quota ID that applies to this directory.
func
(
v
xfsVolumeQuota
)
GetQuotaOnDir
(
path
string
)
(
common
.
QuotaID
,
error
)
{
return
common
.
GetQuotaOnDir
(
path
)
}
// SetQuotaOnDir -- apply the specified quota to the directory. If
// bytes is not greater than zero, the quota should be applied in a
// way that is non-enforcing (either explicitly so or by setting a
// quota larger than anything the user may possibly create)
func
(
v
xfsVolumeQuota
)
SetQuotaOnDir
(
path
string
,
id
common
.
QuotaID
,
bytes
int64
)
error
{
klog
.
V
(
3
)
.
Infof
(
"xfsSetQuotaOn %s ID %v bytes %v"
,
path
,
id
,
bytes
)
if
bytes
<
0
||
bytes
>
maxQuota
{
bytes
=
maxQuota
}
var
d
C
.
fs_disk_quota_t
d
.
d_version
=
C
.
FS_DQUOT_VERSION
d
.
d_id
=
C
.
__u32
(
id
)
d
.
d_flags
=
C
.
XFS_PROJ_QUOTA
d
.
d_fieldmask
=
C
.
FS_DQ_BHARD
d
.
d_blk_hardlimit
=
C
.
__u64
(
bytes
/
quotaBsize
)
d
.
d_blk_softlimit
=
d
.
d_blk_hardlimit
var
cs
=
C
.
CString
(
v
.
backingDev
)
defer
C
.
free
(
unsafe
.
Pointer
(
cs
))
_
,
_
,
errno
:=
unix
.
Syscall6
(
unix
.
SYS_QUOTACTL
,
C
.
Q_XSETPQLIM
,
uintptr
(
unsafe
.
Pointer
(
cs
)),
uintptr
(
d
.
d_id
),
uintptr
(
unsafe
.
Pointer
(
&
d
)),
0
,
0
)
if
errno
!=
0
{
return
fmt
.
Errorf
(
"Failed to set quota limit for ID %d on %s: %v"
,
id
,
path
,
errno
.
Error
())
}
return
common
.
ApplyProjectToDir
(
path
,
id
)
}
func
(
v
xfsVolumeQuota
)
getQuotaInfo
(
path
string
,
id
common
.
QuotaID
)
(
C
.
fs_disk_quota_t
,
syscall
.
Errno
)
{
var
d
C
.
fs_disk_quota_t
var
cs
=
C
.
CString
(
v
.
backingDev
)
defer
C
.
free
(
unsafe
.
Pointer
(
cs
))
_
,
_
,
errno
:=
unix
.
Syscall6
(
unix
.
SYS_QUOTACTL
,
C
.
Q_XGETPQUOTA
,
uintptr
(
unsafe
.
Pointer
(
cs
)),
uintptr
(
C
.
__u32
(
id
)),
uintptr
(
unsafe
.
Pointer
(
&
d
)),
0
,
0
)
return
d
,
errno
}
// QuotaIDIsInUse -- determine whether the quota ID is already in use.
func
(
v
xfsVolumeQuota
)
QuotaIDIsInUse
(
path
string
,
id
common
.
QuotaID
)
(
bool
,
error
)
{
_
,
errno
:=
v
.
getQuotaInfo
(
path
,
id
)
return
errno
==
0
,
nil
}
// GetConsumption -- retrieve the consumption (in bytes) of the directory
func
(
v
xfsVolumeQuota
)
GetConsumption
(
path
string
,
id
common
.
QuotaID
)
(
int64
,
error
)
{
d
,
errno
:=
v
.
getQuotaInfo
(
path
,
id
)
if
errno
!=
0
{
return
0
,
fmt
.
Errorf
(
"Failed to get quota for %s: %s"
,
path
,
errno
.
Error
())
}
klog
.
V
(
3
)
.
Infof
(
"Consumption for %s is %v"
,
path
,
d
.
d_bcount
*
quotaBsize
)
return
int64
(
d
.
d_bcount
)
*
quotaBsize
,
nil
}
// GetInodes -- retrieve the number of inodes in use under the directory
func
(
v
xfsVolumeQuota
)
GetInodes
(
path
string
,
id
common
.
QuotaID
)
(
int64
,
error
)
{
d
,
errno
:=
v
.
getQuotaInfo
(
path
,
id
)
if
errno
!=
0
{
return
0
,
fmt
.
Errorf
(
"Failed to get quota for %s: %s"
,
path
,
errno
.
Error
())
}
klog
.
V
(
3
)
.
Infof
(
"Inode consumption for %s is %v"
,
path
,
d
.
d_icount
)
return
int64
(
d
.
d_icount
),
nil
}
pkg/volume/util/util.go
View file @
f8661d62
...
@@ -540,3 +540,11 @@ func GetPluginMountDir(host volume.VolumeHost, name string) string {
...
@@ -540,3 +540,11 @@ func GetPluginMountDir(host volume.VolumeHost, name string) string {
mntDir
:=
filepath
.
Join
(
host
.
GetPluginDir
(
name
),
MountsInGlobalPDPath
)
mntDir
:=
filepath
.
Join
(
host
.
GetPluginDir
(
name
),
MountsInGlobalPDPath
)
return
mntDir
return
mntDir
}
}
// IsLocalEphemeralVolume determines whether the argument is a local ephemeral
// volume vs. some other type
func
IsLocalEphemeralVolume
(
volume
v1
.
Volume
)
bool
{
return
volume
.
GitRepo
!=
nil
||
(
volume
.
EmptyDir
!=
nil
&&
volume
.
EmptyDir
.
Medium
!=
v1
.
StorageMediumMemory
)
||
volume
.
ConfigMap
!=
nil
||
volume
.
DownwardAPI
!=
nil
}
pkg/volume/volume.go
View file @
f8661d62
...
@@ -104,7 +104,7 @@ type Attributes struct {
...
@@ -104,7 +104,7 @@ type Attributes struct {
// MounterArgs provides more easily extensible arguments to Mounter
// MounterArgs provides more easily extensible arguments to Mounter
type
MounterArgs
struct
{
type
MounterArgs
struct
{
FsGroup
*
int64
FsGroup
*
int64
DesiredSize
int64
DesiredSize
*
resource
.
Quantity
PodUID
string
PodUID
string
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment