diff --git a/cmd/cluster-operator/customcluster/customcluster.go b/cmd/cluster-operator/customcluster/customcluster.go index 787cad50e..949aba03c 100644 --- a/cmd/cluster-operator/customcluster/customcluster.go +++ b/cmd/cluster-operator/customcluster/customcluster.go @@ -19,6 +19,8 @@ package customcluster import ( "context" + "sigs.k8s.io/controller-runtime/pkg/controller" + ctrl "sigs.k8s.io/controller-runtime" "kurator.dev/kurator/pkg/controllers" @@ -38,7 +40,7 @@ func InitControllers(ctx context.Context, mgr ctrl.Manager) error { if err := (&controllers.CustomMachineController{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { + }).SetupWithManager(ctx, mgr, controller.Options{}); err != nil { log.Error(err, "unable to create controller", "controller", "CustomMachine") return err } diff --git a/manifests/charts/base/templates/cluster.kurator.dev_custommachines.yaml b/manifests/charts/base/templates/cluster.kurator.dev_custommachines.yaml index d5178f92e..631abf1c8 100644 --- a/manifests/charts/base/templates/cluster.kurator.dev_custommachines.yaml +++ b/manifests/charts/base/templates/cluster.kurator.dev_custommachines.yaml @@ -194,6 +194,10 @@ spec: type: object status: description: Current status of the machine. + properties: + ready: + description: TODO add state. Indicate whether the machines are ready. + type: boolean type: object type: object served: true diff --git a/pkg/apis/cluster/v1alpha1/machine.go b/pkg/apis/cluster/v1alpha1/machine.go index d1f955695..b88bc51dc 100644 --- a/pkg/apis/cluster/v1alpha1/machine.go +++ b/pkg/apis/cluster/v1alpha1/machine.go @@ -50,6 +50,8 @@ type CustomMachineSpec struct { // CustomMachineStatus represents the current status of the machine. type CustomMachineStatus struct { // TODO add state. + // Indicate whether the machines are ready. + Ready *bool `json:"ready,omitempty"` } // Machine defines a node. diff --git a/pkg/controllers/custommachine_controller.go b/pkg/controllers/custommachine_controller.go index 6aec6d498..7decaf81a 100644 --- a/pkg/controllers/custommachine_controller.go +++ b/pkg/controllers/custommachine_controller.go @@ -18,45 +18,88 @@ package controllers import ( "context" + "time" + "github.com/pkg/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/cluster-api/controllers/external" + utilconversion "sigs.k8s.io/cluster-api/util/conversion" + "sigs.k8s.io/cluster-api/util/patch" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/log" clusterv1alpha1 "kurator.dev/kurator/pkg/apis/cluster/v1alpha1" ) -// CustomMachineReconciler reconciles a CustomMachine object +// CustomMachineController reconciles a CustomMachine object type CustomMachineController struct { client.Client - Scheme *runtime.Scheme -} - -//+kubebuilder:rbac:groups=kurator.dev.kurator.dev,resources=custommachines,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=kurator.dev.kurator.dev,resources=custommachines/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=kurator.dev.kurator.dev,resources=custommachines/finalizers,verbs=update - -// Reconcile is part of the main kubernetes reconciliation loop which aims to -// move the current state of the cluster closer to the desired state. -// TODO(user): Modify the Reconcile function to compare the state specified by -// the CustomMachine object against the actual cluster state, and then -// perform operations to make the cluster state reflect the state specified by -// the user. -// -// For more details, check Reconcile and its Result here: -// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.13.0/pkg/reconcile -func (r *CustomMachineController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - _ = log.FromContext(ctx) - - // TODO(user): your logic here - - return ctrl.Result{}, nil + APIReader client.Reader + Scheme *runtime.Scheme + externalTracker external.ObjectTracker } // SetupWithManager sets up the controller with the Manager. -func (r *CustomMachineController) SetupWithManager(mgr ctrl.Manager) error { +func (r *CustomMachineController) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { return ctrl.NewControllerManagedBy(mgr). For(&clusterv1alpha1.CustomMachine{}). + WithOptions(options). Complete(r) } + +func (r *CustomMachineController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + log := log.FromContext(ctx) + // Fetch the CustomMachine instance. + customMachine := &clusterv1alpha1.CustomMachine{} + if err := r.Client.Get(ctx, req.NamespacedName, customMachine); err != nil { + if apierrors.IsNotFound(err) { + log.Info("Could not find CustomMachine ", req.NamespacedName, "maybe deleted") + return ctrl.Result{}, nil + } + + // Error reading the object - requeue the request. + return ctrl.Result{Requeue: true}, err + } + return r.reconcile(ctx, customMachine) +} + +func (r *CustomMachineController) reconcile(ctx context.Context, customMachine *clusterv1alpha1.CustomMachine) (ctrl.Result, error) { + log := ctrl.LoggerFrom(ctx) + keyRef := customMachine.Spec.Master[0].SSHKey + if err := utilconversion.UpdateReferenceAPIContract(ctx, r.Client, r.APIReader, keyRef); err != nil { + return ctrl.Result{}, err + } + machineReady := false + obj, err := external.Get(ctx, r.Client, keyRef, customMachine.Namespace) + if err != nil { + if apierrors.IsNotFound(errors.Cause(err)) { + log.Info("Could not find external object for CustomMachine, requeuing", "refGroupVersionKind", keyRef.GroupVersionKind(), "refName", keyRef.Name) + return ctrl.Result{RequeueAfter: 30 * time.Second}, nil + } + return ctrl.Result{}, err + } + machineReady = true + // Initialize the patch helper. + patchHelper, err := patch.NewHelper(customMachine, r.Client) + if err != nil { + return ctrl.Result{}, err + } + // Set external object ControllerReference to the Cluster. + if err := controllerutil.SetControllerReference(customMachine, obj, r.Client.Scheme()); err != nil { + return ctrl.Result{}, err + } + // Ensure we add a watcher to the external ssh key object. + if err := r.externalTracker.Watch(log, obj, &handler.EnqueueRequestForOwner{OwnerType: &clusterv1alpha1.CustomMachine{}}); err != nil { + return ctrl.Result{}, err + } + // TODO: Set customMachine.status.ready=true + customMachine.Status.Ready = &machineReady + err = patchHelper.Patch(ctx, customMachine) + return ctrl.Result{}, err + +}