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/config
the directory is the configuration code. Checking /fabric/core/config/config.go
the code content shows that the configuration system of Fabric mainly uses the third-party package viper .
viper
It 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 cobra
comes 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.go
is not much, mainly depends on InitViper
the 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 InitViper
the first parameter *viper.Viper
. In InitViper
the function, whether it is adding a search path (using AddConfigPath
the 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.AddConfigPath
and viper. SetConfigName
are global; By v.AddConfigPath
and v.SetConfigName
done 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 orderer
are configured using a separate viper.
3.2 peer command search path and configuration file
/fabric/cmd
From 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.go
the 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.go
the 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