Remove package tree
This commit is contained in:
parent
62ee664fbe
commit
e069e421d0
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tree
|
||||
|
||||
import (
|
||||
"path"
|
||||
|
||||
manifest "k8s.io/kubectl/pkg/apis/manifest/v1alpha1"
|
||||
)
|
||||
|
||||
func adjustPathsForManifest(m *manifest.Manifest, pathToDir []string) {
|
||||
m.Packages = adjustPaths(m.Packages, pathToDir)
|
||||
m.Resources = adjustPaths(m.Resources, pathToDir)
|
||||
m.Patches = adjustPaths(m.Patches, pathToDir)
|
||||
m.Configmaps = adjustPathForConfigMaps(m.Configmaps, pathToDir)
|
||||
}
|
||||
|
||||
func adjustPathForConfigMaps(cms []manifest.ConfigMap, prefix []string) []manifest.ConfigMap {
|
||||
for i, cm := range cms {
|
||||
if len(cm.FileSources) > 0 {
|
||||
for j, fileSource := range cm.FileSources {
|
||||
cms[i].FileSources[j] = adjustPath(fileSource, prefix)
|
||||
}
|
||||
}
|
||||
if len(cm.EnvSource) > 0 {
|
||||
cms[i].EnvSource = adjustPath(cm.EnvSource, prefix)
|
||||
}
|
||||
}
|
||||
return cms
|
||||
}
|
||||
|
||||
func adjustPath(original string, prefix []string) string {
|
||||
return path.Join(append(prefix, original)...)
|
||||
}
|
||||
|
||||
func adjustPaths(original []string, prefix []string) []string {
|
||||
for i, filename := range original {
|
||||
original[i] = adjustPath(filename, prefix)
|
||||
}
|
||||
return original
|
||||
}
|
||||
|
|
@ -1,168 +0,0 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tree
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
manifest "k8s.io/kubectl/pkg/apis/manifest/v1alpha1"
|
||||
cutil "k8s.io/kubectl/pkg/kinflate/configmapandsecret"
|
||||
"k8s.io/kubectl/pkg/kinflate/types"
|
||||
kutil "k8s.io/kubectl/pkg/kinflate/util"
|
||||
)
|
||||
|
||||
// LoadManifestDataFromPath takes a path to a Kube-manifest.yaml or a dir that has a Kube-manifest.yaml.
|
||||
// It returns a tree of ManifestData.
|
||||
func (l *ManifestLoader) LoadManifestDataFromPath() (*ManifestData, error) {
|
||||
m, err := l.loadManifestFileFromPath()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return l.manifestToManifestData(m)
|
||||
}
|
||||
|
||||
// loadManifestFileFromPath loads a manifest object from file.
|
||||
func (l *ManifestLoader) loadManifestFileFromPath() (*manifest.Manifest, error) {
|
||||
mLoader := ManifestLoader{FS: l.FS}
|
||||
// Expand the initial directory or file path into the full manifest file path.
|
||||
fullFilepath, err := mLoader.MakeValidManifestPath(l.InitialPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l.fullFilePath = fullFilepath
|
||||
m, err := mLoader.Read(fullFilepath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mLoader.Validate(m)
|
||||
return m, err
|
||||
}
|
||||
|
||||
// manifestToManifestData make a ManifestData given an Manifest object
|
||||
func (l *ManifestLoader) manifestToManifestData(m *manifest.Manifest) (*ManifestData, error) {
|
||||
mdata, err := l.loadManifestDataFromManifestFileAndResources(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pkgs := []*ManifestData{}
|
||||
for _, pkg := range m.Packages {
|
||||
loader := &ManifestLoader{FS: l.FS, InitialPath: pkg}
|
||||
pkgNode, err := loader.LoadManifestDataFromPath()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pkgs = append(pkgs, pkgNode)
|
||||
}
|
||||
mdata.Packages = pkgs
|
||||
return mdata, nil
|
||||
}
|
||||
|
||||
func (l *ManifestLoader) loadManifestDataFromManifestFileAndResources(m *manifest.Manifest) (*ManifestData, error) {
|
||||
mdata := &ManifestData{}
|
||||
var err error
|
||||
mdata.Name = m.Name
|
||||
mdata.NamePrefix = NamePrefixType(m.NamePrefix)
|
||||
mdata.ObjectLabels = m.ObjectLabels
|
||||
mdata.ObjectAnnotations = m.ObjectAnnotations
|
||||
|
||||
res, err := l.loadKObjectFromPaths(m.Resources)
|
||||
if err != nil {
|
||||
errorMsg := fmt.Sprintf("Resource from Manifest (%s) couldn't be loaded properly.\n%v\n"+
|
||||
"Please check the Resource subsection in (%s).", l.fullFilePath, err, l.fullFilePath)
|
||||
return nil, fmt.Errorf(errorMsg)
|
||||
}
|
||||
mdata.Resources = ResourcesType(res)
|
||||
|
||||
pat, err := l.loadKObjectFromPaths(m.Patches)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mdata.Patches = PatchesType(pat)
|
||||
|
||||
cms, err := cutil.MakeConfigMapsKObject(m.Configmaps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mdata.Configmaps = ConfigmapsType(cms)
|
||||
|
||||
sec, err := cutil.MakeSecretsKObject(m.SecretGenerators, l.fullFilePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mdata.Secrets = SecretsType(sec)
|
||||
return mdata, nil
|
||||
}
|
||||
|
||||
func (l *ManifestLoader) loadKObjectFromPaths(paths []string) (types.KObject, error) {
|
||||
res := types.KObject{}
|
||||
for _, path := range paths {
|
||||
err := l.loadKObjectFromPath(path, res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (l *ManifestLoader) loadKObjectFromPath(path string, into types.KObject) error {
|
||||
_, err := l.FS.Stat(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if into == nil {
|
||||
return fmt.Errorf("cannot load object to an empty KObject")
|
||||
}
|
||||
|
||||
var e error
|
||||
filepath.Walk(path, func(filepath string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
e = err
|
||||
return err
|
||||
}
|
||||
// Skip all the dir
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
err = l.loadKObjectFromFile(filepath, into)
|
||||
return nil
|
||||
})
|
||||
return e
|
||||
}
|
||||
|
||||
func (l *ManifestLoader) loadKObjectFromFile(filename string, into types.KObject) error {
|
||||
f, err := l.FS.Stat(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if f.IsDir() {
|
||||
return fmt.Errorf("%q is NOT expected to be an dir", filename)
|
||||
}
|
||||
content, err := l.FS.ReadFile(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = kutil.DecodeToKObject(content, into)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,346 +0,0 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tree
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
manifest "k8s.io/kubectl/pkg/apis/manifest/v1alpha1"
|
||||
"k8s.io/kubectl/pkg/kinflate/types"
|
||||
"k8s.io/kubectl/pkg/kinflate/util/fs"
|
||||
)
|
||||
|
||||
func makeMapOfConfigMap() types.KObject {
|
||||
return types.KObject{
|
||||
{
|
||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||
Name: "cm1",
|
||||
}: {
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm1",
|
||||
},
|
||||
"data": map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func makeMapOfPod() types.KObject {
|
||||
return makeMapOfPodWithImageName("nginx")
|
||||
}
|
||||
|
||||
func makeMapOfPodWithImageName(imageName string) types.KObject {
|
||||
return types.KObject{
|
||||
{
|
||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Pod"},
|
||||
Name: "pod1",
|
||||
}: {
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Pod",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "pod1",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "nginx",
|
||||
"image": imageName,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func makeManifestData(name string) *ManifestData {
|
||||
return &ManifestData{
|
||||
Name: name,
|
||||
Resources: ResourcesType(types.KObject{}),
|
||||
Patches: PatchesType(types.KObject{}),
|
||||
Configmaps: ConfigmapsType(types.KObject{}),
|
||||
Secrets: SecretsType(types.KObject{}),
|
||||
Packages: []*ManifestData{},
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileToMap(t *testing.T) {
|
||||
type testcase struct {
|
||||
filename string
|
||||
expected types.KObject
|
||||
expectErr bool
|
||||
errorStr string
|
||||
}
|
||||
|
||||
testcases := []testcase{
|
||||
{
|
||||
filename: "testdata/valid/cm/configmap.yaml",
|
||||
expected: types.KObject{
|
||||
{
|
||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||
Name: "cm1",
|
||||
}: {
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm1",
|
||||
},
|
||||
"data": map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
filename: "testdata/valid/cm/",
|
||||
expectErr: true,
|
||||
errorStr: "NOT expected to be an dir",
|
||||
},
|
||||
{
|
||||
filename: "does-not-exist",
|
||||
expectErr: true,
|
||||
errorStr: "no such file or directory",
|
||||
},
|
||||
}
|
||||
|
||||
// TODO: Convert to a fake filesystem instead of using test files.
|
||||
loader := ManifestLoader{FS: fs.MakeRealFS()}
|
||||
|
||||
for _, tc := range testcases {
|
||||
actual := types.KObject{}
|
||||
err := loader.loadKObjectFromFile(tc.filename, actual)
|
||||
if err == nil {
|
||||
if tc.expectErr {
|
||||
t.Errorf("filename: %q, expect an error containing %q, but didn't get an error", tc.filename, tc.errorStr)
|
||||
}
|
||||
if !reflect.DeepEqual(actual, tc.expected) {
|
||||
t.Errorf("filename: %q, expect %v, but got %v", tc.filename, tc.expected, actual)
|
||||
}
|
||||
} else {
|
||||
if tc.expectErr {
|
||||
if !strings.Contains(err.Error(), tc.errorStr) {
|
||||
t.Errorf("filename: %q, expect an error containing %q, but got %v", tc.filename, tc.errorStr, err)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPathToMap(t *testing.T) {
|
||||
type testcase struct {
|
||||
filename string
|
||||
expected types.KObject
|
||||
expectErr bool
|
||||
errorStr string
|
||||
}
|
||||
|
||||
expectedMap := makeMapOfConfigMap()
|
||||
|
||||
testcases := []testcase{
|
||||
{
|
||||
filename: "testdata/valid/cm/configmap.yaml",
|
||||
expected: expectedMap,
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
filename: "testdata/valid/cm/",
|
||||
expected: expectedMap,
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
filename: "does-not-exist",
|
||||
expectErr: true,
|
||||
errorStr: "no such file or directory",
|
||||
},
|
||||
}
|
||||
|
||||
// TODO: Convert to a fake filesystem instead of using test files.
|
||||
loader := ManifestLoader{FS: fs.MakeRealFS()}
|
||||
|
||||
for _, tc := range testcases {
|
||||
actual := types.KObject{}
|
||||
err := loader.loadKObjectFromPath(tc.filename, actual)
|
||||
if err == nil {
|
||||
if tc.expectErr {
|
||||
t.Errorf("filename: %q, expect an error containing %q, but didn't get an error", tc.filename, tc.errorStr)
|
||||
}
|
||||
if !reflect.DeepEqual(actual, tc.expected) {
|
||||
t.Errorf("filename: %q, expect %v, but got %v", tc.filename, tc.expected, actual)
|
||||
}
|
||||
} else {
|
||||
if tc.expectErr {
|
||||
if !strings.Contains(err.Error(), tc.errorStr) {
|
||||
t.Errorf("filename: %q, expect an error containing %q, but got %v", tc.filename, tc.errorStr, err)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPathsToMap(t *testing.T) {
|
||||
type testcase struct {
|
||||
filenames []string
|
||||
expected types.KObject
|
||||
expectErr bool
|
||||
errorStr string
|
||||
}
|
||||
|
||||
mapOfConfigMap := makeMapOfConfigMap()
|
||||
mapOfPod := makeMapOfPod()
|
||||
err := types.Merge(mapOfPod, mapOfConfigMap)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
mergedMap := mapOfPod
|
||||
|
||||
testcases := []testcase{
|
||||
{
|
||||
filenames: []string{"testdata/valid/cm/"},
|
||||
expected: mapOfConfigMap,
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
filenames: []string{"testdata/valid/pod.yaml"},
|
||||
expected: makeMapOfPod(),
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
filenames: []string{"testdata/valid/cm/", "testdata/valid/pod.yaml"},
|
||||
expected: mergedMap,
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
filenames: []string{"does-not-exist"},
|
||||
expectErr: true,
|
||||
errorStr: "no such file or directory",
|
||||
},
|
||||
}
|
||||
|
||||
// TODO: Convert to a fake filesystem instead of using test files.
|
||||
loader := ManifestLoader{FS: fs.MakeRealFS()}
|
||||
|
||||
for _, tc := range testcases {
|
||||
actual, err := loader.loadKObjectFromPaths(tc.filenames)
|
||||
if err == nil {
|
||||
if tc.expectErr {
|
||||
t.Errorf("filenames: %q, expect an error containing %q, but didn't get an error", tc.filenames, tc.errorStr)
|
||||
}
|
||||
if !reflect.DeepEqual(actual, tc.expected) {
|
||||
t.Errorf("filenames: %q, expect %v, but got %v", tc.filenames, tc.expected, actual)
|
||||
}
|
||||
} else {
|
||||
if tc.expectErr {
|
||||
if !strings.Contains(err.Error(), tc.errorStr) {
|
||||
t.Errorf("filenames: %q, expect an error containing %q, but got %v", tc.filenames, tc.errorStr, err)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestManifestToManifestData(t *testing.T) {
|
||||
mapOfConfigMap := makeMapOfConfigMap()
|
||||
mapOfPod := makeMapOfPod()
|
||||
err := types.Merge(mapOfPod, mapOfConfigMap)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
mergedMap := mapOfPod
|
||||
|
||||
m := &manifest.Manifest{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-manifest",
|
||||
},
|
||||
NamePrefix: "someprefix-",
|
||||
ObjectLabels: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
ObjectAnnotations: map[string]string{
|
||||
"note": "This is an annotation.",
|
||||
},
|
||||
Resources: []string{
|
||||
"testdata/valid/cm/",
|
||||
"testdata/valid/pod.yaml",
|
||||
},
|
||||
Patches: []string{
|
||||
"testdata/valid/patch.yaml",
|
||||
},
|
||||
}
|
||||
|
||||
expectedMd := &ManifestData{
|
||||
Name: "test-manifest",
|
||||
NamePrefix: "someprefix-",
|
||||
ObjectLabels: map[string]string{"foo": "bar"},
|
||||
ObjectAnnotations: map[string]string{"note": "This is an annotation."},
|
||||
Resources: ResourcesType(mergedMap),
|
||||
Patches: PatchesType(makeMapOfPodWithImageName("nginx:latest")),
|
||||
Configmaps: ConfigmapsType(types.KObject{}),
|
||||
Secrets: SecretsType(types.KObject{}),
|
||||
}
|
||||
|
||||
// TODO: Convert to a fake filesystem instead of using test files.
|
||||
loader := ManifestLoader{FS: fs.MakeRealFS()}
|
||||
actual, err := loader.loadManifestDataFromManifestFileAndResources(m)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(actual, expectedMd) {
|
||||
t.Errorf("expect:\n%#v\nbut got:\n%#v", expectedMd, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadManifestDataFromPath(t *testing.T) {
|
||||
grandparent := makeManifestData("grandparent")
|
||||
parent1 := makeManifestData("parent1")
|
||||
parent2 := makeManifestData("parent2")
|
||||
child1 := makeManifestData("child1")
|
||||
child2 := makeManifestData("child2")
|
||||
grandparent.Packages = []*ManifestData{parent1, parent2}
|
||||
parent1.Packages = []*ManifestData{child1}
|
||||
parent2.Packages = []*ManifestData{child2}
|
||||
|
||||
loader := ManifestLoader{FS: fs.MakeRealFS(), InitialPath: "testdata/hierarchy"}
|
||||
expected := grandparent
|
||||
actual, err := loader.LoadManifestDataFromPath()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("expect:\n%#v\nbut got:\n%#v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tree
|
||||
|
||||
import (
|
||||
"k8s.io/kubectl/pkg/kinflate/transformers"
|
||||
"k8s.io/kubectl/pkg/kinflate/types"
|
||||
)
|
||||
|
||||
// DefaultTransformer generates the following transformers:
|
||||
// 1) apply overlay
|
||||
// 2) name prefix
|
||||
// 3) apply labels
|
||||
// 4) apply annotations
|
||||
// 5) update name reference
|
||||
func DefaultTransformer(m *ManifestData) (transformers.Transformer, error) {
|
||||
ts := []transformers.Transformer{}
|
||||
|
||||
ot, err := transformers.NewOverlayTransformer(types.KObject(m.Patches))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ts = append(ts, ot)
|
||||
|
||||
npt, err := transformers.NewDefaultingNamePrefixTransformer(string(m.NamePrefix))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ts = append(ts, npt)
|
||||
|
||||
lt, err := transformers.NewDefaultingLabelsMapTransformer(m.ObjectLabels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ts = append(ts, lt)
|
||||
|
||||
at, err := transformers.NewDefaultingAnnotationsMapTransformer(m.ObjectAnnotations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ts = append(ts, at)
|
||||
|
||||
nrt, err := transformers.NewDefaultingNameReferenceTransformer()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ts = append(ts, nrt)
|
||||
return transformers.NewMultiTransformer(ts), nil
|
||||
}
|
||||
|
|
@ -1,130 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tree
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
|
||||
manifest "k8s.io/kubectl/pkg/apis/manifest/v1alpha1"
|
||||
"k8s.io/kubectl/pkg/kinflate/constants"
|
||||
"k8s.io/kubectl/pkg/kinflate/util/fs"
|
||||
)
|
||||
|
||||
type ManifestLoader struct {
|
||||
// Allows unit tests with fake filesystem.
|
||||
FS fs.FileSystem
|
||||
|
||||
// Initial path to manifest directory or manifest filename.
|
||||
InitialPath string
|
||||
|
||||
// Full expanded manifest file path.
|
||||
fullFilePath string
|
||||
}
|
||||
|
||||
// First pass to encapsulate fields for more informative error messages.
|
||||
type ManifestErrors struct {
|
||||
filepath string
|
||||
errorMsg string
|
||||
}
|
||||
|
||||
func (m *ManifestLoader) fs() fs.FileSystem {
|
||||
if m.FS == nil {
|
||||
m.FS = fs.MakeRealFS()
|
||||
}
|
||||
return m.FS
|
||||
}
|
||||
|
||||
// makeValidManifestPath returns a path to a KubeManifest file known to exist.
|
||||
// The argument is either the full path to the file itself, or a path to a directory
|
||||
// that immediately contains the file. Anything else is an error.
|
||||
func (m *ManifestLoader) MakeValidManifestPath(mPath string) (string, error) {
|
||||
f, err := m.fs().Stat(mPath)
|
||||
if err != nil {
|
||||
errorMsg := fmt.Sprintf("Manifest (%s) missing\nRun `kinflate init` first", mPath)
|
||||
return "", errors.New(errorMsg)
|
||||
}
|
||||
if f.IsDir() {
|
||||
mPath = path.Join(mPath, constants.KubeManifestFileName)
|
||||
_, err = m.fs().Stat(mPath)
|
||||
if err != nil {
|
||||
errorMsg := fmt.Sprintf("Manifest (%s) missing\nRun `kinflate init` first", mPath)
|
||||
return "", errors.New(errorMsg)
|
||||
}
|
||||
} else {
|
||||
if !strings.HasSuffix(mPath, constants.KubeManifestFileName) {
|
||||
return "", fmt.Errorf("Manifest file (%s) should have %s suffix\n", mPath, constants.KubeManifestSuffix)
|
||||
}
|
||||
}
|
||||
return mPath, nil
|
||||
}
|
||||
|
||||
// Read loads a manifest file and parse it in to the Manifest object.
|
||||
func (m *ManifestLoader) Read(filename string) (*manifest.Manifest, error) {
|
||||
bytes, err := m.fs().ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var manifest manifest.Manifest
|
||||
err = yaml.Unmarshal(bytes, &manifest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dir, _ := path.Split(filename)
|
||||
adjustPathsForManifest(&manifest, []string{dir})
|
||||
return &manifest, err
|
||||
}
|
||||
|
||||
// Write dumps the Manifest object into a file. If manifest is nil, an
|
||||
// error is returned.
|
||||
func (m *ManifestLoader) Write(filename string, manifest *manifest.Manifest) error {
|
||||
if manifest == nil {
|
||||
return errors.New("util: failed to write passed-in nil manifest")
|
||||
}
|
||||
bytes, err := yaml.Marshal(manifest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return m.fs().WriteFile(filename, bytes)
|
||||
}
|
||||
|
||||
// Read must have already been called and we have a loaded manifest
|
||||
func (m *ManifestLoader) Validate(manifest *manifest.Manifest) []ManifestErrors {
|
||||
//TODO: implement this function
|
||||
//// validate Packages
|
||||
//merrors := m.validatePackages(manifest.Packages)
|
||||
//// validate Resources
|
||||
//merrors = merrors + m.validateResources(manifest.Resources)
|
||||
//
|
||||
//// validate Patches
|
||||
//merrors = append(merrors, m.validatePatches(manifest.Patches))
|
||||
//
|
||||
//// validate Configmaps
|
||||
//merrors = append(merrors, m.validateConfigmaps(manifest.Configmaps))
|
||||
//
|
||||
//// validate GenericSecrets
|
||||
//merrors = append(merrors, m.validateGenericSecrets(manifest.GenericSecrets))
|
||||
//
|
||||
//// validate TLSSecrets
|
||||
//merrors = append(merrors, m.validateTLSSecrets(manifest.TLSSecrets))
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tree_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"strings"
|
||||
|
||||
manifest "k8s.io/kubectl/pkg/apis/manifest/v1alpha1"
|
||||
"k8s.io/kubectl/pkg/kinflate/tree"
|
||||
"k8s.io/kubectl/pkg/kinflate/util/fs"
|
||||
)
|
||||
|
||||
func TestManifestLoader(t *testing.T) {
|
||||
manifest := &manifest.Manifest{
|
||||
NamePrefix: "prefix",
|
||||
}
|
||||
loader := tree.ManifestLoader{FS: fs.MakeFakeFS()}
|
||||
|
||||
if err := loader.Write("Kube-manifest.yaml", manifest); err != nil {
|
||||
t.Fatalf("Couldn't write manifest file: %v\n", err)
|
||||
}
|
||||
|
||||
readManifest, err := loader.Read("Kube-manifest.yaml")
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't read manifest file: %v\n", err)
|
||||
}
|
||||
if !reflect.DeepEqual(manifest, readManifest) {
|
||||
t.Fatal("Read manifest is different from written manifest")
|
||||
}
|
||||
}
|
||||
|
||||
func TestManifestLoaderEmptyFile(t *testing.T) {
|
||||
manifest := &manifest.Manifest{
|
||||
NamePrefix: "prefix",
|
||||
}
|
||||
loader := tree.ManifestLoader{}
|
||||
if loader.Write("", manifest) == nil {
|
||||
t.Fatalf("Write to empty filename should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadNotExist(t *testing.T) {
|
||||
badSuffix := "foo.bar"
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
fakeFS.Mkdir(".", 0644)
|
||||
fakeFS.Create(badSuffix)
|
||||
loader := tree.ManifestLoader{FS: fakeFS}
|
||||
_, err := loader.MakeValidManifestPath("Kube-manifest.yaml")
|
||||
if err == nil {
|
||||
t.Fatalf("expect an error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "Run `kinflate init` first") {
|
||||
t.Fatalf("expect an error contains %q, but got %v", "does not exist", err)
|
||||
}
|
||||
_, err = loader.MakeValidManifestPath(".")
|
||||
if err == nil {
|
||||
t.Fatalf("expect an error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "Run `kinflate init` first") {
|
||||
t.Fatalf("expect an error contains %q, but got %v", "does not exist", err)
|
||||
}
|
||||
_, err = loader.MakeValidManifestPath(badSuffix)
|
||||
if err == nil {
|
||||
t.Fatalf("expect an error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "should have .yaml suffix") {
|
||||
t.Fatalf("expect an error contains %q, but got %v", "does not exist", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tree
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/kubectl/pkg/kinflate/transformers"
|
||||
"k8s.io/kubectl/pkg/kinflate/types"
|
||||
)
|
||||
|
||||
type NamePrefixType string
|
||||
|
||||
type ObjectLabelsType map[string]string
|
||||
|
||||
type ObjectAnnotationsType map[string]string
|
||||
|
||||
type ResourcesType types.KObject
|
||||
|
||||
type PatchesType types.KObject
|
||||
|
||||
type ConfigmapsType types.KObject
|
||||
|
||||
type SecretsType types.KObject
|
||||
|
||||
type PackagesType []*ManifestData
|
||||
|
||||
// ManifestData contains all the objects loaded from the filesystem according to
|
||||
// the Manifest Object.
|
||||
// Data in one node may refer to data in other nodes.
|
||||
// The node is invalid if it requires data it cannot find.
|
||||
// A node is either a base app, or a patch to the base, or a patch to a patch to the base, etc.
|
||||
type ManifestData struct {
|
||||
// Name of the manifest
|
||||
Name string
|
||||
|
||||
NamePrefix NamePrefixType
|
||||
ObjectLabels ObjectLabelsType
|
||||
ObjectAnnotations ObjectAnnotationsType
|
||||
Resources ResourcesType
|
||||
Patches PatchesType
|
||||
Configmaps ConfigmapsType
|
||||
Secrets SecretsType
|
||||
|
||||
Packages PackagesType
|
||||
}
|
||||
|
||||
func (md *ManifestData) allResources() error {
|
||||
err := types.Merge(md.Resources, md.Configmaps)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return types.Merge(md.Resources, md.Secrets)
|
||||
}
|
||||
|
||||
// ModeType is the option type for kinflate inflate
|
||||
type ModeType string
|
||||
|
||||
const (
|
||||
// ModeNormal means regular transformation.
|
||||
ModeNormal ModeType = "normal_mode"
|
||||
// ModeNoop means no transformation.
|
||||
ModeNoop ModeType = "noop_mode"
|
||||
)
|
||||
|
||||
func (md *ManifestData) preprocess(mode ModeType) error {
|
||||
switch mode {
|
||||
case ModeNormal:
|
||||
return md.allResources()
|
||||
case ModeNoop:
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("unknown mode for inflate")
|
||||
}
|
||||
}
|
||||
|
||||
func (md *ManifestData) makeTransformer(mode ModeType) (transformers.Transformer, error) {
|
||||
switch mode {
|
||||
case ModeNormal:
|
||||
return DefaultTransformer(md)
|
||||
case ModeNoop:
|
||||
return transformers.NewNoOpTransformer(), nil
|
||||
default:
|
||||
return transformers.NewNoOpTransformer(), fmt.Errorf("unknown mode for inflate")
|
||||
}
|
||||
}
|
||||
|
||||
// Inflate will recursively do the transformation on all the nodes below.
|
||||
func (md *ManifestData) Inflate(mode ModeType) error {
|
||||
for _, pkg := range md.Packages {
|
||||
err := pkg.Inflate(ModeNormal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, pkg := range md.Packages {
|
||||
err := types.Merge(md.Resources, pkg.Resources)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err := md.preprocess(mode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t, err := md.makeTransformer(mode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return t.Transform(types.KObject(md.Resources))
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
apiVersion: manifest.k8s.io/v1alpha1
|
||||
kind: Manifest
|
||||
metadata:
|
||||
name: grandparent
|
||||
packages:
|
||||
- parent1/
|
||||
- parent2/
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
apiVersion: manifest.k8s.io/v1alpha1
|
||||
kind: Manifest
|
||||
metadata:
|
||||
name: parent1
|
||||
packages:
|
||||
- child1/
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
apiVersion: manifest.k8s.io/v1alpha1
|
||||
kind: Manifest
|
||||
metadata:
|
||||
name: child1
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
apiVersion: manifest.k8s.io/v1alpha1
|
||||
kind: Manifest
|
||||
metadata:
|
||||
name: parent2
|
||||
packages:
|
||||
- child2/
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
apiVersion: manifest.k8s.io/v1alpha1
|
||||
kind: Manifest
|
||||
metadata:
|
||||
name: child2
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
apiVersion: manifest.k8s.io/v1alpha1
|
||||
kind: Manifest
|
||||
metadata:
|
||||
name: valid-app
|
||||
namePrefix: someprefix-
|
||||
objectLabels:
|
||||
foo: bar
|
||||
objectAnnotations:
|
||||
baseAnno: This is an annotation.
|
||||
resources:
|
||||
- deployment.yaml
|
||||
- cm/configmap.yaml
|
||||
patches:
|
||||
- patch.yaml
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
apiVersion: v1
|
||||
data:
|
||||
foo: bar
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm1
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: pod1
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:latest
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: pod1
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
Loading…
Reference in New Issue