-
Notifications
You must be signed in to change notification settings - Fork 250
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
OpenStack single-stack IPv6 support #1909
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ package openstack | |
import ( | ||
"context" | ||
"fmt" | ||
"net" | ||
"net/url" | ||
"os" | ||
"os/exec" | ||
|
@@ -44,11 +45,16 @@ const ( | |
) | ||
|
||
var ( | ||
metadataServiceUrl = url.URL{ | ||
metadataServiceUrlIPv4 = url.URL{ | ||
Scheme: "http", | ||
Host: "169.254.169.254", | ||
Path: "openstack/latest/user_data", | ||
} | ||
metadataServiceUrlIPv6 = url.URL{ | ||
Scheme: "http", | ||
Host: "[fe80::a9fe:a9fe%]", | ||
Path: "openstack/latest/user_data", | ||
} | ||
) | ||
|
||
func init() { | ||
|
@@ -166,14 +172,84 @@ func fetchConfigFromDevice(logger *log.Logger, ctx context.Context, path string) | |
return os.ReadFile(filepath.Join(mnt, configDriveUserdataPath)) | ||
} | ||
|
||
func isIPv6Address(ip net.IP) bool { | ||
isIPv6 := ip.To4() == nil | ||
return isIPv6 | ||
} | ||
|
||
func findZoneID() (string, error) { | ||
fmt.Println("Fetching zone id...") | ||
interfaces, err := net.Interfaces() | ||
if err != nil { | ||
return "", fmt.Errorf("error fetching zone id: %v", err) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it might be more appropriate to say network interfaces as this is not really the zone id, and could confuse debugging. wdyt? "error fetching network interfaces: %v", err |
||
} | ||
|
||
for _, iface := range interfaces { | ||
fmt.Printf("Checking interface: %s\n", iface.Name) | ||
|
||
if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 { | ||
continue | ||
} | ||
|
||
addrs, err := iface.Addrs() | ||
if err != nil { | ||
fmt.Printf("Error fetching addresses for interface %s: %v\n", iface.Name, err) | ||
continue | ||
} | ||
|
||
for _, addr := range addrs { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can I get a small comment explaining how this is giving us the zoneID? |
||
if ipnet, ok := addr.(*net.IPNet); ok && isIPv6Address(ipnet.IP) { | ||
return iface.Name, nil | ||
} | ||
} | ||
} | ||
return "", fmt.Errorf("no active IPv6 network interface found") | ||
} | ||
|
||
// Fetches configuration from both IPv4 and IPv6 metadata services | ||
func fetchConfigFromMetadataService(f *resource.Fetcher) ([]byte, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, this whole function is a bit confusing in the direction it wants to go. The intent is to get our config from the metadata service. If a metadata service has our config we should be happy regardless of which one had it. Currently, we are fetching two times even if we already have the data we need to continue. First we need to decide based on the issue which metadata service should be primary?
wdyt? |
||
res, err := f.FetchToBuffer(metadataServiceUrl, resource.FetchOptions{}) | ||
var ipv4Res, ipv6Res []byte | ||
var ipv4Err, ipv6Err error | ||
|
||
// Attempt to fetch from IPv4 | ||
ipv4Res, ipv4Err = f.FetchToBuffer(metadataServiceUrlIPv4, resource.FetchOptions{}) | ||
if ipv4Err == nil { | ||
fmt.Println("Successfully fetched configuration from IPv4.") | ||
|
||
// If IPv4 succeeds, attempt to fetch from IPv6 as well | ||
interfaceName, err := findZoneID() | ||
if err != nil { | ||
fmt.Printf("IPv6 metadata service lookup failed: %v\n", err) | ||
return ipv4Res, fmt.Errorf("IPv6 lookup failed, returning IPv4 result") | ||
} | ||
metadataServiceUrlIPv6.Host = fmt.Sprintf("[%s%s]", "fe80::a9fe:a9fe%", interfaceName) | ||
metadataServiceUrlIPv6Str := fmt.Sprintf("http://[%s%s]/openstack/latest/user_data", metadataServiceUrlIPv6.Host, interfaceName) | ||
fmt.Printf("Fetching from IPv6 metadata service at %s...\n", metadataServiceUrlIPv6Str) | ||
ipv6Res, ipv6Err = f.FetchToBuffer(metadataServiceUrlIPv6, resource.FetchOptions{}) | ||
|
||
if ipv6Err != nil { | ||
fmt.Printf("IPv6 metadata service failed: %v\n", ipv6Err) | ||
return ipv4Res, fmt.Errorf("IPv4 succeeded, but IPv6 failed: %v", ipv6Err) | ||
} | ||
fmt.Println("Successfully fetched configuration from both IPv4 and IPv6.") | ||
return append(ipv4Res, ipv6Res...), nil | ||
} | ||
|
||
// the metadata server exists but doesn't contain any actual metadata, | ||
// assume that there is no config specified | ||
if err == resource.ErrNotFound { | ||
return nil, nil | ||
// If IPv4 fails, attempt to fetch from IPv6 | ||
interfaceName, err := findZoneID() | ||
if err != nil { | ||
fmt.Printf("IPv6 metadata service lookup failed: %v\n", err) | ||
return nil, fmt.Errorf("both IPv4 and IPv6 lookup failed") | ||
} | ||
|
||
return res, err | ||
metadataServiceUrlIPv6.Host = fmt.Sprintf("[%s%s]", "fe80::a9fe:a9fe%", interfaceName) | ||
metadataServiceUrlIPv6Str := fmt.Sprintf("http://[%s%s]/openstack/latest/user_data", metadataServiceUrlIPv6.Host, interfaceName) | ||
fmt.Printf("Fetching from IPv6 metadata service at %s...\n", metadataServiceUrlIPv6Str) | ||
ipv6Res, ipv6Err = f.FetchToBuffer(metadataServiceUrlIPv6, resource.FetchOptions{}) | ||
|
||
if ipv6Err != nil { | ||
fmt.Printf("IPv6 metadata service failed: %v\n", ipv6Err) | ||
return nil, fmt.Errorf("both IPv4 and IPv6 services failed") | ||
} | ||
return ipv6Res, fmt.Errorf("IPv4 failed, returning IPv6 result") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be good to have some reference on why you are looking for the zone ID in the manner that you are. A simple link to the IPV6 metadata service docs should be good with a quick summary? wdyt?