Skip to content

Commit ad09355

Browse files
authored
Merge pull request #398 from monopole/injectDecoder
Introduce k8sdeps package to isolate k8s deps.
2 parents 2fbccdd + 8f150d8 commit ad09355

File tree

12 files changed

+208
-28
lines changed

12 files changed

+208
-28
lines changed

pkg/commands/build.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"errors"
2121
"io"
2222
"log"
23+
"sigs.k8s.io/kustomize/pkg/ifc"
2324
"strings"
2425

2526
"github.com/spf13/cobra"
@@ -57,7 +58,9 @@ Use different transformer configurations by passing files to kustomize
5758
`
5859

5960
// newCmdBuild creates a new build command.
60-
func newCmdBuild(out io.Writer, fs fs.FileSystem) *cobra.Command {
61+
func newCmdBuild(
62+
out io.Writer, fs fs.FileSystem,
63+
decoder ifc.Decoder) *cobra.Command {
6164
var o buildOptions
6265
var p string
6366

@@ -71,7 +74,7 @@ func newCmdBuild(out io.Writer, fs fs.FileSystem) *cobra.Command {
7174
if err != nil {
7275
return err
7376
}
74-
return o.RunBuild(out, fs)
77+
return o.RunBuild(out, fs, decoder)
7578
},
7679
}
7780
cmd.Flags().StringVarP(
@@ -114,14 +117,18 @@ func (o *buildOptions) Validate(args []string, p string, fs fs.FileSystem) error
114117
}
115118

116119
// RunBuild runs build command.
117-
func (o *buildOptions) RunBuild(out io.Writer, fSys fs.FileSystem) error {
120+
func (o *buildOptions) RunBuild(
121+
out io.Writer, fSys fs.FileSystem,
122+
decoder ifc.Decoder) error {
118123
rootLoader, err := loader.NewLoader(o.kustomizationPath, "", fSys)
119124
if err != nil {
120125
return err
121126
}
122127
defer rootLoader.Cleanup()
123128
kt, err := target.NewKustTarget(
124-
rootLoader, fSys, makeTransformerconfig(fSys, o.transformerconfigPaths))
129+
rootLoader, fSys,
130+
makeTransformerconfig(fSys, o.transformerconfigPaths),
131+
decoder)
125132
if err != nil {
126133
return err
127134
}

pkg/commands/build_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"os"
2323
"path/filepath"
2424
"reflect"
25+
"sigs.k8s.io/kustomize/pkg/internal/k8sdeps"
2526
"strings"
2627
"testing"
2728

@@ -124,7 +125,7 @@ func runBuildTestCase(t *testing.T, testcaseName string, updateKustomizeExpected
124125
kustomizationPath: testcase.Filename,
125126
}
126127
buf := bytes.NewBuffer([]byte{})
127-
err = ops.RunBuild(buf, fSys)
128+
err = ops.RunBuild(buf, fSys, k8sdeps.NewKustDecoder())
128129
switch {
129130
case err != nil && len(testcase.ExpectedError) == 0:
130131
t.Errorf("unexpected error: %v", err)

pkg/commands/commands.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ package commands
2020
import (
2121
"flag"
2222
"os"
23+
"sigs.k8s.io/kustomize/pkg/internal/k8sdeps"
2324

2425
"github.com/spf13/cobra"
2526
"sigs.k8s.io/kustomize/pkg/fs"
@@ -43,7 +44,7 @@ See https://sigs.k8s.io/kustomize
4344

4445
c.AddCommand(
4546
// TODO: Make consistent API for newCmd* functions.
46-
newCmdBuild(stdOut, fsys),
47+
newCmdBuild(stdOut, fsys, k8sdeps.NewKustDecoder()),
4748
newCmdEdit(fsys),
4849
newCmdConfig(fsys),
4950
newCmdVersion(stdOut),

pkg/ifc/ifc.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
Copyright 2018 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
// Package ifc holds miscellaneous interfaces used by kustomize.
18+
package ifc
19+
20+
// Decoder unmarshalls byte input into an object.
21+
type Decoder interface {
22+
// SetInput accepts new input.
23+
SetInput([]byte)
24+
// Decode yields the next object from the input, else io.EOF
25+
Decode(interface{}) error
26+
}

pkg/internal/k8sdeps/decoder.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
Copyright 2018 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package k8sdeps
18+
19+
import (
20+
"bytes"
21+
"errors"
22+
"k8s.io/apimachinery/pkg/util/yaml"
23+
)
24+
25+
// KustDecoder unmarshalls bytes to objects.
26+
type KustDecoder struct {
27+
d *yaml.YAMLOrJSONDecoder
28+
}
29+
30+
// NewKustDecoder returns a new KustDecoder.
31+
func NewKustDecoder() *KustDecoder {
32+
return &KustDecoder{}
33+
}
34+
35+
// SetInput initializes an apimachinery decoder.
36+
func (k *KustDecoder) SetInput(in []byte) {
37+
k.d = yaml.NewYAMLOrJSONDecoder(
38+
bytes.NewReader(in), 1024)
39+
}
40+
41+
// Decode delegates to the apimachinery decoder.
42+
func (k *KustDecoder) Decode(into interface{}) error {
43+
if k.d == nil {
44+
return errors.New("no decoder")
45+
}
46+
return k.d.Decode(into)
47+
}

pkg/internal/k8sdeps/doc.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
Copyright 2018 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
// It's possible that kustomize's features will be vendored into
18+
// the kubernetes/kubernetes repo and made available to kubectl
19+
// commands, while at the same time the kustomize program will
20+
// continue to exist as an independent CLI. Vendoring snapshots
21+
// would be taken just before a kubectl release.
22+
//
23+
// This creates a problem in that freestanding-kustomize depends on
24+
// (for example):
25+
//
26+
// https://github.com/kubernetes/apimachinery/
27+
// tree/master/pkg/util/yaml
28+
//
29+
// It vendors that package into
30+
// sigs.k8s.io/kustomize/vendor/k8s.io/apimachinery/
31+
//
32+
// Whereas kubectl-kustomize would have to depend on the "staging"
33+
// version of this code, located at
34+
//
35+
// https://github.com/kubernetes/kubernetes/
36+
// blob/master/staging/src/k8s.io/apimachinery/pkg/util/yaml
37+
//
38+
// which is "vendored" via symlinks:
39+
// k8s.io/kubernetes/vendor/k8s.io/apimachinery
40+
// is a symlink to
41+
// ../../staging/src/k8s.io/apimachinery
42+
//
43+
// The staging version is the canonical, under-development
44+
// version of the code that kubectl depends on, whereas the packages
45+
// at kubernetes/apimachinery are periodic snapshots of staging made
46+
// for outside tools to depend on.
47+
//
48+
// apimachinery isn't the only package that poses this problem, just
49+
// using it as a specific example.
50+
//
51+
// The kubectl binary cannot vendor in kustomize code that in
52+
// turn vendors in the non-staging packages.
53+
//
54+
// One way to fix some of this would be to copy code - a hard fork.
55+
// This has all the problems associated with a hard forking.
56+
//
57+
// Another way would be to break the kustomize repo into three:
58+
//
59+
// (1) kustomize - repo with the main() function,
60+
// vendoring (2) and (3).
61+
//
62+
// (2) kustomize-libs - packages used by (1) with no
63+
// apimachinery dependence.
64+
//
65+
// (3) kustomize-k8sdeps - A thin code layer that depends
66+
// on (vendors) apimachinery to provide thin implementations
67+
// to interfaces used in (2).
68+
//
69+
// The kubectl repo would then vendor from (2) only, and have
70+
// a local implementation of (3). With that in mind, it's clear
71+
// that (3) doesn't have to be a repo; the kustomize version of
72+
// the thin layer can live directly in (1).
73+
//
74+
// This package is the code in (3), meant for kustomize.
75+
76+
package k8sdeps

pkg/resmap/resmap.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"bytes"
2222
"fmt"
2323
"reflect"
24+
"sigs.k8s.io/kustomize/pkg/ifc"
2425
"sort"
2526

2627
"github.com/ghodss/yaml"
@@ -151,14 +152,16 @@ func (m ResMap) FilterBy(inputId resource.ResId) ResMap {
151152
}
152153

153154
// NewResMapFromFiles returns a ResMap given a resource path slice.
154-
func NewResMapFromFiles(loader loader.Loader, paths []string) (ResMap, error) {
155+
func NewResMapFromFiles(
156+
loader loader.Loader, paths []string,
157+
d ifc.Decoder) (ResMap, error) {
155158
var result []ResMap
156159
for _, path := range paths {
157160
content, err := loader.Load(path)
158161
if err != nil {
159162
return nil, errors.Wrap(err, "Load from path "+path+" failed")
160163
}
161-
res, err := newResMapFromBytes(content)
164+
res, err := newResMapFromBytes(content, d)
162165
if err != nil {
163166
return nil, internal.Handler(err, path)
164167
}
@@ -168,8 +171,8 @@ func NewResMapFromFiles(loader loader.Loader, paths []string) (ResMap, error) {
168171
}
169172

170173
// newResMapFromBytes decodes a list of objects in byte array format.
171-
func newResMapFromBytes(b []byte) (ResMap, error) {
172-
resources, err := resource.NewResourceSliceFromBytes(b)
174+
func newResMapFromBytes(b []byte, d ifc.Decoder) (ResMap, error) {
175+
resources, err := resource.NewResourceSliceFromBytes(b, d)
173176
if err != nil {
174177
return nil, err
175178
}

pkg/resmap/resmap_test.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package resmap
1919
import (
2020
"fmt"
2121
"reflect"
22+
"sigs.k8s.io/kustomize/pkg/internal/k8sdeps"
2223
"testing"
2324

2425
"sigs.k8s.io/kustomize/pkg/gvk"
@@ -106,7 +107,9 @@ metadata:
106107
}),
107108
}
108109

109-
m, _ := NewResMapFromFiles(l, []string{"/home/seans/project/deployment.yaml"})
110+
m, _ := NewResMapFromFiles(
111+
l, []string{"/home/seans/project/deployment.yaml"},
112+
k8sdeps.NewKustDecoder())
110113
if len(m) != 2 {
111114
t.Fatalf("%#v should contain 2 appResource, but got %d", m, len(m))
112115
}
@@ -145,7 +148,7 @@ metadata:
145148
},
146149
}),
147150
}
148-
m, err := newResMapFromBytes(encoded)
151+
m, err := newResMapFromBytes(encoded, k8sdeps.NewKustDecoder())
149152
fmt.Printf("%v\n", m)
150153
if err != nil {
151154
t.Fatalf("unexpected error: %v", err)

pkg/resource/resource.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ limitations under the License.
1818
package resource
1919

2020
import (
21-
"bytes"
2221
"encoding/json"
2322
"fmt"
2423
"io"
@@ -27,8 +26,8 @@ import (
2726
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2827
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2928
"k8s.io/apimachinery/pkg/runtime"
30-
"k8s.io/apimachinery/pkg/util/yaml"
3129
"sigs.k8s.io/kustomize/pkg/gvk"
30+
"sigs.k8s.io/kustomize/pkg/ifc"
3231
internal "sigs.k8s.io/kustomize/pkg/internal/error"
3332
"sigs.k8s.io/kustomize/pkg/loader"
3433
"sigs.k8s.io/kustomize/pkg/patch"
@@ -68,14 +67,15 @@ func NewResourceFromUnstruct(u unstructured.Unstructured) *Resource {
6867
// NewResourceSliceFromPatches returns a slice of resources given a patch path
6968
// slice from a kustomization file.
7069
func NewResourceSliceFromPatches(
71-
ldr loader.Loader, paths []patch.StrategicMerge) ([]*Resource, error) {
70+
ldr loader.Loader, paths []patch.StrategicMerge,
71+
decoder ifc.Decoder) ([]*Resource, error) {
7272
var result []*Resource
7373
for _, path := range paths {
7474
content, err := ldr.Load(string(path))
7575
if err != nil {
7676
return nil, err
7777
}
78-
res, err := NewResourceSliceFromBytes(content)
78+
res, err := NewResourceSliceFromBytes(content, decoder)
7979
if err != nil {
8080
return nil, internal.Handler(err, string(path))
8181
}
@@ -85,8 +85,9 @@ func NewResourceSliceFromPatches(
8585
}
8686

8787
// NewResourceSliceFromBytes unmarshalls bytes into a Resource slice.
88-
func NewResourceSliceFromBytes(in []byte) ([]*Resource, error) {
89-
decoder := yaml.NewYAMLOrJSONDecoder(bytes.NewReader(in), 1024)
88+
func NewResourceSliceFromBytes(
89+
in []byte, decoder ifc.Decoder) ([]*Resource, error) {
90+
decoder.SetInput(in)
9091
var result []*Resource
9192
var err error
9293
for err == nil || isEmptyYamlError(err) {

pkg/resource/resource_test.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package resource
1818

1919
import (
2020
"reflect"
21+
"sigs.k8s.io/kustomize/pkg/internal/k8sdeps"
2122
"testing"
2223

2324
"sigs.k8s.io/kustomize/pkg/internal/loadertest"
@@ -121,7 +122,8 @@ WOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOT: woot
121122
},
122123
}
123124
for _, test := range tests {
124-
rs, err := NewResourceSliceFromPatches(l, test.input)
125+
rs, err := NewResourceSliceFromPatches(
126+
l, test.input, k8sdeps.NewKustDecoder())
125127
if test.expectedErr && err == nil {
126128
t.Fatalf("%v: should return error", test.name)
127129
}
@@ -211,7 +213,8 @@ WOOOOOOOOOOOOOOOOOOOOOOOOT: woot
211213
}
212214

213215
for _, test := range tests {
214-
rs, err := NewResourceSliceFromBytes(test.input)
216+
rs, err := NewResourceSliceFromBytes(
217+
test.input, k8sdeps.NewKustDecoder())
215218
if test.expectedErr && err == nil {
216219
t.Fatalf("%v: should return error", test.name)
217220
}

0 commit comments

Comments
 (0)