mirror of https://github.com/hashicorp/consul
Kyle Havlovitz
8 years ago
committed by
GitHub
9 changed files with 291 additions and 42 deletions
@ -0,0 +1,75 @@
|
||||
package command |
||||
|
||||
import ( |
||||
"fmt" |
||||
"strings" |
||||
|
||||
"github.com/hashicorp/consul/command/agent" |
||||
"github.com/hashicorp/consul/command/base" |
||||
) |
||||
|
||||
// ValidateCommand is a Command implementation that is used to
|
||||
// verify config files
|
||||
type ValidateCommand struct { |
||||
base.Command |
||||
} |
||||
|
||||
func (c *ValidateCommand) Help() string { |
||||
helpText := ` |
||||
Usage: consul validate [options] FILE_OR_DIRECTORY... |
||||
|
||||
Performs a basic sanity test on Consul configuration files. For each file |
||||
or directory given, the validate command will attempt to parse the |
||||
contents just as the "consul agent" command would, and catch any errors. |
||||
This is useful to do a test of the configuration only, without actually |
||||
starting the agent. |
||||
|
||||
Returns 0 if the configuration is valid, or 1 if there are problems. |
||||
|
||||
` + c.Command.Help() |
||||
|
||||
return strings.TrimSpace(helpText) |
||||
} |
||||
|
||||
func (c *ValidateCommand) Run(args []string) int { |
||||
var configFiles []string |
||||
var quiet bool |
||||
|
||||
f := c.Command.NewFlagSet(c) |
||||
f.Var((*agent.AppendSliceValue)(&configFiles), "config-file", |
||||
"Path to a JSON file to read configuration from. This can be specified multiple times.") |
||||
f.Var((*agent.AppendSliceValue)(&configFiles), "config-dir", |
||||
"Path to a directory to read configuration files from. This will read every file ending in "+ |
||||
".json as configuration in this directory in alphabetical order.") |
||||
f.BoolVar(&quiet, "quiet", false, |
||||
"When given, a successful run will produce no output.") |
||||
c.Command.HideFlags("config-file", "config-dir") |
||||
|
||||
if err := c.Command.Parse(args); err != nil { |
||||
return 1 |
||||
} |
||||
|
||||
if len(f.Args()) > 0 { |
||||
configFiles = append(configFiles, f.Args()...) |
||||
} |
||||
|
||||
if len(configFiles) < 1 { |
||||
c.Ui.Error("Must specify at least one config file or directory") |
||||
return 1 |
||||
} |
||||
|
||||
_, err := agent.ReadConfigPaths(configFiles) |
||||
if err != nil { |
||||
c.Ui.Error(fmt.Sprintf("Config validation failed: %v", err.Error())) |
||||
return 1 |
||||
} |
||||
|
||||
if !quiet { |
||||
c.Ui.Output("Configuration is valid!") |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (c *ValidateCommand) Synopsis() string { |
||||
return "Validate config files/directories" |
||||
} |
@ -0,0 +1,140 @@
|
||||
package command |
||||
|
||||
import ( |
||||
"io/ioutil" |
||||
"os" |
||||
"path/filepath" |
||||
"testing" |
||||
|
||||
"github.com/hashicorp/consul/command/base" |
||||
"github.com/mitchellh/cli" |
||||
) |
||||
|
||||
func testValidateCommand(t *testing.T) (*cli.MockUi, *ValidateCommand) { |
||||
ui := new(cli.MockUi) |
||||
return ui, &ValidateCommand{ |
||||
Command: base.Command{ |
||||
Ui: ui, |
||||
Flags: base.FlagSetNone, |
||||
}, |
||||
} |
||||
} |
||||
|
||||
func TestValidateCommand_implements(t *testing.T) { |
||||
var _ cli.Command = &ValidateCommand{} |
||||
} |
||||
|
||||
func TestValidateCommandFailOnEmptyFile(t *testing.T) { |
||||
tmpFile, err := ioutil.TempFile("", "consul") |
||||
if err != nil { |
||||
t.Fatalf("err: %s", err) |
||||
} |
||||
defer os.RemoveAll(tmpFile.Name()) |
||||
|
||||
_, cmd := testValidateCommand(t) |
||||
|
||||
args := []string{tmpFile.Name()} |
||||
|
||||
if code := cmd.Run(args); code == 0 { |
||||
t.Fatalf("bad: %d", code) |
||||
} |
||||
} |
||||
|
||||
func TestValidateCommandSucceedOnEmptyDir(t *testing.T) { |
||||
td, err := ioutil.TempDir("", "consul") |
||||
if err != nil { |
||||
t.Fatalf("err: %s", err) |
||||
} |
||||
defer os.RemoveAll(td) |
||||
|
||||
ui, cmd := testValidateCommand(t) |
||||
|
||||
args := []string{td} |
||||
|
||||
if code := cmd.Run(args); code != 0 { |
||||
t.Fatalf("bad: %d, %s", code, ui.ErrorWriter.String()) |
||||
} |
||||
} |
||||
|
||||
func TestValidateCommandSucceedOnMinimalConfigFile(t *testing.T) { |
||||
td, err := ioutil.TempDir("", "consul") |
||||
if err != nil { |
||||
t.Fatalf("err: %s", err) |
||||
} |
||||
defer os.RemoveAll(td) |
||||
|
||||
fp := filepath.Join(td, "config.json") |
||||
err = ioutil.WriteFile(fp, []byte(`{}`), 0644) |
||||
if err != nil { |
||||
t.Fatalf("err: %s", err) |
||||
} |
||||
|
||||
_, cmd := testValidateCommand(t) |
||||
|
||||
args := []string{fp} |
||||
|
||||
if code := cmd.Run(args); code != 0 { |
||||
t.Fatalf("bad: %d", code) |
||||
} |
||||
} |
||||
|
||||
func TestValidateCommandSucceedOnMinimalConfigDir(t *testing.T) { |
||||
td, err := ioutil.TempDir("", "consul") |
||||
if err != nil { |
||||
t.Fatalf("err: %s", err) |
||||
} |
||||
defer os.RemoveAll(td) |
||||
|
||||
err = ioutil.WriteFile(filepath.Join(td, "config.json"), []byte(`{}`), 0644) |
||||
if err != nil { |
||||
t.Fatalf("err: %s", err) |
||||
} |
||||
|
||||
_, cmd := testValidateCommand(t) |
||||
|
||||
args := []string{td} |
||||
|
||||
if code := cmd.Run(args); code != 0 { |
||||
t.Fatalf("bad: %d", code) |
||||
} |
||||
} |
||||
|
||||
func TestValidateCommandSucceedOnConfigDirWithEmptyFile(t *testing.T) { |
||||
td, err := ioutil.TempDir("", "consul") |
||||
if err != nil { |
||||
t.Fatalf("err: %s", err) |
||||
} |
||||
defer os.RemoveAll(td) |
||||
|
||||
err = ioutil.WriteFile(filepath.Join(td, "config.json"), []byte{}, 0644) |
||||
if err != nil { |
||||
t.Fatalf("err: %s", err) |
||||
} |
||||
|
||||
_, cmd := testValidateCommand(t) |
||||
|
||||
args := []string{td} |
||||
|
||||
if code := cmd.Run(args); code != 0 { |
||||
t.Fatalf("bad: %d", code) |
||||
} |
||||
} |
||||
|
||||
func TestValidateCommandQuiet(t *testing.T) { |
||||
td, err := ioutil.TempDir("", "consul") |
||||
if err != nil { |
||||
t.Fatalf("err: %s", err) |
||||
} |
||||
defer os.RemoveAll(td) |
||||
|
||||
ui, cmd := testValidateCommand(t) |
||||
|
||||
args := []string{"-quiet", td} |
||||
|
||||
if code := cmd.Run(args); code != 0 { |
||||
t.Fatalf("bad: %d, %s", code, ui.ErrorWriter.String()) |
||||
} |
||||
if ui.OutputWriter.String() != "<nil>" { |
||||
t.Fatalf("bad: %v", ui.OutputWriter.String()) |
||||
} |
||||
} |
@ -1,34 +0,0 @@
|
||||
--- |
||||
layout: "docs" |
||||
page_title: "Commands: ConfigTest" |
||||
sidebar_current: "docs-commands-configtest" |
||||
description: > |
||||
The `consul configtest` command tests that config files are valid by |
||||
attempting to parse them. Useful to ensure a configuration change will |
||||
not cause consul to fail after a restart. |
||||
--- |
||||
|
||||
# Consul ConfigTest |
||||
|
||||
The `consul configtest` command performs a basic sanity test on Consul |
||||
configuration files. For each file or directory given, the configtest command |
||||
will attempt to parse the contents just as the "consul agent" command would, |
||||
and catch any errors. This is useful to do a test of the configuration only, |
||||
without actually starting the agent. |
||||
|
||||
For more information on the format of Consul's configuration files, read the |
||||
consul agent [Configuration Files](/docs/agent/options.html#configuration_files) |
||||
section. |
||||
|
||||
## Usage |
||||
|
||||
Usage: `consul configtest [options]` |
||||
|
||||
At least one `-config-file` or `-config-dir` parameter must be given. Returns 0 |
||||
if the configuration is valid, or 1 if there are problems. The list of |
||||
available flags are: |
||||
|
||||
* `-config-file` - Path to a config file. May be specified multiple times. |
||||
|
||||
* `-config-dir` - Path to a directory of config files. All files ending in |
||||
`.json` in the directory will be included. May be specified multiple times. |
@ -0,0 +1,39 @@
|
||||
--- |
||||
layout: "docs" |
||||
page_title: "Commands: Validate" |
||||
sidebar_current: "docs-commands-validate" |
||||
description: > |
||||
The `consul validate` command tests that config files are valid by |
||||
attempting to parse them. Useful to ensure a configuration change will |
||||
not cause consul to fail after a restart. |
||||
--- |
||||
|
||||
# Consul Validate |
||||
|
||||
The `consul validate` command performs a basic sanity test on Consul |
||||
configuration files. For each file or directory given, the validate command |
||||
will attempt to parse the contents just as the "consul agent" command would, |
||||
and catch any errors. This is useful to do a test of the configuration only, |
||||
without actually starting the agent. |
||||
|
||||
For more information on the format of Consul's configuration files, read the |
||||
consul agent [Configuration Files](/docs/agent/options.html#configuration_files) |
||||
section. |
||||
|
||||
## Usage |
||||
|
||||
Usage: `consul validate [options] FILE_OR_DIRECTORY...` |
||||
|
||||
Performs a basic sanity test on Consul configuration files. For each file |
||||
or directory given, the validate command will attempt to parse the |
||||
contents just as the "consul agent" command would, and catch any errors. |
||||
This is useful to do a test of the configuration only, without actually |
||||
starting the agent. |
||||
|
||||
Returns 0 if the configuration is valid, or 1 if there are problems. |
||||
|
||||
```text |
||||
$ consul validate /etc/consul.d |
||||
Configuration is valid! |
||||
``` |
||||
|
Loading…
Reference in new issue