github.com/xeptore/docker-cli@v20.10.14+incompatible/cli/command/stack/kubernetes/ps.go (about) 1 package kubernetes 2 3 import ( 4 "fmt" 5 "sort" 6 7 "github.com/docker/cli/cli/command" 8 "github.com/docker/cli/cli/command/stack/formatter" 9 "github.com/docker/cli/cli/command/stack/options" 10 "github.com/docker/cli/cli/command/task" 11 "github.com/docker/docker/api/types/swarm" 12 apiv1 "k8s.io/api/core/v1" 13 apierrs "k8s.io/apimachinery/pkg/api/errors" 14 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 15 corev1 "k8s.io/client-go/kubernetes/typed/core/v1" 16 ) 17 18 var supportedPSFilters = map[string]bool{ 19 "name": true, 20 "service": true, 21 "node": true, 22 } 23 24 // RunPS is the kubernetes implementation of docker stack ps 25 func RunPS(dockerCli *KubeCli, options options.PS) error { 26 filters := options.Filter.Value() 27 if err := filters.Validate(supportedPSFilters); err != nil { 28 return err 29 } 30 client, err := dockerCli.composeClient() 31 if err != nil { 32 return err 33 } 34 stacks, err := client.Stacks(false) 35 if err != nil { 36 return err 37 } 38 stackName := options.Namespace 39 _, err = stacks.Get(stackName) 40 if apierrs.IsNotFound(err) { 41 return fmt.Errorf("nothing found in stack: %s", stackName) 42 } 43 if err != nil { 44 return err 45 } 46 pods, err := fetchPods(stackName, client.Pods(), filters) 47 if err != nil { 48 return err 49 } 50 if len(pods) == 0 { 51 return fmt.Errorf("nothing found in stack: %s", stackName) 52 } 53 return printTasks(dockerCli, options, stackName, client, pods) 54 } 55 56 func printTasks(dockerCli command.Cli, options options.PS, namespace string, client corev1.NodesGetter, pods []apiv1.Pod) error { 57 format := options.Format 58 if format == "" { 59 format = task.DefaultFormat(dockerCli.ConfigFile(), options.Quiet) 60 } 61 62 tasks := make([]swarm.Task, len(pods)) 63 for i, pod := range pods { 64 tasks[i] = podToTask(pod) 65 } 66 sort.Stable(tasksBySlot(tasks)) 67 68 names := map[string]string{} 69 nodes := map[string]string{} 70 71 n, err := listNodes(client, options.NoResolve) 72 if err != nil { 73 return err 74 } 75 for i, task := range tasks { 76 nodeValue, err := resolveNode(pods[i].Spec.NodeName, n, options.NoResolve) 77 if err != nil { 78 return err 79 } 80 names[task.ID] = fmt.Sprintf("%s_%s", namespace, pods[i].Name) 81 nodes[task.ID] = nodeValue 82 } 83 84 tasksCtx := formatter.Context{ 85 Output: dockerCli.Out(), 86 Format: task.NewTaskFormat(format, options.Quiet), 87 Trunc: !options.NoTrunc, 88 } 89 90 return task.FormatWrite(tasksCtx, tasks, names, nodes) 91 } 92 93 func resolveNode(name string, nodes *apiv1.NodeList, noResolve bool) (string, error) { 94 // Here we have a name and we need to resolve its identifier. To mimic swarm behavior 95 // we need to resolve to the id when noResolve is set, otherwise we return the name. 96 if noResolve { 97 for _, node := range nodes.Items { 98 if node.Name == name { 99 return string(node.UID), nil 100 } 101 } 102 return "", fmt.Errorf("could not find node '%s'", name) 103 } 104 return name, nil 105 } 106 107 func listNodes(client corev1.NodesGetter, noResolve bool) (*apiv1.NodeList, error) { 108 if noResolve { 109 return client.Nodes().List(metav1.ListOptions{}) 110 } 111 return nil, nil 112 }