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  }