Skip to content

Commit

Permalink
command/configtest: add
Browse files Browse the repository at this point in the history
  • Loading branch information
josephholsten committed May 8, 2015
1 parent a86f315 commit afbf688
Show file tree
Hide file tree
Showing 4 changed files with 208 additions and 0 deletions.
61 changes: 61 additions & 0 deletions command/configtest.go
Original file line number Diff line number Diff line change
@@ -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 changes: 105 additions & 0 deletions command/configtest_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
6 changes: 6 additions & 0 deletions commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ func init() {
}, nil
},

"configtest": func() (cli.Command, error) {
return &command.ConfigTestCommand{
Ui: ui,
}, nil
},

"event": func() (cli.Command, error) {
return &command.EventCommand{
Ui: ui,
Expand Down
36 changes: 36 additions & 0 deletions website/source/docs/commands/configtest.html.markdown
Original file line number Diff line number Diff line change
@@ -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.

0 comments on commit afbf688

Please sign in to comment.