github.com/portworx/docker@v1.12.1/api/client/node/inspect.go (about)

     1  package node
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"sort"
     7  	"strings"
     8  
     9  	"github.com/docker/docker/api/client"
    10  	"github.com/docker/docker/api/client/inspect"
    11  	"github.com/docker/docker/cli"
    12  	"github.com/docker/docker/pkg/ioutils"
    13  	"github.com/docker/engine-api/types/swarm"
    14  	"github.com/docker/go-units"
    15  	"github.com/spf13/cobra"
    16  	"golang.org/x/net/context"
    17  )
    18  
    19  type inspectOptions struct {
    20  	nodeIds []string
    21  	format  string
    22  	pretty  bool
    23  }
    24  
    25  func newInspectCommand(dockerCli *client.DockerCli) *cobra.Command {
    26  	var opts inspectOptions
    27  
    28  	cmd := &cobra.Command{
    29  		Use:   "inspect [OPTIONS] self|NODE [NODE...]",
    30  		Short: "Display detailed information on one or more nodes",
    31  		Args:  cli.RequiresMinArgs(1),
    32  		RunE: func(cmd *cobra.Command, args []string) error {
    33  			opts.nodeIds = args
    34  			return runInspect(dockerCli, opts)
    35  		},
    36  	}
    37  
    38  	flags := cmd.Flags()
    39  	flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given go template")
    40  	flags.BoolVar(&opts.pretty, "pretty", false, "Print the information in a human friendly format.")
    41  	return cmd
    42  }
    43  
    44  func runInspect(dockerCli *client.DockerCli, opts inspectOptions) error {
    45  	client := dockerCli.Client()
    46  	ctx := context.Background()
    47  	getRef := func(ref string) (interface{}, []byte, error) {
    48  		nodeRef, err := Reference(client, ctx, ref)
    49  		if err != nil {
    50  			return nil, nil, err
    51  		}
    52  		node, _, err := client.NodeInspectWithRaw(ctx, nodeRef)
    53  		return node, nil, err
    54  	}
    55  
    56  	if !opts.pretty {
    57  		return inspect.Inspect(dockerCli.Out(), opts.nodeIds, opts.format, getRef)
    58  	}
    59  	return printHumanFriendly(dockerCli.Out(), opts.nodeIds, getRef)
    60  }
    61  
    62  func printHumanFriendly(out io.Writer, refs []string, getRef inspect.GetRefFunc) error {
    63  	for idx, ref := range refs {
    64  		obj, _, err := getRef(ref)
    65  		if err != nil {
    66  			return err
    67  		}
    68  		printNode(out, obj.(swarm.Node))
    69  
    70  		// TODO: better way to do this?
    71  		// print extra space between objects, but not after the last one
    72  		if idx+1 != len(refs) {
    73  			fmt.Fprintf(out, "\n\n")
    74  		}
    75  	}
    76  	return nil
    77  }
    78  
    79  // TODO: use a template
    80  func printNode(out io.Writer, node swarm.Node) {
    81  	fmt.Fprintf(out, "ID:\t\t\t%s\n", node.ID)
    82  	ioutils.FprintfIfNotEmpty(out, "Name:\t\t\t%s\n", node.Spec.Name)
    83  	if node.Spec.Labels != nil {
    84  		fmt.Fprintln(out, "Labels:")
    85  		for k, v := range node.Spec.Labels {
    86  			fmt.Fprintf(out, " - %s = %s\n", k, v)
    87  		}
    88  	}
    89  
    90  	ioutils.FprintfIfNotEmpty(out, "Hostname:\t\t%s\n", node.Description.Hostname)
    91  	fmt.Fprintf(out, "Joined at:\t\t%s\n", client.PrettyPrint(node.CreatedAt))
    92  	fmt.Fprintln(out, "Status:")
    93  	fmt.Fprintf(out, " State:\t\t\t%s\n", client.PrettyPrint(node.Status.State))
    94  	ioutils.FprintfIfNotEmpty(out, " Message:\t\t%s\n", client.PrettyPrint(node.Status.Message))
    95  	fmt.Fprintf(out, " Availability:\t\t%s\n", client.PrettyPrint(node.Spec.Availability))
    96  
    97  	if node.ManagerStatus != nil {
    98  		fmt.Fprintln(out, "Manager Status:")
    99  		fmt.Fprintf(out, " Address:\t\t%s\n", node.ManagerStatus.Addr)
   100  		fmt.Fprintf(out, " Raft Status:\t\t%s\n", client.PrettyPrint(node.ManagerStatus.Reachability))
   101  		leader := "No"
   102  		if node.ManagerStatus.Leader {
   103  			leader = "Yes"
   104  		}
   105  		fmt.Fprintf(out, " Leader:\t\t%s\n", leader)
   106  	}
   107  
   108  	fmt.Fprintln(out, "Platform:")
   109  	fmt.Fprintf(out, " Operating System:\t%s\n", node.Description.Platform.OS)
   110  	fmt.Fprintf(out, " Architecture:\t\t%s\n", node.Description.Platform.Architecture)
   111  
   112  	fmt.Fprintln(out, "Resources:")
   113  	fmt.Fprintf(out, " CPUs:\t\t\t%d\n", node.Description.Resources.NanoCPUs/1e9)
   114  	fmt.Fprintf(out, " Memory:\t\t%s\n", units.BytesSize(float64(node.Description.Resources.MemoryBytes)))
   115  
   116  	var pluginTypes []string
   117  	pluginNamesByType := map[string][]string{}
   118  	for _, p := range node.Description.Engine.Plugins {
   119  		// append to pluginTypes only if not done previously
   120  		if _, ok := pluginNamesByType[p.Type]; !ok {
   121  			pluginTypes = append(pluginTypes, p.Type)
   122  		}
   123  		pluginNamesByType[p.Type] = append(pluginNamesByType[p.Type], p.Name)
   124  	}
   125  
   126  	if len(pluginTypes) > 0 {
   127  		fmt.Fprintln(out, "Plugins:")
   128  		sort.Strings(pluginTypes) // ensure stable output
   129  		for _, pluginType := range pluginTypes {
   130  			fmt.Fprintf(out, "  %s:\t\t%s\n", pluginType, strings.Join(pluginNamesByType[pluginType], ", "))
   131  		}
   132  	}
   133  	fmt.Fprintf(out, "Engine Version:\t\t%s\n", node.Description.Engine.EngineVersion)
   134  
   135  	if len(node.Description.Engine.Labels) != 0 {
   136  		fmt.Fprintln(out, "Engine Labels:")
   137  		for k, v := range node.Description.Engine.Labels {
   138  			fmt.Fprintf(out, " - %s = %s", k, v)
   139  		}
   140  	}
   141  
   142  }