github.com/yimialmonte/fabric@v2.1.1+incompatible/common/configtx/configmap.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package configtx
     8  
     9  import (
    10  	"strings"
    11  
    12  	"github.com/golang/protobuf/proto"
    13  	cb "github.com/hyperledger/fabric-protos-go/common"
    14  	"github.com/hyperledger/fabric/protoutil"
    15  	"github.com/pkg/errors"
    16  )
    17  
    18  const (
    19  	groupPrefix  = "[Group]  "
    20  	valuePrefix  = "[Value]  "
    21  	policyPrefix = "[Policy] "
    22  
    23  	pathSeparator = "/"
    24  
    25  	// Hacky fix constants, used in recurseConfigMap
    26  	hackyFixOrdererCapabilities = "[Value]  /Channel/Orderer/Capabilities"
    27  	hackyFixNewModPolicy        = "Admins"
    28  )
    29  
    30  // mapConfig is intended to be called outside this file
    31  // it takes a ConfigGroup and generates a map of fqPath to comparables (or error on invalid keys)
    32  func mapConfig(channelGroup *cb.ConfigGroup, rootGroupKey string) (map[string]comparable, error) {
    33  	result := make(map[string]comparable)
    34  	if channelGroup != nil {
    35  		err := recurseConfig(result, []string{rootGroupKey}, channelGroup)
    36  		if err != nil {
    37  			return nil, err
    38  		}
    39  	}
    40  	return result, nil
    41  }
    42  
    43  // addToMap is used only internally by mapConfig
    44  func addToMap(cg comparable, result map[string]comparable) error {
    45  	var fqPath string
    46  
    47  	switch {
    48  	case cg.ConfigGroup != nil:
    49  		fqPath = groupPrefix
    50  	case cg.ConfigValue != nil:
    51  		fqPath = valuePrefix
    52  	case cg.ConfigPolicy != nil:
    53  		fqPath = policyPrefix
    54  	}
    55  
    56  	if err := validateConfigID(cg.key); err != nil {
    57  		return errors.WithMessagef(err, "illegal characters in key: %s", fqPath)
    58  	}
    59  
    60  	if len(cg.path) == 0 {
    61  		fqPath += pathSeparator + cg.key
    62  	} else {
    63  		fqPath += pathSeparator + strings.Join(cg.path, pathSeparator) + pathSeparator + cg.key
    64  	}
    65  
    66  	logger.Debugf("Adding to config map: %s", fqPath)
    67  
    68  	result[fqPath] = cg
    69  
    70  	return nil
    71  }
    72  
    73  // recurseConfig is used only internally by mapConfig
    74  func recurseConfig(result map[string]comparable, path []string, group *cb.ConfigGroup) error {
    75  	if err := addToMap(comparable{key: path[len(path)-1], path: path[:len(path)-1], ConfigGroup: group}, result); err != nil {
    76  		return err
    77  	}
    78  
    79  	for key, group := range group.Groups {
    80  		nextPath := make([]string, len(path)+1)
    81  		copy(nextPath, path)
    82  		nextPath[len(nextPath)-1] = key
    83  		if err := recurseConfig(result, nextPath, group); err != nil {
    84  			return err
    85  		}
    86  	}
    87  
    88  	for key, value := range group.Values {
    89  		if err := addToMap(comparable{key: key, path: path, ConfigValue: value}, result); err != nil {
    90  			return err
    91  		}
    92  	}
    93  
    94  	for key, policy := range group.Policies {
    95  		if err := addToMap(comparable{key: key, path: path, ConfigPolicy: policy}, result); err != nil {
    96  			return err
    97  		}
    98  	}
    99  
   100  	return nil
   101  }
   102  
   103  // configMapToConfig is intended to be called from outside this file
   104  // It takes a configMap and converts it back into a *cb.ConfigGroup structure
   105  func configMapToConfig(configMap map[string]comparable, rootGroupKey string) (*cb.ConfigGroup, error) {
   106  	rootPath := pathSeparator + rootGroupKey
   107  	return recurseConfigMap(rootPath, configMap)
   108  }
   109  
   110  // recurseConfigMap is used only internally by configMapToConfig
   111  // Note, this function no longer mutates the cb.Config* entries within configMap
   112  func recurseConfigMap(path string, configMap map[string]comparable) (*cb.ConfigGroup, error) {
   113  	groupPath := groupPrefix + path
   114  	group, ok := configMap[groupPath]
   115  	if !ok {
   116  		return nil, errors.Errorf("missing group at path: %s", groupPath)
   117  	}
   118  
   119  	if group.ConfigGroup == nil {
   120  		return nil, errors.Errorf("ConfigGroup not found at group path: %s", groupPath)
   121  	}
   122  
   123  	newConfigGroup := protoutil.NewConfigGroup()
   124  	proto.Merge(newConfigGroup, group.ConfigGroup)
   125  
   126  	for key := range group.Groups {
   127  		updatedGroup, err := recurseConfigMap(path+pathSeparator+key, configMap)
   128  		if err != nil {
   129  			return nil, err
   130  		}
   131  		newConfigGroup.Groups[key] = updatedGroup
   132  	}
   133  
   134  	for key := range group.Values {
   135  		valuePath := valuePrefix + path + pathSeparator + key
   136  		value, ok := configMap[valuePath]
   137  		if !ok {
   138  			return nil, errors.Errorf("missing value at path: %s", valuePath)
   139  		}
   140  		if value.ConfigValue == nil {
   141  			return nil, errors.Errorf("ConfigValue not found at value path: %s", valuePath)
   142  		}
   143  		newConfigGroup.Values[key] = proto.Clone(value.ConfigValue).(*cb.ConfigValue)
   144  	}
   145  
   146  	for key := range group.Policies {
   147  		policyPath := policyPrefix + path + pathSeparator + key
   148  		policy, ok := configMap[policyPath]
   149  		if !ok {
   150  			return nil, errors.Errorf("missing policy at path: %s", policyPath)
   151  		}
   152  		if policy.ConfigPolicy == nil {
   153  			return nil, errors.Errorf("ConfigPolicy not found at policy path: %s", policyPath)
   154  		}
   155  		newConfigGroup.Policies[key] = proto.Clone(policy.ConfigPolicy).(*cb.ConfigPolicy)
   156  		logger.Debugf("Setting policy for key %s to %+v", key, group.Policies[key])
   157  	}
   158  
   159  	// This is a really very hacky fix to facilitate upgrading channels which were constructed
   160  	// using the channel generation from v1.0 with bugs FAB-5309, and FAB-6080.
   161  	// In summary, these channels were constructed with a bug which left mod_policy unset in some cases.
   162  	// If mod_policy is unset, it's impossible to modify the element, and current code disallows
   163  	// unset mod_policy values.  This hack 'fixes' existing config with empty mod_policy values.
   164  	// If the capabilities framework is on, it sets any unset mod_policy to 'Admins'.
   165  	// This code needs to sit here until validation of v1.0 channels is deprecated from the codebase.
   166  	if _, ok := configMap[hackyFixOrdererCapabilities]; ok {
   167  		// Hacky fix constants, used in recurseConfigMap
   168  		if newConfigGroup.ModPolicy == "" {
   169  			logger.Debugf("Performing upgrade of group %s empty mod_policy", groupPath)
   170  			newConfigGroup.ModPolicy = hackyFixNewModPolicy
   171  		}
   172  
   173  		for key, value := range newConfigGroup.Values {
   174  			if value.ModPolicy == "" {
   175  				logger.Debugf("Performing upgrade of value %s empty mod_policy", valuePrefix+path+pathSeparator+key)
   176  				value.ModPolicy = hackyFixNewModPolicy
   177  			}
   178  		}
   179  
   180  		for key, policy := range newConfigGroup.Policies {
   181  			if policy.ModPolicy == "" {
   182  				logger.Debugf("Performing upgrade of policy %s empty mod_policy", policyPrefix+path+pathSeparator+key)
   183  
   184  				policy.ModPolicy = hackyFixNewModPolicy
   185  			}
   186  		}
   187  	}
   188  
   189  	return newConfigGroup, nil
   190  }