Hyperledger Fabric (2) - Design of Config configuration module for source code analysis

1. Background

For an excellent blockchain open source project, the reading of configuration parameters is essential. Generally speaking, the project will be developed based on the existing configuration reading framework.

This article mainly explores the configuration reading principle of Fabric from the perspective of source code.

2. Find the relevant code

From the article Hyperledger Fabric (1) - overall architecture and source code structure,/fabric/core it can be seen that the directory is the core code area of ​​the project, so start from here to find out whether the reading module of the configuration parameters is in it.

Sure enough, /fabric/core/configthe directory is the configuration code. Checking /fabric/core/config/config.gothe code content shows that the configuration system of Fabric mainly uses the third-party package viper .

viperIt can read and set system environment variables, configuration files in yaml/json format and even remote configuration, and can dynamically set the value of new configuration items and make them take effect in real time without restarting the service. It is a solution specially dealing with configuration, with the title of Cobra, and the library of the command line cobracomes from the same developer spfl3.

3. Source code analysis

3.1 Read configuration file main module

The amount of code in /fabric/core/config/config.gois not much, mainly depends on InitViperthe function, see the following Chinese comments for details

func InitViper(v *viper.Viper, configName string) error {
    
    
	var altPath = os.Getenv("FABRIC_CFG_PATH")
	// 首先判断环境变量 FABRIC_CFG_PATH 是否有值, 如果有值说明是用户人为定义FABRIC 配置文件的路径
	if altPath != "" {
    
    
		// If the user has overridden the path with an envvar, its the only path
		// we will consider
		//判断路径是否存在
		if !dirExists(altPath) {
    
    
			return fmt.Errorf("FABRIC_CFG_PATH %s does not exist", altPath)
		}
		//如果路径存在,将FABRIC_CFG_PATH 内容添加作为配置文件的路径
		AddConfigPath(v, altPath)
	/*若没有定义该环境变量的值 ,则用代码添加两个路径作为搜索配置文件的路径
		1.首先将当前路径作为搜索配置文件的路径
		2.如果OfficialPath = "/etc/hyperledger/fabric"存在,则使用此路径作为搜索配置文件的路径
	*/
	} else {
    
    
		// If we get here, we should use the default paths in priority order:
		//
		// *) CWD
		// *) /etc/hyperledger/fabric

		// CWD
		AddConfigPath(v, "./")

		// And finally, the official path
		if dirExists(OfficialPath) {
    
    
			AddConfigPath(v, OfficialPath)
		}
	}

	/*调用 SetConfigName()设置配置文件名,
	  所指的的配置文件名 configName 是由参数传递进来的*/
	// Now set the configuration file.
	if v != nil {
    
    
		v.SetConfigName(configName)
	} else {
    
    
		viper.SetConfigName(configName)
	}

	return nil
}

Another thing to note is InitViperthe first parameter *viper.Viper. In InitViperthe function, whether it is adding a search path (using AddConfigPaththe function), or setting the configuration file name (function) to be searched SetConfigName, it is divided into a global viper and a specific viper (that is, the parameters are finally completed by viper.AddConfigPathand viper. SetConfigNameare global; By v.AddConfigPathand v.SetConfigNamedone are specific.

This makes it easy to initialize modules that need to use viper alone. The modules that will be analyzed in the next article ordererare configured using a separate viper.

3.2 peer command search path and configuration file

/fabric/cmdFrom the point of view of the command mode, there is a high probability that it is the command startup code of the project theme or tool. From this entry, you can find /fabric/cmd/peer/main.gothe file. The code is as follows. For details, see the following Chinese notes

// The main command describes the service and
// defaults to printing the help message.
var mainCmd = &cobra.Command{
    
    Use: "peer"}

func main() {
    
    
	// For environment variables.
	//通过viper设置前缀为 common.CmdRoot = "core"环境变量前缀名
	viper.SetEnvPrefix(common.CmdRoot)
	//通过viper获取所有的环境变量,如果设置过了前缀则会自动补全前缀名
	viper.AutomaticEnv()
	replacer := strings.NewReplacer(".", "_")
	viper.SetEnvKeyReplacer(replacer)

	// Define command-line flags that are valid for all peer commands and
	// subcommands.
	mainFlags := mainCmd.PersistentFlags()

	mainFlags.String("logging-level", "", "Legacy logging level flag")
	viper.BindPFlag("logging_level", mainFlags.Lookup("logging-level"))
	mainFlags.MarkHidden("logging-level")

	cryptoProvider := factory.GetDefault()

	mainCmd.AddCommand(version.Cmd())
	mainCmd.AddCommand(node.Cmd())
	mainCmd.AddCommand(chaincode.Cmd(nil, cryptoProvider))
	mainCmd.AddCommand(channel.Cmd(nil))
	mainCmd.AddCommand(lifecycle.Cmd(cryptoProvider))

	// On failure Cobra prints the usage message and error string, so we only
	// need to exit with a non-0 status
	if mainCmd.Execute() != nil {
    
    
		os.Exit(1)
	}
}

3.3 How the orderer command searches and reads configuration files

Similarly, if you look at /fabric/cmd/orderer/main.gothe file, see the following Chinese notes for details

// Main is the entry point of orderer process
func Main() {
    
    
	fullCmd := kingpin.MustParse(app.Parse(os.Args[1:]))

	// "version" command
	if fullCmd == version.FullCommand() {
    
    
		fmt.Println(metadata.GetVersionInfo())
		return
	}
	//配置文件加载入口
	conf, err := localconfig.Load()
	if err != nil {
    
    
		logger.Error("failed to parse config: ", err)
		os.Exit(1)
	}
	initializeLogging()

	prettyPrintStruct(conf)

/fabric/orderer/common/loadconfig/config.go, see the following Chinese notes for details

// Load parses the orderer YAML file and environment, producing
// a struct suitable for config use, returning error on failure.
func Load() (*TopLevel, error) {
    
    
	//新建独立的viper
	config := viper.New()
	//调用 InitViper函数,configName 为配置文件名`orderer`
	coreconfig.InitViper(config, "orderer")  //`coreconfig`包就是`/fabric/core/config`包
	//通过viper设置前缀为 Prefix = "ORDERER"环境变量前缀名
	config.SetEnvPrefix(Prefix)
	//通过viper获取所有的环境变量,如果设置过了前缀则会自动补全前缀名
	config.AutomaticEnv()
	replacer := strings.NewReplacer(".", "_")
	config.SetEnvKeyReplacer(replacer)
	//读取配置文件
	if err := config.ReadInConfig(); err != nil {
    
    
		return nil, fmt.Errorf("Error reading configuration: %s", err)
	}

	var uconf TopLevel
	if err := viperutil.EnhancedExactUnmarshal(config, &uconf); err != nil {
    
    
		return nil, fmt.Errorf("Error unmarshaling config into struct: %s", err)
	}

	uconf.completeInitialization(filepath.Dir(config.ConfigFileUsed()))
	return &uconf, nil
}

4. Continue to analyze other modules from the source code

Please see below
Hyperledger Fabric (3) - Peer startup process for source code analysis

Guess you like

Origin blog.csdn.net/u010159567/article/details/105548285