Skip to content

Commit

Permalink
add validation method for supporting expression based filtering
Browse files Browse the repository at this point in the history
Signed-off-by: abhay.tomar <[email protected]>
  • Loading branch information
ApsTomar committed Jan 10, 2025
1 parent a065ee8 commit bb8ba3f
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 33 deletions.
5 changes: 4 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,10 @@ type EnableSwitchWithPatches struct {
}

type SyncSelector struct {
MatchLabels map[string]string `json:"matchLabels,omitempty"`
// MatchLabels are the labels to select the object from.
MatchLabels map[string]string `json:"matchLabels,omitempty"`

// MatchExpressions is a list of label selector requirements which supports operators such as In, NotIn, Exists and DoesNotExist.
MatchExpressions []metav1.LabelSelectorRequirement `json:"matchExpressions,omitempty"`
}

Expand Down
35 changes: 9 additions & 26 deletions pkg/controllers/resources/services/syncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package services
import (
"errors"
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"time"

"github.com/loft-sh/vcluster/pkg/mappings"
Expand Down Expand Up @@ -78,34 +76,19 @@ func (s *serviceSyncer) SyncToHost(ctx *synccontext.SyncContext, event *synccont
return patcher.DeleteVirtualObject(ctx, event.Virtual, event.HostOld, "host object was deleted")
}

// fetch the selector present in the config.
configLabelSelector := ctx.Config.Sync.ToHost.Services.Selector
var selector labels.Selector
var err error
if configLabelSelector != nil {
// form labelSelector from selector provided in the config
labelSelector := &metav1.LabelSelector{
MatchLabels: configLabelSelector.MatchLabels,
MatchExpressions: configLabelSelector.MatchExpressions,
}
selector, err = metav1.LabelSelectorAsSelector(labelSelector)
if err != nil {
return ctrl.Result{}, err
}
// check whether the service labels match with the label selector provided in the vcluster config.
validated, err := ValidateServiceBeforeSync(ctx, event.Virtual.GetLabels())
if err != nil {
return ctrl.Result{}, fmt.Errorf("failed to validate the service labels: %w", err)
}
// cancel sync operation if the validation fails i.e. there is a mismatch in the labels.
if !validated {
ctx.Log.Infof("The labels of the service %s don't match against the selector provided in the config", event.Virtual.Name)
return ctrl.Result{}, nil
}

pObj := s.translate(ctx, event.Virtual)

// fetch the labels of the input service and if they match with config selector
// then continue with the sync operation else return.
serviceLabels := pObj.GetLabels()
if serviceLabels != nil {
if !selector.Matches(labels.Set(serviceLabels)) {
ctx.Log.Infof("The labels of the service %s don't match with the labelSelector provided, hence the sync operation is cancelled", pObj.Name)
return ctrl.Result{}, nil
}
}

err = pro.ApplyPatchesHostObject(ctx, nil, pObj, event.Virtual, ctx.Config.Sync.ToHost.Services.Patches, false)
if err != nil {
return ctrl.Result{}, err
Expand Down
34 changes: 34 additions & 0 deletions pkg/controllers/resources/services/validate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package services

import (
"fmt"

"github.com/loft-sh/vcluster/pkg/syncer/synccontext"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
)

// ValidateServiceBeforeSync checks whether service labels match with the label selector provided in the vcluster config.
// These matchers provided in the config decide whether the services will be synced to host or not.
func ValidateServiceBeforeSync(ctx *synccontext.SyncContext, serviceLabels map[string]string) (bool, error) {
// fetch the selector provided in the config.
configLabelSelector := ctx.Config.Sync.ToHost.Services.Selector
var selector labels.Selector
var err error
if configLabelSelector != nil {
// form metav1.LabelSelector object from selector provided in the config.
labelSelector := &metav1.LabelSelector{
MatchLabels: configLabelSelector.MatchLabels,
MatchExpressions: configLabelSelector.MatchExpressions,
}
selector, err = metav1.LabelSelectorAsSelector(labelSelector)
if err != nil {
return false, fmt.Errorf("invalid label selector: %v", err)
}
}

if selector != nil && !selector.Matches(labels.Set(serviceLabels)) {
return false, nil
}
return true, nil
}
22 changes: 16 additions & 6 deletions pkg/server/filters/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,15 +216,25 @@ func createService(ctx *synccontext.SyncContext, req *http.Request, decoder enco
}
newService.Annotations[services.ServiceBlockDeletion] = "true"
newService.Spec.Selector = translate.HostLabelsMap(vService.Spec.Selector, nil, vService.Namespace, false)
err = ctx.PhysicalClient.Create(req.Context(), newService)
if err != nil {
klog.Infof("Error creating service in physical cluster: %v", err)
if kerrors.IsAlreadyExists(err) {
return nil, kerrors.NewAlreadyExists(corev1.Resource("services"), vService.Name)
}

// create the service on the host cluster if the labels successfully match with the config's label selector
validated, err := services.ValidateServiceBeforeSync(ctx, vService.GetLabels())
if err != nil {
klog.Errorf("Failed to validate the service labels: %v", err)
return nil, err
}
if validated {
err = ctx.PhysicalClient.Create(req.Context(), newService)
if err != nil {
klog.Infof("Error creating service in physical cluster: %v", err)
if kerrors.IsAlreadyExists(err) {
return nil, kerrors.NewAlreadyExists(corev1.Resource("services"), vService.Name)
}
return nil, err
}
} else {
klog.Infof("The labels of the service %s don't match against the selector provided in the config", vService.Name)
}

vService.Spec.ClusterIP = newService.Spec.ClusterIP
vService.Spec.ClusterIPs = newService.Spec.ClusterIPs
Expand Down

0 comments on commit bb8ba3f

Please sign in to comment.