package edgeinjector import ( "fmt" "os" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" virtv1 "kubevirt.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/webhook" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" dsapi "edge-infra.dev/pkg/edge/datasync/apis/v1alpha1" dsv1 "edge-infra.dev/pkg/sds/devices/k8s/apis/v1" "github.com/go-logr/logr" "edge-infra.dev/pkg/k8s/runtime/controller" "edge-infra.dev/pkg/lib/fog" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" ctrl "sigs.k8s.io/controller-runtime" ) // +kubebuilder:rbac:groups="",resources=pods;nodes,verbs=get;list;watch // +kubebuilder:rbac:groups="",resources=secrets,verbs=create;get;list;update;patch;watch;delete // +kubebuilder:rbac:groups="",resources=pods/status;secrets/status;nodes/status,verbs=get;watch // +kubebuilder:rbac:groups="apps",resources=daemonsets;deployments;replicasets;statefulsets,verbs=get;list;watch // +kubebuilder:rbac:groups="datasync.edge.ncr.com",resources=couchdbusers,verbs=create;get;list;update;patch;watch // +kubebuilder:rbac:groups="datasync.edge.ncr.com",resources=couchdbusers/status,verbs=get;watch // +kubebuilder:rbac:groups="device-system.edge.ncr.com",resources=devicestatuses,verbs=get;watch;list func Run(o ...controller.Option) error { log := fog.New() log.WithName("EdgeInjector") c, err := NewConfig() if err != nil { log.Error(err, "fail to build configuration") os.Exit(1) } mgr, err := create(log, c, o...) if err != nil { return err } log.Info("starting webhooks") if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { log.Error(err, "problem running manager") return err } return nil } // create a webhook, implementation example can be found here: https://book.kubebuilder.io/cronjob-tutorial/webhook-implementation.html func create(log logr.Logger, c *Config, o ...controller.Option) (ctrl.Manager, error) { ctrl.SetLogger(log) log.Info("setting up manager") if c.EnableWebhook { o = append(o, controller.WithCertDir(c.CertDir), controller.WithPort(c.Port), ) } mgr, err := createManager(o...) if err != nil { ctrl.Log.Error(err, "unable to create manager") return nil, err } if c.EnableWebhook { webhookServer := mgr.GetWebhookServer() webhookServer.Register(Path(CouchDBSecret), &webhook.Admission{Handler: admission.WithCustomDefaulter(createScheme(), &corev1.Pod{}, &CouchUserWebhook{Client: mgr.GetClient()})}) webhookServer.Register(Path(NodeSecret), &webhook.Admission{Handler: admission.WithCustomDefaulter(createScheme(), &corev1.Pod{}, &NodeWebhook{Client: mgr.GetClient()})}) webhookServer.Register("/resourcerequest-deployment", &admission.Webhook{Handler: admission.WithCustomDefaulter(createScheme(), &appsv1.Deployment{}, &ResourceRequestWebhook{Client: mgr.GetClient()})}) webhookServer.Register("/resourcerequest-daemonset", &admission.Webhook{Handler: admission.WithCustomDefaulter(createScheme(), &appsv1.DaemonSet{}, &ResourceRequestWebhook{Client: mgr.GetClient()})}) webhookServer.Register("/resourcerequest-statefulset", &admission.Webhook{Handler: admission.WithCustomDefaulter(createScheme(), &appsv1.StatefulSet{}, &ResourceRequestWebhook{Client: mgr.GetClient()})}) webhookServer.Register("/resourcerequest-pods", &admission.Webhook{Handler: admission.WithCustomDefaulter(createScheme(), &corev1.Pod{}, &ResourceRequestWebhook{Client: mgr.GetClient()})}) webhookServer.Register("/device-class-validation-deviceclasses", &admission.Webhook{Handler: admission.WithCustomValidator(createScheme(), &dsv1.DeviceClass{}, &DeviceClassWebhook{})}) webhookServer.Register("/device-class-validation-devicesets", &admission.Webhook{Handler: admission.WithCustomValidator(createScheme(), &dsv1.DeviceSet{}, &DeviceClassWebhook{})}) } if err := (&PodSecretReconciler{ Client: mgr.GetClient(), Name: "podsecretreconciler", RequeueTime: c.RequeueTime, PollingInterval: c.PollingInterval, ReconcileConcurrency: c.ReconcileConcurrency, }).SetupWithManager(mgr); err != nil { log.Error(err, "failed to create PodSecretReconciler and set up with manager") return nil, err } return mgr, nil } func createManager(o ...controller.Option) (ctrl.Manager, error) { cfg, opts := controller.ProcessOptions(o...) opts.LeaderElectionID = InjectorLabel opts.Scheme = createScheme() return ctrl.NewManager(cfg, opts) } func Path(s SecretType) string { return fmt.Sprintf("/mutating-create-update-pod-%s", s) } func createScheme() *runtime.Scheme { scheme := runtime.NewScheme() utilruntime.Must(clientgoscheme.AddToScheme(scheme)) utilruntime.Must(dsapi.AddToScheme(scheme)) utilruntime.Must(dsv1.AddToScheme(scheme)) utilruntime.Must(virtv1.AddToScheme(scheme)) return scheme }