diff --git a/cmd/manager/main.go b/cmd/manager/main.go index d9e0d9c8..87a47304 100644 --- a/cmd/manager/main.go +++ b/cmd/manager/main.go @@ -28,6 +28,7 @@ import ( "github.com/openshift/cluster-api-provider-ovirt/pkg/apis" "github.com/openshift/cluster-api-provider-ovirt/pkg/cloud/ovirt" "github.com/openshift/cluster-api-provider-ovirt/pkg/cloud/ovirt/machine" + "github.com/openshift/cluster-api-provider-ovirt/pkg/cloud/ovirt/providerIDcontroller" clusterapis "github.com/openshift/cluster-api/pkg/apis" "github.com/openshift/cluster-api/pkg/client/clientset_generated/clientset" @@ -146,6 +147,8 @@ func main() { capimachine.AddWithActuator(mgr, machineActuator) + providerIDcontroller.Add(mgr, manager.Options{}) + if err := mgr.AddReadyzCheck("ping", healthz.Ping); err != nil { klog.Fatal(err) } diff --git a/go.mod b/go.mod index d556c6fd..d6596095 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/openshift/cluster-api-provider-ovirt go 1.12 require ( + github.com/go-logr/logr v0.1.0 github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef // indirect github.com/openshift/cluster-api v0.0.0-20191030113141-9a3a7bbe9258 github.com/ovirt/go-ovirt v0.0.0-20200428093010-9bcc4fd4e6c0 diff --git a/pkg/cloud/ovirt/providerIDcontroller/providerIDController.go b/pkg/cloud/ovirt/providerIDcontroller/providerIDController.go new file mode 100644 index 00000000..2198217f --- /dev/null +++ b/pkg/cloud/ovirt/providerIDcontroller/providerIDController.go @@ -0,0 +1,146 @@ +package providerIDcontroller + +import ( + "context" + "fmt" + + "github.com/go-logr/logr" + ovirtsdk "github.com/ovirt/go-ovirt" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/klog/klogr" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" + + "github.com/openshift/cluster-api-provider-ovirt/pkg/cloud/ovirt/clients" +) + +var _ reconcile.Reconciler = &providerIDReconciler{} + +type providerIDReconciler struct { + log logr.Logger + client client.Client + listNodesByFieldFunc func(key, value string) ([]corev1.Node, error) + fetchProviderIDFunc func(string) (string, error) + ovirtApi *ovirtsdk.Connection +} + +func (r *providerIDReconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) { + log := r.log.WithValues("node", request.NamespacedName) + log.V(3).Info("Reconciling", request.NamespacedName) + + // Fetch the Node instance + node := corev1.Node{} + err := r.client.Get(context.Background(), request.NamespacedName, &node) + if err != nil { + if errors.IsNotFound(err) { + // Request object not found, could have been deleted after reconcile request. + // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers. + // Return and don't requeue + return reconcile.Result{}, nil + } + // Error reading the object - requeue the request. + return reconcile.Result{}, fmt.Errorf("error getting node: %v", err) + } + + if node.Spec.ProviderID != "" { + return reconcile.Result{}, nil + } + + r.log.Info("spec.ProviderID is empty, fetching from ovirt") + id, err := r.fetchProviderIDFunc(node.Name) + if err != nil { + return reconcile.Result{}, fmt.Errorf("failed getting VM from oVirt: %v", err) + } + + node.Spec.ProviderID = fmt.Sprintf("ovirt://%s", id) + err = r.client.Update(context.Background(), &node) + if err != nil { + return reconcile.Result{}, fmt.Errorf("failed updating node %s: %v", node.Name, err) + } + return reconcile.Result{}, nil +} + +func (r *providerIDReconciler) fetchOvirtVmID(nodeName string) (string, error) { + c, err := r.getConnection("openshift-machine-api", "ovirt-credentials") + if err != nil { + return "", err + } + send, err := c.SystemService().VmsService().List().Search(fmt.Sprintf("name=%s", nodeName)).Send() + if err != nil { + r.log.Error(err, "Failed to find VM", "VM name", nodeName) + return "", err + } + vms := send.MustVms().Slice() + if len(vms) != 1 { + return "", fmt.Errorf("expected to get 1 VM but got %v", len(vms)) + } + return vms[0].MustId(), nil +} + +func Add(mgr manager.Manager, opts manager.Options) error { + reconciler, err := NewProviderIDReconciler(mgr) + + if err != nil { + return fmt.Errorf("error building reconciler: %v", err) + } + + c, err := controller.New("provdierID-controller", mgr, controller.Options{Reconciler: reconciler}) + if err != nil { + return err + } + + //Watch node changes + err = c.Watch(&source.Kind{Type: &corev1.Node{}}, &handler.EnqueueRequestForObject{}) + if err != nil { + return err + } + + return nil +} + +func NewProviderIDReconciler(mgr manager.Manager) (*providerIDReconciler, error) { + log.SetLogger(klogr.New()) + r := providerIDReconciler{ + log: log.Log.WithName("controllers").WithName("providerID-reconciler"), + client: mgr.GetClient(), + } + r.fetchProviderIDFunc = r.fetchOvirtVmID + return &r, nil +} + +func (r *providerIDReconciler) getConnection(namespace, secretName string) (*ovirtsdk.Connection, error) { + var err error + if r.ovirtApi == nil || r.ovirtApi.Test() != nil { + // session expired or some other error, re-login. + r.ovirtApi, err = createApiConnection(r.client, namespace, secretName) + } + return r.ovirtApi, err +} + +//createApiConnection returns a a client to oVirt's API endpoint +func createApiConnection(client client.Client, namespace string, secretName string) (*ovirtsdk.Connection, error) { + creds, err := clients.GetCredentialsSecret(client, namespace, secretName) + + if err != nil { + return nil, fmt.Errorf("failed getting credentials for namespace %s, %s", namespace, err) + } + + connection, err := ovirtsdk.NewConnectionBuilder(). + URL(creds.URL). + Username(creds.Username). + Password(creds.Password). + CAFile(creds.CAFile). + Insecure(creds.Insecure). + Build() + if err != nil { + return nil, err + } + + return connection, nil +} diff --git a/pkg/cloud/ovirt/providerIDcontroller/providerIDController_test.go b/pkg/cloud/ovirt/providerIDcontroller/providerIDController_test.go new file mode 100644 index 00000000..d8454ad8 --- /dev/null +++ b/pkg/cloud/ovirt/providerIDcontroller/providerIDController_test.go @@ -0,0 +1 @@ +package providerIDcontroller