github.com/DaoCloud/dao@v0.0.0-20161212064103-c3dbfd13ee36/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: "显示一个或多个服务的详细信息", 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 参数和人工可读格式不兼容") 39 } 40 return runInspect(dockerCli, opts) 41 }, 42 } 43 44 flags := cmd.Flags() 45 flags.StringVarP(&opts.format, "format", "f", "", "通过指定的Go语言模板格式化命令输出内容。") 46 flags.BoolVar(&opts.pretty, "pretty", false, "通过人工可读的格式输出命令信息。") 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("错误: 没有该服务 %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, "名称:\t\t%s\n", service.Spec.Name) 90 if service.Spec.Labels != nil { 91 fmt.Fprintln(out, "标签:") 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, "模式:\t\t全局") 99 } else { 100 fmt.Fprintln(out, "模式:\t\t副本") 101 if service.Spec.Mode.Replicated.Replicas != nil { 102 fmt.Fprintf(out, " 副本个数:\t%d\n", *service.Spec.Mode.Replicated.Replicas) 103 } 104 } 105 106 if service.UpdateStatus.State != "" { 107 fmt.Fprintln(out, "更新状态:") 108 fmt.Fprintf(out, " 状态:\t\t%s\n", service.UpdateStatus.State) 109 fmt.Fprintf(out, " 启动时间:\t%s 之前\n", strings.ToLower(units.HumanDuration(time.Since(service.UpdateStatus.StartedAt)))) 110 if service.UpdateStatus.State == swarm.UpdateStateCompleted { 111 fmt.Fprintf(out, " 完成时间:\t%s 之前\n", strings.ToLower(units.HumanDuration(time.Since(service.UpdateStatus.CompletedAt)))) 112 } 113 fmt.Fprintf(out, " 更新消息:\t%s\n", service.UpdateStatus.Message) 114 } 115 116 fmt.Fprintln(out, "放置策略:") 117 if service.Spec.TaskTemplate.Placement != nil && len(service.Spec.TaskTemplate.Placement.Constraints) > 0 { 118 ioutils.FprintfIfNotEmpty(out, " 限制\t: %s\n", strings.Join(service.Spec.TaskTemplate.Placement.Constraints, ", ")) 119 } 120 if service.Spec.UpdateConfig != nil { 121 fmt.Fprintf(out, "更新配置:\n") 122 fmt.Fprintf(out, " 并行数:\t%d\n", service.Spec.UpdateConfig.Parallelism) 123 if service.Spec.UpdateConfig.Delay.Nanoseconds() > 0 { 124 fmt.Fprintf(out, " 更新延迟:\t\t%s\n", service.Spec.UpdateConfig.Delay) 125 } 126 fmt.Fprintf(out, " 出错重启策略:\t%s\n", service.Spec.UpdateConfig.FailureAction) 127 } 128 129 fmt.Fprintf(out, "容器配置:\n") 130 printContainerSpec(out, service.Spec.TaskTemplate.ContainerSpec) 131 132 resources := service.Spec.TaskTemplate.Resources 133 if resources != nil { 134 fmt.Fprintln(out, "资源:") 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, " 内存资源:\t%s\n", units.BytesSize(float64(r.MemoryBytes))) 145 } 146 } 147 printResources(out, "资源预留", resources.Reservations) 148 printResources(out, "资源限制", resources.Limits) 149 } 150 if len(service.Spec.Networks) > 0 { 151 fmt.Fprintf(out, "网络:") 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, "端口:") 160 for _, port := range service.Endpoint.Ports { 161 ioutils.FprintfIfNotEmpty(out, " 名称 = %s\n", port.Name) 162 fmt.Fprintf(out, " 协议 = %s\n", port.Protocol) 163 fmt.Fprintf(out, " 目标端口 = %d\n", port.TargetPort) 164 fmt.Fprintf(out, " 暴露端口 = %d\n", port.PublishedPort) 165 } 166 } 167 } 168 169 func printContainerSpec(out io.Writer, containerSpec swarm.ContainerSpec) { 170 fmt.Fprintf(out, " 镜像:\t\t%s\n", containerSpec.Image) 171 if len(containerSpec.Args) > 0 { 172 fmt.Fprintf(out, " 参数:\t\t%s\n", strings.Join(containerSpec.Args, " ")) 173 } 174 if len(containerSpec.Env) > 0 { 175 fmt.Fprintf(out, " 环境变量:\t\t%s\n", strings.Join(containerSpec.Env, " ")) 176 } 177 ioutils.FprintfIfNotEmpty(out, " 目录\t\t%s\n", containerSpec.Dir) 178 ioutils.FprintfIfNotEmpty(out, " 用户\t\t%s\n", containerSpec.User) 179 if len(containerSpec.Mounts) > 0 { 180 fmt.Fprintln(out, " 挂载:") 181 for _, v := range containerSpec.Mounts { 182 fmt.Fprintf(out, " 目标地址 = %s\n", v.Target) 183 fmt.Fprintf(out, " 源地址 = %s\n", v.Source) 184 fmt.Fprintf(out, " 只读 = %v\n", v.ReadOnly) 185 fmt.Fprintf(out, " 挂载类型 = %v\n", v.Type) 186 } 187 } 188 }