-
Notifications
You must be signed in to change notification settings - Fork 2.7k
/
reporting.go
149 lines (128 loc) · 5.46 KB
/
reporting.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
145
146
147
148
149
/*
Copyright 2021 The Rook Authors. All rights reserved.
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.
*/
// Reporting focuses on reporting Events, Status Conditions, and the like to users.
package reporting
import (
"context"
"fmt"
"github.com/coreos/pkg/capnslog"
"github.com/pkg/errors"
cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
"github.com/rook/rook/pkg/util/dependents"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/tools/record"
"k8s.io/client-go/util/retry"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)
// ReportReconcileResult will report the result of an object's reconcile in 2 ways:
// 1. to the given logger
// 2. as an event on the object (via the given event recorder)
// The results of the object's reconcile should include the object, the reconcile response, and the
// error returned by the reconcile.
// The function is designed to return the appropriate values needed for the controller-runtime
// framework's Reconcile() method.
func ReportReconcileResult(logger *capnslog.PackageLogger, recorder record.EventRecorder,
obj client.Object, reconcileResponse reconcile.Result, err error,
) (reconcile.Result, error) {
kind := obj.GetObjectKind().GroupVersionKind().Kind
nsName := fmt.Sprintf("%s/%s", obj.GetNamespace(), obj.GetName())
if err != nil {
// 1. log
logger.Errorf("failed to reconcile %s %q. %v", kind, nsName, err)
// 2. event
recorder.Event(obj, corev1.EventTypeWarning, string(cephv1.ReconcileFailed), err.Error())
if !reconcileResponse.IsZero() {
// The framework will requeue immediately if there is an error. If we get an error with
// a non-empty reconcile response, just return the response with the error now logged as
// an event so that the framework can pause before the next reconcile per the response's
// intent.
return reconcileResponse, nil
}
} else {
successMsg := fmt.Sprintf("successfully configured %s %q", kind, nsName)
// 1. log
logger.Debug(successMsg)
// 2. event
recorder.Event(obj, corev1.EventTypeNormal, string(cephv1.ReconcileSucceeded), successMsg)
}
return reconcileResponse, err
}
// ReportDeletionBlockedDueToDependents reports that deletion of a Rook-Ceph object is blocked due
// to the given dependents in 3 ways:
// 1. to the given logger
// 2. as a condition on the object (added to the object's conditions list given)
// 3. as the returned error which should be included in the FailedReconcile message
func ReportDeletionBlockedDueToDependents(
logger *capnslog.PackageLogger, client client.Client, obj cephv1.StatusConditionGetter, deps *dependents.DependentList,
) error {
kind := obj.GetObjectKind().GroupVersionKind().Kind
nsName := types.NamespacedName{
Namespace: obj.GetNamespace(),
Name: obj.GetName(),
}
blockedMsg := deps.StringWithHeader("%s %q will not be deleted until all dependents are removed", kind, nsName.String())
// 1. log
logger.Info(blockedMsg)
// 2. condition
blockedCond := dependents.DeletionBlockedDueToDependentsCondition(true, blockedMsg)
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
if err := client.Get(context.TODO(), nsName, obj); err != nil {
return errors.Wrapf(err, "failed to get latest %s %q", kind, nsName.String())
}
if err := UpdateStatusCondition(client, obj, blockedCond); err != nil {
return err
}
return nil
})
if err != nil {
return errors.Wrapf(err, "on condition %s", blockedMsg)
}
// 3. error for later FailedReconcile message
return errors.New(blockedMsg)
}
// ReportDeletionNotBlockedDueToDependents reports that deletion of a Rook-Ceph object is proceeding
// and NOT blocked due to dependents in 3 ways:
// 1. to the given logger
// 2. as an event on the object (via the given event recorder)
// 3. as a condition on the object (added to the object's conditions list given)
func ReportDeletionNotBlockedDueToDependents(
logger *capnslog.PackageLogger, client client.Client, recorder record.EventRecorder, obj cephv1.StatusConditionGetter,
) {
kind := obj.GetObjectKind().GroupVersionKind().Kind
nsName := types.NamespacedName{
Namespace: obj.GetNamespace(),
Name: obj.GetName(),
}
safeMsg := fmt.Sprintf("%s %q can be deleted safely", kind, nsName.String())
deletingMsg := fmt.Sprintf("deleting %s %q", kind, nsName.String())
// 1. log
logger.Infof("%s. %s", safeMsg, deletingMsg)
// 2. event
recorder.Event(obj, corev1.EventTypeNormal, string(cephv1.DeletingReason), deletingMsg)
// 3. condition
unblockedCond := dependents.DeletionBlockedDueToDependentsCondition(false, safeMsg)
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
if err := client.Get(context.TODO(), nsName, obj); err != nil {
return errors.Wrapf(err, "failed to get latest %s %q", kind, nsName.String())
}
if err := UpdateStatusCondition(client, obj, unblockedCond); err != nil {
return err
}
return nil
})
if err != nil {
logger.Warningf("continuing deletion of %s %q without setting the condition. %v", kind, nsName.String(), err)
}
}