Load and calculate Destination of files for kustomize localize (#4652)

* Implement file localization for localize

Implement file localization for new command kustomize localize

* Patch file localization

Fix lint errors, address feedback, begin transition to file loader from
localizer

* Add Repo() to Loader

* Implement locLoader factory + cleanup

* Add domain to RepoSpec

Fix ssh relative url host parsing for non-github domain on the side

* Implement Load(), New(), Root(), Dst() for LocLoader

* Address repospec code review comments

* Address 1st round of code review feedback

* Address feedback #2

Removed localized path calculations to cover edge case and improve readability.

* Remove ldr Cleanup logging

* Address code review round #3

* Address code review feedback #4
This commit is contained in:
Anna Song
2022-08-19 14:33:53 -07:00
committed by GitHub
parent a8010ac469
commit bf17fe1d8f
27 changed files with 792 additions and 100 deletions

View File

@@ -18,6 +18,13 @@ import (
"sigs.k8s.io/kustomize/kyaml/filesys"
)
// HasRemoteFileScheme returns whether path has a url scheme that kustomize allows for
// remote files. See https://github.com/kubernetes-sigs/kustomize/blob/master/examples/remoteBuild.md
func HasRemoteFileScheme(path string) bool {
u, err := url.Parse(path)
return err == nil && (u.Scheme == "http" || u.Scheme == "https")
}
// fileLoader is a kustomization's interface to files.
//
// The directory in which a kustomization file sits
@@ -114,6 +121,15 @@ func NewFileLoaderAtRoot(fSys filesys.FileSystem) *fileLoader {
RestrictionRootOnly, fSys, filesys.Separator)
}
// Repo returns the absolute path to the repo that contains Root and true
// if this fileLoader was created from a url; otherwise, the empty string and false
func (fl *fileLoader) Repo() (string, bool) {
if fl.repoSpec != nil {
return fl.repoSpec.Dir.String(), true
}
return "", false
}
// Root returns the absolute path that is prepended to any
// relative paths used in Load.
func (fl *fileLoader) Root() string {
@@ -279,34 +295,37 @@ func (fl *fileLoader) errIfRepoCycle(newRepoSpec *git.RepoSpec) error {
return fl.referrer.errIfRepoCycle(newRepoSpec)
}
func loadURL(hc *http.Client, path string) ([]byte, error) {
resp, err := hc.Get(path)
if err != nil {
return nil, errors.WrapPrefixf(err, "cannot GET url")
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode > 299 {
if _, err = git.NewRepoSpecFromURL(path); 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))
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errors.WrapPrefixf(err, "cannot read url content")
}
return body, nil
}
// Load returns the content of file at the given path,
// else an error. Relative paths are taken relative
// to the root.
func (fl *fileLoader) Load(path string) ([]byte, error) {
if u, err := url.Parse(path); err == nil && (u.Scheme == "http" || u.Scheme == "https") {
if HasRemoteFileScheme(path) {
var hc *http.Client
if fl.http != nil {
hc = fl.http
} else {
hc = &http.Client{}
}
resp, err := hc.Get(path)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode > 299 {
_, 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))
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return body, nil
return loadURL(hc, path)
}
if !filepath.IsAbs(path) {
path = fl.root.Join(path)

View File

@@ -21,6 +21,40 @@ import (
"sigs.k8s.io/kustomize/kyaml/filesys"
)
func TestHasRemoteFileScheme(t *testing.T) {
cases := map[string]struct {
url string
valid bool
}{
"https file": {
"https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/examples/helloWorld/configMap.yaml",
true,
},
"https dir": {
"https://github.com/kubernetes-sigs/kustomize//examples/helloWorld/",
true,
},
"no scheme": {
"github.com/kubernetes-sigs/kustomize//examples/helloWorld/",
false,
},
"ssh": {
"ssh://git@github.com/kubernetes-sigs/kustomize.git",
false,
},
"local": {
"pod.yaml",
false,
},
}
for name, test := range cases {
test := test
t.Run(name, func(t *testing.T) {
require.Equal(t, test.valid, HasRemoteFileScheme(test.url))
})
}
}
type testData struct {
path string
expectedContent string
@@ -61,6 +95,8 @@ func TestLoaderLoad(t *testing.T) {
require := require.New(t)
l1 := makeLoader()
_, remote := l1.Repo()
require.False(remote)
require.Equal("/", l1.Root())
for _, x := range testCases {
@@ -73,6 +109,9 @@ func TestLoaderLoad(t *testing.T) {
}
l2, err := l1.New("foo/project")
require.NoError(err)
_, remote = l2.Repo()
require.False(remote)
require.Equal("/foo/project", l2.Root())
for _, x := range testCases {
@@ -322,6 +361,9 @@ whatever
repoSpec, fSys, nil,
git.DoNothingCloner(filesys.ConfirmedDir(coRoot)))
require.NoError(err)
repo, remote := l.Repo()
require.True(remote)
require.Equal(coRoot, repo)
require.Equal(coRoot+"/"+pathInRepo, l.Root())
_, err = l.New(url)
@@ -335,6 +377,10 @@ whatever
url = rootURL + "/" + pathInRepo
l2, err := l.New(url)
require.NoError(err)
repo, remote = l2.Repo()
require.True(remote)
require.Equal(coRoot, repo)
require.Equal(coRoot+"/"+pathInRepo, l2.Root())
}
@@ -389,6 +435,8 @@ func TestLoaderDisallowsLocalBaseFromRemoteOverlay(t *testing.T) {
// This is okay.
l2, err = l1.New("../base")
require.NoError(err)
_, remote := l2.Repo()
require.False(remote)
require.Equal(cloneRoot+"/foo/base", l2.Root())
// This is not okay.
@@ -414,6 +462,9 @@ func TestLocalLoaderReferencingGitBase(t *testing.T) {
l2, err := l1.New("github.com/someOrg/someRepo/foo/base")
require.NoError(err)
repo, remote := l2.Repo()
require.True(remote)
require.Equal(cloneRoot, repo)
require.Equal(cloneRoot+"/foo/base", l2.Root())
}