@@ -22,6 +22,7 @@ package openstack
2222import (
2323 "context"
2424 "fmt"
25+ "net"
2526 "net/url"
2627 "os"
2728 "os/exec"
@@ -44,11 +45,16 @@ const (
4445)
4546
4647var (
47- metadataServiceUrl = url.URL {
48+ metadataServiceUrlIPv4 = url.URL {
4849 Scheme : "http" ,
4950 Host : "169.254.169.254" ,
5051 Path : "openstack/latest/user_data" ,
5152 }
53+ metadataServiceUrlIPv6 = url.URL {
54+ Scheme : "http" ,
55+ Host : "[fe80::a9fe:a9fe%]" ,
56+ Path : "openstack/latest/user_data" ,
57+ }
5258)
5359
5460func init () {
@@ -166,14 +172,84 @@ func fetchConfigFromDevice(logger *log.Logger, ctx context.Context, path string)
166172 return os .ReadFile (filepath .Join (mnt , configDriveUserdataPath ))
167173}
168174
175+ func isIPv6Address (ip net.IP ) bool {
176+ isIPv6 := ip .To4 () == nil
177+ return isIPv6
178+ }
179+
180+ func findZoneID () (string , error ) {
181+ fmt .Println ("Fetching zone id..." )
182+ interfaces , err := net .Interfaces ()
183+ if err != nil {
184+ return "" , fmt .Errorf ("error fetching zone id: %v" , err )
185+ }
186+
187+ for _ , iface := range interfaces {
188+ fmt .Printf ("Checking interface: %s\n " , iface .Name )
189+
190+ if iface .Flags & net .FlagUp == 0 || iface .Flags & net .FlagLoopback != 0 {
191+ continue
192+ }
193+
194+ addrs , err := iface .Addrs ()
195+ if err != nil {
196+ fmt .Printf ("Error fetching addresses for interface %s: %v\n " , iface .Name , err )
197+ continue
198+ }
199+
200+ for _ , addr := range addrs {
201+ if ipnet , ok := addr .(* net.IPNet ); ok && isIPv6Address (ipnet .IP ) {
202+ return iface .Name , nil
203+ }
204+ }
205+ }
206+ return "" , fmt .Errorf ("no active IPv6 network interface found" )
207+ }
208+
209+ // Fetches configuration from both IPv4 and IPv6 metadata services
169210func fetchConfigFromMetadataService (f * resource.Fetcher ) ([]byte , error ) {
170- res , err := f .FetchToBuffer (metadataServiceUrl , resource.FetchOptions {})
211+ var ipv4Res , ipv6Res []byte
212+ var ipv4Err , ipv6Err error
213+
214+ // Attempt to fetch from IPv4
215+ ipv4Res , ipv4Err = f .FetchToBuffer (metadataServiceUrlIPv4 , resource.FetchOptions {})
216+ if ipv4Err == nil {
217+ fmt .Println ("Successfully fetched configuration from IPv4." )
218+
219+ // If IPv4 succeeds, attempt to fetch from IPv6 as well
220+ interfaceName , err := findZoneID ()
221+ if err != nil {
222+ fmt .Printf ("IPv6 metadata service lookup failed: %v\n " , err )
223+ return ipv4Res , fmt .Errorf ("IPv6 lookup failed, returning IPv4 result" )
224+ }
225+ metadataServiceUrlIPv6 .Host = fmt .Sprintf ("[%s%s]" , "fe80::a9fe:a9fe%" , interfaceName )
226+ metadataServiceUrlIPv6Str := fmt .Sprintf ("http://[%s%s]/openstack/latest/user_data" , metadataServiceUrlIPv6 .Host , interfaceName )
227+ fmt .Printf ("Fetching from IPv6 metadata service at %s...\n " , metadataServiceUrlIPv6Str )
228+ ipv6Res , ipv6Err = f .FetchToBuffer (metadataServiceUrlIPv6 , resource.FetchOptions {})
229+
230+ if ipv6Err != nil {
231+ fmt .Printf ("IPv6 metadata service failed: %v\n " , ipv6Err )
232+ return ipv4Res , fmt .Errorf ("IPv4 succeeded, but IPv6 failed: %v" , ipv6Err )
233+ }
234+ fmt .Println ("Successfully fetched configuration from both IPv4 and IPv6." )
235+ return append (ipv4Res , ipv6Res ... ), nil
236+ }
171237
172- // the metadata server exists but doesn't contain any actual metadata,
173- // assume that there is no config specified
174- if err == resource .ErrNotFound {
175- return nil , nil
238+ // If IPv4 fails, attempt to fetch from IPv6
239+ interfaceName , err := findZoneID ()
240+ if err != nil {
241+ fmt .Printf ("IPv6 metadata service lookup failed: %v\n " , err )
242+ return nil , fmt .Errorf ("both IPv4 and IPv6 lookup failed" )
176243 }
177244
178- return res , err
245+ metadataServiceUrlIPv6 .Host = fmt .Sprintf ("[%s%s]" , "fe80::a9fe:a9fe%" , interfaceName )
246+ metadataServiceUrlIPv6Str := fmt .Sprintf ("http://[%s%s]/openstack/latest/user_data" , metadataServiceUrlIPv6 .Host , interfaceName )
247+ fmt .Printf ("Fetching from IPv6 metadata service at %s...\n " , metadataServiceUrlIPv6Str )
248+ ipv6Res , ipv6Err = f .FetchToBuffer (metadataServiceUrlIPv6 , resource.FetchOptions {})
249+
250+ if ipv6Err != nil {
251+ fmt .Printf ("IPv6 metadata service failed: %v\n " , ipv6Err )
252+ return nil , fmt .Errorf ("both IPv4 and IPv6 services failed" )
253+ }
254+ return ipv6Res , fmt .Errorf ("IPv4 failed, returning IPv6 result" )
179255}
0 commit comments