mirror of https://github.com/docker/docs.git
Allow custom format for ls
Signed-off-by: David Gageot <david@gageot.net>
This commit is contained in:
parent
c64af2918e
commit
adc60712c8
|
@ -214,6 +214,9 @@ var Commands = []cli.Command{
|
||||||
Action: fatalOnError(cmdKill),
|
Action: fatalOnError(cmdKill),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Name: "ls",
|
||||||
|
Usage: "List machines",
|
||||||
|
Action: fatalOnError(cmdLs),
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
Name: "quiet, q",
|
Name: "quiet, q",
|
||||||
|
@ -229,10 +232,11 @@ var Commands = []cli.Command{
|
||||||
Usage: fmt.Sprintf("Timeout in seconds, default to %s", stateTimeoutDuration),
|
Usage: fmt.Sprintf("Timeout in seconds, default to %s", stateTimeoutDuration),
|
||||||
Value: lsDefaultTimeout,
|
Value: lsDefaultTimeout,
|
||||||
},
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "format, f",
|
||||||
|
Usage: "Pretty-print machines using a Go template",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Name: "ls",
|
|
||||||
Usage: "List machines",
|
|
||||||
Action: fatalOnError(cmdLs),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "regenerate-certs",
|
Name: "regenerate-certs",
|
||||||
|
|
|
@ -11,6 +11,8 @@ import (
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"io"
|
||||||
|
|
||||||
"github.com/docker/machine/libmachine"
|
"github.com/docker/machine/libmachine"
|
||||||
"github.com/docker/machine/libmachine/drivers"
|
"github.com/docker/machine/libmachine/drivers"
|
||||||
"github.com/docker/machine/libmachine/engine"
|
"github.com/docker/machine/libmachine/engine"
|
||||||
|
@ -23,11 +25,14 @@ import (
|
||||||
"github.com/skarademir/naturalsort"
|
"github.com/skarademir/naturalsort"
|
||||||
)
|
)
|
||||||
|
|
||||||
const lsDefaultTimeout = 10
|
const (
|
||||||
|
lsDefaultTimeout = 10
|
||||||
|
tableFormatKey = "table"
|
||||||
|
lsDefaultFormat = "table {{ .Name }}\t{{ .Active }}\t{{ .DriverName}}\t{{ .State }}\t{{ .URL }}\t{{ .Swarm }}\t{{ .DockerVersion }}\t{{ .Error}}"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
stateTimeoutDuration = lsDefaultTimeout * time.Second
|
stateTimeoutDuration = lsDefaultTimeout * time.Second
|
||||||
defaultLsTemplate = "{{ .Name }}\t{{ .Active }}\t{{ .DriverName}}\t{{ .State }}\t{{ .URL }}\t{{ .Swarm }}\t{{ .DockerVersion }}\t{{ .Error}}"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// FilterOptions -
|
// FilterOptions -
|
||||||
|
@ -54,11 +59,25 @@ type HostListItem struct {
|
||||||
DockerVersion string
|
DockerVersion string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Headers struct {
|
||||||
|
Name string
|
||||||
|
Active string
|
||||||
|
ActiveHost string
|
||||||
|
ActiveSwarm string
|
||||||
|
DriverName string
|
||||||
|
State string
|
||||||
|
URL string
|
||||||
|
SwarmOptions string
|
||||||
|
Swarm string
|
||||||
|
EngineOptions string
|
||||||
|
Error string
|
||||||
|
DockerVersion string
|
||||||
|
}
|
||||||
|
|
||||||
func cmdLs(c CommandLine, api libmachine.API) error {
|
func cmdLs(c CommandLine, api libmachine.API) error {
|
||||||
stateTimeoutDuration = time.Duration(c.Int("timeout")) * time.Second
|
stateTimeoutDuration = time.Duration(c.Int("timeout")) * time.Second
|
||||||
log.Debugf("ls timeout set to %s", stateTimeoutDuration)
|
log.Debugf("ls timeout set to %s", stateTimeoutDuration)
|
||||||
|
|
||||||
quiet := c.Bool("quiet")
|
|
||||||
filters, err := parseFilters(c.StringSlice("filter"))
|
filters, err := parseFilters(c.StringSlice("filter"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -72,27 +91,52 @@ func cmdLs(c CommandLine, api libmachine.API) error {
|
||||||
hostList = filterHosts(hostList, filters)
|
hostList = filterHosts(hostList, filters)
|
||||||
|
|
||||||
// Just print out the names if we're being quiet
|
// Just print out the names if we're being quiet
|
||||||
if quiet {
|
if c.Bool("quiet") {
|
||||||
for _, host := range hostList {
|
for _, host := range hostList {
|
||||||
fmt.Println(host.Name)
|
fmt.Println(host.Name)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
t := template.New("lsConfig")
|
template, table, err := parseFormat(c.String("format"))
|
||||||
template, err := t.Parse(defaultLsTemplate + "\n")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var w io.Writer
|
||||||
|
if table {
|
||||||
|
tabWriter := tabwriter.NewWriter(os.Stdout, 5, 1, 3, ' ', 0)
|
||||||
|
defer tabWriter.Flush()
|
||||||
|
|
||||||
|
w = tabWriter
|
||||||
|
|
||||||
|
headers := &Headers{
|
||||||
|
Name: "NAME",
|
||||||
|
Active: "ACTIVE",
|
||||||
|
ActiveHost: "DRIVER",
|
||||||
|
ActiveSwarm: "STATE",
|
||||||
|
DriverName: "URL",
|
||||||
|
State: "STATE",
|
||||||
|
URL: "URL",
|
||||||
|
SwarmOptions: "SWARM_OPTIONS",
|
||||||
|
Swarm: "SWARM",
|
||||||
|
EngineOptions: "ENGINE_OPTIONS",
|
||||||
|
Error: "ERRORS",
|
||||||
|
DockerVersion: "DOCKER",
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := template.Execute(w, headers); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
w = os.Stdout
|
||||||
|
}
|
||||||
|
|
||||||
|
items := getHostListItems(hostList, hostInError)
|
||||||
|
|
||||||
swarmMasters := make(map[string]string)
|
swarmMasters := make(map[string]string)
|
||||||
swarmInfo := make(map[string]string)
|
swarmInfo := make(map[string]string)
|
||||||
|
|
||||||
w := tabwriter.NewWriter(os.Stdout, 5, 1, 3, ' ', 0)
|
|
||||||
defer w.Flush()
|
|
||||||
|
|
||||||
fmt.Fprintln(w, "NAME\tACTIVE\tDRIVER\tSTATE\tURL\tSWARM\tDOCKER\tERRORS")
|
|
||||||
|
|
||||||
for _, host := range hostList {
|
for _, host := range hostList {
|
||||||
if host.HostOptions != nil {
|
if host.HostOptions != nil {
|
||||||
swarmOptions := host.HostOptions.SwarmOptions
|
swarmOptions := host.HostOptions.SwarmOptions
|
||||||
|
@ -106,7 +150,6 @@ func cmdLs(c CommandLine, api libmachine.API) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
items := getHostListItems(hostList, hostInError)
|
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
swarmColumn := ""
|
swarmColumn := ""
|
||||||
if item.SwarmOptions != nil && item.SwarmOptions.Discovery != "" {
|
if item.SwarmOptions != nil && item.SwarmOptions.Discovery != "" {
|
||||||
|
@ -125,6 +168,31 @@ func cmdLs(c CommandLine, api libmachine.API) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseFormat(format string) (*template.Template, bool, error) {
|
||||||
|
table := false
|
||||||
|
finalFormat := format
|
||||||
|
|
||||||
|
if finalFormat == "" {
|
||||||
|
finalFormat = lsDefaultFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(finalFormat, tableFormatKey) {
|
||||||
|
table = true
|
||||||
|
finalFormat = finalFormat[len(tableFormatKey):]
|
||||||
|
}
|
||||||
|
|
||||||
|
finalFormat = strings.Trim(finalFormat, " ")
|
||||||
|
r := strings.NewReplacer(`\t`, "\t", `\n`, "\n")
|
||||||
|
finalFormat = r.Replace(finalFormat)
|
||||||
|
|
||||||
|
template, err := template.New("").Parse(finalFormat + "\n")
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return template, table, nil
|
||||||
|
}
|
||||||
|
|
||||||
func parseFilters(filters []string) (FilterOptions, error) {
|
func parseFilters(filters []string) (FilterOptions, error) {
|
||||||
options := FilterOptions{}
|
options := FilterOptions{}
|
||||||
for _, f := range filters {
|
for _, f := range filters {
|
||||||
|
|
|
@ -96,7 +96,7 @@ _docker_machine_ls() {
|
||||||
COMPREPLY=()
|
COMPREPLY=()
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
COMPREPLY=($(compgen -W "--quiet --filter --timeout --help" -- "${cur}"))
|
COMPREPLY=($(compgen -W "--quiet --filter --format --timeout --help" -- "${cur}"))
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ parent="smn_machine_subcmds"
|
||||||
--quiet, -q Enable quiet mode
|
--quiet, -q Enable quiet mode
|
||||||
--filter [--filter option --filter option] Filter output based on conditions provided
|
--filter [--filter option --filter option] Filter output based on conditions provided
|
||||||
--timeout, -t Timeout in seconds, default to 10s
|
--timeout, -t Timeout in seconds, default to 10s
|
||||||
|
--format, -f Pretty-print machines using a Go template
|
||||||
|
|
||||||
## Timeout
|
## Timeout
|
||||||
|
|
||||||
|
@ -47,6 +48,42 @@ The currently supported filters are:
|
||||||
- name (Machine name returned by driver, supports [golang style](https://github.com/google/re2/wiki/Syntax) regular expressions)
|
- name (Machine name returned by driver, supports [golang style](https://github.com/google/re2/wiki/Syntax) regular expressions)
|
||||||
- label (Machine created with `--engine-label` option, can be filtered with `label=<key>[=<value>]`)
|
- label (Machine created with `--engine-label` option, can be filtered with `label=<key>[=<value>]`)
|
||||||
|
|
||||||
|
## Formatting
|
||||||
|
|
||||||
|
The formatting option (`--format`) will pretty-print machines using a Go template.
|
||||||
|
|
||||||
|
Valid placeholders for the Go template are listed below:
|
||||||
|
|
||||||
|
| Placeholder | Description |
|
||||||
|
| -------------- | ---------------------------------------- |
|
||||||
|
| .Name | Machine name |
|
||||||
|
| .Active | Is the machine active? |
|
||||||
|
| .ActiveHost | Is the machine an active non-swarm host? |
|
||||||
|
| .ActiveSwarm | Is the machine an active swarm master? |
|
||||||
|
| .DriverName | Driver name |
|
||||||
|
| .State | Machine state (running, stopped...) |
|
||||||
|
| .URL | Machine URL |
|
||||||
|
| .Swarm | Machine swarm name |
|
||||||
|
| .Error | Machine errors |
|
||||||
|
| .DockerVersion | Docker Daemon version |
|
||||||
|
|
||||||
|
When using the `--format` option, the `ls` command will either output the data exactly as the template declares or,
|
||||||
|
when using the table directive, will include column headers as well.
|
||||||
|
|
||||||
|
The following example uses a template without headers and outputs the `Name` and `Driver` entries separated by a colon
|
||||||
|
for all running machines:
|
||||||
|
|
||||||
|
$ docker-machine ls --format "{{.Name}}: {{.DriverName}}"
|
||||||
|
default: virtualbox
|
||||||
|
ec2: amazonec2
|
||||||
|
|
||||||
|
To list all machine names with their driver in a table format you can use:
|
||||||
|
|
||||||
|
$ docker-machine ls --format "table {{.Name}}: {{.DriverName}}"
|
||||||
|
NAME DRIVER
|
||||||
|
default virtualbox
|
||||||
|
ec2 amazonec2
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
$ docker-machine ls
|
$ docker-machine ls
|
||||||
|
|
|
@ -165,3 +165,27 @@ bootstrap_swarm () {
|
||||||
[[ ${lines[1]} == "testswarm2" ]]
|
[[ ${lines[1]} == "testswarm2" ]]
|
||||||
[[ ${lines[2]} == "testswarm3" ]]
|
[[ ${lines[2]} == "testswarm3" ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "ls: format on driver 'machine ls --format '{{ .DriverName }}'" {
|
||||||
|
run machine ls --format '{{ .DriverName }}'
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ ${#lines[@]} == 5 ]]
|
||||||
|
[[ ${lines[0]} =~ "none" ]]
|
||||||
|
[[ ${lines[1]} =~ "none" ]]
|
||||||
|
[[ ${lines[2]} =~ "none" ]]
|
||||||
|
[[ ${lines[3]} =~ "none" ]]
|
||||||
|
[[ ${lines[4]} =~ "none" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@test "ls: format on name and driver 'machine ls --format 'table {{ .Name}}: {{ .DriverName }}'" {
|
||||||
|
run machine ls --format 'table {{ .Name}}: {{ .DriverName }}'
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ ${#lines[@]} == 6 ]]
|
||||||
|
[[ ${lines[1]} =~ "testmachine: none" ]]
|
||||||
|
[[ ${lines[2]} =~ "testmachine2: none" ]]
|
||||||
|
[[ ${lines[3]} =~ "testmachine3: none" ]]
|
||||||
|
[[ ${lines[4]} =~ "testmachine4: none" ]]
|
||||||
|
[[ ${lines[5]} =~ "testmachine5: none" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue