From 0f5ffa0d49b3d5e813db981468f62d4195c85f31 Mon Sep 17 00:00:00 2001 From: Dmitry Volodin Date: Sun, 5 Jan 2025 15:50:45 +0300 Subject: [PATCH] Add specific DecodeURL function in decoder package --- klient/decoder/decoder.go | 17 +++++++++++++++-- klient/decoder/decoder_test.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/klient/decoder/decoder.go b/klient/decoder/decoder.go index 6f558d1d..adf9008e 100644 --- a/klient/decoder/decoder.go +++ b/klient/decoder/decoder.go @@ -27,6 +27,7 @@ import ( "os" "strings" + "github.com/vladimirvivien/gexe/http" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" @@ -83,7 +84,7 @@ func DecodeEachFile(ctx context.Context, fsys fs.FS, pattern string, handlerFn H return nil } -// DecodeAllFiles resolves files at the filesystem matching the pattern, decoding JSON or YAML files. Supports multi-document files. +// DecodeAllFiles resolves files at the filesystem matching the pattern, decoding JSON or YAML files. Supports multi-document files. // Falls back to the unstructured.Unstructured type if a matching type cannot be found for the Kind. // Options may be provided to configure the behavior of the decoder. func DecodeAllFiles(ctx context.Context, fsys fs.FS, pattern string, options ...DecodeOption) ([]k8s.Object, error) { @@ -140,7 +141,7 @@ func DecodeEach(ctx context.Context, manifest io.Reader, handlerFn HandlerFunc, return nil } -// DecodeAll is a stream of documents of any Kind using either the innate typing of the scheme. +// DecodeAll is a stream of documents of any Kind using either the innate typing of the scheme. // Falls back to the unstructured.Unstructured type if a matching type cannot be found for the Kind. // Options may be provided to configure the behavior of the decoder. func DecodeAll(ctx context.Context, manifest io.Reader, options ...DecodeOption) ([]k8s.Object, error) { @@ -217,6 +218,18 @@ func DecodeFile(fsys fs.FS, manifestPath string, obj k8s.Object, options ...Deco return Decode(f, obj, options...) } +// DecodeURL decodes a document from the URL of any Kind using either the innate typing of the scheme. +// Falls back to the unstructured.Unstructured type if a matching type cannot be found for the Kind. +func DecodeURL(ctx context.Context, url string, handlerFn HandlerFunc, options ...DecodeOption) error { + resp := http.Get(url).Do() + if resp.Err() != nil { + return resp.Err() + } + defer resp.Body().Close() + + return DecodeEach(ctx, resp.Body(), handlerFn, options...) +} + // DecodeString decodes a single-document YAML or JSON string into the provided object. Patches are applied // after decoding to the object to update the loaded resource. func DecodeString(rawManifest string, obj k8s.Object, options ...DecodeOption) error { diff --git a/klient/decoder/decoder_test.go b/klient/decoder/decoder_test.go index 4d0015ee..c1f4e930 100644 --- a/klient/decoder/decoder_test.go +++ b/klient/decoder/decoder_test.go @@ -18,7 +18,10 @@ package decoder_test import ( "context" + _ "embed" "fmt" + "net/http" + "net/http/httptest" "os" "path/filepath" "testing" @@ -38,6 +41,9 @@ const ( serviceAccountPrefix = "example-sa*" ) +//go:embed testdata/example-multidoc-1.yaml +var testDataExampleMultiDoc string + func TestDecode(t *testing.T) { testYAML := filepath.Join("testdata", "example-configmap-1.yaml") f, err := os.Open(testYAML) @@ -217,6 +223,33 @@ func TestDecodeEach(t *testing.T) { } } +func TestDecodeURL(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprint(w, testDataExampleMultiDoc) + })) + defer ts.Close() + t.Run("Testing decode with URL", func(t *testing.T) { + count := 0 + err := decoder.DecodeURL(context.TODO(), ts.URL, func(ctx context.Context, obj k8s.Object) error { + count++ + switch cfg := obj.(type) { + case *v1.ConfigMap: + if _, ok := cfg.Data["foo"]; !ok { + t.Fatalf("expected key 'foo' in ConfigMap.Data, got: %v", cfg.Data) + } + default: + t.Fatalf("unexpected type returned not ConfigMap: %T", cfg) + } + return nil + }) + if err != nil { + t.Fatal(err) + } else if count != 2 { + t.Fatalf("expected 2 documents, got: %d", count) + } + }) +} + func TestDecodeAll(t *testing.T) { for _, file := range []string{"example-multidoc-1.yaml", "example-multidoc-emptyitemcomment.yaml"} { t.Run(fmt.Sprintf("Testing multi doc with %s", file), func(t *testing.T) {