Skip to content

Commit 6470c8f

Browse files
fix: simplify sandbox pod lookup
Signed-off-by: Krrish <krrishrastogi00@gmail.com>
1 parent 9963d8f commit 6470c8f

5 files changed

Lines changed: 71 additions & 67 deletions

File tree

pkg/workloadmanager/handlers.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -235,13 +235,9 @@ func (s *Server) createSandbox(ctx context.Context, dynamicClient dynamic.Interf
235235
return nil, errSandboxCreationTimeout
236236
}
237237

238-
// agent-sandbox create pod with same name as sandbox if no warmpool is used
239-
// so here we try to get pod IP by sandbox name first
240-
// if warmpool is used, the pod name is stored in sandbox's annotation `agents.x-k8s.io/sandbox-pod-name`
241-
// https://github.com/kubernetes-sigs/agent-sandbox/blob/3ab7fbcd85ad0d75c6e632ecd14bcaeda5e76e1e/controllers/sandbox_controller.go#L465
242-
sandboxPodName := sandbox.Name
243-
if podName, exists := createdSandbox.Annotations[controllers.SandboxPodNameAnnotation]; exists {
244-
sandboxPodName = podName
238+
sandboxPodName := createdSandbox.Annotations[controllers.SandboxPodNameAnnotation]
239+
if sandboxPodName == "" {
240+
return nil, api.NewInternalError(fmt.Errorf("sandbox %s/%s missing pod name annotation %s", sandbox.Namespace, sandbox.Name, controllers.SandboxPodNameAnnotation))
245241
}
246242

247243
podIP, err := s.k8sClient.GetSandboxPodIP(ctx, sandbox.Namespace, sandbox.Name, sandboxPodName)

pkg/workloadmanager/handlers_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ func TestServerCreateSandbox(t *testing.T) {
111111
readyErr error
112112
updateErr error
113113
sendResult bool
114+
missingPodName bool
114115
expectErr bool
115116
expectCreateCalls int
116117
expectClaimCalls int
@@ -159,6 +160,14 @@ func TestServerCreateSandbox(t *testing.T) {
159160
expectCreateCalls: 1,
160161
expectDeleteCalls: 1,
161162
},
163+
{
164+
name: "missing pod name annotation triggers rollback",
165+
sendResult: true,
166+
missingPodName: true,
167+
expectErr: true,
168+
expectCreateCalls: 1,
169+
expectDeleteCalls: 1,
170+
},
162171
{
163172
name: "entrypoint readiness failure triggers rollback",
164173
readyErr: errors.New("connection refused"),
@@ -233,6 +242,9 @@ func TestServerCreateSandbox(t *testing.T) {
233242

234243
resultChan := make(chan SandboxStatusUpdate, 1)
235244
sb := readySandbox()
245+
if tt.missingPodName {
246+
delete(sb.Annotations, controllers.SandboxPodNameAnnotation)
247+
}
236248
if tt.sendResult {
237249
resultChan <- SandboxStatusUpdate{Sandbox: sb.DeepCopy()}
238250
}

pkg/workloadmanager/k8s_client.go

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,11 @@ import (
2121
"fmt"
2222
"time"
2323

24-
"k8s.io/klog/v2"
25-
2624
runtimev1alpha1 "github.com/volcano-sh/agentcube/pkg/apis/runtime/v1alpha1"
2725
corev1 "k8s.io/api/core/v1"
2826
apierrors "k8s.io/apimachinery/pkg/api/errors"
2927
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3028
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
31-
"k8s.io/apimachinery/pkg/labels"
3229
"k8s.io/apimachinery/pkg/runtime"
3330
"k8s.io/client-go/dynamic"
3431
"k8s.io/client-go/dynamic/dynamicinformer"
@@ -296,31 +293,19 @@ func (u *UserK8sClient) DeleteSandboxClaim(ctx context.Context, namespace, sandb
296293

297294
// GetSandboxPodIP gets the IP address of the pod corresponding to the Sandbox
298295
func (c *K8sClient) GetSandboxPodIP(_ context.Context, namespace, sandboxName, podName string) (string, error) {
299-
// If podName is provided, try to get it directly from cache first
300-
if podName != "" {
301-
pod, err := c.podLister.Pods(namespace).Get(podName)
302-
if err == nil && pod != nil {
303-
return validateAndGetPodIP(pod)
304-
}
305-
klog.Infof("failed to get sandbox pod %s/%s: %v, try get pod by sandbox-name label", namespace, podName, err)
296+
if podName == "" {
297+
return "", fmt.Errorf("sandbox %s has no pod name annotation", sandboxName)
306298
}
307-
// Find pod through label selector (sandbox-name label we set)
308-
pods, err := c.podLister.Pods(namespace).List(labels.SelectorFromSet(map[string]string{SandboxNameLabelKey: sandboxName}))
299+
300+
pod, err := c.podLister.Pods(namespace).Get(podName)
309301
if err != nil {
310-
return "", fmt.Errorf("failed to list pods from cache: %w", err)
302+
return "", fmt.Errorf("failed to get sandbox pod %s/%s: %w", namespace, podName, err)
311303
}
312-
// Find the pod that belongs to this sandbox by checking ownerReferences
313-
for _, pod := range pods {
314-
for _, ownerRef := range pod.OwnerReferences {
315-
if ownerRef.Kind == "Sandbox" && ownerRef.Name == sandboxName {
316-
if ownerRef.Controller == nil || *ownerRef.Controller {
317-
return validateAndGetPodIP(pod)
318-
}
319-
}
320-
}
304+
if pod == nil {
305+
return "", fmt.Errorf("sandbox pod %s/%s not found", namespace, podName)
321306
}
322307

323-
return "", fmt.Errorf("no pod found for sandbox %s", sandboxName)
308+
return validateAndGetPodIP(pod)
324309
}
325310

326311
// validateAndGetPodIP validates pod status and returns IP

pkg/workloadmanager/k8s_client_test.go

Lines changed: 47 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -22,28 +22,19 @@ import (
2222

2323
"github.com/stretchr/testify/assert"
2424
corev1 "k8s.io/api/core/v1"
25+
apierrors "k8s.io/apimachinery/pkg/api/errors"
2526
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2627
"k8s.io/apimachinery/pkg/labels"
28+
"k8s.io/apimachinery/pkg/runtime/schema"
2729
listersv1 "k8s.io/client-go/listers/core/v1"
2830
)
2931

30-
// Helper function to create a pod with owner reference
31-
func createPodWithOwner(name, namespace, sandboxName string, phase corev1.PodPhase, podIP string) *corev1.Pod {
32-
controller := true
32+
// Helper function to create a pod.
33+
func createPod(name, namespace string, phase corev1.PodPhase, podIP string) *corev1.Pod {
3334
return &corev1.Pod{
3435
ObjectMeta: metav1.ObjectMeta{
3536
Name: name,
3637
Namespace: namespace,
37-
Labels: map[string]string{
38-
SandboxNameLabelKey: sandboxName,
39-
},
40-
OwnerReferences: []metav1.OwnerReference{
41-
{
42-
Kind: "Sandbox",
43-
Name: sandboxName,
44-
Controller: &controller,
45-
},
46-
},
4738
},
4839
Status: corev1.PodStatus{
4940
Phase: phase,
@@ -52,6 +43,14 @@ func createPodWithOwner(name, namespace, sandboxName string, phase corev1.PodPha
5243
}
5344
}
5445

46+
func createPodWithLabel(name, namespace, sandboxName string, phase corev1.PodPhase, podIP string) *corev1.Pod {
47+
pod := createPod(name, namespace, phase, podIP)
48+
pod.Labels = map[string]string{
49+
SandboxNameLabelKey: sandboxName,
50+
}
51+
return pod
52+
}
53+
5554
// mockPodNamespaceLister is a mock implementation of listersv1.PodNamespaceLister
5655
type mockPodNamespaceLister struct {
5756
pods []*corev1.Pod
@@ -76,7 +75,7 @@ func (m *mockPodNamespaceLister) Get(name string) (*corev1.Pod, error) {
7675
return pod, nil
7776
}
7877
}
79-
return nil, nil
78+
return nil, apierrors.NewNotFound(schema.GroupResource{Resource: "pods"}, name)
8079
}
8180

8281
// mockPodLister is a mock implementation of listersv1.PodLister
@@ -118,7 +117,7 @@ func (m *mockPodLister) addPod(pod *corev1.Pod) {
118117
// TestGetSandboxPodIP_Success verifies GetSandboxPodIP returns IP when pod is present and valid
119118
func TestGetSandboxPodIP_Success(t *testing.T) {
120119
// Setup: Create a mock pod lister with a valid running pod
121-
pod := createPodWithOwner("test-pod", "test-namespace", "test-sandbox", corev1.PodRunning, "10.0.0.1")
120+
pod := createPod("test-pod", "test-namespace", corev1.PodRunning, "10.0.0.1")
122121
mockPodLister := newMockPodLister()
123122
mockPodLister.addPod(pod)
124123

@@ -127,43 +126,55 @@ func TestGetSandboxPodIP_Success(t *testing.T) {
127126
}
128127

129128
// Execute
130-
ip, err := client.GetSandboxPodIP(context.Background(), "test-namespace", "test-sandbox", "")
129+
ip, err := client.GetSandboxPodIP(context.Background(), "test-namespace", "test-sandbox", "test-pod")
131130

132131
// Verify
133132
assert.NoError(t, err, "Expected no error for valid pod")
134133
assert.Equal(t, "10.0.0.1", ip, "Expected IP to match pod IP")
135134
}
136135

137-
// TestGetSandboxPodIP_PodNotFound verifies GetSandboxPodIP returns error when pod is not found
136+
func TestGetSandboxPodIP_MissingPodName(t *testing.T) {
137+
client := &K8sClient{
138+
podLister: newMockPodLister(),
139+
}
140+
141+
ip, err := client.GetSandboxPodIP(context.Background(), "test-namespace", "test-sandbox", "")
142+
143+
assert.Error(t, err, "Expected error when pod name is empty")
144+
assert.Empty(t, ip, "Expected empty IP when error occurs")
145+
assert.Contains(t, err.Error(), "sandbox test-sandbox has no pod name annotation")
146+
}
147+
148+
// TestGetSandboxPodIP_PodNotFound verifies GetSandboxPodIP returns error when annotated pod is not found.
138149
func TestGetSandboxPodIP_PodNotFound(t *testing.T) {
139-
// Setup: Create a mock pod lister with pod that has wrong label
140150
mockPodLister := newMockPodLister()
141-
pod := &corev1.Pod{
142-
ObjectMeta: metav1.ObjectMeta{
143-
Name: "test-pod",
144-
Namespace: "test-namespace",
145-
Labels: map[string]string{
146-
SandboxNameLabelKey: "other-sandbox",
147-
},
148-
},
149-
Status: corev1.PodStatus{
150-
Phase: corev1.PodRunning,
151-
PodIP: "10.0.0.1",
152-
},
153-
}
154-
mockPodLister.addPod(pod)
155151

156152
client := &K8sClient{
157153
podLister: mockPodLister,
158154
}
159155

160156
// Execute
161-
ip, err := client.GetSandboxPodIP(context.Background(), "test-namespace", "test-sandbox", "")
157+
ip, err := client.GetSandboxPodIP(context.Background(), "test-namespace", "test-sandbox", "missing-pod")
162158

163159
// Verify
164160
assert.Error(t, err, "Expected error when pod not found")
165161
assert.Empty(t, ip, "Expected empty IP when error occurs")
166-
assert.Contains(t, err.Error(), "no pod found for sandbox test-sandbox", "Error message should indicate pod not found")
162+
assert.Contains(t, err.Error(), "failed to get sandbox pod test-namespace/missing-pod", "Error message should indicate pod not found")
163+
}
164+
165+
func TestGetSandboxPodIP_DoesNotFallbackToLabelSelector(t *testing.T) {
166+
mockPodLister := newMockPodLister()
167+
mockPodLister.addPod(createPodWithLabel("label-matched-pod", "test-namespace", "test-sandbox", corev1.PodRunning, "10.0.0.1"))
168+
169+
client := &K8sClient{
170+
podLister: mockPodLister,
171+
}
172+
173+
ip, err := client.GetSandboxPodIP(context.Background(), "test-namespace", "test-sandbox", "missing-pod")
174+
175+
assert.Error(t, err, "Expected error when annotated pod is missing")
176+
assert.Empty(t, ip, "Expected empty IP when error occurs")
177+
assert.Contains(t, err.Error(), "missing-pod")
167178
}
168179

169180
// TestGetSandboxPodIP_InvalidPodStatus verifies GetSandboxPodIP returns error when pod status is invalid
@@ -192,7 +203,7 @@ func TestGetSandboxPodIP_InvalidPodStatus(t *testing.T) {
192203
for _, tc := range testCases {
193204
t.Run(tc.name, func(t *testing.T) {
194205
// Setup: Create a mock pod lister with invalid pod status
195-
pod := createPodWithOwner("test-pod", "test-namespace", "test-sandbox", tc.phase, tc.podIP)
206+
pod := createPod("test-pod", "test-namespace", tc.phase, tc.podIP)
196207
mockPodLister := newMockPodLister()
197208
mockPodLister.addPod(pod)
198209

@@ -201,7 +212,7 @@ func TestGetSandboxPodIP_InvalidPodStatus(t *testing.T) {
201212
}
202213

203214
// Execute
204-
ip, err := client.GetSandboxPodIP(context.Background(), "test-namespace", "test-sandbox", "")
215+
ip, err := client.GetSandboxPodIP(context.Background(), "test-namespace", "test-sandbox", "test-pod")
205216

206217
// Verify
207218
assert.Error(t, err, "Expected error for invalid pod status")

test/e2e/run_e2e.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ IFS=$'\n\t'
66
E2E_CLUSTER_NAME=${E2E_CLUSTER_NAME:-agentcube-e2e}
77
E2E_CLEAN_CLUSTER=${E2E_CLEAN_CLUSTER:-true}
88
E2E_SKIP_SETUP=${E2E_SKIP_SETUP:-false}
9-
AGENT_SANDBOX_VERSION=${AGENT_SANDBOX_VERSION:-v0.1.1}
9+
AGENT_SANDBOX_VERSION=${AGENT_SANDBOX_VERSION:-v0.3.10}
1010
WORKLOAD_MANAGER_IMAGE=${WORKLOAD_MANAGER_IMAGE:-workloadmanager:latest}
1111
ROUTER_IMAGE=${ROUTER_IMAGE:-agentcube-router:latest}
1212
PICOD_IMAGE=${PICOD_IMAGE:-picod:latest}

0 commit comments

Comments
 (0)