mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-11-04 03:27:23 -05:00 
			
		
		
		
	Add clustering plugin types; use latest certmagic.Storage interface
This commit is contained in:
		
							parent
							
								
									33f2b16a1b
								
							
						
					
					
						commit
						393bc2992e
					
				
							
								
								
									
										23
									
								
								caddy.go
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								caddy.go
									
									
									
									
									
								
							@ -41,10 +41,12 @@ 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
 | 
				
			||||||
@ -462,6 +464,25 @@ 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 (this should be done
 | 
				
			||||||
 | 
						// exactly once -- but we can't do it during init when they're still
 | 
				
			||||||
 | 
						// getting plugged in, 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 {
 | 
				
			||||||
@ -985,5 +1006,7 @@ 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 (
 | 
				
			|||||||
// 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 := 30 // importing caddyhttp plugs in this many plugins
 | 
						numStandardPlugins := 31 // importing caddyhttp plugs in this many plugins
 | 
				
			||||||
	s := caddy.DescribePlugins()
 | 
						s := caddy.DescribePlugins()
 | 
				
			||||||
	if got, want := strings.Count(s, "\n"), numStandardPlugins+5; got != want {
 | 
						if got, want := strings.Count(s, "\n"), numStandardPlugins+7; 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)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -35,8 +35,8 @@ import (
 | 
				
			|||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
	caddy.RegisterPlugin("tls", caddy.Plugin{Action: setupTLS})
 | 
						caddy.RegisterPlugin("tls", caddy.Plugin{Action: setupTLS})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ensure TLS assets are stored and accessed from the CADDYPATH
 | 
						// ensure the default Storage implementation is plugged in
 | 
				
			||||||
	certmagic.DefaultStorage = certmagic.FileStorage{Path: caddy.AssetsPath()}
 | 
						caddy.RegisterClusterPlugin("file", constructDefaultClusterPlugin)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// setupTLS sets up the TLS configuration and installs certificates that
 | 
					// setupTLS sets up the TLS configuration and installs certificates that
 | 
				
			||||||
@ -442,3 +442,7 @@ func loadCertsInDir(cfg *Config, c *caddy.Controller, dir string) error {
 | 
				
			|||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func constructDefaultClusterPlugin() (certmagic.Storage, error) {
 | 
				
			||||||
 | 
						return certmagic.FileStorage{Path: caddy.AssetsPath()}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -108,13 +108,3 @@ 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{})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
// TODO...
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// var storageProviders = make(map[string]StorageConstructor)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// // RegisterStorageProvider registers provider by name for storing tls data
 | 
					 | 
				
			||||||
// func RegisterStorageProvider(name string, provider StorageConstructor) {
 | 
					 | 
				
			||||||
// 	storageProviders[name] = provider
 | 
					 | 
				
			||||||
// 	caddy.RegisterPlugin("tls.storage."+name, caddy.Plugin{})
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										28
									
								
								plugins.go
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								plugins.go
									
									
									
									
									
								
							@ -22,6 +22,7 @@ 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.
 | 
				
			||||||
@ -73,6 +74,13 @@ func DescribePlugins() string {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(pl["clustering"]) > 0 {
 | 
				
			||||||
 | 
							str += "\nClustering plugins:\n"
 | 
				
			||||||
 | 
							for _, name := range pl["clustering"] {
 | 
				
			||||||
 | 
								str += "  " + name + "\n"
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	str += "\nOther plugins:\n"
 | 
						str += "\nOther plugins:\n"
 | 
				
			||||||
	for _, name := range pl["others"] {
 | 
						for _, name := range pl["others"] {
 | 
				
			||||||
		str += "  " + name + "\n"
 | 
							str += "  " + name + "\n"
 | 
				
			||||||
@ -99,6 +107,11 @@ 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["clsutering"], 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))
 | 
				
			||||||
@ -443,6 +456,21 @@ 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
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										59
									
								
								vendor/github.com/mholt/certmagic/certmagic.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										59
									
								
								vendor/github.com/mholt/certmagic/certmagic.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -12,6 +12,25 @@
 | 
				
			|||||||
// See the License for the specific language governing permissions and
 | 
					// See the License for the specific language governing permissions and
 | 
				
			||||||
// limitations under the License.
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Package certmagic automates the obtaining and renewal of TLS certificates,
 | 
				
			||||||
 | 
					// including TLS & HTTPS best practices such as robust OCSP stapling, caching,
 | 
				
			||||||
 | 
					// HTTP->HTTPS redirects, and more.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Its high-level API serves your HTTP handlers over HTTPS by simply giving
 | 
				
			||||||
 | 
					// the domain name(s) and the http.Handler; CertMagic will create and run
 | 
				
			||||||
 | 
					// the HTTPS server for you, fully managing certificates during the lifetime
 | 
				
			||||||
 | 
					// of the server. Similarly, it can be used to start TLS listeners or return
 | 
				
			||||||
 | 
					// a ready-to-use tls.Config -- whatever layer you need TLS for, CertMagic
 | 
				
			||||||
 | 
					// makes it easy.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// If you need more control, create a Config using New() and then call
 | 
				
			||||||
 | 
					// Manage() on the config; but you'll have to be sure to solve the HTTP
 | 
				
			||||||
 | 
					// and TLS-ALPN challenges yourself (unless you disabled them or use the
 | 
				
			||||||
 | 
					// DNS challenge) by using the provided Config.GetCertificate function
 | 
				
			||||||
 | 
					// in your tls.Config and/or Config.HTTPChallangeHandler in your HTTP
 | 
				
			||||||
 | 
					// handler.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// See the package's README for more instruction.
 | 
				
			||||||
package certmagic
 | 
					package certmagic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
@ -166,46 +185,6 @@ func manageWithDefaultConfig(domainNames []string, disableHTTPChallenge bool) (*
 | 
				
			|||||||
	return cfg, cfg.Manage(domainNames)
 | 
						return cfg, cfg.Manage(domainNames)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Locker facilitates synchronization of certificate tasks across
 | 
					 | 
				
			||||||
// machines and networks.
 | 
					 | 
				
			||||||
type Locker interface {
 | 
					 | 
				
			||||||
	// TryLock will attempt to acquire the lock for key. If a
 | 
					 | 
				
			||||||
	// lock could be obtained, nil values are returned as no
 | 
					 | 
				
			||||||
	// waiting is required. If not (meaning another process is
 | 
					 | 
				
			||||||
	// already working on key), a Waiter value will be returned,
 | 
					 | 
				
			||||||
	// upon which you should Wait() until it is finished.
 | 
					 | 
				
			||||||
	//
 | 
					 | 
				
			||||||
	// The key should be a carefully-chosen value that uniquely
 | 
					 | 
				
			||||||
	// and precisely identifies the operation being locked. For
 | 
					 | 
				
			||||||
	// example, if it is for a certificate obtain or renew with
 | 
					 | 
				
			||||||
	// the ACME protocol to the same CA endpoint (remembering
 | 
					 | 
				
			||||||
	// that an obtain and renew are the same according to ACME,
 | 
					 | 
				
			||||||
	// thus both obtain and renew should share a lock key), a
 | 
					 | 
				
			||||||
	// good key would identify that operation by some name,
 | 
					 | 
				
			||||||
	// concatenated with the domain name and the CA endpoint.
 | 
					 | 
				
			||||||
	//
 | 
					 | 
				
			||||||
	// TryLock never blocks; it always returns without waiting.
 | 
					 | 
				
			||||||
	//
 | 
					 | 
				
			||||||
	// To prevent deadlocks, all implementations (where this concern
 | 
					 | 
				
			||||||
	// is relevant) should put a reasonable expiration on the lock in
 | 
					 | 
				
			||||||
	// case Unlock is unable to be called due to some sort of storage
 | 
					 | 
				
			||||||
	// system failure or crash.
 | 
					 | 
				
			||||||
	TryLock(key string) (Waiter, error)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Unlock releases the lock for key. This method must ONLY be
 | 
					 | 
				
			||||||
	// called after a successful call to TryLock where no Waiter was
 | 
					 | 
				
			||||||
	// returned, and only after the operation requiring the lock is
 | 
					 | 
				
			||||||
	// finished, even if it returned an error or timed out. Unlock
 | 
					 | 
				
			||||||
	// should also clean up any unused resources allocated during
 | 
					 | 
				
			||||||
	// TryLock.
 | 
					 | 
				
			||||||
	Unlock(key string) error
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Waiter is a type that can block until a lock is released.
 | 
					 | 
				
			||||||
type Waiter interface {
 | 
					 | 
				
			||||||
	Wait()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// OnDemandConfig contains some state relevant for providing
 | 
					// OnDemandConfig contains some state relevant for providing
 | 
				
			||||||
// on-demand TLS.
 | 
					// on-demand TLS.
 | 
				
			||||||
type OnDemandConfig struct {
 | 
					type OnDemandConfig struct {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										60
									
								
								vendor/github.com/mholt/certmagic/client.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										60
									
								
								vendor/github.com/mholt/certmagic/client.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -217,23 +217,21 @@ func (cfg *Config) lockKey(op, domainName string) string {
 | 
				
			|||||||
// Callers who have access to a Config value should use the ObtainCert
 | 
					// Callers who have access to a Config value should use the ObtainCert
 | 
				
			||||||
// method on that instead of this lower-level method.
 | 
					// method on that instead of this lower-level method.
 | 
				
			||||||
func (c *acmeClient) Obtain(name string) error {
 | 
					func (c *acmeClient) Obtain(name string) error {
 | 
				
			||||||
	if c.config.Sync != nil {
 | 
						lockKey := c.config.lockKey("cert_acme", name)
 | 
				
			||||||
		lockKey := c.config.lockKey("cert_acme", name)
 | 
						waiter, err := c.config.certCache.storage.TryLock(lockKey)
 | 
				
			||||||
		waiter, err := c.config.Sync.TryLock(lockKey)
 | 
						if err != nil {
 | 
				
			||||||
		if err != nil {
 | 
							return err
 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if waiter != nil {
 | 
					 | 
				
			||||||
			log.Printf("[INFO] Certificate for %s is already being obtained elsewhere and stored; waiting", name)
 | 
					 | 
				
			||||||
			waiter.Wait()
 | 
					 | 
				
			||||||
			return nil // we assume the process with the lock succeeded, rather than hammering this execution path again
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		defer func() {
 | 
					 | 
				
			||||||
			if err := c.config.Sync.Unlock(lockKey); err != nil {
 | 
					 | 
				
			||||||
				log.Printf("[ERROR] Unable to unlock obtain call for %s: %v", name, err)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}()
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if waiter != nil {
 | 
				
			||||||
 | 
							log.Printf("[INFO] Certificate for %s is already being obtained elsewhere and stored; waiting", name)
 | 
				
			||||||
 | 
							waiter.Wait()
 | 
				
			||||||
 | 
							return nil // we assume the process with the lock succeeded, rather than hammering this execution path again
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer func() {
 | 
				
			||||||
 | 
							if err := c.config.certCache.storage.Unlock(lockKey); err != nil {
 | 
				
			||||||
 | 
								log.Printf("[ERROR] Unable to unlock obtain call for %s: %v", name, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for attempts := 0; attempts < 2; attempts++ {
 | 
						for attempts := 0; attempts < 2; attempts++ {
 | 
				
			||||||
		request := certificate.ObtainRequest{
 | 
							request := certificate.ObtainRequest{
 | 
				
			||||||
@ -276,23 +274,21 @@ func (c *acmeClient) Obtain(name string) error {
 | 
				
			|||||||
// Callers who have access to a Config value should use the RenewCert
 | 
					// Callers who have access to a Config value should use the RenewCert
 | 
				
			||||||
// method on that instead of this lower-level method.
 | 
					// method on that instead of this lower-level method.
 | 
				
			||||||
func (c *acmeClient) Renew(name string) error {
 | 
					func (c *acmeClient) Renew(name string) error {
 | 
				
			||||||
	if c.config.Sync != nil {
 | 
						lockKey := c.config.lockKey("cert_acme", name)
 | 
				
			||||||
		lockKey := c.config.lockKey("cert_acme", name)
 | 
						waiter, err := c.config.certCache.storage.TryLock(lockKey)
 | 
				
			||||||
		waiter, err := c.config.Sync.TryLock(lockKey)
 | 
						if err != nil {
 | 
				
			||||||
		if err != nil {
 | 
							return err
 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if waiter != nil {
 | 
					 | 
				
			||||||
			log.Printf("[INFO] Certificate for %s is already being renewed elsewhere and stored; waiting", name)
 | 
					 | 
				
			||||||
			waiter.Wait()
 | 
					 | 
				
			||||||
			return nil // assume that the worker that renewed the cert succeeded; avoid hammering this path over and over
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		defer func() {
 | 
					 | 
				
			||||||
			if err := c.config.Sync.Unlock(lockKey); err != nil {
 | 
					 | 
				
			||||||
				log.Printf("[ERROR] Unable to unlock renew call for %s: %v", name, err)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}()
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if waiter != nil {
 | 
				
			||||||
 | 
							log.Printf("[INFO] Certificate for %s is already being renewed elsewhere and stored; waiting", name)
 | 
				
			||||||
 | 
							waiter.Wait()
 | 
				
			||||||
 | 
							return nil // assume that the worker that renewed the cert succeeded to avoid hammering this path over and over
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer func() {
 | 
				
			||||||
 | 
							if err := c.config.certCache.storage.Unlock(lockKey); err != nil {
 | 
				
			||||||
 | 
								log.Printf("[ERROR] Unable to unlock renew call for %s: %v", name, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Prepare for renewal (load PEM cert, key, and meta)
 | 
						// Prepare for renewal (load PEM cert, key, and meta)
 | 
				
			||||||
	certRes, err := c.config.loadCertResource(name)
 | 
						certRes, err := c.config.loadCertResource(name)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										30
									
								
								vendor/github.com/mholt/certmagic/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										30
									
								
								vendor/github.com/mholt/certmagic/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -38,15 +38,6 @@ type Config struct {
 | 
				
			|||||||
	// selecting an existing ACME server account
 | 
						// selecting an existing ACME server account
 | 
				
			||||||
	Email string
 | 
						Email string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// The synchronization implementation - although
 | 
					 | 
				
			||||||
	// it is not strictly required to have a Sync
 | 
					 | 
				
			||||||
	// value in general, all instances running in
 | 
					 | 
				
			||||||
	// in a cluster for the same domain names must
 | 
					 | 
				
			||||||
	// specify a Sync and use the same one, otherwise
 | 
					 | 
				
			||||||
	// some cert operations will not be properly
 | 
					 | 
				
			||||||
	// coordinated
 | 
					 | 
				
			||||||
	Sync Locker
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Set to true if agreed to the CA's
 | 
						// Set to true if agreed to the CA's
 | 
				
			||||||
	// subscriber agreement
 | 
						// subscriber agreement
 | 
				
			||||||
	Agreed bool
 | 
						Agreed bool
 | 
				
			||||||
@ -198,20 +189,6 @@ func NewWithCache(certCache *Cache, cfg Config) *Config {
 | 
				
			|||||||
		cfg.MustStaple = MustStaple
 | 
							cfg.MustStaple = MustStaple
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// if no sync facility is provided, we'll default to
 | 
					 | 
				
			||||||
	// a file system synchronizer backed by the storage
 | 
					 | 
				
			||||||
	// given to certCache (if it is one), or just a simple
 | 
					 | 
				
			||||||
	// in-memory sync facility otherwise (strictly speaking,
 | 
					 | 
				
			||||||
	// a sync is not required; only if running multiple
 | 
					 | 
				
			||||||
	// instances for the same domain names concurrently)
 | 
					 | 
				
			||||||
	if cfg.Sync == nil {
 | 
					 | 
				
			||||||
		if ccfs, ok := certCache.storage.(FileStorage); ok {
 | 
					 | 
				
			||||||
			cfg.Sync = NewFileStorageLocker(ccfs)
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			cfg.Sync = NewMemoryLocker()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// ensure the unexported fields are valid
 | 
						// ensure the unexported fields are valid
 | 
				
			||||||
	cfg.certificates = make(map[string]string)
 | 
						cfg.certificates = make(map[string]string)
 | 
				
			||||||
	cfg.certCache = certCache
 | 
						cfg.certCache = certCache
 | 
				
			||||||
@ -222,7 +199,12 @@ func NewWithCache(certCache *Cache, cfg Config) *Config {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Manage causes the certificates for domainNames to be managed
 | 
					// Manage causes the certificates for domainNames to be managed
 | 
				
			||||||
// according to cfg.
 | 
					// according to cfg. If cfg is enabled for OnDemand, then this
 | 
				
			||||||
 | 
					// simply whitelists the domain names. Otherwise, the certificate(s)
 | 
				
			||||||
 | 
					// for each name are loaded from storage or obtained from the CA;
 | 
				
			||||||
 | 
					// and if loaded from storage, renewed if they are expiring or
 | 
				
			||||||
 | 
					// expired. It then caches the certificate in memory and is
 | 
				
			||||||
 | 
					// prepared to serve them up during TLS handshakes.
 | 
				
			||||||
func (cfg *Config) Manage(domainNames []string) error {
 | 
					func (cfg *Config) Manage(domainNames []string) error {
 | 
				
			||||||
	for _, domainName := range domainNames {
 | 
						for _, domainName := range domainNames {
 | 
				
			||||||
		// if on-demand is configured, simply whitelist this name
 | 
							// if on-demand is configured, simply whitelist this name
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										113
									
								
								vendor/github.com/mholt/certmagic/filestorage.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										113
									
								
								vendor/github.com/mholt/certmagic/filestorage.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -15,10 +15,13 @@
 | 
				
			|||||||
package certmagic
 | 
					package certmagic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"runtime"
 | 
						"runtime"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FileStorage facilitates forming file paths derived from a root
 | 
					// FileStorage facilitates forming file paths derived from a root
 | 
				
			||||||
@ -123,4 +126,114 @@ func dataDir() string {
 | 
				
			|||||||
	return filepath.Join(baseDir, "certmagic")
 | 
						return filepath.Join(baseDir, "certmagic")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TryLock attempts to get a lock for name, otherwise it returns
 | 
				
			||||||
 | 
					// a Waiter value to wait until the other process is finished.
 | 
				
			||||||
 | 
					func (fs FileStorage) TryLock(key string) (Waiter, error) {
 | 
				
			||||||
 | 
						fileStorageNameLocksMu.Lock()
 | 
				
			||||||
 | 
						defer fileStorageNameLocksMu.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// see if lock already exists within this process - allows
 | 
				
			||||||
 | 
						// for faster unlocking since we don't have to poll the disk
 | 
				
			||||||
 | 
						fw, ok := fileStorageNameLocks[key]
 | 
				
			||||||
 | 
						if ok {
 | 
				
			||||||
 | 
							// lock already created within process, let caller wait on it
 | 
				
			||||||
 | 
							return fw, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// attempt to persist lock to disk by creating lock file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// parent dir must exist
 | 
				
			||||||
 | 
						lockDir := fs.lockDir()
 | 
				
			||||||
 | 
						if err := os.MkdirAll(lockDir, 0700); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fw = &fileStorageWaiter{
 | 
				
			||||||
 | 
							filename: filepath.Join(lockDir, safeKey(key)+".lock"),
 | 
				
			||||||
 | 
							wg:       new(sync.WaitGroup),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// create the file in a special mode such that an
 | 
				
			||||||
 | 
						// error is returned if it already exists
 | 
				
			||||||
 | 
						lf, err := os.OpenFile(fw.filename, os.O_CREATE|os.O_EXCL, 0644)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if os.IsExist(err) {
 | 
				
			||||||
 | 
								// another process has the lock; use it to wait
 | 
				
			||||||
 | 
								return fw, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// otherwise, this was some unexpected error
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						lf.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// looks like we get the lock
 | 
				
			||||||
 | 
						fw.wg.Add(1)
 | 
				
			||||||
 | 
						fileStorageNameLocks[key] = fw
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Unlock releases the lock for name.
 | 
				
			||||||
 | 
					func (fs FileStorage) Unlock(key string) error {
 | 
				
			||||||
 | 
						fileStorageNameLocksMu.Lock()
 | 
				
			||||||
 | 
						defer fileStorageNameLocksMu.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fw, ok := fileStorageNameLocks[key]
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return fmt.Errorf("FileStorage: no lock to release for %s", key)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// remove lock file
 | 
				
			||||||
 | 
						os.Remove(fw.filename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// if parent folder is now empty, remove it too to keep it tidy
 | 
				
			||||||
 | 
						dir, err := os.Open(fs.lockDir()) // OK to ignore error here
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							items, _ := dir.Readdirnames(3) // OK to ignore error here
 | 
				
			||||||
 | 
							if len(items) == 0 {
 | 
				
			||||||
 | 
								os.Remove(dir.Name())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							dir.Close()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// clean up in memory
 | 
				
			||||||
 | 
						fw.wg.Done()
 | 
				
			||||||
 | 
						delete(fileStorageNameLocks, key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (fs FileStorage) lockDir() string {
 | 
				
			||||||
 | 
						return filepath.Join(fs.Path, "locks")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// fileStorageWaiter waits for a file to disappear; it
 | 
				
			||||||
 | 
					// polls the file system to check for the existence of
 | 
				
			||||||
 | 
					// a file. It also uses a WaitGroup to optimize the
 | 
				
			||||||
 | 
					// polling in the case when this process is the only
 | 
				
			||||||
 | 
					// one waiting. (Other processes that are waiting for
 | 
				
			||||||
 | 
					// the lock will still block, but must wait for the
 | 
				
			||||||
 | 
					// polling to get their answer.)
 | 
				
			||||||
 | 
					type fileStorageWaiter struct {
 | 
				
			||||||
 | 
						filename string
 | 
				
			||||||
 | 
						wg       *sync.WaitGroup
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Wait waits until the lock is released.
 | 
				
			||||||
 | 
					func (fw *fileStorageWaiter) Wait() {
 | 
				
			||||||
 | 
						start := time.Now()
 | 
				
			||||||
 | 
						fw.wg.Wait()
 | 
				
			||||||
 | 
						for time.Since(start) < 1*time.Hour {
 | 
				
			||||||
 | 
							_, err := os.Stat(fw.filename)
 | 
				
			||||||
 | 
							if os.IsNotExist(err) {
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							time.Sleep(1 * time.Second)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var fileStorageNameLocks = make(map[string]*fileStorageWaiter)
 | 
				
			||||||
 | 
					var fileStorageNameLocksMu sync.Mutex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var _ Storage = FileStorage{}
 | 
					var _ Storage = FileStorage{}
 | 
				
			||||||
 | 
					var _ Waiter = &fileStorageWaiter{}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										146
									
								
								vendor/github.com/mholt/certmagic/filestoragesync.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										146
									
								
								vendor/github.com/mholt/certmagic/filestoragesync.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -1,146 +0,0 @@
 | 
				
			|||||||
// Copyright 2015 Matthew Holt
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
					 | 
				
			||||||
// you may not use this file except in compliance with the License.
 | 
					 | 
				
			||||||
// You may obtain a copy of the License at
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Unless required by applicable law or agreed to in writing, software
 | 
					 | 
				
			||||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
					 | 
				
			||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					 | 
				
			||||||
// See the License for the specific language governing permissions and
 | 
					 | 
				
			||||||
// limitations under the License.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package certmagic
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"os"
 | 
					 | 
				
			||||||
	"path/filepath"
 | 
					 | 
				
			||||||
	"sync"
 | 
					 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// FileStorageLocker implements the Locker interface
 | 
					 | 
				
			||||||
// using the file system. An empty value is NOT VALID,
 | 
					 | 
				
			||||||
// so you must use NewFileStorageLocker() to get one.
 | 
					 | 
				
			||||||
type FileStorageLocker struct {
 | 
					 | 
				
			||||||
	fs FileStorage
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// NewFileStorageLocker returns a valid Locker backed by fs.
 | 
					 | 
				
			||||||
func NewFileStorageLocker(fs FileStorage) *FileStorageLocker {
 | 
					 | 
				
			||||||
	return &FileStorageLocker{fs: fs}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TryLock attempts to get a lock for name, otherwise it returns
 | 
					 | 
				
			||||||
// a Waiter value to wait until the other process is finished.
 | 
					 | 
				
			||||||
func (l *FileStorageLocker) TryLock(name string) (Waiter, error) {
 | 
					 | 
				
			||||||
	fileStorageNameLocksMu.Lock()
 | 
					 | 
				
			||||||
	defer fileStorageNameLocksMu.Unlock()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// see if lock already exists within this process
 | 
					 | 
				
			||||||
	fw, ok := fileStorageNameLocks[name]
 | 
					 | 
				
			||||||
	if ok {
 | 
					 | 
				
			||||||
		// lock already created within process, let caller wait on it
 | 
					 | 
				
			||||||
		return fw, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// attempt to persist lock to disk by creating lock file
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// parent dir must exist
 | 
					 | 
				
			||||||
	lockDir := l.lockDir()
 | 
					 | 
				
			||||||
	if err := os.MkdirAll(lockDir, 0700); err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	fw = &FileStorageWaiter{
 | 
					 | 
				
			||||||
		filename: filepath.Join(lockDir, safeKey(name)+".lock"),
 | 
					 | 
				
			||||||
		wg:       new(sync.WaitGroup),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// create the file in a special mode such that an
 | 
					 | 
				
			||||||
	// error is returned if it already exists
 | 
					 | 
				
			||||||
	lf, err := os.OpenFile(fw.filename, os.O_CREATE|os.O_EXCL, 0644)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		if os.IsExist(err) {
 | 
					 | 
				
			||||||
			// another process has the lock; use it to wait
 | 
					 | 
				
			||||||
			return fw, nil
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		// otherwise, this was some unexpected error
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	lf.Close()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// looks like we get the lock
 | 
					 | 
				
			||||||
	fw.wg.Add(1)
 | 
					 | 
				
			||||||
	fileStorageNameLocks[name] = fw
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return nil, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Unlock releases the lock for name.
 | 
					 | 
				
			||||||
func (l *FileStorageLocker) Unlock(name string) error {
 | 
					 | 
				
			||||||
	fileStorageNameLocksMu.Lock()
 | 
					 | 
				
			||||||
	defer fileStorageNameLocksMu.Unlock()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	fw, ok := fileStorageNameLocks[name]
 | 
					 | 
				
			||||||
	if !ok {
 | 
					 | 
				
			||||||
		return fmt.Errorf("FileStorageLocker: no lock to release for %s", name)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// remove lock file
 | 
					 | 
				
			||||||
	os.Remove(fw.filename)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// if parent folder is now empty, remove it too to keep it tidy
 | 
					 | 
				
			||||||
	dir, err := os.Open(l.lockDir()) // OK to ignore error here
 | 
					 | 
				
			||||||
	if err == nil {
 | 
					 | 
				
			||||||
		items, _ := dir.Readdirnames(3) // OK to ignore error here
 | 
					 | 
				
			||||||
		if len(items) == 0 {
 | 
					 | 
				
			||||||
			os.Remove(dir.Name())
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		dir.Close()
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// clean up in memory
 | 
					 | 
				
			||||||
	fw.wg.Done()
 | 
					 | 
				
			||||||
	delete(fileStorageNameLocks, name)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (l *FileStorageLocker) lockDir() string {
 | 
					 | 
				
			||||||
	return filepath.Join(l.fs.Path, "locks")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// FileStorageWaiter waits for a file to disappear; it
 | 
					 | 
				
			||||||
// polls the file system to check for the existence of
 | 
					 | 
				
			||||||
// a file. It also uses a WaitGroup to optimize the
 | 
					 | 
				
			||||||
// polling in the case when this process is the only
 | 
					 | 
				
			||||||
// one waiting. (Other processes that are waiting
 | 
					 | 
				
			||||||
// for the lock will still block, but must wait
 | 
					 | 
				
			||||||
// for the poll intervals to get their answer.)
 | 
					 | 
				
			||||||
type FileStorageWaiter struct {
 | 
					 | 
				
			||||||
	filename string
 | 
					 | 
				
			||||||
	wg       *sync.WaitGroup
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Wait waits until the lock is released.
 | 
					 | 
				
			||||||
func (fw *FileStorageWaiter) Wait() {
 | 
					 | 
				
			||||||
	start := time.Now()
 | 
					 | 
				
			||||||
	fw.wg.Wait()
 | 
					 | 
				
			||||||
	for time.Since(start) < 1*time.Hour {
 | 
					 | 
				
			||||||
		_, err := os.Stat(fw.filename)
 | 
					 | 
				
			||||||
		if os.IsNotExist(err) {
 | 
					 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		time.Sleep(1 * time.Second)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var fileStorageNameLocks = make(map[string]*FileStorageWaiter)
 | 
					 | 
				
			||||||
var fileStorageNameLocksMu sync.Mutex
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var _ Locker = &FileStorageLocker{}
 | 
					 | 
				
			||||||
var _ Waiter = &FileStorageWaiter{}
 | 
					 | 
				
			||||||
							
								
								
									
										48
									
								
								vendor/github.com/mholt/certmagic/storage.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										48
									
								
								vendor/github.com/mholt/certmagic/storage.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -31,9 +31,9 @@ import (
 | 
				
			|||||||
// in order to share certificates and other TLS resources
 | 
					// in order to share certificates and other TLS resources
 | 
				
			||||||
// with the cluster.
 | 
					// with the cluster.
 | 
				
			||||||
type Storage interface {
 | 
					type Storage interface {
 | 
				
			||||||
	// Exists returns true if the key exists
 | 
						// Locker provides atomic synchronization
 | 
				
			||||||
	// and there was no error checking.
 | 
						// operations, making Storage safe to share.
 | 
				
			||||||
	Exists(key string) bool
 | 
						Locker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Store puts value at key.
 | 
						// Store puts value at key.
 | 
				
			||||||
	Store(key string, value []byte) error
 | 
						Store(key string, value []byte) error
 | 
				
			||||||
@ -44,6 +44,10 @@ type Storage interface {
 | 
				
			|||||||
	// Delete deletes key.
 | 
						// Delete deletes key.
 | 
				
			||||||
	Delete(key string) error
 | 
						Delete(key string) error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Exists returns true if the key exists
 | 
				
			||||||
 | 
						// and there was no error checking.
 | 
				
			||||||
 | 
						Exists(key string) bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// List returns all keys that match prefix.
 | 
						// List returns all keys that match prefix.
 | 
				
			||||||
	List(prefix string) ([]string, error)
 | 
						List(prefix string) ([]string, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -51,6 +55,41 @@ type Storage interface {
 | 
				
			|||||||
	Stat(key string) (KeyInfo, error)
 | 
						Stat(key string) (KeyInfo, error)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Locker facilitates synchronization of certificate tasks across
 | 
				
			||||||
 | 
					// machines and networks.
 | 
				
			||||||
 | 
					type Locker interface {
 | 
				
			||||||
 | 
						// TryLock will attempt to acquire the lock for key. If a
 | 
				
			||||||
 | 
						// lock could be obtained, nil values are returned as no
 | 
				
			||||||
 | 
						// waiting is required. If not (meaning another process is
 | 
				
			||||||
 | 
						// already working on key), a Waiter value will be returned,
 | 
				
			||||||
 | 
						// upon which you should Wait() until it is finished.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// The actual implementation of obtaining of a lock must be
 | 
				
			||||||
 | 
						// an atomic operation so that multiple TryLock calls at the
 | 
				
			||||||
 | 
						// same time always results in only one caller receiving the
 | 
				
			||||||
 | 
						// lock. TryLock always returns without waiting.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// To prevent deadlocks, all implementations (where this concern
 | 
				
			||||||
 | 
						// is relevant) should put a reasonable expiration on the lock in
 | 
				
			||||||
 | 
						// case Unlock is unable to be called due to some sort of network
 | 
				
			||||||
 | 
						// or system failure or crash.
 | 
				
			||||||
 | 
						TryLock(key string) (Waiter, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Unlock releases the lock for key. This method must ONLY be
 | 
				
			||||||
 | 
						// called after a successful call to TryLock where no Waiter was
 | 
				
			||||||
 | 
						// returned, and only after the operation requiring the lock is
 | 
				
			||||||
 | 
						// finished, even if it errored or timed out. It is INCORRECT to
 | 
				
			||||||
 | 
						// call Unlock if any non-nil value was returned from a call to
 | 
				
			||||||
 | 
						// TryLock or if Unlock was not called at all. Unlock should also
 | 
				
			||||||
 | 
						// clean up any unused resources allocated during TryLock.
 | 
				
			||||||
 | 
						Unlock(key string) error
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Waiter is a type that can block until a lock is released.
 | 
				
			||||||
 | 
					type Waiter interface {
 | 
				
			||||||
 | 
						Wait()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// KeyInfo holds information about a key in storage.
 | 
					// KeyInfo holds information about a key in storage.
 | 
				
			||||||
type KeyInfo struct {
 | 
					type KeyInfo struct {
 | 
				
			||||||
	Key      string
 | 
						Key      string
 | 
				
			||||||
@ -207,6 +246,3 @@ var defaultFileStorage = FileStorage{Path: dataDir()}
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// DefaultStorage is the default Storage implementation.
 | 
					// DefaultStorage is the default Storage implementation.
 | 
				
			||||||
var DefaultStorage Storage = defaultFileStorage
 | 
					var DefaultStorage Storage = defaultFileStorage
 | 
				
			||||||
 | 
					 | 
				
			||||||
// DefaultSync is a default sync to use.
 | 
					 | 
				
			||||||
var DefaultSync Locker
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								vendor/manifest
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/manifest
									
									
									
									
										vendored
									
									
								
							@ -138,7 +138,7 @@
 | 
				
			|||||||
			"importpath": "github.com/mholt/certmagic",
 | 
								"importpath": "github.com/mholt/certmagic",
 | 
				
			||||||
			"repository": "https://github.com/mholt/certmagic",
 | 
								"repository": "https://github.com/mholt/certmagic",
 | 
				
			||||||
			"vcs": "git",
 | 
								"vcs": "git",
 | 
				
			||||||
			"revision": "4dd0c62355ec3c3732f18c506449fc9b5f9f4c59",
 | 
								"revision": "8b6ddf223c912a863aaadd388bfdd29be295fb5d",
 | 
				
			||||||
			"branch": "master",
 | 
								"branch": "master",
 | 
				
			||||||
			"notests": true
 | 
								"notests": true
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user