X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/66a089434f38163273c3a5b9138f9c4347873b69..053f74285455278bed87cd4b3dc0df2adffb3b9c:/lib/config/load.go diff --git a/lib/config/load.go b/lib/config/load.go index 956a47b1a4..418a400e62 100644 --- a/lib/config/load.go +++ b/lib/config/load.go @@ -6,6 +6,7 @@ package config import ( "bytes" + _ "embed" "encoding/json" "errors" "flag" @@ -14,6 +15,7 @@ import ( "io/ioutil" "os" "regexp" + "strconv" "strings" "git.arvados.org/arvados.git/sdk/go/arvados" @@ -22,6 +24,9 @@ import ( "github.com/sirupsen/logrus" ) +//go:embed config.default.yml +var DefaultYAML []byte + var ErrNoClustersDefined = errors.New("config does not define any clusters") type Loader struct { @@ -225,6 +230,9 @@ func (ldr *Loader) Load() (*arvados.Config, error) { } ldr.logExtraKeys(merged, src, "") removeSampleKeys(merged) + // We merge the loaded config into the default, overriding any existing keys. + // Make sure we do not override a default with a key that has a 'null' value. + removeNullKeys(src) err = mergo.Merge(&merged, src, mergo.WithOverride) if err != nil { return nil, fmt.Errorf("merging config data: %s", err) @@ -291,14 +299,16 @@ func (ldr *Loader) Load() (*arvados.Config, error) { for _, err = range []error{ ldr.checkClusterID(fmt.Sprintf("Clusters.%s", id), id, false), ldr.checkClusterID(fmt.Sprintf("Clusters.%s.Login.LoginCluster", id), cc.Login.LoginCluster, true), - ldr.checkToken(fmt.Sprintf("Clusters.%s.ManagementToken", id), cc.ManagementToken), - ldr.checkToken(fmt.Sprintf("Clusters.%s.SystemRootToken", id), cc.SystemRootToken), - ldr.checkToken(fmt.Sprintf("Clusters.%s.Collections.BlobSigningKey", id), cc.Collections.BlobSigningKey), + ldr.checkToken(fmt.Sprintf("Clusters.%s.ManagementToken", id), cc.ManagementToken, true), + ldr.checkToken(fmt.Sprintf("Clusters.%s.SystemRootToken", id), cc.SystemRootToken, true), + ldr.checkToken(fmt.Sprintf("Clusters.%s.Users.AnonymousUserToken", id), cc.Users.AnonymousUserToken, false), + ldr.checkToken(fmt.Sprintf("Clusters.%s.Collections.BlobSigningKey", id), cc.Collections.BlobSigningKey, true), checkKeyConflict(fmt.Sprintf("Clusters.%s.PostgreSQL.Connection", id), cc.PostgreSQL.Connection), ldr.checkEnum("Containers.LocalKeepLogsToContainerLog", cc.Containers.LocalKeepLogsToContainerLog, "none", "all", "errors"), ldr.checkEmptyKeepstores(cc), ldr.checkUnlistedKeepstores(cc), ldr.checkStorageClasses(cc), + ldr.checkCUDAVersions(cc), // TODO: check non-empty Rendezvous on // services other than Keepstore } { @@ -324,14 +334,15 @@ func (ldr *Loader) checkClusterID(label, clusterID string, emptyStringOk bool) e var acceptableTokenRe = regexp.MustCompile(`^[a-zA-Z0-9]+$`) var acceptableTokenLength = 32 -func (ldr *Loader) checkToken(label, token string) error { - if token == "" { +func (ldr *Loader) checkToken(label, token string, mandatory bool) error { + // when a token is not mandatory, the acceptable length and content is only checked if its length is non-zero + if mandatory && token == "" { if ldr.Logger != nil { ldr.Logger.Warnf("%s: secret token is not set (use %d+ random characters from a-z, A-Z, 0-9)", label, acceptableTokenLength) } - } else if !acceptableTokenRe.MatchString(token) { + } else if (mandatory || len(token) > 0) && !acceptableTokenRe.MatchString(token) { return fmt.Errorf("%s: unacceptable characters in token (only a-z, A-Z, 0-9 are acceptable)", label) - } else if len(token) < acceptableTokenLength { + } else if (mandatory || len(token) > 0) && len(token) < acceptableTokenLength { if ldr.Logger != nil { ldr.Logger.Warnf("%s: token is too short (should be at least %d characters)", label, acceptableTokenLength) } @@ -399,6 +410,24 @@ func (ldr *Loader) checkStorageClasses(cc arvados.Cluster) error { return nil } +func (ldr *Loader) checkCUDAVersions(cc arvados.Cluster) error { + for _, it := range cc.InstanceTypes { + if it.CUDA.DeviceCount == 0 { + continue + } + + _, err := strconv.ParseFloat(it.CUDA.DriverVersion, 64) + if err != nil { + return fmt.Errorf("InstanceType %q has invalid CUDA.DriverVersion %q, expected format X.Y (%v)", it.Name, it.CUDA.DriverVersion, err) + } + _, err = strconv.ParseFloat(it.CUDA.HardwareCapability, 64) + if err != nil { + return fmt.Errorf("InstanceType %q has invalid CUDA.HardwareCapability %q, expected format X.Y (%v)", it.Name, it.CUDA.HardwareCapability, err) + } + } + return nil +} + func checkKeyConflict(label string, m map[string]string) error { saw := map[string]bool{} for k := range m { @@ -411,6 +440,17 @@ func checkKeyConflict(label string, m map[string]string) error { return nil } +func removeNullKeys(m map[string]interface{}) { + for k, v := range m { + if v == nil { + delete(m, k) + } + if v, _ := v.(map[string]interface{}); v != nil { + removeNullKeys(v) + } + } +} + func removeSampleKeys(m map[string]interface{}) { delete(m, "SAMPLE") for _, v := range m {