github.com/yacovm/fabric@v2.0.0-alpha.0.20191128145320-c5d4087dc723+incompatible/common/configtx/configmap.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package configtx 8 9 import ( 10 "strings" 11 12 "github.com/golang/protobuf/proto" 13 cb "github.com/hyperledger/fabric-protos-go/common" 14 "github.com/hyperledger/fabric/protoutil" 15 "github.com/pkg/errors" 16 ) 17 18 const ( 19 groupPrefix = "[Group] " 20 valuePrefix = "[Value] " 21 policyPrefix = "[Policy] " 22 23 pathSeparator = "/" 24 25 // Hacky fix constants, used in recurseConfigMap 26 hackyFixOrdererCapabilities = "[Value] /Channel/Orderer/Capabilities" 27 hackyFixNewModPolicy = "Admins" 28 ) 29 30 // mapConfig is intended to be called outside this file 31 // it takes a ConfigGroup and generates a map of fqPath to comparables (or error on invalid keys) 32 func mapConfig(channelGroup *cb.ConfigGroup, rootGroupKey string) (map[string]comparable, error) { 33 result := make(map[string]comparable) 34 if channelGroup != nil { 35 err := recurseConfig(result, []string{rootGroupKey}, channelGroup) 36 if err != nil { 37 return nil, err 38 } 39 } 40 return result, nil 41 } 42 43 // addToMap is used only internally by mapConfig 44 func addToMap(cg comparable, result map[string]comparable) error { 45 var fqPath string 46 47 switch { 48 case cg.ConfigGroup != nil: 49 fqPath = groupPrefix 50 case cg.ConfigValue != nil: 51 fqPath = valuePrefix 52 case cg.ConfigPolicy != nil: 53 fqPath = policyPrefix 54 } 55 56 if err := validateConfigID(cg.key); err != nil { 57 return errors.WithMessagef(err, "illegal characters in key: %s", fqPath) 58 } 59 60 if len(cg.path) == 0 { 61 fqPath += pathSeparator + cg.key 62 } else { 63 fqPath += pathSeparator + strings.Join(cg.path, pathSeparator) + pathSeparator + cg.key 64 } 65 66 logger.Debugf("Adding to config map: %s", fqPath) 67 68 result[fqPath] = cg 69 70 return nil 71 } 72 73 // recurseConfig is used only internally by mapConfig 74 func recurseConfig(result map[string]comparable, path []string, group *cb.ConfigGroup) error { 75 if err := addToMap(comparable{key: path[len(path)-1], path: path[:len(path)-1], ConfigGroup: group}, result); err != nil { 76 return err 77 } 78 79 for key, group := range group.Groups { 80 nextPath := make([]string, len(path)+1) 81 copy(nextPath, path) 82 nextPath[len(nextPath)-1] = key 83 if err := recurseConfig(result, nextPath, group); err != nil { 84 return err 85 } 86 } 87 88 for key, value := range group.Values { 89 if err := addToMap(comparable{key: key, path: path, ConfigValue: value}, result); err != nil { 90 return err 91 } 92 } 93 94 for key, policy := range group.Policies { 95 if err := addToMap(comparable{key: key, path: path, ConfigPolicy: policy}, result); err != nil { 96 return err 97 } 98 } 99 100 return nil 101 } 102 103 // configMapToConfig is intended to be called from outside this file 104 // It takes a configMap and converts it back into a *cb.ConfigGroup structure 105 func configMapToConfig(configMap map[string]comparable, rootGroupKey string) (*cb.ConfigGroup, error) { 106 rootPath := pathSeparator + rootGroupKey 107 return recurseConfigMap(rootPath, configMap) 108 } 109 110 // recurseConfigMap is used only internally by configMapToConfig 111 // Note, this function no longer mutates the cb.Config* entries within configMap 112 func recurseConfigMap(path string, configMap map[string]comparable) (*cb.ConfigGroup, error) { 113 groupPath := groupPrefix + path 114 group, ok := configMap[groupPath] 115 if !ok { 116 return nil, errors.Errorf("missing group at path: %s", groupPath) 117 } 118 119 if group.ConfigGroup == nil { 120 return nil, errors.Errorf("ConfigGroup not found at group path: %s", groupPath) 121 } 122 123 newConfigGroup := protoutil.NewConfigGroup() 124 proto.Merge(newConfigGroup, group.ConfigGroup) 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 newConfigGroup.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, errors.Errorf("missing value at path: %s", valuePath) 139 } 140 if value.ConfigValue == nil { 141 return nil, errors.Errorf("ConfigValue not found at value path: %s", valuePath) 142 } 143 newConfigGroup.Values[key] = proto.Clone(value.ConfigValue).(*cb.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, errors.Errorf("missing policy at path: %s", policyPath) 151 } 152 if policy.ConfigPolicy == nil { 153 return nil, errors.Errorf("ConfigPolicy not found at policy path: %s", policyPath) 154 } 155 newConfigGroup.Policies[key] = proto.Clone(policy.ConfigPolicy).(*cb.ConfigPolicy) 156 logger.Debugf("Setting policy for key %s to %+v", key, group.Policies[key]) 157 } 158 159 // This is a really very hacky fix to facilitate upgrading channels which were constructed 160 // using the channel generation from v1.0 with bugs FAB-5309, and FAB-6080. 161 // In summary, these channels were constructed with a bug which left mod_policy unset in some cases. 162 // If mod_policy is unset, it's impossible to modify the element, and current code disallows 163 // unset mod_policy values. This hack 'fixes' existing config with empty mod_policy values. 164 // If the capabilities framework is on, it sets any unset mod_policy to 'Admins'. 165 // This code needs to sit here until validation of v1.0 channels is deprecated from the codebase. 166 if _, ok := configMap[hackyFixOrdererCapabilities]; ok { 167 // Hacky fix constants, used in recurseConfigMap 168 if newConfigGroup.ModPolicy == "" { 169 logger.Debugf("Performing upgrade of group %s empty mod_policy", groupPath) 170 newConfigGroup.ModPolicy = hackyFixNewModPolicy 171 } 172 173 for key, value := range newConfigGroup.Values { 174 if value.ModPolicy == "" { 175 logger.Debugf("Performing upgrade of value %s empty mod_policy", valuePrefix+path+pathSeparator+key) 176 value.ModPolicy = hackyFixNewModPolicy 177 } 178 } 179 180 for key, policy := range newConfigGroup.Policies { 181 if policy.ModPolicy == "" { 182 logger.Debugf("Performing upgrade of policy %s empty mod_policy", policyPrefix+path+pathSeparator+key) 183 184 policy.ModPolicy = hackyFixNewModPolicy 185 } 186 } 187 } 188 189 return newConfigGroup, nil 190 }