/
finalizer.go
129 lines (107 loc) · 3.2 KB
/
finalizer.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
package operator
import (
"fmt"
"time"
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilnet "k8s.io/apimachinery/pkg/util/net"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/util/retry"
"k8s.io/klog"
imageregistryv1 "github.com/openshift/api/imageregistry/v1"
regopset "github.com/openshift/cluster-image-registry-operator/pkg/generated/clientset/versioned/typed/imageregistry/v1"
"github.com/openshift/cluster-image-registry-operator/pkg/parameters"
)
func (c *Controller) RemoveResources(o *imageregistryv1.Config) error {
c.setStatusRemoving(o)
return c.generator.Remove(o)
}
func (c *Controller) finalizeResources(o *imageregistryv1.Config) error {
if o.ObjectMeta.DeletionTimestamp == nil {
return nil
}
finalizers := []string{}
for _, v := range o.ObjectMeta.Finalizers {
if v != parameters.ImageRegistryOperatorResourceFinalizer {
finalizers = append(finalizers, v)
}
}
if len(finalizers) == len(o.ObjectMeta.Finalizers) {
return nil
}
klog.Infof("finalizing %s", utilObjectInfo(o))
client, err := regopset.NewForConfig(c.kubeconfig)
if err != nil {
return err
}
err = c.RemoveResources(o)
if err != nil {
c.setStatusRemoveFailed(o, err)
return fmt.Errorf("unable to finalize resource: %s", err)
}
cr := o
err = retry.RetryOnConflict(retry.DefaultBackoff, func() error {
if cr == nil {
// Skip using the cache here so we don't have as many
// retries due to slow cache updates
cr, err := client.Configs().Get(o.Name, metav1.GetOptions{})
if err != nil {
return fmt.Errorf("failed to get %s: %s", utilObjectInfo(o), err)
}
finalizers = []string{}
for _, v := range cr.ObjectMeta.Finalizers {
if v != parameters.ImageRegistryOperatorResourceFinalizer {
finalizers = append(finalizers, v)
}
}
}
cr.ObjectMeta.Finalizers = finalizers
_, err := client.Configs().Update(cr)
if err != nil {
cr = nil
return err
}
return nil
})
if err != nil {
return fmt.Errorf("unable to update finalizers in %s: %s", utilObjectInfo(o), err)
}
// These errors may indicate a transient error that we can retry in tests.
errorFuncs := []func(error) bool{
kerrors.IsInternalError,
kerrors.IsTimeout,
kerrors.IsServerTimeout,
kerrors.IsTooManyRequests,
utilnet.IsProbableEOF,
utilnet.IsConnectionReset,
}
retryTime := 3 * time.Second
err = wait.PollInfinite(retryTime, func() (stop bool, err error) {
_, err = c.listers.RegistryConfigs.Get(o.Name)
if err == nil {
return
}
if !kerrors.IsNotFound(err) {
for _, isRetryError := range errorFuncs {
if isRetryError(err) {
return false, nil
}
}
// If the error sends the Retry-After header, we respect it as an explicit confirmation we should retry.
if delaySeconds, shouldRetry := kerrors.SuggestsClientDelay(err); shouldRetry {
delayTime := time.Duration(delaySeconds) * time.Second
if retryTime < delayTime {
time.Sleep(delayTime - retryTime)
}
return false, nil
}
err = fmt.Errorf("failed to get %s: %s", utilObjectInfo(o), err)
return
}
return true, nil
})
if err != nil {
return fmt.Errorf("unable to wait for %s deletion: %s", utilObjectInfo(o), err)
}
return nil
}