fix: Only port-forward to ready pods (#10610) (#22794)

Signed-off-by: Mike Bryant <mike.bryant@mettle.co.uk>
This commit is contained in:
Mike Bryant 2025-04-27 23:18:02 +01:00 committed by GitHub
parent 89f006a351
commit b2ad0122d5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 105 additions and 18 deletions

View file

@ -16,10 +16,29 @@ import (
"k8s.io/client-go/tools/portforward"
"k8s.io/client-go/transport/spdy"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/util/podutils"
"github.com/argoproj/argo-cd/v3/util/io"
)
func selectPodForPortForward(clientSet kubernetes.Interface, namespace string, podSelectors ...string) (*corev1.Pod, error) {
for _, podSelector := range podSelectors {
pods, err := clientSet.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{
LabelSelector: podSelector,
})
if err != nil {
return nil, err
}
for _, po := range pods.Items {
if po.Status.Phase == corev1.PodRunning && podutils.IsPodReady(&po) {
return &po, nil
}
}
}
return nil, fmt.Errorf("cannot find ready pod with selector: %v - use the --{component}-name flag in this command or set the environmental variable (Refer to https://argo-cd.readthedocs.io/en/stable/user-guide/environment-variables), to change the Argo CD component name in the CLI", podSelectors)
}
func PortForward(targetPort int, namespace string, overrides *clientcmd.ConfigOverrides, podSelectors ...string) (int, error) {
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig
@ -41,24 +60,9 @@ func PortForward(targetPort int, namespace string, overrides *clientcmd.ConfigOv
return -1, err
}
var pod *corev1.Pod
for _, podSelector := range podSelectors {
pods, err := clientSet.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{
LabelSelector: podSelector,
})
if err != nil {
return -1, err
}
if len(pods.Items) > 0 {
pod = &pods.Items[0]
break
}
}
if pod == nil {
return -1, fmt.Errorf("cannot find pod with selector: %v - use the --{component}-name flag in this command or set the environmental variable (Refer to https://argo-cd.readthedocs.io/en/stable/user-guide/environment-variables), to change the Argo CD component name in the CLI", podSelectors)
pod, err := selectPodForPortForward(clientSet, namespace, podSelectors...)
if err != nil {
return -1, err
}
url := clientSet.CoreV1().RESTClient().Post().

View file

@ -0,0 +1,83 @@
package kube
import (
"testing"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
)
func Test_selectPodForPortForward(t *testing.T) {
// Mock the Kubernetes client
client := fake.NewSimpleClientset(
&corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "test-pod",
Namespace: "default",
Labels: map[string]string{
"app": "test-app",
},
},
Status: corev1.PodStatus{
Conditions: []corev1.PodCondition{
{
Type: corev1.PodReady,
Status: corev1.ConditionTrue,
LastTransitionTime: metav1.Now(),
},
},
Phase: corev1.PodRunning,
},
},
&corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "test2-pod-broken",
Namespace: "default",
Labels: map[string]string{
"app": "test2",
},
},
Status: corev1.PodStatus{
Conditions: []corev1.PodCondition{
{
Type: corev1.PodReady,
Status: corev1.ConditionFalse,
LastTransitionTime: metav1.Now(),
},
},
Phase: corev1.PodFailed,
},
},
&corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "test2-pod-working",
Namespace: "default",
Labels: map[string]string{
"app": "test2",
},
},
Status: corev1.PodStatus{
Conditions: []corev1.PodCondition{
{
Type: corev1.PodReady,
Status: corev1.ConditionTrue,
LastTransitionTime: metav1.Now(),
},
},
Phase: corev1.PodRunning,
},
},
)
// Test selecting the pod
selectedPod, err := selectPodForPortForward(client, "default", "app=test-app")
require.NoError(t, err)
require.Equal(t, "test-pod", selectedPod.Name)
// Test selecting the working pod
selectedPod2, err := selectPodForPortForward(client, "default", "app=test2")
require.NoError(t, err)
require.Equal(t, "test2-pod-working", selectedPod2.Name)
}