summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Goff <cpuguy83@gmail.com>2016-07-25 15:24:34 -0400
committerBrian Goff <cpuguy83@gmail.com>2016-09-19 16:28:19 -0400
commit54ba82beab8ef8b71f5a6a2f7082ed7759b40df3 (patch)
treee91ba67e1fd50efb1219377cbf6e5763e6994b7b
parent45a8f680263558657e98c899204a632153b60cde (diff)
downloaddocker-54ba82beab8ef8b71f5a6a2f7082ed7759b40df3.tar.gz
Add formatter for service inspect
Allows the user to use `pretty` as the format string. This enables users to put custom format options into their CLI config just like is supported for `docker ps` and `docker images` Signed-off-by: Brian Goff <cpuguy83@gmail.com>
-rw-r--r--cli/command/formatter/formatter.go8
-rw-r--r--cli/command/formatter/service.go285
-rw-r--r--cli/command/service/inspect.go144
-rw-r--r--cli/command/service/inspect_test.go14
-rw-r--r--cliconfig/configfile/file.go19
-rw-r--r--docs/reference/commandline/cli.md8
-rw-r--r--docs/reference/commandline/service_inspect.md2
7 files changed, 342 insertions, 138 deletions
diff --git a/cli/command/formatter/formatter.go b/cli/command/formatter/formatter.go
index 32f9a4d359..e859a1ca26 100644
--- a/cli/command/formatter/formatter.go
+++ b/cli/command/formatter/formatter.go
@@ -11,11 +11,11 @@ import (
"github.com/docker/docker/utils/templates"
)
+// Format keys used to specify certain kinds of output formats
const (
- // TableFormatKey is the key used to format as a table
- TableFormatKey = "table"
- // RawFormatKey is the key used to format as raw JSON
- RawFormatKey = "raw"
+ TableFormatKey = "table"
+ RawFormatKey = "raw"
+ PrettyFormatKey = "pretty"
defaultQuietFormat = "{{.ID}}"
)
diff --git a/cli/command/formatter/service.go b/cli/command/formatter/service.go
new file mode 100644
index 0000000000..2ce18aba5c
--- /dev/null
+++ b/cli/command/formatter/service.go
@@ -0,0 +1,285 @@
+package formatter
+
+import (
+ "fmt"
+ "strings"
+ "time"
+
+ mounttypes "github.com/docker/docker/api/types/mount"
+ "github.com/docker/docker/api/types/swarm"
+ "github.com/docker/docker/cli/command/inspect"
+ units "github.com/docker/go-units"
+)
+
+const serviceInspectPrettyTemplate Format = `
+ID: {{.ID}}
+Name: {{.Name}}
+{{- if .Labels }}
+Labels:
+{{- range $k, $v := .Labels }}
+ {{ $k }}{{if $v }}={{ $v }}{{ end }}
+{{- end }}{{ end }}
+Mode:
+{{- if .IsModeGlobal }} Global
+{{- else }} Replicated
+{{- if .ModeReplicatedReplicas }}
+ Replicas: {{ .ModeReplicatedReplicas }}
+{{- end }}{{ end }}
+{{- if .HasUpdateStatus }}
+UpdateStatus:
+ State: {{ .UpdateStatusState }}
+ Started: {{ .UpdateStatusStarted }}
+{{- if .UpdateIsCompleted }}
+ Completed: {{ .UpdateStatusCompleted }}
+{{- end }}
+ Message: {{ .UpdateStatusMessage }}
+{{- end }}
+Placement:
+{{- if .TaskPlacementConstraints -}}
+ Contraints: {{ .TaskPlacementConstraints }}
+{{- end }}
+{{- if .HasUpdateConfig }}
+UpdateConfig:
+ Parallelism: {{ .UpdateParallelism }}
+{{- if .HasUpdateDelay -}}
+ Delay: {{ .UpdateDelay }}
+{{- end }}
+ On failure: {{ .UpdateOnFailure }}
+{{- end }}
+ContainerSpec:
+ Image: {{ .ContainerImage }}
+{{- if .ContainerArgs }}
+ Args: {{ range $arg := .ContainerArgs }}{{ $arg }} {{ end }}
+{{- end -}}
+{{- if .ContainerEnv }}
+ Env: {{ range $env := .ContainerEnv }}{{ $env }} {{ end }}
+{{- end -}}
+{{- if .ContainerWorkDir }}
+ Dir: {{ .ContainerWorkDir }}
+{{- end -}}
+{{- if .ContainerUser }}
+ User: {{ .ContainerUser }}
+{{- end }}
+{{- if .ContainerMounts }}
+Mounts:
+{{- end }}
+{{- range $mount := .ContainerMounts }}
+ Target = {{ $mount.Target }}
+ Source = {{ $mount.Source }}
+ ReadOnly = {{ $mount.ReadOnly }}
+ Type = {{ $mount.Type }}
+{{- end -}}
+{{- if .HasResources }}
+Resources:
+{{- if .HasResourceReservations }}
+ Reservations:
+{{- end }}
+{{- if gt .ResourceReservationNanoCPUs 0.0 }}
+ CPU: {{ .ResourceReservationNanoCPUs }}
+{{- end }}
+{{- if .ResourceReservationMemory }}
+ Memory: {{ .ResourceReservationMemory }}
+{{- end }}
+{{- if .HasResourceLimits }}
+ Limits:
+{{- end }}
+{{- if gt .ResourceLimitsNanoCPUs 0.0 }}
+ CPU: {{ .ResourceLimitsNanoCPUs }}
+{{- end }}
+{{- if .ResourceLimitMemory }}
+ Memory: {{ .ResourceLimitMemory }}
+{{- end }}{{ end }}
+{{- if .Networks }}
+Networks:
+{{- range $network := .Networks }} {{ $network }}{{ end }} {{ end }}
+{{- if .Ports }}
+Ports:
+{{- range $port := .Ports }}
+ PublishedPort {{ $port.PublishedPort }}
+ Protocol = {{ $port.Protocol }}
+ TargetPort = {{ $port.TargetPort }}
+{{- end }} {{ end -}}
+`
+
+// NewServiceFormat returns a Format for rendering using a Context
+func NewServiceFormat(source string) Format {
+ switch source {
+ case PrettyFormatKey:
+ return serviceInspectPrettyTemplate
+ default:
+ return Format(strings.TrimPrefix(source, RawFormatKey))
+ }
+}
+
+// ServiceInspectWrite renders the context for a list of services
+func ServiceInspectWrite(ctx Context, refs []string, getRef inspect.GetRefFunc) error {
+ if ctx.Format != serviceInspectPrettyTemplate {
+ return inspect.Inspect(ctx.Output, refs, string(ctx.Format), getRef)
+ }
+ render := func(format func(subContext subContext) error) error {
+ for _, ref := range refs {
+ serviceI, _, err := getRef(ref)
+ if err != nil {
+ return err
+ }
+ service, ok := serviceI.(swarm.Service)
+ if !ok {
+ return fmt.Errorf("got wrong object to inspect")
+ }
+ if err := format(&serviceInspectContext{Service: service}); err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+ return ctx.Write(&serviceInspectContext{}, render)
+}
+
+type serviceInspectContext struct {
+ swarm.Service
+ subContext
+}
+
+func (ctx *serviceInspectContext) ID() string {
+ return ctx.Service.ID
+}
+
+func (ctx *serviceInspectContext) Name() string {
+ return ctx.Service.Spec.Name
+}
+
+func (ctx *serviceInspectContext) Labels() map[string]string {
+ return ctx.Service.Spec.Labels
+}
+
+func (ctx *serviceInspectContext) IsModeGlobal() bool {
+ return ctx.Service.Spec.Mode.Global != nil
+}
+
+func (ctx *serviceInspectContext) ModeReplicatedReplicas() *uint64 {
+ return ctx.Service.Spec.Mode.Replicated.Replicas
+}
+
+func (ctx *serviceInspectContext) HasUpdateStatus() bool {
+ return ctx.Service.UpdateStatus.State != ""
+}
+
+func (ctx *serviceInspectContext) UpdateStatusState() swarm.UpdateState {
+ return ctx.Service.UpdateStatus.State
+}
+
+func (ctx *serviceInspectContext) UpdateStatusStarted() string {
+ return units.HumanDuration(time.Since(ctx.Service.UpdateStatus.StartedAt))
+}
+
+func (ctx *serviceInspectContext) UpdateIsCompleted() bool {
+ return ctx.Service.UpdateStatus.State == swarm.UpdateStateCompleted
+}
+
+func (ctx *serviceInspectContext) UpdateStatusCompleted() string {
+ return units.HumanDuration(time.Since(ctx.Service.UpdateStatus.CompletedAt))
+}
+
+func (ctx *serviceInspectContext) UpdateStatusMessage() string {
+ return ctx.Service.UpdateStatus.Message
+}
+
+func (ctx *serviceInspectContext) TaskPlacementConstraints() []string {
+ if ctx.Service.Spec.TaskTemplate.Placement != nil {
+ return ctx.Service.Spec.TaskTemplate.Placement.Constraints
+ }
+ return nil
+}
+
+func (ctx *serviceInspectContext) HasUpdateConfig() bool {
+ return ctx.Service.Spec.UpdateConfig != nil
+}
+
+func (ctx *serviceInspectContext) UpdateParallelism() uint64 {
+ return ctx.Service.Spec.UpdateConfig.Parallelism
+}
+
+func (ctx *serviceInspectContext) HasUpdateDelay() bool {
+ return ctx.Service.Spec.UpdateConfig.Delay.Nanoseconds() > 0
+}
+
+func (ctx *serviceInspectContext) UpdateDelay() time.Duration {
+ return ctx.Service.Spec.UpdateConfig.Delay
+}
+
+func (ctx *serviceInspectContext) UpdateOnFailure() string {
+ return ctx.Service.Spec.UpdateConfig.FailureAction
+}
+
+func (ctx *serviceInspectContext) ContainerImage() string {
+ return ctx.Service.Spec.TaskTemplate.ContainerSpec.Image
+}
+
+func (ctx *serviceInspectContext) ContainerArgs() []string {
+ return ctx.Service.Spec.TaskTemplate.ContainerSpec.Args
+}
+
+func (ctx *serviceInspectContext) ContainerEnv() []string {
+ return ctx.Service.Spec.TaskTemplate.ContainerSpec.Env
+}
+
+func (ctx *serviceInspectContext) ContainerWorkDir() string {
+ return ctx.Service.Spec.TaskTemplate.ContainerSpec.Dir
+}
+
+func (ctx *serviceInspectContext) ContainerUser() string {
+ return ctx.Service.Spec.TaskTemplate.ContainerSpec.User
+}
+
+func (ctx *serviceInspectContext) ContainerMounts() []mounttypes.Mount {
+ return ctx.Service.Spec.TaskTemplate.ContainerSpec.Mounts
+}
+
+func (ctx *serviceInspectContext) HasResources() bool {
+ return ctx.Service.Spec.TaskTemplate.Resources != nil
+}
+
+func (ctx *serviceInspectContext) HasResourceReservations() bool {
+ return ctx.Service.Spec.TaskTemplate.Resources.Reservations.NanoCPUs > 0 || ctx.Service.Spec.TaskTemplate.Resources.Reservations.MemoryBytes > 0
+}
+
+func (ctx *serviceInspectContext) ResourceReservationNanoCPUs() float64 {
+ if ctx.Service.Spec.TaskTemplate.Resources.Reservations.NanoCPUs == 0 {
+ return float64(0)
+ }
+ return float64(ctx.Service.Spec.TaskTemplate.Resources.Reservations.NanoCPUs) / 1e9
+}
+
+func (ctx *serviceInspectContext) ResourceReservationMemory() string {
+ if ctx.Service.Spec.TaskTemplate.Resources.Reservations.MemoryBytes == 0 {
+ return ""
+ }
+ return units.BytesSize(float64(ctx.Service.Spec.TaskTemplate.Resources.Reservations.MemoryBytes))
+}
+
+func (ctx *serviceInspectContext) HasResourceLimits() bool {
+ return ctx.Service.Spec.TaskTemplate.Resources.Limits.NanoCPUs > 0 || ctx.Service.Spec.TaskTemplate.Resources.Limits.MemoryBytes > 0
+}
+
+func (ctx *serviceInspectContext) ResourceLimitsNanoCPUs() float64 {
+ return float64(ctx.Service.Spec.TaskTemplate.Resources.Limits.NanoCPUs) / 1e9
+}
+
+func (ctx *serviceInspectContext) ResourceLimitMemory() string {
+ if ctx.Service.Spec.TaskTemplate.Resources.Limits.MemoryBytes == 0 {
+ return ""
+ }
+ return units.BytesSize(float64(ctx.Service.Spec.TaskTemplate.Resources.Limits.MemoryBytes))
+}
+
+func (ctx *serviceInspectContext) Networks() []string {
+ var out []string
+ for _, n := range ctx.Service.Spec.Networks {
+ out = append(out, n.Target)
+ }
+ return out
+}
+
+func (ctx *serviceInspectContext) Ports() []swarm.PortConfig {
+ return ctx.Service.Endpoint.Ports
+}
diff --git a/cli/command/service/inspect.go b/cli/command/service/inspect.go
index 8facb1f28b..054c24383e 100644
--- a/cli/command/service/inspect.go
+++ b/cli/command/service/inspect.go
@@ -2,19 +2,14 @@ package service
import (
"fmt"
- "io"
"strings"
- "time"
"golang.org/x/net/context"
- "github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/cli"
"github.com/docker/docker/cli/command"
- "github.com/docker/docker/cli/command/inspect"
+ "github.com/docker/docker/cli/command/formatter"
apiclient "github.com/docker/docker/client"
- "github.com/docker/docker/pkg/ioutils"
- "github.com/docker/go-units"
"github.com/spf13/cobra"
)
@@ -51,6 +46,10 @@ func runInspect(dockerCli *command.DockerCli, opts inspectOptions) error {
client := dockerCli.Client()
ctx := context.Background()
+ if opts.pretty {
+ opts.format = "pretty"
+ }
+
getRef := func(ref string) (interface{}, []byte, error) {
service, _, err := client.ServiceInspectWithRaw(ctx, ref)
if err == nil || !apiclient.IsErrServiceNotFound(err) {
@@ -59,130 +58,27 @@ func runInspect(dockerCli *command.DockerCli, opts inspectOptions) error {
return nil, nil, fmt.Errorf("Error: no such service: %s", ref)
}
- if !opts.pretty {
- return inspect.Inspect(dockerCli.Out(), opts.refs, opts.format, getRef)
- }
-
- return printHumanFriendly(dockerCli.Out(), opts.refs, getRef)
-}
-
-func printHumanFriendly(out io.Writer, refs []string, getRef inspect.GetRefFunc) error {
- for idx, ref := range refs {
- obj, _, err := getRef(ref)
- if err != nil {
- return err
- }
- printService(out, obj.(swarm.Service))
-
- // TODO: better way to do this?
- // print extra space between objects, but not after the last one
- if idx+1 != len(refs) {
- fmt.Fprintf(out, "\n\n")
- }
- }
- return nil
-}
-
-// TODO: use a template
-func printService(out io.Writer, service swarm.Service) {
- fmt.Fprintf(out, "ID:\t\t%s\n", service.ID)
- fmt.Fprintf(out, "Name:\t\t%s\n", service.Spec.Name)
- if service.Spec.Labels != nil {
- fmt.Fprintln(out, "Labels:")
- for k, v := range service.Spec.Labels {
- fmt.Fprintf(out, " - %s=%s\n", k, v)
- }
- }
-
- if service.Spec.Mode.Global != nil {
- fmt.Fprintln(out, "Mode:\t\tGlobal")
- } else {
- fmt.Fprintln(out, "Mode:\t\tReplicated")
- if service.Spec.Mode.Replicated.Replicas != nil {
- fmt.Fprintf(out, " Replicas:\t%d\n", *service.Spec.Mode.Replicated.Replicas)
- }
- }
-
- if service.UpdateStatus.State != "" {
- fmt.Fprintln(out, "Update status:")
- fmt.Fprintf(out, " State:\t\t%s\n", service.UpdateStatus.State)
- fmt.Fprintf(out, " Started:\t%s ago\n", strings.ToLower(units.HumanDuration(time.Since(service.UpdateStatus.StartedAt))))
- if service.UpdateStatus.State == swarm.UpdateStateCompleted {
- fmt.Fprintf(out, " Completed:\t%s ago\n", strings.ToLower(units.HumanDuration(time.Since(service.UpdateStatus.CompletedAt))))
- }
- fmt.Fprintf(out, " Message:\t%s\n", service.UpdateStatus.Message)
- }
-
- fmt.Fprintln(out, "Placement:")
- if service.Spec.TaskTemplate.Placement != nil && len(service.Spec.TaskTemplate.Placement.Constraints) > 0 {
- ioutils.FprintfIfNotEmpty(out, " Constraints\t: %s\n", strings.Join(service.Spec.TaskTemplate.Placement.Constraints, ", "))
- }
- if service.Spec.UpdateConfig != nil {
- fmt.Fprintf(out, "UpdateConfig:\n")
- fmt.Fprintf(out, " Parallelism:\t%d\n", service.Spec.UpdateConfig.Parallelism)
- if service.Spec.UpdateConfig.Delay.Nanoseconds() > 0 {
- fmt.Fprintf(out, " Delay:\t\t%s\n", service.Spec.UpdateConfig.Delay)
+ f := opts.format
+ if len(f) == 0 {
+ f = "raw"
+ if len(dockerCli.ConfigFile().ServiceInspectFormat) > 0 {
+ f = dockerCli.ConfigFile().ServiceInspectFormat
}
- fmt.Fprintf(out, " On failure:\t%s\n", service.Spec.UpdateConfig.FailureAction)
}
- fmt.Fprintf(out, "ContainerSpec:\n")
- printContainerSpec(out, service.Spec.TaskTemplate.ContainerSpec)
-
- resources := service.Spec.TaskTemplate.Resources
- if resources != nil {
- fmt.Fprintln(out, "Resources:")
- printResources := func(out io.Writer, requirement string, r *swarm.Resources) {
- if r == nil || (r.MemoryBytes == 0 && r.NanoCPUs == 0) {
- return
- }
- fmt.Fprintf(out, " %s:\n", requirement)
- if r.NanoCPUs != 0 {
- fmt.Fprintf(out, " CPU:\t\t%g\n", float64(r.NanoCPUs)/1e9)
- }
- if r.MemoryBytes != 0 {
- fmt.Fprintf(out, " Memory:\t%s\n", units.BytesSize(float64(r.MemoryBytes)))
- }
- }
- printResources(out, "Reservations", resources.Reservations)
- printResources(out, "Limits", resources.Limits)
- }
- if len(service.Spec.Networks) > 0 {
- fmt.Fprintf(out, "Networks:")
- for _, n := range service.Spec.Networks {
- fmt.Fprintf(out, " %s", n.Target)
- }
- fmt.Fprintln(out, "")
+ // check if the user is trying to apply a template to the pretty format, which
+ // is not supported
+ if strings.HasPrefix(f, "pretty") && f != "pretty" {
+ return fmt.Errorf("Cannot supply extra formatting options to the pretty template")
}
- if len(service.Endpoint.Ports) > 0 {
- fmt.Fprintln(out, "Ports:")
- for _, port := range service.Endpoint.Ports {
- ioutils.FprintfIfNotEmpty(out, " Name = %s\n", port.Name)
- fmt.Fprintf(out, " Protocol = %s\n", port.Protocol)
- fmt.Fprintf(out, " TargetPort = %d\n", port.TargetPort)
- fmt.Fprintf(out, " PublishedPort = %d\n", port.PublishedPort)
- }
+ serviceCtx := formatter.Context{
+ Output: dockerCli.Out(),
+ Format: formatter.NewServiceFormat(f),
}
-}
-func printContainerSpec(out io.Writer, containerSpec swarm.ContainerSpec) {
- fmt.Fprintf(out, " Image:\t\t%s\n", containerSpec.Image)
- if len(containerSpec.Args) > 0 {
- fmt.Fprintf(out, " Args:\t\t%s\n", strings.Join(containerSpec.Args, " "))
- }
- if len(containerSpec.Env) > 0 {
- fmt.Fprintf(out, " Env:\t\t%s\n", strings.Join(containerSpec.Env, " "))
- }
- ioutils.FprintfIfNotEmpty(out, " Dir\t\t%s\n", containerSpec.Dir)
- ioutils.FprintfIfNotEmpty(out, " User\t\t%s\n", containerSpec.User)
- if len(containerSpec.Mounts) > 0 {
- fmt.Fprintln(out, " Mounts:")
- for _, v := range containerSpec.Mounts {
- fmt.Fprintf(out, " Target = %s\n", v.Target)
- fmt.Fprintf(out, " Source = %s\n", v.Source)
- fmt.Fprintf(out, " ReadOnly = %v\n", v.ReadOnly)
- fmt.Fprintf(out, " Type = %v\n", v.Type)
- }
+ if err := formatter.ServiceInspectWrite(serviceCtx, opts.refs, getRef); err != nil {
+ return cli.StatusError{StatusCode: 1, Status: err.Error()}
}
+ return nil
}
diff --git a/cli/command/service/inspect_test.go b/cli/command/service/inspect_test.go
index 0e0f2ae74f..8e73a70efa 100644
--- a/cli/command/service/inspect_test.go
+++ b/cli/command/service/inspect_test.go
@@ -7,6 +7,7 @@ import (
"time"
"github.com/docker/docker/api/types/swarm"
+ "github.com/docker/docker/cli/command/formatter"
)
func TestPrettyPrintWithNoUpdateConfig(t *testing.T) {
@@ -77,7 +78,18 @@ func TestPrettyPrintWithNoUpdateConfig(t *testing.T) {
},
}
- printService(b, s)
+ ctx := formatter.Context{
+ Output: b,
+ Format: formatter.NewServiceFormat("pretty"),
+ }
+
+ err := formatter.ServiceInspectWrite(ctx, []string{"de179gar9d0o7ltdybungplod"}, func(ref string) (interface{}, []byte, error) {
+ return s, nil, nil
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+
if strings.Contains(b.String(), "UpdateStatus") {
t.Fatal("Pretty print failed before parsing UpdateStatus")
}
diff --git a/cliconfig/configfile/file.go b/cliconfig/configfile/file.go
index c0f5ce2d9a..d9ba28ee64 100644
--- a/cliconfig/configfile/file.go
+++ b/cliconfig/configfile/file.go
@@ -22,15 +22,16 @@ const (
// ConfigFile ~/.docker/config.json file info
type ConfigFile struct {
- AuthConfigs map[string]types.AuthConfig `json:"auths"`
- HTTPHeaders map[string]string `json:"HttpHeaders,omitempty"`
- PsFormat string `json:"psFormat,omitempty"`
- ImagesFormat string `json:"imagesFormat,omitempty"`
- NetworksFormat string `json:"networksFormat,omitempty"`
- VolumesFormat string `json:"volumesFormat,omitempty"`
- DetachKeys string `json:"detachKeys,omitempty"`
- CredentialsStore string `json:"credsStore,omitempty"`
- Filename string `json:"-"` // Note: for internal use only
+ AuthConfigs map[string]types.AuthConfig `json:"auths"`
+ HTTPHeaders map[string]string `json:"HttpHeaders,omitempty"`
+ PsFormat string `json:"psFormat,omitempty"`
+ ImagesFormat string `json:"imagesFormat,omitempty"`
+ NetworksFormat string `json:"networksFormat,omitempty"`
+ VolumesFormat string `json:"volumesFormat,omitempty"`
+ DetachKeys string `json:"detachKeys,omitempty"`
+ CredentialsStore string `json:"credsStore,omitempty"`
+ Filename string `json:"-"` // Note: for internal use only
+ ServiceInspectFormat string `json:"serviceInspectFormat,omitempty"`
}
// LegacyLoadFromReader reads the non-nested configuration data given and sets up the
diff --git a/docs/reference/commandline/cli.md b/docs/reference/commandline/cli.md
index 61e33957b1..a118430042 100644
--- a/docs/reference/commandline/cli.md
+++ b/docs/reference/commandline/cli.md
@@ -143,6 +143,13 @@ Docker's client uses this property. If this property is not set, the client
falls back to the default table format. For a list of supported formatting
directives, see the [**Formatting** section in the `docker images` documentation](images.md)
+The property `serviceInspectFormat` specifies the default format for `docker
+service inspect` output. When the `--format` flag is not provided with the
+`docker service inspect` command, Docker's client uses this property. If this
+property is not set, the client falls back to the default json format. For a
+list of supported formatting directives, see the
+[**Formatting** section in the `docker service inspect` documentation](service_inspect.md)
+
Following is a sample `config.json` file:
{
@@ -151,6 +158,7 @@ Following is a sample `config.json` file:
},
"psFormat": "table {{.ID}}\\t{{.Image}}\\t{{.Command}}\\t{{.Labels}}",
"imagesFormat": "table {{.ID}}\\t{{.Repository}}\\t{{.Tag}}\\t{{.CreatedAt}}",
+ "serviceInspectFormat": "pretty",
"detachKeys": "ctrl-e,e"
}
diff --git a/docs/reference/commandline/service_inspect.md b/docs/reference/commandline/service_inspect.md
index 2fbaedd8fe..4923d8e706 100644
--- a/docs/reference/commandline/service_inspect.md
+++ b/docs/reference/commandline/service_inspect.md
@@ -130,6 +130,8 @@ Ports:
PublishedPort = 4443
```
+You can also use `--format pretty` for the same effect.
+
### Finding the number of tasks running as part of a service