DockerCLI/cli/command/stack/kubernetes/ps.go

113 lines
2.9 KiB
Go

package kubernetes
import (
"fmt"
"sort"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/stack/formatter"
"github.com/docker/cli/cli/command/stack/options"
"github.com/docker/cli/cli/command/task"
"github.com/docker/docker/api/types/swarm"
apiv1 "k8s.io/api/core/v1"
apierrs "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
)
var supportedPSFilters = map[string]bool{
"name": true,
"service": true,
"node": true,
}
// RunPS is the kubernetes implementation of docker stack ps
func RunPS(dockerCli *KubeCli, options options.PS) error {
filters := options.Filter.Value()
if err := filters.Validate(supportedPSFilters); err != nil {
return err
}
client, err := dockerCli.composeClient()
if err != nil {
return err
}
stacks, err := client.Stacks(false)
if err != nil {
return err
}
stackName := options.Namespace
_, err = stacks.Get(stackName)
if apierrs.IsNotFound(err) {
return fmt.Errorf("nothing found in stack: %s", stackName)
}
if err != nil {
return err
}
pods, err := fetchPods(stackName, client.Pods(), filters)
if err != nil {
return err
}
if len(pods) == 0 {
return fmt.Errorf("nothing found in stack: %s", stackName)
}
return printTasks(dockerCli, options, stackName, client, pods)
}
func printTasks(dockerCli command.Cli, options options.PS, namespace string, client corev1.NodesGetter, pods []apiv1.Pod) error {
format := options.Format
if format == "" {
format = task.DefaultFormat(dockerCli.ConfigFile(), options.Quiet)
}
tasks := make([]swarm.Task, len(pods))
for i, pod := range pods {
tasks[i] = podToTask(pod)
}
sort.Stable(tasksBySlot(tasks))
names := map[string]string{}
nodes := map[string]string{}
n, err := listNodes(client, options.NoResolve)
if err != nil {
return err
}
for i, task := range tasks {
nodeValue, err := resolveNode(pods[i].Spec.NodeName, n, options.NoResolve)
if err != nil {
return err
}
names[task.ID] = fmt.Sprintf("%s_%s", namespace, pods[i].Name)
nodes[task.ID] = nodeValue
}
tasksCtx := formatter.Context{
Output: dockerCli.Out(),
Format: task.NewTaskFormat(format, options.Quiet),
Trunc: !options.NoTrunc,
}
return task.FormatWrite(tasksCtx, tasks, names, nodes)
}
func resolveNode(name string, nodes *apiv1.NodeList, noResolve bool) (string, error) {
// Here we have a name and we need to resolve its identifier. To mimic swarm behavior
// we need to resolve to the id when noResolve is set, otherwise we return the name.
if noResolve {
for _, node := range nodes.Items {
if node.Name == name {
return string(node.UID), nil
}
}
return "", fmt.Errorf("could not find node '%s'", name)
}
return name, nil
}
func listNodes(client corev1.NodesGetter, noResolve bool) (*apiv1.NodeList, error) {
if noResolve {
return client.Nodes().List(metav1.ListOptions{})
}
return nil, nil
}