Specifying container in PodExecOptions isn't working

151 views Asked by At

I want to do the equivalent to kubectl exec -it POD -c CONTAINER -- CMD in Golang. The pod has multiple containers, so I need to specify the container.

Here's the relevant snippets from my code:

import (
...
    v1 "k8s.io/api/core/v1"
...
)


....

    podName := "<pod-name-here>"
    containerName := "<container-name-goes-here"
    namespace := "<namespace-here>"
    cmd := []string{"/bin/sh", "-c", "echo Hello World"}

    req := clientset.CoreV1().RESTClient().
        Post().
        Resource("pods").
        Name(podName).
        Namespace(namespace).
        SubResource("exec").
        VersionedParams(&v1.PodExecOptions{
            Command:   cmd,
            Container: containerName,
            Stdin:     false,
            Stdout:    true,
            Stderr:    true,
            TTY:       false,
        }, metav1.ParameterCodec)


    // Create buffers to capture stdout and stderr
    var stdout, stderr bytes.Buffer

    exec, err := remotecommand.NewSPDYExecutor(config, "POST", req.URL())
    if err != nil {
        panic(err)
    }

    // Create a context to manage the stream's lifecycle
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel() // Cancel the context when done to clean up resources

    err = exec.StreamWithContext(ctx, remotecommand.StreamOptions{
        Stdin:  nil,
        Stdout: &stdout, // Capture stdout here
        Stderr: &stderr, // Capture stderr here
        Tty:    false,
    })
    if err != nil {
        panic(err)
    }

Although I keep getting this error

    panic: a container name must be specified for pod POD, choose one of: [CONTAINER1 CONTAINER2 CONTAINER3]

I'm specifying the container name in PodExecOptions, so why am I getting this error?

Any suggestions on how to troubleshoot?

1

There are 1 answers

0
jersey bean On

I found this works:

import (
...
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
...
)

    req := clientset.CoreV1().RESTClient().
        Post().
        Resource("pods").
        Name(podName).
        Namespace(namespace).
        SubResource("exec").
        Param("container", containerName).   // <--- this line is needed
        VersionedParams(&v1.PodExecOptions{
            Command: cmd,
            //Container: containerName,
            Stdin:  false,
            Stdout: true,
            Stderr: true,
            TTY:    false,
        }, metav1.ParameterCodec)

I also found this works:

import (
...
    "k8s.io/client-go/kubernetes/scheme"
...
)

    req := clientset.CoreV1().RESTClient().
        Post().
        Resource("pods").
        Name(podName).
        Namespace(namespace).
        SubResource("exec").
        VersionedParams(&v1.PodExecOptions{
            Container: containerName,
            Command:   cmd,
            Stdin:     false,
            Stdout:    true,
            Stderr:    true,
            TTY:       false,
        }, scheme.ParameterCodec)  // <--- using different codec

I couldn't find a good explanation in the docs for which codec to choose here.