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 }