mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-27 06:03:48 +03:00
cmd: Add validate subcommand; list-modules --versions; some renaming
Renames --config-adapter flag to --adapter, adapt-config command to adapt, --print-env flag to --environ, and --input flag to --config.
This commit is contained in:
parent
0006df6026
commit
5b36424cf0
2 changed files with 154 additions and 24 deletions
|
@ -26,6 +26,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"reflect"
|
||||||
|
"runtime/debug"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/caddyserver/caddy/v2"
|
"github.com/caddyserver/caddy/v2"
|
||||||
|
@ -36,7 +38,7 @@ import (
|
||||||
|
|
||||||
func cmdStart(fl Flags) (int, error) {
|
func cmdStart(fl Flags) (int, error) {
|
||||||
startCmdConfigFlag := fl.String("config")
|
startCmdConfigFlag := fl.String("config")
|
||||||
startCmdConfigAdapterFlag := fl.String("config-adapter")
|
startCmdConfigAdapterFlag := fl.String("adapter")
|
||||||
|
|
||||||
// open a listener to which the child process will connect when
|
// open a listener to which the child process will connect when
|
||||||
// it is ready to confirm that it has successfully started
|
// it is ready to confirm that it has successfully started
|
||||||
|
@ -61,7 +63,7 @@ func cmdStart(fl Flags) (int, error) {
|
||||||
cmd.Args = append(cmd.Args, "--config", startCmdConfigFlag)
|
cmd.Args = append(cmd.Args, "--config", startCmdConfigFlag)
|
||||||
}
|
}
|
||||||
if startCmdConfigAdapterFlag != "" {
|
if startCmdConfigAdapterFlag != "" {
|
||||||
cmd.Args = append(cmd.Args, "--config-adapter", startCmdConfigAdapterFlag)
|
cmd.Args = append(cmd.Args, "--adapter", startCmdConfigAdapterFlag)
|
||||||
}
|
}
|
||||||
stdinpipe, err := cmd.StdinPipe()
|
stdinpipe, err := cmd.StdinPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -137,8 +139,8 @@ func cmdStart(fl Flags) (int, error) {
|
||||||
|
|
||||||
func cmdRun(fl Flags) (int, error) {
|
func cmdRun(fl Flags) (int, error) {
|
||||||
runCmdConfigFlag := fl.String("config")
|
runCmdConfigFlag := fl.String("config")
|
||||||
runCmdConfigAdapterFlag := fl.String("config-adapter")
|
runCmdConfigAdapterFlag := fl.String("adapter")
|
||||||
runCmdPrintEnvFlag := fl.Bool("print-env")
|
runCmdPrintEnvFlag := fl.Bool("environ")
|
||||||
runCmdPingbackFlag := fl.String("pingback")
|
runCmdPingbackFlag := fl.String("pingback")
|
||||||
|
|
||||||
// if we are supposed to print the environment, do that first
|
// if we are supposed to print the environment, do that first
|
||||||
|
@ -216,7 +218,7 @@ func cmdStop(_ Flags) (int, error) {
|
||||||
|
|
||||||
func cmdReload(fl Flags) (int, error) {
|
func cmdReload(fl Flags) (int, error) {
|
||||||
reloadCmdConfigFlag := fl.String("config")
|
reloadCmdConfigFlag := fl.String("config")
|
||||||
reloadCmdConfigAdapterFlag := fl.String("config-adapter")
|
reloadCmdConfigAdapterFlag := fl.String("adapter")
|
||||||
reloadCmdAddrFlag := fl.String("address")
|
reloadCmdAddrFlag := fl.String("address")
|
||||||
|
|
||||||
// a configuration is required
|
// a configuration is required
|
||||||
|
@ -282,10 +284,61 @@ func cmdVersion(_ Flags) (int, error) {
|
||||||
return caddy.ExitCodeSuccess, nil
|
return caddy.ExitCodeSuccess, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdListModules(_ Flags) (int, error) {
|
func cmdListModules(fl Flags) (int, error) {
|
||||||
for _, m := range caddy.Modules() {
|
versions := fl.Bool("versions")
|
||||||
fmt.Println(m)
|
|
||||||
|
bi, ok := debug.ReadBuildInfo()
|
||||||
|
if !ok || !versions {
|
||||||
|
// if there's no build information,
|
||||||
|
// just print out the modules
|
||||||
|
for _, m := range caddy.Modules() {
|
||||||
|
fmt.Println(m)
|
||||||
|
}
|
||||||
|
return caddy.ExitCodeSuccess, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, modName := range caddy.Modules() {
|
||||||
|
modInfo, err := caddy.GetModule(modName)
|
||||||
|
if err != nil {
|
||||||
|
// that's weird
|
||||||
|
fmt.Println(modName)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// to get the Caddy plugin's version info, we need to know
|
||||||
|
// the package that the Caddy module's value comes from; we
|
||||||
|
// can use reflection but we need a non-pointer value (I'm
|
||||||
|
// not sure why), and since New() should return a pointer
|
||||||
|
// value, we need to dereference it first
|
||||||
|
iface := interface{}(modInfo.New())
|
||||||
|
if rv := reflect.ValueOf(iface); rv.Kind() == reflect.Ptr {
|
||||||
|
iface = reflect.New(reflect.TypeOf(iface).Elem()).Elem().Interface()
|
||||||
|
}
|
||||||
|
modPkgPath := reflect.TypeOf(iface).PkgPath()
|
||||||
|
|
||||||
|
// now we find the Go module that the Caddy module's package
|
||||||
|
// belongs to; we assume the Caddy module package path will
|
||||||
|
// be prefixed by its Go module path, and we will choose the
|
||||||
|
// longest matching prefix in case there are nested modules
|
||||||
|
var matched *debug.Module
|
||||||
|
for _, dep := range bi.Deps {
|
||||||
|
if strings.HasPrefix(modPkgPath, dep.Path) {
|
||||||
|
if matched == nil || len(dep.Path) > len(matched.Path) {
|
||||||
|
matched = dep
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we could find no matching module, just print out
|
||||||
|
// the module name instead
|
||||||
|
if matched == nil {
|
||||||
|
fmt.Println(modName)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%s %s\n", modName, matched.Version)
|
||||||
|
}
|
||||||
|
|
||||||
return caddy.ExitCodeSuccess, nil
|
return caddy.ExitCodeSuccess, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,13 +348,13 @@ func cmdEnviron(_ Flags) (int, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdAdaptConfig(fl Flags) (int, error) {
|
func cmdAdaptConfig(fl Flags) (int, error) {
|
||||||
|
adaptCmdInputFlag := fl.String("config")
|
||||||
adaptCmdAdapterFlag := fl.String("adapter")
|
adaptCmdAdapterFlag := fl.String("adapter")
|
||||||
adaptCmdInputFlag := fl.String("input")
|
|
||||||
adaptCmdPrettyFlag := fl.Bool("pretty")
|
adaptCmdPrettyFlag := fl.Bool("pretty")
|
||||||
|
|
||||||
if adaptCmdAdapterFlag == "" || adaptCmdInputFlag == "" {
|
if adaptCmdAdapterFlag == "" || adaptCmdInputFlag == "" {
|
||||||
return caddy.ExitCodeFailedStartup,
|
return caddy.ExitCodeFailedStartup,
|
||||||
fmt.Errorf("usage: caddy adapt-config --adapter <name> --input <file>")
|
fmt.Errorf("usage: caddy adapt --adapter <name> --input <file>")
|
||||||
}
|
}
|
||||||
|
|
||||||
cfgAdapter := caddyconfig.GetAdapter(adaptCmdAdapterFlag)
|
cfgAdapter := caddyconfig.GetAdapter(adaptCmdAdapterFlag)
|
||||||
|
@ -341,6 +394,55 @@ func cmdAdaptConfig(fl Flags) (int, error) {
|
||||||
return caddy.ExitCodeSuccess, nil
|
return caddy.ExitCodeSuccess, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cmdValidateConfig(fl Flags) (int, error) {
|
||||||
|
validateCmdConfigFlag := fl.String("config")
|
||||||
|
validateCmdAdapterFlag := fl.String("adapter")
|
||||||
|
|
||||||
|
input, err := ioutil.ReadFile(validateCmdConfigFlag)
|
||||||
|
if err != nil {
|
||||||
|
return caddy.ExitCodeFailedStartup,
|
||||||
|
fmt.Errorf("reading input file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if validateCmdAdapterFlag != "" {
|
||||||
|
cfgAdapter := caddyconfig.GetAdapter(validateCmdAdapterFlag)
|
||||||
|
if cfgAdapter == nil {
|
||||||
|
return caddy.ExitCodeFailedStartup,
|
||||||
|
fmt.Errorf("unrecognized config adapter: %s", validateCmdAdapterFlag)
|
||||||
|
}
|
||||||
|
|
||||||
|
adaptedConfig, warnings, err := cfgAdapter.Adapt(input, nil)
|
||||||
|
if err != nil {
|
||||||
|
return caddy.ExitCodeFailedStartup, err
|
||||||
|
}
|
||||||
|
// print warnings to stderr
|
||||||
|
for _, warn := range warnings {
|
||||||
|
msg := warn.Message
|
||||||
|
if warn.Directive != "" {
|
||||||
|
msg = fmt.Sprintf("%s: %s", warn.Directive, warn.Message)
|
||||||
|
}
|
||||||
|
log.Printf("[WARNING][%s] %s:%d: %s", validateCmdAdapterFlag, warn.File, warn.Line, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
input = adaptedConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
var cfg *caddy.Config
|
||||||
|
err = json.Unmarshal(input, &cfg)
|
||||||
|
if err != nil {
|
||||||
|
return caddy.ExitCodeFailedStartup, fmt.Errorf("decoding config: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = caddy.Validate(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return caddy.ExitCodeFailedStartup, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Valid configuration")
|
||||||
|
|
||||||
|
return caddy.ExitCodeSuccess, nil
|
||||||
|
}
|
||||||
|
|
||||||
func cmdHelp(fl Flags) (int, error) {
|
func cmdHelp(fl Flags) (int, error) {
|
||||||
const fullDocs = `Full documentation is available at:
|
const fullDocs = `Full documentation is available at:
|
||||||
https://github.com/caddyserver/caddy/wiki/v2:-Documentation`
|
https://github.com/caddyserver/caddy/wiki/v2:-Documentation`
|
||||||
|
|
|
@ -54,7 +54,7 @@ var commands = map[string]Command{
|
||||||
"start": {
|
"start": {
|
||||||
Name: "start",
|
Name: "start",
|
||||||
Func: cmdStart,
|
Func: cmdStart,
|
||||||
Usage: "[--config <path>] [--config-adapter <name>]",
|
Usage: "[--config <path>] [--adapter <name>]",
|
||||||
Short: "Starts the Caddy process and returns after server has started.",
|
Short: "Starts the Caddy process and returns after server has started.",
|
||||||
Long: `
|
Long: `
|
||||||
Starts the Caddy process, optionally bootstrapped with an initial
|
Starts the Caddy process, optionally bootstrapped with an initial
|
||||||
|
@ -65,7 +65,7 @@ details.`,
|
||||||
Flags: func() *flag.FlagSet {
|
Flags: func() *flag.FlagSet {
|
||||||
fs := flag.NewFlagSet("start", flag.ExitOnError)
|
fs := flag.NewFlagSet("start", flag.ExitOnError)
|
||||||
fs.String("config", "", "Configuration file")
|
fs.String("config", "", "Configuration file")
|
||||||
fs.String("config-adapter", "", "Name of config adapter to apply")
|
fs.String("adapter", "", "Name of config adapter to apply")
|
||||||
return fs
|
return fs
|
||||||
}(),
|
}(),
|
||||||
},
|
},
|
||||||
|
@ -73,7 +73,7 @@ details.`,
|
||||||
"run": {
|
"run": {
|
||||||
Name: "run",
|
Name: "run",
|
||||||
Func: cmdRun,
|
Func: cmdRun,
|
||||||
Usage: "[--config <path>] [--config-adapter <name>] [--print-env]",
|
Usage: "[--config <path>] [--adapter <name>] [--print-env]",
|
||||||
Short: `Starts the Caddy process and blocks indefinitely.`,
|
Short: `Starts the Caddy process and blocks indefinitely.`,
|
||||||
Long: `
|
Long: `
|
||||||
Same as start, but blocks indefinitely; i.e. runs Caddy in "daemon" mode. On
|
Same as start, but blocks indefinitely; i.e. runs Caddy in "daemon" mode. On
|
||||||
|
@ -83,25 +83,25 @@ window.
|
||||||
|
|
||||||
If a config file is specified, it will be applied immediately after the process
|
If a config file is specified, it will be applied immediately after the process
|
||||||
is running. If the config file is not in Caddy's native JSON format, you can
|
is running. If the config file is not in Caddy's native JSON format, you can
|
||||||
specify an adapter with --config-adapter to adapt the given config file to
|
specify an adapter with --adapter to adapt the given config file to
|
||||||
Caddy's native format. The config adapter must be a registered module. Any
|
Caddy's native format. The config adapter must be a registered module. Any
|
||||||
warnings will be printed to the log, but beware that any adaptation without
|
warnings will be printed to the log, but beware that any adaptation without
|
||||||
errors will immediately be used. If you want to review the results of the
|
errors will immediately be used. If you want to review the results of the
|
||||||
adaptation first, use adapt-config.
|
adaptation first, use the 'adapt' subcommand.
|
||||||
|
|
||||||
As a special case, if the current working directory has a file called
|
As a special case, if the current working directory has a file called
|
||||||
"Caddyfile" and the caddyfile config adapter is plugged in (default), then that
|
"Caddyfile" and the caddyfile config adapter is plugged in (default), then that
|
||||||
file will be loaded and used to configure Caddy, even without any command line
|
file will be loaded and used to configure Caddy, even without any command line
|
||||||
flags.
|
flags.
|
||||||
|
|
||||||
If --print-env is specified, the environment as seen by the Caddy process will
|
If --environ is specified, the environment as seen by the Caddy process will
|
||||||
be printed before starting. This is the same as the environ command but does
|
be printed before starting. This is the same as the environ command but does
|
||||||
not quit after printing.`,
|
not quit after printing.`,
|
||||||
Flags: func() *flag.FlagSet {
|
Flags: func() *flag.FlagSet {
|
||||||
fs := flag.NewFlagSet("run", flag.ExitOnError)
|
fs := flag.NewFlagSet("run", flag.ExitOnError)
|
||||||
fs.String("config", "", "Configuration file")
|
fs.String("config", "", "Configuration file")
|
||||||
fs.String("config-adapter", "", "Name of config adapter to apply")
|
fs.String("adapter", "", "Name of config adapter to apply")
|
||||||
fs.Bool("print-env", false, "Print environment")
|
fs.Bool("environ", false, "Print environment")
|
||||||
fs.String("pingback", "", "Echo confirmation bytes to this address on success")
|
fs.String("pingback", "", "Echo confirmation bytes to this address on success")
|
||||||
return fs
|
return fs
|
||||||
}(),
|
}(),
|
||||||
|
@ -120,7 +120,7 @@ shutdown on Windows, use Ctrl+C or the /stop endpoint.`,
|
||||||
"reload": {
|
"reload": {
|
||||||
Name: "reload",
|
Name: "reload",
|
||||||
Func: cmdReload,
|
Func: cmdReload,
|
||||||
Usage: "--config <path> [--config-adapter <name>] [--address <interface>]",
|
Usage: "--config <path> [--adapter <name>] [--address <interface>]",
|
||||||
Short: "Gives the running Caddy instance a new configuration",
|
Short: "Gives the running Caddy instance a new configuration",
|
||||||
Long: `Gives the running Caddy instance a new configuration. This has the same effect
|
Long: `Gives the running Caddy instance a new configuration. This has the same effect
|
||||||
as POSTing a document to the /load endpoint, but is convenient for simple
|
as POSTing a document to the /load endpoint, but is convenient for simple
|
||||||
|
@ -129,9 +129,9 @@ configurable, the endpoint configuration is loaded from the --address flag if
|
||||||
specified; otherwise it is loaded from the given config file; otherwise the
|
specified; otherwise it is loaded from the given config file; otherwise the
|
||||||
default is assumed.`,
|
default is assumed.`,
|
||||||
Flags: func() *flag.FlagSet {
|
Flags: func() *flag.FlagSet {
|
||||||
fs := flag.NewFlagSet("load", flag.ExitOnError)
|
fs := flag.NewFlagSet("reload", flag.ExitOnError)
|
||||||
fs.String("config", "", "Configuration file")
|
fs.String("config", "", "Configuration file")
|
||||||
fs.String("config-adapter", "", "Name of config adapter to apply")
|
fs.String("adapter", "", "Name of config adapter to apply")
|
||||||
fs.String("address", "", "Address of the administration listener, if different from config")
|
fs.String("address", "", "Address of the administration listener, if different from config")
|
||||||
return fs
|
return fs
|
||||||
}(),
|
}(),
|
||||||
|
@ -149,6 +149,11 @@ default is assumed.`,
|
||||||
Func: cmdListModules,
|
Func: cmdListModules,
|
||||||
Short: "List installed Caddy modules.",
|
Short: "List installed Caddy modules.",
|
||||||
Long: `List installed Caddy modules.`,
|
Long: `List installed Caddy modules.`,
|
||||||
|
Flags: func() *flag.FlagSet {
|
||||||
|
fs := flag.NewFlagSet("list-modules", flag.ExitOnError)
|
||||||
|
fs.Bool("versions", false, "Print version information")
|
||||||
|
return fs
|
||||||
|
}(),
|
||||||
},
|
},
|
||||||
|
|
||||||
"environ": {
|
"environ": {
|
||||||
|
@ -158,15 +163,38 @@ default is assumed.`,
|
||||||
Long: `Prints the environment as seen by Caddy.`,
|
Long: `Prints the environment as seen by Caddy.`,
|
||||||
},
|
},
|
||||||
|
|
||||||
"adapt-config": {
|
"adapt": {
|
||||||
Name: "adapt-config",
|
Name: "adapt",
|
||||||
Func: cmdAdaptConfig,
|
Func: cmdAdaptConfig,
|
||||||
Usage: "--input <path> --adapter <name> [--pretty]",
|
Usage: "--config <path> --adapter <name> [--pretty]",
|
||||||
Short: "Adapts a configuration to Caddy's native JSON config structure",
|
Short: "Adapts a configuration to Caddy's native JSON config structure",
|
||||||
Long: `
|
Long: `
|
||||||
Adapts a configuration to Caddy's native JSON config structure and writes the
|
Adapts a configuration to Caddy's native JSON config structure and writes the
|
||||||
output to stdout, along with any warnings to stderr. If --pretty is specified,
|
output to stdout, along with any warnings to stderr. If --pretty is specified,
|
||||||
the output will be formatted with indentation for human readability.`,
|
the output will be formatted with indentation for human readability.`,
|
||||||
|
Flags: func() *flag.FlagSet {
|
||||||
|
fs := flag.NewFlagSet("adapt", flag.ExitOnError)
|
||||||
|
fs.String("config", "", "Configuration file to adapt")
|
||||||
|
fs.String("adapter", "", "Name of config adapter")
|
||||||
|
fs.Bool("pretty", false, "Format the output for human readability")
|
||||||
|
return fs
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
|
||||||
|
"validate": {
|
||||||
|
Name: "validate",
|
||||||
|
Func: cmdValidateConfig,
|
||||||
|
Usage: "--config <path> [--adapter <name>]",
|
||||||
|
Short: "Tests whether a configuration file is valid.",
|
||||||
|
Long: `
|
||||||
|
Loads and provisions the provided config, but does not start
|
||||||
|
running it.`,
|
||||||
|
Flags: func() *flag.FlagSet {
|
||||||
|
fs := flag.NewFlagSet("load", flag.ExitOnError)
|
||||||
|
fs.String("config", "", "Input configuration file")
|
||||||
|
fs.String("adapter", "", "Name of config adapter")
|
||||||
|
return fs
|
||||||
|
}(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue