github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/cmd/cryptogen/main.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  package main
     7  
     8  import (
     9  	"bytes"
    10  	"fmt"
    11  	"io"
    12  	"io/ioutil"
    13  	"os"
    14  	"path/filepath"
    15  	"text/template"
    16  
    17  	"github.com/hyperledger/fabric/internal/cryptogen/ca"
    18  	"github.com/hyperledger/fabric/internal/cryptogen/csp"
    19  	"github.com/hyperledger/fabric/internal/cryptogen/metadata"
    20  	"github.com/hyperledger/fabric/internal/cryptogen/msp"
    21  
    22  	kingpin "gopkg.in/alecthomas/kingpin.v2"
    23  	yaml "gopkg.in/yaml.v2"
    24  )
    25  
    26  const (
    27  	userBaseName            = "User"
    28  	adminBaseName           = "Admin"
    29  	defaultHostnameTemplate = "{{.Prefix}}{{.Index}}"
    30  	defaultCNTemplate       = "{{.Hostname}}.{{.Domain}}"
    31  )
    32  
    33  type HostnameData struct {
    34  	Prefix string
    35  	Index  int
    36  	Domain string
    37  }
    38  
    39  type SpecData struct {
    40  	Hostname   string
    41  	Domain     string
    42  	CommonName string
    43  }
    44  
    45  type NodeTemplate struct {
    46  	Count    int      `yaml:"Count"`
    47  	Start    int      `yaml:"Start"`
    48  	Hostname string   `yaml:"Hostname"`
    49  	SANS     []string `yaml:"SANS"`
    50  }
    51  
    52  type NodeSpec struct {
    53  	isAdmin            bool
    54  	Hostname           string   `yaml:"Hostname"`
    55  	CommonName         string   `yaml:"CommonName"`
    56  	Country            string   `yaml:"Country"`
    57  	Province           string   `yaml:"Province"`
    58  	Locality           string   `yaml:"Locality"`
    59  	OrganizationalUnit string   `yaml:"OrganizationalUnit"`
    60  	StreetAddress      string   `yaml:"StreetAddress"`
    61  	PostalCode         string   `yaml:"PostalCode"`
    62  	SANS               []string `yaml:"SANS"`
    63  }
    64  
    65  type UsersSpec struct {
    66  	Count int `yaml:"Count"`
    67  }
    68  
    69  type OrgSpec struct {
    70  	Name          string       `yaml:"Name"`
    71  	Domain        string       `yaml:"Domain"`
    72  	EnableNodeOUs bool         `yaml:"EnableNodeOUs"`
    73  	CA            NodeSpec     `yaml:"CA"`
    74  	Template      NodeTemplate `yaml:"Template"`
    75  	Specs         []NodeSpec   `yaml:"Specs"`
    76  	Users         UsersSpec    `yaml:"Users"`
    77  }
    78  
    79  type Config struct {
    80  	OrdererOrgs []OrgSpec `yaml:"OrdererOrgs"`
    81  	PeerOrgs    []OrgSpec `yaml:"PeerOrgs"`
    82  }
    83  
    84  var defaultConfig = `
    85  # ---------------------------------------------------------------------------
    86  # "OrdererOrgs" - Definition of organizations managing orderer nodes
    87  # ---------------------------------------------------------------------------
    88  OrdererOrgs:
    89    # ---------------------------------------------------------------------------
    90    # Orderer
    91    # ---------------------------------------------------------------------------
    92    - Name: Orderer
    93      Domain: example.com
    94      EnableNodeOUs: false
    95  
    96      # ---------------------------------------------------------------------------
    97      # "Specs" - See PeerOrgs below for complete description
    98      # ---------------------------------------------------------------------------
    99      Specs:
   100        - Hostname: orderer
   101  
   102  # ---------------------------------------------------------------------------
   103  # "PeerOrgs" - Definition of organizations managing peer nodes
   104  # ---------------------------------------------------------------------------
   105  PeerOrgs:
   106    # ---------------------------------------------------------------------------
   107    # Org1
   108    # ---------------------------------------------------------------------------
   109    - Name: Org1
   110      Domain: org1.example.com
   111      EnableNodeOUs: false
   112  
   113      # ---------------------------------------------------------------------------
   114      # "CA"
   115      # ---------------------------------------------------------------------------
   116      # Uncomment this section to enable the explicit definition of the CA for this
   117      # organization.  This entry is a Spec.  See "Specs" section below for details.
   118      # ---------------------------------------------------------------------------
   119      # CA:
   120      #    Hostname: ca # implicitly ca.org1.example.com
   121      #    Country: US
   122      #    Province: California
   123      #    Locality: San Francisco
   124      #    OrganizationalUnit: Hyperledger Fabric
   125      #    StreetAddress: address for org # default nil
   126      #    PostalCode: postalCode for org # default nil
   127  
   128      # ---------------------------------------------------------------------------
   129      # "Specs"
   130      # ---------------------------------------------------------------------------
   131      # Uncomment this section to enable the explicit definition of hosts in your
   132      # configuration.  Most users will want to use Template, below
   133      #
   134      # Specs is an array of Spec entries.  Each Spec entry consists of two fields:
   135      #   - Hostname:   (Required) The desired hostname, sans the domain.
   136      #   - CommonName: (Optional) Specifies the template or explicit override for
   137      #                 the CN.  By default, this is the template:
   138      #
   139      #                              "{{.Hostname}}.{{.Domain}}"
   140      #
   141      #                 which obtains its values from the Spec.Hostname and
   142      #                 Org.Domain, respectively.
   143      #   - SANS:       (Optional) Specifies one or more Subject Alternative Names
   144      #                 to be set in the resulting x509. Accepts template
   145      #                 variables {{.Hostname}}, {{.Domain}}, {{.CommonName}}. IP
   146      #                 addresses provided here will be properly recognized. Other
   147      #                 values will be taken as DNS names.
   148      #                 NOTE: Two implicit entries are created for you:
   149      #                     - {{ .CommonName }}
   150      #                     - {{ .Hostname }}
   151      # ---------------------------------------------------------------------------
   152      # Specs:
   153      #   - Hostname: foo # implicitly "foo.org1.example.com"
   154      #     CommonName: foo27.org5.example.com # overrides Hostname-based FQDN set above
   155      #     SANS:
   156      #       - "bar.{{.Domain}}"
   157      #       - "altfoo.{{.Domain}}"
   158      #       - "{{.Hostname}}.org6.net"
   159      #       - 172.16.10.31
   160      #   - Hostname: bar
   161      #   - Hostname: baz
   162  
   163      # ---------------------------------------------------------------------------
   164      # "Template"
   165      # ---------------------------------------------------------------------------
   166      # Allows for the definition of 1 or more hosts that are created sequentially
   167      # from a template. By default, this looks like "peer%d" from 0 to Count-1.
   168      # You may override the number of nodes (Count), the starting index (Start)
   169      # or the template used to construct the name (Hostname).
   170      #
   171      # Note: Template and Specs are not mutually exclusive.  You may define both
   172      # sections and the aggregate nodes will be created for you.  Take care with
   173      # name collisions
   174      # ---------------------------------------------------------------------------
   175      Template:
   176        Count: 1
   177        # Start: 5
   178        # Hostname: {{.Prefix}}{{.Index}} # default
   179        # SANS:
   180        #   - "{{.Hostname}}.alt.{{.Domain}}"
   181  
   182      # ---------------------------------------------------------------------------
   183      # "Users"
   184      # ---------------------------------------------------------------------------
   185      # Count: The number of user accounts _in addition_ to Admin
   186      # ---------------------------------------------------------------------------
   187      Users:
   188        Count: 1
   189  
   190    # ---------------------------------------------------------------------------
   191    # Org2: See "Org1" for full specification
   192    # ---------------------------------------------------------------------------
   193    - Name: Org2
   194      Domain: org2.example.com
   195      EnableNodeOUs: false
   196      Template:
   197        Count: 1
   198      Users:
   199        Count: 1
   200  `
   201  
   202  //command line flags
   203  var (
   204  	app = kingpin.New("cryptogen", "Utility for generating Hyperledger Fabric key material")
   205  
   206  	gen           = app.Command("generate", "Generate key material")
   207  	outputDir     = gen.Flag("output", "The output directory in which to place artifacts").Default("crypto-config").String()
   208  	genConfigFile = gen.Flag("config", "The configuration template to use").File()
   209  
   210  	showtemplate = app.Command("showtemplate", "Show the default configuration template")
   211  
   212  	version       = app.Command("version", "Show version information")
   213  	ext           = app.Command("extend", "Extend existing network")
   214  	inputDir      = ext.Flag("input", "The input directory in which existing network place").Default("crypto-config").String()
   215  	extConfigFile = ext.Flag("config", "The configuration template to use").File()
   216  )
   217  
   218  func main() {
   219  	kingpin.Version("0.0.1")
   220  	switch kingpin.MustParse(app.Parse(os.Args[1:])) {
   221  
   222  	// "generate" command
   223  	case gen.FullCommand():
   224  		generate()
   225  
   226  	case ext.FullCommand():
   227  		extend()
   228  
   229  		// "showtemplate" command
   230  	case showtemplate.FullCommand():
   231  		fmt.Print(defaultConfig)
   232  		os.Exit(0)
   233  
   234  		// "version" command
   235  	case version.FullCommand():
   236  		printVersion()
   237  	}
   238  
   239  }
   240  
   241  func getConfig() (*Config, error) {
   242  	var configData string
   243  
   244  	if *genConfigFile != nil {
   245  		data, err := ioutil.ReadAll(*genConfigFile)
   246  		if err != nil {
   247  			return nil, fmt.Errorf("Error reading configuration: %s", err)
   248  		}
   249  
   250  		configData = string(data)
   251  	} else if *extConfigFile != nil {
   252  		data, err := ioutil.ReadAll(*extConfigFile)
   253  		if err != nil {
   254  			return nil, fmt.Errorf("Error reading configuration: %s", err)
   255  		}
   256  
   257  		configData = string(data)
   258  	} else {
   259  		configData = defaultConfig
   260  	}
   261  
   262  	config := &Config{}
   263  	err := yaml.Unmarshal([]byte(configData), &config)
   264  	if err != nil {
   265  		return nil, fmt.Errorf("Error Unmarshaling YAML: %s", err)
   266  	}
   267  
   268  	return config, nil
   269  }
   270  
   271  func extend() {
   272  	config, err := getConfig()
   273  	if err != nil {
   274  		fmt.Printf("Error reading config: %s", err)
   275  		os.Exit(-1)
   276  	}
   277  
   278  	for _, orgSpec := range config.PeerOrgs {
   279  		err = renderOrgSpec(&orgSpec, "peer")
   280  		if err != nil {
   281  			fmt.Printf("Error processing peer configuration: %s", err)
   282  			os.Exit(-1)
   283  		}
   284  		extendPeerOrg(orgSpec)
   285  	}
   286  
   287  	for _, orgSpec := range config.OrdererOrgs {
   288  		err = renderOrgSpec(&orgSpec, "orderer")
   289  		if err != nil {
   290  			fmt.Printf("Error processing orderer configuration: %s", err)
   291  			os.Exit(-1)
   292  		}
   293  		extendOrdererOrg(orgSpec)
   294  	}
   295  
   296  }
   297  
   298  func extendPeerOrg(orgSpec OrgSpec) {
   299  	orgName := orgSpec.Domain
   300  	orgDir := filepath.Join(*inputDir, "peerOrganizations", orgName)
   301  	if _, err := os.Stat(orgDir); os.IsNotExist(err) {
   302  		generatePeerOrg(*inputDir, orgSpec)
   303  		return
   304  	}
   305  
   306  	peersDir := filepath.Join(orgDir, "peers")
   307  	usersDir := filepath.Join(orgDir, "users")
   308  	caDir := filepath.Join(orgDir, "ca")
   309  	tlscaDir := filepath.Join(orgDir, "tlsca")
   310  
   311  	signCA := getCA(caDir, orgSpec, orgSpec.CA.CommonName)
   312  	tlsCA := getCA(tlscaDir, orgSpec, "tls"+orgSpec.CA.CommonName)
   313  
   314  	generateNodes(peersDir, orgSpec.Specs, signCA, tlsCA, msp.PEER, orgSpec.EnableNodeOUs)
   315  
   316  	adminUser := NodeSpec{
   317  		isAdmin:    true,
   318  		CommonName: fmt.Sprintf("%s@%s", adminBaseName, orgName),
   319  	}
   320  	// copy the admin cert to each of the org's peer's MSP admincerts
   321  	for _, spec := range orgSpec.Specs {
   322  		if orgSpec.EnableNodeOUs {
   323  			continue
   324  		}
   325  		err := copyAdminCert(usersDir,
   326  			filepath.Join(peersDir, spec.CommonName, "msp", "admincerts"), adminUser.CommonName)
   327  		if err != nil {
   328  			fmt.Printf("Error copying admin cert for org %s peer %s:\n%v\n",
   329  				orgName, spec.CommonName, err)
   330  			os.Exit(1)
   331  		}
   332  	}
   333  
   334  	// TODO: add ability to specify usernames
   335  	users := []NodeSpec{}
   336  	for j := 1; j <= orgSpec.Users.Count; j++ {
   337  		user := NodeSpec{
   338  			CommonName: fmt.Sprintf("%s%d@%s", userBaseName, j, orgName),
   339  		}
   340  
   341  		users = append(users, user)
   342  	}
   343  
   344  	generateNodes(usersDir, users, signCA, tlsCA, msp.CLIENT, orgSpec.EnableNodeOUs)
   345  }
   346  
   347  func extendOrdererOrg(orgSpec OrgSpec) {
   348  	orgName := orgSpec.Domain
   349  
   350  	orgDir := filepath.Join(*inputDir, "ordererOrganizations", orgName)
   351  	caDir := filepath.Join(orgDir, "ca")
   352  	usersDir := filepath.Join(orgDir, "users")
   353  	tlscaDir := filepath.Join(orgDir, "tlsca")
   354  	orderersDir := filepath.Join(orgDir, "orderers")
   355  	if _, err := os.Stat(orgDir); os.IsNotExist(err) {
   356  		generateOrdererOrg(*inputDir, orgSpec)
   357  		return
   358  	}
   359  
   360  	signCA := getCA(caDir, orgSpec, orgSpec.CA.CommonName)
   361  	tlsCA := getCA(tlscaDir, orgSpec, "tls"+orgSpec.CA.CommonName)
   362  
   363  	generateNodes(orderersDir, orgSpec.Specs, signCA, tlsCA, msp.ORDERER, orgSpec.EnableNodeOUs)
   364  
   365  	adminUser := NodeSpec{
   366  		isAdmin:    true,
   367  		CommonName: fmt.Sprintf("%s@%s", adminBaseName, orgName),
   368  	}
   369  
   370  	for _, spec := range orgSpec.Specs {
   371  		if orgSpec.EnableNodeOUs {
   372  			continue
   373  		}
   374  		err := copyAdminCert(usersDir,
   375  			filepath.Join(orderersDir, spec.CommonName, "msp", "admincerts"), adminUser.CommonName)
   376  		if err != nil {
   377  			fmt.Printf("Error copying admin cert for org %s orderer %s:\n%v\n",
   378  				orgName, spec.CommonName, err)
   379  			os.Exit(1)
   380  		}
   381  	}
   382  }
   383  
   384  func generate() {
   385  
   386  	config, err := getConfig()
   387  	if err != nil {
   388  		fmt.Printf("Error reading config: %s", err)
   389  		os.Exit(-1)
   390  	}
   391  
   392  	for _, orgSpec := range config.PeerOrgs {
   393  		err = renderOrgSpec(&orgSpec, "peer")
   394  		if err != nil {
   395  			fmt.Printf("Error processing peer configuration: %s", err)
   396  			os.Exit(-1)
   397  		}
   398  		generatePeerOrg(*outputDir, orgSpec)
   399  	}
   400  
   401  	for _, orgSpec := range config.OrdererOrgs {
   402  		err = renderOrgSpec(&orgSpec, "orderer")
   403  		if err != nil {
   404  			fmt.Printf("Error processing orderer configuration: %s", err)
   405  			os.Exit(-1)
   406  		}
   407  		generateOrdererOrg(*outputDir, orgSpec)
   408  	}
   409  }
   410  
   411  func parseTemplate(input string, data interface{}) (string, error) {
   412  
   413  	t, err := template.New("parse").Parse(input)
   414  	if err != nil {
   415  		return "", fmt.Errorf("Error parsing template: %s", err)
   416  	}
   417  
   418  	output := new(bytes.Buffer)
   419  	err = t.Execute(output, data)
   420  	if err != nil {
   421  		return "", fmt.Errorf("Error executing template: %s", err)
   422  	}
   423  
   424  	return output.String(), nil
   425  }
   426  
   427  func parseTemplateWithDefault(input, defaultInput string, data interface{}) (string, error) {
   428  
   429  	// Use the default if the input is an empty string
   430  	if len(input) == 0 {
   431  		input = defaultInput
   432  	}
   433  
   434  	return parseTemplate(input, data)
   435  }
   436  
   437  func renderNodeSpec(domain string, spec *NodeSpec) error {
   438  	data := SpecData{
   439  		Hostname: spec.Hostname,
   440  		Domain:   domain,
   441  	}
   442  
   443  	// Process our CommonName
   444  	cn, err := parseTemplateWithDefault(spec.CommonName, defaultCNTemplate, data)
   445  	if err != nil {
   446  		return err
   447  	}
   448  
   449  	spec.CommonName = cn
   450  	data.CommonName = cn
   451  
   452  	// Save off our original, unprocessed SANS entries
   453  	origSANS := spec.SANS
   454  
   455  	// Set our implicit SANS entries for CN/Hostname
   456  	spec.SANS = []string{cn, spec.Hostname}
   457  
   458  	// Finally, process any remaining SANS entries
   459  	for _, _san := range origSANS {
   460  		san, err := parseTemplate(_san, data)
   461  		if err != nil {
   462  			return err
   463  		}
   464  
   465  		spec.SANS = append(spec.SANS, san)
   466  	}
   467  
   468  	return nil
   469  }
   470  
   471  func renderOrgSpec(orgSpec *OrgSpec, prefix string) error {
   472  	// First process all of our templated nodes
   473  	for i := 0; i < orgSpec.Template.Count; i++ {
   474  		data := HostnameData{
   475  			Prefix: prefix,
   476  			Index:  i + orgSpec.Template.Start,
   477  			Domain: orgSpec.Domain,
   478  		}
   479  
   480  		hostname, err := parseTemplateWithDefault(orgSpec.Template.Hostname, defaultHostnameTemplate, data)
   481  		if err != nil {
   482  			return err
   483  		}
   484  
   485  		spec := NodeSpec{
   486  			Hostname: hostname,
   487  			SANS:     orgSpec.Template.SANS,
   488  		}
   489  		orgSpec.Specs = append(orgSpec.Specs, spec)
   490  	}
   491  
   492  	// Touch up all general node-specs to add the domain
   493  	for idx, spec := range orgSpec.Specs {
   494  		err := renderNodeSpec(orgSpec.Domain, &spec)
   495  		if err != nil {
   496  			return err
   497  		}
   498  
   499  		orgSpec.Specs[idx] = spec
   500  	}
   501  
   502  	// Process the CA node-spec in the same manner
   503  	if len(orgSpec.CA.Hostname) == 0 {
   504  		orgSpec.CA.Hostname = "ca"
   505  	}
   506  	err := renderNodeSpec(orgSpec.Domain, &orgSpec.CA)
   507  	if err != nil {
   508  		return err
   509  	}
   510  
   511  	return nil
   512  }
   513  
   514  func generatePeerOrg(baseDir string, orgSpec OrgSpec) {
   515  
   516  	orgName := orgSpec.Domain
   517  
   518  	fmt.Println(orgName)
   519  	// generate CAs
   520  	orgDir := filepath.Join(baseDir, "peerOrganizations", orgName)
   521  	caDir := filepath.Join(orgDir, "ca")
   522  	tlsCADir := filepath.Join(orgDir, "tlsca")
   523  	mspDir := filepath.Join(orgDir, "msp")
   524  	peersDir := filepath.Join(orgDir, "peers")
   525  	usersDir := filepath.Join(orgDir, "users")
   526  	adminCertsDir := filepath.Join(mspDir, "admincerts")
   527  	// generate signing CA
   528  	signCA, err := ca.NewCA(caDir, orgName, orgSpec.CA.CommonName, orgSpec.CA.Country, orgSpec.CA.Province, orgSpec.CA.Locality, orgSpec.CA.OrganizationalUnit, orgSpec.CA.StreetAddress, orgSpec.CA.PostalCode)
   529  	if err != nil {
   530  		fmt.Printf("Error generating signCA for org %s:\n%v\n", orgName, err)
   531  		os.Exit(1)
   532  	}
   533  	// generate TLS CA
   534  	tlsCA, err := ca.NewCA(tlsCADir, orgName, "tls"+orgSpec.CA.CommonName, orgSpec.CA.Country, orgSpec.CA.Province, orgSpec.CA.Locality, orgSpec.CA.OrganizationalUnit, orgSpec.CA.StreetAddress, orgSpec.CA.PostalCode)
   535  	if err != nil {
   536  		fmt.Printf("Error generating tlsCA for org %s:\n%v\n", orgName, err)
   537  		os.Exit(1)
   538  	}
   539  
   540  	err = msp.GenerateVerifyingMSP(mspDir, signCA, tlsCA, orgSpec.EnableNodeOUs)
   541  	if err != nil {
   542  		fmt.Printf("Error generating MSP for org %s:\n%v\n", orgName, err)
   543  		os.Exit(1)
   544  	}
   545  
   546  	generateNodes(peersDir, orgSpec.Specs, signCA, tlsCA, msp.PEER, orgSpec.EnableNodeOUs)
   547  
   548  	// TODO: add ability to specify usernames
   549  	users := []NodeSpec{}
   550  	for j := 1; j <= orgSpec.Users.Count; j++ {
   551  		user := NodeSpec{
   552  			CommonName: fmt.Sprintf("%s%d@%s", userBaseName, j, orgName),
   553  		}
   554  
   555  		users = append(users, user)
   556  	}
   557  	// add an admin user
   558  	adminUser := NodeSpec{
   559  		isAdmin:    true,
   560  		CommonName: fmt.Sprintf("%s@%s", adminBaseName, orgName),
   561  	}
   562  
   563  	users = append(users, adminUser)
   564  	generateNodes(usersDir, users, signCA, tlsCA, msp.CLIENT, orgSpec.EnableNodeOUs)
   565  
   566  	// copy the admin cert to the org's MSP admincerts
   567  	if !orgSpec.EnableNodeOUs {
   568  		err = copyAdminCert(usersDir, adminCertsDir, adminUser.CommonName)
   569  		if err != nil {
   570  			fmt.Printf("Error copying admin cert for org %s:\n%v\n",
   571  				orgName, err)
   572  			os.Exit(1)
   573  		}
   574  	}
   575  
   576  	// copy the admin cert to each of the org's peer's MSP admincerts
   577  	for _, spec := range orgSpec.Specs {
   578  		if orgSpec.EnableNodeOUs {
   579  			continue
   580  		}
   581  		err = copyAdminCert(usersDir,
   582  			filepath.Join(peersDir, spec.CommonName, "msp", "admincerts"), adminUser.CommonName)
   583  		if err != nil {
   584  			fmt.Printf("Error copying admin cert for org %s peer %s:\n%v\n",
   585  				orgName, spec.CommonName, err)
   586  			os.Exit(1)
   587  		}
   588  	}
   589  }
   590  
   591  func copyAdminCert(usersDir, adminCertsDir, adminUserName string) error {
   592  	if _, err := os.Stat(filepath.Join(adminCertsDir,
   593  		adminUserName+"-cert.pem")); err == nil {
   594  		return nil
   595  	}
   596  	// delete the contents of admincerts
   597  	err := os.RemoveAll(adminCertsDir)
   598  	if err != nil {
   599  		return err
   600  	}
   601  	// recreate the admincerts directory
   602  	err = os.MkdirAll(adminCertsDir, 0755)
   603  	if err != nil {
   604  		return err
   605  	}
   606  	err = copyFile(filepath.Join(usersDir, adminUserName, "msp", "signcerts",
   607  		adminUserName+"-cert.pem"), filepath.Join(adminCertsDir,
   608  		adminUserName+"-cert.pem"))
   609  	if err != nil {
   610  		return err
   611  	}
   612  	return nil
   613  }
   614  
   615  func generateNodes(baseDir string, nodes []NodeSpec, signCA *ca.CA, tlsCA *ca.CA, nodeType int, nodeOUs bool) {
   616  	for _, node := range nodes {
   617  		nodeDir := filepath.Join(baseDir, node.CommonName)
   618  		if _, err := os.Stat(nodeDir); os.IsNotExist(err) {
   619  			currentNodeType := nodeType
   620  			if node.isAdmin && nodeOUs {
   621  				currentNodeType = msp.ADMIN
   622  			}
   623  			err := msp.GenerateLocalMSP(nodeDir, node.CommonName, node.SANS, signCA, tlsCA, currentNodeType, nodeOUs)
   624  			if err != nil {
   625  				fmt.Printf("Error generating local MSP for %v:\n%v\n", node, err)
   626  				os.Exit(1)
   627  			}
   628  		}
   629  	}
   630  }
   631  
   632  func generateOrdererOrg(baseDir string, orgSpec OrgSpec) {
   633  
   634  	orgName := orgSpec.Domain
   635  
   636  	// generate CAs
   637  	orgDir := filepath.Join(baseDir, "ordererOrganizations", orgName)
   638  	caDir := filepath.Join(orgDir, "ca")
   639  	tlsCADir := filepath.Join(orgDir, "tlsca")
   640  	mspDir := filepath.Join(orgDir, "msp")
   641  	orderersDir := filepath.Join(orgDir, "orderers")
   642  	usersDir := filepath.Join(orgDir, "users")
   643  	adminCertsDir := filepath.Join(mspDir, "admincerts")
   644  	// generate signing CA
   645  	signCA, err := ca.NewCA(caDir, orgName, orgSpec.CA.CommonName, orgSpec.CA.Country, orgSpec.CA.Province, orgSpec.CA.Locality, orgSpec.CA.OrganizationalUnit, orgSpec.CA.StreetAddress, orgSpec.CA.PostalCode)
   646  	if err != nil {
   647  		fmt.Printf("Error generating signCA for org %s:\n%v\n", orgName, err)
   648  		os.Exit(1)
   649  	}
   650  	// generate TLS CA
   651  	tlsCA, err := ca.NewCA(tlsCADir, orgName, "tls"+orgSpec.CA.CommonName, orgSpec.CA.Country, orgSpec.CA.Province, orgSpec.CA.Locality, orgSpec.CA.OrganizationalUnit, orgSpec.CA.StreetAddress, orgSpec.CA.PostalCode)
   652  	if err != nil {
   653  		fmt.Printf("Error generating tlsCA for org %s:\n%v\n", orgName, err)
   654  		os.Exit(1)
   655  	}
   656  
   657  	err = msp.GenerateVerifyingMSP(mspDir, signCA, tlsCA, orgSpec.EnableNodeOUs)
   658  	if err != nil {
   659  		fmt.Printf("Error generating MSP for org %s:\n%v\n", orgName, err)
   660  		os.Exit(1)
   661  	}
   662  
   663  	generateNodes(orderersDir, orgSpec.Specs, signCA, tlsCA, msp.ORDERER, orgSpec.EnableNodeOUs)
   664  
   665  	adminUser := NodeSpec{
   666  		isAdmin:    true,
   667  		CommonName: fmt.Sprintf("%s@%s", adminBaseName, orgName),
   668  	}
   669  
   670  	// generate an admin for the orderer org
   671  	users := []NodeSpec{}
   672  	// add an admin user
   673  	users = append(users, adminUser)
   674  	generateNodes(usersDir, users, signCA, tlsCA, msp.CLIENT, orgSpec.EnableNodeOUs)
   675  
   676  	// copy the admin cert to the org's MSP admincerts
   677  	if !orgSpec.EnableNodeOUs {
   678  		err = copyAdminCert(usersDir, adminCertsDir, adminUser.CommonName)
   679  		if err != nil {
   680  			fmt.Printf("Error copying admin cert for org %s:\n%v\n",
   681  				orgName, err)
   682  			os.Exit(1)
   683  		}
   684  	}
   685  
   686  	// copy the admin cert to each of the org's orderers's MSP admincerts
   687  	for _, spec := range orgSpec.Specs {
   688  		if orgSpec.EnableNodeOUs {
   689  			continue
   690  		}
   691  		err = copyAdminCert(usersDir,
   692  			filepath.Join(orderersDir, spec.CommonName, "msp", "admincerts"), adminUser.CommonName)
   693  		if err != nil {
   694  			fmt.Printf("Error copying admin cert for org %s orderer %s:\n%v\n",
   695  				orgName, spec.CommonName, err)
   696  			os.Exit(1)
   697  		}
   698  	}
   699  
   700  }
   701  
   702  func copyFile(src, dst string) error {
   703  	in, err := os.Open(src)
   704  	if err != nil {
   705  		return err
   706  	}
   707  	defer in.Close()
   708  	out, err := os.Create(dst)
   709  	if err != nil {
   710  		return err
   711  	}
   712  	defer out.Close()
   713  	_, err = io.Copy(out, in)
   714  	cerr := out.Close()
   715  	if err != nil {
   716  		return err
   717  	}
   718  	return cerr
   719  }
   720  
   721  func printVersion() {
   722  	fmt.Println(metadata.GetVersionInfo())
   723  }
   724  
   725  func getCA(caDir string, spec OrgSpec, name string) *ca.CA {
   726  	priv, _ := csp.LoadPrivateKey(caDir)
   727  	cert, _ := ca.LoadCertificateECDSA(caDir)
   728  
   729  	return &ca.CA{
   730  		Name:               name,
   731  		Signer:             priv,
   732  		SignCert:           cert,
   733  		Country:            spec.CA.Country,
   734  		Province:           spec.CA.Province,
   735  		Locality:           spec.CA.Locality,
   736  		OrganizationalUnit: spec.CA.OrganizationalUnit,
   737  		StreetAddress:      spec.CA.StreetAddress,
   738  		PostalCode:         spec.CA.PostalCode,
   739  	}
   740  }