Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
caddy
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
caddy
Commits
8811853f
Commit
8811853f
authored
Dec 13, 2018
by
Matthew Holt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
caddytls: Better handle FileStorage and cleaning up locks on exit
parent
b7028b13
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
101 additions
and
33 deletions
+101
-33
caddy.go
caddy.go
+5
-3
caddytls/config.go
caddytls/config.go
+2
-2
caddytls/setup.go
caddytls/setup.go
+1
-13
vendor/github.com/mholt/certmagic/cache.go
vendor/github.com/mholt/certmagic/cache.go
+2
-3
vendor/github.com/mholt/certmagic/client.go
vendor/github.com/mholt/certmagic/client.go
+9
-1
vendor/github.com/mholt/certmagic/config.go
vendor/github.com/mholt/certmagic/config.go
+16
-3
vendor/github.com/mholt/certmagic/filestorage.go
vendor/github.com/mholt/certmagic/filestorage.go
+48
-1
vendor/github.com/mholt/certmagic/maintain.go
vendor/github.com/mholt/certmagic/maintain.go
+6
-6
vendor/github.com/mholt/certmagic/storage.go
vendor/github.com/mholt/certmagic/storage.go
+11
-0
vendor/manifest
vendor/manifest
+1
-1
No files found.
caddy.go
View file @
8811853f
...
@@ -469,9 +469,10 @@ func (i *Instance) Caddyfile() Input {
...
@@ -469,9 +469,10 @@ 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
// set up the clustering plugin, if there is one (and there should
// exactly once -- but we can't do it during init when they're still
// always be one) -- this should be done exactly once, but we can't
// getting plugged in, so do it when starting the first instance)
// do it during init while plugins are still registering, so do it
// when starting the first instance)
if
atomic
.
CompareAndSwapInt32
(
&
clusterPluginSetup
,
0
,
1
)
{
if
atomic
.
CompareAndSwapInt32
(
&
clusterPluginSetup
,
0
,
1
)
{
clusterPluginName
:=
os
.
Getenv
(
"CADDY_CLUSTERING"
)
clusterPluginName
:=
os
.
Getenv
(
"CADDY_CLUSTERING"
)
if
clusterPluginName
==
""
{
if
clusterPluginName
==
""
{
...
@@ -486,6 +487,7 @@ func Start(cdyfile Input) (*Instance, error) {
...
@@ -486,6 +487,7 @@ func Start(cdyfile Input) (*Instance, error) {
return
nil
,
fmt
.
Errorf
(
"constructing cluster plugin %s: %v"
,
clusterPluginName
,
err
)
return
nil
,
fmt
.
Errorf
(
"constructing cluster plugin %s: %v"
,
clusterPluginName
,
err
)
}
}
certmagic
.
DefaultStorage
=
storage
certmagic
.
DefaultStorage
=
storage
OnProcessExit
=
append
(
OnProcessExit
,
certmagic
.
DefaultStorage
.
UnlockAllObtained
)
}
}
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
{})}
...
...
caddytls/config.go
View file @
8811853f
...
@@ -98,7 +98,7 @@ func NewConfig(inst *caddy.Instance) *Config {
...
@@ -98,7 +98,7 @@ func NewConfig(inst *caddy.Instance) *Config {
certCache
,
ok
:=
inst
.
Storage
[
CertCacheInstStorageKey
]
.
(
*
certmagic
.
Cache
)
certCache
,
ok
:=
inst
.
Storage
[
CertCacheInstStorageKey
]
.
(
*
certmagic
.
Cache
)
inst
.
StorageMu
.
RUnlock
()
inst
.
StorageMu
.
RUnlock
()
if
!
ok
||
certCache
==
nil
{
if
!
ok
||
certCache
==
nil
{
certCache
=
certmagic
.
NewCache
(
certmagic
.
FileStorage
{
Path
:
caddy
.
AssetsPath
()}
)
certCache
=
certmagic
.
NewCache
(
certmagic
.
DefaultStorage
)
inst
.
OnShutdown
=
append
(
inst
.
OnShutdown
,
func
()
error
{
inst
.
OnShutdown
=
append
(
inst
.
OnShutdown
,
func
()
error
{
certCache
.
Stop
()
certCache
.
Stop
()
return
nil
return
nil
...
@@ -108,7 +108,7 @@ func NewConfig(inst *caddy.Instance) *Config {
...
@@ -108,7 +108,7 @@ func NewConfig(inst *caddy.Instance) *Config {
inst
.
StorageMu
.
Unlock
()
inst
.
StorageMu
.
Unlock
()
}
}
return
&
Config
{
return
&
Config
{
Manager
:
certmagic
.
NewWithCache
(
certCache
,
certmagic
.
Config
{}),
// TODO
Manager
:
certmagic
.
NewWithCache
(
certCache
,
certmagic
.
Config
{}),
}
}
}
}
...
...
caddytls/setup.go
View file @
8811853f
...
@@ -57,7 +57,7 @@ func setupTLS(c *caddy.Controller) error {
...
@@ -57,7 +57,7 @@ func setupTLS(c *caddy.Controller) error {
// a single certificate cache is used by the whole caddy.Instance; get a pointer to it
// a single certificate cache is used by the whole caddy.Instance; get a pointer to it
certCache
,
ok
:=
c
.
Get
(
CertCacheInstStorageKey
)
.
(
*
certmagic
.
Cache
)
certCache
,
ok
:=
c
.
Get
(
CertCacheInstStorageKey
)
.
(
*
certmagic
.
Cache
)
if
!
ok
||
certCache
==
nil
{
if
!
ok
||
certCache
==
nil
{
certCache
=
certmagic
.
NewCache
(
certmagic
.
FileStorage
{
Path
:
caddy
.
AssetsPath
()}
)
certCache
=
certmagic
.
NewCache
(
certmagic
.
DefaultStorage
)
c
.
OnShutdown
(
func
()
error
{
c
.
OnShutdown
(
func
()
error
{
certCache
.
Stop
()
certCache
.
Stop
()
return
nil
return
nil
...
@@ -252,18 +252,6 @@ func setupTLS(c *caddy.Controller) error {
...
@@ -252,18 +252,6 @@ func setupTLS(c *caddy.Controller) error {
return
c
.
Errf
(
"Setting up DNS provider '%s': %v"
,
dnsProvName
,
err
)
return
c
.
Errf
(
"Setting up DNS provider '%s': %v"
,
dnsProvName
,
err
)
}
}
config
.
Manager
.
DNSProvider
=
dnsProv
config
.
Manager
.
DNSProvider
=
dnsProv
// TODO
// case "storage":
// args := c.RemainingArgs()
// if len(args) != 1 {
// return c.ArgErr()
// }
// storageProvName := args[0]
// storageProvConstr, ok := storageProviders[storageProvName]
// if !ok {
// return c.Errf("Unsupported Storage provider '%s'", args[0])
// }
// config.Manager.Storage = storageProvConstr
case
"alpn"
:
case
"alpn"
:
args
:=
c
.
RemainingArgs
()
args
:=
c
.
RemainingArgs
()
if
len
(
args
)
==
0
{
if
len
(
args
)
==
0
{
...
...
vendor/github.com/mholt/certmagic/cache.go
View file @
8811853f
...
@@ -165,6 +165,5 @@ func (certCache *Cache) reloadManagedCertificate(oldCert Certificate) error {
...
@@ -165,6 +165,5 @@ func (certCache *Cache) reloadManagedCertificate(oldCert Certificate) error {
return
nil
return
nil
}
}
// defaultCache is a convenient, default certificate cache for
var
defaultCache
*
Cache
// use by this process when no other certificate cache is provided.
var
defaultCacheMu
sync
.
Mutex
var
defaultCache
=
NewCache
(
DefaultStorage
)
vendor/github.com/mholt/certmagic/client.go
View file @
8811853f
...
@@ -94,7 +94,7 @@ func (cfg *Config) newACMEClient(interactive bool) (*acmeClient, error) {
...
@@ -94,7 +94,7 @@ func (cfg *Config) newACMEClient(interactive bool) (*acmeClient, error) {
legoCfg
:=
lego
.
NewConfig
(
&
leUser
)
legoCfg
:=
lego
.
NewConfig
(
&
leUser
)
legoCfg
.
CADirURL
=
caURL
legoCfg
.
CADirURL
=
caURL
legoCfg
.
KeyType
=
keyType
legoCfg
.
KeyType
=
keyType
legoCfg
.
UserAgent
=
UserAgent
legoCfg
.
UserAgent
=
buildUAString
()
legoCfg
.
HTTPClient
.
Timeout
=
HTTPTimeout
legoCfg
.
HTTPClient
.
Timeout
=
HTTPTimeout
client
,
err
=
lego
.
NewClient
(
legoCfg
)
client
,
err
=
lego
.
NewClient
(
legoCfg
)
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -373,6 +373,14 @@ func (c *acmeClient) Revoke(name string) error {
...
@@ -373,6 +373,14 @@ func (c *acmeClient) Revoke(name string) error {
return
nil
return
nil
}
}
func
buildUAString
()
string
{
ua
:=
"CertMagic"
if
UserAgent
!=
""
{
ua
+=
" "
+
UserAgent
}
return
ua
}
// Some default values passed down to the underlying lego client.
// Some default values passed down to the underlying lego client.
var
(
var
(
UserAgent
string
UserAgent
string
...
...
vendor/github.com/mholt/certmagic/config.go
View file @
8811853f
...
@@ -125,15 +125,28 @@ func NewDefault() *Config {
...
@@ -125,15 +125,28 @@ func NewDefault() *Config {
// a default certificate cache. All calls to
// a default certificate cache. All calls to
// New() will use the same certificate cache.
// New() will use the same certificate cache.
func
New
(
cfg
Config
)
*
Config
{
func
New
(
cfg
Config
)
*
Config
{
return
NewWithCache
(
defaultCache
,
cfg
)
return
NewWithCache
(
nil
,
cfg
)
}
}
// NewWithCache makes a valid new config based on cfg
// NewWithCache makes a valid new config based on cfg
// and uses the provided certificate cache.
// and uses the provided certificate cache. If certCache
// is nil, a new, default one will be created using
// DefaultStorage; or, if a default cache has already
// been created, it will be reused.
func
NewWithCache
(
certCache
*
Cache
,
cfg
Config
)
*
Config
{
func
NewWithCache
(
certCache
*
Cache
,
cfg
Config
)
*
Config
{
// avoid nil pointers with sensible defaults
// avoid nil pointers with sensible defaults,
// careful to initialize a default cache (which
// begins its maintenance goroutine) only if
// needed - and only once (we don't initialize
// it at package init to give importers a chance
// to set DefaultStorage if they so desire)
if
certCache
==
nil
{
if
certCache
==
nil
{
defaultCacheMu
.
Lock
()
if
defaultCache
==
nil
{
defaultCache
=
NewCache
(
DefaultStorage
)
}
certCache
=
defaultCache
certCache
=
defaultCache
defaultCacheMu
.
Unlock
()
}
}
if
certCache
.
storage
==
nil
{
if
certCache
.
storage
==
nil
{
certCache
.
storage
=
DefaultStorage
certCache
.
storage
=
DefaultStorage
...
...
vendor/github.com/mholt/certmagic/filestorage.go
View file @
8811853f
...
@@ -17,6 +17,7 @@ package certmagic
...
@@ -17,6 +17,7 @@ package certmagic
import
(
import
(
"fmt"
"fmt"
"io/ioutil"
"io/ioutil"
"log"
"os"
"os"
"path"
"path"
"path/filepath"
"path/filepath"
...
@@ -171,18 +172,36 @@ func (fs FileStorage) TryLock(key string) (Waiter, error) {
...
@@ -171,18 +172,36 @@ func (fs FileStorage) TryLock(key string) (Waiter, error) {
}
}
fw
=
&
fileStorageWaiter
{
fw
=
&
fileStorageWaiter
{
key
:
key
,
filename
:
filepath
.
Join
(
lockDir
,
StorageKeys
.
safe
(
key
)
+
".lock"
),
filename
:
filepath
.
Join
(
lockDir
,
StorageKeys
.
safe
(
key
)
+
".lock"
),
wg
:
new
(
sync
.
WaitGroup
),
wg
:
new
(
sync
.
WaitGroup
),
}
}
var
checkedStaleLock
bool
// sentinel value to avoid infinite goto-ing
createLock
:
// create the file in a special mode such that an
// create the file in a special mode such that an
// error is returned if it already exists
// error is returned if it already exists
lf
,
err
:=
os
.
OpenFile
(
fw
.
filename
,
os
.
O_CREATE
|
os
.
O_EXCL
,
0644
)
lf
,
err
:=
os
.
OpenFile
(
fw
.
filename
,
os
.
O_CREATE
|
os
.
O_EXCL
,
0644
)
if
err
!=
nil
{
if
err
!=
nil
{
if
os
.
IsExist
(
err
)
{
if
os
.
IsExist
(
err
)
{
// another process has the lock; use it to wait
// another process has the lock
// check to see if the lock is stale, if we haven't already
if
!
checkedStaleLock
{
checkedStaleLock
=
true
if
fs
.
lockFileStale
(
fw
.
filename
)
{
log
.
Printf
(
"[INFO][%s] Lock for '%s' is stale; removing then retrying: %s"
,
fs
,
key
,
fw
.
filename
)
os
.
Remove
(
fw
.
filename
)
goto
createLock
}
}
// if lock is not stale, wait upon it
return
fw
,
nil
return
fw
,
nil
}
}
// otherwise, this was some unexpected error
// otherwise, this was some unexpected error
return
nil
,
err
return
nil
,
err
}
}
...
@@ -225,10 +244,33 @@ func (fs FileStorage) Unlock(key string) error {
...
@@ -225,10 +244,33 @@ func (fs FileStorage) Unlock(key string) error {
return
nil
return
nil
}
}
// UnlockAllObtained removes all locks obtained by
// this instance of fs.
func
(
fs
FileStorage
)
UnlockAllObtained
()
{
for
key
,
fw
:=
range
fileStorageNameLocks
{
err
:=
fs
.
Unlock
(
fw
.
key
)
if
err
!=
nil
{
log
.
Printf
(
"[ERROR][%s] Releasing obtained lock for %s: %v"
,
fs
,
key
,
err
)
}
}
}
func
(
fs
FileStorage
)
lockFileStale
(
filename
string
)
bool
{
info
,
err
:=
os
.
Stat
(
filename
)
if
err
!=
nil
{
return
true
// no good way to handle this, really; lock is useless?
}
return
time
.
Since
(
info
.
ModTime
())
>
staleLockDuration
}
func
(
fs
FileStorage
)
lockDir
()
string
{
func
(
fs
FileStorage
)
lockDir
()
string
{
return
filepath
.
Join
(
fs
.
Path
,
"locks"
)
return
filepath
.
Join
(
fs
.
Path
,
"locks"
)
}
}
func
(
fs
FileStorage
)
String
()
string
{
return
"FileStorage:"
+
fs
.
Path
}
// fileStorageWaiter waits for a file to disappear; it
// fileStorageWaiter waits for a file to disappear; it
// polls the file system to check for the existence of
// polls the file system to check for the existence of
// a file. It also uses a WaitGroup to optimize the
// a file. It also uses a WaitGroup to optimize the
...
@@ -237,6 +279,7 @@ func (fs FileStorage) lockDir() string {
...
@@ -237,6 +279,7 @@ func (fs FileStorage) lockDir() string {
// the lock will still block, but must wait for the
// the lock will still block, but must wait for the
// polling to get their answer.)
// polling to get their answer.)
type
fileStorageWaiter
struct
{
type
fileStorageWaiter
struct
{
key
string
filename
string
filename
string
wg
*
sync
.
WaitGroup
wg
*
sync
.
WaitGroup
}
}
...
@@ -259,3 +302,7 @@ var fileStorageNameLocksMu sync.Mutex
...
@@ -259,3 +302,7 @@ var fileStorageNameLocksMu sync.Mutex
var
_
Storage
=
FileStorage
{}
var
_
Storage
=
FileStorage
{}
var
_
Waiter
=
&
fileStorageWaiter
{}
var
_
Waiter
=
&
fileStorageWaiter
{}
// staleLockDuration is the length of time
// before considering a lock to be stale.
const
staleLockDuration
=
2
*
time
.
Hour
vendor/github.com/mholt/certmagic/maintain.go
View file @
8811853f
...
@@ -38,21 +38,21 @@ func (certCache *Cache) maintainAssets() {
...
@@ -38,21 +38,21 @@ func (certCache *Cache) maintainAssets() {
for
{
for
{
select
{
select
{
case
<-
renewalTicker
.
C
:
case
<-
renewalTicker
.
C
:
log
.
Print
ln
(
"[INFO] Scanning for expiring certificates"
)
log
.
Print
f
(
"[INFO][%s] Scanning for expiring certificates"
,
certCache
.
storage
)
err
:=
certCache
.
RenewManagedCertificates
(
false
)
err
:=
certCache
.
RenewManagedCertificates
(
false
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Printf
(
"[ERROR]
Renewing managed certificates: %v"
,
err
)
log
.
Printf
(
"[ERROR]
[%s] Renewing managed certificates: %v"
,
certCache
.
storage
,
err
)
}
}
log
.
Print
ln
(
"[INFO] Done checking certificates"
)
log
.
Print
f
(
"[INFO][%s] Done scanning certificates"
,
certCache
.
storage
)
case
<-
ocspTicker
.
C
:
case
<-
ocspTicker
.
C
:
log
.
Print
ln
(
"[INFO] Scanning for stale OCSP staples"
)
log
.
Print
f
(
"[INFO][%s] Scanning for stale OCSP staples"
,
certCache
.
storage
)
certCache
.
updateOCSPStaples
()
certCache
.
updateOCSPStaples
()
certCache
.
deleteOldStapleFiles
()
certCache
.
deleteOldStapleFiles
()
log
.
Print
ln
(
"[INFO] Done checking OCSP staples"
)
log
.
Print
f
(
"[INFO][%s] Done checking OCSP staples"
,
certCache
.
storage
)
case
<-
certCache
.
stopChan
:
case
<-
certCache
.
stopChan
:
renewalTicker
.
Stop
()
renewalTicker
.
Stop
()
ocspTicker
.
Stop
()
ocspTicker
.
Stop
()
log
.
Print
ln
(
"[INFO] Stopped certificate maintenance routine"
)
log
.
Print
f
(
"[INFO][%s] Stopped certificate maintenance routine"
,
certCache
.
storage
)
return
return
}
}
}
}
...
...
vendor/github.com/mholt/certmagic/storage.go
View file @
8811853f
...
@@ -30,6 +30,8 @@ import (
...
@@ -30,6 +30,8 @@ import (
// same Storage value (its implementation and configuration)
// same Storage value (its implementation and configuration)
// in order to share certificates and other TLS resources
// in order to share certificates and other TLS resources
// with the cluster.
// with the cluster.
//
// Implementations of Storage must be safe for concurrent use.
type
Storage
interface
{
type
Storage
interface
{
// Locker provides atomic synchronization
// Locker provides atomic synchronization
// operations, making Storage safe to share.
// operations, making Storage safe to share.
...
@@ -87,6 +89,15 @@ type Locker interface {
...
@@ -87,6 +89,15 @@ type Locker interface {
// TryLock or if Unlock was not called at all. Unlock should also
// TryLock or if Unlock was not called at all. Unlock should also
// clean up any unused resources allocated during TryLock.
// clean up any unused resources allocated during TryLock.
Unlock
(
key
string
)
error
Unlock
(
key
string
)
error
// UnlockAllObtained removes all locks obtained by this process,
// upon which others may be waiting. The importer should call
// this on shutdowns (and crashes, ideally) to avoid leaving stale
// locks, but Locker implementations must NOT rely on this being
// the case and should anticipate and handle stale locks. Errors
// should be printed or logged, since there could be multiple,
// with no good way to handle them anyway.
UnlockAllObtained
()
}
}
// Waiter is a type that can block until a lock is released.
// Waiter is a type that can block until a lock is released.
...
...
vendor/manifest
View file @
8811853f
...
@@ -138,7 +138,7 @@
...
@@ -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": "
dc98c40439d15f67021f10f0d9219a39d7cf2990
",
"revision": "
fe722057f2654b33cd528b8fd8b90e53fa495564
",
"branch": "master",
"branch": "master",
"notests": true
"notests": true
},
},
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment