diff options
-rw-r--r-- | deploy/crds/k8s_v1alpha1_providernetwork_cr.yaml | 19 | ||||
-rw-r--r-- | deploy/crds/k8s_v1alpha1_providernetwork_crd.yaml | 14 | ||||
-rw-r--r-- | pkg/controller/add_providernetwork.go | 10 | ||||
-rw-r--r-- | pkg/controller/providernetwork/providernetwork_controller.go | 196 |
4 files changed, 236 insertions, 3 deletions
diff --git a/deploy/crds/k8s_v1alpha1_providernetwork_cr.yaml b/deploy/crds/k8s_v1alpha1_providernetwork_cr.yaml new file mode 100644 index 0000000..ef03725 --- /dev/null +++ b/deploy/crds/k8s_v1alpha1_providernetwork_cr.yaml @@ -0,0 +1,19 @@ +apiVersion: k8s.plugin.opnfv.org/v1alpha1 +kind: ProviderNetwork +metadata: + name: pnetwork +spec: + cniType: ovn4nfv + ipv4Subnets: + - subnet: 172.16.33.0/24 + name: subnet1 + gateway: 172.16.33.1/24 + excludeIps: 172.16.33.2 172.16.33.5..172.16.33.10 + providerNetType: VLAN + vlan: + vlanId: "100" + providerInterfaceName: eth1 + logicalInterfaceName: eth1.100 + vlanNodeSelector: specific + nodeLabelList: + - kubernetes.io/hostname=testnode1 diff --git a/deploy/crds/k8s_v1alpha1_providernetwork_crd.yaml b/deploy/crds/k8s_v1alpha1_providernetwork_crd.yaml index eabf3f2..cea5b72 100644 --- a/deploy/crds/k8s_v1alpha1_providernetwork_crd.yaml +++ b/deploy/crds/k8s_v1alpha1_providernetwork_crd.yaml @@ -101,15 +101,23 @@ spec: properties: logicalInterfaceName: type: string - node: - type: string + nodeLabelList: + description: '"all"/"any"(in which case a node will be randomly + selected)/"specific"(see below)' + items: + type: string + type: array providerInterfaceName: + description: if VlanNodeSelector is value "specific" then this array + provides a list of nodes labels type: string vlanId: type: string + vlanNodeSelector: + type: string required: - vlanId - - node + - vlanNodeSelector - providerInterfaceName type: object required: diff --git a/pkg/controller/add_providernetwork.go b/pkg/controller/add_providernetwork.go new file mode 100644 index 0000000..58c3940 --- /dev/null +++ b/pkg/controller/add_providernetwork.go @@ -0,0 +1,10 @@ +package controller + +import ( + "ovn4nfv-k8s-plugin/pkg/controller/providernetwork" +) + +func init() { + // AddToManagerFuncs is a list of functions to create controllers and add them to a manager. + AddToManagerFuncs = append(AddToManagerFuncs, providernetwork.Add) +} diff --git a/pkg/controller/providernetwork/providernetwork_controller.go b/pkg/controller/providernetwork/providernetwork_controller.go new file mode 100644 index 0000000..1281ac3 --- /dev/null +++ b/pkg/controller/providernetwork/providernetwork_controller.go @@ -0,0 +1,196 @@ +package providernetwork + +import ( + "context" + "fmt" + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + notif "ovn4nfv-k8s-plugin/internal/pkg/nfnNotify" + "ovn4nfv-k8s-plugin/internal/pkg/ovn" + k8sv1alpha1 "ovn4nfv-k8s-plugin/pkg/apis/k8s/v1alpha1" + "ovn4nfv-k8s-plugin/pkg/utils" + "reflect" + "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/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" + "sigs.k8s.io/controller-runtime/pkg/source" +) + +var log = logf.Log.WithName("controller_providernetwork") + +// Add creates a new ProviderNetwork Controller and adds it to the Manager. The Manager will set fields on the Controller +// and Start it when the Manager is Started. +func Add(mgr manager.Manager) error { + return add(mgr, newReconciler(mgr)) +} + +// newReconciler returns a new reconcile.Reconciler +func newReconciler(mgr manager.Manager) reconcile.Reconciler { + return &ReconcileProviderNetwork{client: mgr.GetClient(), scheme: mgr.GetScheme()} +} + +// add adds a new Controller to mgr with r as the reconcile.Reconciler +func add(mgr manager.Manager, r reconcile.Reconciler) error { + // Create a new controller + c, err := controller.New("providernetwork-controller", mgr, controller.Options{Reconciler: r}) + if err != nil { + return err + } + + // Watch for changes to primary resource ProviderNetwork + err = c.Watch(&source.Kind{Type: &k8sv1alpha1.ProviderNetwork{}}, &handler.EnqueueRequestForObject{}) + if err != nil { + return err + } + return nil +} + +// blank assignment to verify that ReconcileProviderNetwork implements reconcile.Reconciler +var _ reconcile.Reconciler = &ReconcileProviderNetwork{} + +// ReconcileProviderNetwork reconciles a ProviderNetwork object +type ReconcileProviderNetwork struct { + // This client, initialized using mgr.Client() above, is a split client + // that reads objects from the cache and writes to the apiserver + client client.Client + scheme *runtime.Scheme +} +type reconcileFun func(instance *k8sv1alpha1.ProviderNetwork, reqLogger logr.Logger) error + +// Reconcile reads that state of the cluster for a ProviderNetwork object and makes changes based on the state read +// and what is in the ProviderNetwork.Spec +// The Controller will requeue the Request to be processed again if the returned error is non-nil or +// Result.Requeue is true, otherwise upon completion it will remove the work from the queue. +func (r *ReconcileProviderNetwork) Reconcile(request reconcile.Request) (reconcile.Result, error) { + reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name) + reqLogger.Info("Reconciling ProviderNetwork") + + // Fetch the ProviderNetwork instance + instance := &k8sv1alpha1.ProviderNetwork{} + err := r.client.Get(context.TODO(), request.NamespacedName, instance) + 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{}, err + } + for _, fun := range []reconcileFun{ + r.reconcileFinalizers, + r.createNetwork, + } { + if err = fun(instance, reqLogger); err != nil { + return reconcile.Result{}, err + } + } + return reconcile.Result{}, nil +} + +const ( + nfnProviderNetworkFinalizer = "nfnCleanUpProviderNetwork" +) + +func (r *ReconcileProviderNetwork) createNetwork(cr *k8sv1alpha1.ProviderNetwork, reqLogger logr.Logger) error { + + if !cr.DeletionTimestamp.IsZero() { + // Marked for deletion + return nil + } + switch { + case cr.Spec.CniType == "ovn4nfv": + ovnCtl, err := ovn.GetOvnController() + if err != nil { + return err + } + err = ovnCtl.CreateProviderNetwork(cr) + if err != nil && !reflect.DeepEqual(err, fmt.Errorf("LS exists")) { + // Log the error + reqLogger.Error(err, "Error Creating Network") + cr.Status.State = k8sv1alpha1.CreateInternalError + } else { + err := notif.SendNotif(cr, "create", "") + if err != nil { + cr.Status.State = k8sv1alpha1.CreateInternalError + reqLogger.Error(err, "Error Sending Message") + } else { + cr.Status.State = k8sv1alpha1.Created + } + err = r.client.Status().Update(context.TODO(), cr) + if err != nil { + return err + } + } + // If OVN internal error don't requeue + return nil + // Add other CNI types here + } + reqLogger.Info("CNI type not supported", "name", cr.Spec.CniType) + return fmt.Errorf("CNI type not supported") +} + +func (r *ReconcileProviderNetwork) deleteNetwork(cr *k8sv1alpha1.ProviderNetwork, reqLogger logr.Logger) error { + + switch { + case cr.Spec.CniType == "ovn4nfv": + ovnCtl, err := ovn.GetOvnController() + if err != nil { + return err + } + + notif.SendNotif(cr, "delete", "") + + err = ovnCtl.DeleteProviderNetwork(cr) + if err != nil { + // Log the error + reqLogger.Error(err, "Error Delete Network") + cr.Status.State = k8sv1alpha1.DeleteInternalError + err = r.client.Status().Update(context.TODO(), cr) + if err != nil { + return err + } + } + // If OVN internal error don't requeue + return nil + // Add other CNI types here + } + reqLogger.Info("CNI type not supported", "name", cr.Spec.CniType) + return fmt.Errorf("CNI type not supported") +} + +func (r *ReconcileProviderNetwork) reconcileFinalizers(instance *k8sv1alpha1.ProviderNetwork, reqLogger logr.Logger) (err error) { + + if !instance.DeletionTimestamp.IsZero() { + // Instance marked for deletion + if utils.Contains(instance.ObjectMeta.Finalizers, nfnProviderNetworkFinalizer) { + reqLogger.V(1).Info("Finalizer found - delete network") + if err = r.deleteNetwork(instance, reqLogger); err != nil { + reqLogger.Error(err, "Delete network") + } + // Remove the finalizer even if Delete Network fails. Fatal error retry will not resolve + instance.ObjectMeta.Finalizers = utils.Remove(instance.ObjectMeta.Finalizers, nfnProviderNetworkFinalizer) + if err = r.client.Update(context.TODO(), instance); err != nil { + reqLogger.Error(err, "Removing Finalize") + return err + } + } + + } else { + // If finalizer doesn't exist add it + if !utils.Contains(instance.GetFinalizers(), nfnProviderNetworkFinalizer) { + instance.SetFinalizers(append(instance.GetFinalizers(), nfnProviderNetworkFinalizer)) + if err = r.client.Update(context.TODO(), instance); err != nil { + reqLogger.Error(err, "Adding Finalize") + return err + } + reqLogger.V(1).Info("Finalizer added") + } + } + return nil +} |