github.com/webmeshproj/webmesh-cni@v0.0.27/internal/controllers/node_controller.go (about) 1 /* 2 Copyright 2023 Avi Zimmerman <avi.zimmerman@gmail.com>. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package controllers 18 19 import ( 20 "context" 21 "fmt" 22 "time" 23 24 v1 "github.com/webmeshproj/api/go/v1" 25 storagev1 "github.com/webmeshproj/storage-provider-k8s/api/storage/v1" 26 "github.com/webmeshproj/storage-provider-k8s/provider" 27 meshtypes "github.com/webmeshproj/webmesh/pkg/storage/types" 28 ctrl "sigs.k8s.io/controller-runtime" 29 "sigs.k8s.io/controller-runtime/pkg/client" 30 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" 31 "sigs.k8s.io/controller-runtime/pkg/handler" 32 "sigs.k8s.io/controller-runtime/pkg/log" 33 34 "github.com/webmeshproj/webmesh-cni/internal/host" 35 ) 36 37 // StoragePeerFinalizer is the StoragePeer finalizer. 38 const StoragePeerFinalizer = "storagepeer.cniv1.webmesh.io" 39 40 //+kubebuilder:rbac:groups=storage.webmesh.io,resources=storagepeers/finalizers,verbs=get;update;patch 41 42 // NodeReconciler watches for nodes joining and leaving the cluster and ensures 43 // we have edges between the host node and them. 44 type NodeReconciler struct { 45 client.Client 46 Host host.Node 47 Provider *provider.Provider 48 } 49 50 // SetupWithManager sets up the node reconciler with the manager. 51 func (r *NodeReconciler) SetupWithManager(mgr ctrl.Manager) error { 52 return ctrl.NewControllerManagedBy(mgr). 53 Named("node-edges"). 54 Watches(&storagev1.StoragePeer{}, &handler.EnqueueRequestForObject{}). 55 Complete(r) 56 } 57 58 // Reconcile reconciles a node. 59 func (r *NodeReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { 60 log := log.FromContext(ctx) 61 if !r.Host.Started() { 62 log.Info("Host not started yet, requeing") 63 return ctrl.Result{Requeue: true, RequeueAfter: time.Second * 2}, nil 64 } 65 log.Info("Reconciling cluster CNI node") 66 var node storagev1.StoragePeer 67 if err := r.Get(ctx, req.NamespacedName, &node); err != nil { 68 if client.IgnoreNotFound(err) != nil { 69 log.Error(err, "Failed to lookup node") 70 return ctrl.Result{}, err 71 } 72 return ctrl.Result{}, nil 73 } 74 if node.GetId() == r.Host.ID().String() { 75 log.Info("Ignoring the local host node") 76 return ctrl.Result{}, nil 77 } 78 if node.GetDeletionTimestamp() != nil { 79 // Ensure the edge is removed. 80 log.Info("Removing edge to node", "source", r.Host.ID(), "target", node.GetName()) 81 err := r.Provider.MeshDB().Peers().RemoveEdge(ctx, meshtypes.NodeID(r.Host.ID()), meshtypes.NodeID(node.GetId())) 82 if err != nil { 83 log.Error(err, "Failed to remove edge to node") 84 return ctrl.Result{}, err 85 } 86 if controllerutil.ContainsFinalizer(&node, StoragePeerFinalizer) { 87 updated := controllerutil.RemoveFinalizer(&node, StoragePeerFinalizer) 88 if updated { 89 log.Info("Removing finalizer from storage peer") 90 if err := r.Update(ctx, &node); err != nil { 91 return ctrl.Result{}, fmt.Errorf("failed to remove finalizer: %w", err) 92 } 93 } 94 } 95 return ctrl.Result{}, nil 96 } 97 // Make sure the finalizer is present first. 98 if !controllerutil.ContainsFinalizer(&node, StoragePeerFinalizer) { 99 updated := controllerutil.AddFinalizer(&node, StoragePeerFinalizer) 100 if updated { 101 log.V(1).Info("Adding finalizer to storage peer") 102 if err := r.Update(ctx, &node); err != nil { 103 return ctrl.Result{}, fmt.Errorf("failed to add finalizer: %w", err) 104 } 105 return ctrl.Result{}, nil 106 } 107 } 108 log.Info("Ensuring edge to node", "source", r.Host.ID(), "target", node.GetName()) 109 err := r.Provider.MeshDB().Peers().PutEdge(ctx, meshtypes.MeshEdge{ 110 MeshEdge: &v1.MeshEdge{ 111 Source: r.Host.ID().String(), 112 Target: node.GetId(), 113 Weight: 100, 114 }, 115 }) 116 if err != nil { 117 log.Error(err, "Failed to add edge to node") 118 return ctrl.Result{}, err 119 } 120 return ctrl.Result{}, nil 121 }