From 0b51cf7c1cfff2f4601e8b21de1141d0cd2c1c68 Mon Sep 17 00:00:00 2001 From: Dmitri Fedotov Date: Thu, 27 Mar 2025 23:26:12 +0200 Subject: [PATCH 1/4] bootserver: Add /ipxe/uuid enpoint --- server/bootserver.go | 52 ++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/server/bootserver.go b/server/bootserver.go index 8529223c..c95fb8fe 100644 --- a/server/bootserver.go +++ b/server/bootserver.go @@ -38,6 +38,10 @@ func RunBootServer(ipxeServerAddr string, ipxeServiceURL string, k8sClient clien handleIPXE(w, r, k8sClient, log, ipxeServiceURL, defaultIpxeTemplateData) }) + http.HandleFunc("/ipxe/", func(w http.ResponseWriter, r *http.Request) { + handleIPXE(w, r, k8sClient, log, ipxeServiceURL, defaultIpxeTemplateData) + }) + http.HandleFunc("/httpboot", func(w http.ResponseWriter, r *http.Request) { handleHTTPBoot(w, r, k8sClient, log, defaultUKIURL) }) @@ -83,41 +87,27 @@ func handleIPXE(w http.ResponseWriter, r *http.Request, k8sClient client.Client, log.Info("Processing IPXE request", "method", r.Method, "path", r.URL.Path, "clientIP", r.RemoteAddr) ctx := r.Context() - clientIP, _, err := net.SplitHostPort(r.RemoteAddr) - if err != nil { - log.Error(err, "Failed to parse client IP address", "clientIP", r.RemoteAddr) - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - return - } - - clientIPs := []string{clientIP} - if xff := r.Header.Get("X-Forwarded-For"); xff != "" { - for _, ip := range strings.Split(xff, ",") { - trimmedIP := strings.TrimSpace(ip) - if trimmedIP != "" { - clientIPs = append(clientIPs, trimmedIP) - } + if strings.HasPrefix(r.URL.Path, "/ipxe/") { + uuid := strings.TrimPrefix(r.URL.Path, "/ipxe/") + if uuid == "" { + http.Error(w, "Bad Request: UUID is required", http.StatusBadRequest) + return } - } - var ipxeConfigs bootv1alpha1.IPXEBootConfigList - for _, ip := range clientIPs { - if err := k8sClient.List(ctx, &ipxeConfigs, client.MatchingFields{bootv1alpha1.SystemIPIndexKey: ip}); err != nil { - log.Info("Failed to list IPXEBootConfig for IP", "IP", ip, "error", err) - continue + ipxeBootConfigList := &bootv1alpha1.IPXEBootConfigList{} + err := k8sClient.List(ctx, ipxeBootConfigList, client.MatchingFields{bootv1alpha1.SystemUUIDIndexKey: uuid}) + if client.IgnoreNotFound(err) != nil { + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return } - if len(ipxeConfigs.Items) > 0 { - log.Info("Found IPXEBootConfig", "IP", ip) - break + if len(ipxeBootConfigList.Items) == 0 { + log.Info("No specified UUID is found, delivering default script") + serveDefaultIPXETemplate(w, log, defaultIpxeTemplateData) + return } - } - if len(ipxeConfigs.Items) == 0 { - log.Info("No IPXEBootConfig found for client IP, delivering default script", "clientIP", clientIP) - serveDefaultIPXETemplate(w, log, defaultIpxeTemplateData) - } else { - config := ipxeConfigs.Items[0] + config := ipxeBootConfigList.Items[0] if config.Spec.IPXEScriptSecretRef != nil { secret := &corev1.Secret{} err := k8sClient.Get(ctx, types.NamespacedName{Name: config.Spec.IPXEScriptSecretRef.Name, Namespace: config.Namespace}, secret) @@ -147,7 +137,11 @@ func handleIPXE(w http.ResponseWriter, r *http.Request, k8sClient client.Client, SquashfsURL: config.Spec.SquashfsURL, IPXEServerURL: ipxeServiceURL, }) + return } + + log.Info("No UUID is specified, delivering default script") + serveDefaultIPXETemplate(w, log, defaultIpxeTemplateData) } func handleIgnitionIPXEBoot(w http.ResponseWriter, r *http.Request, k8sClient client.Client, log logr.Logger, uuid string) { From 82c3049c6f4e282c0a079a324cebf20c129e99a1 Mon Sep 17 00:00:00 2001 From: Dmitri Fedotov Date: Fri, 4 Apr 2025 13:56:05 +0300 Subject: [PATCH 2/4] reply only to /ipxe/ --- server/bootserver.go | 84 +++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 47 deletions(-) diff --git a/server/bootserver.go b/server/bootserver.go index c95fb8fe..7e9c42d5 100644 --- a/server/bootserver.go +++ b/server/bootserver.go @@ -34,10 +34,6 @@ type IPXETemplateData struct { } func RunBootServer(ipxeServerAddr string, ipxeServiceURL string, k8sClient client.Client, log logr.Logger, defaultIpxeTemplateData IPXETemplateData, defaultUKIURL string) { - http.HandleFunc("/ipxe", func(w http.ResponseWriter, r *http.Request) { - handleIPXE(w, r, k8sClient, log, ipxeServiceURL, defaultIpxeTemplateData) - }) - http.HandleFunc("/ipxe/", func(w http.ResponseWriter, r *http.Request) { handleIPXE(w, r, k8sClient, log, ipxeServiceURL, defaultIpxeTemplateData) }) @@ -87,61 +83,55 @@ func handleIPXE(w http.ResponseWriter, r *http.Request, k8sClient client.Client, log.Info("Processing IPXE request", "method", r.Method, "path", r.URL.Path, "clientIP", r.RemoteAddr) ctx := r.Context() - if strings.HasPrefix(r.URL.Path, "/ipxe/") { - uuid := strings.TrimPrefix(r.URL.Path, "/ipxe/") - if uuid == "" { - http.Error(w, "Bad Request: UUID is required", http.StatusBadRequest) - return - } + uuid := strings.TrimPrefix(r.URL.Path, "/ipxe/") + if uuid == "" { + http.Error(w, "Bad Request: UUID is required", http.StatusBadRequest) + return + } - ipxeBootConfigList := &bootv1alpha1.IPXEBootConfigList{} - err := k8sClient.List(ctx, ipxeBootConfigList, client.MatchingFields{bootv1alpha1.SystemUUIDIndexKey: uuid}) - if client.IgnoreNotFound(err) != nil { + ipxeBootConfigList := &bootv1alpha1.IPXEBootConfigList{} + err := k8sClient.List(ctx, ipxeBootConfigList, client.MatchingFields{bootv1alpha1.SystemUUIDIndexKey: uuid}) + if client.IgnoreNotFound(err) != nil { + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } + + if len(ipxeBootConfigList.Items) == 0 { + log.Info("No specified UUID is found, delivering default script") + http.Error(w, "Resource Not Found", http.StatusNotFound) + return + } + + config := ipxeBootConfigList.Items[0] + if config.Spec.IPXEScriptSecretRef != nil { + secret := &corev1.Secret{} + err := k8sClient.Get(ctx, types.NamespacedName{Name: config.Spec.IPXEScriptSecretRef.Name, Namespace: config.Namespace}, secret) + if err != nil { + log.Error(err, "Failed to fetch IPXE script from secret", "SecretName", config.Spec.IPXEScriptSecretRef.Name) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } - if len(ipxeBootConfigList.Items) == 0 { - log.Info("No specified UUID is found, delivering default script") - serveDefaultIPXETemplate(w, log, defaultIpxeTemplateData) + ipxeScript, exists := secret.Data[bootv1alpha1.DefaultIPXEScriptKey] + if !exists { + log.Info("IPXE script not found in the secret", "ExpectedKey", bootv1alpha1.DefaultIPXEScriptKey) + http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } - config := ipxeBootConfigList.Items[0] - if config.Spec.IPXEScriptSecretRef != nil { - secret := &corev1.Secret{} - err := k8sClient.Get(ctx, types.NamespacedName{Name: config.Spec.IPXEScriptSecretRef.Name, Namespace: config.Namespace}, secret) - if err != nil { - log.Error(err, "Failed to fetch IPXE script from secret", "SecretName", config.Spec.IPXEScriptSecretRef.Name) - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - return - } - - ipxeScript, exists := secret.Data[bootv1alpha1.DefaultIPXEScriptKey] - if !exists { - log.Info("IPXE script not found in the secret", "ExpectedKey", bootv1alpha1.DefaultIPXEScriptKey) - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - return - } - - if _, err := w.Write(ipxeScript); err != nil { - log.Info("Failed to write custom IPXE script", "error", err) - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - } - return + if _, err := w.Write(ipxeScript); err != nil { + log.Info("Failed to write custom IPXE script", "error", err) + http.Error(w, "Internal Server Error", http.StatusInternalServerError) } - - serveDefaultIPXETemplate(w, log, IPXETemplateData{ - KernelURL: config.Spec.KernelURL, - InitrdURL: config.Spec.InitrdURL, - SquashfsURL: config.Spec.SquashfsURL, - IPXEServerURL: ipxeServiceURL, - }) return } - log.Info("No UUID is specified, delivering default script") - serveDefaultIPXETemplate(w, log, defaultIpxeTemplateData) + serveDefaultIPXETemplate(w, log, IPXETemplateData{ + KernelURL: config.Spec.KernelURL, + InitrdURL: config.Spec.InitrdURL, + SquashfsURL: config.Spec.SquashfsURL, + IPXEServerURL: ipxeServiceURL, + }) } func handleIgnitionIPXEBoot(w http.ResponseWriter, r *http.Request, k8sClient client.Client, log logr.Logger, uuid string) { From 0fc9917a76cbceaa70a959525ee78a415f2bd8c7 Mon Sep 17 00:00:00 2001 From: Dmitri Fedotov Date: Fri, 4 Apr 2025 14:03:01 +0300 Subject: [PATCH 3/4] remove default IPXE template --- cmd/main.go | 13 +------------ server/bootserver.go | 6 +++--- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 0da4501c..dc145d4f 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -60,7 +60,6 @@ func init() { func main() { ctx := ctrl.LoggerInto(ctrl.SetupSignalHandler(), setupLog) - defaultIpxeTemplateData := NewDefaultIPXETemplateData() defaultHttpUKIURL := NewDefaultHTTPBootData() skipControllerNameValidation := true @@ -254,7 +253,7 @@ func main() { } setupLog.Info("starting boot-server") - go bootserver.RunBootServer(bootserverAddr, ipxeServiceURL, mgr.GetClient(), serverLog.WithName("bootserver"), *defaultIpxeTemplateData, *defaultHttpUKIURL) + go bootserver.RunBootServer(bootserverAddr, ipxeServiceURL, mgr.GetClient(), serverLog.WithName("bootserver"), *defaultHttpUKIURL) setupLog.Info("starting image-proxy-server") go bootserver.RunImageProxyServer(imageProxyServerAddr, mgr.GetClient(), serverLog.WithName("imageproxyserver")) @@ -313,16 +312,6 @@ func IndexHTTPBootConfigBySystemIPs(ctx context.Context, mgr ctrl.Manager) error ) } -func NewDefaultIPXETemplateData() *bootserver.IPXETemplateData { - var cfg bootserver.IPXETemplateData - flag.StringVar(&cfg.KernelURL, "default-kernel-url", "", "Default URL for the kernel") - flag.StringVar(&cfg.InitrdURL, "default-initrd-url", "", "Default URL for the initrd") - flag.StringVar(&cfg.SquashfsURL, "default-squashfs-url", "", "Default URL for the squashfs") - flag.StringVar(&cfg.IPXEServerURL, "default-ipxe-server-url", "", "Default IPXE Server URL to while generating ipxe-script") - - return &cfg -} - func NewDefaultHTTPBootData() *string { var defaultUKIURL string flag.StringVar(&defaultUKIURL, "default-httpboot-uki-url", "", "Default UKI URL for http boot") diff --git a/server/bootserver.go b/server/bootserver.go index 7e9c42d5..eb20ba51 100644 --- a/server/bootserver.go +++ b/server/bootserver.go @@ -33,9 +33,9 @@ type IPXETemplateData struct { IPXEServerURL string } -func RunBootServer(ipxeServerAddr string, ipxeServiceURL string, k8sClient client.Client, log logr.Logger, defaultIpxeTemplateData IPXETemplateData, defaultUKIURL string) { +func RunBootServer(ipxeServerAddr string, ipxeServiceURL string, k8sClient client.Client, log logr.Logger, defaultUKIURL string) { http.HandleFunc("/ipxe/", func(w http.ResponseWriter, r *http.Request) { - handleIPXE(w, r, k8sClient, log, ipxeServiceURL, defaultIpxeTemplateData) + handleIPXE(w, r, k8sClient, log, ipxeServiceURL) }) http.HandleFunc("/httpboot", func(w http.ResponseWriter, r *http.Request) { @@ -79,7 +79,7 @@ func RunBootServer(ipxeServerAddr string, ipxeServiceURL string, k8sClient clien } } -func handleIPXE(w http.ResponseWriter, r *http.Request, k8sClient client.Client, log logr.Logger, ipxeServiceURL string, defaultIpxeTemplateData IPXETemplateData) { +func handleIPXE(w http.ResponseWriter, r *http.Request, k8sClient client.Client, log logr.Logger, ipxeServiceURL string) { log.Info("Processing IPXE request", "method", r.Method, "path", r.URL.Path, "clientIP", r.RemoteAddr) ctx := r.Context() From c627f3397b820758bd17892de345a5f2f6c51982 Mon Sep 17 00:00:00 2001 From: Dmitri Fedotov <13087245+defo89@users.noreply.github.com> Date: Mon, 7 Apr 2025 11:59:06 +0300 Subject: [PATCH 4/4] update log message Co-authored-by: Hardik Dodiya --- server/bootserver.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/bootserver.go b/server/bootserver.go index eb20ba51..7c3a3496 100644 --- a/server/bootserver.go +++ b/server/bootserver.go @@ -97,7 +97,7 @@ func handleIPXE(w http.ResponseWriter, r *http.Request, k8sClient client.Client, } if len(ipxeBootConfigList.Items) == 0 { - log.Info("No specified UUID is found, delivering default script") + log.Info("No IPXEBootConfig found for the given UUID") http.Error(w, "Resource Not Found", http.StatusNotFound) return }