mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-29 01:30:51 +00:00
Compare commits
6 Commits
cmd/resour
...
api/v0.3.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c9a3756b4 | ||
|
|
3f417c7b5b | ||
|
|
4526cb14e8 | ||
|
|
595e41a3ec | ||
|
|
118ba7eefe | ||
|
|
7b1a5f85ed |
@@ -4,7 +4,6 @@ go 1.13
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/spf13/cobra v0.0.5
|
github.com/spf13/cobra v0.0.5
|
||||||
k8s.io/api v0.17.0
|
|
||||||
k8s.io/apimachinery v0.17.0
|
k8s.io/apimachinery v0.17.0
|
||||||
k8s.io/cli-runtime v0.17.0
|
k8s.io/cli-runtime v0.17.0
|
||||||
k8s.io/client-go v0.17.0
|
k8s.io/client-go v0.17.0
|
||||||
|
|||||||
@@ -5,7 +5,10 @@
|
|||||||
package kubectlcobra
|
package kubectlcobra
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/cli-runtime/pkg/resource"
|
"k8s.io/cli-runtime/pkg/resource"
|
||||||
)
|
)
|
||||||
@@ -57,3 +60,86 @@ func sortGroupingObject(infos []*resource.Info) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adds the inventory of all objects (passed as infos) to the
|
||||||
|
// grouping object. Returns an error if a grouping object does not
|
||||||
|
// exist, or we are unable to successfully add the inventory to
|
||||||
|
// the grouping object; nil otherwise. Each object is in
|
||||||
|
// unstructured.Unstructured format.
|
||||||
|
func addInventoryToGroupingObj(infos []*resource.Info) error {
|
||||||
|
|
||||||
|
// Iterate through the objects (infos), creating an Inventory struct
|
||||||
|
// as metadata for the object, or if it's the grouping object, store it.
|
||||||
|
var groupingObj *unstructured.Unstructured
|
||||||
|
inventoryMap := map[string]string{}
|
||||||
|
for _, info := range infos {
|
||||||
|
obj := info.Object
|
||||||
|
if isGroupingObject(obj) {
|
||||||
|
// If we have more than one grouping object--error.
|
||||||
|
if groupingObj != nil {
|
||||||
|
return fmt.Errorf("Error--applying more than one grouping object.")
|
||||||
|
}
|
||||||
|
var ok bool
|
||||||
|
groupingObj, ok = obj.(*unstructured.Unstructured)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Grouping object is not an Unstructured: %#v", groupingObj)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if obj == nil {
|
||||||
|
return fmt.Errorf("Creating inventory; object is nil")
|
||||||
|
}
|
||||||
|
gk := obj.GetObjectKind().GroupVersionKind().GroupKind()
|
||||||
|
inventory, err := createInventory(info.Namespace, info.Name, gk)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
inventoryMap[inventory.String()] = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we've found the grouping object, store the object metadata inventory
|
||||||
|
// in the grouping config map.
|
||||||
|
if groupingObj == nil {
|
||||||
|
return fmt.Errorf("Grouping object not found")
|
||||||
|
}
|
||||||
|
err := unstructured.SetNestedStringMap(groupingObj.UnstructuredContent(), inventoryMap, "data")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// retrieveInventoryFromGroupingObj returns a slice of pointers to the
|
||||||
|
// inventory metadata. This function finds the grouping object, then
|
||||||
|
// parses the stored resource metadata into Inventory structs. Returns
|
||||||
|
// an error if there is a problem parsing the data into Inventory
|
||||||
|
// structs, or if the grouping object is not in Unstructured format; nil
|
||||||
|
// otherwise. If a grouping object does not exist, or it does not have a
|
||||||
|
// "data" map, then returns an empty slice and no error.
|
||||||
|
func retrieveInventoryFromGroupingObj(infos []*resource.Info) ([]*Inventory, error) {
|
||||||
|
inventory := []*Inventory{}
|
||||||
|
groupingInfo, exists := findGroupingObject(infos)
|
||||||
|
if exists {
|
||||||
|
groupingObj, ok := groupingInfo.Object.(*unstructured.Unstructured)
|
||||||
|
if !ok {
|
||||||
|
err := fmt.Errorf("Grouping object is not an Unstructured: %#v", groupingObj)
|
||||||
|
return inventory, err
|
||||||
|
}
|
||||||
|
invMap, exists, err := unstructured.NestedStringMap(groupingObj.Object, "data")
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error retrieving inventory from grouping object.")
|
||||||
|
return inventory, err
|
||||||
|
}
|
||||||
|
if exists {
|
||||||
|
for invStr := range invMap {
|
||||||
|
inv, err := parseInventory(invStr)
|
||||||
|
if err != nil {
|
||||||
|
return inventory, err
|
||||||
|
}
|
||||||
|
inventory = append(inventory, inv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return inventory, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ package kubectlcobra
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/cli-runtime/pkg/resource"
|
"k8s.io/cli-runtime/pkg/resource"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -19,12 +19,16 @@ var pod1Name = "pod-1"
|
|||||||
var pod2Name = "pod-2"
|
var pod2Name = "pod-2"
|
||||||
var pod3Name = "pod-3"
|
var pod3Name = "pod-3"
|
||||||
|
|
||||||
var groupingObj = corev1.ConfigMap{
|
var groupingObj = unstructured.Unstructured{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
Object: map[string]interface{}{
|
||||||
Namespace: testNamespace,
|
"apiVersion": "v1",
|
||||||
Name: groupingObjName,
|
"kind": "ConfigMap",
|
||||||
Labels: map[string]string{
|
"metadata": map[string]interface{}{
|
||||||
GroupingLabel: "true",
|
"name": groupingObjName,
|
||||||
|
"namespace": testNamespace,
|
||||||
|
"labels": map[string]interface{}{
|
||||||
|
GroupingLabel: "true",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -35,10 +39,14 @@ var groupingInfo = &resource.Info{
|
|||||||
Object: &groupingObj,
|
Object: &groupingObj,
|
||||||
}
|
}
|
||||||
|
|
||||||
var pod1 = corev1.Pod{
|
var pod1 = unstructured.Unstructured{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
Object: map[string]interface{}{
|
||||||
Namespace: testNamespace,
|
"apiVersion": "v1",
|
||||||
Name: pod1Name,
|
"kind": "Pod",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": pod1Name,
|
||||||
|
"namespace": testNamespace,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,10 +56,14 @@ var pod1Info = &resource.Info{
|
|||||||
Object: &pod1,
|
Object: &pod1,
|
||||||
}
|
}
|
||||||
|
|
||||||
var pod2 = corev1.Pod{
|
var pod2 = unstructured.Unstructured{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
Object: map[string]interface{}{
|
||||||
Namespace: testNamespace,
|
"apiVersion": "v1",
|
||||||
Name: pod2Name,
|
"kind": "Pod",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": pod2Name,
|
||||||
|
"namespace": testNamespace,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,10 +73,14 @@ var pod2Info = &resource.Info{
|
|||||||
Object: &pod2,
|
Object: &pod2,
|
||||||
}
|
}
|
||||||
|
|
||||||
var pod3 = corev1.Pod{
|
var pod3 = unstructured.Unstructured{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
Object: map[string]interface{}{
|
||||||
Namespace: testNamespace,
|
"apiVersion": "v1",
|
||||||
Name: pod3Name,
|
"kind": "Pod",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": pod3Name,
|
||||||
|
"namespace": testNamespace,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,3 +231,190 @@ func TestSortGroupingObject(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAddRetrieveInventoryToFromGroupingObject(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
infos []*resource.Info
|
||||||
|
expected []*Inventory
|
||||||
|
isError bool
|
||||||
|
}{
|
||||||
|
// No grouping object is an error.
|
||||||
|
{
|
||||||
|
infos: []*resource.Info{},
|
||||||
|
isError: true,
|
||||||
|
},
|
||||||
|
// No grouping object is an error.
|
||||||
|
{
|
||||||
|
infos: []*resource.Info{pod1Info, pod2Info},
|
||||||
|
isError: true,
|
||||||
|
},
|
||||||
|
// Grouping object without other objects is OK.
|
||||||
|
{
|
||||||
|
infos: []*resource.Info{groupingInfo},
|
||||||
|
expected: []*Inventory{},
|
||||||
|
isError: false,
|
||||||
|
},
|
||||||
|
// More than one grouping object is an error.
|
||||||
|
{
|
||||||
|
infos: []*resource.Info{groupingInfo, groupingInfo},
|
||||||
|
expected: []*Inventory{},
|
||||||
|
isError: true,
|
||||||
|
},
|
||||||
|
// More than one grouping object is an error.
|
||||||
|
{
|
||||||
|
infos: []*resource.Info{groupingInfo, pod1Info, groupingInfo},
|
||||||
|
expected: []*Inventory{},
|
||||||
|
isError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
infos: []*resource.Info{groupingInfo, pod1Info},
|
||||||
|
expected: []*Inventory{
|
||||||
|
&Inventory{
|
||||||
|
Namespace: testNamespace,
|
||||||
|
Name: pod1Name,
|
||||||
|
GroupKind: schema.GroupKind{
|
||||||
|
Group: "",
|
||||||
|
Kind: "Pod",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
isError: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
infos: []*resource.Info{pod1Info, groupingInfo},
|
||||||
|
expected: []*Inventory{
|
||||||
|
&Inventory{
|
||||||
|
Namespace: testNamespace,
|
||||||
|
Name: pod1Name,
|
||||||
|
GroupKind: schema.GroupKind{
|
||||||
|
Group: "",
|
||||||
|
Kind: "Pod",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
isError: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
infos: []*resource.Info{pod1Info, pod2Info, groupingInfo, pod3Info},
|
||||||
|
expected: []*Inventory{
|
||||||
|
&Inventory{
|
||||||
|
Namespace: testNamespace,
|
||||||
|
Name: pod1Name,
|
||||||
|
GroupKind: schema.GroupKind{
|
||||||
|
Group: "",
|
||||||
|
Kind: "Pod",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&Inventory{
|
||||||
|
Namespace: testNamespace,
|
||||||
|
Name: pod2Name,
|
||||||
|
GroupKind: schema.GroupKind{
|
||||||
|
Group: "",
|
||||||
|
Kind: "Pod",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&Inventory{
|
||||||
|
Namespace: testNamespace,
|
||||||
|
Name: pod3Name,
|
||||||
|
GroupKind: schema.GroupKind{
|
||||||
|
Group: "",
|
||||||
|
Kind: "Pod",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
isError: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
infos: []*resource.Info{pod1Info, pod2Info, pod3Info, groupingInfo},
|
||||||
|
expected: []*Inventory{
|
||||||
|
&Inventory{
|
||||||
|
Namespace: testNamespace,
|
||||||
|
Name: pod1Name,
|
||||||
|
GroupKind: schema.GroupKind{
|
||||||
|
Group: "",
|
||||||
|
Kind: "Pod",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&Inventory{
|
||||||
|
Namespace: testNamespace,
|
||||||
|
Name: pod2Name,
|
||||||
|
GroupKind: schema.GroupKind{
|
||||||
|
Group: "",
|
||||||
|
Kind: "Pod",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&Inventory{
|
||||||
|
Namespace: testNamespace,
|
||||||
|
Name: pod3Name,
|
||||||
|
GroupKind: schema.GroupKind{
|
||||||
|
Group: "",
|
||||||
|
Kind: "Pod",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
isError: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
infos: []*resource.Info{groupingInfo, pod1Info, pod2Info, pod3Info},
|
||||||
|
expected: []*Inventory{
|
||||||
|
&Inventory{
|
||||||
|
Namespace: testNamespace,
|
||||||
|
Name: pod1Name,
|
||||||
|
GroupKind: schema.GroupKind{
|
||||||
|
Group: "",
|
||||||
|
Kind: "Pod",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&Inventory{
|
||||||
|
Namespace: testNamespace,
|
||||||
|
Name: pod2Name,
|
||||||
|
GroupKind: schema.GroupKind{
|
||||||
|
Group: "",
|
||||||
|
Kind: "Pod",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&Inventory{
|
||||||
|
Namespace: testNamespace,
|
||||||
|
Name: pod3Name,
|
||||||
|
GroupKind: schema.GroupKind{
|
||||||
|
Group: "",
|
||||||
|
Kind: "Pod",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
isError: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
err := addInventoryToGroupingObj(test.infos)
|
||||||
|
if test.isError && err == nil {
|
||||||
|
t.Errorf("Should have produced an error, but returned none.")
|
||||||
|
}
|
||||||
|
if !test.isError {
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Received error when expecting none (%s)\n", err)
|
||||||
|
} else {
|
||||||
|
retrieved, err := retrieveInventoryFromGroupingObj(test.infos)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error retrieving inventory: %s\n", err)
|
||||||
|
}
|
||||||
|
if len(test.expected) != len(retrieved) {
|
||||||
|
t.Errorf("Expected inventory for %d resources, actual %d",
|
||||||
|
len(test.expected), len(retrieved))
|
||||||
|
}
|
||||||
|
for _, expected := range test.expected {
|
||||||
|
found := false
|
||||||
|
for _, actual := range retrieved {
|
||||||
|
if expected.Equals(actual) {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
t.Errorf("Expected inventory (%s) not found", expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -138,10 +138,10 @@ func (s *TablePrinter) Print() {
|
|||||||
|
|
||||||
func (s *TablePrinter) PrintUntil(stop <-chan struct{}, interval time.Duration) <-chan struct{} {
|
func (s *TablePrinter) PrintUntil(stop <-chan struct{}, interval time.Duration) <-chan struct{} {
|
||||||
completed := make(chan struct{})
|
completed := make(chan struct{})
|
||||||
|
setColor(s.out, WHITE)
|
||||||
|
s.printTable(s.statusInfo.CurrentStatus(), false)
|
||||||
go func() {
|
go func() {
|
||||||
defer close(completed)
|
defer close(completed)
|
||||||
setColor(s.out, WHITE)
|
|
||||||
s.printTable(s.statusInfo.CurrentStatus(), false)
|
|
||||||
ticker := time.NewTicker(interval)
|
ticker := time.NewTicker(interval)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ func TestWaitNoResources(t *testing.T) {
|
|||||||
|
|
||||||
aggStatuses := tableOutput.allAggStatuses()
|
aggStatuses := tableOutput.allAggStatuses()
|
||||||
expectedAggStatuses := []status.Status{
|
expectedAggStatuses := []status.Status{
|
||||||
status.CurrentStatus,
|
status.UnknownStatus,
|
||||||
status.CurrentStatus,
|
status.CurrentStatus,
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(aggStatuses, expectedAggStatuses) {
|
if !reflect.DeepEqual(aggStatuses, expectedAggStatuses) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# VERSIONS contains the release versions of each kustomize go module
|
# VERSIONS contains the release versions of each kustomize go module
|
||||||
# update this file and run releaseall.sh to cut a new release
|
# update this file and run releasemodule.sh to cut a new release
|
||||||
|
|
||||||
# kyaml version
|
# kyaml version
|
||||||
export kyaml_major=0
|
export kyaml_major=0
|
||||||
@@ -16,7 +16,7 @@ export kstatus_patch=1
|
|||||||
# kustomize api version
|
# kustomize api version
|
||||||
export api_major=0
|
export api_major=0
|
||||||
export api_minor=3
|
export api_minor=3
|
||||||
export api_patch=1
|
export api_patch=2
|
||||||
|
|
||||||
# cmd/config version
|
# cmd/config version
|
||||||
export cmd_config_major=0
|
export cmd_config_major=0
|
||||||
|
|||||||
Reference in New Issue
Block a user