github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/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 length 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  	if err := validateConfigID(cg.key); err != nil {
    63  		return fmt.Errorf("Illegal characters in key: %s", fqPath)
    64  	}
    65  
    66  	if len(cg.path) == 0 {
    67  		fqPath += PathSeparator + cg.key
    68  	} else {
    69  		fqPath += PathSeparator + strings.Join(cg.path, PathSeparator) + PathSeparator + cg.key
    70  	}
    71  
    72  	logger.Debugf("Adding to config map: %s", fqPath)
    73  
    74  	result[fqPath] = cg
    75  
    76  	return nil
    77  }
    78  
    79  // recurseConfig is used only internally by MapConfig
    80  func recurseConfig(result map[string]comparable, path []string, group *cb.ConfigGroup) error {
    81  	if err := addToMap(comparable{key: path[len(path)-1], path: path[:len(path)-1], ConfigGroup: group}, result); err != nil {
    82  		return err
    83  	}
    84  
    85  	for key, group := range group.Groups {
    86  		nextPath := append(path, key)
    87  		if err := recurseConfig(result, nextPath, group); err != nil {
    88  			return err
    89  		}
    90  	}
    91  
    92  	for key, value := range group.Values {
    93  		if err := addToMap(comparable{key: key, path: path, ConfigValue: value}, result); err != nil {
    94  			return err
    95  		}
    96  	}
    97  
    98  	for key, policy := range group.Policies {
    99  		if err := addToMap(comparable{key: key, path: path, ConfigPolicy: policy}, result); err != nil {
   100  			return err
   101  		}
   102  	}
   103  
   104  	return nil
   105  }
   106  
   107  // configMapToConfig is intended to be called from outside this file
   108  // It takes a configMap and converts it back into a *cb.ConfigGroup structure
   109  func configMapToConfig(configMap map[string]comparable) (*cb.ConfigGroup, error) {
   110  	rootPath := PathSeparator + RootGroupKey
   111  	return recurseConfigMap(rootPath, configMap)
   112  }
   113  
   114  // recurseConfigMap is used only internally by configMapToConfig
   115  // Note, this function mutates the cb.Config* entrieswithin configMap, so errors are generally fatal
   116  func recurseConfigMap(path string, configMap map[string]comparable) (*cb.ConfigGroup, error) {
   117  	groupPath := GroupPrefix + path
   118  	group, ok := configMap[groupPath]
   119  	if !ok {
   120  		return nil, fmt.Errorf("Missing group at path: %s", groupPath)
   121  	}
   122  
   123  	if group.ConfigGroup == nil {
   124  		return nil, fmt.Errorf("ConfigGroup not found at group path: %s", groupPath)
   125  	}
   126  
   127  	for key, _ := range group.Groups {
   128  		updatedGroup, err := recurseConfigMap(path+PathSeparator+key, configMap)
   129  		if err != nil {
   130  			return nil, err
   131  		}
   132  		group.Groups[key] = updatedGroup
   133  	}
   134  
   135  	for key, _ := range group.Values {
   136  		valuePath := ValuePrefix + path + PathSeparator + key
   137  		value, ok := configMap[valuePath]
   138  		if !ok {
   139  			return nil, fmt.Errorf("Missing value at path: %s", valuePath)
   140  		}
   141  		if value.ConfigValue == nil {
   142  			return nil, fmt.Errorf("ConfigValue not found at value path: %s", valuePath)
   143  		}
   144  		group.Values[key] = value.ConfigValue
   145  	}
   146  
   147  	for key, _ := range group.Policies {
   148  		policyPath := PolicyPrefix + path + PathSeparator + key
   149  		policy, ok := configMap[policyPath]
   150  		if !ok {
   151  			return nil, fmt.Errorf("Missing policy at path: %s", policyPath)
   152  		}
   153  		if policy.ConfigPolicy == nil {
   154  			return nil, fmt.Errorf("ConfigPolicy not found at policy path: %s", policyPath)
   155  		}
   156  		group.Policies[key] = policy.ConfigPolicy
   157  	}
   158  
   159  	return group.ConfigGroup, nil
   160  }