diff --git a/api/internal/loader/errors.go b/api/internal/loader/errors.go index 2463debdbb..c3f7f61bb1 100644 --- a/api/internal/loader/errors.go +++ b/api/internal/loader/errors.go @@ -9,3 +9,12 @@ var ( ErrHTTP = errors.Errorf("HTTP Error") ErrRtNotDir = errors.Errorf("must build at directory") ) + +type RedirectionError struct { + NewPath string + Msg string +} + +func (e *RedirectionError) Error() string { + return e.Msg +} diff --git a/api/internal/loader/fileloader.go b/api/internal/loader/fileloader.go index 6ecc9fcefa..98476e8f0f 100644 --- a/api/internal/loader/fileloader.go +++ b/api/internal/loader/fileloader.go @@ -106,6 +106,9 @@ type FileLoader struct { cleaner func() error } +// This redirect code does not process automaticaly by http client and we can process it manually +const MultipleChoicesRedirectCode = 300 + // Repo returns the absolute path to the repo that contains Root if this fileLoader was created from a url // or the empty string otherwise. func (fl *FileLoader) Repo() string { @@ -318,11 +321,19 @@ func (fl *FileLoader) httpClientGetContent(path string) ([]byte, error) { defer resp.Body.Close() // response unsuccessful if resp.StatusCode < 200 || resp.StatusCode > 299 { - _, err = git.NewRepoSpecFromURL(path) - if err == nil { - return nil, errors.Errorf("URL is a git repository") + if resp.StatusCode == MultipleChoicesRedirectCode { + var newPath string = resp.Header.Get("Location") + return nil, &RedirectionError{ + Msg: "Response is redirect", + NewPath: newPath, + } + } else { + _, err = git.NewRepoSpecFromURL(path) + if err == nil { + return nil, errors.Errorf("URL is a git repository") + } + return nil, fmt.Errorf("%w: status code %d (%s)", ErrHTTP, resp.StatusCode, http.StatusText(resp.StatusCode)) } - return nil, fmt.Errorf("%w: status code %d (%s)", ErrHTTP, resp.StatusCode, http.StatusText(resp.StatusCode)) } content, err := io.ReadAll(resp.Body) return content, errors.Wrap(err) diff --git a/api/internal/loader/fileloader_test.go b/api/internal/loader/fileloader_test.go index fc33a87235..5d47547596 100644 --- a/api/internal/loader/fileloader_test.go +++ b/api/internal/loader/fileloader_test.go @@ -19,6 +19,7 @@ import ( "sigs.k8s.io/kustomize/api/ifc" "sigs.k8s.io/kustomize/api/internal/git" "sigs.k8s.io/kustomize/api/konfig" + "sigs.k8s.io/kustomize/kyaml/errors" "sigs.k8s.io/kustomize/kyaml/filesys" ) @@ -659,6 +660,35 @@ func TestLoaderHTTP(t *testing.T) { _, err := l2.Load(x.path) require.Error(err) } + + var testCaseRedirect = []testData{ + { + path: "https://example.com/resource.yaml", + expectedContent: "https content", + }, + } + for _, x := range testCaseRedirect { + expectedLocation := "https://test.com/resource.yaml" + hc := makeFakeHTTPClient(func(req *http.Request) *http.Response { + response := &http.Response{ + StatusCode: MultipleChoicesRedirectCode, + Body: io.NopCloser(bytes.NewBufferString("")), + Header: make(http.Header), + } + response.Header.Add("Location", expectedLocation) + return response + }) + l2 := l1 + l2.http = hc + _, err := l2.Load(x.path) + require.Error(err) + var redErr *RedirectionError + var path string = "" + if errors.As(err, &redErr) { + path = redErr.NewPath + } + require.Equal(expectedLocation, path) + } } // setupOnDisk sets up a file system on disk and directory that is cleaned after diff --git a/api/internal/localizer/localizer.go b/api/internal/localizer/localizer.go index 71de9dd6f8..a1c7f94c36 100644 --- a/api/internal/localizer/localizer.go +++ b/api/internal/localizer/localizer.go @@ -335,6 +335,11 @@ func (lc *localizer) localizeResource(path string) (string, error) { } } if fileErr != nil { + var redErr *loader.RedirectionError + if errors.As(fileErr, &redErr) { + path = redErr.NewPath + } + var rootErr error locPath, rootErr = lc.localizeRoot(path) if rootErr != nil { diff --git a/api/internal/target/kusttarget.go b/api/internal/target/kusttarget.go index 44c82bc597..b2821ea6bd 100644 --- a/api/internal/target/kusttarget.go +++ b/api/internal/target/kusttarget.go @@ -423,7 +423,12 @@ func (kt *KustTarget) accumulateResources( if errors.Is(errF, load.ErrHTTP) { return nil, errF } + var redErr *load.RedirectionError + if errors.As(errF, &redErr) { + path = redErr.NewPath + } ldr, err := kt.ldr.New(path) + if err != nil { // If accumulateFile found malformed YAML and there was a failure // loading the resource as a base, then the resource is likely a