func load(filename string, opener func(filename string) (jsonconfig.File, error)) (*Config, error) { c := osutil.NewJSONConfigParser() c.Open = opener m, err := c.ReadFile(filename) if err != nil { return nil, err } obj := jsonconfig.Obj(m) conf := &Config{ Obj: obj, } if lowLevel := obj.OptionalBool("handlerConfig", false); lowLevel { return conf, nil } // Check whether the high-level config uses the old names. if err := detectConfigChange(obj); err != nil { return nil, err } // Because the original high-level config might have expanded // through the use of functions, we re-encode the map back to // JSON here so we can unmarshal it into the hiLevelConf // struct later. highExpandedJSON, err := json.Marshal(m) if err != nil { return nil, fmt.Errorf("Can't re-marshal high-level JSON config: %v", err) } var hiLevelConf serverconfig.Config if err := json.Unmarshal(highExpandedJSON, &hiLevelConf); err != nil { return nil, fmt.Errorf("Could not unmarshal into a serverconfig.Config: %v", err) } conf, err = genLowLevelConfig(&hiLevelConf) if err != nil { return nil, fmt.Errorf( "failed to transform user config file into internal handler configuration: %v", err) } if v, _ := strconv.ParseBool(os.Getenv("CAMLI_DEBUG_CONFIG")); v { jsconf, _ := json.MarshalIndent(conf.Obj, "", " ") log.Printf("From high-level config, generated low-level config: %s", jsconf) } return conf, nil }
func buildStorageForReceive(ld blobserver.Loader, confOrString interface{}) (storageFunc, error) { // Static configuration from a string if s, ok := confOrString.(string); ok { sto, err := ld.GetStorage(s) if err != nil { return nil, err } f := func(br blob.Ref, src io.Reader) (blobserver.Storage, io.Reader, error) { return sto, src, nil } return f, nil } conf := jsonconfig.Obj(confOrString.(map[string]interface{})) ifStr := conf.RequiredString("if") // TODO: let 'then' and 'else' point to not just strings but either // a string or a JSON object with another condition, and then // call buildStorageForReceive on it recursively thenTarget := conf.RequiredString("then") elseTarget := conf.RequiredString("else") if err := conf.Validate(); err != nil { return nil, err } thenSto, err := ld.GetStorage(thenTarget) if err != nil { return nil, err } elseSto, err := ld.GetStorage(elseTarget) if err != nil { return nil, err } switch ifStr { case "isSchema": return isSchemaPicker(thenSto, elseSto), nil } return nil, fmt.Errorf("cond: unsupported 'if' type of %q", ifStr) }
// lazy config parsing when there's a known client already. // The client c may be nil. func (c *Client) parseConfig() { if android.OnAndroid() { panic("parseConfig should never have been called on Android") } if configDisabled { panic("parseConfig should never have been called with CAMLI_DISABLE_CLIENT_CONFIG_FILE set") } configPath := osutil.UserClientConfigPath() if _, err := wkfs.Stat(configPath); os.IsNotExist(err) { if c != nil && c.isSharePrefix { return } errMsg := fmt.Sprintf("Client configuration file %v does not exist. See 'camput init' to generate it.", configPath) if keyId := serverKeyId(); keyId != "" { hint := fmt.Sprintf("\nThe key id %v was found in the server config %v, so you might want:\n'camput init -gpgkey %v'", keyId, osutil.UserServerConfigPath(), keyId) errMsg += hint } log.Fatal(errMsg) } // TODO: instead of using jsonconfig, we could read the file, and unmarshall into the structs that we now have in pkg/types/clientconfig. But we'll have to add the old fields (before the name changes, and before the multi-servers change) to the structs as well for our gracefull conversion/error messages to work. conf, err := osutil.NewJSONConfigParser().ReadFile(configPath) if err != nil { log.Fatal(err.Error()) } cfg := jsonconfig.Obj(conf) if singleServerAuth := cfg.OptionalString("auth", ""); singleServerAuth != "" { newConf, err := convertToMultiServers(cfg) if err != nil { log.Print(err) } else { cfg = newConf } } config = &clientconfig.Config{ Identity: cfg.OptionalString("identity", ""), IdentitySecretRing: cfg.OptionalString("identitySecretRing", ""), IgnoredFiles: cfg.OptionalList("ignoredFiles"), } serversList := make(map[string]*clientconfig.Server) servers := cfg.OptionalObject("servers") for alias, vei := range servers { // An alias should never be confused with a host name, // so we forbid anything looking like one. if isURLOrHostPort(alias) { log.Fatalf("Server alias %q looks like a hostname; \".\" or \";\" are not allowed.", alias) } serverMap, ok := vei.(map[string]interface{}) if !ok { log.Fatalf("entry %q in servers section is a %T, want an object", alias, vei) } serverConf := jsonconfig.Obj(serverMap) server := &clientconfig.Server{ Server: cleanServer(serverConf.OptionalString("server", "")), Auth: serverConf.OptionalString("auth", ""), IsDefault: serverConf.OptionalBool("default", false), TrustedCerts: serverConf.OptionalList("trustedCerts"), } if err := serverConf.Validate(); err != nil { log.Fatalf("Error in servers section of config file for server %q: %v", alias, err) } serversList[alias] = server } config.Servers = serversList if err := cfg.Validate(); err != nil { printConfigChangeHelp(cfg) log.Fatalf("Error in config file: %v", err) } }
func (c *reindexdpCmd) RunCommand(args []string) error { var path string var indexConf jsonconfig.Obj switch len(args) { case 0: case 1: path = args[0] default: return errors.New("More than 1 argument not allowed") } cfg, err := serverinit.LoadFile(osutil.UserServerConfigPath()) if err != nil { return err } prefixes, ok := cfg.Obj["prefixes"].(map[string]interface{}) if !ok { return fmt.Errorf("No 'prefixes' object in low-level (or converted) config file %s", osutil.UserServerConfigPath()) } paths, confs := []string{}, []jsonconfig.Obj{} for prefix, vei := range prefixes { pmap, ok := vei.(map[string]interface{}) if !ok { log.Printf("prefix %q value is a %T, not an object", prefix, vei) continue } pconf := jsonconfig.Obj(pmap) handlerType := pconf.RequiredString("handler") handlerArgs := pconf.OptionalObject("handlerArgs") // no pconf.Validate, as this is a recover tool if handlerType != "storage-diskpacked" { continue } log.Printf("handlerArgs of %q: %v", prefix, handlerArgs) if handlerArgs == nil { log.Printf("no handlerArgs for %q", prefix) continue } aconf := jsonconfig.Obj(handlerArgs) apath := aconf.RequiredString("path") // no aconv.Validate, as this is a recover tool if apath == "" { log.Printf("path is missing for %q", prefix) continue } if path != "" && path != apath { continue } paths = append(paths, apath) confs = append(confs, aconf) } if len(paths) == 0 { return fmt.Errorf("Server config file %s doesn't specify a disk-packed storage handler.", osutil.UserServerConfigPath()) } if len(paths) > 1 { return fmt.Errorf("Ambiguity. Server config file %s d specify more than 1 disk-packed storage handler. Please specify one of: %v", osutil.UserServerConfigPath(), paths) } path = paths[0] if path == "" { return errors.New("no path is given/found") } // If no index is specified, the default will be used (as on the regular path). if mi := confs[0]["metaIndex"]; mi != nil { if mi, ok := mi.(map[string]interface{}); ok { indexConf = jsonconfig.Obj(mi) } } log.Printf("indexConf: %v", indexConf) return diskpacked.Reindex(path, c.overwrite, indexConf) }
// InstallHandlers creates and registers all the HTTP Handlers needed by config // into the provided HandlerInstaller. // // baseURL is required and specifies the root of this webserver, without trailing slash. // context may be nil (used and required by App Engine only) // // The returned shutdown value can be used to cleanly shut down the // handlers. func (config *Config) InstallHandlers(hi HandlerInstaller, baseURL string, reindex bool, context *http.Request) (shutdown io.Closer, err error) { defer func() { if e := recover(); e != nil { log.Printf("Caught panic installer handlers: %v", e) err = fmt.Errorf("Caught panic: %v", e) } }() if err := config.checkValidAuth(); err != nil { return nil, fmt.Errorf("error while configuring auth: %v", err) } prefixes := config.RequiredObject("prefixes") if err := config.Validate(); err != nil { return nil, fmt.Errorf("configuration error in root object's keys: %v", err) } if v := os.Getenv("CAMLI_PPROF_START"); v != "" { cpuf := mustCreate(v + ".cpu") defer cpuf.Close() memf := mustCreate(v + ".mem") defer memf.Close() rpprof.StartCPUProfile(cpuf) defer rpprof.StopCPUProfile() defer rpprof.WriteHeapProfile(memf) } hl := &handlerLoader{ installer: hi, baseURL: baseURL, config: make(map[string]*handlerConfig), handler: make(map[string]interface{}), context: context, reindex: reindex, } for prefix, vei := range prefixes { if !strings.HasPrefix(prefix, "/") { exitFailure("prefix %q doesn't start with /", prefix) } if !strings.HasSuffix(prefix, "/") { exitFailure("prefix %q doesn't end with /", prefix) } pmap, ok := vei.(map[string]interface{}) if !ok { exitFailure("prefix %q value is a %T, not an object", prefix, vei) } pconf := jsonconfig.Obj(pmap) enabled := pconf.OptionalBool("enabled", true) if !enabled { continue } handlerType := pconf.RequiredString("handler") handlerArgs := pconf.OptionalObject("handlerArgs") internal := pconf.OptionalBool("internal", false) if err := pconf.Validate(); err != nil { exitFailure("configuration error in prefix %s: %v", prefix, err) } h := &handlerConfig{ prefix: prefix, htype: handlerType, conf: handlerArgs, internal: internal, } hl.config[prefix] = h if handlerType == "ui" { config.UIPath = prefix } } hl.setupAll() // Now that everything is setup, run any handlers' InitHandler // methods. // And register apps that will be started later. for pfx, handler := range hl.handler { if starter, ok := handler.(*app.Handler); ok { config.apps = append(config.apps, starter) } if helpHandler, ok := handler.(*server.HelpHandler); ok { helpHandler.SetServerConfig(config.Obj) } if in, ok := handler.(blobserver.HandlerIniter); ok { if err := in.InitHandler(hl); err != nil { return nil, fmt.Errorf("Error calling InitHandler on %s: %v", pfx, err) } } } if v, _ := strconv.ParseBool(os.Getenv("CAMLI_HTTP_EXPVAR")); v { hi.Handle("/debug/vars", expvarHandler{}) } if v, _ := strconv.ParseBool(os.Getenv("CAMLI_HTTP_PPROF")); v { hi.Handle("/debug/pprof/", profileHandler{}) } hi.Handle("/debug/config", auth.RequireAuth(configHandler{config}, auth.OpAll)) hi.Handle("/debug/logs/", auth.RequireAuth(http.HandlerFunc(logsHandler), auth.OpAll)) return multiCloser(hl.closers), nil }