Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support out-of-cluster installation #82

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions internal/controllers/import_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ const (

// CAPIImportReconciler represents a reconciler for importing CAPI clusters in Rancher.
type CAPIImportReconciler struct {
client.Client
Client client.Client
RancherClient client.Client
recorder record.EventRecorder
WatchFilterValue string
Scheme *runtime.Scheme
Expand Down Expand Up @@ -178,7 +179,7 @@ func (r *CAPIImportReconciler) Reconcile(ctx context.Context, req ctrl.Request)
errs = append(errs, fmt.Errorf("error reconciling cluster: %w", err))
}

if err := r.Patch(ctx, capiCluster, patchBase); err != nil {
if err := r.Client.Patch(ctx, capiCluster, patchBase); err != nil {
errs = append(errs, fmt.Errorf("failed to patch cluster: %w", err))
}

Expand All @@ -191,7 +192,7 @@ func (r *CAPIImportReconciler) Reconcile(ctx context.Context, req ctrl.Request)

func (r *CAPIImportReconciler) reconcile(ctx context.Context, capiCluster *clusterv1.Cluster) (ctrl.Result, error) {
// fetch the rancher clusters
rancherClusterHandler := rancher.NewClusterHandler(ctx, r.Client)
rancherClusterHandler := rancher.NewClusterHandler(ctx, r.RancherClient)
rancherClusterName := turtelesnaming.Name(capiCluster.Name).ToRancherName()

rancherCluster, err := rancherClusterHandler.Get(client.ObjectKey{Namespace: capiCluster.Namespace, Name: rancherClusterName})
Expand Down Expand Up @@ -346,7 +347,7 @@ func (r *CAPIImportReconciler) getClusterRegistrationManifest(ctx context.Contex
log := log.FromContext(ctx)

key := client.ObjectKey{Name: clusterRegistrationTokenName, Namespace: clusterName}
tokenHandler := rancher.NewClusterRegistrationTokenHandler(ctx, r.Client)
tokenHandler := rancher.NewClusterRegistrationTokenHandler(ctx, r.RancherClient)

token, err := tokenHandler.Get(key)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions internal/controllers/import_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ var _ = Describe("reconcile CAPI Cluster", func() {
BeforeEach(func() {
r = &CAPIImportReconciler{
Client: cl,
RancherClient: cl, // rancher and rancher-turtles deployed in the same cluster
remoteClientGetter: remote.NewClusterClient,
}

Expand Down
51 changes: 51 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ import (
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/client-go/tools/leaderelection/resourcelock"
"k8s.io/component-base/version"
"k8s.io/klog/v2"
Expand Down Expand Up @@ -57,6 +60,7 @@ var (
syncPeriod time.Duration
healthAddr string
concurrencyNumber int
rancherKubeconfig string
)

func init() {
Expand Down Expand Up @@ -97,6 +101,9 @@ func initFlags(fs *pflag.FlagSet) {

fs.IntVar(&concurrencyNumber, "concurrency", 1,
"Number of resources to process simultaneously")

fs.StringVar(&rancherKubeconfig, "rancher-kubeconfig", "",
salasberryfin marked this conversation as resolved.
Show resolved Hide resolved
"Path to the Rancher kubeconfig file. Only required if running out-of-cluster.")
}

func main() {
Expand Down Expand Up @@ -155,11 +162,55 @@ func setupChecks(mgr ctrl.Manager) {
}

func setupReconcilers(ctx context.Context, mgr ctrl.Manager) {
rancherClient, err := setupRancherClient(mgr)
if err != nil {
setupLog.Error(err, "failed to create client")
os.Exit(1)
}

if err := (&controllers.CAPIImportReconciler{
Client: mgr.GetClient(),
RancherClient: rancherClient,
WatchFilterValue: watchFilterValue,
}).SetupWithManager(ctx, mgr, controller.Options{MaxConcurrentReconciles: concurrencyNumber}); err != nil {
setupLog.Error(err, "unable to create capi controller")
os.Exit(1)
}
}

// setupRancherClient can either create a client for an in-cluster installation (rancher and rancher-turtles in the same cluster)
// or create a client for an out-of-cluster installation (rancher and rancher-turtles in different clusters) based on the
// existence of Rancher kubeconfig file.
func setupRancherClient(mgr ctrl.Manager) (client.Client, error) {
if len(rancherKubeconfig) > 0 {
setupLog.Info("out-of-cluster installation of rancher-turtles", "using kubeconfig from path", rancherKubeconfig)

restConfig, err := loadConfigWithContext("", &clientcmd.ClientConfigLoadingRules{ExplicitPath: rancherKubeconfig}, "")
if err != nil {
return nil, fmt.Errorf("unable to load kubeconfig from file: %w", err)
}

rancherClient, err := client.New(restConfig, client.Options{Scheme: mgr.GetClient().Scheme()})
if err != nil {
return nil, err
}

return rancherClient, nil
}

setupLog.Info("in-cluster installation of rancher-turtles")

return mgr.GetClient(), nil
}

// loadConfigWithContext loads a REST Config from a path using a logic similar to the one used in controller-runtime.
func loadConfigWithContext(apiServerURL string, loader clientcmd.ClientConfigLoader, context string) (*rest.Config, error) {
return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
loader,
&clientcmd.ConfigOverrides{
ClusterInfo: clientcmdapi.Cluster{
Server: apiServerURL,
},
CurrentContext: context,
}).ClientConfig()
}