github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/common/configtx/tool/configtxgen/main.go (about)

     1  /*
     2  Copyright IBM Corp. 2017 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8                   http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package main
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/json"
    22  	"flag"
    23  	"fmt"
    24  	"io/ioutil"
    25  	"os"
    26  	"strings"
    27  
    28  	"github.com/hyperledger/fabric/bccsp/factory"
    29  	"github.com/hyperledger/fabric/common/config"
    30  	mspconfig "github.com/hyperledger/fabric/common/config/msp"
    31  	"github.com/hyperledger/fabric/common/configtx"
    32  	"github.com/hyperledger/fabric/common/configtx/tool/configtxgen/metadata"
    33  	genesisconfig "github.com/hyperledger/fabric/common/configtx/tool/localconfig"
    34  	"github.com/hyperledger/fabric/common/configtx/tool/provisional"
    35  	"github.com/hyperledger/fabric/common/flogging"
    36  	cb "github.com/hyperledger/fabric/protos/common"
    37  	pb "github.com/hyperledger/fabric/protos/peer"
    38  	"github.com/hyperledger/fabric/protos/utils"
    39  
    40  	"github.com/golang/protobuf/proto"
    41  	logging "github.com/op/go-logging"
    42  )
    43  
    44  var exitCode = 0
    45  
    46  var logger = flogging.MustGetLogger("common/configtx/tool")
    47  
    48  func doOutputBlock(config *genesisconfig.Profile, channelID string, outputBlock string) error {
    49  	pgen := provisional.New(config)
    50  	logger.Info("Generating genesis block")
    51  	if config.Orderer == nil {
    52  		return fmt.Errorf("config does not contain an Orderers section, necessary for all config blocks, aborting")
    53  	}
    54  	if config.Consortiums == nil {
    55  		logger.Warning("Genesis block does not contain a consortiums group definition.  This block cannot be used for orderer bootstrap.")
    56  	}
    57  	genesisBlock := pgen.GenesisBlockForChannel(channelID)
    58  	logger.Info("Writing genesis block")
    59  	err := ioutil.WriteFile(outputBlock, utils.MarshalOrPanic(genesisBlock), 0644)
    60  	if err != nil {
    61  		return fmt.Errorf("Error writing genesis block: %s", err)
    62  	}
    63  	return nil
    64  }
    65  
    66  func doOutputChannelCreateTx(conf *genesisconfig.Profile, channelID string, outputChannelCreateTx string) error {
    67  	logger.Info("Generating new channel configtx")
    68  
    69  	if conf.Application == nil {
    70  		return fmt.Errorf("Cannot define a new channel with no Application section")
    71  	}
    72  
    73  	if conf.Consortium == "" {
    74  		return fmt.Errorf("Cannot define a new channel with no Consortium value")
    75  	}
    76  
    77  	// XXX we ignore the non-application org names here, once the tool supports configuration updates
    78  	// we should come up with a cleaner way to handle this, but leaving as is for the moment to not break
    79  	// backwards compatibility
    80  	var orgNames []string
    81  	for _, org := range conf.Application.Organizations {
    82  		orgNames = append(orgNames, org.Name)
    83  	}
    84  	configtx, err := configtx.MakeChainCreationTransaction(channelID, conf.Consortium, nil, orgNames...)
    85  	if err != nil {
    86  		return fmt.Errorf("Error generating configtx: %s", err)
    87  	}
    88  	logger.Info("Writing new channel tx")
    89  	err = ioutil.WriteFile(outputChannelCreateTx, utils.MarshalOrPanic(configtx), 0644)
    90  	if err != nil {
    91  		return fmt.Errorf("Error writing channel create tx: %s", err)
    92  	}
    93  	return nil
    94  }
    95  
    96  func doOutputAnchorPeersUpdate(conf *genesisconfig.Profile, channelID string, outputAnchorPeersUpdate string, asOrg string) error {
    97  	logger.Info("Generating anchor peer update")
    98  	if asOrg == "" {
    99  		return fmt.Errorf("Must specify an organization to update the anchor peer for")
   100  	}
   101  
   102  	if conf.Application == nil {
   103  		return fmt.Errorf("Cannot update anchor peers without an application section")
   104  	}
   105  
   106  	var org *genesisconfig.Organization
   107  	for _, iorg := range conf.Application.Organizations {
   108  		if iorg.Name == asOrg {
   109  			org = iorg
   110  		}
   111  	}
   112  
   113  	if org == nil {
   114  		return fmt.Errorf("No organization name matching: %s", asOrg)
   115  	}
   116  
   117  	anchorPeers := make([]*pb.AnchorPeer, len(org.AnchorPeers))
   118  	for i, anchorPeer := range org.AnchorPeers {
   119  		anchorPeers[i] = &pb.AnchorPeer{
   120  			Host: anchorPeer.Host,
   121  			Port: int32(anchorPeer.Port),
   122  		}
   123  	}
   124  
   125  	configGroup := config.TemplateAnchorPeers(org.Name, anchorPeers)
   126  	configGroup.Groups[config.ApplicationGroupKey].Groups[org.Name].Values[config.AnchorPeersKey].ModPolicy = mspconfig.AdminsPolicyKey
   127  	configUpdate := &cb.ConfigUpdate{
   128  		ChannelId: channelID,
   129  		WriteSet:  configGroup,
   130  		ReadSet:   cb.NewConfigGroup(),
   131  	}
   132  
   133  	// Add all the existing config to the readset
   134  	configUpdate.ReadSet.Groups[config.ApplicationGroupKey] = cb.NewConfigGroup()
   135  	configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Version = 1
   136  	configUpdate.ReadSet.Groups[config.ApplicationGroupKey].ModPolicy = mspconfig.AdminsPolicyKey
   137  	configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Groups[org.Name] = cb.NewConfigGroup()
   138  	configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Values[config.MSPKey] = &cb.ConfigValue{}
   139  	configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.ReadersPolicyKey] = &cb.ConfigPolicy{}
   140  	configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.WritersPolicyKey] = &cb.ConfigPolicy{}
   141  	configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.AdminsPolicyKey] = &cb.ConfigPolicy{}
   142  
   143  	// Add all the existing at the same versions to the writeset
   144  	configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Version = 1
   145  	configUpdate.WriteSet.Groups[config.ApplicationGroupKey].ModPolicy = mspconfig.AdminsPolicyKey
   146  	configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Version = 1
   147  	configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org.Name].ModPolicy = mspconfig.AdminsPolicyKey
   148  	configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Values[config.MSPKey] = &cb.ConfigValue{}
   149  	configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.ReadersPolicyKey] = &cb.ConfigPolicy{}
   150  	configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.WritersPolicyKey] = &cb.ConfigPolicy{}
   151  	configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.AdminsPolicyKey] = &cb.ConfigPolicy{}
   152  
   153  	configUpdateEnvelope := &cb.ConfigUpdateEnvelope{
   154  		ConfigUpdate: utils.MarshalOrPanic(configUpdate),
   155  	}
   156  
   157  	update := &cb.Envelope{
   158  		Payload: utils.MarshalOrPanic(&cb.Payload{
   159  			Header: &cb.Header{
   160  				ChannelHeader: utils.MarshalOrPanic(&cb.ChannelHeader{
   161  					ChannelId: channelID,
   162  					Type:      int32(cb.HeaderType_CONFIG_UPDATE),
   163  				}),
   164  			},
   165  			Data: utils.MarshalOrPanic(configUpdateEnvelope),
   166  		}),
   167  	}
   168  
   169  	logger.Info("Writing anchor peer update")
   170  	err := ioutil.WriteFile(outputAnchorPeersUpdate, utils.MarshalOrPanic(update), 0644)
   171  	if err != nil {
   172  		return fmt.Errorf("Error writing channel anchor peer update: %s", err)
   173  	}
   174  	return nil
   175  }
   176  
   177  func doInspectBlock(inspectBlock string) error {
   178  	logger.Info("Inspecting block")
   179  	data, err := ioutil.ReadFile(inspectBlock)
   180  	if err != nil {
   181  		return fmt.Errorf("Could not read block %s", inspectBlock)
   182  	}
   183  
   184  	logger.Info("Parsing genesis block")
   185  	block := &cb.Block{}
   186  	err = proto.Unmarshal(data, block)
   187  	if err != nil {
   188  		return fmt.Errorf("Error unmarshaling block: %s", err)
   189  	}
   190  
   191  	ctx, err := utils.ExtractEnvelope(block, 0)
   192  	if err != nil {
   193  		return fmt.Errorf("Error retrieving configtx from block: %s", err)
   194  	}
   195  
   196  	payload, err := utils.UnmarshalPayload(ctx.Payload)
   197  	if err != nil {
   198  		return fmt.Errorf("Error extracting configtx payload: %s", err)
   199  	}
   200  
   201  	if payload.Header == nil {
   202  		return fmt.Errorf("Config block did not contain header")
   203  	}
   204  
   205  	header, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   206  	if err != nil {
   207  		return fmt.Errorf("Error unmarshaling channel header: %s", err)
   208  	}
   209  
   210  	if header.Type != int32(cb.HeaderType_CONFIG) {
   211  		return fmt.Errorf("Bad header type: %d", header.Type)
   212  	}
   213  
   214  	configEnvelope, err := configtx.UnmarshalConfigEnvelope(payload.Data)
   215  	if err != nil {
   216  		return fmt.Errorf("Bad configuration envelope")
   217  	}
   218  
   219  	if configEnvelope.Config == nil {
   220  		return fmt.Errorf("ConfigEnvelope contained no config")
   221  	}
   222  
   223  	configAsJSON, err := configGroupAsJSON(configEnvelope.Config.ChannelGroup)
   224  	if err != nil {
   225  		return err
   226  	}
   227  
   228  	fmt.Printf("Config for channel: %s at sequence %d\n", header.ChannelId, configEnvelope.Config.Sequence)
   229  	fmt.Println(configAsJSON)
   230  
   231  	return nil
   232  }
   233  
   234  func configGroupAsJSON(group *cb.ConfigGroup) (string, error) {
   235  	configResult, err := configtx.NewConfigResult(group, configtx.NewInitializer())
   236  	if err != nil {
   237  		return "", fmt.Errorf("Error parsing config: %s", err)
   238  	}
   239  
   240  	buffer := &bytes.Buffer{}
   241  	err = json.Indent(buffer, []byte(configResult.JSON()), "", "    ")
   242  	if err != nil {
   243  		return "", fmt.Errorf("Error in output JSON (usually a programming bug): %s", err)
   244  	}
   245  	return buffer.String(), nil
   246  }
   247  
   248  func doInspectChannelCreateTx(inspectChannelCreateTx string) error {
   249  	logger.Info("Inspecting transaction")
   250  	data, err := ioutil.ReadFile(inspectChannelCreateTx)
   251  	if err != nil {
   252  		return fmt.Errorf("could not read channel create tx: %s", err)
   253  	}
   254  
   255  	logger.Info("Parsing transaction")
   256  	env, err := utils.UnmarshalEnvelope(data)
   257  	if err != nil {
   258  		return fmt.Errorf("Error unmarshaling envelope: %s", err)
   259  	}
   260  
   261  	payload, err := utils.UnmarshalPayload(env.Payload)
   262  	if err != nil {
   263  		return fmt.Errorf("Error extracting configtx payload: %s", err)
   264  	}
   265  
   266  	if payload.Header == nil {
   267  		return fmt.Errorf("Config block did not contain header")
   268  	}
   269  
   270  	header, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   271  	if err != nil {
   272  		return fmt.Errorf("Error unmarshaling channel header: %s", err)
   273  	}
   274  
   275  	if header.Type != int32(cb.HeaderType_CONFIG_UPDATE) {
   276  		return fmt.Errorf("Bad header type: %d", header.Type)
   277  	}
   278  
   279  	configUpdateEnvelope, err := configtx.UnmarshalConfigUpdateEnvelope(payload.Data)
   280  	if err != nil {
   281  		return fmt.Errorf("Bad ConfigUpdateEnvelope")
   282  	}
   283  
   284  	configUpdate, err := configtx.UnmarshalConfigUpdate(configUpdateEnvelope.ConfigUpdate)
   285  	if err != nil {
   286  		return fmt.Errorf("ConfigUpdateEnvelope contained no config")
   287  	}
   288  
   289  	if configUpdate.ChannelId != header.ChannelId {
   290  		return fmt.Errorf("ConfigUpdateEnvelope was for different channel than envelope: %s vs %s", configUpdate.ChannelId, header.ChannelId)
   291  	}
   292  
   293  	fmt.Printf("\nChannel creation for channel: %s\n", header.ChannelId)
   294  	fmt.Println()
   295  
   296  	if configUpdate.ReadSet == nil {
   297  		fmt.Println("Read Set: empty")
   298  	} else {
   299  		fmt.Println("Read Set:")
   300  		readSetAsJSON, err := configGroupAsJSON(configUpdate.ReadSet)
   301  		if err != nil {
   302  			return err
   303  		}
   304  		fmt.Println(readSetAsJSON)
   305  	}
   306  	fmt.Println()
   307  
   308  	if configUpdate.WriteSet == nil {
   309  		return fmt.Errorf("Empty WriteSet")
   310  	}
   311  
   312  	fmt.Println("Write Set:")
   313  	writeSetAsJSON, err := configGroupAsJSON(configUpdate.WriteSet)
   314  	if err != nil {
   315  		return err
   316  	}
   317  	fmt.Println(writeSetAsJSON)
   318  	fmt.Println()
   319  
   320  	readSetMap, err := configtx.MapConfig(configUpdate.ReadSet)
   321  	if err != nil {
   322  		return fmt.Errorf("Error mapping read set: %s", err)
   323  	}
   324  	writeSetMap, err := configtx.MapConfig(configUpdate.WriteSet)
   325  	if err != nil {
   326  		return fmt.Errorf("Error mapping write set: %s", err)
   327  	}
   328  
   329  	fmt.Println("Delta Set:")
   330  	deltaSet := configtx.ComputeDeltaSet(readSetMap, writeSetMap)
   331  	for key := range deltaSet {
   332  		fmt.Println(key)
   333  	}
   334  	fmt.Println()
   335  
   336  	return nil
   337  }
   338  
   339  func main() {
   340  	var outputBlock, outputChannelCreateTx, profile, channelID, inspectBlock, inspectChannelCreateTx, outputAnchorPeersUpdate, asOrg string
   341  
   342  	flag.StringVar(&outputBlock, "outputBlock", "", "The path to write the genesis block to (if set)")
   343  	flag.StringVar(&channelID, "channelID", provisional.TestChainID, "The channel ID to use in the configtx")
   344  	flag.StringVar(&outputChannelCreateTx, "outputCreateChannelTx", "", "The path to write a channel creation configtx to (if set)")
   345  	flag.StringVar(&profile, "profile", genesisconfig.SampleInsecureProfile, "The profile from configtx.yaml to use for generation.")
   346  	flag.StringVar(&inspectBlock, "inspectBlock", "", "Prints the configuration contained in the block at the specified path")
   347  	flag.StringVar(&inspectChannelCreateTx, "inspectChannelCreateTx", "", "Prints the configuration contained in the transaction at the specified path")
   348  	flag.StringVar(&outputAnchorPeersUpdate, "outputAnchorPeersUpdate", "", "Creates an config update to update an anchor peer (works only with the default channel creation, and only for the first update)")
   349  	flag.StringVar(&asOrg, "asOrg", "", "Performs the config generation as a particular organization (by name), only including values in the write set that org (likely) has privilege to set")
   350  
   351  	version := flag.Bool("version", false, "Show version information")
   352  
   353  	flag.Parse()
   354  
   355  	// show version
   356  	if *version {
   357  		printVersion()
   358  		os.Exit(exitCode)
   359  	}
   360  
   361  	logging.SetLevel(logging.INFO, "")
   362  
   363  	// don't need to panic when running via command line
   364  	defer func() {
   365  		if err := recover(); err != nil {
   366  			if strings.Contains(fmt.Sprint(err), "Error reading configuration: Unsupported Config Type") {
   367  				logger.Error("Could not find configtx.yaml. " +
   368  					"Please make sure that FABRIC_CFG_PATH is set to a path " +
   369  					"which contains configtx.yaml")
   370  			}
   371  			os.Exit(1)
   372  		}
   373  	}()
   374  
   375  	logger.Info("Loading configuration")
   376  	factory.InitFactories(nil)
   377  	config := genesisconfig.Load(profile)
   378  
   379  	if outputBlock != "" {
   380  		if err := doOutputBlock(config, channelID, outputBlock); err != nil {
   381  			logger.Fatalf("Error on outputBlock: %s", err)
   382  		}
   383  	}
   384  
   385  	if outputChannelCreateTx != "" {
   386  		if err := doOutputChannelCreateTx(config, channelID, outputChannelCreateTx); err != nil {
   387  			logger.Fatalf("Error on outputChannelCreateTx: %s", err)
   388  		}
   389  	}
   390  
   391  	if inspectBlock != "" {
   392  		if err := doInspectBlock(inspectBlock); err != nil {
   393  			logger.Fatalf("Error on inspectBlock: %s", err)
   394  		}
   395  	}
   396  
   397  	if inspectChannelCreateTx != "" {
   398  		if err := doInspectChannelCreateTx(inspectChannelCreateTx); err != nil {
   399  			logger.Fatalf("Error on inspectChannelCreateTx: %s", err)
   400  		}
   401  	}
   402  
   403  	if outputAnchorPeersUpdate != "" {
   404  		if err := doOutputAnchorPeersUpdate(config, channelID, outputAnchorPeersUpdate, asOrg); err != nil {
   405  			logger.Fatalf("Error on inspectChannelCreateTx: %s", err)
   406  		}
   407  	}
   408  }
   409  
   410  func printVersion() {
   411  	fmt.Println(metadata.GetVersionInfo())
   412  }