github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/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  	err := recurseConfig(result, []string{RootGroupKey}, channelGroup)
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  	return result, nil
    45  }
    46  
    47  // addToMap is used only internally by mapConfig
    48  func addToMap(cg comparable, result map[string]comparable) error {
    49  	var fqPath string
    50  
    51  	switch {
    52  	case cg.ConfigGroup != nil:
    53  		fqPath = GroupPrefix
    54  	case cg.ConfigValue != nil:
    55  		fqPath = ValuePrefix
    56  	case cg.ConfigPolicy != nil:
    57  		fqPath = PolicyPrefix
    58  	}
    59  
    60  	// TODO rename validateChainID to validateConfigID
    61  	if err := validateChainID(cg.key); err != nil {
    62  		return fmt.Errorf("Illegal characters in key: %s", fqPath)
    63  	}
    64  
    65  	if len(cg.path) == 0 {
    66  		fqPath += PathSeparator + cg.key
    67  	} else {
    68  		fqPath += PathSeparator + strings.Join(cg.path, PathSeparator) + PathSeparator + cg.key
    69  	}
    70  
    71  	logger.Debugf("Adding to config map: %s", fqPath)
    72  
    73  	result[fqPath] = cg
    74  
    75  	return nil
    76  }
    77  
    78  // recurseConfig is used only internally by mapConfig
    79  func recurseConfig(result map[string]comparable, path []string, group *cb.ConfigGroup) error {
    80  	if err := addToMap(comparable{key: path[len(path)-1], path: path[:len(path)-1], ConfigGroup: group}, result); err != nil {
    81  		return err
    82  	}
    83  
    84  	for key, group := range group.Groups {
    85  		nextPath := append(path, key)
    86  		if err := recurseConfig(result, nextPath, group); err != nil {
    87  			return err
    88  		}
    89  	}
    90  
    91  	for key, value := range group.Values {
    92  		if err := addToMap(comparable{key: key, path: path, ConfigValue: value}, result); err != nil {
    93  			return err
    94  		}
    95  	}
    96  
    97  	for key, policy := range group.Policies {
    98  		if err := addToMap(comparable{key: key, path: path, ConfigPolicy: policy}, result); err != nil {
    99  			return err
   100  		}
   101  	}
   102  
   103  	return nil
   104  }
   105  
   106  // configMapToConfig is intended to be called from outside this file
   107  // It takes a configMap and converts it back into a *cb.ConfigGroup structure
   108  func configMapToConfig(configMap map[string]comparable) (*cb.ConfigGroup, error) {
   109  	rootPath := PathSeparator + RootGroupKey
   110  	return recurseConfigMap(rootPath, configMap)
   111  }
   112  
   113  // recurseConfigMap is used only internally by configMapToConfig
   114  // Note, this function mutates the cb.Config* entrieswithin configMap, so errors are generally fatal
   115  func recurseConfigMap(path string, configMap map[string]comparable) (*cb.ConfigGroup, error) {
   116  	groupPath := GroupPrefix + path
   117  	group, ok := configMap[groupPath]
   118  	if !ok {
   119  		return nil, fmt.Errorf("Missing group at path: %s", groupPath)
   120  	}
   121  
   122  	if group.ConfigGroup == nil {
   123  		return nil, fmt.Errorf("ConfigGroup not found at group path", groupPath)
   124  	}
   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  		group.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, fmt.Errorf("Missing value at path: %s", valuePath)
   139  		}
   140  		if value.ConfigValue == nil {
   141  			return nil, fmt.Errorf("ConfigValue not found at value path", valuePath)
   142  		}
   143  		group.Values[key] = value.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, fmt.Errorf("Missing policy at path: %s", policyPath)
   151  		}
   152  		if policy.ConfigPolicy == nil {
   153  			return nil, fmt.Errorf("ConfigPolicy not found at policy path", policyPath)
   154  		}
   155  		group.Policies[key] = policy.ConfigPolicy
   156  	}
   157  
   158  	return group.ConfigGroup, nil
   159  }