node.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. package formatter
  2. import (
  3. "fmt"
  4. "strings"
  5. "github.com/docker/docker/api/types"
  6. "github.com/docker/docker/api/types/swarm"
  7. "github.com/docker/docker/cli/command"
  8. "github.com/docker/docker/cli/command/inspect"
  9. units "github.com/docker/go-units"
  10. )
  11. const (
  12. defaultNodeTableFormat = "table {{.ID}} {{if .Self}}*{{else}} {{ end }}\t{{.Hostname}}\t{{.Status}}\t{{.Availability}}\t{{.ManagerStatus}}"
  13. nodeInspectPrettyTemplate Format = `ID: {{.ID}}
  14. {{- if .Name }}
  15. Name: {{.Name}}
  16. {{- end }}
  17. {{- if .Labels }}
  18. Labels:
  19. {{- range $k, $v := .Labels }}
  20. - {{ $k }}{{if $v }}={{ $v }}{{ end }}
  21. {{- end }}{{ end }}
  22. Hostname: {{.Hostname}}
  23. Joined at: {{.CreatedAt}}
  24. Status:
  25. State: {{.StatusState}}
  26. {{- if .HasStatusMessage}}
  27. Message: {{.StatusMessage}}
  28. {{- end}}
  29. Availability: {{.SpecAvailability}}
  30. {{- if .Status.Addr}}
  31. Address: {{.StatusAddr}}
  32. {{- end}}
  33. {{- if .HasManagerStatus}}
  34. Manager Status:
  35. Address: {{.ManagerStatusAddr}}
  36. Raft Status: {{.ManagerStatusReachability}}
  37. {{- if .IsManagerStatusLeader}}
  38. Leader: Yes
  39. {{- else}}
  40. Leader: No
  41. {{- end}}
  42. {{- end}}
  43. Platform:
  44. Operating System: {{.PlatformOS}}
  45. Architecture: {{.PlatformArchitecture}}
  46. Resources:
  47. CPUs: {{.ResourceNanoCPUs}}
  48. Memory: {{.ResourceMemory}}
  49. {{- if .HasEnginePlugins}}
  50. Plugins:
  51. {{- range $k, $v := .EnginePlugins }}
  52. {{ $k }}:{{if $v }} {{ $v }}{{ end }}
  53. {{- end }}
  54. {{- end }}
  55. Engine Version: {{.EngineVersion}}
  56. {{- if .EngineLabels}}
  57. Engine Labels:
  58. {{- range $k, $v := .EngineLabels }}
  59. - {{ $k }}{{if $v }}={{ $v }}{{ end }}
  60. {{- end }}{{- end }}
  61. `
  62. nodeIDHeader = "ID"
  63. selfHeader = ""
  64. hostnameHeader = "HOSTNAME"
  65. availabilityHeader = "AVAILABILITY"
  66. managerStatusHeader = "MANAGER STATUS"
  67. )
  68. // NewNodeFormat returns a Format for rendering using a node Context
  69. func NewNodeFormat(source string, quiet bool) Format {
  70. switch source {
  71. case PrettyFormatKey:
  72. return nodeInspectPrettyTemplate
  73. case TableFormatKey:
  74. if quiet {
  75. return defaultQuietFormat
  76. }
  77. return defaultNodeTableFormat
  78. case RawFormatKey:
  79. if quiet {
  80. return `node_id: {{.ID}}`
  81. }
  82. return `node_id: {{.ID}}\nhostname: {{.Hostname}}\nstatus: {{.Status}}\navailability: {{.Availability}}\nmanager_status: {{.ManagerStatus}}\n`
  83. }
  84. return Format(source)
  85. }
  86. // NodeWrite writes the context
  87. func NodeWrite(ctx Context, nodes []swarm.Node, info types.Info) error {
  88. render := func(format func(subContext subContext) error) error {
  89. for _, node := range nodes {
  90. nodeCtx := &nodeContext{n: node, info: info}
  91. if err := format(nodeCtx); err != nil {
  92. return err
  93. }
  94. }
  95. return nil
  96. }
  97. nodeCtx := nodeContext{}
  98. nodeCtx.header = nodeHeaderContext{
  99. "ID": nodeIDHeader,
  100. "Self": selfHeader,
  101. "Hostname": hostnameHeader,
  102. "Status": statusHeader,
  103. "Availability": availabilityHeader,
  104. "ManagerStatus": managerStatusHeader,
  105. }
  106. return ctx.Write(&nodeCtx, render)
  107. }
  108. type nodeHeaderContext map[string]string
  109. type nodeContext struct {
  110. HeaderContext
  111. n swarm.Node
  112. info types.Info
  113. }
  114. func (c *nodeContext) MarshalJSON() ([]byte, error) {
  115. return marshalJSON(c)
  116. }
  117. func (c *nodeContext) ID() string {
  118. return c.n.ID
  119. }
  120. func (c *nodeContext) Self() bool {
  121. return c.n.ID == c.info.Swarm.NodeID
  122. }
  123. func (c *nodeContext) Hostname() string {
  124. return c.n.Description.Hostname
  125. }
  126. func (c *nodeContext) Status() string {
  127. return command.PrettyPrint(string(c.n.Status.State))
  128. }
  129. func (c *nodeContext) Availability() string {
  130. return command.PrettyPrint(string(c.n.Spec.Availability))
  131. }
  132. func (c *nodeContext) ManagerStatus() string {
  133. reachability := ""
  134. if c.n.ManagerStatus != nil {
  135. if c.n.ManagerStatus.Leader {
  136. reachability = "Leader"
  137. } else {
  138. reachability = string(c.n.ManagerStatus.Reachability)
  139. }
  140. }
  141. return command.PrettyPrint(reachability)
  142. }
  143. // NodeInspectWrite renders the context for a list of services
  144. func NodeInspectWrite(ctx Context, refs []string, getRef inspect.GetRefFunc) error {
  145. if ctx.Format != nodeInspectPrettyTemplate {
  146. return inspect.Inspect(ctx.Output, refs, string(ctx.Format), getRef)
  147. }
  148. render := func(format func(subContext subContext) error) error {
  149. for _, ref := range refs {
  150. nodeI, _, err := getRef(ref)
  151. if err != nil {
  152. return err
  153. }
  154. node, ok := nodeI.(swarm.Node)
  155. if !ok {
  156. return fmt.Errorf("got wrong object to inspect :%v", ok)
  157. }
  158. if err := format(&nodeInspectContext{Node: node}); err != nil {
  159. return err
  160. }
  161. }
  162. return nil
  163. }
  164. return ctx.Write(&nodeInspectContext{}, render)
  165. }
  166. type nodeInspectContext struct {
  167. swarm.Node
  168. subContext
  169. }
  170. func (ctx *nodeInspectContext) ID() string {
  171. return ctx.Node.ID
  172. }
  173. func (ctx *nodeInspectContext) Name() string {
  174. return ctx.Node.Spec.Name
  175. }
  176. func (ctx *nodeInspectContext) Labels() map[string]string {
  177. return ctx.Node.Spec.Labels
  178. }
  179. func (ctx *nodeInspectContext) Hostname() string {
  180. return ctx.Node.Description.Hostname
  181. }
  182. func (ctx *nodeInspectContext) CreatedAt() string {
  183. return command.PrettyPrint(ctx.Node.CreatedAt)
  184. }
  185. func (ctx *nodeInspectContext) StatusState() string {
  186. return command.PrettyPrint(ctx.Node.Status.State)
  187. }
  188. func (ctx *nodeInspectContext) HasStatusMessage() bool {
  189. return ctx.Node.Status.Message != ""
  190. }
  191. func (ctx *nodeInspectContext) StatusMessage() string {
  192. return command.PrettyPrint(ctx.Node.Status.Message)
  193. }
  194. func (ctx *nodeInspectContext) SpecAvailability() string {
  195. return command.PrettyPrint(ctx.Node.Spec.Availability)
  196. }
  197. func (ctx *nodeInspectContext) HasStatusAddr() bool {
  198. return ctx.Node.Status.Addr != ""
  199. }
  200. func (ctx *nodeInspectContext) StatusAddr() string {
  201. return ctx.Node.Status.Addr
  202. }
  203. func (ctx *nodeInspectContext) HasManagerStatus() bool {
  204. return ctx.Node.ManagerStatus != nil
  205. }
  206. func (ctx *nodeInspectContext) ManagerStatusAddr() string {
  207. return ctx.Node.ManagerStatus.Addr
  208. }
  209. func (ctx *nodeInspectContext) ManagerStatusReachability() string {
  210. return command.PrettyPrint(ctx.Node.ManagerStatus.Reachability)
  211. }
  212. func (ctx *nodeInspectContext) IsManagerStatusLeader() bool {
  213. return ctx.Node.ManagerStatus.Leader
  214. }
  215. func (ctx *nodeInspectContext) PlatformOS() string {
  216. return ctx.Node.Description.Platform.OS
  217. }
  218. func (ctx *nodeInspectContext) PlatformArchitecture() string {
  219. return ctx.Node.Description.Platform.Architecture
  220. }
  221. func (ctx *nodeInspectContext) ResourceNanoCPUs() int {
  222. if ctx.Node.Description.Resources.NanoCPUs == 0 {
  223. return int(0)
  224. }
  225. return int(ctx.Node.Description.Resources.NanoCPUs) / 1e9
  226. }
  227. func (ctx *nodeInspectContext) ResourceMemory() string {
  228. if ctx.Node.Description.Resources.MemoryBytes == 0 {
  229. return ""
  230. }
  231. return units.BytesSize(float64(ctx.Node.Description.Resources.MemoryBytes))
  232. }
  233. func (ctx *nodeInspectContext) HasEnginePlugins() bool {
  234. return len(ctx.Node.Description.Engine.Plugins) > 0
  235. }
  236. func (ctx *nodeInspectContext) EnginePlugins() map[string]string {
  237. pluginMap := map[string][]string{}
  238. for _, p := range ctx.Node.Description.Engine.Plugins {
  239. pluginMap[p.Type] = append(pluginMap[p.Type], p.Name)
  240. }
  241. pluginNamesByType := map[string]string{}
  242. for k, v := range pluginMap {
  243. pluginNamesByType[k] = strings.Join(v, ", ")
  244. }
  245. return pluginNamesByType
  246. }
  247. func (ctx *nodeInspectContext) EngineLabels() map[string]string {
  248. return ctx.Node.Description.Engine.Labels
  249. }
  250. func (ctx *nodeInspectContext) EngineVersion() string {
  251. return ctx.Node.Description.Engine.EngineVersion
  252. }