Example #1
0
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
}
Example #2
0
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)
}
Example #3
0
// 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)
	}
}
Example #4
0
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)
}
Example #5
0
// 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
}