service.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. package formatter
  2. import (
  3. "fmt"
  4. "strings"
  5. "time"
  6. mounttypes "github.com/docker/docker/api/types/mount"
  7. "github.com/docker/docker/api/types/swarm"
  8. "github.com/docker/docker/cli/command/inspect"
  9. units "github.com/docker/go-units"
  10. )
  11. const serviceInspectPrettyTemplate Format = `
  12. ID: {{.ID}}
  13. Name: {{.Name}}
  14. {{- if .Labels }}
  15. Labels:
  16. {{- range $k, $v := .Labels }}
  17. {{ $k }}{{if $v }}={{ $v }}{{ end }}
  18. {{- end }}{{ end }}
  19. Mode:
  20. {{- if .IsModeGlobal }} Global
  21. {{- else }} Replicated
  22. {{- if .ModeReplicatedReplicas }}
  23. Replicas: {{ .ModeReplicatedReplicas }}
  24. {{- end }}{{ end }}
  25. {{- if .HasUpdateStatus }}
  26. UpdateStatus:
  27. State: {{ .UpdateStatusState }}
  28. Started: {{ .UpdateStatusStarted }}
  29. {{- if .UpdateIsCompleted }}
  30. Completed: {{ .UpdateStatusCompleted }}
  31. {{- end }}
  32. Message: {{ .UpdateStatusMessage }}
  33. {{- end }}
  34. Placement:
  35. {{- if .TaskPlacementConstraints -}}
  36. Contraints: {{ .TaskPlacementConstraints }}
  37. {{- end }}
  38. {{- if .HasUpdateConfig }}
  39. UpdateConfig:
  40. Parallelism: {{ .UpdateParallelism }}
  41. {{- if .HasUpdateDelay -}}
  42. Delay: {{ .UpdateDelay }}
  43. {{- end }}
  44. On failure: {{ .UpdateOnFailure }}
  45. {{- end }}
  46. ContainerSpec:
  47. Image: {{ .ContainerImage }}
  48. {{- if .ContainerArgs }}
  49. Args: {{ range $arg := .ContainerArgs }}{{ $arg }} {{ end }}
  50. {{- end -}}
  51. {{- if .ContainerEnv }}
  52. Env: {{ range $env := .ContainerEnv }}{{ $env }} {{ end }}
  53. {{- end -}}
  54. {{- if .ContainerWorkDir }}
  55. Dir: {{ .ContainerWorkDir }}
  56. {{- end -}}
  57. {{- if .ContainerUser }}
  58. User: {{ .ContainerUser }}
  59. {{- end }}
  60. {{- if .ContainerMounts }}
  61. Mounts:
  62. {{- end }}
  63. {{- range $mount := .ContainerMounts }}
  64. Target = {{ $mount.Target }}
  65. Source = {{ $mount.Source }}
  66. ReadOnly = {{ $mount.ReadOnly }}
  67. Type = {{ $mount.Type }}
  68. {{- end -}}
  69. {{- if .HasResources }}
  70. Resources:
  71. {{- if .HasResourceReservations }}
  72. Reservations:
  73. {{- end }}
  74. {{- if gt .ResourceReservationNanoCPUs 0.0 }}
  75. CPU: {{ .ResourceReservationNanoCPUs }}
  76. {{- end }}
  77. {{- if .ResourceReservationMemory }}
  78. Memory: {{ .ResourceReservationMemory }}
  79. {{- end }}
  80. {{- if .HasResourceLimits }}
  81. Limits:
  82. {{- end }}
  83. {{- if gt .ResourceLimitsNanoCPUs 0.0 }}
  84. CPU: {{ .ResourceLimitsNanoCPUs }}
  85. {{- end }}
  86. {{- if .ResourceLimitMemory }}
  87. Memory: {{ .ResourceLimitMemory }}
  88. {{- end }}{{ end }}
  89. {{- if .Networks }}
  90. Networks:
  91. {{- range $network := .Networks }} {{ $network }}{{ end }} {{ end }}
  92. {{- if .Ports }}
  93. Ports:
  94. {{- range $port := .Ports }}
  95. PublishedPort {{ $port.PublishedPort }}
  96. Protocol = {{ $port.Protocol }}
  97. TargetPort = {{ $port.TargetPort }}
  98. {{- end }} {{ end -}}
  99. `
  100. // NewServiceFormat returns a Format for rendering using a Context
  101. func NewServiceFormat(source string) Format {
  102. switch source {
  103. case PrettyFormatKey:
  104. return serviceInspectPrettyTemplate
  105. default:
  106. return Format(strings.TrimPrefix(source, RawFormatKey))
  107. }
  108. }
  109. // ServiceInspectWrite renders the context for a list of services
  110. func ServiceInspectWrite(ctx Context, refs []string, getRef inspect.GetRefFunc) error {
  111. if ctx.Format != serviceInspectPrettyTemplate {
  112. return inspect.Inspect(ctx.Output, refs, string(ctx.Format), getRef)
  113. }
  114. render := func(format func(subContext subContext) error) error {
  115. for _, ref := range refs {
  116. serviceI, _, err := getRef(ref)
  117. if err != nil {
  118. return err
  119. }
  120. service, ok := serviceI.(swarm.Service)
  121. if !ok {
  122. return fmt.Errorf("got wrong object to inspect")
  123. }
  124. if err := format(&serviceInspectContext{Service: service}); err != nil {
  125. return err
  126. }
  127. }
  128. return nil
  129. }
  130. return ctx.Write(&serviceInspectContext{}, render)
  131. }
  132. type serviceInspectContext struct {
  133. swarm.Service
  134. subContext
  135. }
  136. func (ctx *serviceInspectContext) ID() string {
  137. return ctx.Service.ID
  138. }
  139. func (ctx *serviceInspectContext) Name() string {
  140. return ctx.Service.Spec.Name
  141. }
  142. func (ctx *serviceInspectContext) Labels() map[string]string {
  143. return ctx.Service.Spec.Labels
  144. }
  145. func (ctx *serviceInspectContext) IsModeGlobal() bool {
  146. return ctx.Service.Spec.Mode.Global != nil
  147. }
  148. func (ctx *serviceInspectContext) ModeReplicatedReplicas() *uint64 {
  149. return ctx.Service.Spec.Mode.Replicated.Replicas
  150. }
  151. func (ctx *serviceInspectContext) HasUpdateStatus() bool {
  152. return ctx.Service.UpdateStatus.State != ""
  153. }
  154. func (ctx *serviceInspectContext) UpdateStatusState() swarm.UpdateState {
  155. return ctx.Service.UpdateStatus.State
  156. }
  157. func (ctx *serviceInspectContext) UpdateStatusStarted() string {
  158. return units.HumanDuration(time.Since(ctx.Service.UpdateStatus.StartedAt))
  159. }
  160. func (ctx *serviceInspectContext) UpdateIsCompleted() bool {
  161. return ctx.Service.UpdateStatus.State == swarm.UpdateStateCompleted
  162. }
  163. func (ctx *serviceInspectContext) UpdateStatusCompleted() string {
  164. return units.HumanDuration(time.Since(ctx.Service.UpdateStatus.CompletedAt))
  165. }
  166. func (ctx *serviceInspectContext) UpdateStatusMessage() string {
  167. return ctx.Service.UpdateStatus.Message
  168. }
  169. func (ctx *serviceInspectContext) TaskPlacementConstraints() []string {
  170. if ctx.Service.Spec.TaskTemplate.Placement != nil {
  171. return ctx.Service.Spec.TaskTemplate.Placement.Constraints
  172. }
  173. return nil
  174. }
  175. func (ctx *serviceInspectContext) HasUpdateConfig() bool {
  176. return ctx.Service.Spec.UpdateConfig != nil
  177. }
  178. func (ctx *serviceInspectContext) UpdateParallelism() uint64 {
  179. return ctx.Service.Spec.UpdateConfig.Parallelism
  180. }
  181. func (ctx *serviceInspectContext) HasUpdateDelay() bool {
  182. return ctx.Service.Spec.UpdateConfig.Delay.Nanoseconds() > 0
  183. }
  184. func (ctx *serviceInspectContext) UpdateDelay() time.Duration {
  185. return ctx.Service.Spec.UpdateConfig.Delay
  186. }
  187. func (ctx *serviceInspectContext) UpdateOnFailure() string {
  188. return ctx.Service.Spec.UpdateConfig.FailureAction
  189. }
  190. func (ctx *serviceInspectContext) ContainerImage() string {
  191. return ctx.Service.Spec.TaskTemplate.ContainerSpec.Image
  192. }
  193. func (ctx *serviceInspectContext) ContainerArgs() []string {
  194. return ctx.Service.Spec.TaskTemplate.ContainerSpec.Args
  195. }
  196. func (ctx *serviceInspectContext) ContainerEnv() []string {
  197. return ctx.Service.Spec.TaskTemplate.ContainerSpec.Env
  198. }
  199. func (ctx *serviceInspectContext) ContainerWorkDir() string {
  200. return ctx.Service.Spec.TaskTemplate.ContainerSpec.Dir
  201. }
  202. func (ctx *serviceInspectContext) ContainerUser() string {
  203. return ctx.Service.Spec.TaskTemplate.ContainerSpec.User
  204. }
  205. func (ctx *serviceInspectContext) ContainerMounts() []mounttypes.Mount {
  206. return ctx.Service.Spec.TaskTemplate.ContainerSpec.Mounts
  207. }
  208. func (ctx *serviceInspectContext) HasResources() bool {
  209. return ctx.Service.Spec.TaskTemplate.Resources != nil
  210. }
  211. func (ctx *serviceInspectContext) HasResourceReservations() bool {
  212. return ctx.Service.Spec.TaskTemplate.Resources.Reservations.NanoCPUs > 0 || ctx.Service.Spec.TaskTemplate.Resources.Reservations.MemoryBytes > 0
  213. }
  214. func (ctx *serviceInspectContext) ResourceReservationNanoCPUs() float64 {
  215. if ctx.Service.Spec.TaskTemplate.Resources.Reservations.NanoCPUs == 0 {
  216. return float64(0)
  217. }
  218. return float64(ctx.Service.Spec.TaskTemplate.Resources.Reservations.NanoCPUs) / 1e9
  219. }
  220. func (ctx *serviceInspectContext) ResourceReservationMemory() string {
  221. if ctx.Service.Spec.TaskTemplate.Resources.Reservations.MemoryBytes == 0 {
  222. return ""
  223. }
  224. return units.BytesSize(float64(ctx.Service.Spec.TaskTemplate.Resources.Reservations.MemoryBytes))
  225. }
  226. func (ctx *serviceInspectContext) HasResourceLimits() bool {
  227. return ctx.Service.Spec.TaskTemplate.Resources.Limits.NanoCPUs > 0 || ctx.Service.Spec.TaskTemplate.Resources.Limits.MemoryBytes > 0
  228. }
  229. func (ctx *serviceInspectContext) ResourceLimitsNanoCPUs() float64 {
  230. return float64(ctx.Service.Spec.TaskTemplate.Resources.Limits.NanoCPUs) / 1e9
  231. }
  232. func (ctx *serviceInspectContext) ResourceLimitMemory() string {
  233. if ctx.Service.Spec.TaskTemplate.Resources.Limits.MemoryBytes == 0 {
  234. return ""
  235. }
  236. return units.BytesSize(float64(ctx.Service.Spec.TaskTemplate.Resources.Limits.MemoryBytes))
  237. }
  238. func (ctx *serviceInspectContext) Networks() []string {
  239. var out []string
  240. for _, n := range ctx.Service.Spec.Networks {
  241. out = append(out, n.Target)
  242. }
  243. return out
  244. }
  245. func (ctx *serviceInspectContext) Ports() []swarm.PortConfig {
  246. return ctx.Service.Endpoint.Ports
  247. }