Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Declare out of disk when there is no free inodes #28176

Merged
merged 1 commit into from
Jul 2, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions pkg/kubelet/disk_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,11 @@ type DiskSpacePolicy struct {
}

type fsInfo struct {
Usage int64
Capacity int64
Available int64
Timestamp time.Time
Usage int64
Capacity int64
Available int64
Timestamp time.Time
InodesFree int64
}

type realDiskSpaceManager struct {
Expand Down Expand Up @@ -78,6 +79,7 @@ func (dm *realDiskSpaceManager) getFsInfo(fsType string, f func() (cadvisorapi.F
fsi.Usage = int64(fs.Usage)
fsi.Capacity = int64(fs.Capacity)
fsi.Available = int64(fs.Available)
fsi.InodesFree = int64(fs.InodesFree)
dm.cachedInfo[fsType] = fsi
}
return fsi, nil
Expand All @@ -102,11 +104,14 @@ func (dm *realDiskSpaceManager) isSpaceAvailable(fsType string, threshold int, f
if fsInfo.Available < 0 {
return true, fmt.Errorf("wrong available space for %q: %+v", fsType, fsInfo)
}

if fsInfo.Available < int64(threshold)*mb {
glog.Infof("Running out of space on disk for %q: available %d MB, threshold %d MB", fsType, fsInfo.Available/mb, threshold)
return false, nil
}
if fsInfo.InodesFree == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we define a threshold for inodes as well that is > 0? By the time kubelet detects that there are inodes, the pods on the node are most likely stuck.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My comment can be resolved in a subsequent PR too.

glog.Infof("Running out of inodes for %q", fsType)
return false, nil
}
return true, nil
}

Expand Down
127 changes: 90 additions & 37 deletions pkg/kubelet/disk_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,15 @@ func TestSpaceAvailable(t *testing.T) {
assert.NoError(err)

mockCadvisor.On("ImagesFsInfo").Return(cadvisorapi.FsInfo{
Usage: 400 * mb,
Capacity: 1000 * mb,
Available: 600 * mb,
Usage: 400 * mb,
Capacity: 1000 * mb,
Available: 600 * mb,
InodesFree: 5,
}, nil)
mockCadvisor.On("RootFsInfo").Return(cadvisorapi.FsInfo{
Usage: 9 * mb,
Capacity: 10 * mb,
Usage: 9 * mb,
Capacity: 10 * mb,
InodesFree: 5,
}, nil)

ok, err := dm.IsRuntimeDiskSpaceAvailable()
Expand All @@ -81,17 +83,18 @@ func TestSpaceAvailable(t *testing.T) {
}

// TestIsRuntimeDiskSpaceAvailableWithSpace verifies IsRuntimeDiskSpaceAvailable results when
// space is available.
// space and inodes are available.
func TestIsRuntimeDiskSpaceAvailableWithSpace(t *testing.T) {
assert, policy, mockCadvisor := setUp(t)
dm, err := newDiskSpaceManager(mockCadvisor, policy)
require.NoError(t, err)

// 500MB available
mockCadvisor.On("ImagesFsInfo").Return(cadvisorapi.FsInfo{
Usage: 9500 * mb,
Capacity: 10000 * mb,
Available: 500 * mb,
Usage: 9500 * mb,
Capacity: 10000 * mb,
Available: 500 * mb,
InodesFree: 10,
}, nil)

ok, err := dm.IsRuntimeDiskSpaceAvailable()
Expand All @@ -105,9 +108,30 @@ func TestIsRuntimeDiskSpaceAvailableWithoutSpace(t *testing.T) {
// 1MB available
assert, policy, mockCadvisor := setUp(t)
mockCadvisor.On("ImagesFsInfo").Return(cadvisorapi.FsInfo{
Usage: 999 * mb,
Capacity: 1000 * mb,
Available: 1 * mb,
Usage: 999 * mb,
Capacity: 1000 * mb,
Available: 1 * mb,
InodesFree: 10,
}, nil)

dm, err := newDiskSpaceManager(mockCadvisor, policy)
require.NoError(t, err)

ok, err := dm.IsRuntimeDiskSpaceAvailable()
assert.NoError(err)
assert.False(ok)
}

// TestIsRuntimeDiskSpaceAvailableWithoutInode verifies IsRuntimeDiskSpaceAvailable results when
// inode is not available.
func TestIsRuntimeDiskSpaceAvailableWithoutInode(t *testing.T) {
// 1MB available
assert, policy, mockCadvisor := setUp(t)
mockCadvisor.On("ImagesFsInfo").Return(cadvisorapi.FsInfo{
Usage: 999 * mb,
Capacity: 1000 * mb,
Available: 500 * mb,
InodesFree: 0,
}, nil)

dm, err := newDiskSpaceManager(mockCadvisor, policy)
Expand All @@ -119,7 +143,7 @@ func TestIsRuntimeDiskSpaceAvailableWithoutSpace(t *testing.T) {
}

// TestIsRootDiskSpaceAvailableWithSpace verifies IsRootDiskSpaceAvailable results when
// space is available.
// space and inodes are available.
func TestIsRootDiskSpaceAvailableWithSpace(t *testing.T) {
assert, policy, mockCadvisor := setUp(t)
policy.RootFreeDiskMB = 10
Expand All @@ -128,9 +152,10 @@ func TestIsRootDiskSpaceAvailableWithSpace(t *testing.T) {

// 999MB available
mockCadvisor.On("RootFsInfo").Return(cadvisorapi.FsInfo{
Usage: 1 * mb,
Capacity: 1000 * mb,
Available: 999 * mb,
Usage: 1 * mb,
Capacity: 1000 * mb,
Available: 999 * mb,
InodesFree: 10,
}, nil)

ok, err := dm.IsRootDiskSpaceAvailable()
Expand All @@ -148,9 +173,31 @@ func TestIsRootDiskSpaceAvailableWithoutSpace(t *testing.T) {

// 9MB available
mockCadvisor.On("RootFsInfo").Return(cadvisorapi.FsInfo{
Usage: 990 * mb,
Capacity: 1000 * mb,
Available: 9 * mb,
Usage: 990 * mb,
Capacity: 1000 * mb,
Available: 9 * mb,
InodesFree: 10,
}, nil)

ok, err := dm.IsRootDiskSpaceAvailable()
assert.NoError(err)
assert.False(ok)
}

// TestIsRootDiskSpaceAvailableWithoutInode verifies IsRootDiskSpaceAvailable results when
// inode is not available.
func TestIsRootDiskSpaceAvailableWithoutInode(t *testing.T) {
assert, policy, mockCadvisor := setUp(t)
policy.RootFreeDiskMB = 10
dm, err := newDiskSpaceManager(mockCadvisor, policy)
assert.NoError(err)

// 9MB available
mockCadvisor.On("RootFsInfo").Return(cadvisorapi.FsInfo{
Usage: 990 * mb,
Capacity: 1000 * mb,
Available: 500 * mb,
InodesFree: 0,
}, nil)

ok, err := dm.IsRootDiskSpaceAvailable()
Expand All @@ -165,14 +212,16 @@ func TestCache(t *testing.T) {
assert.NoError(err)

mockCadvisor.On("ImagesFsInfo").Return(cadvisorapi.FsInfo{
Usage: 400 * mb,
Capacity: 1000 * mb,
Available: 300 * mb,
Usage: 400 * mb,
Capacity: 1000 * mb,
Available: 300 * mb,
InodesFree: 10,
}, nil).Once()
mockCadvisor.On("RootFsInfo").Return(cadvisorapi.FsInfo{
Usage: 500 * mb,
Capacity: 1000 * mb,
Available: 500 * mb,
Usage: 500 * mb,
Capacity: 1000 * mb,
Available: 500 * mb,
InodesFree: 5,
}, nil).Once()

// Initial calls which should be recorded in mockCadvisor
Expand Down Expand Up @@ -224,9 +273,10 @@ func Test_getFsInfo(t *testing.T) {

// Sunny day case
mockCadvisor.On("RootFsInfo").Return(cadvisorapi.FsInfo{
Usage: 10 * mb,
Capacity: 100 * mb,
Available: 90 * mb,
Usage: 10 * mb,
Capacity: 100 * mb,
Available: 90 * mb,
InodesFree: 5,
}, nil).Once()

dm := &realDiskSpaceManager{
Expand All @@ -242,9 +292,10 @@ func Test_getFsInfo(t *testing.T) {
// Threshold case
mockCadvisor = new(cadvisortest.Mock)
mockCadvisor.On("RootFsInfo").Return(cadvisorapi.FsInfo{
Usage: 9 * mb,
Capacity: 100 * mb,
Available: 9 * mb,
Usage: 9 * mb,
Capacity: 100 * mb,
Available: 9 * mb,
InodesFree: 5,
}, nil).Once()

dm = &realDiskSpaceManager{
Expand All @@ -258,9 +309,10 @@ func Test_getFsInfo(t *testing.T) {

// Frozen case
mockCadvisor.On("RootFsInfo").Return(cadvisorapi.FsInfo{
Usage: 9 * mb,
Capacity: 10 * mb,
Available: 500 * mb,
Usage: 9 * mb,
Capacity: 10 * mb,
Available: 500 * mb,
InodesFree: 5,
}, nil).Once()

dm = &realDiskSpaceManager{
Expand All @@ -275,9 +327,10 @@ func Test_getFsInfo(t *testing.T) {
// Capacity error case
mockCadvisor = new(cadvisortest.Mock)
mockCadvisor.On("RootFsInfo").Return(cadvisorapi.FsInfo{
Usage: 9 * mb,
Capacity: 0,
Available: 500 * mb,
Usage: 9 * mb,
Capacity: 0,
Available: 500 * mb,
InodesFree: 5,
}, nil).Once()

dm = &realDiskSpaceManager{
Expand Down
4 changes: 2 additions & 2 deletions pkg/kubelet/kubelet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2695,8 +2695,8 @@ func TestValidateContainerLogStatus(t *testing.T) {
// sufficient disk space or it is out of disk, depending on the capacity, availability and
// threshold values.
func updateDiskSpacePolicy(kubelet *Kubelet, mockCadvisor *cadvisortest.Mock, rootCap, dockerCap, rootAvail, dockerAvail uint64, rootThreshold, dockerThreshold int) error {
dockerimagesFsInfo := cadvisorapiv2.FsInfo{Capacity: rootCap * mb, Available: rootAvail * mb}
rootFsInfo := cadvisorapiv2.FsInfo{Capacity: dockerCap * mb, Available: dockerAvail * mb}
dockerimagesFsInfo := cadvisorapiv2.FsInfo{Capacity: rootCap * mb, Available: rootAvail * mb, InodesFree: 5}
rootFsInfo := cadvisorapiv2.FsInfo{Capacity: dockerCap * mb, Available: dockerAvail * mb, InodesFree: 5}
mockCadvisor.On("ImagesFsInfo").Return(dockerimagesFsInfo, nil)
mockCadvisor.On("RootFsInfo").Return(rootFsInfo, nil)

Expand Down