From ea70663492f9f7c59cfc0b00dce5ede556beecf6 Mon Sep 17 00:00:00 2001 From: liujian Date: Sun, 28 Sep 2025 16:14:05 +0800 Subject: [PATCH] feat: add validation for unique host variables in inventory (#2779) This update introduces a function to ensure that internal IPv4 addresses and SSH connections are unique across all hosts in the inventory. It checks for duplicates and returns an error if any are found, enhancing the integrity of the inventory data. Signed-off-by: redscholar --- pkg/web/handler/inventory.go | 50 ++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/pkg/web/handler/inventory.go b/pkg/web/handler/inventory.go index 0678b9b8..9223fe5b 100644 --- a/pkg/web/handler/inventory.go +++ b/pkg/web/handler/inventory.go @@ -1,6 +1,7 @@ package handler import ( + "fmt" "io" "reflect" "slices" @@ -136,6 +137,11 @@ func (h *InventoryHandler) Patch(request *restful.Request, response *restful.Res return } + if err := validateUniqueHostVariables(updatedInventory); err != nil { + api.HandleBadRequest(response, request, errors.Wrapf(err, "unable to patch Inventory %s/%s in the cluster: %v", namespace, inventoryName, err)) + return + } + // completeInventory normalizes the inventory groups: // - Synchronizes the "kube_control_plane" group to the "etcd" group. // - Removes duplicate hosts and groups within each group. @@ -443,3 +449,47 @@ func (h *InventoryHandler) ListHosts(request *restful.Request, response *restful results := query.DefaultList(hostTable, queryParam, less, filter) _ = response.WriteEntity(results) } + +// validateUniqueHostVariables ensures that certain host variables are unique across all hosts in the inventory. +// Specifically, it checks that: +// - Each internal IPv4 address (_const.VariableIPv4) is assigned to only one host. +// - Each SSH connection (the combination of ssh_host and ssh_port under the "connector" variable) is unique to a single host. +func validateUniqueHostVariables(inventory *kkcorev1.Inventory) error { + // Maps to track uniqueness: internal IPv4 address -> hostname, and "ssh_host:ssh_port" -> hostname + internalIPv4ToHostname := make(map[string]string) + sshConnectionToHostname := make(map[string]string) + + for hostname, rawHostVars := range inventory.Spec.Hosts { + hostVars := variable.Extension2Variables(rawHostVars) + + // 1. Ensure internal IPv4 address is unique across all hosts + if internalIPv4, ok := hostVars[_const.VariableIPv4].(string); ok && internalIPv4 != "" { + if existingHost, found := internalIPv4ToHostname[internalIPv4]; found && existingHost != hostname { + return fmt.Errorf("duplicate internal_ipv4 detected: %s is assigned to both %s and %s", internalIPv4, existingHost, hostname) + } + internalIPv4ToHostname[internalIPv4] = hostname + } + + // 2. Ensure SSH connection (ssh_host + ssh_port) is unique across all hosts + var sshHost, sshPort string + if connector, ok := hostVars[_const.VariableConnector].(map[string]any); ok { + if v, ok := connector[_const.VariableConnectorHost].(string); ok { + sshHost = v + } + switch v := connector[_const.VariableConnectorPort].(type) { + case string: + sshPort = v + case float64: + sshPort = fmt.Sprintf("%.0f", v) + } + } + if sshHost != "" && sshPort != "" { + sshKey := sshHost + ":" + sshPort + if existingHost, found := sshConnectionToHostname[sshKey]; found && existingHost != hostname { + return fmt.Errorf("duplicate SSH connection detected: %s is assigned to both %s and %s", sshKey, existingHost, hostname) + } + sshConnectionToHostname[sshKey] = hostname + } + } + return nil +}