Commit 1867ded1 authored by Matt Holt's avatar Matt Holt Committed by GitHub

caddytls: Change clustering to be a plugin to the caddytls package (#2459)

* 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.

* Remove unused variable

* caddyhttp: Fix test (adjust plugin counting)

* ummmm, remove extra line break

somehow VS Code didn't fmt on save... weird.
parent 2ea544e9
...@@ -41,12 +41,10 @@ import ( ...@@ -41,12 +41,10 @@ import (
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/mholt/caddy/caddyfile" "github.com/mholt/caddy/caddyfile"
"github.com/mholt/caddy/telemetry" "github.com/mholt/caddy/telemetry"
"github.com/mholt/certmagic"
) )
// Configurable application parameters // Configurable application parameters
...@@ -472,26 +470,6 @@ func (i *Instance) Caddyfile() Input { ...@@ -472,26 +470,6 @@ func (i *Instance) Caddyfile() Input {
// //
// This function blocks until all the servers are listening. // This function blocks until all the servers are listening.
func Start(cdyfile Input) (*Instance, error) { 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{})} inst := &Instance{serverType: cdyfile.ServerType(), wg: new(sync.WaitGroup), Storage: make(map[interface{}]interface{})}
err := startWithListenerFds(cdyfile, inst, nil) err := startWithListenerFds(cdyfile, inst, nil)
if err != nil { if err != nil {
...@@ -1021,7 +999,5 @@ var ( ...@@ -1021,7 +999,5 @@ var (
DefaultConfigFile = "Caddyfile" DefaultConfigFile = "Caddyfile"
) )
var clusterPluginSetup int32 // access atomically
// CtxKey is a value type for use with context.WithValue. // CtxKey is a value type for use with context.WithValue.
type CtxKey string type CtxKey string
...@@ -25,9 +25,9 @@ import ( ...@@ -25,9 +25,9 @@ import (
// ensure that the standard plugins are in fact plugged in // ensure that the standard plugins are in fact plugged in
// and registered properly; this is a quick/naive way to do it. // and registered properly; this is a quick/naive way to do it.
func TestStandardPlugins(t *testing.T) { func TestStandardPlugins(t *testing.T) {
numStandardPlugins := 31 // importing caddyhttp plugs in this many plugins numStandardPlugins := 32 // importing caddyhttp plugs in this many plugins
s := caddy.DescribePlugins() s := caddy.DescribePlugins()
if got, want := strings.Count(s, "\n"), numStandardPlugins+7; got != want { if got, want := strings.Count(s, "\n"), numStandardPlugins+4; got != want {
t.Errorf("Expected all standard plugins to be plugged in, got:\n%s", s) t.Errorf("Expected all standard plugins to be plugged in, got:\n%s", s)
} }
} }
...@@ -26,6 +26,7 @@ import ( ...@@ -26,6 +26,7 @@ import (
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"sync/atomic"
"github.com/mholt/caddy" "github.com/mholt/caddy"
"github.com/mholt/caddy/telemetry" "github.com/mholt/caddy/telemetry"
...@@ -36,13 +37,34 @@ func init() { ...@@ -36,13 +37,34 @@ func init() {
caddy.RegisterPlugin("tls", caddy.Plugin{Action: setupTLS}) caddy.RegisterPlugin("tls", caddy.Plugin{Action: setupTLS})
// ensure the default Storage implementation is plugged in // 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 // setupTLS sets up the TLS configuration and installs certificates that
// are specified by the user in the config file. All the automatic HTTPS // are specified by the user in the config file. All the automatic HTTPS
// stuff comes later outside of this function. // stuff comes later outside of this function.
func setupTLS(c *caddy.Controller) error { 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()] configGetter, ok := configGetters[c.ServerType()]
if !ok { if !ok {
return fmt.Errorf("no caddytls.ConfigGetter for %s server type; must call RegisterConfigGetter", c.ServerType()) 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 { ...@@ -423,3 +445,5 @@ func loadCertsInDir(cfg *Config, c *caddy.Controller, dir string) error {
func constructDefaultClusterPlugin() (certmagic.Storage, error) { func constructDefaultClusterPlugin() (certmagic.Storage, error) {
return &certmagic.FileStorage{Path: caddy.AssetsPath()}, nil return &certmagic.FileStorage{Path: caddy.AssetsPath()}, nil
} }
var clusterPluginSetup int32 // access atomically
...@@ -108,3 +108,19 @@ func RegisterDNSProvider(name string, provider DNSProviderConstructor) { ...@@ -108,3 +108,19 @@ func RegisterDNSProvider(name string, provider DNSProviderConstructor) {
dnsProviders[name] = provider dnsProviders[name] = provider
caddy.RegisterPlugin("tls.dns."+name, caddy.Plugin{}) 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{})
}
...@@ -22,7 +22,6 @@ import ( ...@@ -22,7 +22,6 @@ import (
"sync" "sync"
"github.com/mholt/caddy/caddyfile" "github.com/mholt/caddy/caddyfile"
"github.com/mholt/certmagic"
) )
// These are all the registered plugins. // These are all the registered plugins.
...@@ -107,11 +106,6 @@ func ListPlugins() map[string][]string { ...@@ -107,11 +106,6 @@ func ListPlugins() map[string][]string {
p["caddyfile_loaders"] = append(p["caddyfile_loaders"], defaultCaddyfileLoader.name) 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 // List the event hook plugins
eventHooks.Range(func(k, _ interface{}) bool { eventHooks.Range(func(k, _ interface{}) bool {
p["event_hooks"] = append(p["event_hooks"], k.(string)) p["event_hooks"] = append(p["event_hooks"], k.(string))
...@@ -456,21 +450,6 @@ func loadCaddyfileInput(serverType string) (Input, error) { ...@@ -456,21 +450,6 @@ func loadCaddyfileInput(serverType string) (Input, error) {
return caddyfileToUse, nil 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 // OnProcessExit is a list of functions to run when the process
// exits -- they are ONLY for cleanup and should not block, // exits -- they are ONLY for cleanup and should not block,
// return errors, or do anything fancy. They will be run with // return errors, or do anything fancy. They will be run with
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment