config tree defaults to graph structure when ownerRefs available

This commit is contained in:
Katrina Verey
2019-12-23 16:36:25 -05:00
parent 3900166fdf
commit 24cf0c1fdc
5 changed files with 231 additions and 18 deletions

View File

@@ -20,8 +20,9 @@ container names, etc.
kustomize config tree supports printing arbitrary fields using the '--field' flag.
By default, kustomize config tree uses the directory structure for the tree structure, however when printing
from the cluster, the Resource graph structure may be used instead.
By default, kustomize config tree uses Resource graph structure if any relationships between resources (ownerReferences)
are detected, as is typically the case when printing from a cluster. Otherwise, directory graph structure is used. The
graph structure can also be selected explicitly using the '--graph-structure' flag.
### Examples
@@ -42,8 +43,7 @@ from the cluster, the Resource graph structure may be used instead.
--field="status.conditions[type=Completed].status"
# print live Resources from a cluster using owners for graph structure
kubectl get all -o yaml | kustomize config tree --replicas --name --image \
--graph-structure=owners
kubectl get all -o yaml | kustomize config tree --replicas --name --image
# print live Resources with status condition fields
kubectl get all -o yaml | kustomize config tree \

View File

@@ -45,7 +45,7 @@ func GetTreeRunner(name string) *TreeRunner {
"if true, include local-config in the output.")
c.Flags().BoolVar(&r.excludeNonLocal, "exclude-non-local", false,
"if true, exclude non-local-config in the output.")
c.Flags().StringVar(&r.structure, "graph-structure", "directory",
c.Flags().StringVar(&r.structure, "graph-structure", "",
"Graph structure to use for printing the tree. may be any of: "+
strings.Join(kio.GraphStructures, ","))

View File

@@ -460,8 +460,9 @@ container names, etc.
kustomize config tree supports printing arbitrary fields using the '--field' flag.
By default, kustomize config tree uses the directory structure for the tree structure, however when printing
from the cluster, the Resource graph structure may be used instead.
By default, kustomize config tree uses Resource graph structure if any relationships between resources (ownerReferences)
are detected, as is typically the case when printing from a cluster. Otherwise, directory graph structure is used. The
graph structure can also be selected explicitly using the '--graph-structure' flag.
`
var TreeExamples = `
# print Resources using directory structure
@@ -481,8 +482,7 @@ var TreeExamples = `
--field="status.conditions[type=Completed].status"
# print live Resources from a cluster using owners for graph structure
kubectl get all -o yaml | kustomize config tree --replicas --name --image \
--graph-structure=owners
kubectl get all -o yaml | kustomize config tree --replicas --name --image
# print live Resources with status condition fields
kubectl get all -o yaml | kustomize config tree \

View File

@@ -98,9 +98,15 @@ func (p TreeWriter) Write(nodes []*yaml.RNode) error {
return p.packageStructure(nodes)
case TreeStructureGraph:
return p.graphStructure(nodes)
default:
return p.packageStructure(nodes)
}
// If any resource has an owner reference, default to the graph structure. Otherwise, use package structure.
for _, node := range nodes {
if owners, _ := node.Pipe(yaml.Lookup("metadata", "ownerReferences")); owners != nil {
return p.graphStructure(nodes)
}
}
return p.packageStructure(nodes)
}
// node wraps a tree node, and any children nodes

View File

@@ -12,7 +12,7 @@ import (
"sigs.k8s.io/kustomize/kyaml/yaml"
)
func TestPrinter_Write(t *testing.T) {
func TestPrinter_Write_Package_Structure(t *testing.T) {
in := `kind: Deployment
metadata:
labels:
@@ -66,7 +66,7 @@ spec:
out := &bytes.Buffer{}
err := Pipeline{
Inputs: []Reader{&ByteReader{Reader: bytes.NewBufferString(in)}},
Outputs: []Writer{TreeWriter{Writer: out}},
Outputs: []Writer{TreeWriter{Writer: out, Structure: TreeStructurePackage}},
}.Execute()
if !assert.NoError(t, err) {
t.FailNow()
@@ -85,7 +85,7 @@ spec:
}
}
func TestPrinter_Write_base(t *testing.T) {
func TestPrinter_Write_Package_Structure_base(t *testing.T) {
in := `kind: Deployment
metadata:
labels:
@@ -139,7 +139,7 @@ spec:
out := &bytes.Buffer{}
err := Pipeline{
Inputs: []Reader{&ByteReader{Reader: bytes.NewBufferString(in)}},
Outputs: []Writer{TreeWriter{Writer: out}},
Outputs: []Writer{TreeWriter{Writer: out, Structure: TreeStructurePackage}},
}.Execute()
if !assert.NoError(t, err) {
t.FailNow()
@@ -157,7 +157,7 @@ spec:
}
}
func TestPrinter_Write_sort(t *testing.T) {
func TestPrinter_Write_Package_Structure_sort(t *testing.T) {
in := `apiVersion: extensions/v1
kind: Deployment
metadata:
@@ -255,7 +255,7 @@ spec:
out := &bytes.Buffer{}
err := Pipeline{
Inputs: []Reader{&ByteReader{Reader: bytes.NewBufferString(in)}},
Outputs: []Writer{TreeWriter{Writer: out}},
Outputs: []Writer{TreeWriter{Writer: out, Structure: TreeStructurePackage}},
}.Execute()
if !assert.NoError(t, err) {
t.FailNow()
@@ -287,7 +287,7 @@ func TestPrinter_metaError(t *testing.T) {
}
}
func TestPrinter_Write_owners(t *testing.T) {
func TestPrinter_Write_Graph_Structure(t *testing.T) {
in := `
apiVersion: v1
kind: Pod
@@ -384,3 +384,210 @@ metadata:
t.FailNow()
}
}
func TestPrinter_Write_Structure_Defaulting_when_ownerRefs_present(t *testing.T) {
in := `
apiVersion: v1
kind: Pod
metadata:
name: cockroachdb-0
namespace: myapp-staging
ownerReferences:
- apiVersion: apps/v1
kind: StatefulSet
name: cockroachdb
spec:
containers:
- name: cockroachdb
image: cockraochdb:1.1.1
---
apiVersion: v1
kind: Pod
metadata:
name: cockroachdb-1
namespace: myapp-staging
ownerReferences:
- apiVersion: apps/v1
kind: StatefulSet
name: cockroachdb
spec:
containers:
- name: cockroachdb
image: cockraochdb:1.1.1
---
apiVersion: v1
kind: Pod
metadata:
name: cockroachdb-2
namespace: myapp-staging
ownerReferences:
- apiVersion: apps/v1
kind: StatefulSet
name: cockroachdb
spec:
containers:
- name: cockroachdb
image: cockraochdb:1.1.0
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: cockroachdb
namespace: myapp-staging
ownerReferences:
- apiVersion: app.k8s.io/v1beta1
kind: Application
name: myapp
spec:
replicas: 3
containers:
- name: cockroachdb
image: cockraochdb:1.1.1
---
apiVersion: v1
kind: Service
metadata:
name: cockroachdb
namespace: myapp-staging
ownerReferences:
- apiVersion: app.k8s.io/v1beta1
kind: Application
name: myapp
---
apiVersion: app.k8s.io/v1beta1
kind: Application
metadata:
labels:
app.kubernetes.io/name: myapp
name: myapp
namespace: myapp-staging
`
out := &bytes.Buffer{}
err := Pipeline{
Inputs: []Reader{&ByteReader{Reader: bytes.NewBufferString(in)}},
Outputs: []Writer{TreeWriter{Writer: out}}, // Structure unspecified
}.Execute()
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.Equal(t, `.
└── [Resource] Application myapp-staging/myapp
├── [Resource] Service myapp-staging/cockroachdb
└── [Resource] StatefulSet myapp-staging/cockroachdb
├── [Resource] Pod myapp-staging/cockroachdb-0
├── [Resource] Pod myapp-staging/cockroachdb-1
└── [Resource] Pod myapp-staging/cockroachdb-2
`, out.String()) {
t.FailNow()
}
}
func TestPrinter_Write_Structure_Defaulting_when_ownerRefs_absent(t *testing.T) {
in := `
apiVersion: v1
kind: Pod
metadata:
name: cockroachdb-0
namespace: myapp-staging
spec:
containers:
- name: cockroachdb
image: cockraochdb:1.1.1
---
apiVersion: v1
kind: Pod
metadata:
name: cockroachdb-1
namespace: myapp-staging
spec:
containers:
- name: cockroachdb
image: cockraochdb:1.1.1
---
apiVersion: v1
kind: Pod
metadata:
name: cockroachdb-2
namespace: myapp-staging
spec:
containers:
- name: cockroachdb
image: cockraochdb:1.1.0
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: cockroachdb
namespace: myapp-staging
spec:
replicas: 3
containers:
- name: cockroachdb
image: cockraochdb:1.1.1
---
apiVersion: v1
kind: Service
metadata:
name: cockroachdb
namespace: myapp-staging
---
apiVersion: app.k8s.io/v1beta1
kind: Application
metadata:
labels:
app.kubernetes.io/name: myapp
name: myapp
namespace: myapp-staging
`
out := &bytes.Buffer{}
err := Pipeline{
Inputs: []Reader{&ByteReader{Reader: bytes.NewBufferString(in)}},
Outputs: []Writer{TreeWriter{Writer: out}}, // Structure unspecified
}.Execute()
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.Equal(t, `
└──
├── [.] Service myapp-staging/cockroachdb
├── [.] StatefulSet myapp-staging/cockroachdb
├── [.] Pod myapp-staging/cockroachdb-0
├── [.] Pod myapp-staging/cockroachdb-1
├── [.] Pod myapp-staging/cockroachdb-2
└── [.] Application myapp-staging/myapp
`, out.String()) {
t.FailNow()
}
}
func TestPrinter_Write_error_when_owner_missing(t *testing.T) {
in := `
---
apiVersion: v1
kind: Service
metadata:
name: cockroachdb
namespace: myapp-staging
ownerReferences:
- apiVersion: app.k8s.io/v1beta1
kind: Application
name: nginx
---
apiVersion: app.k8s.io/v1beta1
kind: Application
metadata:
labels:
app.kubernetes.io/name: myapp
name: myapp
namespace: myapp-staging
`
out := &bytes.Buffer{}
err := Pipeline{
Inputs: []Reader{&ByteReader{Reader: bytes.NewBufferString(in)}},
Outputs: []Writer{TreeWriter{Writer: out}},
}.Execute()
assert.Error(t, err)
assert.Equal(t, "owner 'Application myapp-staging/nginx' not found in input, but found as an owner of input objects", err.Error())
}