Commit 1dfe1e5a authored by Luna Duclos's avatar Luna Duclos

Add plugin capabilities for tls storage.

To use a plugged in storage, specify "storage storage_name" in the tls block of the Caddyfile, by default, file storage will be used
parent 628920e2
......@@ -11,7 +11,7 @@ import (
// ensure that the standard plugins are in fact plugged in
// and registered properly; this is a quick/naive way to do it.
func TestStandardPlugins(t *testing.T) {
numStandardPlugins := 25 // importing caddyhttp plugs in this many plugins
numStandardPlugins := 26 // importing caddyhttp plugs in this many plugins
s := caddy.DescribePlugins()
if got, want := strings.Count(s, "\n"), numStandardPlugins+5; got != want {
t.Errorf("Expected all standard plugins to be plugged in, got:\n%s", s)
......
......@@ -99,12 +99,10 @@ type Config struct {
// certificates
KeyType acme.KeyType
// The explicitly set storage creator or nil; use
// StorageFor() to get a guaranteed non-nil Storage
// instance. Note, Caddy may call this frequently so
// implementors are encouraged to cache any heavy
// instantiations.
StorageCreator StorageCreator
// The storage creator; use StorageFor() to get a guaranteed
// non-nil Storage instance. Note, Caddy may call this frequently
// so implementors are encouraged to cache any heavy instantiations.
StorageProvider string
// The state needed to operate on-demand TLS
OnDemandState OnDemandState
......@@ -285,19 +283,20 @@ func (c *Config) StorageFor(caURL string) (Storage, error) {
// Create the storage based on the URL
var s Storage
if c.StorageCreator != nil {
s, err = c.StorageCreator(u)
if err != nil {
return nil, fmt.Errorf("%s: unable to create custom storage: %v", caURL, err)
}
if c.StorageProvider == "" {
c.StorageProvider = "file"
}
if s == nil {
// We trust that this does not return a nil s when there's a nil err
s, err = FileStorageCreator(u)
if err != nil {
return nil, fmt.Errorf("%s: unable to create file storage: %v", caURL, err)
}
creator, ok := storageProviders[c.StorageProvider]
if !ok {
return nil, fmt.Errorf("%s: Unknown storage: %v", caURL, c.StorageProvider)
}
s, err = creator(u)
if err != nil {
return nil, fmt.Errorf("%s: unable to create custom storage '%v': %v", caURL, c.StorageProvider, err)
}
return s, nil
}
......
......@@ -38,11 +38,12 @@ func TestStorageForNoURL(t *testing.T) {
func TestStorageForLowercasesAndPrefixesScheme(t *testing.T) {
resultStr := ""
RegisterStorageProvider("fake-TestStorageForLowercasesAndPrefixesScheme", func(caURL *url.URL) (Storage, error) {
resultStr = caURL.String()
return nil, nil
})
c := &Config{
StorageCreator: func(caURL *url.URL) (Storage, error) {
resultStr = caURL.String()
return nil, nil
},
StorageProvider: "fake-TestStorageForLowercasesAndPrefixesScheme",
}
if _, err := c.StorageFor("EXAMPLE.COM/BLAH"); err != nil {
t.Fatal(err)
......@@ -71,11 +72,10 @@ func TestStorageForDefault(t *testing.T) {
}
func TestStorageForCustom(t *testing.T) {
storage := fakeStorage("fake")
storage := fakeStorage("fake-TestStorageForCustom")
RegisterStorageProvider("fake-TestStorageForCustom", func(caURL *url.URL) (Storage, error) { return storage, nil })
c := &Config{
StorageCreator: func(caURL *url.URL) (Storage, error) {
return storage, nil
},
StorageProvider: "fake-TestStorageForCustom",
}
s, err := c.StorageFor("example.com")
if err != nil {
......@@ -87,10 +87,9 @@ func TestStorageForCustom(t *testing.T) {
}
func TestStorageForCustomError(t *testing.T) {
RegisterStorageProvider("fake-TestStorageForCustomError", func(caURL *url.URL) (Storage, error) { return nil, errors.New("some error") })
c := &Config{
StorageCreator: func(caURL *url.URL) (Storage, error) {
return nil, errors.New("some error")
},
StorageProvider: "fake-TestStorageForCustomError",
}
if _, err := c.StorageFor("example.com"); err == nil {
t.Fatal("Expecting error")
......@@ -99,11 +98,7 @@ func TestStorageForCustomError(t *testing.T) {
func TestStorageForCustomNil(t *testing.T) {
// Should fall through to the default
c := &Config{
StorageCreator: func(caURL *url.URL) (Storage, error) {
return nil, nil
},
}
c := &Config{StorageProvider: ""}
s, err := c.StorageFor("example.com")
if err != nil {
t.Fatal(err)
......
......@@ -9,6 +9,10 @@ import (
"strings"
)
func init() {
RegisterStorageProvider("file", FileStorageCreator)
}
// storageBasePath is the root path in which all TLS/ACME assets are
// stored. Do not change this value during the lifetime of the program.
var storageBasePath = filepath.Join(caddy.AssetsPath(), "acme")
......
......@@ -146,6 +146,16 @@ func setupTLS(c *caddy.Controller) error {
return c.Errf("Unsupported DNS provider '%s'", args[0])
}
config.DNSProvider = args[0]
case "storage":
args := c.RemainingArgs()
if len(args) != 1 {
return c.ArgErr()
}
storageProvName := args[0]
if _, ok := storageProviders[storageProvName]; !ok {
return c.Errf("Unsupported Storage provider '%s'", args[0])
}
config.StorageProvider = args[0]
default:
return c.Errf("Unknown keyword '%s'", c.Val())
}
......
......@@ -168,3 +168,11 @@ var (
// when no other key type is specified.
DefaultKeyType = acme.RSA2048
)
var storageProviders = make(map[string]StorageCreator)
// RegisterStorageProvider registers provider by name for storing tls data
func RegisterStorageProvider(name string, provider StorageCreator) {
storageProviders[name] = provider
caddy.RegisterPlugin("tls.storage."+name, caddy.Plugin{})
}
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