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

feat: (wip) implement kwok machine controller #3

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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
6 changes: 6 additions & 0 deletions api/infrastructure/v1alpha1/kwokmachine_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"time"

sharedv1 "github.com/capi-samples/cluster-api-provider-kwok/api/shared/v1alpha1"
apiv1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
"sigs.k8s.io/cluster-api/errors"
Expand All @@ -38,6 +39,11 @@ type KwokMachineSpec struct {
// SimulationConfig holds the configuration options for changing the behavior of the simulation.
//+optional
SimulationConfig *sharedv1.SimulationConfig `json:"simulationConfig,omitempty"`

// NodeSpec defines node spec on the new kwok machine nodes
NodeSpec *apiv1.NodeSpec `json:"nodeSpec,omitempty"`
// NodeStatus defines node status on the new kwok machine nodes
NodeStatus *apiv1.NodeStatus `json:"nodeStatus,omitempty"`
}

// KwokMachineStatus defines the observed state of KwokMachine
Expand Down
127 changes: 124 additions & 3 deletions internal/controller/infrastructure/kwokmachine_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,20 @@ package controller
import (
"context"

apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog/v2"
"sigs.k8s.io/cluster-api/util"
"sigs.k8s.io/cluster-api/util/annotations"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/reconcile"

controlplanev1alpha1 "github.com/capi-samples/cluster-api-provider-kwok/api/controlplane/v1alpha1"
infrastructurev1alpha1 "github.com/capi-samples/cluster-api-provider-kwok/api/infrastructure/v1alpha1"
"github.com/go-logr/logr"
"github.com/pkg/errors"
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
)

// KwokMachineReconciler reconciles a KwokMachine object
Expand All @@ -47,13 +55,126 @@ type KwokMachineReconciler struct {
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.14.4/pkg/reconcile
func (r *KwokMachineReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
_ = log.FromContext(ctx)
logger := ctrl.LoggerFrom(ctx)

// TODO(user): your logic here
kwokMachine := &infrastructurev1alpha1.KwokMachine{}
err := r.Get(ctx, req.NamespacedName, kwokMachine)
if err != nil {
if apierrors.IsNotFound(err) {
return reconcile.Result{}, nil
}
return reconcile.Result{}, err
}

// Fetch the machine
machine, err := util.GetOwnerMachine(ctx, r.Client, kwokMachine.ObjectMeta)
if err != nil {
logger.Error(err, "Failed to retrieve owner Machine from the API Server")

return ctrl.Result{}, err
}

if machine == nil {
logger.Info("Machine Controller has not yet set OwnerRef")

return ctrl.Result{Requeue: true}, nil
}

logger = logger.WithValues("machine", machine.Name, "kwokMachine", kwokMachine.GetName())

if kwokMachine.Status.FailureMessage != nil ||
kwokMachine.Status.FailureReason != nil {
// TODO(vadasambar): add better log msg
// with more details (machine name, failure msg/reason etc.,)
logger.Info("KwokMachine has failed status")
return ctrl.Result{}, nil
}

// Fetch the Cluster.
cluster, err := util.GetClusterFromMetadata(ctx, r.Client, machine.ObjectMeta)
if err != nil {
logger.Info("Machine is missing cluster label or cluster does not exist")
return ctrl.Result{}, nil
}

if annotations.IsPaused(cluster, kwokMachine) {
logger.Info("Machine or linked Cluster is marked as paused. Won't reconcile")
return ctrl.Result{}, nil
}

logger = logger.WithValues("cluster", klog.KObj(cluster))

if cluster.Status.InfrastructureReady == false {
logger.Info("Cluster is not ready yet")
return ctrl.Result{}, nil
}

if machine.Spec.Bootstrap.DataSecretName == nil {
logger.Info("Bootstrap data secret is not present")
return ctrl.Result{}, nil
}

infraCluster, err := r.getInfraCluster(ctx, &logger, cluster, kwokMachine)

if err != nil {
return ctrl.Result{}, errors.New("error getting infra provider cluster or control plane object")
}
if infraCluster == nil {
logger.Info("KwokCluster or KwokManagedControlPlane is not ready yet")
return ctrl.Result{}, nil
}

if !machine.ObjectMeta.DeletionTimestamp.IsZero() {
err := r.Delete(context.Background(), kwokMachine)
if err != nil {
logger.Info("Error deleting KwokMachine", "err", err)
return ctrl.Result{Requeue: true}, nil
} else {
return ctrl.Result{}, nil
}
}

err = r.Create(context.Background(), kwokMachine)
if err != nil {
logger.Info("Error creating KwokMachine", "err", err)
return ctrl.Result{}, nil
}

return ctrl.Result{}, nil
}

func (r *KwokMachineReconciler) getInfraCluster(ctx context.Context, log *logr.Logger, cluster *clusterv1.Cluster, kwokMachine *infrastructurev1alpha1.KwokMachine) (runtime.Object, error) {

if cluster.Spec.ControlPlaneRef != nil && cluster.Spec.ControlPlaneRef.Kind == "KwokControlPlane" {
controlPlane := &controlplanev1alpha1.KwokControlPlane{}
controlPlaneName := client.ObjectKey{
Namespace: kwokMachine.Namespace,
Name: cluster.Spec.ControlPlaneRef.Name,
}

if err := r.Get(ctx, controlPlaneName, controlPlane); err != nil {
// KwokControlPlane is not ready
return nil, nil //nolint:nilerr
}

return controlPlane, nil
}

kwokCluster := &infrastructurev1alpha1.KwokCluster{}

infraClusterName := client.ObjectKey{
Namespace: kwokCluster.Namespace,
Name: cluster.Spec.InfrastructureRef.Name,
}

if err := r.Client.Get(ctx, infraClusterName, kwokCluster); err != nil {
// KwokCluster is not ready
return nil, nil //nolint:nilerr
}

return kwokCluster, nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *KwokMachineReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
Expand Down
14 changes: 7 additions & 7 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,13 +206,13 @@ func setupReconcilers(ctx context.Context, mgr ctrl.Manager) {
setupLog.Error(err, "unable to create controller", "controller", "KwokCluster")
os.Exit(1)
}
//if err := (&infracontroller.KwokMachineReconciler{
// Client: mgr.GetClient(),
// Scheme: mgr.GetScheme(),
// }).SetupWithManager(mgr); err != nil {
// setupLog.Error(err, "unable to create controller", "controller", "KwokMachine")
// os.Exit(1)
// }
if err := (&infracontroller.KwokMachineReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "KwokMachine")
os.Exit(1)
}
if err := (&controlplanecontroller.KwokControlPlaneReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Expand Down