diff --git a/internal/providers/openstack/openstack.go b/internal/providers/openstack/openstack.go index 803c6f396..52a2b2a07 100644 --- a/internal/providers/openstack/openstack.go +++ b/internal/providers/openstack/openstack.go @@ -13,14 +13,14 @@ // limitations under the License. // The OpenStack provider fetches configurations from the userdata available in -// both the config-drive as well as the network metadata service. Whichever +// both the config-drive and the network metadata service. Whichever // responds first is the config that is used. -// NOTE: This provider is still EXPERIMENTAL. package openstack import ( "context" + "errors" "fmt" "net" "net/url" @@ -92,8 +92,8 @@ func fetchConfig(f *resource.Fetcher) (types.Config, report.Report, error) { go func() { raw, err := fn() if err != nil { - switch err { - case context.Canceled: + switch { + case errors.Is(err, context.Canceled): default: f.Logger.Err("failed to fetch config from %s: %v", name, err) } @@ -137,7 +137,7 @@ Loop: func fileExists(path string) bool { _, err := os.Stat(path) - return (err == nil) + return err == nil } func fetchConfigFromDevice(logger *log.Logger, ctx context.Context, path string) ([]byte, error) { @@ -182,11 +182,14 @@ func fetchConfigFromDevice(logger *log.Logger, ctx context.Context, path string) } func fetchConfigFromMetadataService(f *resource.Fetcher) ([]byte, error) { + retryCodes := []int{ + 404, // not found + } ipv6Interfaces, err := findInterfacesWithIPv6() if err != nil { f.Logger.Info("No active IPv6 network interface found: %v", err) // Fall back to IPv4 only - return fetchConfigFromMetadataServiceIPv4Only(f) + return fetchConfigFromMetadataServiceIPv4Only(f, retryCodes) } urls := []url.URL{userdataURLs[resource.IPv4]} @@ -198,11 +201,11 @@ func fetchConfigFromMetadataService(f *resource.Fetcher) ([]byte, error) { } // Use parallel fetching for all interfaces - data, err := fetchConfigParallel(f, urls) + data, err := fetchConfigParallel(f, urls, retryCodes) if err != nil { // the metadata server exists but doesn't contain any actual metadata, // assume that there is no config specified - if err == resource.ErrNotFound { + if errors.Is(err, resource.ErrNotFound) { return nil, nil } return nil, err @@ -211,12 +214,12 @@ func fetchConfigFromMetadataService(f *resource.Fetcher) ([]byte, error) { return data, nil } -func fetchConfigFromMetadataServiceIPv4Only(f *resource.Fetcher) ([]byte, error) { +func fetchConfigFromMetadataServiceIPv4Only(f *resource.Fetcher, retryCodes []int) ([]byte, error) { ipv4Url := userdataURLs[resource.IPv4] - data, err := f.FetchToBuffer(ipv4Url, resource.FetchOptions{}) + data, err := f.FetchToBuffer(ipv4Url, resource.FetchOptions{RetryCodes: retryCodes}) if err != nil { - if err == resource.ErrNotFound { + if errors.Is(err, resource.ErrNotFound) { return nil, nil } return nil, err @@ -225,7 +228,7 @@ func fetchConfigFromMetadataServiceIPv4Only(f *resource.Fetcher) ([]byte, error) return data, nil } -func fetchConfigParallel(f *resource.Fetcher, urls []url.URL) ([]byte, error) { +func fetchConfigParallel(f *resource.Fetcher, urls []url.URL, retryCodes []int) ([]byte, error) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -237,18 +240,18 @@ func fetchConfigParallel(f *resource.Fetcher, urls []url.URL) ([]byte, error) { cfg := make(map[url.URL][]byte) success := make(chan url.URL, 1) - errors := make(chan error, len(urls)) + errs := make(chan error, len(urls)) // Use waitgroup to wait for all goroutines to complete var wg sync.WaitGroup fetch := func(_ context.Context, u url.URL) { defer wg.Done() - d, e := f.FetchToBuffer(u, resource.FetchOptions{}) + d, e := f.FetchToBuffer(u, resource.FetchOptions{RetryCodes: retryCodes}) if e != nil { f.Logger.Err("fetching configuration for %s: %v", u.String(), e) err = e - errors <- e + errs <- e } else { cfg[u] = d select { @@ -275,7 +278,7 @@ func fetchConfigParallel(f *resource.Fetcher, urls []url.URL) ([]byte, error) { case u := <-success: f.Logger.Debug("got configuration from: %s", u.String()) return cfg[u], nil - case <-errors: + case <-errs: nbErrors++ if nbErrors == len(urls) { f.Logger.Debug("all routines have failed to fetch configuration, returning last known error: %v", err)