From eac939e9a73cce3878f6e142d128580223107e5a Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Fri, 8 Feb 2019 12:25:01 -0700 Subject: [PATCH] caddytls: Change clustering to be a plugin to the caddytls package Should resolve the failure in https://github.com/coredns/coredns/pull/2541. This change is breaking to clustering plugin developers (not Caddy users), but logical, since only the caddytls package uses CertMagic directly (the httpserver package also uses it, but only because it also uses the caddytls plugin); and it is early enough that no clustering plugins really exist yet. This will also require a change of devportal so that it looks for a different registration function, which has moved to the caddytls package. --- caddy.go | 22 ---------------------- caddytls/setup.go | 26 +++++++++++++++++++++++++- caddytls/tls.go | 16 ++++++++++++++++ plugins.go | 21 --------------------- 4 files changed, 41 insertions(+), 44 deletions(-) diff --git a/caddy.go b/caddy.go index b29a0280a..c1f9ecae6 100644 --- a/caddy.go +++ b/caddy.go @@ -41,12 +41,10 @@ import ( "strconv" "strings" "sync" - "sync/atomic" "time" "github.com/mholt/caddy/caddyfile" "github.com/mholt/caddy/telemetry" - "github.com/mholt/certmagic" ) // Configurable application parameters @@ -472,26 +470,6 @@ func (i *Instance) Caddyfile() Input { // // This function blocks until all the servers are listening. func Start(cdyfile Input) (*Instance, error) { - // set up the clustering plugin, if there is one (and there should - // always be one) -- this should be done exactly once, but we can't - // do it during init while plugins are still registering, so do it - // when starting the first instance) - if atomic.CompareAndSwapInt32(&clusterPluginSetup, 0, 1) { - clusterPluginName := os.Getenv("CADDY_CLUSTERING") - if clusterPluginName == "" { - clusterPluginName = "file" // name of default storage plugin as registered in caddytls package - } - clusterFn, ok := clusterProviders[clusterPluginName] - if !ok { - return nil, fmt.Errorf("unrecognized cluster plugin (was it included in the Caddy build?): %s", clusterPluginName) - } - storage, err := clusterFn() - if err != nil { - return nil, fmt.Errorf("constructing cluster plugin %s: %v", clusterPluginName, err) - } - certmagic.DefaultStorage = storage - } - inst := &Instance{serverType: cdyfile.ServerType(), wg: new(sync.WaitGroup), Storage: make(map[interface{}]interface{})} err := startWithListenerFds(cdyfile, inst, nil) if err != nil { diff --git a/caddytls/setup.go b/caddytls/setup.go index 9ac89a07f..e76732385 100644 --- a/caddytls/setup.go +++ b/caddytls/setup.go @@ -26,6 +26,7 @@ import ( "path/filepath" "strconv" "strings" + "sync/atomic" "github.com/mholt/caddy" "github.com/mholt/caddy/telemetry" @@ -36,13 +37,34 @@ func init() { caddy.RegisterPlugin("tls", caddy.Plugin{Action: setupTLS}) // ensure the default Storage implementation is plugged in - caddy.RegisterClusterPlugin("file", constructDefaultClusterPlugin) + RegisterClusterPlugin("file", constructDefaultClusterPlugin) } // setupTLS sets up the TLS configuration and installs certificates that // are specified by the user in the config file. All the automatic HTTPS // stuff comes later outside of this function. func setupTLS(c *caddy.Controller) error { + // set up the clustering plugin, if there is one (and there should always + // be one since this tls plugin requires it) -- this should be done exactly + // once, but we can't do it during init while plugins are still registering, + // so do it as soon as we run a setup) + if atomic.CompareAndSwapInt32(&clusterPluginSetup, 0, 1) { + clusterPluginName := os.Getenv("CADDY_CLUSTERING") + if clusterPluginName == "" { + clusterPluginName = "file" // name of default storage plugin + } + clusterFn, ok := clusterProviders[clusterPluginName] + if ok { + storage, err := clusterFn() + if err != nil { + return fmt.Errorf("constructing cluster plugin %s: %v", clusterPluginName, err) + } + certmagic.DefaultStorage = storage + } else { + return fmt.Errorf("unrecognized cluster plugin (was it included in the Caddy build?): %s", clusterPluginName) + } + } + configGetter, ok := configGetters[c.ServerType()] if !ok { return fmt.Errorf("no caddytls.ConfigGetter for %s server type; must call RegisterConfigGetter", c.ServerType()) @@ -423,3 +445,5 @@ func loadCertsInDir(cfg *Config, c *caddy.Controller, dir string) error { func constructDefaultClusterPlugin() (certmagic.Storage, error) { return &certmagic.FileStorage{Path: caddy.AssetsPath()}, nil } + +var clusterPluginSetup int32 // access atomically diff --git a/caddytls/tls.go b/caddytls/tls.go index 9a9d5c639..f6a375b79 100644 --- a/caddytls/tls.go +++ b/caddytls/tls.go @@ -108,3 +108,19 @@ func RegisterDNSProvider(name string, provider DNSProviderConstructor) { dnsProviders[name] = provider caddy.RegisterPlugin("tls.dns."+name, caddy.Plugin{}) } + +// ClusterPluginConstructor is a function type that is used to +// instantiate a new implementation of both certmagic.Storage +// and certmagic.Locker, which are required for successful +// use in cluster environments. +type ClusterPluginConstructor func() (certmagic.Storage, error) + +// clusterProviders is the list of storage providers +var clusterProviders = make(map[string]ClusterPluginConstructor) + +// RegisterClusterPlugin registers provider by name for facilitating +// cluster-wide operations like storage and synchronization. +func RegisterClusterPlugin(name string, provider ClusterPluginConstructor) { + clusterProviders[name] = provider + caddy.RegisterPlugin("tls.cluster."+name, caddy.Plugin{}) +} diff --git a/plugins.go b/plugins.go index 56f3679af..cd4497fa9 100644 --- a/plugins.go +++ b/plugins.go @@ -22,7 +22,6 @@ import ( "sync" "github.com/mholt/caddy/caddyfile" - "github.com/mholt/certmagic" ) // These are all the registered plugins. @@ -107,11 +106,6 @@ func ListPlugins() map[string][]string { p["caddyfile_loaders"] = append(p["caddyfile_loaders"], defaultCaddyfileLoader.name) } - // cluster plugins in registration order - for name := range clusterProviders { - p["clustering"] = append(p["clustering"], name) - } - // List the event hook plugins eventHooks.Range(func(k, _ interface{}) bool { p["event_hooks"] = append(p["event_hooks"], k.(string)) @@ -456,21 +450,6 @@ func loadCaddyfileInput(serverType string) (Input, error) { return caddyfileToUse, nil } -// ClusterPluginConstructor is a function type that is used to -// instantiate a new implementation of both certmagic.Storage -// and certmagic.Locker, which are required for successful -// use in cluster environments. -type ClusterPluginConstructor func() (certmagic.Storage, error) - -// clusterProviders is the list of storage providers -var clusterProviders = make(map[string]ClusterPluginConstructor) - -// RegisterClusterPlugin registers provider by name for facilitating -// cluster-wide operations like storage and synchronization. -func RegisterClusterPlugin(name string, provider ClusterPluginConstructor) { - clusterProviders[name] = provider -} - // OnProcessExit is a list of functions to run when the process // exits -- they are ONLY for cleanup and should not block, // return errors, or do anything fancy. They will be run with