-
Notifications
You must be signed in to change notification settings - Fork 4.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Deprecate configtest and add validate command #2732
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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! | ||
``` | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kyhavlov I still think it'd be a better UX to just accept one option here and determine if it's a file or folder appropriately. I don't see a reason why we need to treat them separately.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left those in as hidden flags to stay compatible with configtest; everything (args,
-config-file
,config-dir
) gets added toconfigFiles
which works with files or directories. Do you think we should just remove the flags from validate altogether?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah sorry. I didn't see the "hidden" call below. +1 to BC! Great work on this and sorry for the confusion