mirror of
https://github.com/kemko/nomad.git
synced 2026-01-06 18:35:44 +03:00
Merge pull request #1503 from nak3/add-printer
Support nomad CLI output with JSON and template format
This commit is contained in:
@@ -38,11 +38,17 @@ Alloc Status Options:
|
||||
-short
|
||||
Display short output. Shows only the most recent task event.
|
||||
|
||||
-stats
|
||||
Display detailed resource usage statistics
|
||||
-stats
|
||||
Display detailed resource usage statistics.
|
||||
|
||||
-verbose
|
||||
Show full information.
|
||||
|
||||
-json
|
||||
Output the allocation in its JSON format.
|
||||
|
||||
-t
|
||||
Format and display allocation using a Go template.
|
||||
`
|
||||
|
||||
return strings.TrimSpace(helpText)
|
||||
@@ -53,13 +59,16 @@ func (c *AllocStatusCommand) Synopsis() string {
|
||||
}
|
||||
|
||||
func (c *AllocStatusCommand) Run(args []string) int {
|
||||
var short, displayStats, verbose bool
|
||||
var short, displayStats, verbose, json bool
|
||||
var tmpl string
|
||||
|
||||
flags := c.Meta.FlagSet("alloc-status", FlagSetClient)
|
||||
flags.Usage = func() { c.Ui.Output(c.Help()) }
|
||||
flags.BoolVar(&short, "short", false, "")
|
||||
flags.BoolVar(&verbose, "verbose", false, "")
|
||||
flags.BoolVar(&displayStats, "stats", false, "")
|
||||
flags.BoolVar(&json, "json", false, "")
|
||||
flags.StringVar(&tmpl, "t", "", "")
|
||||
|
||||
if err := flags.Parse(args); err != nil {
|
||||
return 1
|
||||
@@ -67,11 +76,6 @@ func (c *AllocStatusCommand) Run(args []string) int {
|
||||
|
||||
// Check that we got exactly one allocation ID
|
||||
args = flags.Args()
|
||||
if len(args) != 1 {
|
||||
c.Ui.Error(c.Help())
|
||||
return 1
|
||||
}
|
||||
allocID := args[0]
|
||||
|
||||
// Get the HTTP client
|
||||
client, err := c.Meta.Client()
|
||||
@@ -80,6 +84,50 @@ func (c *AllocStatusCommand) Run(args []string) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
// If args not specified but output format is specified, format and output the allocations data list
|
||||
if len(args) == 0 {
|
||||
var format string
|
||||
if json && len(tmpl) > 0 {
|
||||
c.Ui.Error("Both -json and -t are not allowed")
|
||||
return 1
|
||||
} else if json {
|
||||
format = "json"
|
||||
} else if len(tmpl) > 0 {
|
||||
format = "template"
|
||||
}
|
||||
if len(format) > 0 {
|
||||
allocs, _, err := client.Allocations().List(nil)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error querying allocations: %v", err))
|
||||
return 1
|
||||
}
|
||||
// Return nothing if no allocations found
|
||||
if len(allocs) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
f, err := DataFormat(format, tmpl)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error getting formatter: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
out, err := f.TransformData(allocs)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error formatting the data: %s", err))
|
||||
return 1
|
||||
}
|
||||
c.Ui.Output(out)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
if len(args) != 1 {
|
||||
c.Ui.Error(c.Help())
|
||||
return 1
|
||||
}
|
||||
allocID := args[0]
|
||||
|
||||
// Truncate the id unless full length is requested
|
||||
length := shortId
|
||||
if verbose {
|
||||
@@ -130,6 +178,32 @@ func (c *AllocStatusCommand) Run(args []string) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
// If output format is specified, format and output the data
|
||||
var format string
|
||||
if json && len(tmpl) > 0 {
|
||||
c.Ui.Error("Both -json and -t are not allowed")
|
||||
return 1
|
||||
} else if json {
|
||||
format = "json"
|
||||
} else if len(tmpl) > 0 {
|
||||
format = "template"
|
||||
}
|
||||
if len(format) > 0 {
|
||||
f, err := DataFormat(format, tmpl)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error getting formatter: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
out, err := f.TransformData(alloc)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error formatting the data: %s", err))
|
||||
return 1
|
||||
}
|
||||
c.Ui.Output(out)
|
||||
return 0
|
||||
}
|
||||
|
||||
var statsErr error
|
||||
var stats *api.AllocResourceUsage
|
||||
stats, statsErr = client.Allocations().Stats(alloc, nil)
|
||||
|
||||
@@ -61,5 +61,13 @@ func TestAllocStatusCommand_Fails(t *testing.T) {
|
||||
if out := ui.ErrorWriter.String(); !strings.Contains(out, "No allocation(s) with prefix or id") {
|
||||
t.Fatalf("expected not found error, got: %s", out)
|
||||
}
|
||||
ui.ErrorWriter.Reset()
|
||||
|
||||
// Failed on both -json and -t options are specified
|
||||
if code := cmd.Run([]string{"-address=" + url, "-json", "-t", "{{.ID}}"}); code != 1 {
|
||||
t.Fatalf("expected exit 1, got: %d", code)
|
||||
}
|
||||
if out := ui.ErrorWriter.String(); !strings.Contains(out, "Both -json and -t are not allowed") {
|
||||
t.Fatalf("expected getting formatter error, got: %s", out)
|
||||
}
|
||||
}
|
||||
|
||||
65
command/data_format.go
Normal file
65
command/data_format.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
//DataFormatter is a transformer of the data.
|
||||
type DataFormatter interface {
|
||||
// TransformData should return transformed string data.
|
||||
TransformData(interface{}) (string, error)
|
||||
}
|
||||
|
||||
// DataFormat returns the data formatter specified format.
|
||||
func DataFormat(format, tmpl string) (DataFormatter, error) {
|
||||
switch format {
|
||||
case "json":
|
||||
if len(tmpl) > 0 {
|
||||
return nil, fmt.Errorf("json format does not support template option.")
|
||||
}
|
||||
return &JSONFormat{}, nil
|
||||
case "template":
|
||||
return &TemplateFormat{tmpl}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("Unsupported format is specified.")
|
||||
}
|
||||
|
||||
type JSONFormat struct {
|
||||
}
|
||||
|
||||
// TransformData returns JSON format string data.
|
||||
func (p *JSONFormat) TransformData(data interface{}) (string, error) {
|
||||
out, err := json.MarshalIndent(&data, "", " ")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(out), nil
|
||||
}
|
||||
|
||||
type TemplateFormat struct {
|
||||
tmpl string
|
||||
}
|
||||
|
||||
// TransformData returns template format string data.
|
||||
func (p *TemplateFormat) TransformData(data interface{}) (string, error) {
|
||||
var out io.Writer = new(bytes.Buffer)
|
||||
if len(p.tmpl) == 0 {
|
||||
return "", fmt.Errorf("template needs to be specified the golang templates.")
|
||||
}
|
||||
|
||||
t, err := template.New("format").Parse(p.tmpl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = t.Execute(out, data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprint(out), nil
|
||||
}
|
||||
64
command/data_format_test.go
Normal file
64
command/data_format_test.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type testData struct {
|
||||
Region string
|
||||
ID string
|
||||
Name string
|
||||
}
|
||||
|
||||
const expectJSON = `{
|
||||
"Region": "global",
|
||||
"ID": "1",
|
||||
"Name": "example"
|
||||
}`
|
||||
|
||||
var (
|
||||
tData = testData{"global", "1", "example"}
|
||||
testFormat = map[string]string{"json": "", "template": "{{.Region}}"}
|
||||
expectOutput = map[string]string{"json": expectJSON, "template": "global"}
|
||||
)
|
||||
|
||||
func TestDataFormat(t *testing.T) {
|
||||
for k, v := range testFormat {
|
||||
fm, err := DataFormat(k, v)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
result, err := fm.TransformData(tData)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
if result != expectOutput[k] {
|
||||
t.Fatalf("expected output: %s, actual: %s", expectOutput[k], result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidJSONTemplate(t *testing.T) {
|
||||
// Invalid template {{.foo}}
|
||||
fm, err := DataFormat("template", "{{.foo}}")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
_, err = fm.TransformData(tData)
|
||||
if !strings.Contains(err.Error(), "foo is not a field of struct type command.testData") {
|
||||
t.Fatalf("expected invalid template error, got: %s", err.Error())
|
||||
}
|
||||
|
||||
// No template is specified
|
||||
fm, err = DataFormat("template", "")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
_, err = fm.TransformData(tData)
|
||||
if !strings.Contains(err.Error(), "template needs to be specified the golang templates.") {
|
||||
t.Fatalf("expected not specified template error, got: %s", err.Error())
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,12 @@ Eval Status Options:
|
||||
|
||||
-verbose
|
||||
Show full information.
|
||||
|
||||
-json
|
||||
Output the evaluation in its JSON format.
|
||||
|
||||
-t
|
||||
Format and display evaluation using a Go template.
|
||||
`
|
||||
|
||||
return strings.TrimSpace(helpText)
|
||||
@@ -41,12 +47,15 @@ func (c *EvalStatusCommand) Synopsis() string {
|
||||
}
|
||||
|
||||
func (c *EvalStatusCommand) Run(args []string) int {
|
||||
var monitor, verbose bool
|
||||
var monitor, verbose, json bool
|
||||
var tmpl string
|
||||
|
||||
flags := c.Meta.FlagSet("eval-status", FlagSetClient)
|
||||
flags.Usage = func() { c.Ui.Output(c.Help()) }
|
||||
flags.BoolVar(&monitor, "monitor", false, "")
|
||||
flags.BoolVar(&verbose, "verbose", false, "")
|
||||
flags.BoolVar(&json, "json", false, "")
|
||||
flags.StringVar(&tmpl, "t", "", "")
|
||||
|
||||
if err := flags.Parse(args); err != nil {
|
||||
return 1
|
||||
@@ -54,11 +63,6 @@ func (c *EvalStatusCommand) Run(args []string) int {
|
||||
|
||||
// Check that we got exactly one evaluation ID
|
||||
args = flags.Args()
|
||||
if len(args) != 1 {
|
||||
c.Ui.Error(c.Help())
|
||||
return 1
|
||||
}
|
||||
evalID := args[0]
|
||||
|
||||
// Get the HTTP client
|
||||
client, err := c.Meta.Client()
|
||||
@@ -67,6 +71,51 @@ func (c *EvalStatusCommand) Run(args []string) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
// If args not specified but output format is specified, format and output the evaluations data list
|
||||
if len(args) == 0 {
|
||||
var format string
|
||||
if json && len(tmpl) > 0 {
|
||||
c.Ui.Error("Both -json and -t are not allowed")
|
||||
return 1
|
||||
} else if json {
|
||||
format = "json"
|
||||
} else if len(tmpl) > 0 {
|
||||
format = "template"
|
||||
}
|
||||
if len(format) > 0 {
|
||||
evals, _, err := client.Evaluations().List(nil)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error querying evaluations: %v", err))
|
||||
return 1
|
||||
}
|
||||
// Return nothing if no evaluations found
|
||||
if len(evals) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
f, err := DataFormat(format, tmpl)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error getting formatter: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
out, err := f.TransformData(evals)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error formatting the data: %s", err))
|
||||
return 1
|
||||
}
|
||||
c.Ui.Output(out)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
if len(args) != 1 {
|
||||
c.Ui.Error(c.Help())
|
||||
return 1
|
||||
}
|
||||
|
||||
evalID := args[0]
|
||||
|
||||
// Truncate the id unless full length is requested
|
||||
length := shortId
|
||||
if verbose {
|
||||
@@ -93,6 +142,7 @@ func (c *EvalStatusCommand) Run(args []string) int {
|
||||
c.Ui.Error(fmt.Sprintf("No evaluation(s) with prefix or id %q found", evalID))
|
||||
return 1
|
||||
}
|
||||
|
||||
if len(evals) > 1 {
|
||||
// Format the evals
|
||||
out := make([]string, len(evals)+1)
|
||||
@@ -124,6 +174,29 @@ func (c *EvalStatusCommand) Run(args []string) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
// If output format is specified, format and output the data
|
||||
var format string
|
||||
if json {
|
||||
format = "json"
|
||||
} else if len(tmpl) > 0 {
|
||||
format = "template"
|
||||
}
|
||||
if len(format) > 0 {
|
||||
f, err := DataFormat(format, tmpl)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error getting formatter: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
out, err := f.TransformData(eval)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error formatting the data: %s", err))
|
||||
return 1
|
||||
}
|
||||
c.Ui.Output(out)
|
||||
return 0
|
||||
}
|
||||
|
||||
failureString, failures := evalFailureStatus(eval)
|
||||
triggerNoun, triggerSubj := getTriggerDetails(eval)
|
||||
statusDesc := eval.StatusDescription
|
||||
|
||||
@@ -43,4 +43,14 @@ func TestEvalStatusCommand_Fails(t *testing.T) {
|
||||
if out := ui.ErrorWriter.String(); !strings.Contains(out, "Error querying evaluation") {
|
||||
t.Fatalf("expected failed query error, got: %s", out)
|
||||
}
|
||||
ui.ErrorWriter.Reset()
|
||||
|
||||
// Failed on both -json and -t options are specified
|
||||
if code := cmd.Run([]string{"-address=" + url, "-json", "-t", "{{.ID}}"}); code != 1 {
|
||||
t.Fatalf("expected exit 1, got: %d", code)
|
||||
}
|
||||
if out := ui.ErrorWriter.String(); !strings.Contains(out, "Both -json and -t are not allowed") {
|
||||
t.Fatalf("expected getting formatter error, got: %s", out)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,8 +20,16 @@ Usage: nomad inspect [options] <job>
|
||||
|
||||
General Options:
|
||||
|
||||
` + generalOptionsUsage()
|
||||
` + generalOptionsUsage() + `
|
||||
|
||||
Inspect Options:
|
||||
|
||||
-json
|
||||
Output the evaluation in its JSON format.
|
||||
|
||||
-t
|
||||
Format and display evaluation using a Go template.
|
||||
`
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
@@ -30,20 +38,18 @@ func (c *InspectCommand) Synopsis() string {
|
||||
}
|
||||
|
||||
func (c *InspectCommand) Run(args []string) int {
|
||||
var ojson bool
|
||||
var tmpl string
|
||||
|
||||
flags := c.Meta.FlagSet("inspect", FlagSetClient)
|
||||
flags.Usage = func() { c.Ui.Output(c.Help()) }
|
||||
flags.BoolVar(&ojson, "json", false, "")
|
||||
flags.StringVar(&tmpl, "t", "", "")
|
||||
|
||||
if err := flags.Parse(args); err != nil {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Check that we got exactly one job
|
||||
args = flags.Args()
|
||||
if len(args) != 1 {
|
||||
c.Ui.Error(c.Help())
|
||||
return 1
|
||||
}
|
||||
jobID := args[0]
|
||||
|
||||
// Get the HTTP client
|
||||
client, err := c.Meta.Client()
|
||||
@@ -52,6 +58,50 @@ func (c *InspectCommand) Run(args []string) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
// If args not specified but output format is specified, format and output the jobs data list
|
||||
if len(args) == 0 {
|
||||
var format string
|
||||
if ojson && len(tmpl) > 0 {
|
||||
c.Ui.Error("Both -json and -t are not allowed")
|
||||
return 1
|
||||
} else if ojson {
|
||||
format = "json"
|
||||
} else if len(tmpl) > 0 {
|
||||
format = "template"
|
||||
}
|
||||
if len(format) > 0 {
|
||||
jobs, _, err := client.Jobs().List(nil)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error querying jobs: %v", err))
|
||||
return 1
|
||||
}
|
||||
f, err := DataFormat(format, tmpl)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error getting formatter: %s", err))
|
||||
return 1
|
||||
}
|
||||
// Return nothing if no jobs found
|
||||
if len(jobs) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
out, err := f.TransformData(jobs)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error formatting the data: %s", err))
|
||||
return 1
|
||||
}
|
||||
c.Ui.Output(out)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// Check that we got exactly one job
|
||||
if len(args) != 1 {
|
||||
c.Ui.Error(c.Help())
|
||||
return 1
|
||||
}
|
||||
jobID := args[0]
|
||||
|
||||
// Check if the job exists
|
||||
jobs, _, err := client.Jobs().PrefixList(jobID)
|
||||
if err != nil {
|
||||
@@ -83,6 +133,29 @@ func (c *InspectCommand) Run(args []string) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
// If output format is specified, format and output the data
|
||||
var format string
|
||||
if ojson {
|
||||
format = "json"
|
||||
} else if len(tmpl) > 0 {
|
||||
format = "template"
|
||||
}
|
||||
if len(format) > 0 {
|
||||
f, err := DataFormat(format, tmpl)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error getting formatter: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
out, err := f.TransformData(job)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error formatting the data: %s", err))
|
||||
return 1
|
||||
}
|
||||
c.Ui.Output(out)
|
||||
return 0
|
||||
}
|
||||
|
||||
// Print the contents of the job
|
||||
req := api.RegisterJobRequest{Job: job}
|
||||
buf, err := json.MarshalIndent(req, "", " ")
|
||||
|
||||
@@ -43,4 +43,13 @@ func TestInspectCommand_Fails(t *testing.T) {
|
||||
if out := ui.ErrorWriter.String(); !strings.Contains(out, "Error inspecting job") {
|
||||
t.Fatalf("expected failed query error, got: %s", out)
|
||||
}
|
||||
ui.ErrorWriter.Reset()
|
||||
|
||||
// Failed on both -json and -t options are specified
|
||||
if code := cmd.Run([]string{"-address=" + url, "-json", "-t", "{{.ID}}"}); code != 1 {
|
||||
t.Fatalf("expected exit 1, got: %d", code)
|
||||
}
|
||||
if out := ui.ErrorWriter.String(); !strings.Contains(out, "Both -json and -t are not allowed") {
|
||||
t.Fatalf("expected getting formatter error, got: %s", out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ type NodeStatusCommand struct {
|
||||
list_allocs bool
|
||||
self bool
|
||||
stats bool
|
||||
json bool
|
||||
tmpl string
|
||||
}
|
||||
|
||||
func (c *NodeStatusCommand) Help() string {
|
||||
@@ -66,6 +68,12 @@ Node Status Options:
|
||||
|
||||
-verbose
|
||||
Display full information.
|
||||
|
||||
-json
|
||||
Output the node in its JSON format.
|
||||
|
||||
-t
|
||||
Format and display node using a Go template.
|
||||
`
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
@@ -83,6 +91,8 @@ func (c *NodeStatusCommand) Run(args []string) int {
|
||||
flags.BoolVar(&c.list_allocs, "allocs", false, "")
|
||||
flags.BoolVar(&c.self, "self", false, "")
|
||||
flags.BoolVar(&c.stats, "stats", false, "")
|
||||
flags.BoolVar(&c.json, "json", false, "")
|
||||
flags.StringVar(&c.tmpl, "t", "", "")
|
||||
|
||||
if err := flags.Parse(args); err != nil {
|
||||
return 1
|
||||
@@ -110,6 +120,17 @@ func (c *NodeStatusCommand) Run(args []string) int {
|
||||
|
||||
// Use list mode if no node name was provided
|
||||
if len(args) == 0 && !c.self {
|
||||
// If output format is specified, format and output the node data list
|
||||
var format string
|
||||
if c.json && len(c.tmpl) > 0 {
|
||||
c.Ui.Error("Both -json and -t are not allowed")
|
||||
return 1
|
||||
} else if c.json {
|
||||
format = "json"
|
||||
} else if len(c.tmpl) > 0 {
|
||||
format = "template"
|
||||
}
|
||||
|
||||
// Query the node info
|
||||
nodes, _, err := client.Nodes().List(nil)
|
||||
if err != nil {
|
||||
@@ -122,6 +143,22 @@ func (c *NodeStatusCommand) Run(args []string) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
if len(format) > 0 {
|
||||
f, err := DataFormat(format, c.tmpl)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error getting formatter: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
out, err := f.TransformData(nodes)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error formatting the data: %s", err))
|
||||
return 1
|
||||
}
|
||||
c.Ui.Output(out)
|
||||
return 0
|
||||
}
|
||||
|
||||
// Format the nodes list
|
||||
out := make([]string, len(nodes)+1)
|
||||
if c.list_allocs {
|
||||
@@ -129,6 +166,7 @@ func (c *NodeStatusCommand) Run(args []string) int {
|
||||
} else {
|
||||
out[0] = "ID|DC|Name|Class|Drain|Status"
|
||||
}
|
||||
|
||||
for i, node := range nodes {
|
||||
if c.list_allocs {
|
||||
numAllocs, err := getRunningAllocs(client, node.ID)
|
||||
@@ -216,6 +254,32 @@ func (c *NodeStatusCommand) Run(args []string) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
// If output format is specified, format and output the data
|
||||
var format string
|
||||
if c.json && len(c.tmpl) > 0 {
|
||||
c.Ui.Error("Both -json and -t are not allowed")
|
||||
return 1
|
||||
} else if c.json {
|
||||
format = "json"
|
||||
} else if len(c.tmpl) > 0 {
|
||||
format = "template"
|
||||
}
|
||||
if len(format) > 0 {
|
||||
f, err := DataFormat(format, c.tmpl)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error getting formatter: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
out, err := f.TransformData(node)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error formatting the data: %s", err))
|
||||
return 1
|
||||
}
|
||||
c.Ui.Output(out)
|
||||
return 0
|
||||
}
|
||||
|
||||
return c.formatNode(client, node)
|
||||
}
|
||||
|
||||
|
||||
@@ -200,4 +200,13 @@ func TestNodeStatusCommand_Fails(t *testing.T) {
|
||||
if out := ui.ErrorWriter.String(); !strings.Contains(out, "must contain at least two characters.") {
|
||||
t.Fatalf("expected too few characters error, got: %s", out)
|
||||
}
|
||||
ui.ErrorWriter.Reset()
|
||||
|
||||
// Failed on both -json and -t options are specified
|
||||
if code := cmd.Run([]string{"-address=" + url, "-json", "-t", "{{.ID}}"}); code != 1 {
|
||||
t.Fatalf("expected exit 1, got: %d", code)
|
||||
}
|
||||
if out := ui.ErrorWriter.String(); !strings.Contains(out, "Both -json and -t are not allowed") {
|
||||
t.Fatalf("expected getting formatter error, got: %s", out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ allocations and information will be displayed.
|
||||
|
||||
* `-short`: Display short output. Shows only the most recent task event.
|
||||
* `-verbose`: Show full information.
|
||||
* `-json` : Output the allocation in its JSON format.
|
||||
* `-t` : Format and display allocation using a Go template.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -48,6 +48,10 @@ indicated by exit code 1.
|
||||
|
||||
* `-verbose`: Show full information.
|
||||
|
||||
* `-json` : Output the evaluation in its JSON format.
|
||||
|
||||
* `-t` : Format and display evaluation using a Go template.
|
||||
|
||||
## Examples
|
||||
|
||||
Show the status of an evaluation that has placement failures
|
||||
|
||||
@@ -25,6 +25,13 @@ version of a job Nomad is running.
|
||||
|
||||
<%= general_options_usage %>
|
||||
|
||||
## Inspect Options
|
||||
|
||||
* `-short`: Display short output. Used only when a single node is being queried.
|
||||
Drops verbose node allocation data from the output.
|
||||
|
||||
* `-verbose`: Show full information.
|
||||
|
||||
## Examples
|
||||
|
||||
Inspect a submitted job:
|
||||
|
||||
@@ -45,6 +45,10 @@ information will be displayed. If running the command on a Nomad Client, the
|
||||
|
||||
* `-verbose`: Show full information.
|
||||
|
||||
* `-json` : Output the node in its JSON format.
|
||||
|
||||
* `-t` : Format and display node using a Go template.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
Reference in New Issue
Block a user