Merge pull request #904 from josephholsten/configtest-clean

add minimal configtest command
This commit is contained in:
Ryan Uber 2015-05-11 09:01:54 -07:00
commit 3ad94bd81d
4 changed files with 208 additions and 0 deletions

61
command/configtest.go Normal file
View File

@ -0,0 +1,61 @@
package command
import (
"flag"
"fmt"
"strings"
"github.com/hashicorp/consul/command/agent"
"github.com/mitchellh/cli"
)
// ConfigTestCommand is a Command implementation that is used to
// verify config files
type ConfigTestCommand struct {
Ui cli.Ui
}
func (c *ConfigTestCommand) Help() string {
helpText := `
Usage: consul configtest [options]
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.
Options:
-config-file=foo Path to a JSON file to read configuration from.
This can be specified multiple times.
-config-dir=foo 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.
`
return strings.TrimSpace(helpText)
}
func (c *ConfigTestCommand) Run(args []string) int {
var configFiles []string
cmdFlags := flag.NewFlagSet("configtest", flag.ContinueOnError)
cmdFlags.Usage = func() { c.Ui.Output(c.Help()) }
cmdFlags.Var((*agent.AppendSliceValue)(&configFiles), "config-file", "json file to read config from")
cmdFlags.Var((*agent.AppendSliceValue)(&configFiles), "config-dir", "directory of json files to read")
if err := cmdFlags.Parse(args); err != nil {
return 1
}
if len(configFiles) <= 0 {
c.Ui.Error("Must specify config using -config-file or -config-dir")
return 1
}
_, err := agent.ReadConfigPaths(configFiles)
if err != nil {
c.Ui.Error(fmt.Sprintf("Config validation failed: %v", err.Error()))
return 1
}
return 0
}
func (c *ConfigTestCommand) Synopsis() string {
return "Validate config file"
}

105
command/configtest_test.go Normal file
View File

@ -0,0 +1,105 @@
package command
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/mitchellh/cli"
)
func TestConfigTestCommand_implements(t *testing.T) {
var _ cli.Command = &ConfigTestCommand{}
}
func TestConfigTestCommandFailOnEmptyFile(t *testing.T) {
tmpFile, err := ioutil.TempFile("", "consul")
if err != nil {
t.Fatalf("err: %s", err)
}
defer os.RemoveAll(tmpFile.Name())
cmd := &ConfigTestCommand{
Ui: new(cli.MockUi),
}
args := []string{
"-config-file", tmpFile.Name(),
}
if code := cmd.Run(args); code == 0 {
t.Fatalf("bad: %d", code)
}
}
func TestConfigTestCommandSucceedOnEmptyDir(t *testing.T) {
td, err := ioutil.TempDir("", "consul")
if err != nil {
t.Fatalf("err: %s", err)
}
defer os.RemoveAll(td)
cmd := &ConfigTestCommand{
Ui: new(cli.MockUi),
}
args := []string{
"-config-dir", td,
}
if code := cmd.Run(args); code != 0 {
t.Fatalf("bad: %d", code)
}
}
func TestConfigTestCommandSucceedOnMinimalConfigFile(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 := &ConfigTestCommand{
Ui: new(cli.MockUi),
}
args := []string{
"-config-file", fp,
}
if code := cmd.Run(args); code != 0 {
t.Fatalf("bad: %d", code)
}
}
func TestConfigTestCommandSucceedOnMinimalConfigDir(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 := &ConfigTestCommand{
Ui: new(cli.MockUi),
}
args := []string{
"-config-dir", td,
}
if code := cmd.Run(args); code != 0 {
t.Fatalf("bad: %d", code)
}
}

View File

@ -27,6 +27,12 @@ func init() {
}, nil }, nil
}, },
"configtest": func() (cli.Command, error) {
return &command.ConfigTestCommand{
Ui: ui,
}, nil
},
"event": func() (cli.Command, error) { "event": func() (cli.Command, error) {
return &command.EventCommand{ return &command.EventCommand{
Ui: ui, Ui: ui,

View File

@ -0,0 +1,36 @@
---
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 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.
## Usage
Usage: `consul configtest [options]`
At least one `-config-file` or `-config-dir` paramater must be given. The list of available flags are:
- `-config-file` - config file. may be specified multiple times
- `-config-dir` - config directory. all files ending in `.json` in the directory will be included. may be specified multiple times.
* <a name="config_file"></a> `-config-file` - A configuration file
to load. For more information on
the format of this file, read the [Configuration Files](/docs/agent/options.html#configuration_files) section in the agent option documentation.
This option can be specified multiple times to load multiple configuration
files. If it is specified multiple times, configuration files loaded later
will merge with configuration files loaded earlier. During a config merge,
single-value keys (string, int, bool) will simply have their values replaced
while list types will be appended together.
* `-config-dir` - A directory of
configuration files to load. Consul will
load all files in this directory with the suffix ".json". The load order
is alphabetical, and the the same merge routine is used as with the
[`config-file`](#_config_file) option above. For more information
on the format of the configuration files, see the [Configuration Files](/docs/agent/options.html#configuration_files) section in the agent option documentation.