mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #43509 from thaJeztah/daemon_fix_hosts_validation_step1a
cmd/dockerd: improve validation to allow early exit
This commit is contained in:
commit
2b1dcf4cbf
7 changed files with 123 additions and 83 deletions
|
@ -8,6 +8,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -75,7 +76,7 @@ func NewDaemonCli() *DaemonCli {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *DaemonCli) start(opts *daemonOptions) (err error) {
|
func (cli *DaemonCli) start(opts *daemonOptions) (err error) {
|
||||||
opts.SetDefaultOptions(opts.flags)
|
opts.setDefaultOptions()
|
||||||
|
|
||||||
if cli.Config, err = loadDaemonCliConfig(opts); err != nil {
|
if cli.Config, err = loadDaemonCliConfig(opts); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -84,6 +85,11 @@ func (cli *DaemonCli) start(opts *daemonOptions) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serverConfig, err := newAPIServerConfig(cli.Config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if opts.Validate {
|
if opts.Validate {
|
||||||
// If config wasn't OK we wouldn't have made it this far.
|
// If config wasn't OK we wouldn't have made it this far.
|
||||||
fmt.Fprintln(os.Stderr, "configuration OK")
|
fmt.Fprintln(os.Stderr, "configuration OK")
|
||||||
|
@ -91,10 +97,7 @@ func (cli *DaemonCli) start(opts *daemonOptions) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
configureProxyEnv(cli.Config)
|
configureProxyEnv(cli.Config)
|
||||||
|
configureDaemonLogs(cli.Config)
|
||||||
if err := configureDaemonLogs(cli.Config); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Info("Starting up")
|
logrus.Info("Starting up")
|
||||||
|
|
||||||
|
@ -161,10 +164,6 @@ func (cli *DaemonCli) start(opts *daemonOptions) (err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
serverConfig, err := newAPIServerConfig(cli)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to create API server")
|
|
||||||
}
|
|
||||||
cli.api = apiserver.New(serverConfig)
|
cli.api = apiserver.New(serverConfig)
|
||||||
|
|
||||||
hosts, err := loadListeners(cli, serverConfig)
|
hosts, err := loadListeners(cli, serverConfig)
|
||||||
|
@ -393,21 +392,26 @@ func loadDaemonCliConfig(opts *daemonOptions) (*config.Config, error) {
|
||||||
conf.Hosts = opts.Hosts
|
conf.Hosts = opts.Hosts
|
||||||
conf.LogLevel = opts.LogLevel
|
conf.LogLevel = opts.LogLevel
|
||||||
|
|
||||||
if opts.flags.Changed(FlagTLS) {
|
if flags.Changed("graph") && flags.Changed("data-root") {
|
||||||
|
return nil, errors.New(`cannot specify both "--graph" and "--data-root" option`)
|
||||||
|
}
|
||||||
|
if flags.Changed(FlagTLS) {
|
||||||
conf.TLS = &opts.TLS
|
conf.TLS = &opts.TLS
|
||||||
}
|
}
|
||||||
if opts.flags.Changed(FlagTLSVerify) {
|
if flags.Changed(FlagTLSVerify) {
|
||||||
conf.TLSVerify = &opts.TLSVerify
|
conf.TLSVerify = &opts.TLSVerify
|
||||||
v := true
|
v := true
|
||||||
conf.TLS = &v
|
conf.TLS = &v
|
||||||
}
|
}
|
||||||
|
|
||||||
conf.CommonTLSOptions = config.CommonTLSOptions{}
|
|
||||||
|
|
||||||
if opts.TLSOptions != nil {
|
if opts.TLSOptions != nil {
|
||||||
conf.CommonTLSOptions.CAFile = opts.TLSOptions.CAFile
|
conf.CommonTLSOptions = config.CommonTLSOptions{
|
||||||
conf.CommonTLSOptions.CertFile = opts.TLSOptions.CertFile
|
CAFile: opts.TLSOptions.CAFile,
|
||||||
conf.CommonTLSOptions.KeyFile = opts.TLSOptions.KeyFile
|
CertFile: opts.TLSOptions.CertFile,
|
||||||
|
KeyFile: opts.TLSOptions.KeyFile,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
conf.CommonTLSOptions = config.CommonTLSOptions{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if conf.TrustKeyPath == "" {
|
if conf.TrustKeyPath == "" {
|
||||||
|
@ -418,10 +422,6 @@ func loadDaemonCliConfig(opts *daemonOptions) (*config.Config, error) {
|
||||||
conf.TrustKeyPath = filepath.Join(daemonConfDir, defaultTrustKeyFile)
|
conf.TrustKeyPath = filepath.Join(daemonConfDir, defaultTrustKeyFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
if flags.Changed("graph") && flags.Changed("data-root") {
|
|
||||||
return nil, errors.New(`cannot specify both "--graph" and "--data-root" option`)
|
|
||||||
}
|
|
||||||
|
|
||||||
if opts.configFile != "" {
|
if opts.configFile != "" {
|
||||||
c, err := config.MergeDaemonConfigurations(conf, flags, opts.configFile)
|
c, err := config.MergeDaemonConfigurations(conf, flags, opts.configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -437,6 +437,10 @@ func loadDaemonCliConfig(opts *daemonOptions) (*config.Config, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := normalizeHosts(conf); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if err := config.Validate(conf); err != nil {
|
if err := config.Validate(conf); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -471,6 +475,41 @@ func loadDaemonCliConfig(opts *daemonOptions) (*config.Config, error) {
|
||||||
return conf, nil
|
return conf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// normalizeHosts normalizes the configured config.Hosts and remove duplicates.
|
||||||
|
// It returns an error if it fails to parse a host.
|
||||||
|
func normalizeHosts(config *config.Config) error {
|
||||||
|
if len(config.Hosts) == 0 {
|
||||||
|
// if no hosts are configured, create a single entry slice, so that the
|
||||||
|
// default is used.
|
||||||
|
//
|
||||||
|
// TODO(thaJeztah) implement a cleaner way for this; this depends on a
|
||||||
|
// side-effect of how we parse empty/partial hosts.
|
||||||
|
config.Hosts = make([]string, 1)
|
||||||
|
}
|
||||||
|
hosts := make([]string, 0, len(config.Hosts))
|
||||||
|
seen := make(map[string]struct{}, len(config.Hosts))
|
||||||
|
|
||||||
|
useTLS := DefaultTLSValue
|
||||||
|
if config.TLS != nil {
|
||||||
|
useTLS = *config.TLS
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, h := range config.Hosts {
|
||||||
|
host, err := dopts.ParseHost(useTLS, honorXDG, h)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, ok := seen[host]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[host] = struct{}{}
|
||||||
|
hosts = append(hosts, host)
|
||||||
|
}
|
||||||
|
sort.Strings(hosts)
|
||||||
|
config.Hosts = hosts
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func checkDeprecatedOptions(config *config.Config) error {
|
func checkDeprecatedOptions(config *config.Config) error {
|
||||||
// Overlay networks with external k/v stores have been deprecated
|
// Overlay networks with external k/v stores have been deprecated
|
||||||
if config.ClusterAdvertise != "" || len(config.ClusterOpts) > 0 || config.ClusterStore != "" {
|
if config.ClusterAdvertise != "" || len(config.ClusterOpts) > 0 || config.ClusterStore != "" {
|
||||||
|
@ -567,36 +606,32 @@ func (cli *DaemonCli) getContainerdDaemonOpts() ([]supervisor.DaemonOpt, error)
|
||||||
return opts, nil
|
return opts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAPIServerConfig(cli *DaemonCli) (*apiserver.Config, error) {
|
func newAPIServerConfig(config *config.Config) (*apiserver.Config, error) {
|
||||||
serverConfig := &apiserver.Config{
|
serverConfig := &apiserver.Config{
|
||||||
SocketGroup: cli.Config.SocketGroup,
|
SocketGroup: config.SocketGroup,
|
||||||
Version: dockerversion.Version,
|
Version: dockerversion.Version,
|
||||||
CorsHeaders: cli.Config.CorsHeaders,
|
CorsHeaders: config.CorsHeaders,
|
||||||
}
|
}
|
||||||
|
|
||||||
if cli.Config.TLS != nil && *cli.Config.TLS {
|
if config.TLS != nil && *config.TLS {
|
||||||
tlsOptions := tlsconfig.Options{
|
tlsOptions := tlsconfig.Options{
|
||||||
CAFile: cli.Config.CommonTLSOptions.CAFile,
|
CAFile: config.CommonTLSOptions.CAFile,
|
||||||
CertFile: cli.Config.CommonTLSOptions.CertFile,
|
CertFile: config.CommonTLSOptions.CertFile,
|
||||||
KeyFile: cli.Config.CommonTLSOptions.KeyFile,
|
KeyFile: config.CommonTLSOptions.KeyFile,
|
||||||
ExclusiveRootPools: true,
|
ExclusiveRootPools: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
if cli.Config.TLSVerify == nil || *cli.Config.TLSVerify {
|
if config.TLSVerify == nil || *config.TLSVerify {
|
||||||
// server requires and verifies client's certificate
|
// server requires and verifies client's certificate
|
||||||
tlsOptions.ClientAuth = tls.RequireAndVerifyClientCert
|
tlsOptions.ClientAuth = tls.RequireAndVerifyClientCert
|
||||||
}
|
}
|
||||||
tlsConfig, err := tlsconfig.Server(tlsOptions)
|
tlsConfig, err := tlsconfig.Server(tlsOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, errors.Wrap(err, "invalid TLS configuration")
|
||||||
}
|
}
|
||||||
serverConfig.TLSConfig = tlsConfig
|
serverConfig.TLSConfig = tlsConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(cli.Config.Hosts) == 0 {
|
|
||||||
cli.Config.Hosts = make([]string, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return serverConfig, nil
|
return serverConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -626,32 +661,19 @@ func checkTLSAuthOK(c *config.Config) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadListeners(cli *DaemonCli, serverConfig *apiserver.Config) ([]string, error) {
|
func loadListeners(cli *DaemonCli, serverConfig *apiserver.Config) ([]string, error) {
|
||||||
var hosts []string
|
if len(cli.Config.Hosts) == 0 {
|
||||||
seen := make(map[string]struct{}, len(cli.Config.Hosts))
|
return nil, errors.New("no hosts configured")
|
||||||
|
|
||||||
useTLS := DefaultTLSValue
|
|
||||||
if cli.Config.TLS != nil {
|
|
||||||
useTLS = *cli.Config.TLS
|
|
||||||
}
|
}
|
||||||
|
var hosts []string
|
||||||
|
|
||||||
for i := 0; i < len(cli.Config.Hosts); i++ {
|
for i := 0; i < len(cli.Config.Hosts); i++ {
|
||||||
var err error
|
|
||||||
if cli.Config.Hosts[i], err = dopts.ParseHost(useTLS, honorXDG, cli.Config.Hosts[i]); err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "error parsing -H %s", cli.Config.Hosts[i])
|
|
||||||
}
|
|
||||||
if _, ok := seen[cli.Config.Hosts[i]]; ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
seen[cli.Config.Hosts[i]] = struct{}{}
|
|
||||||
|
|
||||||
protoAddr := cli.Config.Hosts[i]
|
protoAddr := cli.Config.Hosts[i]
|
||||||
protoAddrParts := strings.SplitN(protoAddr, "://", 2)
|
protoAddrParts := strings.SplitN(cli.Config.Hosts[i], "://", 2)
|
||||||
if len(protoAddrParts) != 2 {
|
if len(protoAddrParts) != 2 {
|
||||||
return nil, fmt.Errorf("bad format %s, expected PROTO://ADDR", protoAddr)
|
return nil, fmt.Errorf("bad format %s, expected PROTO://ADDR", protoAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
proto := protoAddrParts[0]
|
proto, addr := protoAddrParts[0], protoAddrParts[1]
|
||||||
addr := protoAddrParts[1]
|
|
||||||
|
|
||||||
// It's a bad idea to bind to TCP without tlsverify.
|
// It's a bad idea to bind to TCP without tlsverify.
|
||||||
authEnabled := serverConfig.TLSConfig != nil && serverConfig.TLSConfig.ClientAuth == tls.RequireAndVerifyClientCert
|
authEnabled := serverConfig.TLSConfig != nil && serverConfig.TLSConfig.ClientAuth == tls.RequireAndVerifyClientCert
|
||||||
|
@ -764,14 +786,14 @@ func systemContainerdRunning(honorXDG bool) (string, bool, error) {
|
||||||
return addr, err == nil, nil
|
return addr, err == nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// configureDaemonLogs sets the logrus logging level and formatting
|
// configureDaemonLogs sets the logrus logging level and formatting. It expects
|
||||||
func configureDaemonLogs(conf *config.Config) error {
|
// the passed configuration to already be validated, and ignores invalid options.
|
||||||
|
func configureDaemonLogs(conf *config.Config) {
|
||||||
if conf.LogLevel != "" {
|
if conf.LogLevel != "" {
|
||||||
lvl, err := logrus.ParseLevel(conf.LogLevel)
|
lvl, err := logrus.ParseLevel(conf.LogLevel)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return fmt.Errorf("unable to parse logging level: %s", conf.LogLevel)
|
logrus.SetLevel(lvl)
|
||||||
}
|
}
|
||||||
logrus.SetLevel(lvl)
|
|
||||||
} else {
|
} else {
|
||||||
logrus.SetLevel(logrus.InfoLevel)
|
logrus.SetLevel(logrus.InfoLevel)
|
||||||
}
|
}
|
||||||
|
@ -780,7 +802,6 @@ func configureDaemonLogs(conf *config.Config) error {
|
||||||
DisableColors: conf.RawLogs,
|
DisableColors: conf.RawLogs,
|
||||||
FullTimestamp: true,
|
FullTimestamp: true,
|
||||||
})
|
})
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func configureProxyEnv(conf *config.Config) {
|
func configureProxyEnv(conf *config.Config) {
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
func defaultOptions(t *testing.T, configFile string) *daemonOptions {
|
func defaultOptions(t *testing.T, configFile string) *daemonOptions {
|
||||||
opts := newDaemonOptions(&config.Config{})
|
opts := newDaemonOptions(&config.Config{})
|
||||||
opts.flags = &pflag.FlagSet{}
|
opts.flags = &pflag.FlagSet{}
|
||||||
opts.InstallFlags(opts.flags)
|
opts.installFlags(opts.flags)
|
||||||
if err := installConfigFlags(opts.daemonConfig, opts.flags); err != nil {
|
if err := installConfigFlags(opts.daemonConfig, opts.flags); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -186,19 +186,15 @@ func TestLoadDaemonConfigWithRegistryOptions(t *testing.T) {
|
||||||
|
|
||||||
func TestConfigureDaemonLogs(t *testing.T) {
|
func TestConfigureDaemonLogs(t *testing.T) {
|
||||||
conf := &config.Config{}
|
conf := &config.Config{}
|
||||||
err := configureDaemonLogs(conf)
|
configureDaemonLogs(conf)
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Check(t, is.Equal(logrus.InfoLevel, logrus.GetLevel()))
|
assert.Check(t, is.Equal(logrus.InfoLevel, logrus.GetLevel()))
|
||||||
|
|
||||||
conf.LogLevel = "warn"
|
conf.LogLevel = "warn"
|
||||||
err = configureDaemonLogs(conf)
|
configureDaemonLogs(conf)
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Check(t, is.Equal(logrus.WarnLevel, logrus.GetLevel()))
|
assert.Check(t, is.Equal(logrus.WarnLevel, logrus.GetLevel()))
|
||||||
|
|
||||||
|
// log level should not be changed when passing an invalid value
|
||||||
conf.LogLevel = "foobar"
|
conf.LogLevel = "foobar"
|
||||||
err = configureDaemonLogs(conf)
|
configureDaemonLogs(conf)
|
||||||
assert.Error(t, err, "unable to parse logging level: foobar")
|
|
||||||
|
|
||||||
// log level should not be changed after a failure
|
|
||||||
assert.Check(t, is.Equal(logrus.WarnLevel, logrus.GetLevel()))
|
assert.Check(t, is.Equal(logrus.WarnLevel, logrus.GetLevel()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ func newDaemonCommand() (*cobra.Command, error) {
|
||||||
}
|
}
|
||||||
flags.StringVar(&opts.configFile, "config-file", defaultDaemonConfigFile, "Daemon configuration file")
|
flags.StringVar(&opts.configFile, "config-file", defaultDaemonConfigFile, "Daemon configuration file")
|
||||||
configureCertsDir()
|
configureCertsDir()
|
||||||
opts.InstallFlags(flags)
|
opts.installFlags(flags)
|
||||||
if err := installConfigFlags(opts.daemonConfig, flags); err != nil {
|
if err := installConfigFlags(opts.daemonConfig, flags); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,8 +51,8 @@ func newDaemonOptions(config *config.Config) *daemonOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstallFlags adds flags for the common options on the FlagSet
|
// installFlags adds flags for the common options on the FlagSet
|
||||||
func (o *daemonOptions) InstallFlags(flags *pflag.FlagSet) {
|
func (o *daemonOptions) installFlags(flags *pflag.FlagSet) {
|
||||||
if dockerCertPath == "" {
|
if dockerCertPath == "" {
|
||||||
// cliconfig.Dir returns $DOCKER_CONFIG or ~/.docker.
|
// cliconfig.Dir returns $DOCKER_CONFIG or ~/.docker.
|
||||||
// cliconfig.Dir does not look up $XDG_CONFIG_HOME
|
// cliconfig.Dir does not look up $XDG_CONFIG_HOME
|
||||||
|
@ -77,18 +77,18 @@ func (o *daemonOptions) InstallFlags(flags *pflag.FlagSet) {
|
||||||
flags.VarP(hostOpt, "host", "H", "Daemon socket(s) to connect to")
|
flags.VarP(hostOpt, "host", "H", "Daemon socket(s) to connect to")
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDefaultOptions sets default values for options after flag parsing is
|
// setDefaultOptions sets default values for options after flag parsing is
|
||||||
// complete
|
// complete
|
||||||
func (o *daemonOptions) SetDefaultOptions(flags *pflag.FlagSet) {
|
func (o *daemonOptions) setDefaultOptions() {
|
||||||
// Regardless of whether the user sets it to true or false, if they
|
// Regardless of whether the user sets it to true or false, if they
|
||||||
// specify --tlsverify at all then we need to turn on TLS
|
// specify --tlsverify at all then we need to turn on TLS
|
||||||
// TLSVerify can be true even if not set due to DOCKER_TLS_VERIFY env var, so we need
|
// TLSVerify can be true even if not set due to DOCKER_TLS_VERIFY env var, so we need
|
||||||
// to check that here as well
|
// to check that here as well
|
||||||
if flags.Changed(FlagTLSVerify) || o.TLSVerify {
|
if o.flags.Changed(FlagTLSVerify) || o.TLSVerify {
|
||||||
o.TLS = true
|
o.TLS = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.TLS && !flags.Changed(FlagTLSVerify) {
|
if o.TLS && !o.flags.Changed(FlagTLSVerify) {
|
||||||
// Enable tls verification unless explicitly disabled
|
// Enable tls verification unless explicitly disabled
|
||||||
o.TLSVerify = true
|
o.TLSVerify = true
|
||||||
}
|
}
|
||||||
|
@ -96,19 +96,18 @@ func (o *daemonOptions) SetDefaultOptions(flags *pflag.FlagSet) {
|
||||||
if !o.TLS {
|
if !o.TLS {
|
||||||
o.TLSOptions = nil
|
o.TLSOptions = nil
|
||||||
} else {
|
} else {
|
||||||
tlsOptions := o.TLSOptions
|
o.TLSOptions.InsecureSkipVerify = !o.TLSVerify
|
||||||
tlsOptions.InsecureSkipVerify = !o.TLSVerify
|
|
||||||
|
|
||||||
// Reset CertFile and KeyFile to empty string if the user did not specify
|
// Reset CertFile and KeyFile to empty string if the user did not specify
|
||||||
// the respective flags and the respective default files were not found.
|
// the respective flags and the respective default files were not found.
|
||||||
if !flags.Changed("tlscert") {
|
if !o.flags.Changed("tlscert") {
|
||||||
if _, err := os.Stat(tlsOptions.CertFile); os.IsNotExist(err) {
|
if _, err := os.Stat(o.TLSOptions.CertFile); os.IsNotExist(err) {
|
||||||
tlsOptions.CertFile = ""
|
o.TLSOptions.CertFile = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !flags.Changed("tlskey") {
|
if !o.flags.Changed("tlskey") {
|
||||||
if _, err := os.Stat(tlsOptions.KeyFile); os.IsNotExist(err) {
|
if _, err := os.Stat(o.TLSOptions.KeyFile); os.IsNotExist(err) {
|
||||||
tlsOptions.KeyFile = ""
|
o.TLSOptions.KeyFile = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
func TestCommonOptionsInstallFlags(t *testing.T) {
|
func TestCommonOptionsInstallFlags(t *testing.T) {
|
||||||
flags := pflag.NewFlagSet("testing", pflag.ContinueOnError)
|
flags := pflag.NewFlagSet("testing", pflag.ContinueOnError)
|
||||||
opts := newDaemonOptions(&config.Config{})
|
opts := newDaemonOptions(&config.Config{})
|
||||||
opts.InstallFlags(flags)
|
opts.installFlags(flags)
|
||||||
|
|
||||||
err := flags.Parse([]string{
|
err := flags.Parse([]string{
|
||||||
"--tlscacert=/foo/cafile",
|
"--tlscacert=/foo/cafile",
|
||||||
|
@ -34,7 +34,7 @@ func defaultPath(filename string) string {
|
||||||
func TestCommonOptionsInstallFlagsWithDefaults(t *testing.T) {
|
func TestCommonOptionsInstallFlagsWithDefaults(t *testing.T) {
|
||||||
flags := pflag.NewFlagSet("testing", pflag.ContinueOnError)
|
flags := pflag.NewFlagSet("testing", pflag.ContinueOnError)
|
||||||
opts := newDaemonOptions(&config.Config{})
|
opts := newDaemonOptions(&config.Config{})
|
||||||
opts.InstallFlags(flags)
|
opts.installFlags(flags)
|
||||||
|
|
||||||
err := flags.Parse([]string{})
|
err := flags.Parse([]string{})
|
||||||
assert.Check(t, err)
|
assert.Check(t, err)
|
||||||
|
|
|
@ -558,6 +558,13 @@ func findConfigurationConflicts(config map[string]interface{}, flags *pflag.Flag
|
||||||
// such as config.DNS, config.Labels, config.DNSSearch,
|
// such as config.DNS, config.Labels, config.DNSSearch,
|
||||||
// as well as config.MaxConcurrentDownloads, config.MaxConcurrentUploads and config.MaxDownloadAttempts.
|
// as well as config.MaxConcurrentDownloads, config.MaxConcurrentUploads and config.MaxDownloadAttempts.
|
||||||
func Validate(config *Config) error {
|
func Validate(config *Config) error {
|
||||||
|
// validate log-level
|
||||||
|
if config.LogLevel != "" {
|
||||||
|
if _, err := logrus.ParseLevel(config.LogLevel); err != nil {
|
||||||
|
return fmt.Errorf("invalid logging level: %s", config.LogLevel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// validate DNS
|
// validate DNS
|
||||||
for _, dns := range config.DNS {
|
for _, dns := range config.DNS {
|
||||||
if _, err := opts.ValidateIPAddress(dns); err != nil {
|
if _, err := opts.ValidateIPAddress(dns); err != nil {
|
||||||
|
|
|
@ -345,6 +345,15 @@ func TestValidateConfigurationErrors(t *testing.T) {
|
||||||
},
|
},
|
||||||
expectedErr: "invalid bind address (127.0.0.1:2375/path): should not contain a path element",
|
expectedErr: "invalid bind address (127.0.0.1:2375/path): should not contain a path element",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "with invalid log-level",
|
||||||
|
config: &Config{
|
||||||
|
CommonConfig: CommonConfig{
|
||||||
|
LogLevel: "foobar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedErr: "invalid logging level: foobar",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
@ -437,6 +446,14 @@ func TestValidateConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "with log-level warn",
|
||||||
|
config: &Config{
|
||||||
|
CommonConfig: CommonConfig{
|
||||||
|
LogLevel: "warn",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
|
Loading…
Reference in a new issue