github.com/kaisenlinux/docker@v0.0.0-20230510090727-ea55db55fac7/swarmkit/cmd/swarmctl/node/inspect.go (about)

     1  package node
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"sort"
     8  	"text/tabwriter"
     9  
    10  	"github.com/docker/swarmkit/api"
    11  	"github.com/docker/swarmkit/api/genericresource"
    12  	"github.com/docker/swarmkit/cmd/swarmctl/common"
    13  	"github.com/docker/swarmkit/cmd/swarmctl/task"
    14  	"github.com/dustin/go-humanize"
    15  	"github.com/spf13/cobra"
    16  )
    17  
    18  func printNodeSummary(node *api.Node) {
    19  	w := tabwriter.NewWriter(os.Stdout, 8, 8, 8, ' ', 0)
    20  	defer func() {
    21  		// Ignore flushing errors - there's nothing we can do.
    22  		_ = w.Flush()
    23  	}()
    24  	spec := &node.Spec
    25  	desc := node.Description
    26  	if desc == nil {
    27  		desc = &api.NodeDescription{}
    28  	}
    29  	common.FprintfIfNotEmpty(w, "ID\t: %s\n", node.ID)
    30  	if node.Description != nil {
    31  		common.FprintfIfNotEmpty(w, "Hostname\t: %s\n", node.Description.Hostname)
    32  	}
    33  	if len(spec.Annotations.Labels) != 0 {
    34  		fmt.Fprint(w, "Node Labels\t:")
    35  		// sort label output for readability
    36  		var keys []string
    37  		for k := range spec.Annotations.Labels {
    38  			keys = append(keys, k)
    39  		}
    40  		sort.Strings(keys)
    41  		for _, k := range keys {
    42  			fmt.Fprintf(w, " %s=%s", k, spec.Annotations.Labels[k])
    43  		}
    44  		fmt.Fprintln(w)
    45  	}
    46  	fmt.Fprintln(w, "Status:\t")
    47  	common.FprintfIfNotEmpty(w, "  State\t: %s\n", node.Status.State.String())
    48  	common.FprintfIfNotEmpty(w, "  Message\t: %s\n", node.Status.Message)
    49  	common.FprintfIfNotEmpty(w, "  Availability\t: %s\n", spec.Availability.String())
    50  	common.FprintfIfNotEmpty(w, "  Address\t: %s\n", node.Status.Addr)
    51  
    52  	if node.ManagerStatus != nil {
    53  		fmt.Fprintln(w, "Manager status:\t")
    54  		common.FprintfIfNotEmpty(w, "  Address\t: %s\n", node.ManagerStatus.Addr)
    55  		common.FprintfIfNotEmpty(w, "  Raft status\t: %s\n", node.ManagerStatus.Reachability.String())
    56  		leader := "no"
    57  		if node.ManagerStatus.Leader {
    58  			leader = "yes"
    59  		}
    60  		common.FprintfIfNotEmpty(w, "  Leader\t: %s\n", leader)
    61  	}
    62  
    63  	if desc.Platform != nil {
    64  		fmt.Fprintln(w, "Platform:\t")
    65  		common.FprintfIfNotEmpty(w, "  Operating System\t: %s\n", desc.Platform.OS)
    66  		common.FprintfIfNotEmpty(w, "  Architecture\t: %s\n", desc.Platform.Architecture)
    67  	}
    68  
    69  	if desc.Resources != nil {
    70  		fmt.Fprintln(w, "Resources:\t")
    71  		fmt.Fprintf(w, "  CPUs\t: %d\n", desc.Resources.NanoCPUs/1e9)
    72  		fmt.Fprintf(w, "  Memory\t: %s\n", humanize.IBytes(uint64(desc.Resources.MemoryBytes)))
    73  		fmt.Fprintln(w, "  Generic Resources:\t")
    74  		for _, r := range desc.Resources.Generic {
    75  			k := genericresource.Kind(r)
    76  			v := genericresource.Value(r)
    77  			fmt.Fprintf(w, "    %s\t: %s\n", k, v)
    78  		}
    79  	}
    80  
    81  	if desc.Engine != nil {
    82  		fmt.Fprintln(w, "Plugins:\t")
    83  		var pluginTypes []string
    84  		pluginNamesByType := map[string][]string{}
    85  		for _, p := range desc.Engine.Plugins {
    86  			// append to pluginTypes only if not done previously
    87  			if _, ok := pluginNamesByType[p.Type]; !ok {
    88  				pluginTypes = append(pluginTypes, p.Type)
    89  			}
    90  			pluginNamesByType[p.Type] = append(pluginNamesByType[p.Type], p.Name)
    91  		}
    92  
    93  		sort.Strings(pluginTypes) // ensure stable output
    94  		for _, pluginType := range pluginTypes {
    95  			fmt.Fprintf(w, "  %s\t: %v\n", pluginType, pluginNamesByType[pluginType])
    96  		}
    97  	}
    98  
    99  	if desc.Engine != nil {
   100  		common.FprintfIfNotEmpty(w, "Engine Version\t: %s\n", desc.Engine.EngineVersion)
   101  
   102  		if len(desc.Engine.Labels) != 0 {
   103  			fmt.Fprint(w, "Engine Labels\t:")
   104  			var keys []string
   105  			for k := range desc.Engine.Labels {
   106  				keys = append(keys, k)
   107  			}
   108  			sort.Strings(keys)
   109  			for _, k := range keys {
   110  				fmt.Fprintf(w, " %s=%s", k, desc.Engine.Labels[k])
   111  			}
   112  			fmt.Fprintln(w)
   113  		}
   114  	}
   115  }
   116  
   117  var (
   118  	inspectCmd = &cobra.Command{
   119  		Use:   "inspect <node ID>",
   120  		Short: "Inspect a node",
   121  		RunE: func(cmd *cobra.Command, args []string) error {
   122  			if len(args) == 0 {
   123  				return errors.New("node ID missing")
   124  			}
   125  
   126  			if len(args) > 1 {
   127  				return errors.New("inspect command takes exactly 1 argument")
   128  			}
   129  
   130  			flags := cmd.Flags()
   131  
   132  			all, err := flags.GetBool("all")
   133  			if err != nil {
   134  				return err
   135  			}
   136  
   137  			c, err := common.Dial(cmd)
   138  			if err != nil {
   139  				return err
   140  			}
   141  
   142  			node, err := getNode(common.Context(cmd), c, args[0])
   143  			if err != nil {
   144  				return err
   145  			}
   146  
   147  			r, err := c.ListTasks(common.Context(cmd),
   148  				&api.ListTasksRequest{
   149  					Filters: &api.ListTasksRequest_Filters{
   150  						NodeIDs: []string{node.ID},
   151  					},
   152  				})
   153  			if err != nil {
   154  				return err
   155  			}
   156  
   157  			printNodeSummary(node)
   158  			if len(r.Tasks) > 0 {
   159  				fmt.Println()
   160  				task.Print(r.Tasks, all, common.NewResolver(cmd, c))
   161  			}
   162  
   163  			return nil
   164  		},
   165  	}
   166  )
   167  
   168  func init() {
   169  	inspectCmd.Flags().BoolP("all", "a", false, "Show all tasks (default shows just running)")
   170  }