Files
docker-cli/components/engine/cli/command/node/inspect.go
Vincent Demeester f6ad06ceb6 Add some unit tests to the node and swarm cli code
Start work on adding unit tests to our cli code in order to have to
write less costly integration test.

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
Upstream-commit: f151c297eb268e22dc1eb36ded0e356885f40739
Component: engine
2017-01-09 18:30:15 +01:00

145 lines
4.4 KiB
Go

package node
import (
"fmt"
"io"
"sort"
"strings"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/cli"
"github.com/docker/docker/cli/command"
"github.com/docker/docker/cli/command/inspect"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/go-units"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)
type inspectOptions struct {
nodeIds []string
format string
pretty bool
}
func newInspectCommand(dockerCli command.Cli) *cobra.Command {
var opts inspectOptions
cmd := &cobra.Command{
Use: "inspect [OPTIONS] self|NODE [NODE...]",
Short: "Display detailed information on one or more nodes",
Args: cli.RequiresMinArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
opts.nodeIds = args
return runInspect(dockerCli, opts)
},
}
flags := cmd.Flags()
flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given Go template")
flags.BoolVar(&opts.pretty, "pretty", false, "Print the information in a human friendly format.")
return cmd
}
func runInspect(dockerCli command.Cli, opts inspectOptions) error {
client := dockerCli.Client()
ctx := context.Background()
getRef := func(ref string) (interface{}, []byte, error) {
nodeRef, err := Reference(ctx, client, ref)
if err != nil {
return nil, nil, err
}
node, _, err := client.NodeInspectWithRaw(ctx, nodeRef)
return node, nil, err
}
if !opts.pretty {
return inspect.Inspect(dockerCli.Out(), opts.nodeIds, opts.format, getRef)
}
return printHumanFriendly(dockerCli.Out(), opts.nodeIds, getRef)
}
func printHumanFriendly(out io.Writer, refs []string, getRef inspect.GetRefFunc) error {
for idx, ref := range refs {
obj, _, err := getRef(ref)
if err != nil {
return err
}
printNode(out, obj.(swarm.Node))
// TODO: better way to do this?
// print extra space between objects, but not after the last one
if idx+1 != len(refs) {
fmt.Fprintf(out, "\n\n")
} else {
fmt.Fprintf(out, "\n")
}
}
return nil
}
// TODO: use a template
func printNode(out io.Writer, node swarm.Node) {
fmt.Fprintf(out, "ID:\t\t\t%s\n", node.ID)
ioutils.FprintfIfNotEmpty(out, "Name:\t\t\t%s\n", node.Spec.Name)
if node.Spec.Labels != nil {
fmt.Fprintln(out, "Labels:")
for k, v := range node.Spec.Labels {
fmt.Fprintf(out, " - %s = %s\n", k, v)
}
}
ioutils.FprintfIfNotEmpty(out, "Hostname:\t\t%s\n", node.Description.Hostname)
fmt.Fprintf(out, "Joined at:\t\t%s\n", command.PrettyPrint(node.CreatedAt))
fmt.Fprintln(out, "Status:")
fmt.Fprintf(out, " State:\t\t\t%s\n", command.PrettyPrint(node.Status.State))
ioutils.FprintfIfNotEmpty(out, " Message:\t\t%s\n", command.PrettyPrint(node.Status.Message))
fmt.Fprintf(out, " Availability:\t\t%s\n", command.PrettyPrint(node.Spec.Availability))
ioutils.FprintfIfNotEmpty(out, " Address:\t\t%s\n", command.PrettyPrint(node.Status.Addr))
if node.ManagerStatus != nil {
fmt.Fprintln(out, "Manager Status:")
fmt.Fprintf(out, " Address:\t\t%s\n", node.ManagerStatus.Addr)
fmt.Fprintf(out, " Raft Status:\t\t%s\n", command.PrettyPrint(node.ManagerStatus.Reachability))
leader := "No"
if node.ManagerStatus.Leader {
leader = "Yes"
}
fmt.Fprintf(out, " Leader:\t\t%s\n", leader)
}
fmt.Fprintln(out, "Platform:")
fmt.Fprintf(out, " Operating System:\t%s\n", node.Description.Platform.OS)
fmt.Fprintf(out, " Architecture:\t\t%s\n", node.Description.Platform.Architecture)
fmt.Fprintln(out, "Resources:")
fmt.Fprintf(out, " CPUs:\t\t\t%d\n", node.Description.Resources.NanoCPUs/1e9)
fmt.Fprintf(out, " Memory:\t\t%s\n", units.BytesSize(float64(node.Description.Resources.MemoryBytes)))
var pluginTypes []string
pluginNamesByType := map[string][]string{}
for _, p := range node.Description.Engine.Plugins {
// append to pluginTypes only if not done previously
if _, ok := pluginNamesByType[p.Type]; !ok {
pluginTypes = append(pluginTypes, p.Type)
}
pluginNamesByType[p.Type] = append(pluginNamesByType[p.Type], p.Name)
}
if len(pluginTypes) > 0 {
fmt.Fprintln(out, "Plugins:")
sort.Strings(pluginTypes) // ensure stable output
for _, pluginType := range pluginTypes {
fmt.Fprintf(out, " %s:\t\t%s\n", pluginType, strings.Join(pluginNamesByType[pluginType], ", "))
}
}
fmt.Fprintf(out, "Engine Version:\t\t%s\n", node.Description.Engine.EngineVersion)
if len(node.Description.Engine.Labels) != 0 {
fmt.Fprintln(out, "Engine Labels:")
for k, v := range node.Description.Engine.Labels {
fmt.Fprintf(out, " - %s = %s\n", k, v)
}
}
}