mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Merge pull request #126429 from saschagrunert/kubelet-panic
Fix kubelet cadvisor stats runtime panic
This commit is contained in:
commit
e8588e6493
@ -270,26 +270,34 @@ func (p *cadvisorStatsProvider) ImageFsStats(ctx context.Context) (imageFsRet *s
|
||||
return imageFs, imageFs, nil
|
||||
}
|
||||
imageStats, err := p.imageService.ImageFsInfo(ctx)
|
||||
if err != nil || imageStats == nil {
|
||||
return nil, nil, fmt.Errorf("failed to get image stats: %v", err)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to get image stats: %w", err)
|
||||
}
|
||||
if imageStats == nil || len(imageStats.ImageFilesystems) == 0 || len(imageStats.ContainerFilesystems) == 0 {
|
||||
return nil, nil, fmt.Errorf("missing image stats: %+v", imageStats)
|
||||
}
|
||||
splitFileSystem := false
|
||||
if imageStats.ImageFilesystems[0].FsId.Mountpoint != imageStats.ContainerFilesystems[0].FsId.Mountpoint {
|
||||
klog.InfoS("Detect Split Filesystem", "ImageFilesystems", imageStats.ImageFilesystems[0], "ContainerFilesystems", imageStats.ContainerFilesystems[0])
|
||||
imageFs := imageStats.ImageFilesystems[0]
|
||||
containerFs := imageStats.ContainerFilesystems[0]
|
||||
if imageFs.FsId != nil && containerFs.FsId != nil && imageFs.FsId.Mountpoint != containerFs.FsId.Mountpoint {
|
||||
klog.InfoS("Detect Split Filesystem", "ImageFilesystems", imageFs, "ContainerFilesystems", containerFs)
|
||||
splitFileSystem = true
|
||||
}
|
||||
imageFs := imageStats.ImageFilesystems[0]
|
||||
var imageFsInodesUsed *uint64
|
||||
if imageFsInfo.Inodes != nil && imageFsInfo.InodesFree != nil {
|
||||
imageFsIU := *imageFsInfo.Inodes - *imageFsInfo.InodesFree
|
||||
imageFsInodesUsed = &imageFsIU
|
||||
}
|
||||
var usedBytes uint64
|
||||
if imageFs.GetUsedBytes() != nil {
|
||||
usedBytes = imageFs.GetUsedBytes().GetValue()
|
||||
}
|
||||
|
||||
fsStats := &statsapi.FsStats{
|
||||
Time: metav1.NewTime(imageFsInfo.Timestamp),
|
||||
AvailableBytes: &imageFsInfo.Available,
|
||||
CapacityBytes: &imageFsInfo.Capacity,
|
||||
UsedBytes: &imageFs.UsedBytes.Value,
|
||||
UsedBytes: &usedBytes,
|
||||
InodesFree: imageFsInfo.InodesFree,
|
||||
Inodes: imageFsInfo.Inodes,
|
||||
InodesUsed: imageFsInodesUsed,
|
||||
@ -305,18 +313,21 @@ func (p *cadvisorStatsProvider) ImageFsStats(ctx context.Context) (imageFsRet *s
|
||||
return nil, nil, fmt.Errorf("failed to get container fs info: %w", err)
|
||||
}
|
||||
|
||||
containerFs := imageStats.ContainerFilesystems[0]
|
||||
var containerFsInodesUsed *uint64
|
||||
if containerFsInfo.Inodes != nil && containerFsInfo.InodesFree != nil {
|
||||
containerFsIU := *containerFsInfo.Inodes - *containerFsInfo.InodesFree
|
||||
containerFsInodesUsed = &containerFsIU
|
||||
}
|
||||
var usedContainerBytes uint64
|
||||
if containerFs.GetUsedBytes() != nil {
|
||||
usedContainerBytes = containerFs.GetUsedBytes().GetValue()
|
||||
}
|
||||
|
||||
fsContainerStats := &statsapi.FsStats{
|
||||
Time: metav1.NewTime(containerFsInfo.Timestamp),
|
||||
AvailableBytes: &containerFsInfo.Available,
|
||||
CapacityBytes: &containerFsInfo.Capacity,
|
||||
UsedBytes: &containerFs.UsedBytes.Value,
|
||||
UsedBytes: &usedContainerBytes,
|
||||
InodesFree: containerFsInfo.InodesFree,
|
||||
Inodes: containerFsInfo.Inodes,
|
||||
InodesUsed: containerFsInodesUsed,
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
|
||||
cadvisorapiv2 "github.com/google/cadvisor/info/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@ -546,6 +547,86 @@ func TestCadvisorImagesFsStatsKubeletSeparateDiskOff(t *testing.T) {
|
||||
assert.Equal(*imageFsInfo.Inodes-*imageFsInfo.InodesFree, *stats.InodesUsed)
|
||||
}
|
||||
|
||||
func TestImageFsStatsCustomResponse(t *testing.T) {
|
||||
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.KubeletSeparateDiskGC, true)
|
||||
for desc, tc := range map[string]struct {
|
||||
response *runtimeapi.ImageFsInfoResponse
|
||||
callContainerFsInfo, shouldErr bool
|
||||
}{
|
||||
"image stats are nil": {
|
||||
shouldErr: true,
|
||||
},
|
||||
"no image filesystems in image stats": {
|
||||
response: &runtimeapi.ImageFsInfoResponse{
|
||||
ImageFilesystems: []*runtimeapi.FilesystemUsage{},
|
||||
ContainerFilesystems: []*runtimeapi.FilesystemUsage{{}},
|
||||
},
|
||||
shouldErr: true,
|
||||
},
|
||||
"no container filesystems in image stats": {
|
||||
response: &runtimeapi.ImageFsInfoResponse{
|
||||
ImageFilesystems: []*runtimeapi.FilesystemUsage{{}},
|
||||
ContainerFilesystems: []*runtimeapi.FilesystemUsage{},
|
||||
},
|
||||
shouldErr: true,
|
||||
},
|
||||
"image and container filesystem identifiers are nil": {
|
||||
response: &runtimeapi.ImageFsInfoResponse{
|
||||
ImageFilesystems: []*runtimeapi.FilesystemUsage{{}},
|
||||
ContainerFilesystems: []*runtimeapi.FilesystemUsage{{}},
|
||||
},
|
||||
shouldErr: false,
|
||||
},
|
||||
"using different mountpoints but no used bytes set": {
|
||||
response: &runtimeapi.ImageFsInfoResponse{
|
||||
ImageFilesystems: []*runtimeapi.FilesystemUsage{{
|
||||
FsId: &runtimeapi.FilesystemIdentifier{Mountpoint: "mnt-1"},
|
||||
}},
|
||||
ContainerFilesystems: []*runtimeapi.FilesystemUsage{{
|
||||
FsId: &runtimeapi.FilesystemIdentifier{Mountpoint: "mnt-2"},
|
||||
}},
|
||||
},
|
||||
callContainerFsInfo: true,
|
||||
shouldErr: false,
|
||||
},
|
||||
"using different mountpoints and set used bytes": {
|
||||
response: &runtimeapi.ImageFsInfoResponse{
|
||||
ImageFilesystems: []*runtimeapi.FilesystemUsage{{
|
||||
FsId: &runtimeapi.FilesystemIdentifier{Mountpoint: "mnt-1"},
|
||||
UsedBytes: &runtimeapi.UInt64Value{Value: 10},
|
||||
}},
|
||||
ContainerFilesystems: []*runtimeapi.FilesystemUsage{{
|
||||
FsId: &runtimeapi.FilesystemIdentifier{Mountpoint: "mnt-2"},
|
||||
UsedBytes: &runtimeapi.UInt64Value{Value: 20},
|
||||
}},
|
||||
},
|
||||
callContainerFsInfo: true,
|
||||
shouldErr: false,
|
||||
},
|
||||
} {
|
||||
ctx := context.Background()
|
||||
mockCadvisor := cadvisortest.NewMockInterface(t)
|
||||
mockRuntime := containertest.NewMockRuntime(t)
|
||||
|
||||
res := getTestFsInfo(1000)
|
||||
mockCadvisor.EXPECT().ImagesFsInfo().Return(res, nil)
|
||||
mockRuntime.EXPECT().ImageFsInfo(ctx).Return(tc.response, nil)
|
||||
if tc.callContainerFsInfo {
|
||||
mockCadvisor.EXPECT().ContainerFsInfo().Return(res, nil)
|
||||
}
|
||||
|
||||
provider := newCadvisorStatsProvider(mockCadvisor, &fakeResourceAnalyzer{}, mockRuntime, nil, NewFakeHostStatsProvider())
|
||||
stats, containerfs, err := provider.ImageFsStats(ctx)
|
||||
if tc.shouldErr {
|
||||
require.Error(t, err, desc)
|
||||
assert.Nil(t, stats)
|
||||
assert.Nil(t, containerfs)
|
||||
} else {
|
||||
assert.NoError(t, err, desc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCadvisorImagesFsStats(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
var (
|
||||
|
Loading…
Reference in New Issue
Block a user