-
Notifications
You must be signed in to change notification settings - Fork 129
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move the unidling controller code to its own package and add e2e test. OVN, if configured with the empty-lb-backend options, must generate an event PodsNeeded if it receives traffic to a Service VIP without endpoints that is annotated with k8s.ovn.org/idled-at Signed-off-by: Antonio Ojea <aojea@redhat.com>
- Loading branch information
Antonio Ojea
committed
Feb 24, 2021
1 parent
f8225cd
commit e4e05cf
Showing
8 changed files
with
248 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
go-controller/pkg/ovn/ovn_event.go → .../pkg/ovn/controller/unidling/ovn_event.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
package ovn | ||
package unidling | ||
|
||
import ( | ||
"encoding/json" | ||
|
2 changes: 1 addition & 1 deletion
2
go-controller/pkg/ovn/ovn_event_test.go → ...ovn/controller/unidling/ovn_event_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
package ovn | ||
package unidling | ||
|
||
import ( | ||
"reflect" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
package unidling | ||
|
||
import ( | ||
"sync" | ||
"time" | ||
|
||
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/util" | ||
v1 "k8s.io/api/core/v1" | ||
"k8s.io/apimachinery/pkg/types" | ||
"k8s.io/client-go/tools/cache" | ||
"k8s.io/client-go/tools/record" | ||
|
||
"k8s.io/klog/v2" | ||
) | ||
|
||
// unidlinController checks periodically the OVN events db | ||
// and generates a Kubernetes NeedPods events with the Service | ||
// associated to the VIP | ||
type unidlingController struct { | ||
eventRecorder record.EventRecorder | ||
// Map of load balancers to service namespace | ||
serviceVIPToName map[ServiceVIPKey]types.NamespacedName | ||
serviceVIPToNameLock sync.Mutex | ||
} | ||
|
||
// NewController creates a new unidling controller | ||
func NewController(recorder record.EventRecorder, serviceInformer cache.SharedIndexInformer) *unidlingController { | ||
uc := &unidlingController{ | ||
eventRecorder: recorder, | ||
serviceVIPToName: map[ServiceVIPKey]types.NamespacedName{}, | ||
} | ||
|
||
// we only process events on unidling, there is no reconcilation | ||
klog.Info("Setting up event handlers for services") | ||
serviceInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ | ||
AddFunc: uc.onServiceAdd, | ||
UpdateFunc: func(old, new interface{}) { | ||
uc.onServiceDelete(old) | ||
uc.onServiceAdd(new) | ||
}, | ||
DeleteFunc: uc.onServiceDelete, | ||
}) | ||
return uc | ||
} | ||
|
||
func (uc *unidlingController) onServiceAdd(obj interface{}) { | ||
svc := obj.(*v1.Service) | ||
if util.ServiceTypeHasClusterIP(svc) && util.IsClusterIPSet(svc) { | ||
for _, ip := range util.GetClusterIPs(svc) { | ||
for _, svcPort := range svc.Spec.Ports { | ||
vip := util.JoinHostPortInt32(ip, svcPort.Port) | ||
uc.AddServiceVIPToName(vip, svcPort.Protocol, svc.Namespace, svc.Name) | ||
} | ||
} | ||
} | ||
} | ||
|
||
func (uc *unidlingController) onServiceDelete(obj interface{}) { | ||
svc := obj.(*v1.Service) | ||
if util.ServiceTypeHasClusterIP(svc) && util.IsClusterIPSet(svc) { | ||
for _, ip := range util.GetClusterIPs(svc) { | ||
for _, svcPort := range svc.Spec.Ports { | ||
vip := util.JoinHostPortInt32(ip, svcPort.Port) | ||
uc.DeleteServiceVIPToName(vip, svcPort.Protocol) | ||
} | ||
} | ||
} | ||
} | ||
|
||
// ServiceVIPKey is used for looking up service namespace information for a | ||
// particular load balancer | ||
type ServiceVIPKey struct { | ||
// Load balancer VIP in the form "ip:port" | ||
vip string | ||
// Protocol used by the load balancer | ||
protocol v1.Protocol | ||
} | ||
|
||
// AddServiceVIPToName associates a k8s service name with a load balancer VIP | ||
func (uc *unidlingController) AddServiceVIPToName(vip string, protocol v1.Protocol, namespace, name string) { | ||
uc.serviceVIPToNameLock.Lock() | ||
defer uc.serviceVIPToNameLock.Unlock() | ||
uc.serviceVIPToName[ServiceVIPKey{vip, protocol}] = types.NamespacedName{Namespace: namespace, Name: name} | ||
} | ||
|
||
// GetServiceVIPToName retrieves the associated k8s service name for a load balancer VIP | ||
func (uc *unidlingController) GetServiceVIPToName(vip string, protocol v1.Protocol) (types.NamespacedName, bool) { | ||
uc.serviceVIPToNameLock.Lock() | ||
defer uc.serviceVIPToNameLock.Unlock() | ||
namespace, ok := uc.serviceVIPToName[ServiceVIPKey{vip, protocol}] | ||
return namespace, ok | ||
} | ||
|
||
// DeleteServiceVIPToName retrieves the associated k8s service name for a load balancer VIP | ||
func (uc *unidlingController) DeleteServiceVIPToName(vip string, protocol v1.Protocol) { | ||
uc.serviceVIPToNameLock.Lock() | ||
defer uc.serviceVIPToNameLock.Unlock() | ||
delete(uc.serviceVIPToName, ServiceVIPKey{vip, protocol}) | ||
} | ||
|
||
func (uc *unidlingController) Run(stopCh <-chan struct{}) { | ||
ticker := time.NewTicker(5 * time.Second) | ||
|
||
for { | ||
select { | ||
case <-ticker.C: | ||
out, _, err := util.RunOVNSbctl("--format=json", "list", "controller_event") | ||
if err != nil { | ||
continue | ||
} | ||
|
||
events, err := extractEmptyLBBackendsEvents([]byte(out)) | ||
if err != nil || len(events) == 0 { | ||
continue | ||
} | ||
|
||
for _, event := range events { | ||
_, _, err := util.RunOVNSbctl("destroy", "controller_event", event.uuid) | ||
if err != nil { | ||
// Don't unidle until we are able to remove the controller event | ||
klog.Errorf("Unable to remove controller event %s", event.uuid) | ||
continue | ||
} | ||
if serviceName, ok := uc.GetServiceVIPToName(event.vip, event.protocol); ok { | ||
serviceRef := v1.ObjectReference{ | ||
Kind: "Service", | ||
Namespace: serviceName.Namespace, | ||
Name: serviceName.Name, | ||
} | ||
klog.V(5).Infof("Sending a NeedPods event for service %s in namespace %s.", serviceName.Name, serviceName.Namespace) | ||
uc.eventRecorder.Eventf(&serviceRef, v1.EventTypeNormal, "NeedPods", "The service %s needs pods", serviceName.Name) | ||
} | ||
} | ||
case <-stopCh: | ||
return | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.