Skip to content
Open
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
6 changes: 6 additions & 0 deletions pkg/kubelet/kuberuntime/kuberuntime_container.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import (
"k8s.io/kubernetes/pkg/kubelet/cm"
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
"k8s.io/kubernetes/pkg/kubelet/events"
"k8s.io/kubernetes/pkg/kubelet/managed"
proberesults "k8s.io/kubernetes/pkg/kubelet/prober/results"
"k8s.io/kubernetes/pkg/kubelet/types"
"k8s.io/kubernetes/pkg/kubelet/util/format"
Expand Down Expand Up @@ -625,6 +626,8 @@ func (m *kubeGenericRuntimeManager) getPodContainerStatuses(ctx context.Context,
return nil, nil, err
}

isManagedPod := managed.IsManagedPodFromRuntimeService(ctx, m.runtimeService, activePodSandboxID)

statuses := []*kubecontainer.Status{}
activeContainerStatuses := []*kubecontainer.Status{}
// TODO: optimization: set maximum number of containers per container name to examine.
Expand All @@ -647,6 +650,9 @@ func (m *kubeGenericRuntimeManager) getPodContainerStatuses(ctx context.Context,
return nil, nil, remote.ErrContainerStatusNil
}
cStatus := m.convertToKubeContainerStatus(ctx, status)
if isManagedPod && cStatus.Resources != nil { // Clear CPU resources for managed pods (workload-pinned)
cStatus.Resources.CPURequest, cStatus.Resources.CPULimit = nil, nil
}
statuses = append(statuses, cStatus)
if c.PodSandboxId == activePodSandboxID {
activeContainerStatuses = append(activeContainerStatuses, cStatus)
Expand Down
36 changes: 36 additions & 0 deletions pkg/kubelet/managed/managed.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ limitations under the License.
package managed

import (
"context"
"encoding/json"
"fmt"
"os"
"strings"

v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
)

var (
Expand Down Expand Up @@ -88,6 +90,40 @@ func IsPodManaged(pod *v1.Pod) (bool, string, string) {
return false, "", ""
}

// podSandboxStatusGetter is an interface for getting pod sandbox status
type podSandboxStatusGetter interface {
PodSandboxStatus(ctx context.Context, podSandboxID string, verbose bool) (*runtimeapi.PodSandboxStatusResponse, error)
}

// IsPodSandboxManagedPod checks if a pod sandbox belongs to a managed pod
// by looking for workload pinning annotations.
func IsPodSandboxManagedPod(sandboxAnnotations map[string]string) bool {
Copy link
Member

Choose a reason for hiding this comment

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

nit: can this be defined below where it's called in IsManagedPodFromRuntimeService

Copy link
Author

Choose a reason for hiding this comment

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

Addressed, thanks.

if sandboxAnnotations == nil {
return false
}
for annotation := range sandboxAnnotations {
if strings.HasPrefix(annotation, WorkloadsAnnotationPrefix) {
return true
}
}
return false
}

// IsManagedPodFromRuntimeService checks if a pod is managed by fetching the pod sandbox
// status and checking for workload pinning annotations.
func IsManagedPodFromRuntimeService(ctx context.Context, runtimeService podSandboxStatusGetter, podSandboxID string) bool {
if podSandboxID == "" {
return false
}

sandboxResp, err := runtimeService.PodSandboxStatus(ctx, podSandboxID, false)
if err != nil || sandboxResp == nil || sandboxResp.GetStatus() == nil {
return false
}

return IsPodSandboxManagedPod(sandboxResp.GetStatus().Annotations)
}

// ModifyStaticPodForPinnedManagement will modify a pod for pod management
func ModifyStaticPodForPinnedManagement(pod *v1.Pod) (*v1.Pod, string, error) {
pod = pod.DeepCopy()
Expand Down
172 changes: 172 additions & 0 deletions pkg/kubelet/managed/managed_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package managed

import (
"context"
"fmt"
"testing"

v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
)

func TestModifyStaticPodForPinnedManagementErrorStates(t *testing.T) {
Expand Down Expand Up @@ -1007,3 +1009,173 @@ func createPod(annotations map[string]string, initContainer, container *v1.Conta

return pod
}

func TestIsPodSandboxManagedPod(t *testing.T) {
testCases := []struct {
name string
annotations map[string]string
expected bool
}{
{
name: "nil annotations",
annotations: nil,
expected: false,
},
{
name: "empty annotations",
annotations: map[string]string{},
expected: false,
},
{
name: "regular pod annotations without workload annotations",
annotations: map[string]string{
"some.annotation": "value",
"another.annotation": "value2",
"io.kubernetes.pod.id": "12345",
},
expected: false,
},
{
name: "managed pod with workload management annotation",
annotations: map[string]string{
"some.annotation": "value",
WorkloadsAnnotationPrefix + "management": `{"effect": "PreferredDuringScheduling"}`,
},
expected: true,
},
{
name: "managed pod with workload throttle annotation",
annotations: map[string]string{
WorkloadsAnnotationPrefix + "throttle": `{"effect": "PreferredDuringScheduling"}`,
},
expected: true,
},
{
name: "pod with annotation similar to workload prefix but not matching",
annotations: map[string]string{
"target.workload.openshift.io": "value", // missing trailing slash
"some.other.annotation": "value2",
},
expected: false,
},
{
name: "managed pod with multiple annotations",
annotations: map[string]string{
"io.kubernetes.pod.name": "test-pod",
"io.kubernetes.pod.namespace": "default",
WorkloadsAnnotationPrefix + "management": `{"effect": "PreferredDuringScheduling"}`,
"custom.annotation": "custom-value",
},
expected: true,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := IsPodSandboxManagedPod(tc.annotations)
if result != tc.expected {
t.Errorf("IsPodSandboxManagedPod() = %v, expected %v for annotations: %v",
result, tc.expected, tc.annotations)
}
})
}
}

// mockRuntimeService is a simple mock for testing
type mockRuntimeService struct {
sandboxStatus *runtimeapi.PodSandboxStatusResponse
err error
}

func (m *mockRuntimeService) PodSandboxStatus(ctx context.Context, podSandboxID string, verbose bool) (*runtimeapi.PodSandboxStatusResponse, error) {
return m.sandboxStatus, m.err
}

func TestIsManagedPodFromRuntimeService(t *testing.T) {
ctx := context.Background()

testCases := []struct {
name string
podSandboxID string
sandboxStatus *runtimeapi.PodSandboxStatusResponse
err error
expected bool
}{
{
name: "empty sandbox ID",
podSandboxID: "",
expected: false,
},
{
name: "runtime service returns error",
podSandboxID: "sandbox123",
err: fmt.Errorf("runtime error"),
expected: false,
},
{
name: "nil sandbox response",
podSandboxID: "sandbox123",
sandboxStatus: nil,
expected: false,
},
{
name: "nil status in response",
podSandboxID: "sandbox123",
sandboxStatus: &runtimeapi.PodSandboxStatusResponse{
Status: nil,
},
expected: false,
},
{
name: "regular pod without workload annotations",
podSandboxID: "sandbox123",
sandboxStatus: &runtimeapi.PodSandboxStatusResponse{
Status: &runtimeapi.PodSandboxStatus{
Annotations: map[string]string{
"some.annotation": "value",
},
},
},
expected: false,
},
{
name: "managed pod with workload annotations",
podSandboxID: "sandbox123",
sandboxStatus: &runtimeapi.PodSandboxStatusResponse{
Status: &runtimeapi.PodSandboxStatus{
Annotations: map[string]string{
"some.annotation": "value",
WorkloadsAnnotationPrefix + "management": `{"effect": "PreferredDuringScheduling"}`,
},
},
},
expected: true,
},
{
name: "managed pod with empty annotations but has workload prefix",
podSandboxID: "sandbox123",
sandboxStatus: &runtimeapi.PodSandboxStatusResponse{
Status: &runtimeapi.PodSandboxStatus{
Annotations: map[string]string{
WorkloadsAnnotationPrefix + "throttle": "",
},
},
},
expected: true,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
mockService := &mockRuntimeService{
sandboxStatus: tc.sandboxStatus,
err: tc.err,
}

result := IsManagedPodFromRuntimeService(ctx, mockService, tc.podSandboxID)
if result != tc.expected {
t.Errorf("IsManagedPodFromRuntimeService() = %v, expected %v", result, tc.expected)
}
})
}
}