2014-08-09 22:30:27 +00:00
package daemon
2013-10-04 19:25:15 -07:00
import (
2015-12-10 18:35:10 -05:00
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"strings"
"sync"
"github.com/Sirupsen/logrus"
2014-08-10 01:18:32 +00:00
"github.com/docker/docker/opts"
2015-12-10 18:35:10 -05:00
"github.com/docker/docker/pkg/discovery"
2014-08-10 01:18:32 +00:00
flag "github.com/docker/docker/pkg/mflag"
2015-12-10 18:35:10 -05:00
"github.com/imdario/mergo"
2013-10-04 19:25:15 -07:00
)
2014-01-29 18:34:43 -08:00
const (
2014-02-01 03:38:39 -08:00
defaultNetworkMtu = 1500
2014-09-16 10:37:50 -07:00
disableNetworkBridge = "none"
2014-01-29 18:34:43 -08:00
)
2015-12-10 18:35:10 -05:00
// LogConfig represents the default log configuration.
// It includes json tags to deserialize configuration from a file
// using the same names that the flags in the command line uses.
type LogConfig struct {
Type string ` json:"log-driver,omitempty" `
Config map [ string ] string ` json:"log-opts,omitempty" `
}
// CommonTLSOptions defines TLS configuration for the daemon server.
// It includes json tags to deserialize configuration from a file
// using the same names that the flags in the command line uses.
type CommonTLSOptions struct {
CAFile string ` json:"tlscacert,omitempty" `
CertFile string ` json:"tlscert,omitempty" `
KeyFile string ` json:"tlskey,omitempty" `
}
2015-04-24 15:36:11 -07:00
// CommonConfig defines the configuration of a docker daemon which are
// common across platforms.
2015-12-10 18:35:10 -05:00
// It includes json tags to deserialize configuration from a file
// using the same names that the flags in the command line uses.
2015-04-24 15:36:11 -07:00
type CommonConfig struct {
2015-12-10 18:35:10 -05:00
AuthorizationPlugins [ ] string ` json:"authorization-plugins,omitempty" ` // AuthorizationPlugins holds list of authorization plugins
AutoRestart bool ` json:"-" `
Bridge bridgeConfig ` json:"-" ` // Bridge holds bridge network specific configuration.
Context map [ string ] [ ] string ` json:"-" `
DisableBridge bool ` json:"-" `
DNS [ ] string ` json:"dns,omitempty" `
DNSOptions [ ] string ` json:"dns-opts,omitempty" `
DNSSearch [ ] string ` json:"dns-search,omitempty" `
ExecOptions [ ] string ` json:"exec-opts,omitempty" `
ExecRoot string ` json:"exec-root,omitempty" `
GraphDriver string ` json:"storage-driver,omitempty" `
GraphOptions [ ] string ` json:"storage-opts,omitempty" `
Labels [ ] string ` json:"labels,omitempty" `
LogConfig LogConfig ` json:"log-config,omitempty" `
Mtu int ` json:"mtu,omitempty" `
Pidfile string ` json:"pidfile,omitempty" `
Root string ` json:"graph,omitempty" `
TrustKeyPath string ` json:"-" `
2015-09-10 16:12:00 -07:00
// ClusterStore is the storage backend used for the cluster information. It is used by both
// multihost networking (to store networks and endpoints information) and by the node discovery
// mechanism.
2015-12-10 18:35:10 -05:00
ClusterStore string ` json:"cluster-store,omitempty" `
2015-09-10 16:12:00 -07:00
2015-09-28 16:22:57 -07:00
// ClusterOpts is used to pass options to the discovery package for tuning libkv settings, such
// as TLS configuration settings.
2015-12-10 18:35:10 -05:00
ClusterOpts map [ string ] string ` json:"cluster-store-opts,omitempty" `
2015-09-28 16:22:57 -07:00
2015-09-10 16:12:00 -07:00
// ClusterAdvertise is the network endpoint that the Engine advertises for the purpose of node
// discovery. This should be a 'host:port' combination on which that daemon instance is
// reachable by other hosts.
2015-12-10 18:35:10 -05:00
ClusterAdvertise string ` json:"cluster-advertise,omitempty" `
Debug bool ` json:"debug,omitempty" `
Hosts [ ] string ` json:"hosts,omitempty" `
LogLevel string ` json:"log-level,omitempty" `
TLS bool ` json:"tls,omitempty" `
TLSVerify bool ` json:"tls-verify,omitempty" `
TLSOptions CommonTLSOptions ` json:"tls-opts,omitempty" `
reloadLock sync . Mutex
2013-10-04 19:25:15 -07:00
}
2013-10-21 10:04:42 -06:00
2015-04-24 15:36:11 -07:00
// InstallCommonFlags adds command-line options to the top-level flag parser for
2014-08-10 01:18:32 +00:00
// the current process.
// Subsequent calls to `flag.Parse` will populate config with values parsed
// from the command-line.
2015-05-05 00:18:28 -04:00
func ( config * Config ) InstallCommonFlags ( cmd * flag . FlagSet , usageFn func ( string ) string ) {
2015-12-10 18:35:10 -05:00
cmd . Var ( opts . NewNamedListOptsRef ( "storage-opts" , & config . GraphOptions , nil ) , [ ] string { "-storage-opt" } , usageFn ( "Set storage driver options" ) )
cmd . Var ( opts . NewNamedListOptsRef ( "authorization-plugins" , & config . AuthorizationPlugins , nil ) , [ ] string { "-authorization-plugin" } , usageFn ( "List authorization plugins in order from first evaluator to last" ) )
cmd . Var ( opts . NewNamedListOptsRef ( "exec-opts" , & config . ExecOptions , nil ) , [ ] string { "-exec-opt" } , usageFn ( "Set exec driver options" ) )
2015-05-05 00:18:28 -04:00
cmd . StringVar ( & config . Pidfile , [ ] string { "p" , "-pidfile" } , defaultPidFile , usageFn ( "Path to use for daemon PID file" ) )
cmd . StringVar ( & config . Root , [ ] string { "g" , "-graph" } , defaultGraph , usageFn ( "Root of the Docker runtime" ) )
cmd . StringVar ( & config . ExecRoot , [ ] string { "-exec-root" } , "/var/run/docker" , usageFn ( "Root of the Docker execdriver" ) )
cmd . BoolVar ( & config . AutoRestart , [ ] string { "#r" , "#-restart" } , true , usageFn ( "--restart on the daemon has been deprecated in favor of --restart policies on docker run" ) )
cmd . StringVar ( & config . GraphDriver , [ ] string { "s" , "-storage-driver" } , "" , usageFn ( "Storage driver to use" ) )
cmd . IntVar ( & config . Mtu , [ ] string { "#mtu" , "-mtu" } , 0 , usageFn ( "Set the containers network MTU" ) )
2014-08-10 01:18:32 +00:00
// FIXME: why the inconsistency between "hosts" and "sockets"?
2015-07-30 14:01:53 -07:00
cmd . Var ( opts . NewListOptsRef ( & config . DNS , opts . ValidateIPAddress ) , [ ] string { "#dns" , "-dns" } , usageFn ( "DNS server to use" ) )
2015-12-10 18:35:10 -05:00
cmd . Var ( opts . NewNamedListOptsRef ( "dns-opts" , & config . DNSOptions , nil ) , [ ] string { "-dns-opt" } , usageFn ( "DNS options to use" ) )
2015-07-30 14:01:53 -07:00
cmd . Var ( opts . NewListOptsRef ( & config . DNSSearch , opts . ValidateDNSSearch ) , [ ] string { "-dns-search" } , usageFn ( "DNS search domains to use" ) )
2015-12-10 18:35:10 -05:00
cmd . Var ( opts . NewNamedListOptsRef ( "labels" , & config . Labels , opts . ValidateLabel ) , [ ] string { "-label" } , usageFn ( "Set key=value labels to the daemon" ) )
2015-05-05 00:18:28 -04:00
cmd . StringVar ( & config . LogConfig . Type , [ ] string { "-log-driver" } , "json-file" , usageFn ( "Default driver for container logs" ) )
2015-12-10 18:35:10 -05:00
cmd . Var ( opts . NewNamedMapOpts ( "log-opts" , config . LogConfig . Config , nil ) , [ ] string { "-log-opt" } , usageFn ( "Set log driver options" ) )
2015-10-25 17:12:22 -07:00
cmd . StringVar ( & config . ClusterAdvertise , [ ] string { "-cluster-advertise" } , "" , usageFn ( "Address or interface name to advertise" ) )
2015-09-10 16:12:00 -07:00
cmd . StringVar ( & config . ClusterStore , [ ] string { "-cluster-store" } , "" , usageFn ( "Set the cluster store" ) )
2015-12-10 18:35:10 -05:00
cmd . Var ( opts . NewNamedMapOpts ( "cluster-store-opts" , config . ClusterOpts , nil ) , [ ] string { "-cluster-store-opt" } , usageFn ( "Set cluster store options" ) )
}
func parseClusterAdvertiseSettings ( clusterStore , clusterAdvertise string ) ( string , error ) {
if clusterAdvertise == "" {
return "" , errDiscoveryDisabled
}
if clusterStore == "" {
return "" , fmt . Errorf ( "invalid cluster configuration. --cluster-advertise must be accompanied by --cluster-store configuration" )
}
advertise , err := discovery . ParseAdvertise ( clusterAdvertise )
if err != nil {
return "" , fmt . Errorf ( "discovery advertise parsing failed (%v)" , err )
}
return advertise , nil
}
// ReloadConfiguration reads the configuration in the host and reloads the daemon and server.
func ReloadConfiguration ( configFile string , flags * flag . FlagSet , reload func ( * Config ) ) {
logrus . Infof ( "Got signal to reload configuration, reloading from: %s" , configFile )
newConfig , err := getConflictFreeConfiguration ( configFile , flags )
if err != nil {
logrus . Error ( err )
} else {
reload ( newConfig )
}
}
// MergeDaemonConfigurations reads a configuration file,
// loads the file configuration in an isolated structure,
// and merges the configuration provided from flags on top
// if there are no conflicts.
func MergeDaemonConfigurations ( flagsConfig * Config , flags * flag . FlagSet , configFile string ) ( * Config , error ) {
fileConfig , err := getConflictFreeConfiguration ( configFile , flags )
if err != nil {
return nil , err
}
// merge flags configuration on top of the file configuration
if err := mergo . Merge ( fileConfig , flagsConfig ) ; err != nil {
return nil , err
}
return fileConfig , nil
}
// getConflictFreeConfiguration loads the configuration from a JSON file.
// It compares that configuration with the one provided by the flags,
// and returns an error if there are conflicts.
func getConflictFreeConfiguration ( configFile string , flags * flag . FlagSet ) ( * Config , error ) {
b , err := ioutil . ReadFile ( configFile )
if err != nil {
return nil , err
}
var reader io . Reader
if flags != nil {
var jsonConfig map [ string ] interface { }
reader = bytes . NewReader ( b )
if err := json . NewDecoder ( reader ) . Decode ( & jsonConfig ) ; err != nil {
return nil , err
}
if err := findConfigurationConflicts ( jsonConfig , flags ) ; err != nil {
return nil , err
}
}
var config Config
reader = bytes . NewReader ( b )
err = json . NewDecoder ( reader ) . Decode ( & config )
return & config , err
}
// findConfigurationConflicts iterates over the provided flags searching for
// duplicated configurations. It returns an error with all the conflicts if
// it finds any.
func findConfigurationConflicts ( config map [ string ] interface { } , flags * flag . FlagSet ) error {
var conflicts [ ] string
flatten := make ( map [ string ] interface { } )
for k , v := range config {
if m , ok := v . ( map [ string ] interface { } ) ; ok {
for km , vm := range m {
flatten [ km ] = vm
}
} else {
flatten [ k ] = v
}
}
printConflict := func ( name string , flagValue , fileValue interface { } ) string {
return fmt . Sprintf ( "%s: (from flag: %v, from file: %v)" , name , flagValue , fileValue )
}
collectConflicts := func ( f * flag . Flag ) {
// search option name in the json configuration payload if the value is a named option
if namedOption , ok := f . Value . ( opts . NamedOption ) ; ok {
if optsValue , ok := flatten [ namedOption . Name ( ) ] ; ok {
conflicts = append ( conflicts , printConflict ( namedOption . Name ( ) , f . Value . String ( ) , optsValue ) )
}
} else {
// search flag name in the json configuration payload without trailing dashes
for _ , name := range f . Names {
name = strings . TrimLeft ( name , "-" )
if value , ok := flatten [ name ] ; ok {
conflicts = append ( conflicts , printConflict ( name , f . Value . String ( ) , value ) )
break
}
}
}
}
flags . Visit ( collectConflicts )
if len ( conflicts ) > 0 {
return fmt . Errorf ( "the following directives are specified both as a flag and in the configuration file: %s" , strings . Join ( conflicts , ", " ) )
}
return nil
2014-08-10 01:18:32 +00:00
}