github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/common/configtx/configmap.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 configtx
    18  
    19  import (
    20  	"fmt"
    21  	"strings"
    22  
    23  	cb "github.com/hyperledger/fabric/protos/common"
    24  
    25  	"github.com/golang/protobuf/proto"
    26  )
    27  
    28  const (
    29  	RootGroupKey = "Channel"
    30  
    31  	GroupPrefix  = "[Groups] "
    32  	ValuePrefix  = "[Values] "
    33  	PolicyPrefix = "[Policy] " // The plurarility doesn't match, but, it makes the logs much easier being the same length as "Groups" and "Values"
    34  
    35  	PathSeparator = "/"
    36  )
    37  
    38  // MapConfig is intended to be called outside this file
    39  // it takes a ConfigGroup and generates a map of fqPath to comparables (or error on invalid keys)
    40  func MapConfig(channelGroup *cb.ConfigGroup) (map[string]comparable, error) {
    41  	result := make(map[string]comparable)
    42  	if channelGroup != nil {
    43  		err := recurseConfig(result, []string{RootGroupKey}, channelGroup)
    44  		if err != nil {
    45  			return nil, err
    46  		}
    47  	}
    48  	return result, nil
    49  }
    50  
    51  // addToMap is used only internally by MapConfig
    52  func addToMap(cg comparable, result map[string]comparable) error {
    53  	var fqPath string
    54  
    55  	switch {
    56  	case cg.ConfigGroup != nil:
    57  		fqPath = GroupPrefix
    58  	case cg.ConfigValue != nil:
    59  		fqPath = ValuePrefix
    60  	case cg.ConfigPolicy != nil:
    61  		fqPath = PolicyPrefix
    62  	}
    63  
    64  	if err := validateConfigID(cg.key); err != nil {
    65  		return fmt.Errorf("Illegal characters in key: %s", fqPath)
    66  	}
    67  
    68  	if len(cg.path) == 0 {
    69  		fqPath += PathSeparator + cg.key
    70  	} else {
    71  		fqPath += PathSeparator + strings.Join(cg.path, PathSeparator) + PathSeparator + cg.key
    72  	}
    73  
    74  	logger.Debugf("Adding to config map: %s", fqPath)
    75  
    76  	result[fqPath] = cg
    77  
    78  	return nil
    79  }
    80  
    81  // recurseConfig is used only internally by MapConfig
    82  func recurseConfig(result map[string]comparable, path []string, group *cb.ConfigGroup) error {
    83  	if err := addToMap(comparable{key: path[len(path)-1], path: path[:len(path)-1], ConfigGroup: group}, result); err != nil {
    84  		return err
    85  	}
    86  
    87  	for key, group := range group.Groups {
    88  		nextPath := make([]string, len(path)+1)
    89  		copy(nextPath, path)
    90  		nextPath[len(nextPath)-1] = key
    91  		if err := recurseConfig(result, nextPath, group); err != nil {
    92  			return err
    93  		}
    94  	}
    95  
    96  	for key, value := range group.Values {
    97  		if err := addToMap(comparable{key: key, path: path, ConfigValue: value}, result); err != nil {
    98  			return err
    99  		}
   100  	}
   101  
   102  	for key, policy := range group.Policies {
   103  		if err := addToMap(comparable{key: key, path: path, ConfigPolicy: policy}, result); err != nil {
   104  			return err
   105  		}
   106  	}
   107  
   108  	return nil
   109  }
   110  
   111  // configMapToConfig is intended to be called from outside this file
   112  // It takes a configMap and converts it back into a *cb.ConfigGroup structure
   113  func configMapToConfig(configMap map[string]comparable) (*cb.ConfigGroup, error) {
   114  	rootPath := PathSeparator + RootGroupKey
   115  	return recurseConfigMap(rootPath, configMap)
   116  }
   117  
   118  // recurseConfigMap is used only internally by configMapToConfig
   119  // Note, this function no longer mutates the cb.Config* entries within configMap
   120  func recurseConfigMap(path string, configMap map[string]comparable) (*cb.ConfigGroup, error) {
   121  	groupPath := GroupPrefix + path
   122  	group, ok := configMap[groupPath]
   123  	if !ok {
   124  		return nil, fmt.Errorf("Missing group at path: %s", groupPath)
   125  	}
   126  
   127  	if group.ConfigGroup == nil {
   128  		return nil, fmt.Errorf("ConfigGroup not found at group path: %s", groupPath)
   129  	}
   130  
   131  	newConfigGroup := cb.NewConfigGroup()
   132  	proto.Merge(newConfigGroup, group.ConfigGroup)
   133  
   134  	for key, _ := range group.Groups {
   135  		updatedGroup, err := recurseConfigMap(path+PathSeparator+key, configMap)
   136  		if err != nil {
   137  			return nil, err
   138  		}
   139  		newConfigGroup.Groups[key] = updatedGroup
   140  	}
   141  
   142  	for key, _ := range group.Values {
   143  		valuePath := ValuePrefix + path + PathSeparator + key
   144  		value, ok := configMap[valuePath]
   145  		if !ok {
   146  			return nil, fmt.Errorf("Missing value at path: %s", valuePath)
   147  		}
   148  		if value.ConfigValue == nil {
   149  			return nil, fmt.Errorf("ConfigValue not found at value path: %s", valuePath)
   150  		}
   151  		newConfigGroup.Values[key] = proto.Clone(value.ConfigValue).(*cb.ConfigValue)
   152  	}
   153  
   154  	for key, _ := range group.Policies {
   155  		policyPath := PolicyPrefix + path + PathSeparator + key
   156  		policy, ok := configMap[policyPath]
   157  		if !ok {
   158  			return nil, fmt.Errorf("Missing policy at path: %s", policyPath)
   159  		}
   160  		if policy.ConfigPolicy == nil {
   161  			return nil, fmt.Errorf("ConfigPolicy not found at policy path: %s", policyPath)
   162  		}
   163  		newConfigGroup.Policies[key] = proto.Clone(policy.ConfigPolicy).(*cb.ConfigPolicy)
   164  		logger.Debugf("Setting policy for key %s to %+v", key, group.Policies[key])
   165  	}
   166  
   167  	return newConfigGroup, nil
   168  }