github.com/fabiokung/docker@v0.11.2-0.20170222101415-4534dcd49497/cli/command/formatter/task.go (about) 1 package formatter 2 3 import ( 4 "fmt" 5 "strings" 6 "time" 7 8 "github.com/docker/distribution/reference" 9 "github.com/docker/docker/api/types/swarm" 10 "github.com/docker/docker/cli/command" 11 "github.com/docker/docker/pkg/stringid" 12 "github.com/docker/go-units" 13 ) 14 15 const ( 16 defaultTaskTableFormat = "table {{.ID}}\t{{.Name}}\t{{.Image}}\t{{.Node}}\t{{.DesiredState}}\t{{.CurrentState}}\t{{.Error}}\t{{.Ports}}" 17 18 nodeHeader = "NODE" 19 taskIDHeader = "ID" 20 desiredStateHeader = "DESIRED STATE" 21 currentStateHeader = "CURRENT STATE" 22 errorHeader = "ERROR" 23 24 maxErrLength = 30 25 ) 26 27 // NewTaskFormat returns a Format for rendering using a task Context 28 func NewTaskFormat(source string, quiet bool) Format { 29 switch source { 30 case TableFormatKey: 31 if quiet { 32 return defaultQuietFormat 33 } 34 return defaultTaskTableFormat 35 case RawFormatKey: 36 if quiet { 37 return `id: {{.ID}}` 38 } 39 return `id: {{.ID}}\nname: {{.Name}}\nimage: {{.Image}}\nnode: {{.Node}}\ndesired_state: {{.DesiredState}}\ncurrent_state: {{.CurrentState}}\nerror: {{.Error}}\nports: {{.Ports}}\n` 40 } 41 return Format(source) 42 } 43 44 // TaskWrite writes the context 45 func TaskWrite(ctx Context, tasks []swarm.Task, names map[string]string, nodes map[string]string) error { 46 render := func(format func(subContext subContext) error) error { 47 for _, task := range tasks { 48 taskCtx := &taskContext{trunc: ctx.Trunc, task: task, name: names[task.ID], node: nodes[task.ID]} 49 if err := format(taskCtx); err != nil { 50 return err 51 } 52 } 53 return nil 54 } 55 return ctx.Write(&taskContext{}, render) 56 } 57 58 type taskContext struct { 59 HeaderContext 60 trunc bool 61 task swarm.Task 62 name string 63 node string 64 } 65 66 func (c *taskContext) MarshalJSON() ([]byte, error) { 67 return marshalJSON(c) 68 } 69 70 func (c *taskContext) ID() string { 71 c.AddHeader(taskIDHeader) 72 if c.trunc { 73 return stringid.TruncateID(c.task.ID) 74 } 75 return c.task.ID 76 } 77 78 func (c *taskContext) Name() string { 79 c.AddHeader(nameHeader) 80 return c.name 81 } 82 83 func (c *taskContext) Image() string { 84 c.AddHeader(imageHeader) 85 image := c.task.Spec.ContainerSpec.Image 86 if c.trunc { 87 ref, err := reference.ParseNormalizedNamed(image) 88 if err == nil { 89 // update image string for display, (strips any digest) 90 if nt, ok := ref.(reference.NamedTagged); ok { 91 if namedTagged, err := reference.WithTag(reference.TrimNamed(nt), nt.Tag()); err == nil { 92 image = reference.FamiliarString(namedTagged) 93 } 94 } 95 } 96 } 97 return image 98 } 99 100 func (c *taskContext) Node() string { 101 c.AddHeader(nodeHeader) 102 return c.node 103 } 104 105 func (c *taskContext) DesiredState() string { 106 c.AddHeader(desiredStateHeader) 107 return command.PrettyPrint(c.task.DesiredState) 108 } 109 110 func (c *taskContext) CurrentState() string { 111 c.AddHeader(currentStateHeader) 112 return fmt.Sprintf("%s %s ago", 113 command.PrettyPrint(c.task.Status.State), 114 strings.ToLower(units.HumanDuration(time.Since(c.task.Status.Timestamp))), 115 ) 116 } 117 118 func (c *taskContext) Error() string { 119 c.AddHeader(errorHeader) 120 // Trim and quote the error message. 121 taskErr := c.task.Status.Err 122 if c.trunc && len(taskErr) > maxErrLength { 123 taskErr = fmt.Sprintf("%s…", taskErr[:maxErrLength-1]) 124 } 125 if len(taskErr) > 0 { 126 taskErr = fmt.Sprintf("\"%s\"", taskErr) 127 } 128 return taskErr 129 } 130 131 func (c *taskContext) Ports() string { 132 c.AddHeader(portsHeader) 133 if len(c.task.Status.PortStatus.Ports) == 0 { 134 return "" 135 } 136 ports := []string{} 137 for _, pConfig := range c.task.Status.PortStatus.Ports { 138 ports = append(ports, fmt.Sprintf("*:%d->%d/%s", 139 pConfig.PublishedPort, 140 pConfig.TargetPort, 141 pConfig.Protocol, 142 )) 143 } 144 return strings.Join(ports, ",") 145 }