container.go 4.9 KB

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