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