Skip to content

Commit fa5576e

Browse files
committed
Add checkServiceEndpoints, own deployments
Adds a checkServiceEndpoints function which uses a static list of service names to ensure an endpointslice exists and has associated addresses. This should help make sure webhooks are fully configured before setting the final ready condition upon initial deployment. Also removes old code to "watch" deployments as we can just own them since the initialization resource is namespaced.
1 parent b419ca7 commit fa5576e

File tree

2 files changed

+72
-33
lines changed

2 files changed

+72
-33
lines changed

config/operator/rbac/role.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ rules:
6767
- services
6868
verbs:
6969
- '*'
70+
- apiGroups:
71+
- discovery.k8s.io
72+
resources:
73+
- endpointslices
74+
verbs:
75+
- get
76+
- list
77+
- watch
7078
- apiGroups:
7179
- monitoring.coreos.com
7280
resources:

controllers/operator/openstack_controller.go

Lines changed: 64 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ import (
2929
"k8s.io/client-go/kubernetes"
3030
ctrl "sigs.k8s.io/controller-runtime"
3131
"sigs.k8s.io/controller-runtime/pkg/client"
32-
"sigs.k8s.io/controller-runtime/pkg/handler"
33-
"sigs.k8s.io/controller-runtime/pkg/reconcile"
3432

3533
"k8s.io/apimachinery/pkg/runtime/schema"
3634

@@ -42,6 +40,7 @@ import (
4240
"github.com/openstack-k8s-operators/openstack-operator/pkg/operator/bindata"
4341
"github.com/pkg/errors"
4442
appsv1 "k8s.io/api/apps/v1"
43+
discoveryv1 "k8s.io/api/discovery/v1"
4544
apierrors "k8s.io/apimachinery/pkg/api/errors"
4645
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
4746
uns "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -111,6 +110,7 @@ func SetupEnv() {
111110
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete;
112111
// +kubebuilder:rbac:groups="",resources=serviceaccounts;configmaps;namespaces,verbs="*"
113112
// +kubebuilder:rbac:groups=core,resources=services,verbs="*";
113+
// +kubebuilder:rbac:groups=discovery.k8s.io,resources=endpointslices,verbs=get;list;watch;
114114
// +kubebuilder:rbac:groups=cert-manager.io,resources=issuers,verbs=get;list;watch;create;update;patch;delete;
115115
// +kubebuilder:rbac:groups=cert-manager.io,resources=certificates,verbs=get;list;watch;create;update;patch;delete;
116116
// +kubebuilder:rbac:groups="monitoring.coreos.com",resources=servicemonitors,verbs=list;get;watch;update;create
@@ -271,6 +271,20 @@ func (r *OpenStackReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
271271
return ctrl.Result{}, nil
272272
}
273273

274+
// Check if Services are running and have an endpoint
275+
ctrlResult, err := r.checkServiceEndpoints(ctx, instance)
276+
if err != nil {
277+
instance.Status.Conditions.Set(condition.FalseCondition(
278+
operatorv1beta1.OpenStackOperatorReadyCondition,
279+
condition.ErrorReason,
280+
condition.SeverityWarning,
281+
operatorv1beta1.OpenStackOperatorErrorMessage,
282+
err))
283+
return ctrl.Result{}, err
284+
} else if (ctrlResult != ctrl.Result{}) {
285+
return ctrlResult, nil
286+
}
287+
274288
instance.Status.Conditions.MarkTrue(
275289
operatorv1beta1.OpenStackOperatorReadyCondition,
276290
operatorv1beta1.OpenStackOperatorReadyMessage)
@@ -340,6 +354,53 @@ func (r *OpenStackReconciler) countDeployments(ctx context.Context, instance *op
340354
return count, nil
341355
}
342356

357+
func isWebhookEndpoint(name string) bool {
358+
// NOTE: this is a static list for all operators with webhooks enabled
359+
endpointNames := []string{"openstack-operator-webhook-service", "infra-operator-webhook-service", "openstack-baremetal-operator-webhook-service"}
360+
for _, prefix := range endpointNames {
361+
if strings.HasPrefix(name, prefix) {
362+
return true
363+
}
364+
}
365+
return false
366+
}
367+
368+
// checkServiceEndpoints -
369+
func (r *OpenStackReconciler) checkServiceEndpoints(ctx context.Context, instance *operatorv1beta1.OpenStack) (ctrl.Result, error) {
370+
371+
endpointSliceList := &discoveryv1.EndpointSliceList{}
372+
err := r.Client.List(ctx, endpointSliceList, &client.ListOptions{Namespace: instance.Namespace})
373+
if err != nil {
374+
if apierrors.IsNotFound(err) {
375+
log.Log.Info("Webhook endpoint not found. Requeuing...")
376+
return ctrl.Result{RequeueAfter: time.Duration(5) * time.Second}, nil
377+
}
378+
return ctrl.Result{}, err
379+
}
380+
381+
for _, endpointSlice := range endpointSliceList.Items {
382+
if isWebhookEndpoint(endpointSlice.GetName()) {
383+
if len(endpointSlice.Endpoints) == 0 {
384+
log.Log.Info("Webhook endpoint not configured. Requeuing...", "name", endpointSlice.GetName())
385+
return ctrl.Result{RequeueAfter: time.Duration(5) * time.Second}, nil
386+
}
387+
for _, endpoint := range endpointSlice.Endpoints {
388+
if len(endpoint.Addresses) == 0 {
389+
log.Log.Info("Webhook endpoint addresses aren't healthy. Requeuing...", "name", endpointSlice.GetName())
390+
return ctrl.Result{RequeueAfter: time.Duration(5) * time.Second}, nil
391+
}
392+
bFalse := false
393+
if endpoint.Conditions.Ready == &bFalse || endpoint.Conditions.Serving == &bFalse {
394+
log.Log.Info("Webhook endpoint addresses aren't serving. Requeuing...", "name", endpointSlice.GetName())
395+
return ctrl.Result{RequeueAfter: time.Duration(5) * time.Second}, nil
396+
}
397+
}
398+
}
399+
}
400+
401+
return ctrl.Result{}, nil
402+
}
403+
343404
func (r *OpenStackReconciler) applyManifests(ctx context.Context, instance *operatorv1beta1.OpenStack) error {
344405
if err := r.applyCRDs(ctx, instance); err != nil {
345406
log.Log.Error(err, "failed applying CRD manifests")
@@ -626,38 +687,8 @@ func (r *OpenStackReconciler) postCleanupObsoleteResources(ctx context.Context,
626687
// SetupWithManager sets up the controller with the Manager.
627688
func (r *OpenStackReconciler) SetupWithManager(mgr ctrl.Manager) error {
628689

629-
deploymentFunc := handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, o client.Object) []reconcile.Request {
630-
Log := r.GetLogger(ctx)
631-
632-
instanceList := &operatorv1beta1.OpenStackList{}
633-
err := r.Client.List(ctx, instanceList)
634-
if err != nil {
635-
Log.Error(err, "Unable to retrieve OpenStack instances")
636-
return nil
637-
}
638-
639-
if len(instanceList.Items) == 0 {
640-
return nil
641-
}
642-
643-
instance := &instanceList.Items[0]
644-
if metav1.IsControlledBy(o, instance) {
645-
Log.Info("Reconcile request for OpenStack instance", "instance", instance.Name)
646-
return []reconcile.Request{
647-
{
648-
NamespacedName: client.ObjectKey{
649-
Namespace: instance.Namespace,
650-
Name: instance.Name,
651-
},
652-
},
653-
}
654-
}
655-
656-
return nil
657-
})
658-
659690
return ctrl.NewControllerManagedBy(mgr).
660-
Watches(&appsv1.Deployment{}, deploymentFunc).
691+
Owns(&appsv1.Deployment{}).
661692
For(&operatorv1beta1.OpenStack{}).
662693
Complete(r)
663694
}

0 commit comments

Comments
 (0)