diff --git a/internal/providers/openstack/openstack.go b/internal/providers/openstack/openstack.go index c6da56422..0a5bb1a1d 100644 --- a/internal/providers/openstack/openstack.go +++ b/internal/providers/openstack/openstack.go @@ -44,6 +44,18 @@ const ( configDriveUserdataPath = "/openstack/latest/user_data" ) +var ( + metadataServiceUrlIPv4 = url.URL{ + Scheme: "http", + Host: "169.254.169.254", + Path: "openstack/latest/user_data", + } + metadataServiceUrlIPv6 = url.URL{ + Scheme: "http", + Path: "openstack/latest/user_data", + } +) + func init() { platform.Register(platform.Provider{ Name: "openstack", @@ -159,86 +171,72 @@ func fetchConfigFromDevice(logger *log.Logger, ctx context.Context, path string) return os.ReadFile(filepath.Join(mnt, configDriveUserdataPath)) } -func FindIPv6InterfaceName() (string, error) { +// Checks if an IP address is IPv6 +func isIPv6Address(ip net.IP) bool { + isIPv6 := ip.To4() == nil + fmt.Fprintf(os.Stdout, "Checking if IP is IPv6: %s, Result: %v\n", ip.String(), isIPv6) + return isIPv6 +} + +// Fetches the first valid IPv6 address +func findIPv6Address() (string, error) { + fmt.Fprintln(os.Stdout, "Fetching network interfaces...") interfaces, err := net.Interfaces() if err != nil { - return "", err + return "", fmt.Errorf("error fetching interfaces: %v", err) } for _, iface := range interfaces { - // Check if the interface is up and not loopback - if iface.Flags&net.FlagUp != 0 && iface.Flags&net.FlagLoopback == 0 { - addrs, err := iface.Addrs() - if err != nil { - continue - } + fmt.Fprintf(os.Stdout, "Checking interface: %s\n", iface.Name) - for _, addr := range addrs { - // Check if the address is an IPv6 - if ipnet, ok := addr.(*net.IPNet); ok && ipnet.IP.To4() == nil && !ipnet.IP.IsLinkLocalUnicast() { - return iface.Name, nil - } - } + // Skip down interfaces + if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 { + continue } - } - return "", fmt.Errorf("no IPv6 interface name found") -} - -func fetchConfigFromMetadataService(f *resource.Fetcher) ([]byte, error) { - - // Find IPv6 name - iface, err := FindIPv6InterfaceName() - if err != nil { - return nil, err - } - - // Construct URL - var ( - ipv4MetadataServiceUrl = url.URL{ - Scheme: "http", - Host: "169.254.169.254", - Path: "openstack/latest/user_data", - } - ipv6MetadataServiceUrl = url.URL{ - Scheme: "http", - Host: fmt.Sprintf("[fe80::a9fe:a9fe%%%s]", url.PathEscape(iface)), - Path: "openstack/latest/user_data", + addrs, err := iface.Addrs() + if err != nil { + fmt.Fprintf(os.Stdout, "Error fetching addresses for interface %s: %v\n", iface.Name, err) + continue } - ) - - var resIPv4, resIPv6 []byte - var errIPv4, errIPv6 error - // Try IPv4 endpoint - resIPv4, errIPv4 = f.FetchToBuffer(ipv4MetadataServiceUrl, resource.FetchOptions{}) - if errIPv4 != nil && errIPv4 != resource.ErrNotFound { - f.Logger.Err("Failed to fetch config from IPv4: %v", errIPv4) + for _, addr := range addrs { + if ipnet, ok := addr.(*net.IPNet); ok && isIPv6Address(ipnet.IP) { + ipv6Address := fmt.Sprintf("[%s]", ipnet.IP.String()) + fmt.Fprintf(os.Stdout, "Found IPv6 address: %s on interface %s\n", ipv6Address, iface.Name) + return ipv6Address, nil + } + } } + return "", fmt.Errorf("no IPv6 address found") +} - // Try IPv6 endpoint - resIPv6, errIPv6 = f.FetchToBuffer(ipv6MetadataServiceUrl, resource.FetchOptions{}) - if errIPv6 != nil && errIPv6 != resource.ErrNotFound { - f.Logger.Err("Failed to fetch config from IPv6: %v", errIPv6) +// Fetches configuration from both IPv4 and IPv6 metadata services +func fetchConfigFromMetadataService(f *resource.Fetcher) ([]byte, error) { + fmt.Fprintln(os.Stdout, "Fetching from IPv4 metadata service...") + ipv4Res, ipv4Err := f.FetchToBuffer(metadataServiceUrlIPv4, resource.FetchOptions{}) + if ipv4Err == nil { + fmt.Fprintln(os.Stdout, "Successfully fetched configuration from IPv4 metadata service.") + return ipv4Res, nil } + fmt.Fprintf(os.Stdout, "IPv4 metadata service failed: %v\n", ipv4Err) - // If both IPv4 and IPv6 have valid data, combine them - if resIPv4 != nil && resIPv6 != nil { - return append(resIPv4, resIPv6...), nil - } else if resIPv4 != nil { - return resIPv4, nil - } else if resIPv6 != nil { - return resIPv6, nil + fmt.Fprintln(os.Stdout, "Fetching IPv6 address for metadata service...") + ipv6Address, err := findIPv6Address() + if err != nil { + f.Logger.Warning("IPv6 metadata service lookup failed: %v", err) + fmt.Fprintln(os.Stdout, "No IPv6 address found, returning IPv4 error.") + return nil, ipv4Err // Return the IPv4 error if no IPv6 is found } - // If both endpoints fail, return the appropriate error - if errIPv4 != nil { - return nil, errIPv4 - } - if errIPv6 != nil { - return nil, errIPv6 + metadataServiceUrlIPv6.Host = ipv6Address + fmt.Fprintf(os.Stdout, "Fetching from IPv6 metadata service at %s...\n", metadataServiceUrlIPv6.String()) + ipv6Res, ipv6Err := f.FetchToBuffer(metadataServiceUrlIPv6, resource.FetchOptions{}) + if ipv6Err != nil { + f.Logger.Warning("IPv6 metadata service failed: %v", ipv6Err) + fmt.Fprintf(os.Stdout, "IPv6 metadata service fetch failed: %v\n", ipv6Err) } - // If both endpoints return ErrNotFound - return nil, nil + fmt.Fprintln(os.Stdout, "Returning response from IPv6 metadata service.") + return ipv6Res, ipv6Err }