command/validate: Adding new command

This commit is contained in:
Armon Dadgar 2015-09-24 18:29:46 -07:00
parent fce6a5f7c7
commit 77a9e52449
5 changed files with 197 additions and 0 deletions

60
command/validate.go Normal file
View File

@ -0,0 +1,60 @@
package command
import (
"fmt"
"strings"
"github.com/hashicorp/nomad/jobspec"
)
type ValidateCommand struct {
Meta
}
func (c *ValidateCommand) Help() string {
helpText := `
Usage: nomad validate [options] <file>
Checks if a given job file has a valid specification. This can be used to check
for any syntax errors or validation problems with a job.
`
return strings.TrimSpace(helpText)
}
func (c *ValidateCommand) Synopsis() string {
return "Checks if a given job specification is valid"
}
func (c *ValidateCommand) Run(args []string) int {
flags := c.Meta.FlagSet("validate", FlagSetNone)
flags.Usage = func() { c.Ui.Output(c.Help()) }
if err := flags.Parse(args); err != nil {
return 1
}
// Check that we got exactly one node
args = flags.Args()
if len(args) != 1 {
c.Ui.Error(c.Help())
return 1
}
file := args[0]
// Parse the job file
job, err := jobspec.ParseFile(file)
if err != nil {
c.Ui.Error(fmt.Sprintf("Error parsing job file %s: %s", file, err))
return 1
}
// Check that the job is valid
if err := job.Validate(); err != nil {
c.Ui.Error(fmt.Sprintf("Error validating job: %s", err))
return 1
}
// Done!
c.Ui.Output("Job validation successful")
return 0
}

102
command/validate_test.go Normal file
View File

@ -0,0 +1,102 @@
package command
import (
"io/ioutil"
"os"
"strings"
"testing"
"github.com/mitchellh/cli"
)
func TestValidateCommand_Implements(t *testing.T) {
var _ cli.Command = &ValidateCommand{}
}
func TestValidateCommand(t *testing.T) {
ui := new(cli.MockUi)
cmd := &ValidateCommand{Meta: Meta{Ui: ui}}
fh, err := ioutil.TempFile("", "nomad")
if err != nil {
t.Fatalf("err: %s", err)
}
defer os.Remove(fh.Name())
_, err = fh.WriteString(`
job "job1" {
datacenters = [ "dc1" ]
group "group1" {
count = 1
task "task1" {
driver = "exec"
resources = {
cpu = 1000
mem = 512
}
}
}
}`)
if err != nil {
t.Fatalf("err: %s", err)
}
if code := cmd.Run([]string{fh.Name()}); code != 0 {
t.Fatalf("expect exit 0, got: %d: %s", code, ui.ErrorWriter.String())
}
}
func TestValidateCommand_Fails(t *testing.T) {
ui := new(cli.MockUi)
cmd := &ValidateCommand{Meta: Meta{Ui: ui}}
// Fails on misuse
if code := cmd.Run([]string{"some", "bad", "args"}); code != 1 {
t.Fatalf("expected exit code 1, got: %d", code)
}
if out := ui.ErrorWriter.String(); !strings.Contains(out, cmd.Help()) {
t.Fatalf("expected help output, got: %s", out)
}
ui.ErrorWriter.Reset()
// Fails when specified file does not exist
if code := cmd.Run([]string{"/unicorns/leprechauns"}); code != 1 {
t.Fatalf("expect exit 1, got: %d", code)
}
if out := ui.ErrorWriter.String(); !strings.Contains(out, "Error parsing") {
t.Fatalf("expect parsing error, got: %s", out)
}
ui.ErrorWriter.Reset()
// Fails on invalid HCL
fh1, err := ioutil.TempFile("", "nomad")
if err != nil {
t.Fatalf("err: %s", err)
}
defer os.Remove(fh1.Name())
if _, err := fh1.WriteString("nope"); err != nil {
t.Fatalf("err: %s", err)
}
if code := cmd.Run([]string{fh1.Name()}); code != 1 {
t.Fatalf("expect exit 1, got: %d", code)
}
if out := ui.ErrorWriter.String(); !strings.Contains(out, "Error parsing") {
t.Fatalf("expect parsing error, got: %s", err)
}
ui.ErrorWriter.Reset()
// Fails on invalid job spec
fh2, err := ioutil.TempFile("", "nomad")
if err != nil {
t.Fatalf("err: %s", err)
}
defer os.Remove(fh2.Name())
if _, err := fh2.WriteString(`job "job1" {}`); err != nil {
t.Fatalf("err: %s", err)
}
if code := cmd.Run([]string{fh2.Name()}); code != 1 {
t.Fatalf("expect exit 1, got: %d", code)
}
if out := ui.ErrorWriter.String(); !strings.Contains(out, "Error validating") {
t.Fatalf("expect validation error, got: %s", out)
}
ui.ErrorWriter.Reset()
}

View File

@ -106,6 +106,12 @@ func Commands(metaPtr *command.Meta) map[string]cli.CommandFactory {
}, nil
},
"validate": func() (cli.Command, error) {
return &command.ValidateCommand{
Meta: meta,
}, nil
},
"version": func() (cli.Command, error) {
ver := Version
rel := VersionPrerelease

View File

@ -0,0 +1,26 @@
---
layout: "docs"
page_title: "Commands: validate"
sidebar_current: "docs-commands-validate"
description: >
The validate command is used to check a job specification for syntax errors and validation problems.
---
# Command: validate
The `validate` command is used to check a [job specification](/docs/jobspec/index.html)
for any syntax errors or validation problems.
## Usage
```
nomad validate <file>
```
The validate command requires a single argument, specifying the path to a file
containing a valid [job specification](/docs/jobspec/index.html). This file
will be read and the job checked for any problems.
On successful validation, exit code 0 will be returned, otherwise an exit code
of 1 indicates an error.

View File

@ -105,6 +105,9 @@
</li>
<li<%= sidebar_current("docs-commands-stop") %>>
<a href="/docs/commands/stop.html">stop</a>
</li>
<li<%= sidebar_current("docs-commands-validate") %>>
<a href="/docs/commands/validate.html">validate</a>
</li>
<li<%= sidebar_current("docs-commands-version") %>>
<a href="/docs/commands/version.html">version</a>