mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-30 01:46:23 +00:00
Merge pull request #2167 from yujunz/loader/http
Allow loading file from http
This commit is contained in:
@@ -7,7 +7,6 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@@ -302,18 +301,15 @@ func (kt *KustTarget) configureExternalTransformers() ([]resmap.Transformer, err
|
||||
func (kt *KustTarget) accumulateResources(
|
||||
ra *accumulator.ResAccumulator, paths []string) error {
|
||||
for _, path := range paths {
|
||||
ldr, err := kt.ldr.New(path)
|
||||
if err == nil {
|
||||
err = kt.accumulateDirectory(ra, ldr)
|
||||
if err != nil {
|
||||
return err
|
||||
// try loading resource as file then as base (directory or git repository)
|
||||
if errF := kt.accumulateFile(ra, path); errF != nil {
|
||||
ldr, errL := kt.ldr.New(path)
|
||||
if errL != nil {
|
||||
return fmt.Errorf("accumulateFile %q, loader.New %q", errF, errL)
|
||||
}
|
||||
} else {
|
||||
err2 := kt.accumulateFile(ra, path)
|
||||
if err2 != nil {
|
||||
// Log ldr.New() error to highlight git failures.
|
||||
log.Print(err.Error())
|
||||
return err2
|
||||
errD := kt.accumulateDirectory(ra, ldr)
|
||||
if errD != nil {
|
||||
return fmt.Errorf("accumulateFile %q, accumulateDirector: %q", errF, errD)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ spec:
|
||||
if err == nil {
|
||||
t.Fatalf("expected an error")
|
||||
}
|
||||
if !IsMissingKustomizationFileError(err) {
|
||||
if !strings.Contains(err.Error(), "accumulating resources") {
|
||||
t.Fatalf("unexpected error: %q", err)
|
||||
}
|
||||
}
|
||||
@@ -89,7 +89,7 @@ resources:
|
||||
if err == nil {
|
||||
t.Fatalf("expected an error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "'/app/deployment.yaml' doesn't exist") {
|
||||
if !strings.Contains(err.Error(), "accumulating resources") {
|
||||
t.Fatalf("unexpected error: %q", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,10 @@ package loader
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
@@ -86,6 +89,9 @@ type fileLoader struct {
|
||||
// File system utilities.
|
||||
fSys filesys.FileSystem
|
||||
|
||||
// Used to load from HTTP
|
||||
http *http.Client
|
||||
|
||||
// Used to clone repositories.
|
||||
cloner git.Cloner
|
||||
|
||||
@@ -293,6 +299,25 @@ func (fl *fileLoader) errIfRepoCycle(newRepoSpec *git.RepoSpec) error {
|
||||
// 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") {
|
||||
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()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return body, nil
|
||||
}
|
||||
|
||||
if !filepath.IsAbs(path) {
|
||||
path = fl.root.Join(path)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
package loader
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -54,6 +56,7 @@ func makeLoader() *fileLoader {
|
||||
return NewFileLoaderAtRoot(MakeFakeFs(testCases))
|
||||
|
||||
}
|
||||
|
||||
func TestLoaderLoad(t *testing.T) {
|
||||
l1 := makeLoader()
|
||||
if "/" != l1.Root() {
|
||||
@@ -579,3 +582,93 @@ func TestRepoIndirectCycleDetection(t *testing.T) {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Inspired by https://hassansin.github.io/Unit-Testing-http-client-in-Go
|
||||
type fakeRoundTripper func(req *http.Request) *http.Response
|
||||
|
||||
func (f fakeRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
return f(req), nil
|
||||
}
|
||||
|
||||
func makeFakeHTTPClient(fn fakeRoundTripper) *http.Client {
|
||||
return &http.Client{
|
||||
Transport: fn,
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoaderHTTP test http file loader
|
||||
func TestLoaderHTTP(t *testing.T) {
|
||||
var testCasesFile = []testData{
|
||||
{
|
||||
path: "http/file.yaml",
|
||||
expectedContent: "file content",
|
||||
},
|
||||
}
|
||||
|
||||
l1 := NewFileLoaderAtRoot(MakeFakeFs(testCasesFile))
|
||||
if "/" != l1.Root() {
|
||||
t.Fatalf("incorrect root: '%s'\n", l1.Root())
|
||||
}
|
||||
for _, x := range testCasesFile {
|
||||
b, err := l1.Load(x.path)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected load error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual([]byte(x.expectedContent), b) {
|
||||
t.Fatalf("in load expected %s, but got %s", x.expectedContent, b)
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesHTTP = []testData{
|
||||
{
|
||||
path: "http://example.com/resource.yaml",
|
||||
expectedContent: "http content",
|
||||
},
|
||||
{
|
||||
path: "https://example.com/resource.yaml",
|
||||
expectedContent: "https content",
|
||||
},
|
||||
}
|
||||
|
||||
for _, x := range testCasesHTTP {
|
||||
hc := makeFakeHTTPClient(func(req *http.Request) *http.Response {
|
||||
u := req.URL.String()
|
||||
if x.path != u {
|
||||
t.Fatalf("expected URL %s, but got %s", x.path, u)
|
||||
}
|
||||
return &http.Response{
|
||||
StatusCode: 200,
|
||||
Body: ioutil.NopCloser(bytes.NewBufferString(x.expectedContent)),
|
||||
Header: make(http.Header),
|
||||
}
|
||||
})
|
||||
l2 := l1
|
||||
l2.http = hc
|
||||
b, err := l2.Load(x.path)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected load error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual([]byte(x.expectedContent), b) {
|
||||
t.Fatalf("in load expected %s, but got %s", x.expectedContent, b)
|
||||
}
|
||||
}
|
||||
|
||||
var testCaseUnsupported = []testData{
|
||||
{
|
||||
path: "httpsnotreal://example.com/resource.yaml",
|
||||
expectedContent: "invalid",
|
||||
},
|
||||
}
|
||||
for _, x := range testCaseUnsupported {
|
||||
hc := makeFakeHTTPClient(func(req *http.Request) *http.Response {
|
||||
t.Fatalf("unexpected request to URL %s", req.URL.String())
|
||||
return nil
|
||||
})
|
||||
l2 := l1
|
||||
l2.http = hc
|
||||
_, err := l2.Load(x.path)
|
||||
if err == nil {
|
||||
t.Fatalf("expect error but get %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
25
examples/loadHttp.md
Normal file
25
examples/loadHttp.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# load file from http
|
||||
|
||||
Resource and patch files could be loaded from http
|
||||
|
||||
<!-- @loadHttp -->
|
||||
```sh
|
||||
DEMO_HOME=$(mktemp -d)
|
||||
|
||||
cat <<EOF >$DEMO_HOME/kustomization.yaml
|
||||
resources:
|
||||
- https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/examples/helloWorld/configMap.yaml
|
||||
EOF
|
||||
```
|
||||
|
||||
<!-- @loadHttp -->
|
||||
```sh
|
||||
test 1 == \
|
||||
$(kustomize build $DEMO_HOME | grep "Good Morning!" | wc -l); \
|
||||
echo $?
|
||||
```
|
||||
|
||||
Kustomize will try loading resource as a file either from local or http. If it
|
||||
fails, try to load it as a directory or git repository.
|
||||
|
||||
Http load applies to patches as well. See full example in [loadHttp](loadHttp/).
|
||||
15
examples/loadHttp/kustomization.yaml
Normal file
15
examples/loadHttp/kustomization.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/examples/wordpress/wordpress/deployment.yaml
|
||||
- https://github.com/knative/serving/releases/download/v0.12.0/serving.yaml # redirects to s3
|
||||
patches:
|
||||
- https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/examples/wordpress/patch.yaml
|
||||
patchesStrategicMerge:
|
||||
- |-
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: custom-metrics-auth-reader
|
||||
namespace: kube-system
|
||||
$patch: delete
|
||||
Reference in New Issue
Block a user