@@ -24,14 +24,19 @@ import (
24
24
25
25
appsv1 "k8s.io/api/apps/v1"
26
26
corev1 "k8s.io/api/core/v1"
27
+ "k8s.io/apimachinery/pkg/api/equality"
28
+ apimeta "k8s.io/apimachinery/pkg/api/meta"
27
29
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28
30
"k8s.io/apimachinery/pkg/runtime"
29
31
"k8s.io/apimachinery/pkg/types"
32
+ kerrors "k8s.io/apimachinery/pkg/util/errors"
33
+ "k8s.io/utils/ptr"
30
34
ctrl "sigs.k8s.io/controller-runtime"
31
35
"sigs.k8s.io/controller-runtime/pkg/client"
32
36
"sigs.k8s.io/controller-runtime/pkg/log"
33
37
34
38
"github.com/kcp-dev/kcp-operator/internal/reconciling"
39
+ "github.com/kcp-dev/kcp-operator/internal/resources"
35
40
"github.com/kcp-dev/kcp-operator/internal/resources/frontproxy"
36
41
operatorv1alpha1 "github.com/kcp-dev/kcp-operator/sdk/apis/operator/v1alpha1"
37
42
)
@@ -59,70 +64,170 @@ func (r *FrontProxyReconciler) SetupWithManager(mgr ctrl.Manager) error {
59
64
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
60
65
// +kubebuilder:rbac:groups=core,resources=services;configmaps;secrets,verbs=get;list;watch;create;update;patch;delete
61
66
62
- func (r * FrontProxyReconciler ) Reconcile (ctx context.Context , req ctrl.Request ) (ctrl.Result , error ) {
67
+ func (r * FrontProxyReconciler ) Reconcile (ctx context.Context , req ctrl.Request ) (res ctrl.Result , recErr error ) {
63
68
logger := log .FromContext (ctx )
64
-
65
69
logger .Info ("Reconciling FrontProxy object" )
70
+
66
71
var frontProxy operatorv1alpha1.FrontProxy
67
72
if err := r .Client .Get (ctx , req .NamespacedName , & frontProxy ); err != nil {
68
- return ctrl.Result {}, fmt .Errorf ("failed to find %s/%s: %w" , req .Namespace , req .Name , err )
73
+ if client .IgnoreNotFound (err ) != nil {
74
+ return ctrl.Result {}, fmt .Errorf ("failed to find %s/%s: %w" , req .Namespace , req .Name , err )
75
+ }
76
+
77
+ // Object has apparently been deleted already.
78
+ return ctrl.Result {}, nil
69
79
}
70
80
71
- ownerRefWrapper := k8creconciling .OwnerRefWrapper (* metav1 .NewControllerRef (& frontProxy , operatorv1alpha1 .SchemeGroupVersion .WithKind ("FrontProxy" )))
81
+ defer func () {
82
+ if err := r .reconcileStatus (ctx , & frontProxy ); err != nil {
83
+ recErr = kerrors .NewAggregate ([]error {recErr , err })
84
+ }
85
+ }()
86
+
87
+ return ctrl.Result {}, r .reconcile (ctx , & frontProxy )
88
+ }
89
+
90
+ func (r * FrontProxyReconciler ) reconcile (ctx context.Context , frontProxy * operatorv1alpha1.FrontProxy ) error {
91
+ var errs []error
92
+
93
+ ownerRefWrapper := k8creconciling .OwnerRefWrapper (* metav1 .NewControllerRef (frontProxy , operatorv1alpha1 .SchemeGroupVersion .WithKind ("FrontProxy" )))
72
94
73
95
ref := frontProxy .Spec .RootShard .Reference
74
96
rootShard := & operatorv1alpha1.RootShard {}
75
97
switch {
76
98
case ref != nil :
77
- if err := r .Client .Get (ctx , types.NamespacedName {Name : ref .Name , Namespace : req .Namespace }, rootShard ); err != nil {
78
- return ctrl. Result {}, fmt .Errorf ("referenced RootShard '%s' could not be fetched" , ref .Name )
99
+ if err := r .Client .Get (ctx , types.NamespacedName {Name : ref .Name , Namespace : frontProxy .Namespace }, rootShard ); err != nil {
100
+ return fmt .Errorf ("referenced RootShard '%s' could not be fetched" , ref .Name )
79
101
}
80
102
default :
81
- return ctrl. Result {}, fmt .Errorf ("no valid RootShard in FrontProxy spec defined" )
103
+ return fmt .Errorf ("no valid RootShard in FrontProxy spec defined" )
82
104
}
83
105
84
106
configMapReconcilers := []k8creconciling.NamedConfigMapReconcilerFactory {
85
- frontproxy .ConfigmapReconciler (& frontProxy , rootShard ),
107
+ frontproxy .ConfigmapReconciler (frontProxy , rootShard ),
86
108
}
87
109
88
110
secretReconcilers := []k8creconciling.NamedSecretReconcilerFactory {
89
- frontproxy .DynamicKubeconfigSecretReconciler (& frontProxy , rootShard ),
111
+ frontproxy .DynamicKubeconfigSecretReconciler (frontProxy , rootShard ),
90
112
}
91
113
92
114
certReconcilers := []reconciling.NamedCertificateReconcilerFactory {
93
- frontproxy .ServerCertificateReconciler (& frontProxy , rootShard ),
94
- frontproxy .KubeconfigReconciler (& frontProxy , rootShard ),
95
- frontproxy .AdminKubeconfigReconciler (& frontProxy , rootShard ),
96
- frontproxy .RequestHeaderReconciler (& frontProxy , rootShard ),
115
+ frontproxy .ServerCertificateReconciler (frontProxy , rootShard ),
116
+ frontproxy .KubeconfigReconciler (frontProxy , rootShard ),
117
+ frontproxy .AdminKubeconfigReconciler (frontProxy , rootShard ),
118
+ frontproxy .RequestHeaderReconciler (frontProxy , rootShard ),
97
119
}
98
120
99
121
deploymentReconcilers := []k8creconciling.NamedDeploymentReconcilerFactory {
100
- frontproxy .DeploymentReconciler (& frontProxy , rootShard ),
122
+ frontproxy .DeploymentReconciler (frontProxy , rootShard ),
101
123
}
102
124
103
125
serviceReconcilers := []k8creconciling.NamedServiceReconcilerFactory {
104
- frontproxy .ServiceReconciler (& frontProxy ),
126
+ frontproxy .ServiceReconciler (frontProxy ),
127
+ }
128
+
129
+ if err := k8creconciling .ReconcileConfigMaps (ctx , configMapReconcilers , frontProxy .Namespace , r .Client , ownerRefWrapper ); err != nil {
130
+ errs = append (errs , err )
131
+ }
132
+
133
+ if err := k8creconciling .ReconcileSecrets (ctx , secretReconcilers , frontProxy .Namespace , r .Client , ownerRefWrapper ); err != nil {
134
+ errs = append (errs , err )
135
+ }
136
+
137
+ if err := reconciling .ReconcileCertificates (ctx , certReconcilers , frontProxy .Namespace , r .Client , ownerRefWrapper ); err != nil {
138
+ errs = append (errs , err )
139
+ }
140
+
141
+ if err := k8creconciling .ReconcileDeployments (ctx , deploymentReconcilers , frontProxy .Namespace , r .Client , ownerRefWrapper ); err != nil {
142
+ errs = append (errs , err )
143
+ }
144
+
145
+ if err := k8creconciling .ReconcileServices (ctx , serviceReconcilers , frontProxy .Namespace , r .Client , ownerRefWrapper ); err != nil {
146
+ errs = append (errs , err )
105
147
}
106
148
107
- if err := k8creconciling .ReconcileConfigMaps (ctx , configMapReconcilers , req .Namespace , r .Client , ownerRefWrapper ); err != nil {
108
- return ctrl.Result {}, err
149
+ return kerrors .NewAggregate (errs )
150
+ }
151
+
152
+ func (r * FrontProxyReconciler ) reconcileStatus (ctx context.Context , oldFrontProxy * operatorv1alpha1.FrontProxy ) error {
153
+ frontProxy := oldFrontProxy .DeepCopy ()
154
+ var errs []error
155
+
156
+ if frontProxy .Status .Phase == "" {
157
+ frontProxy .Status .Phase = operatorv1alpha1 .FrontProxyPhaseProvisioning
158
+ }
159
+
160
+ if frontProxy .DeletionTimestamp != nil {
161
+ frontProxy .Status .Phase = operatorv1alpha1 .FrontProxyPhaseDeleting
109
162
}
110
163
111
- if err := k8creconciling . ReconcileSecrets (ctx , secretReconcilers , req . Namespace , r . Client , ownerRefWrapper ); err != nil {
112
- return ctrl. Result {} , err
164
+ if err := r . setAvailableCondition (ctx , frontProxy ); err != nil {
165
+ errs = append ( errs , err )
113
166
}
114
167
115
- if err := reconciling . ReconcileCertificates ( ctx , certReconcilers , req . Namespace , r . Client , ownerRefWrapper ); err != nil {
116
- return ctrl. Result {}, err
168
+ if cond := apimeta . FindStatusCondition ( frontProxy . Status . Conditions , string ( operatorv1alpha1 . RootShardConditionTypeAvailable )); cond . Status == metav1 . ConditionTrue {
169
+ frontProxy . Status . Phase = operatorv1alpha1 . FrontProxyPhaseRunning
117
170
}
118
171
119
- if err := k8creconciling .ReconcileDeployments (ctx , deploymentReconcilers , req .Namespace , r .Client , ownerRefWrapper ); err != nil {
120
- return ctrl.Result {}, err
172
+ // only patch the status if there are actual changes.
173
+ if ! equality .Semantic .DeepEqual (oldFrontProxy .Status , frontProxy .Status ) {
174
+ if err := r .Client .Status ().Patch (ctx , frontProxy , client .MergeFrom (oldFrontProxy )); err != nil {
175
+ errs = append (errs , err )
176
+ }
121
177
}
122
178
123
- if err := k8creconciling .ReconcileServices (ctx , serviceReconcilers , req .Namespace , r .Client , ownerRefWrapper ); err != nil {
124
- return ctrl.Result {}, err
179
+ return kerrors .NewAggregate (errs )
180
+ }
181
+
182
+ func (r * FrontProxyReconciler ) setAvailableCondition (ctx context.Context , frontProxy * operatorv1alpha1.FrontProxy ) error {
183
+
184
+ var dep appsv1.Deployment
185
+ depKey := types.NamespacedName {Namespace : frontProxy .Namespace , Name : resources .GetFrontProxyDeploymentName (frontProxy )}
186
+ if err := r .Client .Get (ctx , depKey , & dep ); client .IgnoreNotFound (err ) != nil {
187
+ return err
188
+ }
189
+
190
+ available := metav1 .ConditionFalse
191
+ reason := operatorv1alpha1 .FrontProxyConditionReasonDeploymentUnavailable
192
+ msg := fmt .Sprintf ("Deployment %s" , depKey )
193
+
194
+ if dep .Name != "" {
195
+ if dep .Status .UpdatedReplicas == dep .Status .ReadyReplicas && dep .Status .ReadyReplicas == ptr .Deref (dep .Spec .Replicas , 0 ) {
196
+ available = metav1 .ConditionTrue
197
+ reason = operatorv1alpha1 .FrontProxyConditionReasonReplicasUp
198
+ msg += " is fully up and running"
199
+ } else {
200
+ available = metav1 .ConditionFalse
201
+ reason = operatorv1alpha1 .FrontProxyConditionReasonReplicasUnavailable
202
+ msg += " is not in desired replica state"
203
+ }
204
+ } else {
205
+ msg += " does not exist"
206
+ }
207
+
208
+ if frontProxy .Status .Conditions == nil {
209
+ frontProxy .Status .Conditions = make ([]metav1.Condition , 0 )
210
+ }
211
+
212
+ cond := apimeta .FindStatusCondition (frontProxy .Status .Conditions , string (operatorv1alpha1 .FrontProxyConditionTypeAvailable ))
213
+
214
+ if cond == nil || cond .ObservedGeneration != frontProxy .Generation || cond .Status != available {
215
+ transitionTime := metav1 .Now ()
216
+ if cond != nil && cond .Status == available {
217
+ // We only need to set LastTransitionTime if we are actually toggling the status
218
+ // or if no transition time was set.
219
+ transitionTime = cond .LastTransitionTime
220
+ }
221
+
222
+ apimeta .SetStatusCondition (& frontProxy .Status .Conditions , metav1.Condition {
223
+ Type : string (operatorv1alpha1 .FrontProxyConditionTypeAvailable ),
224
+ Status : available ,
225
+ ObservedGeneration : frontProxy .Generation ,
226
+ LastTransitionTime : transitionTime ,
227
+ Reason : string (reason ),
228
+ Message : msg ,
229
+ })
125
230
}
126
231
127
- return ctrl. Result {}, nil
232
+ return nil
128
233
}
0 commit comments