github.com/fabiokung/docker@v0.11.2-0.20170222101415-4534dcd49497/cli/command/formatter/service.go (about) 1 package formatter 2 3 import ( 4 "fmt" 5 "strings" 6 "time" 7 8 "github.com/docker/distribution/reference" 9 mounttypes "github.com/docker/docker/api/types/mount" 10 "github.com/docker/docker/api/types/swarm" 11 "github.com/docker/docker/cli/command/inspect" 12 "github.com/docker/docker/pkg/stringid" 13 units "github.com/docker/go-units" 14 ) 15 16 const serviceInspectPrettyTemplate Format = ` 17 ID: {{.ID}} 18 Name: {{.Name}} 19 {{- if .Labels }} 20 Labels: 21 {{- range $k, $v := .Labels }} 22 {{ $k }}{{if $v }}={{ $v }}{{ end }} 23 {{- end }}{{ end }} 24 Service Mode: 25 {{- if .IsModeGlobal }} Global 26 {{- else if .IsModeReplicated }} Replicated 27 {{- if .ModeReplicatedReplicas }} 28 Replicas: {{ .ModeReplicatedReplicas }} 29 {{- end }}{{ end }} 30 {{- if .HasUpdateStatus }} 31 UpdateStatus: 32 State: {{ .UpdateStatusState }} 33 {{- if .HasUpdateStatusStarted }} 34 Started: {{ .UpdateStatusStarted }} 35 {{- end }} 36 {{- if .UpdateIsCompleted }} 37 Completed: {{ .UpdateStatusCompleted }} 38 {{- end }} 39 Message: {{ .UpdateStatusMessage }} 40 {{- end }} 41 Placement: 42 {{- if .TaskPlacementConstraints -}} 43 Contraints: {{ .TaskPlacementConstraints }} 44 {{- end }} 45 {{- if .HasUpdateConfig }} 46 UpdateConfig: 47 Parallelism: {{ .UpdateParallelism }} 48 {{- if .HasUpdateDelay}} 49 Delay: {{ .UpdateDelay }} 50 {{- end }} 51 On failure: {{ .UpdateOnFailure }} 52 {{- if .HasUpdateMonitor}} 53 Monitoring Period: {{ .UpdateMonitor }} 54 {{- end }} 55 Max failure ratio: {{ .UpdateMaxFailureRatio }} 56 {{- end }} 57 ContainerSpec: 58 Image: {{ .ContainerImage }} 59 {{- if .ContainerArgs }} 60 Args: {{ range $arg := .ContainerArgs }}{{ $arg }} {{ end }} 61 {{- end -}} 62 {{- if .ContainerEnv }} 63 Env: {{ range $env := .ContainerEnv }}{{ $env }} {{ end }} 64 {{- end -}} 65 {{- if .ContainerWorkDir }} 66 Dir: {{ .ContainerWorkDir }} 67 {{- end -}} 68 {{- if .ContainerUser }} 69 User: {{ .ContainerUser }} 70 {{- end }} 71 {{- if .ContainerMounts }} 72 Mounts: 73 {{- end }} 74 {{- range $mount := .ContainerMounts }} 75 Target = {{ $mount.Target }} 76 Source = {{ $mount.Source }} 77 ReadOnly = {{ $mount.ReadOnly }} 78 Type = {{ $mount.Type }} 79 {{- end -}} 80 {{- if .HasResources }} 81 Resources: 82 {{- if .HasResourceReservations }} 83 Reservations: 84 {{- if gt .ResourceReservationNanoCPUs 0.0 }} 85 CPU: {{ .ResourceReservationNanoCPUs }} 86 {{- end }} 87 {{- if .ResourceReservationMemory }} 88 Memory: {{ .ResourceReservationMemory }} 89 {{- end }}{{ end }} 90 {{- if .HasResourceLimits }} 91 Limits: 92 {{- if gt .ResourceLimitsNanoCPUs 0.0 }} 93 CPU: {{ .ResourceLimitsNanoCPUs }} 94 {{- end }} 95 {{- if .ResourceLimitMemory }} 96 Memory: {{ .ResourceLimitMemory }} 97 {{- end }}{{ end }}{{ end }} 98 {{- if .Networks }} 99 Networks: 100 {{- range $network := .Networks }} {{ $network }}{{ end }} {{ end }} 101 Endpoint Mode: {{ .EndpointMode }} 102 {{- if .Ports }} 103 Ports: 104 {{- range $port := .Ports }} 105 PublishedPort = {{ $port.PublishedPort }} 106 Protocol = {{ $port.Protocol }} 107 TargetPort = {{ $port.TargetPort }} 108 PublishMode = {{ $port.PublishMode }} 109 {{- end }} {{ end -}} 110 ` 111 112 // NewServiceFormat returns a Format for rendering using a Context 113 func NewServiceFormat(source string) Format { 114 switch source { 115 case PrettyFormatKey: 116 return serviceInspectPrettyTemplate 117 default: 118 return Format(strings.TrimPrefix(source, RawFormatKey)) 119 } 120 } 121 122 // ServiceInspectWrite renders the context for a list of services 123 func ServiceInspectWrite(ctx Context, refs []string, getRef inspect.GetRefFunc) error { 124 if ctx.Format != serviceInspectPrettyTemplate { 125 return inspect.Inspect(ctx.Output, refs, string(ctx.Format), getRef) 126 } 127 render := func(format func(subContext subContext) error) error { 128 for _, ref := range refs { 129 serviceI, _, err := getRef(ref) 130 if err != nil { 131 return err 132 } 133 service, ok := serviceI.(swarm.Service) 134 if !ok { 135 return fmt.Errorf("got wrong object to inspect") 136 } 137 if err := format(&serviceInspectContext{Service: service}); err != nil { 138 return err 139 } 140 } 141 return nil 142 } 143 return ctx.Write(&serviceInspectContext{}, render) 144 } 145 146 type serviceInspectContext struct { 147 swarm.Service 148 subContext 149 } 150 151 func (ctx *serviceInspectContext) MarshalJSON() ([]byte, error) { 152 return marshalJSON(ctx) 153 } 154 155 func (ctx *serviceInspectContext) ID() string { 156 return ctx.Service.ID 157 } 158 159 func (ctx *serviceInspectContext) Name() string { 160 return ctx.Service.Spec.Name 161 } 162 163 func (ctx *serviceInspectContext) Labels() map[string]string { 164 return ctx.Service.Spec.Labels 165 } 166 167 func (ctx *serviceInspectContext) IsModeGlobal() bool { 168 return ctx.Service.Spec.Mode.Global != nil 169 } 170 171 func (ctx *serviceInspectContext) IsModeReplicated() bool { 172 return ctx.Service.Spec.Mode.Replicated != nil 173 } 174 175 func (ctx *serviceInspectContext) ModeReplicatedReplicas() *uint64 { 176 return ctx.Service.Spec.Mode.Replicated.Replicas 177 } 178 179 func (ctx *serviceInspectContext) HasUpdateStatus() bool { 180 return ctx.Service.UpdateStatus != nil && ctx.Service.UpdateStatus.State != "" 181 } 182 183 func (ctx *serviceInspectContext) UpdateStatusState() swarm.UpdateState { 184 return ctx.Service.UpdateStatus.State 185 } 186 187 func (ctx *serviceInspectContext) HasUpdateStatusStarted() bool { 188 return ctx.Service.UpdateStatus.StartedAt != nil 189 } 190 191 func (ctx *serviceInspectContext) UpdateStatusStarted() string { 192 return units.HumanDuration(time.Since(*ctx.Service.UpdateStatus.StartedAt)) 193 } 194 195 func (ctx *serviceInspectContext) UpdateIsCompleted() bool { 196 return ctx.Service.UpdateStatus.State == swarm.UpdateStateCompleted && ctx.Service.UpdateStatus.CompletedAt != nil 197 } 198 199 func (ctx *serviceInspectContext) UpdateStatusCompleted() string { 200 return units.HumanDuration(time.Since(*ctx.Service.UpdateStatus.CompletedAt)) 201 } 202 203 func (ctx *serviceInspectContext) UpdateStatusMessage() string { 204 return ctx.Service.UpdateStatus.Message 205 } 206 207 func (ctx *serviceInspectContext) TaskPlacementConstraints() []string { 208 if ctx.Service.Spec.TaskTemplate.Placement != nil { 209 return ctx.Service.Spec.TaskTemplate.Placement.Constraints 210 } 211 return nil 212 } 213 214 func (ctx *serviceInspectContext) HasUpdateConfig() bool { 215 return ctx.Service.Spec.UpdateConfig != nil 216 } 217 218 func (ctx *serviceInspectContext) UpdateParallelism() uint64 { 219 return ctx.Service.Spec.UpdateConfig.Parallelism 220 } 221 222 func (ctx *serviceInspectContext) HasUpdateDelay() bool { 223 return ctx.Service.Spec.UpdateConfig.Delay.Nanoseconds() > 0 224 } 225 226 func (ctx *serviceInspectContext) UpdateDelay() time.Duration { 227 return ctx.Service.Spec.UpdateConfig.Delay 228 } 229 230 func (ctx *serviceInspectContext) UpdateOnFailure() string { 231 return ctx.Service.Spec.UpdateConfig.FailureAction 232 } 233 234 func (ctx *serviceInspectContext) HasUpdateMonitor() bool { 235 return ctx.Service.Spec.UpdateConfig.Monitor.Nanoseconds() > 0 236 } 237 238 func (ctx *serviceInspectContext) UpdateMonitor() time.Duration { 239 return ctx.Service.Spec.UpdateConfig.Monitor 240 } 241 242 func (ctx *serviceInspectContext) UpdateMaxFailureRatio() float32 { 243 return ctx.Service.Spec.UpdateConfig.MaxFailureRatio 244 } 245 246 func (ctx *serviceInspectContext) ContainerImage() string { 247 return ctx.Service.Spec.TaskTemplate.ContainerSpec.Image 248 } 249 250 func (ctx *serviceInspectContext) ContainerArgs() []string { 251 return ctx.Service.Spec.TaskTemplate.ContainerSpec.Args 252 } 253 254 func (ctx *serviceInspectContext) ContainerEnv() []string { 255 return ctx.Service.Spec.TaskTemplate.ContainerSpec.Env 256 } 257 258 func (ctx *serviceInspectContext) ContainerWorkDir() string { 259 return ctx.Service.Spec.TaskTemplate.ContainerSpec.Dir 260 } 261 262 func (ctx *serviceInspectContext) ContainerUser() string { 263 return ctx.Service.Spec.TaskTemplate.ContainerSpec.User 264 } 265 266 func (ctx *serviceInspectContext) ContainerMounts() []mounttypes.Mount { 267 return ctx.Service.Spec.TaskTemplate.ContainerSpec.Mounts 268 } 269 270 func (ctx *serviceInspectContext) HasResources() bool { 271 return ctx.Service.Spec.TaskTemplate.Resources != nil 272 } 273 274 func (ctx *serviceInspectContext) HasResourceReservations() bool { 275 if ctx.Service.Spec.TaskTemplate.Resources == nil || ctx.Service.Spec.TaskTemplate.Resources.Reservations == nil { 276 return false 277 } 278 return ctx.Service.Spec.TaskTemplate.Resources.Reservations.NanoCPUs > 0 || ctx.Service.Spec.TaskTemplate.Resources.Reservations.MemoryBytes > 0 279 } 280 281 func (ctx *serviceInspectContext) ResourceReservationNanoCPUs() float64 { 282 if ctx.Service.Spec.TaskTemplate.Resources.Reservations.NanoCPUs == 0 { 283 return float64(0) 284 } 285 return float64(ctx.Service.Spec.TaskTemplate.Resources.Reservations.NanoCPUs) / 1e9 286 } 287 288 func (ctx *serviceInspectContext) ResourceReservationMemory() string { 289 if ctx.Service.Spec.TaskTemplate.Resources.Reservations.MemoryBytes == 0 { 290 return "" 291 } 292 return units.BytesSize(float64(ctx.Service.Spec.TaskTemplate.Resources.Reservations.MemoryBytes)) 293 } 294 295 func (ctx *serviceInspectContext) HasResourceLimits() bool { 296 if ctx.Service.Spec.TaskTemplate.Resources == nil || ctx.Service.Spec.TaskTemplate.Resources.Limits == nil { 297 return false 298 } 299 return ctx.Service.Spec.TaskTemplate.Resources.Limits.NanoCPUs > 0 || ctx.Service.Spec.TaskTemplate.Resources.Limits.MemoryBytes > 0 300 } 301 302 func (ctx *serviceInspectContext) ResourceLimitsNanoCPUs() float64 { 303 return float64(ctx.Service.Spec.TaskTemplate.Resources.Limits.NanoCPUs) / 1e9 304 } 305 306 func (ctx *serviceInspectContext) ResourceLimitMemory() string { 307 if ctx.Service.Spec.TaskTemplate.Resources.Limits.MemoryBytes == 0 { 308 return "" 309 } 310 return units.BytesSize(float64(ctx.Service.Spec.TaskTemplate.Resources.Limits.MemoryBytes)) 311 } 312 313 func (ctx *serviceInspectContext) Networks() []string { 314 var out []string 315 for _, n := range ctx.Service.Spec.Networks { 316 out = append(out, n.Target) 317 } 318 return out 319 } 320 321 func (ctx *serviceInspectContext) EndpointMode() string { 322 if ctx.Service.Spec.EndpointSpec == nil { 323 return "" 324 } 325 326 return string(ctx.Service.Spec.EndpointSpec.Mode) 327 } 328 329 func (ctx *serviceInspectContext) Ports() []swarm.PortConfig { 330 return ctx.Service.Endpoint.Ports 331 } 332 333 const ( 334 defaultServiceTableFormat = "table {{.ID}}\t{{.Name}}\t{{.Mode}}\t{{.Replicas}}\t{{.Image}}" 335 336 serviceIDHeader = "ID" 337 modeHeader = "MODE" 338 replicasHeader = "REPLICAS" 339 ) 340 341 // NewServiceListFormat returns a Format for rendering using a service Context 342 func NewServiceListFormat(source string, quiet bool) Format { 343 switch source { 344 case TableFormatKey: 345 if quiet { 346 return defaultQuietFormat 347 } 348 return defaultServiceTableFormat 349 case RawFormatKey: 350 if quiet { 351 return `id: {{.ID}}` 352 } 353 return `id: {{.ID}}\nname: {{.Name}}\nmode: {{.Mode}}\nreplicas: {{.Replicas}}\nimage: {{.Image}}\n` 354 } 355 return Format(source) 356 } 357 358 // ServiceListInfo stores the information about mode and replicas to be used by template 359 type ServiceListInfo struct { 360 Mode string 361 Replicas string 362 } 363 364 // ServiceListWrite writes the context 365 func ServiceListWrite(ctx Context, services []swarm.Service, info map[string]ServiceListInfo) error { 366 render := func(format func(subContext subContext) error) error { 367 for _, service := range services { 368 serviceCtx := &serviceContext{service: service, mode: info[service.ID].Mode, replicas: info[service.ID].Replicas} 369 if err := format(serviceCtx); err != nil { 370 return err 371 } 372 } 373 return nil 374 } 375 return ctx.Write(&serviceContext{}, render) 376 } 377 378 type serviceContext struct { 379 HeaderContext 380 service swarm.Service 381 mode string 382 replicas string 383 } 384 385 func (c *serviceContext) MarshalJSON() ([]byte, error) { 386 return marshalJSON(c) 387 } 388 389 func (c *serviceContext) ID() string { 390 c.AddHeader(serviceIDHeader) 391 return stringid.TruncateID(c.service.ID) 392 } 393 394 func (c *serviceContext) Name() string { 395 c.AddHeader(nameHeader) 396 return c.service.Spec.Name 397 } 398 399 func (c *serviceContext) Mode() string { 400 c.AddHeader(modeHeader) 401 return c.mode 402 } 403 404 func (c *serviceContext) Replicas() string { 405 c.AddHeader(replicasHeader) 406 return c.replicas 407 } 408 409 func (c *serviceContext) Image() string { 410 c.AddHeader(imageHeader) 411 image := c.service.Spec.TaskTemplate.ContainerSpec.Image 412 if ref, err := reference.ParseNormalizedNamed(image); err == nil { 413 // update image string for display, (strips any digest) 414 if nt, ok := ref.(reference.NamedTagged); ok { 415 if namedTagged, err := reference.WithTag(reference.TrimNamed(nt), nt.Tag()); err == nil { 416 image = reference.FamiliarString(namedTagged) 417 } 418 } 419 } 420 421 return image 422 }