github.com/openebs/api@v1.12.0/pkg/apis/cstor/v1/cstorvolumebuilder.go (about) 1 /* 2 Copyright 2020 The OpenEBS Authors 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 ocvtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required cvy applicacvle law or agreed to in writing, software 11 districvuted under the License is districvuted 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 v1 18 19 import ( 20 "fmt" 21 "strings" 22 23 "github.com/openebs/api/pkg/apis/types" 24 "github.com/openebs/api/pkg/util" 25 "k8s.io/apimachinery/pkg/api/resource" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/klog" 28 ) 29 30 const ( 31 32 //CStorNodeBase nodeBase for cstor volume 33 CStorNodeBase string = "iqn.2016-09.com.openebs.cstor" 34 35 // TargetPort is port for cstor volume 36 TargetPort string = "3260" 37 38 // CStorVolumeReplicaFinalizer is the name of finalizer on CStorVolumeConfig 39 CStorVolumeReplicaFinalizer = "cstorvolumereplica.openebs.io/finalizer" 40 ) 41 42 // NewCStorVolumeConfig returns new instance of CStorVolumeConfig 43 func NewCStorVolumeConfig() *CStorVolumeConfig { 44 return &CStorVolumeConfig{} 45 } 46 47 // WithName sets the Name field of CVC with provided value. 48 func (cvc *CStorVolumeConfig) WithName(name string) *CStorVolumeConfig { 49 cvc.Name = name 50 return cvc 51 } 52 53 // WithNamespace sets the Namespace field of CVC provided arguments 54 func (cvc *CStorVolumeConfig) WithNamespace(namespace string) *CStorVolumeConfig { 55 cvc.Namespace = namespace 56 return cvc 57 } 58 59 // WithAnnotationsNew sets the Annotations field of CVC with provided arguments 60 func (cvc *CStorVolumeConfig) WithAnnotationsNew(annotations map[string]string) *CStorVolumeConfig { 61 cvc.Annotations = make(map[string]string) 62 for key, value := range annotations { 63 cvc.Annotations[key] = value 64 } 65 return cvc 66 } 67 68 // WithAnnotations appends or overwrites existing Annotations 69 // values of CVC with provided arguments 70 func (cvc *CStorVolumeConfig) WithAnnotations(annotations map[string]string) *CStorVolumeConfig { 71 72 if cvc.Annotations == nil { 73 return cvc.WithAnnotationsNew(annotations) 74 } 75 for key, value := range annotations { 76 cvc.Annotations[key] = value 77 } 78 return cvc 79 } 80 81 // WithLabelsNew sets the Lacvels field of CVC with provided arguments 82 func (cvc *CStorVolumeConfig) WithLabelsNew(labels map[string]string) *CStorVolumeConfig { 83 cvc.Labels = make(map[string]string) 84 for key, value := range labels { 85 cvc.Labels[key] = value 86 } 87 return cvc 88 } 89 90 // WithLabels appends or overwrites existing Lacvels 91 // values of CVC with provided arguments 92 func (cvc *CStorVolumeConfig) WithLabels(labels map[string]string) *CStorVolumeConfig { 93 if cvc.Labels == nil { 94 return cvc.WithLabelsNew(labels) 95 } 96 for key, value := range labels { 97 cvc.Labels[key] = value 98 } 99 return cvc 100 } 101 102 // WithFinalizer sets the finalizer field in the CVC 103 func (cvc *CStorVolumeConfig) WithFinalizer(finalizers ...string) *CStorVolumeConfig { 104 cvc.Finalizers = append(cvc.Finalizers, finalizers...) 105 return cvc 106 } 107 108 // WithOwnerReference sets the OwnerReference field in CVC with required 109 //fields 110 func (cvc *CStorVolumeConfig) WithOwnerReference(reference metav1.OwnerReference) *CStorVolumeConfig { 111 cvc.OwnerReferences = append(cvc.OwnerReferences, reference) 112 return cvc 113 } 114 115 // WithNewVersion sets the current and desired version field of 116 // CVC with provided arguments 117 func (cvc *CStorVolumeConfig) WithNewVersion(version string) *CStorVolumeConfig { 118 cvc.VersionDetails.Status.Current = version 119 cvc.VersionDetails.Desired = version 120 return cvc 121 } 122 123 // WithDependentsUpgraded sets the field to true for new CVC 124 func (cvc *CStorVolumeConfig) WithDependentsUpgraded() *CStorVolumeConfig { 125 cvc.VersionDetails.Status.DependentsUpgraded = true 126 return cvc 127 } 128 129 // HasFinalizer returns true if the provided finalizer is present on the ocvject. 130 func (cvc *CStorVolumeConfig) HasFinalizer(finalizer string) bool { 131 finalizersList := cvc.GetFinalizers() 132 return util.ContainsString(finalizersList, finalizer) 133 } 134 135 // RemoveFinalizer removes the given finalizer from the ocvject. 136 func (cvc *CStorVolumeConfig) RemoveFinalizer(finalizer string) { 137 cvc.Finalizers = util.RemoveString(cvc.Finalizers, finalizer) 138 } 139 140 // GetDesiredReplicaPoolNames returns list of desired pool names 141 func GetDesiredReplicaPoolNames(cvc *CStorVolumeConfig) []string { 142 poolNames := []string{} 143 for _, poolInfo := range cvc.Spec.Policy.ReplicaPoolInfo { 144 poolNames = append(poolNames, poolInfo.PoolName) 145 } 146 return poolNames 147 } 148 149 // IsScaleDownInProgress return true if length of status replica details is 150 // greater than length of spec replica details 151 func IsScaleDownInProgress(cv *CStorVolume) bool { 152 return len(cv.Status.ReplicaDetails.KnownReplicas) > 153 len(cv.Spec.ReplicaDetails.KnownReplicas) 154 } 155 156 // ************************************************************************** 157 // 158 // CSTOR VOLUMES 159 // 160 // 161 // ************************************************************************** 162 163 // NewCStorVolume returns new instance of CStorVolume 164 func NewCStorVolume() *CStorVolume { 165 return &CStorVolume{} 166 } 167 168 // NewCStorVolumeObj returns a new instance of cstorvolume 169 func NewCStorVolumeObj(obj *CStorVolume) *CStorVolume { 170 return obj 171 } 172 173 // WithName sets the Name field of CVC with provided value. 174 func (cv *CStorVolume) WithName(name string) *CStorVolume { 175 cv.Name = name 176 return cv 177 } 178 179 // WithNamespace sets the Namespace field of CVC provided arguments 180 func (cv *CStorVolume) WithNamespace(namespace string) *CStorVolume { 181 cv.Namespace = namespace 182 return cv 183 } 184 185 // WithAnnotationsNew sets the Annotations field of CVC with provided arguments 186 func (cv *CStorVolume) WithAnnotationsNew(annotations map[string]string) *CStorVolume { 187 cv.Annotations = make(map[string]string) 188 for key, value := range annotations { 189 cv.Annotations[key] = value 190 } 191 return cv 192 } 193 194 // WithAnnotations appends or overwrites existing Annotations 195 // values of CV with provided arguments 196 func (cv *CStorVolume) WithAnnotations(annotations map[string]string) *CStorVolume { 197 198 if cv.Annotations == nil { 199 return cv.WithAnnotationsNew(annotations) 200 } 201 for key, value := range annotations { 202 cv.Annotations[key] = value 203 } 204 return cv 205 } 206 207 // WithLabelsNew sets the Lacvels field of CV with provided arguments 208 func (cv *CStorVolume) WithLabelsNew(labels map[string]string) *CStorVolume { 209 cv.Labels = make(map[string]string) 210 for key, value := range labels { 211 cv.Labels[key] = value 212 } 213 return cv 214 } 215 216 // WithLabels appends or overwrites existing Lacvels 217 // values of CVC with provided arguments 218 func (cv *CStorVolume) WithLabels(labels map[string]string) *CStorVolume { 219 if cv.Labels == nil { 220 return cv.WithLabelsNew(labels) 221 } 222 for key, value := range labels { 223 cv.Labels[key] = value 224 } 225 return cv 226 } 227 228 // WithFinalizers sets the finalizer field in the CV 229 func (cv *CStorVolume) WithFinalizers(finalizers ...string) *CStorVolume { 230 cv.Finalizers = append(cv.Finalizers, finalizers...) 231 return cv 232 } 233 234 // WithOwnerReference sets the OwnerReference field in CV with required 235 //fields 236 func (cv *CStorVolume) WithOwnerReference(reference []metav1.OwnerReference) *CStorVolume { 237 cv.OwnerReferences = append(cv.OwnerReferences, reference...) 238 return cv 239 } 240 241 // WithTargetIP sets the target IP address field of 242 // CStorVolume with provided arguments 243 func (cv *CStorVolume) WithTargetIP(targetip string) *CStorVolume { 244 cv.Spec.TargetIP = targetip 245 return cv 246 } 247 248 // WithCapacity sets the Capacity field of CStorVolume with provided arguments 249 func (cv *CStorVolume) WithCapacity(capacity string) *CStorVolume { 250 capacityQnt, _ := resource.ParseQuantity(capacity) 251 cv.Spec.Capacity = capacityQnt 252 return cv 253 } 254 255 // WithCStorIQN sets the iqn field of CStorVolume with provided arguments 256 func (cv *CStorVolume) WithCStorIQN(name string) *CStorVolume { 257 iqn := CStorNodeBase + ":" + name 258 cv.Spec.Iqn = iqn 259 return cv 260 } 261 262 // WithTargetPortal sets the TargetPortal field of 263 // CStorVolume with provided arguments 264 func (cv *CStorVolume) WithTargetPortal(targetportal string) *CStorVolume { 265 cv.Spec.TargetPortal = targetportal 266 return cv 267 } 268 269 // WithTargetPort sets the TargetPort field of 270 // CStorVolume with provided arguments 271 func (cv *CStorVolume) WithTargetPort(targetport string) *CStorVolume { 272 cv.Spec.TargetPort = targetport 273 return cv 274 } 275 276 // WithReplicationFactor sets the ReplicationFactor field of 277 // CStorVolume with provided arguments 278 func (cv *CStorVolume) WithReplicationFactor(replicationfactor int) *CStorVolume { 279 cv.Spec.ReplicationFactor = replicationfactor 280 return cv 281 } 282 283 // WithDesiredReplicationFactor sets the DesiredReplicationFactor field of 284 // CStorVolume with provided arguments 285 func (cv *CStorVolume) WithDesiredReplicationFactor(desiredRF int) *CStorVolume { 286 cv.Spec.DesiredReplicationFactor = desiredRF 287 return cv 288 } 289 290 // WithConsistencyFactor sets the ConsistencyFactor field of 291 // CStorVolume with provided arguments 292 func (cv *CStorVolume) WithConsistencyFactor(consistencyfactor int) *CStorVolume { 293 cv.Spec.ConsistencyFactor = consistencyfactor 294 return cv 295 } 296 297 // WithNewVersion sets the current and desired version field of 298 // CV with provided arguments 299 func (cv *CStorVolume) WithNewVersion(version string) *CStorVolume { 300 cv.VersionDetails.Status.Current = version 301 cv.VersionDetails.Desired = version 302 return cv 303 } 304 305 // WithDependentsUpgraded sets the field to true for new CV 306 func (cv *CStorVolume) WithDependentsUpgraded() *CStorVolume { 307 cv.VersionDetails.Status.DependentsUpgraded = true 308 return cv 309 } 310 311 // HasFinalizer returns true if the provided finalizer is present on the ocvject. 312 func (cv *CStorVolume) HasFinalizer(finalizer string) bool { 313 finalizersList := cv.GetFinalizers() 314 return util.ContainsString(finalizersList, finalizer) 315 } 316 317 // RemoveFinalizer removes the given finalizer from the ocvject. 318 func (cv *CStorVolume) RemoveFinalizer(finalizer string) { 319 cv.Finalizers = util.RemoveString(cv.Finalizers, finalizer) 320 } 321 322 // IsResizePending return true if resize is in progress 323 func (cv *CStorVolume) IsResizePending() bool { 324 curCapacity := cv.Status.Capacity 325 desiredCapacity := cv.Spec.Capacity 326 // Cmp returns 0 if the curCapacity is equal to desiredCapacity, 327 // -1 if the curCapacity is less than desiredCapacity, or 1 if the 328 // curCapacity is greater than desiredCapacity. 329 return curCapacity.Cmp(desiredCapacity) == -1 330 } 331 332 // IsDRFPending return true if drf update is required else false 333 // Steps to verify whether drf is required 334 // 1. Read DesiredReplicationFactor configurations from istgt conf file 335 // 2. Compare the value with spec.DesiredReplicationFactor and return result 336 func (cv *CStorVolume) IsDRFPending() bool { 337 fileOperator := util.RealFileOperator{} 338 types.ConfFileMutex.Lock() 339 //If it has proper config then we will get --> " DesiredReplicationFactor 3" 340 i, gotConfig, err := fileOperator.GetLineDetails(types.IstgtConfPath, types.DesiredReplicationFactorKey) 341 types.ConfFileMutex.Unlock() 342 if err != nil || i == -1 { 343 klog.Infof("failed to get %s config details error: %v", 344 types.DesiredReplicationFactorKey, 345 err, 346 ) 347 return false 348 } 349 drfStringValue := fmt.Sprintf(" %d", cv.Spec.DesiredReplicationFactor) 350 // gotConfig will have " DesiredReplicationFactor 3" and we will extract 351 // numeric character from output 352 if !strings.HasSuffix(gotConfig, drfStringValue) { 353 return true 354 } 355 // reconciliation check for replica scaledown scenarion 356 return (len(cv.Spec.ReplicaDetails.KnownReplicas) < 357 len(cv.Status.ReplicaDetails.KnownReplicas)) 358 } 359 360 // GetCVCondition returns corresponding cstorvolume condition based argument passed 361 func (cv *CStorVolume) GetCVCondition( 362 condType CStorVolumeConditionType) CStorVolumeCondition { 363 for _, cond := range cv.Status.Conditions { 364 if condType == cond.Type { 365 return cond 366 } 367 } 368 return CStorVolumeCondition{} 369 } 370 371 // IsConditionPresent returns true if condition is available 372 func (cv *CStorVolume) IsConditionPresent(condType CStorVolumeConditionType) bool { 373 for _, cond := range cv.Status.Conditions { 374 if condType == cond.Type { 375 return true 376 } 377 } 378 return false 379 } 380 381 // AreSpecReplicasHealthy return true if all the spec replicas are in Healthy 382 // state else return false 383 func (cv *CStorVolume) AreSpecReplicasHealthy(volStatus *CVStatus) bool { 384 var isReplicaExist bool 385 var replicaInfo ReplicaStatus 386 for _, replicaValue := range cv.Spec.ReplicaDetails.KnownReplicas { 387 isReplicaExist = false 388 for _, replicaInfo = range volStatus.ReplicaStatuses { 389 if replicaInfo.ID == replicaValue { 390 isReplicaExist = true 391 break 392 } 393 } 394 if (isReplicaExist && replicaInfo.Mode != "Healthy") || !isReplicaExist { 395 return false 396 } 397 } 398 return true 399 } 400 401 // GetRemovingReplicaID return replicaID that present in status but not in spec 402 func (cv *CStorVolume) GetRemovingReplicaID() string { 403 for repID := range cv.Status.ReplicaDetails.KnownReplicas { 404 // If known replica is not exist in spec but if it exist in status then 405 // user/operator selected that replica for removal 406 if _, isReplicaExist := 407 cv.Spec.ReplicaDetails.KnownReplicas[repID]; !isReplicaExist { 408 return string(repID) 409 } 410 } 411 return "" 412 } 413 414 // BuildScaleDownConfigData build data based on replica that needs to remove 415 func (cv *CStorVolume) BuildScaleDownConfigData(repID string) map[string]string { 416 configData := map[string]string{} 417 newReplicationFactor := cv.Spec.DesiredReplicationFactor 418 newConsistencyFactor := (newReplicationFactor / 2) + 1 419 key := fmt.Sprintf(" ReplicationFactor") 420 value := fmt.Sprintf(" ReplicationFactor %d", newReplicationFactor) 421 configData[key] = value 422 key = fmt.Sprintf(" ConsistencyFactor") 423 value = fmt.Sprintf(" ConsistencyFactor %d", newConsistencyFactor) 424 configData[key] = value 425 key = fmt.Sprintf(" DesiredReplicationFactor") 426 value = fmt.Sprintf(" DesiredReplicationFactor %d", 427 cv.Spec.DesiredReplicationFactor) 428 configData[key] = value 429 key = fmt.Sprintf(" Replica %s", repID) 430 value = fmt.Sprintf("") 431 configData[key] = value 432 return configData 433 } 434 435 // Conditions enables building CRUD operations on cstorvolume conditions 436 type Conditions []CStorVolumeCondition 437 438 // AddCondition appends the new condition to existing conditions 439 func (c Conditions) AddCondition(cond CStorVolumeCondition) []CStorVolumeCondition { 440 c = append(c, cond) 441 return c 442 } 443 444 // UpdateCondition updates the condition if it is present in Conditions 445 func (c Conditions) UpdateCondition(cond CStorVolumeCondition) []CStorVolumeCondition { 446 for i, condObj := range c { 447 if condObj.Type == cond.Type { 448 c[i] = cond 449 } 450 } 451 return c 452 } 453 454 // DeleteCondition deletes the condition from conditions 455 func (c Conditions) DeleteCondition(cond CStorVolumeCondition) []CStorVolumeCondition { 456 newConditions := []CStorVolumeCondition{} 457 for _, condObj := range c { 458 if condObj.Type != cond.Type { 459 newConditions = append(newConditions, condObj) 460 } 461 } 462 return newConditions 463 } 464 465 // GetResizeCondition will return resize condtion related to 466 // cstorvolume condtions 467 func GetResizeCondition() CStorVolumeCondition { 468 resizeConditions := CStorVolumeCondition{ 469 Type: CStorVolumeResizing, 470 Status: ConditionInProgress, 471 LastProbeTime: metav1.Now(), 472 LastTransitionTime: metav1.Now(), 473 Reason: "Resizing", 474 Message: "Triggered resize by changing capacity in spec", 475 } 476 return resizeConditions 477 } 478 479 // **************************************************************************** 480 // 481 // Version Details 482 // 483 // 484 // **************************************************************************** 485 486 // SetErrorStatus sets the message and reason for the error 487 func (vs *VersionStatus) SetErrorStatus(msg string, err error) { 488 vs.Message = msg 489 vs.Reason = err.Error() 490 vs.LastUpdateTime = metav1.Now() 491 } 492 493 // SetInProgressStatus sets the state as ReconcileInProgress 494 func (vs *VersionStatus) SetInProgressStatus() { 495 vs.State = ReconcileInProgress 496 vs.LastUpdateTime = metav1.Now() 497 } 498 499 // SetSuccessStatus resets the message and reason and sets the state as 500 // Reconciled 501 func (vd *VersionDetails) SetSuccessStatus() { 502 vd.Status.Current = vd.Desired 503 vd.Status.Message = "" 504 vd.Status.Reason = "" 505 vd.Status.State = ReconcileComplete 506 vd.Status.LastUpdateTime = metav1.Now() 507 } 508 509 // ************************************************************************** 510 // 511 // CSTOR VOLUMES REPLICA 512 // 513 // 514 // ************************************************************************** 515 516 // NewCStorVolumeReplica returns new instance of CStorVolumeReplica 517 func NewCStorVolumeReplica() *CStorVolumeReplica { 518 return &CStorVolumeReplica{} 519 } 520 521 // WithName sets the Name field of CVR with provided value. 522 func (cvr *CStorVolumeReplica) WithName(name string) *CStorVolumeReplica { 523 cvr.Name = name 524 return cvr 525 } 526 527 // WithNamespace sets the Namespace field of CVC provided arguments 528 func (cvr *CStorVolumeReplica) WithNamespace(namespace string) *CStorVolumeReplica { 529 cvr.Namespace = namespace 530 return cvr 531 } 532 533 // WithAnnotationsNew sets the Annotations field of CVC with provided arguments 534 func (cvr *CStorVolumeReplica) WithAnnotationsNew(annotations map[string]string) *CStorVolumeReplica { 535 cvr.Annotations = make(map[string]string) 536 for key, value := range annotations { 537 cvr.Annotations[key] = value 538 } 539 return cvr 540 } 541 542 // WithAnnotations appends or overwrites existing Annotations 543 // values of CV with provided arguments 544 func (cvr *CStorVolumeReplica) WithAnnotations(annotations map[string]string) *CStorVolumeReplica { 545 546 if cvr.Annotations == nil { 547 return cvr.WithAnnotationsNew(annotations) 548 } 549 for key, value := range annotations { 550 cvr.Annotations[key] = value 551 } 552 return cvr 553 } 554 555 // WithLabelsNew sets the Lacvrels field of CV with provided arguments 556 func (cvr *CStorVolumeReplica) WithLabelsNew(labels map[string]string) *CStorVolumeReplica { 557 cvr.Labels = make(map[string]string) 558 for key, value := range labels { 559 cvr.Labels[key] = value 560 } 561 return cvr 562 } 563 564 // WithLabels appends or overwrites existing Lacvrels 565 // values of CVC with provided arguments 566 func (cvr *CStorVolumeReplica) WithLabels(labels map[string]string) *CStorVolumeReplica { 567 if cvr.Labels == nil { 568 return cvr.WithLabelsNew(labels) 569 } 570 for key, value := range labels { 571 cvr.Labels[key] = value 572 } 573 return cvr 574 } 575 576 // WithFinalizers sets the finalizer field in the CV 577 func (cvr *CStorVolumeReplica) WithFinalizers(finalizers ...string) *CStorVolumeReplica { 578 cvr.Finalizers = append(cvr.Finalizers, finalizers...) 579 return cvr 580 } 581 582 // WithOwnerReference sets the OwnerReference field in CV with required 583 //fields 584 func (cvr *CStorVolumeReplica) WithOwnerReference(reference []metav1.OwnerReference) *CStorVolumeReplica { 585 cvr.OwnerReferences = append(cvr.OwnerReferences, reference...) 586 return cvr 587 } 588 589 // WithTargetIP sets the target IP address field of 590 // CStorVolumeReplica with provided arguments 591 func (cvr *CStorVolumeReplica) WithTargetIP(targetip string) *CStorVolumeReplica { 592 cvr.Spec.TargetIP = targetip 593 return cvr 594 } 595 596 // WithCapacity sets the Capacity field of CStorVolumeReplica with provided arguments 597 func (cvr *CStorVolumeReplica) WithCapacity(capacity string) *CStorVolumeReplica { 598 // capacityQnt, _ := resource.ParseQuantity(capacity) 599 cvr.Spec.Capacity = capacity 600 return cvr 601 } 602 603 // WithReplicaID sets the replicaID with the provided arguments 604 func (cvr *CStorVolumeReplica) WithReplicaID(replicaID string) *CStorVolumeReplica { 605 cvr.Spec.ReplicaID = replicaID 606 return cvr 607 } 608 609 // WithZvolWorkers sets the zvolworkers with the provided arguments 610 func (cvr *CStorVolumeReplica) WithZvolWorkers(zvolworker string) *CStorVolumeReplica { 611 cvr.Spec.ZvolWorkers = zvolworker 612 return cvr 613 } 614 615 // WithCWithCompression sets the compression algorithm with the provided arguments 616 func (cvr *CStorVolumeReplica) WithCompression(compression string) *CStorVolumeReplica { 617 cvr.Spec.Compression = compression 618 return cvr 619 } 620 621 // WithStatusPhase sets the Status Phase of CStorVolumeReplica with provided 622 //arguments 623 func (cvr *CStorVolumeReplica) WithStatusPhase(phase CStorVolumeReplicaPhase) *CStorVolumeReplica { 624 cvr.Status.Phase = phase 625 return cvr 626 } 627 628 // WithNewVersion sets the current and desired version field of 629 // CV with provided arguments 630 func (cvr *CStorVolumeReplica) WithNewVersion(version string) *CStorVolumeReplica { 631 cvr.VersionDetails.Status.Current = version 632 cvr.VersionDetails.Desired = version 633 return cvr 634 } 635 636 // WithDependentsUpgraded sets the field to true for new CV 637 func (cvr *CStorVolumeReplica) WithDependentsUpgraded() *CStorVolumeReplica { 638 cvr.VersionDetails.Status.DependentsUpgraded = true 639 return cvr 640 } 641 642 // HasFinalizer returns true if the provided finalizer is present on the ocvrject. 643 func (cvr *CStorVolumeReplica) HasFinalizer(finalizer string) bool { 644 finalizersList := cvr.GetFinalizers() 645 return util.ContainsString(finalizersList, finalizer) 646 } 647 648 // RemoveFinalizer removes the given finalizer from the ocvrject. 649 func (cvr *CStorVolumeReplica) RemoveFinalizer(finalizer string) { 650 cvr.Finalizers = util.RemoveString(cvr.Finalizers, finalizer) 651 } 652 653 // GetPoolNames returns list of pool names from cStor volume replcia list 654 func GetPoolNames(cvrList *CStorVolumeReplicaList) []string { 655 poolNames := []string{} 656 for _, cvrObj := range cvrList.Items { 657 poolNames = append(poolNames, cvrObj.Labels[string(types.CStorPoolInstanceNameLabelKey)]) 658 } 659 return poolNames 660 }