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  }