3

I need to grab some pod information which will be used for some unit tests which will be run in-cluster. I need all the information which kubectl describe po gives but from an in cluster api call.

I have some working code which makes an api call to apis/metrics.k8s.io/v1beta1/pods, and have installed the metrics-server on minikube for testing which is all working and gives me output like this:

Namespace: kube-system
Pod name: heapster-rgnlj
SelfLink: /apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/heapster-rgnlj
CreationTimestamp: 2019-09-10 12:27:13 +0000 UTC
Window: 30s
Timestamp: 2019-09-10 12:26:23 +0000 UTC
Name: heapster
Cpu usage: 82166n
Mem usage: 19420Ki 
...
func getMetrics(clientset *kubernetes.Clientset, pods *PodMetricsList) error {
    data, err := clientset.RESTClient().Get().AbsPath("apis/metrics.k8s.io/v1beta1/pods").DoRaw()
    if err != nil {
        return err
    }
    err = json.Unmarshal(data, &pods)
    return err
}

func main() {

    config, err := rest.InClusterConfig()
    if err != nil {
        fmt.Println(err)
    }
    // creates the clientset
    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        fmt.Println(err)
    }
    var pods PodMetricsList
    err = getMetrics(clientset, &pods)
    if err != nil {
        fmt.Println(err)
    }

    for _, m := range pods.Items {

        fmt.Print("Namespace: ", m.Metadata.Namespace, "\n", "Pod name: ", m.Metadata.Name, "\n", )
        fmt.Print("SelfLink: ", m.Metadata.SelfLink, "\n", "CreationTimestamp: ", m.Metadata.CreationTimestamp, "\n", )
        fmt.Print("Window: ", m.Window, "\n", "Timestamp: ", m.Timestamp, "\n", )

        for _, c := range m.Containers {
            fmt.Println("Name:", c.Name)
            fmt.Println("Cpu usage:", c.Usage.CPU)
            fmt.Println("Mem usage:", c.Usage.Memory, "\n")
...

As I say, what i really need is what you'd get with a 'describe pods' type call. Having looked through the kubernetes source this NodeDescriber looks like the right type of function, but I'm slightly at a loss as to how to integrate / implement it to get the desired results.

kubernetes/pkg/printers/internalversion/describe.go

Line 2451 in 4f2d7b9

func (d *NodeDescriber) Describe(namespace, name string, describerSettings...etc)

I'm new to Go and not particularly familiar with kubernetes. Any pointers as to how to go about it would be greatly appreciated.

sensedata1
  • 31
  • 2
  • 3

3 Answers3

3

Looking at the describePod and Describe funcs from staging/src/k8s.io/kubectl/pkg/describe/versioned/describe.go should give you a better picture of how to do this. And since Describe and PodDescriber are public, you can reuse these for your use case.

You could couple this with a CoreV1Client which has a Pods func, that returns a PodInterface that has a List func which would return a list of Pod objects for the given namespace.

Those pod objects will provide the Name needed for the Describe func, the Namespace is already known, and the describe.DescriberSettings is just a struct type that you could inline to enable showing events in the Describe output.

Using the List func will only list the pods that one time. If you're interested in having this list be updated regularly, you might want to look at the Reflector and Informer patterns; both of which are largely implemented in the tools/cache package, and the docs briefly explain this concept in the Efficient detection of changes section.

Hope this helps.

Tats_innit
  • 33,991
  • 10
  • 71
  • 77
cewood
  • 1,011
  • 8
  • 11
  • Thanks for the pointers, I'll delve into this and give it a shot. I'll report back when I have something working. Cheers – sensedata1 Sep 11 '19 at 18:20
1

I didn't try, but I would suggest to start with:

1. using kubectl with --verbosity option to see the full api request

 kubectl describe pod xxx -v=8 

like:

  GET https://xx.xx.xx.xx:6443/api/v1/namespaces/default/events?fieldSelector=involvedObject.uid%3Ddd77c4aa-28e6-4bf0-8dfe-0d8610cbe9c9%2CinvolvedObject.name%3Dmy-app%2CinvolvedObject.namespace%3Ddefault

It contains fields related to your POD: fieldSelector=involvedObject.uid, involvedObject.name, involvedObject.namespace

2. I thing the good start it will be the code from github func describePod to start with.

Hope this help.

Community
  • 1
  • 1
Mark
  • 3,644
  • 6
  • 23
0

Well I ended up just writing out a struct to map the results from a /api/v1/pods query and just iterating through ranges to get what I need.

Here's the struct in case it saves anybody else some time.

type ApiV1PodMetricsList struct {
    Kind       string `json:"kind"`
    APIVersion string `json:"apiVersion"`
    Metadata   struct {
        SelfLink        string `json:"selfLink"`
        ResourceVersion string `json:"resourceVersion"`
    } `json:"metadata"`
    Items []struct {
        Metadata struct {
            Name              string    `json:"name"`
            Namespace         string    `json:"namespace"`
            SelfLink          string    `json:"selfLink"`
            UID               string    `json:"uid"`
            ResourceVersion   string    `json:"resourceVersion"`
            CreationTimestamp time.Time `json:"creationTimestamp"`
            Labels            struct {
                Run string `json:"run"`
            } `json:"labels"`
        } `json:"metadata"`
        Spec struct {
            Volumes []struct {
                Name   string `json:"name"`
                Secret struct {
                    SecretName  string `json:"secretName"`
                    DefaultMode string `json:"defaultMode"`
                } `json:"secret"`
            } `json:"volumes"`
            Containers []struct {
                Name      string `json:"name"`
                Image     string `json:"image"`
                Resources struct {
                } `json:"resources"`
                VolumeMounts []struct {
                    Name      string `json:"name"`
                    ReadOnly  string `json:"readOnly"`
                    MountPath string `json:"mountPath"`
                } `json:"volumeMounts"`
                TerminationMessagePath   string `json:"terminationMessagePath"`
                TerminationMessagePolicy string `json:"terminationMessagePolicy"`
                ImagePullPolicy          string `json:"imagePullPolicy"`
                Stdin                    string `json:"stdin"`
                StdinOnce                string `json:"stdinOnce"`
                Tty                      string `json:"tty"`
            } `json:"containers"`
            RestartPolicy                 string `json:"restartPolicy"`
            TerminationGracePeriodSeconds string `json:"terminationGracePeriodSeconds"`
            DnsPolicy                     string `json:"dnsPolicy"`
            ServiceAccountName            string `json:"serviceAccountName"`
            ServiceAccount                string `json:"serviceAccount"`
            NodeName                      string `json:"nodeName"`
            SecurityContext               struct {
            } `json:"securityContext"`
            SchedulerName string `json:"schedulerName"`
            Tolerations   []struct {
                Key               string `json:"key"`
                Operator          string `json:"operator"`
                Effect            string `json:"effect"`
                TolerationSeconds string `json:"tolerationSeconds"`
            } `json:"tolerations"`
            Priority           string `json:"priority"`
            EnableServiceLinks string `json:"enableServiceLinks"`
        } `json:"spec"`
        Status struct {
            Phase      string `json:"phase"`
            Conditions []struct {
                Type               string    `json:"type"`
                Status             string    `json:"status"`
                LastProbeTime      time.Time `json:"lastProbeTime"`
                LastTransitionTime time.Time `json:"lastTransitionTime"`
                Reason             string    `json:"reason"`
            } `json:"conditions"`
            HostIP            string `json:"hostIP"`
            PodIP             string `json:"podIP"`
            StartTime         string `json:"startTime"`
            ContainerStatuses []struct {
                Name  string `json:"name"`
                State struct {
                    Terminated struct {
                        ExitCode    string    `json:"exitCode"`
                        Reason      string    `json:"reason"`
                        StartedAt   time.Time `json:"startedAt"`
                        FinishedAt  time.Time `json:"finishedAt"`
                        ContainerID string    `json:"containerID"`
                    } `json:"terminated"`
                } `json:"state"`
                LastState struct {
                } `json:"lastState"`
                Ready        bool   `json:"ready"`
                RestartCount int64  `json:"restartCount"`
                Image        string `json:"image"`
                ImageID      string `json:"imageID"`
                ContainerID  string `json:"containerID"`
            } `json:"containerStatuses"`
            QosClass string `json:"qosClass"`
        } `json:"status"`
    } `json:"items"`
}
sensedata1
  • 31
  • 2
  • 3