/
cleanup.go
144 lines (131 loc) · 5.13 KB
/
cleanup.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
Copyright 2020 The OpenEBS Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package app
import (
apis "github.com/openebs/maya/pkg/apis/openebs.io/v1alpha1"
bdc "github.com/openebs/maya/pkg/blockdeviceclaim/v1alpha1"
apiscspc "github.com/openebs/maya/pkg/cstor/poolcluster/v1alpha1"
cspi "github.com/openebs/maya/pkg/cstor/poolinstance/v1alpha3"
util "github.com/openebs/maya/pkg/util"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/klog"
)
// cleanupCSPIResources removes the CSPI resources when a CSPI is
// deleted or downscaled
func cleanupCSPIResources(cspcObj *apis.CStorPoolCluster) error {
cspiList, err := cspi.NewKubeClient().WithNamespace(cspcObj.Namespace).List(
metav1.ListOptions{
LabelSelector: string(apis.CStorPoolClusterCPK) + "=" + cspcObj.Name,
},
)
if err != nil {
return errors.Errorf("failed to list cspi for cspc %s to perform cleanup: %s", cspcObj.Name, err.Error())
}
opts := []cspiCleanupOptions{
cleanupBDC,
}
for _, cspiItem := range cspiList.Items {
cspiObj := cspiItem // pin it
// cleanup to be performed only if DeletionTimestamp is non zero and if
// PoolProtectionFinalizer is not removed wait for the next reconcile attempt
if canPerformCSPICleanup(cspiItem) {
for _, o := range opts {
err = o(cspiObj)
if err != nil {
return errors.Wrapf(err, "failed to cleanup cspi %s for cspc %s", cspiItem.Name, cspcObj.Name)
}
}
cspiObj.Finalizers = util.RemoveString(cspiObj.Finalizers, apiscspc.CSPCFinalizer)
_, err = cspi.NewKubeClient().WithNamespace(cspiItem.Namespace).Update(&cspiObj)
if err != nil {
return errors.Wrapf(err, "failed to remove finalizer from cspi %s", cspiItem.Name)
}
klog.Infof("cleanup for cspi %s was successful", cspiItem.Name)
} else {
if isDestroyed(cspiItem) {
// if cspi has DeletionTimestamp but the PoolProtectionFinalizer is present
// returning error helps prevent removal of finalizer on cspc object
// cspc object should not get deleted before all cspi are deleted successfully
return errors.Errorf("failed to cleanup cspi %s for cspc %s: waiting for pool to get destroyed or there is no CSPC label on CSPI",
cspiItem.Name, cspcObj.Name)
}
}
}
return nil
}
// canPerformCSPICleanup performs the validation if the cleanup for the
// CSPI can begin
func canPerformCSPICleanup(cspiObj apis.CStorPoolInstance) bool {
predicates := []cspiCleanupPredicates{
isDestroyed,
hasCSPCFinalizer,
hasNoPoolProtectionFinalizer,
}
for _, p := range predicates {
if !p(cspiObj) {
return false
}
}
return true
}
type cspiCleanupPredicates func(apis.CStorPoolInstance) bool
// isDestroyed is to check if the call is for cStorPoolInstance destroy.
func isDestroyed(cspiObj apis.CStorPoolInstance) bool {
return !cspiObj.DeletionTimestamp.IsZero()
}
// hasCSPCFinalizer is a predicate which checks whether the CSPC
// finalizer is presemt on the CSPI or not
func hasCSPCFinalizer(cspiObj apis.CStorPoolInstance) bool {
return util.ContainsString(cspiObj.Finalizers, apiscspc.CSPCFinalizer)
}
// hasNoPoolProtectionFinalizer is a predicate which checks whether the pool
// protection finalizer is removed or not. The pool protection finalizer is
// used to make sure that the pool is destroyed before BDCs are deleted.
func hasNoPoolProtectionFinalizer(cspiObj apis.CStorPoolInstance) bool {
return !util.ContainsString(cspiObj.Finalizers, apiscspc.PoolProtectionFinalizer)
}
type cspiCleanupOptions func(apis.CStorPoolInstance) error
// cleanupBDC deletes the BDCs for the CSPI which has been deleted or downscaled
func cleanupBDC(cspiObj apis.CStorPoolInstance) error {
bdcList, err := bdc.NewKubeClient().WithNamespace(cspiObj.Namespace).List(
metav1.ListOptions{
LabelSelector: string(apis.CStorPoolClusterCPK) + "=" + cspiObj.Labels[string(apis.CStorPoolClusterCPK)],
},
)
if err != nil {
return err
}
cspiBDMap := map[string]bool{}
for _, raidGroup := range cspiObj.Spec.RaidGroups {
for _, bdcObj := range raidGroup.BlockDevices {
cspiBDMap[bdcObj.BlockDeviceName] = true
}
}
for _, bdcItem := range bdcList.Items {
bdcItem := bdcItem // pin it
if cspiBDMap[bdcItem.Spec.BlockDeviceName] {
bdcObj := &bdcItem
bdcObj.Finalizers = util.RemoveString(bdcObj.Finalizers, apiscspc.CSPCFinalizer)
bdcObj, err = bdc.NewKubeClient().WithNamespace(cspiObj.Namespace).Update(bdcObj)
if err != nil {
return errors.Wrapf(err, "failed to remove finalizers from bdc %s", bdcItem.Name)
}
err = bdc.NewKubeClient().WithNamespace(cspiObj.Namespace).Delete(bdcObj.Name, &metav1.DeleteOptions{})
if err != nil {
return errors.Wrapf(err, "failed to delete bdc %s", bdcObj.Name)
}
}
}
return err
}