Fabric-ca client端初始化过程源码分析
本文从Fabric-ca源码入手,以newRegisterCommand()函数为例,简单分析client启动时的过程。Fabric-ca源码可以从github.com下载,本文以v1.4.6为例进行简单分析。
与server相似,本文也是从main.go开始:
// fabric-ca/cmd/fabric-ca-client/main.go
package main
import (
...
)
// The fabric-ca client main
func main() {
if err := command.RunMain(os.Args); err != nil {
os.Exit(1)
}
}
main()函数只是调用了package command中的RunMain()函数,所以接下来我们以RunMain()函数为起点来简析client端的启动过程,其中包括client端的初始化以及跟server端的初次交互:
// fabric-ca/cmd/fabric-ca-client/command/root.go
package command
import "os"
// RunMain is the fabric-ca client main
func RunMain(args []string) error {
// Save the os.Args
saveOsArgs := os.Args
os.Args = args
// Execute the command
cmdName := ""
if len(args) > 1 {
cmdName = args[1]
}
ccmd := NewCommand(cmdName)
err := ccmd.Execute()
// Restore original os.Args
os.Args = saveOsArgs
return err
}
不难看出,与server类似,都是先通过NewCommand()函数来添加命令,之后再通过Execute()来执行操作:
// fabric-ca/cmd/fabric-ca-client/command/clientcmd.go
// ClientCmd encapsulates cobra command that provides command line interface
// for the Fabric CA client and the configuration used by the Fabric CA client
type ClientCmd struct {
// name of the sub command
name string
// rootCmd is the base command for the Hyerledger Fabric CA client
rootCmd *cobra.Command
// My viper instance
myViper *viper.Viper
// cfgFileName is the name of the configuration file
cfgFileName string
// homeDirectory is the location of the client's home directory
homeDirectory string
// clientCfg is the client's configuration
clientCfg *lib.ClientConfig
// cfgAttrs are the attributes specified via flags or env variables
// and translated to Attributes field in registration
cfgAttrs []string
// cfgAttrReqs are the attribute requests specified via flags or env variables
// and translated to the AttrReqs field in enrollment
cfgAttrReqs []string
// cfgCsrNames are the certificate signing request names specified via flags
// or env variables
cfgCsrNames []string
// csrCommonName is the certificate signing request common name specified via the flag
csrCommonName string
// gencrl command argument values
crlParams crlArgs
// revoke command argument values
revokeParams revokeArgs
// profileMode is the profiling mode, cpu or mem or empty
profileMode string
// profileInst is the profiling instance object
profileInst interface {
Stop()
}
// Dynamically configuring identities
dynamicIdentity identityArgs
// Dynamically configuring affiliations
dynamicAffiliation affiliationArgs
// Set to log level
logLevel string
}
// NewCommand returns new ClientCmd ready for running
func NewCommand(name string) *ClientCmd {
c := &ClientCmd{
myViper: viper.New(),
}
c.name = strings.ToLower(name)
c.init()
return c
}
...
// init initializes the ClientCmd instance
// It intializes the cobra root and sub commands and
// registers command flgs with viper
func (c *ClientCmd) init() {
...
c.rootCmd.AddCommand(c.newRegisterCommand(),
newEnrollCmd(c).getCommand(),
c.newReenrollCommand(),
c.newRevokeCommand(),
newGetCAInfoCmd(c).getCommand(),
c.newGenCsrCommand(),
c.newGenCRLCommand(),
c.newIdentityCommand(),
c.newAffiliationCommand(),
createCertificateCommand(c))
c.rootCmd.AddCommand(&cobra.Command{
Use: "version",
Short: "Prints Fabric CA Client version",
Run: func(cmd *cobra.Command, args []string) {
fmt.Print(metadata.GetVersionInfo(cmdName))
},
})
c.registerFlags()
...
}
在NewCommand()函数中,创建了一个*ClientCmd的对象,之后,调用该对象的init()方法。在init()方法中,首先实例化了*ClientCmd.rootCmd,其中会要执行checkAndEnableProfiling()来检查运行环境:
// checkAndEnableProfiling checks for the FABRIC_CA_CLIENT_PROFILE_MODE
// env variable, if it is set to "cpu", cpu profiling is enbled;
// if it is set to "heap", heap profiling is enabled
func (c *ClientCmd) checkAndEnableProfiling() error {
...
}
// registerFlags registers command flags with viper
func (c *ClientCmd) registerFlags() {
...
}
之后会调用AddCommand()函数来添加newRegisterCommand()、newEnrollCmd(c).getCommand()、newReenrollCommand()、newRevokeCommand()、newGetCAInfoCmd(c).getCommand()、newGenCsrCommand()、newGenCRLCommand()、newIdentityCommand()、newAffiliationCommand()、createCertificateCommand()和获取client版本的命令。随后执行c.registerFlags()操作。registerFlags()函数中主要是注册一些命令行参数,这里就不细究了。
newRegisterCommand()
// fabric-ca/cmd/fabric-ca-client/command/register.go
func (c *ClientCmd) newRegisterCommand() *cobra.Command {
...
}
// The client register main logic
func (c *ClientCmd) runRegister() error {
...
}
在newRegisterCommand()函数中,实例化了一个*cobra.Command命令对象,该对象中包含两个命令:ConfigInit()和runRegister()。ConfigInit()命令是为fabric-ca-client命令初始化一些配置,这里不做说明,而runRegister()中包含客户端注册的主要逻辑:首先实例化一个lib.Client结构体,之后导入client端的身份凭证client.LoadMyIdentity(),随后发起注册*Identity.Register()。
// fabric-ca/lib/client.go
// Client is the fabric-ca client object
type Client struct {
// The client's home directory
HomeDir string `json:"homeDir,omitempty"`
// The client's configuration
Config *ClientConfig
// Denotes if the client object is already initialized
initialized bool
// File and directory paths
keyFile, certFile, idemixCredFile, idemixCredsDir, ipkFile, caCertsDir string
// The crypto service provider (BCCSP)
csp bccsp.BCCSP
// HTTP client associated with this Fabric CA client
httpClient *http.Client
// Public key of Idemix issuer
issuerPublicKey *idemix.IssuerPublicKey
}
// LoadMyIdentity loads the client's identity from disk
func (c *Client) LoadMyIdentity() (*Identity, error) {
...
return c.LoadIdentity(c.keyFile, c.certFile, c.idemixCredFile)
}
// LoadIdentity loads an identity from disk
func (c *Client) LoadIdentity(keyFile, certFile, idemixCredFile string) (*Identity, error) {
...
return c.NewIdentity(creds)
}
// NewIdentity creates a new identity
func (c *Client) NewIdentity(creds []credential.Credential) (*Identity, error) {
...
return NewIdentity(c, name, creds), nil
}
如上,在LoadMyIdentity()中会先调用Init()来初始化client,然后再调用LoadIdentity()函数,从硬盘中导入身份凭证。在LoadIdentity()中同样会调用Init()来初始化client,之后会调用NewCredential()接口来导入x509和idemin格式的证书。证书读取完成后,调用NewIdentity()来创建新的身份认证。至此,身份导入过程就完成了,接下来就是注册了。
//fabric-ca/lib/identity.go
// Register registers a new identity
// @param req The registration request
func (i *Identity) Register(req *api.RegistrationRequest) (rr *api.RegistrationResponse, err error) {
...
}
在Register(),会将认证请求序列后,通过Post请求发送给服务端,并将服务端的应答返回给调用者。
// Post sends arbitrary request body (reqBody) to an endpoint.
// This adds an authorization header which contains the signature
// of this identity over the body and non-signature part of the authorization header.
// The return value is the body of the response.
func (i *Identity) Post(endpoint string, reqBody []byte, result interface{}, queryParam map[string]string) error {
...
}
至此,注册命令就结束了。
Fabric-ca client端初始化过程源码分析的更多相关文章
- Bootstrap初始化过程源码分析--netty客户端的启动
Bootstrap初始化过程 netty的客户端引导类是Bootstrap,我们看一下spark的rpc中客户端部分对Bootstrap的初始化过程 TransportClientFactory.cr ...
- A2dp初始化流程源码分析
蓝牙启动的时候,会涉及到各个profile 的启动.这篇文章分析一下,蓝牙中a2dp profile的初始化流程. 我们从AdapterState.java中对于USER_TURN_ON 消息的处理说 ...
- A2dp sink 初始化流程源码分析
A2dp sink的初始化流程和A2dp 的初始化流程,基本一样,这里做简单分析.这里分析的android的版本是Android O. 我们先从service的启动说起吧. 下面 是启动的时候的log ...
- Netty入门一:服务端应用搭建 & 启动过程源码分析
最近周末也没啥事就学学Netty,同时打算写一些博客记录一下(写的过程理解更加深刻了) 本文主要从三个方法来呈现:Netty核心组件简介.Netty服务端创建.Netty启动过程源码分析 如果你对Ne ...
- SpringSecurity 初始化流程源码
SpringSecurity 初始化流程源码 本篇主要讲解 SpringSecurity初始化流程的源码部分,包括核心的 springSecurityFilterChain 是如何创建的,以及在介绍哪 ...
- Spark(五十一):Spark On YARN(Yarn-Cluster模式)启动流程源码分析(二)
上篇<Spark(四十九):Spark On YARN启动流程源码分析(一)>我们讲到启动SparkContext初始化,ApplicationMaster启动资源中,讲解的内容明显不完整 ...
- Dubbo消费方服务调用过程源码分析
参考:dubbo消费方服务调用过程源码分析dubbo基于spring的构建分析Dubbo概述--调用过程dubbo 请求调用过程分析dubbo集群容错机制代码分析1dubbo集群容错策略的代码分析2d ...
- [Android]从Launcher开始启动App流程源码分析
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5017056.html 从Launcher开始启动App流程源码 ...
- spark源码阅读--shuffle读过程源码分析
shuffle读过程源码分析 上一篇中,我们分析了shuffle在map阶段的写过程.简单回顾一下,主要是将ShuffleMapTask计算的结果数据在内存中按照分区和key进行排序,过程中由于内存限 ...
- Spark(四十九):Spark On YARN启动流程源码分析(一)
引导: 该篇章主要讲解执行spark-submit.sh提交到将任务提交给Yarn阶段代码分析. spark-submit的入口函数 一般提交一个spark作业的方式采用spark-submit来提交 ...
随机推荐
- 对话 BitSail Contributor | 刘啸:参与开源,提升自我技术力
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 2022 年 10 月,字节跳动 BitSail 数据引擎正式开源.同期,社区推出 Contributor 激励计 ...
- Typora 一行显示多图
图片下显示说明  <center style="font-siz ...
- loguru python中记录日志
loguru python中记录日志 安装 pip install loguru 使用 from loguru import logger # logger.add('ck/test_log.log' ...
- 基于rest_framework的ModelViewSet类编写登录视图和认证视图
背景:看了博主一抹浅笑的rest_framework认证模板,发现登录视图函数是基于APIView类封装. 优化:使用ModelViewSet类通过重写create方法编写登录函数. 环境:既然接触到 ...
- Codeforces Round #653 (Div. 3) 题解
记第一场CF赛,完成3道题 代码更新(降低时间复杂度和修改写法):21.1.23 A题 Required Remainder 题意:给你 x.y.n 求最大的k (k<=n) 使得k%x==y ...
- 理解 docker volume
1. docker volume 简介 文章 介绍了 docker image,它由一系列只读层构成,通过 docker image 可以提高镜像构建,存储和分发的效率,节省时间和存储空间.然而 do ...
- 针对docker中的mongo容器增加鉴权
1. 背景 业务方的服务器经安全检查,发现以docker容器启动的mongo未增加鉴权的漏洞,随优化之 2. 配置 mongo以docker compose方式启动,镜像的版本号为4.2.6,dock ...
- PR 调整时间线宽度
1.问题 这里的宽度太小,不好进行下一步的调整 2.解决方法 方法一 按下=可以放宽 按下-(=左边的那个键)可以缩小宽度 方法二 拖动下方的滑动条即可 方法三 按住ALT+滚轮,即可调节
- Oracledb_exporter 获取表大小信息的简单方法
Oracledb_exporter 获取表大小信息的简单方法 背景 用我儿子的现状作为背景: 我爱学习, 学习让我妈快乐. 下载exporter exporter 可以在github上面下载最新版本是 ...
- [转帖]redis缓存命中率介绍
缓存命中率的介绍 命中:可以直接通过缓存获取到需要的数据. 不命中:无法直接通过缓存获取到想要的数据,需要再次查询数据库或者执行其它的操作.原因可能是由于缓存中根本不存在,或者缓存已经过期. 通常来讲 ...