Support JSON and template format with nomad CLI

This commit is contained in:
Kenjiro Nakayama
2016-07-30 19:20:43 +09:00
parent 044e0672e3
commit 6c694014b4
6 changed files with 206 additions and 2 deletions

View File

@@ -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.
-format
Display specified format, "json" or "template".
-t
Sets the template with golang templates format.
`
return strings.TrimSpace(helpText)
@@ -54,12 +60,15 @@ func (c *AllocStatusCommand) Synopsis() string {
func (c *AllocStatusCommand) Run(args []string) int {
var short, displayStats, verbose bool
var format, 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.StringVar(&format, "format", "default", "")
flags.StringVar(&tmpl, "t", "", "")
if err := flags.Parse(args); err != nil {
return 1
@@ -130,6 +139,23 @@ func (c *AllocStatusCommand) Run(args []string) int {
return 1
}
// If output format is specified, format and output the data
if format != "default" {
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 transform 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)

58
command/data_format.go Normal file
View File

@@ -0,0 +1,58 @@
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":
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 := template.Must(template.New("format").Parse(p.tmpl))
err := t.Execute(out, data)
if err != nil {
return "", err
}
return fmt.Sprint(out), nil
}

View File

@@ -0,0 +1,41 @@
package command
import (
"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)
}
}
}

View File

@@ -31,6 +31,12 @@ Eval Status Options:
-verbose
Show full information.
-format
Display specified format, "json" or "template".
-t
Sets the template with golang templates format.
`
return strings.TrimSpace(helpText)
@@ -42,11 +48,14 @@ func (c *EvalStatusCommand) Synopsis() string {
func (c *EvalStatusCommand) Run(args []string) int {
var monitor, verbose bool
var format, 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.StringVar(&format, "format", "default", "")
flags.StringVar(&tmpl, "t", "", "")
if err := flags.Parse(args); err != nil {
return 1
@@ -124,6 +133,23 @@ func (c *EvalStatusCommand) Run(args []string) int {
return 1
}
// If output format is specified, format and output the data
if format != "default" {
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 transform the data: %s", err))
return 1
}
c.Ui.Output(out)
return 0
}
failureString, failures := evalFailureStatus(eval)
triggerNoun, triggerSubj := getTriggerDetails(eval)
statusDesc := eval.StatusDescription

View File

@@ -30,6 +30,8 @@ type NodeStatusCommand struct {
list_allocs bool
self bool
stats bool
format string
tmpl string
}
func (c *NodeStatusCommand) Help() string {
@@ -66,6 +68,12 @@ Node Status Options:
-verbose
Display full information.
-format
Display specified format, "json" or "template".
-t
Sets the template with golang templates format.
`
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.StringVar(&c.format, "format", "default", "")
flags.StringVar(&c.tmpl, "t", "", "")
if err := flags.Parse(args); err != nil {
return 1
@@ -216,6 +226,23 @@ func (c *NodeStatusCommand) Run(args []string) int {
return 1
}
// If output format is specified, format and output the data
if c.format != "default" {
f, err := DataFormat(c.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 transform the data: %s", err))
return 1
}
c.Ui.Output(out)
return 0
}
return c.formatNode(client, node)
}

View File

@@ -46,6 +46,12 @@ Status Options:
-verbose
Display full information.
-format
Display specified format, "json" or "template".
-t
Sets the template with golang templates format.
`
return strings.TrimSpace(helpText)
}
@@ -56,12 +62,15 @@ func (c *StatusCommand) Synopsis() string {
func (c *StatusCommand) Run(args []string) int {
var short bool
var format, tmpl string
flags := c.Meta.FlagSet("status", FlagSetClient)
flags.Usage = func() { c.Ui.Output(c.Help()) }
flags.BoolVar(&short, "short", false, "")
flags.BoolVar(&c.showEvals, "evals", false, "")
flags.BoolVar(&c.verbose, "verbose", false, "")
flags.StringVar(&format, "format", "default", "")
flags.StringVar(&tmpl, "t", "", "")
if err := flags.Parse(args); err != nil {
return 1
@@ -145,6 +154,23 @@ func (c *StatusCommand) Run(args []string) int {
return 1
}
// If output format is specified, format and output the data
if format != "default" {
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 transform the data: %s", err))
return 1
}
c.Ui.Output(out)
return 0
}
// Check if it is periodic
sJob, err := convertApiJob(job)
if err != nil {