github.com/IBM-Blockchain/fabric-operator@v1.0.4/pkg/migrator/peer/fabric/v2/peer.go (about) 1 /* 2 * Copyright contributors to the Hyperledger Fabric Operator project 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at: 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 package v2 20 21 import ( 22 "context" 23 "fmt" 24 "reflect" 25 "strings" 26 27 "github.com/pkg/errors" 28 29 current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" 30 config "github.com/IBM-Blockchain/fabric-operator/operatorconfig" 31 "github.com/IBM-Blockchain/fabric-operator/pkg/action" 32 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/common" 33 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/deployer" 34 v2peer "github.com/IBM-Blockchain/fabric-operator/pkg/apis/peer/v2" 35 initializer "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/peer" 36 v2config "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/peer/config/v2" 37 k8sclient "github.com/IBM-Blockchain/fabric-operator/pkg/k8s/controllerclient" 38 ver "github.com/IBM-Blockchain/fabric-operator/version" 39 40 appsv1 "k8s.io/api/apps/v1" 41 corev1 "k8s.io/api/core/v1" 42 "k8s.io/apimachinery/pkg/api/resource" 43 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 44 "k8s.io/apimachinery/pkg/runtime" 45 "k8s.io/apimachinery/pkg/types" 46 47 "sigs.k8s.io/controller-runtime/pkg/client" 48 logf "sigs.k8s.io/controller-runtime/pkg/log" 49 "sigs.k8s.io/yaml" 50 ) 51 52 var log = logf.Log.WithName("peer_fabric_migrator") 53 54 //go:generate counterfeiter -o mocks/configmapmanager.go -fake-name ConfigMapManager . ConfigMapManager 55 type ConfigMapManager interface { 56 GetCoreConfig(*current.IBPPeer) (*corev1.ConfigMap, error) 57 CreateOrUpdate(*current.IBPPeer, initializer.CoreConfig) error 58 } 59 60 //go:generate counterfeiter -o mocks/deploymentmanager.go -fake-name DeploymentManager . DeploymentManager 61 type DeploymentManager interface { 62 Get(metav1.Object) (client.Object, error) 63 Delete(metav1.Object) error 64 DeploymentStatus(metav1.Object) (appsv1.DeploymentStatus, error) 65 GetScheme() *runtime.Scheme 66 } 67 68 type Migrate struct { 69 DeploymentManager DeploymentManager 70 ConfigMapManager ConfigMapManager 71 Client k8sclient.Client 72 } 73 74 func (m *Migrate) MigrationNeeded(instance metav1.Object) bool { 75 // Check for DinD container, if DinD container not found this is 76 // v2 fabric IBP instance 77 obj, err := m.DeploymentManager.Get(instance) 78 if err != nil { 79 // If deployment does not exist, this instance is not a healthy 80 // state and migration should be avoided 81 return false 82 } 83 84 var deploymentUpdated bool 85 var configUpdated bool 86 87 dep := obj.(*appsv1.Deployment) 88 for _, cont := range dep.Spec.Template.Spec.Containers { 89 if strings.ToLower(cont.Name) == "dind" { 90 // DinD container found, instance is not at v2 91 deploymentUpdated = false 92 } 93 } 94 95 cm, err := m.ConfigMapManager.GetCoreConfig(instance.(*current.IBPPeer)) 96 if err != nil { 97 // If config map does not exist, this instance is not a healthy 98 // state and migration should be avoided 99 return false 100 } 101 102 v1corebytes := cm.BinaryData["core.yaml"] 103 104 core := &v2config.Core{} 105 err = yaml.Unmarshal(v1corebytes, core) 106 if err != nil { 107 return false 108 } 109 110 configUpdated = configHasBeenUpdated(core) 111 112 return !deploymentUpdated || !configUpdated 113 } 114 115 func (m *Migrate) UpgradeDBs(instance metav1.Object, timeouts config.DBMigrationTimeouts) error { 116 log.Info(fmt.Sprintf("Resetting Peer '%s'", instance.GetName())) 117 return action.UpgradeDBs(m.DeploymentManager, m.Client, instance.(*current.IBPPeer), timeouts) 118 } 119 120 func (m *Migrate) UpdateConfig(instance metav1.Object, version string) error { 121 log.Info("Updating config to v2") 122 cm, err := m.ConfigMapManager.GetCoreConfig(instance.(*current.IBPPeer)) 123 if err != nil { 124 return errors.Wrap(err, "failed to get config map") 125 } 126 v1corebytes := cm.BinaryData["core.yaml"] 127 128 core := &v2config.Core{} 129 err = yaml.Unmarshal(v1corebytes, core) 130 if err != nil { 131 return err 132 } 133 134 // resetting VM endpoint 135 // As per this PR #2165, VM and Ledger structs been added to Peer. endpoint is not required for v2 peer as there is no DinD 136 core.VM.Endpoint = "" 137 138 core.Chaincode.ExternalBuilders = []v2peer.ExternalBuilder{ 139 v2peer.ExternalBuilder{ 140 Name: "ibp-builder", 141 Path: "/usr/local", 142 EnvironmentWhiteList: []string{ 143 "IBP_BUILDER_ENDPOINT", 144 "IBP_BUILDER_SHARED_DIR", 145 }, 146 PropogateEnvironment: []string{ 147 "IBP_BUILDER_ENDPOINT", 148 "IBP_BUILDER_SHARED_DIR", 149 "PEER_NAME", 150 }, 151 }, 152 } 153 154 core.Chaincode.InstallTimeout = common.MustParseDuration("300s") 155 if core.Chaincode.System == nil { 156 core.Chaincode.System = make(map[string]string) 157 } 158 core.Chaincode.System["_lifecycle"] = "enable" 159 160 core.Peer.Limits.Concurrency.DeliverService = 2500 161 core.Peer.Limits.Concurrency.EndorserService = 2500 162 163 core.Peer.Gossip.PvtData.ImplicitCollectionDisseminationPolicy.RequiredPeerCount = 0 164 core.Peer.Gossip.PvtData.ImplicitCollectionDisseminationPolicy.MaxPeerCount = 1 165 166 currentVer := ver.String(version) 167 if currentVer.EqualWithoutTag(ver.V2_4_1) || currentVer.GreaterThan(ver.V2_4_1) { 168 trueVal := true 169 core.Peer.Gateway = v2peer.Gateway{ 170 Enabled: &trueVal, 171 EndorsementTimeout: common.MustParseDuration("30s"), 172 DialTimeout: common.MustParseDuration("120s"), 173 } 174 core.Peer.Limits.Concurrency.GatewayService = 500 175 core.Ledger.State.SnapShots = v2peer.SnapShots{ 176 RootDir: "/data/peer/ledgersData/snapshots/", 177 } 178 } 179 180 core.Ledger.State.CouchdbConfig.CacheSize = 64 181 core.Ledger.State.CouchdbConfig.MaxRetries = 10 182 183 err = m.ConfigMapManager.CreateOrUpdate(instance.(*current.IBPPeer), core) 184 if err != nil { 185 return err 186 } 187 188 return nil 189 } 190 191 // SetChaincodeLauncherResourceOnCR will update the peer's CR by adding chaincode launcher 192 // resources. The default resources are defined in deployer's config map, which is part 193 // IBPConsole resource. The default resources are extracted for the chaincode launcher 194 // by reading the deployer's config map and updating the CR. 195 func (m *Migrate) SetChaincodeLauncherResourceOnCR(instance metav1.Object) error { 196 log.Info("Setting chaincode launcher resource on CR") 197 cr := instance.(*current.IBPPeer) 198 199 if cr.Spec.Resources != nil && cr.Spec.Resources.CCLauncher != nil { 200 // No need to proceed further if Chaincode launcher resources already set 201 return nil 202 } 203 204 consoleList := ¤t.IBPConsoleList{} 205 if err := m.Client.List(context.TODO(), consoleList); err != nil { 206 return err 207 } 208 consoles := consoleList.Items 209 210 // If no consoles found, set default resource for chaincode launcher container 211 rr := &corev1.ResourceRequirements{ 212 Requests: corev1.ResourceList{ 213 corev1.ResourceCPU: resource.MustParse("0.1"), 214 corev1.ResourceMemory: resource.MustParse("100Mi"), 215 }, 216 Limits: corev1.ResourceList{ 217 corev1.ResourceCPU: resource.MustParse("2"), 218 corev1.ResourceMemory: resource.MustParse("2Gi"), 219 }, 220 } 221 222 if len(consoles) > 0 { 223 log.Info("Setting chaincode launcher resource on CR based on deployer config from config map") 224 // Get config map associated with console 225 cm := &corev1.ConfigMap{} 226 nn := types.NamespacedName{ 227 Name: fmt.Sprintf("%s-deployer", consoles[0].GetName()), 228 Namespace: instance.GetNamespace(), 229 } 230 if err := m.Client.Get(context.TODO(), nn, cm); err != nil { 231 return err 232 } 233 234 settingsBytes := []byte(cm.Data["settings.yaml"]) 235 settings := &deployer.Config{} 236 if err := yaml.Unmarshal(settingsBytes, settings); err != nil { 237 return err 238 } 239 240 if settings.Defaults != nil && settings.Defaults.Resources != nil && 241 settings.Defaults.Resources.Peer != nil && settings.Defaults.Resources.Peer.CCLauncher != nil { 242 243 rr = settings.Defaults.Resources.Peer.CCLauncher 244 } 245 } 246 247 log.Info(fmt.Sprintf("Setting chaincode launcher resource on CR to %+v", rr)) 248 if cr.Spec.Resources == nil { 249 cr.Spec.Resources = ¤t.PeerResources{} 250 } 251 cr.Spec.Resources.CCLauncher = rr 252 if err := m.Client.Update(context.TODO(), cr); err != nil { 253 return err 254 } 255 256 return nil 257 } 258 259 // Updates required from v1.4 to v2.x: 260 // - External builders 261 // - Limits 262 // - Install timeout 263 // - Implicit collection dissemination policy 264 func configHasBeenUpdated(core *v2config.Core) bool { 265 if len(core.Chaincode.ExternalBuilders) == 0 { 266 return false 267 } 268 if core.Chaincode.ExternalBuilders[0].Name != "ibp-builder" { 269 return false 270 } 271 272 // Check if install timeout was set 273 if reflect.DeepEqual(core.Chaincode.InstallTimeout, common.Duration{}) { 274 return false 275 } 276 277 if core.Peer.Limits.Concurrency.DeliverService != 2500 { 278 return false 279 } 280 281 if core.Peer.Limits.Concurrency.EndorserService != 2500 { 282 return false 283 } 284 285 return true 286 }