gitee.com/zhaochuninhefei/fabric-ca-gm@v0.0.2/cmd/fabric-ca-client/command/clientcmd.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package command 8 9 import ( 10 "errors" 11 "fmt" 12 "os" 13 "path/filepath" 14 "strings" 15 16 "gitee.com/zhaochuninhefei/fabric-ca-gm/internal/pkg/util" 17 "gitee.com/zhaochuninhefei/fabric-ca-gm/lib" 18 "gitee.com/zhaochuninhefei/fabric-ca-gm/lib/metadata" 19 log "gitee.com/zhaochuninhefei/zcgolog/zclog" 20 "github.com/pkg/profile" 21 "github.com/spf13/cobra" 22 "github.com/spf13/viper" 23 ) 24 25 const ( 26 fabricCAClientProfileMode = "FABRIC_CA_CLIENT_PROFILE_MODE" 27 extraArgsError = "Unrecognized arguments found: %v\n\n%s" 28 ) 29 30 const ( 31 enroll = "enroll" 32 getcacert = "getcacert" 33 getcainfo = "getcainfo" 34 gencsr = "gencsr" 35 ) 36 37 // Command interface initializes client command and loads an identity 38 type Command interface { 39 // Initializes the client command configuration 40 ConfigInit() error 41 // Returns the name of the configuration file 42 GetCfgFileName() string 43 // Loads the credentials of an identity that are in the msp directory specified to this command 44 LoadMyIdentity() (*lib.Identity, error) 45 // Returns lib.ClientCfg instance associated with this command 46 GetClientCfg() *lib.ClientConfig 47 // Returns viper instance associated with this command 48 GetViper() *viper.Viper 49 // Returns the client's home directory 50 GetHomeDirectory() string 51 // Set the default level to be something other than 'info' 52 SetDefaultLogLevel(string) 53 } 54 55 type crlArgs struct { 56 // Genenerate CRL with all the certificates that were revoked after this timestamp 57 RevokedAfter string `help:"Generate CRL with certificates that were revoked after this UTC timestamp (in RFC3339 format)"` 58 // Genenerate CRL with all the certificates that were revoked before this timestamp 59 RevokedBefore string `help:"Generate CRL with certificates that were revoked before this UTC timestamp (in RFC3339 format)"` 60 // Genenerate CRL with all the certificates that expire after this timestamp 61 ExpireAfter string `help:"Generate CRL with certificates that expire after this UTC timestamp (in RFC3339 format)"` 62 // Genenerate CRL with all the certificates that expire before this timestamp 63 ExpireBefore string `help:"Generate CRL with certificates that expire before this UTC timestamp (in RFC3339 format)"` 64 } 65 66 type revokeArgs struct { 67 // GenCRL specifies whether to generate a CRL 68 GenCRL bool `def:"false" json:"gencrl,omitempty" opt:"" help:"Generates a CRL that contains all revoked certificates"` 69 } 70 71 // ClientCmd encapsulates cobra command that provides command line interface 72 // for the Fabric CA client and the configuration used by the Fabric CA client 73 type ClientCmd struct { 74 // name of the sub command 75 name string 76 // rootCmd is the base command for the Hyerledger Fabric CA client 77 rootCmd *cobra.Command 78 // My viper instance 79 myViper *viper.Viper 80 // cfgFileName is the name of the configuration file 81 cfgFileName string 82 // homeDirectory is the location of the client's home directory 83 homeDirectory string 84 // clientCfg is the client's configuration 85 clientCfg *lib.ClientConfig 86 // cfgAttrs are the attributes specified via flags or env variables 87 // and translated to Attributes field in registration 88 cfgAttrs []string 89 // cfgAttrReqs are the attribute requests specified via flags or env variables 90 // and translated to the AttrReqs field in enrollment 91 cfgAttrReqs []string 92 // cfgCsrNames are the certificate signing request names specified via flags 93 // or env variables 94 cfgCsrNames []string 95 // csrCommonName is the certificate signing request common name specified via the flag 96 csrCommonName string 97 // gencrl command argument values 98 crlParams crlArgs 99 // revoke command argument values 100 revokeParams revokeArgs 101 // profileMode is the profiling mode, cpu or mem or empty 102 profileMode string 103 // profileInst is the profiling instance object 104 profileInst interface { 105 Stop() 106 } 107 // Dynamically configuring identities 108 dynamicIdentity identityArgs 109 // Dynamically configuring affiliations 110 dynamicAffiliation affiliationArgs 111 // Set to log level 112 logLevel string 113 } 114 115 // NewCommand returns new ClientCmd ready for running 116 func NewCommand(name string) *ClientCmd { 117 c := &ClientCmd{ 118 myViper: viper.New(), 119 } 120 c.name = strings.ToLower(name) 121 c.init() 122 return c 123 } 124 125 // Execute runs this ClientCmd 126 func (c *ClientCmd) Execute() error { 127 return c.rootCmd.Execute() 128 } 129 130 // init initializes the ClientCmd instance 131 // It initializes the cobra root and sub commands and 132 // registers command flags with viper 133 func (c *ClientCmd) init() { 134 c.rootCmd = &cobra.Command{ 135 Use: cmdName, 136 Short: longName, 137 PersistentPreRunE: func(cmd *cobra.Command, args []string) error { 138 err := c.checkAndEnableProfiling() 139 if err != nil { 140 return err 141 } 142 util.CmdRunBegin(c.myViper) 143 cmd.SilenceUsage = true 144 return nil 145 }, 146 PersistentPostRunE: func(cmd *cobra.Command, args []string) error { 147 if c.profileMode != "" && c.profileInst != nil { 148 c.profileInst.Stop() 149 } 150 return nil 151 }, 152 } 153 c.rootCmd.AddCommand(c.newRegisterCommand(), 154 newEnrollCmd(c).getCommand(), 155 c.newReenrollCommand(), 156 c.newRevokeCommand(), 157 newGetCAInfoCmd(c).getCommand(), 158 c.newGenCsrCommand(), 159 c.newGenCRLCommand(), 160 c.newIdentityCommand(), 161 c.newAffiliationCommand(), 162 createCertificateCommand(c)) 163 c.rootCmd.AddCommand(&cobra.Command{ 164 Use: "version", 165 Short: "Prints Fabric CA Client version", 166 Run: func(cmd *cobra.Command, args []string) { 167 fmt.Print(metadata.GetVersionInfo(cmdName)) 168 }, 169 }) 170 c.registerFlags() 171 log.Level = log.LOG_LEVEL_INFO 172 } 173 174 // registerFlags registers command flags with viper 175 func (c *ClientCmd) registerFlags() { 176 // Get the default config file path 177 cfg := util.GetDefaultConfigFile(cmdName) 178 179 // All env variables must be prefixed 180 c.myViper.SetEnvPrefix(envVarPrefix) 181 c.myViper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) 182 183 host, err := os.Hostname() 184 if err != nil { 185 log.Error(err) 186 } 187 188 // Set global flags used by all commands 189 pflags := c.rootCmd.PersistentFlags() 190 pflags.StringVarP(&c.cfgFileName, "config", "c", "", "Configuration file") 191 pflags.MarkHidden("config") 192 // Don't want to use the default parameter for StringVarP. Need to be able to identify if home directory was explicitly set 193 pflags.StringVarP(&c.homeDirectory, "home", "H", "", fmt.Sprintf("Client's home directory (default \"%s\")", filepath.Dir(cfg))) 194 pflags.StringSliceVarP( 195 &c.cfgAttrs, "id.attrs", "", nil, "A list of comma-separated attributes of the form <name>=<value> (e.g. foo=foo1,bar=bar1)") 196 pflags.StringSliceVarP( 197 &c.cfgAttrReqs, "enrollment.attrs", "", nil, "A list of comma-separated attribute requests of the form <name>[:opt] (e.g. foo,bar:opt)") 198 util.FlagString(c.myViper, pflags, "myhost", "m", host, 199 "Hostname to include in the certificate signing request during enrollment") 200 pflags.StringSliceVarP( 201 &c.cfgCsrNames, "csr.names", "", nil, "A list of comma-separated CSR names of the form <name>=<value> (e.g. C=CA,O=Org1)") 202 203 c.clientCfg = &lib.ClientConfig{} 204 tags := map[string]string{ 205 "help.csr.cn": "The common name field of the certificate signing request", 206 "help.csr.serialnumber": "The serial number in a certificate signing request", 207 "help.csr.hosts": "A list of comma-separated host names in a certificate signing request", 208 "skip.csp.pluginopts.config": "true", // Skipping because this a map 209 } 210 err = util.RegisterFlags(c.myViper, pflags, c.clientCfg, tags) 211 if err != nil { 212 panic(err) 213 } 214 } 215 216 // checkAndEnableProfiling checks for the FABRIC_CA_CLIENT_PROFILE_MODE 217 // env variable, if it is set to "cpu", cpu profiling is enabled; 218 // if it is set to "heap", heap profiling is enabled 219 func (c *ClientCmd) checkAndEnableProfiling() error { 220 c.profileMode = strings.ToLower(os.Getenv(fabricCAClientProfileMode)) 221 if c.profileMode != "" { 222 wd, err := os.Getwd() 223 if err != nil { 224 wd = os.Getenv("HOME") 225 } 226 opt := profile.ProfilePath(wd) 227 switch c.profileMode { 228 case "cpu": 229 c.profileInst = profile.Start(opt, profile.CPUProfile) 230 case "heap": 231 c.profileInst = profile.Start(opt, profile.MemProfileRate(2048)) 232 default: 233 msg := fmt.Sprintf("Invalid value for the %s environment variable; found '%s', expecting 'cpu' or 'heap'", 234 fabricCAClientProfileMode, c.profileMode) 235 return errors.New(msg) 236 } 237 } 238 return nil 239 } 240 241 // Certain client commands can only be executed if enrollment credentials 242 // are present 243 func (c *ClientCmd) requiresEnrollment() bool { 244 return c.name != enroll && c.name != getcacert && c.name != getcainfo && c.name != gencsr 245 } 246 247 // Create default client configuration file only during an enroll or gencsr command 248 func (c *ClientCmd) shouldCreateDefaultConfig() bool { 249 return c.name == enroll || c.name == gencsr 250 } 251 252 func (c *ClientCmd) requiresUser() bool { 253 return c.name != gencsr 254 } 255 256 // LoadMyIdentity loads the client's identity 257 func (c *ClientCmd) LoadMyIdentity() (*lib.Identity, error) { 258 client := &lib.Client{ 259 HomeDir: filepath.Dir(c.cfgFileName), 260 Config: c.clientCfg, 261 } 262 263 id, err := client.LoadMyIdentity() 264 if err != nil { 265 return nil, err 266 } 267 268 return id, nil 269 } 270 271 // GetClientCfg returns client configuration 272 func (c *ClientCmd) GetClientCfg() *lib.ClientConfig { 273 return c.clientCfg 274 } 275 276 // GetCfgFileName returns name of the client command configuration file 277 func (c *ClientCmd) GetCfgFileName() string { 278 return c.cfgFileName 279 } 280 281 // GetViper returns the viper instance 282 func (c *ClientCmd) GetViper() *viper.Viper { 283 return c.myViper 284 } 285 286 // SetDefaultLogLevel sets the default log level for a command to a specific level 287 func (c *ClientCmd) SetDefaultLogLevel(logLevel string) { 288 c.logLevel = logLevel 289 }