@@ -22,6 +22,7 @@ package openstack
22
22
import (
23
23
"context"
24
24
"fmt"
25
+ "net"
25
26
"net/url"
26
27
"os"
27
28
"os/exec"
@@ -44,11 +45,16 @@ const (
44
45
)
45
46
46
47
var (
47
- metadataServiceUrl = url.URL {
48
+ metadataServiceUrlIPv4 = url.URL {
48
49
Scheme : "http" ,
49
50
Host : "169.254.169.254" ,
50
51
Path : "openstack/latest/user_data" ,
51
52
}
53
+ metadataServiceUrlIPv6 = url.URL {
54
+ Scheme : "http" ,
55
+ Host : "[fe80::a9fe:a9fe%]" ,
56
+ Path : "openstack/latest/user_data" ,
57
+ }
52
58
)
53
59
54
60
func init () {
@@ -166,14 +172,84 @@ func fetchConfigFromDevice(logger *log.Logger, ctx context.Context, path string)
166
172
return os .ReadFile (filepath .Join (mnt , configDriveUserdataPath ))
167
173
}
168
174
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
169
210
func 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
+ }
171
237
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" )
176
243
}
177
244
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" )
179
255
}
0 commit comments