github.com/noxiouz/docker@v0.7.3-0.20160629055221-3d231c78e8c5/api/client/service/inspect.go (about) 1 package service 2 3 import ( 4 "fmt" 5 "io" 6 "strings" 7 8 "golang.org/x/net/context" 9 10 "github.com/docker/docker/api/client" 11 "github.com/docker/docker/api/client/inspect" 12 "github.com/docker/docker/cli" 13 "github.com/docker/docker/pkg/ioutils" 14 apiclient "github.com/docker/engine-api/client" 15 "github.com/docker/engine-api/types/swarm" 16 "github.com/docker/go-units" 17 "github.com/spf13/cobra" 18 ) 19 20 type inspectOptions struct { 21 refs []string 22 format string 23 pretty bool 24 } 25 26 func newInspectCommand(dockerCli *client.DockerCli) *cobra.Command { 27 var opts inspectOptions 28 29 cmd := &cobra.Command{ 30 Use: "inspect [OPTIONS] SERVICE [SERVICE...]", 31 Short: "Inspect a service", 32 Args: cli.RequiresMinArgs(1), 33 RunE: func(cmd *cobra.Command, args []string) error { 34 opts.refs = args 35 36 if opts.pretty && len(opts.format) > 0 { 37 return fmt.Errorf("--format is incompatible with human friendly format") 38 } 39 return runInspect(dockerCli, opts) 40 }, 41 } 42 43 flags := cmd.Flags() 44 flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given go template") 45 flags.BoolVarP(&opts.pretty, "pretty", "p", false, "Print the information in a human friendly format.") 46 return cmd 47 } 48 49 func runInspect(dockerCli *client.DockerCli, opts inspectOptions) error { 50 client := dockerCli.Client() 51 ctx := context.Background() 52 53 getRef := func(ref string) (interface{}, []byte, error) { 54 service, _, err := client.ServiceInspectWithRaw(ctx, ref) 55 if err == nil || !apiclient.IsErrServiceNotFound(err) { 56 return service, nil, err 57 } 58 return nil, nil, fmt.Errorf("Error: no such service: %s", ref) 59 } 60 61 if !opts.pretty { 62 return inspect.Inspect(dockerCli.Out(), opts.refs, opts.format, getRef) 63 } 64 65 return printHumanFriendly(dockerCli.Out(), opts.refs, getRef) 66 } 67 68 func printHumanFriendly(out io.Writer, refs []string, getRef inspect.GetRefFunc) error { 69 for idx, ref := range refs { 70 obj, _, err := getRef(ref) 71 if err != nil { 72 return err 73 } 74 printService(out, obj.(swarm.Service)) 75 76 // TODO: better way to do this? 77 // print extra space between objects, but not after the last one 78 if idx+1 != len(refs) { 79 fmt.Fprintf(out, "\n\n") 80 } 81 } 82 return nil 83 } 84 85 // TODO: use a template 86 func printService(out io.Writer, service swarm.Service) { 87 fmt.Fprintf(out, "ID:\t\t%s\n", service.ID) 88 fmt.Fprintf(out, "Name:\t\t%s\n", service.Spec.Name) 89 if service.Spec.Labels != nil { 90 fmt.Fprintln(out, "Labels:") 91 for k, v := range service.Spec.Labels { 92 fmt.Fprintf(out, " - %s=%s\n", k, v) 93 } 94 } 95 96 if service.Spec.Mode.Global != nil { 97 fmt.Fprintln(out, "Mode:\t\tGlobal") 98 } else { 99 fmt.Fprintln(out, "Mode:\t\tReplicated") 100 if service.Spec.Mode.Replicated.Replicas != nil { 101 fmt.Fprintf(out, " Replicas:\t%d\n", *service.Spec.Mode.Replicated.Replicas) 102 } 103 } 104 fmt.Fprintln(out, "Placement:") 105 fmt.Fprintln(out, " Strategy:\tSpread") 106 if service.Spec.TaskTemplate.Placement != nil && len(service.Spec.TaskTemplate.Placement.Constraints) > 0 { 107 ioutils.FprintfIfNotEmpty(out, " Constraints\t: %s\n", strings.Join(service.Spec.TaskTemplate.Placement.Constraints, ", ")) 108 } 109 fmt.Fprintf(out, "UpdateConfig:\n") 110 fmt.Fprintf(out, " Parallelism:\t%d\n", service.Spec.UpdateConfig.Parallelism) 111 if service.Spec.UpdateConfig.Delay.Nanoseconds() > 0 { 112 fmt.Fprintf(out, " Delay:\t\t%s\n", service.Spec.UpdateConfig.Delay) 113 } 114 fmt.Fprintf(out, "ContainerSpec:\n") 115 printContainerSpec(out, service.Spec.TaskTemplate.ContainerSpec) 116 117 if service.Spec.TaskTemplate.Resources != nil { 118 fmt.Fprintln(out, "Resources:") 119 printResources := func(out io.Writer, r *swarm.Resources) { 120 if r.NanoCPUs != 0 { 121 fmt.Fprintf(out, " CPU:\t\t%g\n", float64(r.NanoCPUs)/1e9) 122 } 123 if r.MemoryBytes != 0 { 124 fmt.Fprintf(out, " Memory:\t\t%s\n", units.BytesSize(float64(r.MemoryBytes))) 125 } 126 } 127 if service.Spec.TaskTemplate.Resources.Reservations != nil { 128 fmt.Fprintln(out, "Reservations:") 129 printResources(out, service.Spec.TaskTemplate.Resources.Reservations) 130 } 131 if service.Spec.TaskTemplate.Resources.Limits != nil { 132 fmt.Fprintln(out, "Limits:") 133 printResources(out, service.Spec.TaskTemplate.Resources.Limits) 134 } 135 } 136 if len(service.Spec.Networks) > 0 { 137 fmt.Fprintf(out, "Networks:") 138 for _, n := range service.Spec.Networks { 139 fmt.Fprintf(out, " %s", n.Target) 140 } 141 } 142 143 if len(service.Endpoint.Ports) > 0 { 144 fmt.Fprintln(out, "Ports:") 145 for _, port := range service.Endpoint.Ports { 146 fmt.Fprintf(out, " Name = %s\n", port.Name) 147 fmt.Fprintf(out, " Protocol = %s\n", port.Protocol) 148 fmt.Fprintf(out, " TargetPort = %d\n", port.TargetPort) 149 fmt.Fprintf(out, " PublishedPort = %d\n", port.PublishedPort) 150 } 151 } 152 } 153 154 func printContainerSpec(out io.Writer, containerSpec swarm.ContainerSpec) { 155 fmt.Fprintf(out, " Image:\t\t%s\n", containerSpec.Image) 156 if len(containerSpec.Command) > 0 { 157 fmt.Fprintf(out, " Command:\t%s\n", strings.Join(containerSpec.Command, " ")) 158 } 159 if len(containerSpec.Args) > 0 { 160 fmt.Fprintf(out, " Args:\t\t%s\n", strings.Join(containerSpec.Args, " ")) 161 } 162 if len(containerSpec.Env) > 0 { 163 fmt.Fprintf(out, " Env:\t\t%s\n", strings.Join(containerSpec.Env, " ")) 164 } 165 ioutils.FprintfIfNotEmpty(out, " Dir\t\t%s\n", containerSpec.Dir) 166 ioutils.FprintfIfNotEmpty(out, " User\t\t%s\n", containerSpec.User) 167 if len(containerSpec.Mounts) > 0 { 168 fmt.Fprintln(out, " Mounts:") 169 for _, v := range containerSpec.Mounts { 170 fmt.Fprintf(out, " Target = %s\n", v.Target) 171 fmt.Fprintf(out, " Source = %s\n", v.Source) 172 fmt.Fprintf(out, " Writable = %v\n", v.Writable) 173 fmt.Fprintf(out, " Type = %v\n", v.Type) 174 } 175 } 176 }