container.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. package formatter
  2. import (
  3. "fmt"
  4. "strconv"
  5. "strings"
  6. "time"
  7. "github.com/docker/docker/api"
  8. "github.com/docker/docker/api/types"
  9. "github.com/docker/docker/pkg/stringid"
  10. "github.com/docker/docker/pkg/stringutils"
  11. units "github.com/docker/go-units"
  12. )
  13. const (
  14. defaultContainerTableFormat = "table {{.ID}}\t{{.Image}}\t{{.Command}}\t{{.RunningFor}} ago\t{{.Status}}\t{{.Ports}}\t{{.Names}}"
  15. containerIDHeader = "CONTAINER ID"
  16. namesHeader = "NAMES"
  17. commandHeader = "COMMAND"
  18. runningForHeader = "CREATED"
  19. statusHeader = "STATUS"
  20. portsHeader = "PORTS"
  21. mountsHeader = "MOUNTS"
  22. localVolumes = "LOCAL VOLUMES"
  23. )
  24. // NewContainerFormat returns a Format for rendering using a Context
  25. func NewContainerFormat(source string, quiet bool, size bool) Format {
  26. switch source {
  27. case TableFormatKey:
  28. if quiet {
  29. return defaultQuietFormat
  30. }
  31. format := defaultContainerTableFormat
  32. if size {
  33. format += `\t{{.Size}}`
  34. }
  35. return Format(format)
  36. case RawFormatKey:
  37. if quiet {
  38. return `container_id: {{.ID}}`
  39. }
  40. format := `container_id: {{.ID}}
  41. image: {{.Image}}
  42. command: {{.Command}}
  43. created_at: {{.CreatedAt}}
  44. status: {{- pad .Status 1 0}}
  45. names: {{.Names}}
  46. labels: {{- pad .Labels 1 0}}
  47. ports: {{- pad .Ports 1 0}}
  48. `
  49. if size {
  50. format += `size: {{.Size}}\n`
  51. }
  52. return Format(format)
  53. }
  54. return Format(source)
  55. }
  56. // ContainerWrite renders the context for a list of containers
  57. func ContainerWrite(ctx Context, containers []types.Container) error {
  58. render := func(format func(subContext subContext) error) error {
  59. for _, container := range containers {
  60. err := format(&containerContext{trunc: ctx.Trunc, c: container})
  61. if err != nil {
  62. return err
  63. }
  64. }
  65. return nil
  66. }
  67. return ctx.Write(&containerContext{}, render)
  68. }
  69. type containerContext struct {
  70. HeaderContext
  71. trunc bool
  72. c types.Container
  73. }
  74. func (c *containerContext) MarshalJSON() ([]byte, error) {
  75. return marshalJSON(c)
  76. }
  77. func (c *containerContext) ID() string {
  78. c.AddHeader(containerIDHeader)
  79. if c.trunc {
  80. return stringid.TruncateID(c.c.ID)
  81. }
  82. return c.c.ID
  83. }
  84. func (c *containerContext) Names() string {
  85. c.AddHeader(namesHeader)
  86. names := stripNamePrefix(c.c.Names)
  87. if c.trunc {
  88. for _, name := range names {
  89. if len(strings.Split(name, "/")) == 1 {
  90. names = []string{name}
  91. break
  92. }
  93. }
  94. }
  95. return strings.Join(names, ",")
  96. }
  97. func (c *containerContext) Image() string {
  98. c.AddHeader(imageHeader)
  99. if c.c.Image == "" {
  100. return "<no image>"
  101. }
  102. if c.trunc {
  103. if trunc := stringid.TruncateID(c.c.ImageID); trunc == stringid.TruncateID(c.c.Image) {
  104. return trunc
  105. }
  106. }
  107. return c.c.Image
  108. }
  109. func (c *containerContext) Command() string {
  110. c.AddHeader(commandHeader)
  111. command := c.c.Command
  112. if c.trunc {
  113. command = stringutils.Ellipsis(command, 20)
  114. }
  115. return strconv.Quote(command)
  116. }
  117. func (c *containerContext) CreatedAt() string {
  118. c.AddHeader(createdAtHeader)
  119. return time.Unix(int64(c.c.Created), 0).String()
  120. }
  121. func (c *containerContext) RunningFor() string {
  122. c.AddHeader(runningForHeader)
  123. createdAt := time.Unix(int64(c.c.Created), 0)
  124. return units.HumanDuration(time.Now().UTC().Sub(createdAt))
  125. }
  126. func (c *containerContext) Ports() string {
  127. c.AddHeader(portsHeader)
  128. return api.DisplayablePorts(c.c.Ports)
  129. }
  130. func (c *containerContext) Status() string {
  131. c.AddHeader(statusHeader)
  132. return c.c.Status
  133. }
  134. func (c *containerContext) Size() string {
  135. c.AddHeader(sizeHeader)
  136. srw := units.HumanSizeWithPrecision(float64(c.c.SizeRw), 3)
  137. sv := units.HumanSizeWithPrecision(float64(c.c.SizeRootFs), 3)
  138. sf := srw
  139. if c.c.SizeRootFs > 0 {
  140. sf = fmt.Sprintf("%s (virtual %s)", srw, sv)
  141. }
  142. return sf
  143. }
  144. func (c *containerContext) Labels() string {
  145. c.AddHeader(labelsHeader)
  146. if c.c.Labels == nil {
  147. return ""
  148. }
  149. var joinLabels []string
  150. for k, v := range c.c.Labels {
  151. joinLabels = append(joinLabels, fmt.Sprintf("%s=%s", k, v))
  152. }
  153. return strings.Join(joinLabels, ",")
  154. }
  155. func (c *containerContext) Label(name string) string {
  156. n := strings.Split(name, ".")
  157. r := strings.NewReplacer("-", " ", "_", " ")
  158. h := r.Replace(n[len(n)-1])
  159. c.AddHeader(h)
  160. if c.c.Labels == nil {
  161. return ""
  162. }
  163. return c.c.Labels[name]
  164. }
  165. func (c *containerContext) Mounts() string {
  166. c.AddHeader(mountsHeader)
  167. var name string
  168. var mounts []string
  169. for _, m := range c.c.Mounts {
  170. if m.Name == "" {
  171. name = m.Source
  172. } else {
  173. name = m.Name
  174. }
  175. if c.trunc {
  176. name = stringutils.Ellipsis(name, 15)
  177. }
  178. mounts = append(mounts, name)
  179. }
  180. return strings.Join(mounts, ",")
  181. }
  182. func (c *containerContext) LocalVolumes() string {
  183. c.AddHeader(localVolumes)
  184. count := 0
  185. for _, m := range c.c.Mounts {
  186. if m.Driver == "local" {
  187. count++
  188. }
  189. }
  190. return fmt.Sprintf("%d", count)
  191. }