letsencrypt: Graceful restarts

Lots of refinement still needed and runs only on POSIX systems. Windows will not get true graceful restarts (for now), but we will opt for very, very quick forceful restarts. Also, server configs are no longer put into a map; it is critical that they stay ordered so that they can be matched with their sockets in the child process after forking.

This implementation of graceful restarts is probably not perfect, but it is a good start. Lots of details to attend to now.
This commit is contained in:
Matthew Holt
2015-10-25 18:45:55 -06:00
parent f24ecee603
commit b5b31e398c
5 changed files with 486 additions and 144 deletions

View File

@ -153,14 +153,14 @@ func makeStorages() map[string]interface{} {
// bind address to list of configs that would become VirtualHosts on that
// server. Use the keys of the returned map to create listeners, and use
// the associated values to set up the virtualhosts.
func arrangeBindings(allConfigs []server.Config) (map[*net.TCPAddr][]server.Config, error) {
addresses := make(map[*net.TCPAddr][]server.Config)
func arrangeBindings(allConfigs []server.Config) (Group, error) {
var groupings Group
// Group configs by bind address
for _, conf := range allConfigs {
newAddr, warnErr, fatalErr := resolveAddr(conf)
bindAddr, warnErr, fatalErr := resolveAddr(conf)
if fatalErr != nil {
return addresses, fatalErr
return groupings, fatalErr
}
if warnErr != nil {
log.Println("[Warning]", warnErr)
@ -169,37 +169,40 @@ func arrangeBindings(allConfigs []server.Config) (map[*net.TCPAddr][]server.Conf
// Make sure to compare the string representation of the address,
// not the pointer, since a new *TCPAddr is created each time.
var existing bool
for addr := range addresses {
if addr.String() == newAddr.String() {
addresses[addr] = append(addresses[addr], conf)
for i := 0; i < len(groupings); i++ {
if groupings[i].BindAddr.String() == bindAddr.String() {
groupings[i].Configs = append(groupings[i].Configs, conf)
existing = true
break
}
}
if !existing {
addresses[newAddr] = append(addresses[newAddr], conf)
groupings = append(groupings, BindingMapping{
BindAddr: bindAddr,
Configs: []server.Config{conf},
})
}
}
// Don't allow HTTP and HTTPS to be served on the same address
for _, configs := range addresses {
isTLS := configs[0].TLS.Enabled
for _, config := range configs {
for _, group := range groupings {
isTLS := group.Configs[0].TLS.Enabled
for _, config := range group.Configs {
if config.TLS.Enabled != isTLS {
thisConfigProto, otherConfigProto := "HTTP", "HTTP"
if config.TLS.Enabled {
thisConfigProto = "HTTPS"
}
if configs[0].TLS.Enabled {
if group.Configs[0].TLS.Enabled {
otherConfigProto = "HTTPS"
}
return addresses, fmt.Errorf("configuration error: Cannot multiplex %s (%s) and %s (%s) on same address",
configs[0].Address(), otherConfigProto, config.Address(), thisConfigProto)
return groupings, fmt.Errorf("configuration error: Cannot multiplex %s (%s) and %s (%s) on same address",
group.Configs[0].Address(), otherConfigProto, config.Address(), thisConfigProto)
}
}
}
return addresses, nil
return groupings, nil
}
// resolveAddr determines the address (host and port) that a config will
@ -291,5 +294,15 @@ var (
Port = DefaultPort
)
// BindingMapping maps a network address to configurations
// that will bind to it. The order of the configs is important.
type BindingMapping struct {
BindAddr *net.TCPAddr
Configs []server.Config
}
// Group maps network addresses to their configurations.
type Group map[*net.TCPAddr][]server.Config
// Preserving the order of the groupings is important
// (related to graceful shutdown and restart)
// so this is a slice, not a literal map.
type Group []BindingMapping