+ }
+
+ // Preprocess/automate some configs
+ for id, cc := range cfg.Clusters {
+ ldr.autofillPreemptible("Clusters."+id, &cc)
+
+ if strings.Count(cc.Users.AnonymousUserToken, "/") == 3 {
+ // V2 token, strip it to just a secret
+ tmp := strings.Split(cc.Users.AnonymousUserToken, "/")
+ cc.Users.AnonymousUserToken = tmp[2]
+ }
+
+ cfg.Clusters[id] = cc
+ }
+
+ // Check for known mistakes
+ for id, cc := range cfg.Clusters {
+ for remote := range cc.RemoteClusters {
+ if remote == "*" || remote == "SAMPLE" {
+ continue
+ }
+ err = ldr.checkClusterID(fmt.Sprintf("Clusters.%s.RemoteClusters.%s", id, remote), remote, true)
+ if err != nil {
+ return nil, err
+ }
+ }
+ 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, true, false),
+ ldr.checkToken(fmt.Sprintf("Clusters.%s.SystemRootToken", id), cc.SystemRootToken, true, false),
+ ldr.checkToken(fmt.Sprintf("Clusters.%s.Users.AnonymousUserToken", id), cc.Users.AnonymousUserToken, false, true),
+ ldr.checkToken(fmt.Sprintf("Clusters.%s.Collections.BlobSigningKey", id), cc.Collections.BlobSigningKey, true, false),
+ 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.checkLocalKeepBlobBuffers(cc),
+ ldr.checkStorageClasses(cc),
+ ldr.checkCUDAVersions(cc),
+ // TODO: check non-empty Rendezvous on
+ // services other than Keepstore