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