fixing centos container images to point cni-proxy fix
[ovn4nfv-k8s-plugin.git] / pkg / controller / network / network_controller.go
1 package network
2
3 import (
4         "context"
5         "fmt"
6         k8sv1alpha1 "ovn4nfv-k8s-plugin/pkg/apis/k8s/v1alpha1"
7         "github.com/go-logr/logr"
8         "k8s.io/apimachinery/pkg/api/errors"
9         "k8s.io/apimachinery/pkg/runtime"
10         "ovn4nfv-k8s-plugin/internal/pkg/ovn"
11         "ovn4nfv-k8s-plugin/pkg/utils"
12         "reflect"
13         "sigs.k8s.io/controller-runtime/pkg/client"
14         "sigs.k8s.io/controller-runtime/pkg/controller"
15         "sigs.k8s.io/controller-runtime/pkg/handler"
16         "sigs.k8s.io/controller-runtime/pkg/manager"
17         "sigs.k8s.io/controller-runtime/pkg/reconcile"
18         logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
19         "sigs.k8s.io/controller-runtime/pkg/source"
20 )
21
22 var log = logf.Log.WithName("network_controller")
23
24 // Add creates a new Network Controller and adds it to the Manager. The Manager will set fields on the Controller
25 // and Start it when the Manager is Started.
26 func Add(mgr manager.Manager) error {
27         return add(mgr, newReconciler(mgr))
28 }
29
30 // newReconciler returns a new reconcile.Reconciler
31 func newReconciler(mgr manager.Manager) reconcile.Reconciler {
32         return &ReconcileNetwork{client: mgr.GetClient(), scheme: mgr.GetScheme()}
33 }
34
35 // add adds a new Controller to mgr with r as the reconcile.Reconciler
36 func add(mgr manager.Manager, r reconcile.Reconciler) error {
37         // Create a new controller
38         c, err := controller.New("network-controller", mgr, controller.Options{Reconciler: r})
39         if err != nil {
40                 return err
41         }
42         // Watch for changes to primary resource Network
43         err = c.Watch(&source.Kind{Type: &k8sv1alpha1.Network{}}, &handler.EnqueueRequestForObject{})
44         if err != nil {
45                 return err
46         }
47
48         return nil
49 }
50
51 // blank assignment to verify that ReconcileNetwork implements reconcile.Reconciler
52 var _ reconcile.Reconciler = &ReconcileNetwork{}
53
54 // ReconcileNetwork reconciles a Network object
55 type ReconcileNetwork struct {
56         // This client, initialized using mgr.Client() above, is a split client
57         // that reads objects from the cache and writes to the apiserver
58         client client.Client
59         scheme *runtime.Scheme
60 }
61 type reconcileFun func(instance *k8sv1alpha1.Network, reqLogger logr.Logger) error
62
63 // Reconcile reads that state of the cluster for a Network object and makes changes based on the state read
64 // and what is in the Network.Spec
65 // The Controller will requeue the Request to be processed again if the returned error is non-nil or
66 // Result.Requeue is true, otherwise upon completion it will remove the work from the queue.
67 func (r *ReconcileNetwork) Reconcile(request reconcile.Request) (reconcile.Result, error) {
68         reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
69         reqLogger.V(1).Info("Reconciling Network")
70
71         // Fetch the Network instance
72         instance := &k8sv1alpha1.Network{}
73         err := r.client.Get(context.TODO(), request.NamespacedName, instance)
74         if err != nil {
75                 if errors.IsNotFound(err) {
76                         // Request object not found, could have been deleted after reconcile request.
77                         // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
78                         // Return and don't requeue
79                         reqLogger.V(1).Info("Network Object not found")
80                         return reconcile.Result{}, nil
81                 }
82                 // Error reading the object - requeue the request.
83                 return reconcile.Result{}, err
84         }
85         for _, fun := range []reconcileFun{
86                 r.reconcileFinalizers,
87                 r.createNetwork,
88         } {
89                 if err = fun(instance, reqLogger); err != nil {
90                         return reconcile.Result{}, err
91                 }
92         }
93         return reconcile.Result{}, nil
94 }
95
96 const (
97         nfnNetworkFinalizer = "nfnCleanUpNetwork"
98 )
99
100 func (r *ReconcileNetwork) createNetwork(cr *k8sv1alpha1.Network, reqLogger logr.Logger) error {
101
102         if !cr.DeletionTimestamp.IsZero() {
103                 // Marked for deletion
104                 return nil
105         }
106         switch {
107         case cr.Spec.CniType == "ovn4nfv":
108                 ovnCtl, err := ovn.GetOvnController()
109                 if err != nil {
110                         return err
111                 }
112                 err = ovnCtl.CreateNetwork(cr)
113                 if err != nil && !reflect.DeepEqual(err, fmt.Errorf("LS exists")) {
114                         // Log the error
115                         reqLogger.Error(err, "Error Creating Network")
116                         cr.Status.State = k8sv1alpha1.CreateInternalError
117                 } else {
118                         cr.Status.State = k8sv1alpha1.Created
119                 }
120                 err = r.client.Status().Update(context.TODO(), cr)
121                 if err != nil {
122                         return err
123                 }
124                 // If OVN internal error don't requeue
125                 return nil
126                 // Add other CNI types here
127         }
128         reqLogger.Info("CNI type not supported", "name", cr.Spec.CniType)
129         return fmt.Errorf("CNI type not supported")
130
131 }
132
133 func (r *ReconcileNetwork) deleteNetwork(cr *k8sv1alpha1.Network, reqLogger logr.Logger) error {
134
135         switch {
136         case cr.Spec.CniType == "ovn4nfv":
137                 ovnCtl, err := ovn.GetOvnController()
138                 if err != nil {
139                         return err
140                 }
141                 err = ovnCtl.DeleteNetwork(cr)
142                 if err != nil {
143                         // Log the error
144                         reqLogger.Error(err, "Error Delete Network")
145                         cr.Status.State = k8sv1alpha1.DeleteInternalError
146                         err = r.client.Status().Update(context.TODO(), cr)
147                         if err != nil {
148                                 return err
149                         }
150                 }
151                 // If OVN internal error don't requeue
152                 return nil
153                 // Add other CNI types here
154         }
155         reqLogger.Info("CNI type not supported", "name", cr.Spec.CniType)
156         return fmt.Errorf("CNI type not supported")
157 }
158
159 func (r *ReconcileNetwork) reconcileFinalizers(instance *k8sv1alpha1.Network, reqLogger logr.Logger) (err error) {
160
161         if !instance.DeletionTimestamp.IsZero() {
162                 // Instance marked for deletion
163                 if utils.Contains(instance.ObjectMeta.Finalizers, nfnNetworkFinalizer) {
164                         reqLogger.V(1).Info("Finalizer found - delete network")
165                         if err = r.deleteNetwork(instance, reqLogger); err != nil {
166                                 reqLogger.Error(err, "Delete network")
167                         }
168                         // Remove the finalizer even if Delete Network fails. Fatal error retry will not resolve
169                         instance.ObjectMeta.Finalizers = utils.Remove(instance.ObjectMeta.Finalizers, nfnNetworkFinalizer)
170                         if err = r.client.Update(context.TODO(), instance); err != nil {
171                                 reqLogger.Error(err, "Removing Finalize")
172                                 return err
173                         }
174                 }
175
176         } else {
177                 // If finalizer doesn't exist add it
178                 if !utils.Contains(instance.GetFinalizers(), nfnNetworkFinalizer) {
179                         instance.SetFinalizers(append(instance.GetFinalizers(), nfnNetworkFinalizer))
180                         if err = r.client.Update(context.TODO(), instance); err != nil {
181                                 reqLogger.Error(err, "Adding Finalize")
182                                 return err
183                         }
184                         reqLogger.V(1).Info("Finalizer added")
185                 }
186         }
187         return nil
188 }