Skip to content

Commit

Permalink
Update hostpathmapper to work with multi namespace mode.
Browse files Browse the repository at this point in the history
- When multiNamespace mode is detected, the localmanager cache's listwatch will watch all namespaces instead of just the target namespace.
- In mapHostPaths, only pods belonging to namespaces managed by the current vcluster will be allowed to be processed.
  • Loading branch information
neogopher committed Feb 9, 2024
1 parent 36be0fd commit 07ac1bb
Show file tree
Hide file tree
Showing 5 changed files with 243 additions and 37 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Build the manager binary
FROM golang:1.20 as builder
FROM golang:1.22 as builder

WORKDIR /vcluster-hpm-dev
ARG TARGETOS
Expand Down
111 changes: 75 additions & 36 deletions cmd/hostpaths/hostpaths.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import (
"io/fs"
"os"
"path/filepath"
"slices"
"strings"
"time"

"github.com/loft-sh/vcluster/pkg/controllers/resources/namespaces"
podtranslate "github.com/loft-sh/vcluster/pkg/controllers/resources/pods/translate"
"github.com/loft-sh/vcluster/pkg/util/clienthelper"

Expand All @@ -18,13 +20,12 @@ import (
"github.com/loft-sh/vcluster/pkg/util/translate"
"github.com/pkg/errors"
"github.com/spf13/cobra"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
Expand Down Expand Up @@ -168,13 +169,17 @@ func Start(ctx context.Context, options *context2.VirtualClusterOptions, init bo
return err
}

localManager, err := ctrl.NewManager(inClusterConfig, ctrl.Options{
Scheme: scheme,
MetricsBindAddress: "0",
LeaderElection: false,
Namespace: options.TargetNamespace,
NewClient: pluginhookclient.NewPhysicalPluginClientFactory(blockingcacheclient.NewCacheClient),
})
kubeClient, err := kubernetes.NewForConfig(inClusterConfig)
if err != nil {
return errors.Wrap(err, "create kube client")
}

err = findVclusterModeAndSetDefaultTranslation(ctx, kubeClient, options)
if err != nil {
return errors.Wrap(err, "find vcluster mode")
}

localManager, err := ctrl.NewManager(inClusterConfig, localManagerCtrlOptions(options))
if err != nil {
return err
}
Expand All @@ -193,11 +198,6 @@ func Start(ctx context.Context, options *context2.VirtualClusterOptions, init bo

startManagers(ctx, localManager, virtualClusterManager)

err = findVclusterModeAndSetDefaultTranslation(ctx, localManager, options)
if err != nil {
return err
}

if init {
klog.Info("is init container mode")
defer ctx.Done()
Expand All @@ -216,28 +216,14 @@ func Start(ctx context.Context, options *context2.VirtualClusterOptions, init bo
return nil
}

func getVclusterObject(ctx context.Context, localManager manager.Manager, vclusterName, vclusterNamespace string, object client.Object) error {
err := localManager.GetClient().Get(ctx, types.NamespacedName{
Name: vclusterName,
Namespace: vclusterNamespace,
}, object)
if err != nil {
return err
}

return nil
}

func getSyncerPodSpec(ctx context.Context, localManager manager.Manager, vclusterName, vclusterNamespace string) (*corev1.PodSpec, error) {
func getSyncerPodSpec(ctx context.Context, kubeClient kubernetes.Interface, vclusterName, vclusterNamespace string) (*corev1.PodSpec, error) {
// try looking for the stateful set first
vclusterSts := &appsv1.StatefulSet{}

err := getVclusterObject(ctx, localManager, vclusterName, vclusterNamespace, vclusterSts)
vclusterSts, err := kubeClient.AppsV1().StatefulSets(vclusterNamespace).Get(ctx, vclusterName, metav1.GetOptions{})
if err != nil {
if kerrors.IsNotFound(err) {
// try looking for deployment - in case of eks/k8s
vclusterDeploy := &appsv1.Deployment{}
err := getVclusterObject(ctx, localManager, vclusterName, vclusterNamespace, vclusterDeploy)
vclusterDeploy, err := kubeClient.AppsV1().Deployments(vclusterNamespace).Get(ctx, vclusterName, metav1.GetOptions{})
if err != nil {
if kerrors.IsNotFound(err) {
klog.Errorf("could not find vcluster either in statefulset or deployment: %v", err)
Expand All @@ -257,8 +243,23 @@ func getSyncerPodSpec(ctx context.Context, localManager manager.Manager, vcluste
return &vclusterSts.Spec.Template.Spec, nil
}

func findVclusterModeAndSetDefaultTranslation(ctx context.Context, localManager manager.Manager, options *context2.VirtualClusterOptions) error {
vclusterPodSpec, err := getSyncerPodSpec(ctx, localManager, options.Name, options.TargetNamespace)
func localManagerCtrlOptions(options *context2.VirtualClusterOptions) manager.Options {
controllerOptions := ctrl.Options{
Scheme: scheme,
MetricsBindAddress: "0",
LeaderElection: false,
NewClient: pluginhookclient.NewPhysicalPluginClientFactory(blockingcacheclient.NewCacheClient),
}

if !options.MultiNamespaceMode {
controllerOptions.Cache.Namespaces = []string{options.TargetNamespace}
}

return controllerOptions
}

func findVclusterModeAndSetDefaultTranslation(ctx context.Context, kubeClient kubernetes.Interface, options *context2.VirtualClusterOptions) error {
vclusterPodSpec, err := getSyncerPodSpec(ctx, kubeClient, options.Name, options.TargetNamespace)
if err != nil {
return err
}
Expand All @@ -268,6 +269,7 @@ func findVclusterModeAndSetDefaultTranslation(ctx context.Context, localManager
// iterate over command args
for _, arg := range container.Args {
if strings.Contains(arg, MultiNamespaceMode) {
options.MultiNamespaceMode = true
translate.Default = translate.NewMultiNamespaceTranslator(options.TargetNamespace)
return nil
}
Expand Down Expand Up @@ -339,17 +341,28 @@ func mapHostPaths(ctx context.Context, pManager, vManager manager.Manager) {

wait.Forever(func() {
podList := &corev1.PodList{}
err := pManager.GetClient().List(ctx, podList, &client.ListOptions{
Namespace: options.TargetNamespace,
podListOptions := &client.ListOptions{
FieldSelector: fields.SelectorFromSet(fields.Set{
NodeIndexName: os.Getenv(HostpathMapperSelfNodeNameEnvVar),
}),
})
}

if !options.MultiNamespaceMode {
podListOptions.Namespace = options.TargetNamespace
}

err := pManager.GetClient().List(ctx, podList, podListOptions)
if err != nil {
klog.Errorf("unable to list pods: %v", err)
return
}

err = filterManagedPods(ctx, options, podList, pManager)
if err != nil {
klog.Errorf("unable to filter pods: %v", err)
return
}

podMappings := make(PhysicalPodMap)

fillUpPodMapping(ctx, podList, podMappings)
Expand Down Expand Up @@ -420,6 +433,32 @@ func mapHostPaths(ctx context.Context, pManager, vManager manager.Manager) {
}, time.Second*5)
}

func filterManagedPods(ctx context.Context, options *context2.VirtualClusterOptions, podList *corev1.PodList, pManager manager.Manager) error {
if options.MultiNamespaceMode {
// Limit Pods
nsList := &corev1.NamespaceList{}
err := pManager.GetClient().List(ctx, nsList, &client.ListOptions{
LabelSelector: labels.SelectorFromSet(labels.Set{
namespaces.VclusterNamespaceAnnotation: options.TargetNamespace,
}),
})
if err != nil {
return errors.Wrap(err, "unable to list namespaces")
}

managedNamespaces := make([]string, 0, len(nsList.Items))
for _, ns := range nsList.Items {
managedNamespaces = append(managedNamespaces, ns.Name)
}

podList.Items = slices.DeleteFunc[[]corev1.Pod, corev1.Pod](podList.Items, func(pod corev1.Pod) bool {
return !slices.Contains[[]string, string](managedNamespaces, pod.Namespace)
})
}

return nil
}

func cleanupOldContainerPaths(ctx context.Context, existingVPodsWithNS map[string]bool) error {
options := ctx.Value(optionsKey).(*context2.VirtualClusterOptions)

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions vendor/modules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ github.com/liggitt/tabwriter
github.com/loft-sh/vcluster/cmd/vcluster/context
github.com/loft-sh/vcluster/pkg/constants
github.com/loft-sh/vcluster/pkg/controllers/resources/configmaps
github.com/loft-sh/vcluster/pkg/controllers/resources/namespaces
github.com/loft-sh/vcluster/pkg/controllers/resources/pods/translate
github.com/loft-sh/vcluster/pkg/controllers/resources/priorityclasses
github.com/loft-sh/vcluster/pkg/controllers/syncer
Expand Down

0 comments on commit 07ac1bb

Please sign in to comment.