package controller import ( "context" "fmt" "net" "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" v1alpha1 "git.unkin.net/unkin/kea-operator/api/v1alpha1" ) // KeaSubnetReconciler validates KeaSubnet CRs and maintains their status. The // actual kea config is rendered by the KeaCluster controller, which watches // subnets and re-renders on change. type KeaSubnetReconciler struct { client.Client Scheme *runtime.Scheme } // +kubebuilder:rbac:groups=kea.unkin.net,resources=keasubnets,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=kea.unkin.net,resources=keasubnets/status,verbs=get;update;patch func (r *KeaSubnetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { var subnet v1alpha1.KeaSubnet if err := r.Get(ctx, req.NamespacedName, &subnet); err != nil { return ctrl.Result{}, client.IgnoreNotFound(err) } if _, _, err := net.ParseCIDR(subnet.Spec.Subnet); err != nil { subnet.Status.Phase = "Invalid" setReady(&subnet.Status.Conditions, subnet.Generation, false, "InvalidCIDR", err.Error()) _ = r.Status().Update(ctx, &subnet) return ctrl.Result{}, nil } for _, p := range subnet.Spec.Pools { if err := validatePool(p); err != nil { subnet.Status.Phase = "Invalid" setReady(&subnet.Status.Conditions, subnet.Generation, false, "InvalidPool", err.Error()) _ = r.Status().Update(ctx, &subnet) return ctrl.Result{}, nil } } subnet.Status.Phase = "Ready" subnet.Status.AssignedID = subnet.Spec.ID subnet.Status.ObservedGeneration = subnet.Generation setReady(&subnet.Status.Conditions, subnet.Generation, true, "Validated", "subnet accepted") if err := r.Status().Update(ctx, &subnet); err != nil { return ctrl.Result{}, err } return ctrl.Result{}, nil } func validatePool(p string) error { // Accept "start - end" (with or without spaces) or a single address. fields := splitPool(p) for _, f := range fields { if net.ParseIP(f) == nil { return fmt.Errorf("invalid pool address %q in %q", f, p) } } return nil } func (r *KeaSubnetReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&v1alpha1.KeaSubnet{}). Complete(r) }