diff options
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/caddy/main.go | 1 | ||||
-rw-r--r-- | cmd/commands.go | 81 | ||||
-rw-r--r-- | cmd/main.go | 65 |
3 files changed, 131 insertions, 16 deletions
diff --git a/cmd/caddy/main.go b/cmd/caddy/main.go index c1824d7..5f6b8bb 100644 --- a/cmd/caddy/main.go +++ b/cmd/caddy/main.go @@ -18,6 +18,7 @@ import ( caddycmd "github.com/caddyserver/caddy/v2/cmd" // this is where modules get plugged in + _ "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" _ "github.com/caddyserver/caddy/v2/modules/caddyhttp" _ "github.com/caddyserver/caddy/v2/modules/caddyhttp/encode" _ "github.com/caddyserver/caddy/v2/modules/caddyhttp/encode/brotli" diff --git a/cmd/commands.go b/cmd/commands.go index e63e2d5..99ec642 100644 --- a/cmd/commands.go +++ b/cmd/commands.go @@ -31,6 +31,7 @@ import ( "strings" "github.com/caddyserver/caddy/v2" + "github.com/caddyserver/caddy/v2/caddyconfig" "github.com/mholt/certmagic" "github.com/mitchellh/go-ps" ) @@ -38,6 +39,7 @@ import ( func cmdStart() (int, error) { startCmd := flag.NewFlagSet("start", flag.ExitOnError) startCmdConfigFlag := startCmd.String("config", "", "Configuration file") + startCmdConfigAdapterFlag := startCmd.String("config-adapter", "", "Name of config adapter to apply") startCmd.Parse(os.Args[2:]) // open a listener to which the child process will connect when @@ -62,6 +64,9 @@ func cmdStart() (int, error) { if *startCmdConfigFlag != "" { cmd.Args = append(cmd.Args, "--config", *startCmdConfigFlag) } + if *startCmdConfigAdapterFlag != "" { + cmd.Args = append(cmd.Args, "--config-adapter", *startCmdConfigAdapterFlag) + } stdinpipe, err := cmd.StdinPipe() if err != nil { return caddy.ExitCodeFailedStartup, @@ -137,7 +142,8 @@ func cmdStart() (int, error) { func cmdRun() (int, error) { runCmd := flag.NewFlagSet("run", flag.ExitOnError) runCmdConfigFlag := runCmd.String("config", "", "Configuration file") - runCmdPrintEnvFlag := runCmd.Bool("print-env", false, "Print environment (useful for debugging)") + runCmdConfigAdapterFlag := runCmd.String("config-adapter", "", "Name of config adapter to apply") + runCmdPrintEnvFlag := runCmd.Bool("print-env", false, "Print environment") runCmdPingbackFlag := runCmd.String("pingback", "", "Echo confirmation bytes to this address on success") runCmd.Parse(os.Args[2:]) @@ -149,16 +155,10 @@ func cmdRun() (int, error) { } } - // if a config file was specified for bootstrapping - // the server instance, load it now - var config []byte - if *runCmdConfigFlag != "" { - var err error - config, err = ioutil.ReadFile(*runCmdConfigFlag) - if err != nil { - return caddy.ExitCodeFailedStartup, - fmt.Errorf("reading config file: %v", err) - } + // get the config in caddy's native format + config, err := loadConfig(*runCmdConfigFlag, *runCmdConfigAdapterFlag) + if err != nil { + return caddy.ExitCodeFailedStartup, err } // set a fitting User-Agent for ACME requests @@ -167,7 +167,7 @@ func cmdRun() (int, error) { certmagic.UserAgent = "Caddy/" + cleanModVersion // start the admin endpoint along with any initial config - err := caddy.StartAdmin(config) + err = caddy.StartAdmin(config) if err != nil { return caddy.ExitCodeFailedStartup, fmt.Errorf("starting caddy administration endpoint: %v", err) @@ -226,6 +226,7 @@ func cmdStop() (int, error) { func cmdReload() (int, error) { reloadCmd := flag.NewFlagSet("load", flag.ExitOnError) reloadCmdConfigFlag := reloadCmd.String("config", "", "Configuration file") + reloadCmdConfigAdapterFlag := reloadCmd.String("config-adapter", "", "Name of config adapter to apply") reloadCmdAddrFlag := reloadCmd.String("address", "", "Address of the administration listener, if different from config") reloadCmd.Parse(os.Args[2:]) @@ -235,11 +236,10 @@ func cmdReload() (int, error) { fmt.Errorf("no configuration to load (use --config)") } - // load the configuration file - config, err := ioutil.ReadFile(*reloadCmdConfigFlag) + // get the config in caddy's native format + config, err := loadConfig(*reloadCmdConfigFlag, *reloadCmdConfigAdapterFlag) if err != nil { - return caddy.ExitCodeFailedStartup, - fmt.Errorf("reading config file: %v", err) + return caddy.ExitCodeFailedStartup, err } // get the address of the admin listener and craft endpoint URL @@ -306,3 +306,52 @@ func cmdEnviron() (int, error) { } return caddy.ExitCodeSuccess, nil } + +func cmdAdaptConfig() (int, error) { + adaptCmd := flag.NewFlagSet("adapt", flag.ExitOnError) + adaptCmdAdapterFlag := adaptCmd.String("adapter", "", "Name of config adapter") + adaptCmdInputFlag := adaptCmd.String("input", "", "Configuration file to adapt") + adaptCmdPrettyFlag := adaptCmd.Bool("pretty", false, "Format the output for human readability") + adaptCmd.Parse(os.Args[2:]) + + if *adaptCmdAdapterFlag == "" || *adaptCmdInputFlag == "" { + return caddy.ExitCodeFailedStartup, + fmt.Errorf("usage: caddy adapt-config --adapter <name> --input <file>") + } + + cfgAdapter := caddyconfig.GetAdapter(*adaptCmdAdapterFlag) + if cfgAdapter == nil { + return caddy.ExitCodeFailedStartup, + fmt.Errorf("unrecognized config adapter: %s", *adaptCmdAdapterFlag) + } + + input, err := ioutil.ReadFile(*adaptCmdInputFlag) + if err != nil { + return caddy.ExitCodeFailedStartup, + fmt.Errorf("reading input file: %v", err) + } + + opts := make(map[string]string) + if *adaptCmdPrettyFlag { + opts["pretty"] = "true" + } + + adaptedConfig, warnings, err := cfgAdapter.Adapt(input, opts) + 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", *adaptCmdAdapterFlag, warn.File, warn.Line, msg) + } + + // print result to stdout + fmt.Println(string(adaptedConfig)) + + return caddy.ExitCodeSuccess, nil +} diff --git a/cmd/main.go b/cmd/main.go index 16d065b..e0a3686 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -25,6 +25,7 @@ import ( "os" "github.com/caddyserver/caddy/v2" + "github.com/caddyserver/caddy/v2/caddyconfig" ) // Main implements the main function of the caddy command. @@ -62,6 +63,7 @@ var commands = map[string]commandFunc{ "version": cmdVersion, "list-modules": cmdListModules, "environ": cmdEnviron, + "adapt-config": cmdAdaptConfig, } func usageString() string { @@ -85,3 +87,66 @@ func handlePingbackConn(conn net.Conn, expect []byte) error { } return nil } + +// loadConfig loads the config from configFile and adapts it +// using adapterName. If adapterName is specified, configFile +// must be also. It prints any warnings to stderr, and returns +// the resulting JSON config bytes. +func loadConfig(configFile, adapterName string) ([]byte, error) { + // specifying an adapter without a config file is ambiguous + if configFile == "" && adapterName != "" { + return nil, fmt.Errorf("cannot adapt config without config file (use --config)") + } + + // load initial config and adapter + var config []byte + var cfgAdapter caddyconfig.Adapter + var err error + if configFile != "" { + config, err = ioutil.ReadFile(configFile) + if err != nil { + return nil, fmt.Errorf("reading config file: %v", err) + } + } else if adapterName == "" { + // as a special case when no config file or adapter + // is specified, see if the Caddyfile adapter is + // plugged in, and if so, try using a default Caddyfile + cfgAdapter = caddyconfig.GetAdapter("caddyfile") + if cfgAdapter != nil { + config, err = ioutil.ReadFile("Caddyfile") + if err != nil && !os.IsNotExist(err) { + return nil, fmt.Errorf("reading default Caddyfile: %v", err) + } + configFile = "Caddyfile" + } + } + + // load config adapter + if adapterName != "" { + cfgAdapter = caddyconfig.GetAdapter(adapterName) + if cfgAdapter == nil { + return nil, fmt.Errorf("unrecognized config adapter: %s", adapterName) + } + } + + // adapt config + if cfgAdapter != nil { + adaptedConfig, warnings, err := cfgAdapter.Adapt(config, map[string]string{ + "filename": configFile, + // TODO: all other options... (http-port, etc...) + }) + if err != nil { + return nil, fmt.Errorf("adapting config using %s: %v", adapterName, err) + } + for _, warn := range warnings { + msg := warn.Message + if warn.Directive != "" { + msg = fmt.Sprintf("%s: %s", warn.Directive, warn.Message) + } + fmt.Printf("[WARNING][%s] %s:%d: %s", adapterName, warn.File, warn.Line, msg) + } + config = adaptedConfig + } + + return config, nil +} |