mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-11 17:12:51 +00:00
Convert inventory transformer to plugin, reduce k8sdeps.
This commit is contained in:
@@ -5,12 +5,9 @@
|
||||
package transformer
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/k8sdeps/transformer/inventory"
|
||||
"sigs.k8s.io/kustomize/k8sdeps/transformer/patch"
|
||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||
"sigs.k8s.io/kustomize/pkg/resource"
|
||||
"sigs.k8s.io/kustomize/pkg/transformers"
|
||||
"sigs.k8s.io/kustomize/pkg/types"
|
||||
)
|
||||
|
||||
// FactoryImpl makes patch transformer and name hash transformer
|
||||
@@ -27,11 +24,3 @@ func (p *FactoryImpl) MakePatchTransformer(
|
||||
rf *resource.Factory) (transformers.Transformer, error) {
|
||||
return patch.NewTransformer(slice, rf)
|
||||
}
|
||||
|
||||
func (p *FactoryImpl) MakeInventoryTransformer(
|
||||
arg *types.Inventory,
|
||||
ldr ifc.Loader,
|
||||
namespace string,
|
||||
gp types.GarbagePolicy) transformers.Transformer {
|
||||
return inventory.NewTransformer(arg, ldr, namespace, gp)
|
||||
}
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package inventory
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
|
||||
"sigs.k8s.io/kustomize/pkg/gvk"
|
||||
"sigs.k8s.io/kustomize/pkg/hasher"
|
||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||
"sigs.k8s.io/kustomize/pkg/inventory"
|
||||
"sigs.k8s.io/kustomize/pkg/resid"
|
||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||
"sigs.k8s.io/kustomize/pkg/resource"
|
||||
"sigs.k8s.io/kustomize/pkg/transformers"
|
||||
"sigs.k8s.io/kustomize/pkg/types"
|
||||
)
|
||||
|
||||
// transformer compute the inventory object used in prune
|
||||
type transformer struct {
|
||||
garbagePolicy types.GarbagePolicy
|
||||
ldr ifc.Loader
|
||||
cmName string
|
||||
cmNamespace string
|
||||
}
|
||||
|
||||
var _ transformers.Transformer = &transformer{}
|
||||
|
||||
// NewTransformer makes a new inventory transformer.
|
||||
func NewTransformer(
|
||||
p *types.Inventory,
|
||||
ldr ifc.Loader,
|
||||
namespace string,
|
||||
gp types.GarbagePolicy) transformers.Transformer {
|
||||
if p == nil || p.Type != "ConfigMap" || p.ConfigMap.Namespace != namespace {
|
||||
return transformers.NewNoOpTransformer()
|
||||
}
|
||||
return &transformer{
|
||||
garbagePolicy: gp,
|
||||
ldr: ldr,
|
||||
cmName: p.ConfigMap.Name,
|
||||
cmNamespace: p.ConfigMap.Namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Transform generates an inventory object based on the input ResMap.
|
||||
// this transformer doesn't change existing resources -
|
||||
// it just visits resources and accumulates information to make a new ConfigMap.
|
||||
// The prune ConfigMap is used to support the pruning command in the client side tool,
|
||||
// which is proposed in https://github.com/kubernetes/enhancements/pull/810
|
||||
// The inventory data is written to annotation since
|
||||
// 1. The key in data field is constrained and couldn't include arbitrary letters
|
||||
// 2. The annotation can be put into any kind of objects
|
||||
func (tf *transformer) Transform(m resmap.ResMap) error {
|
||||
invty := inventory.NewInventory()
|
||||
var keys []string
|
||||
for _, r := range m {
|
||||
ns, _ := r.GetFieldValue("metadata.namespace")
|
||||
item := resid.NewItemId(r.GetGvk(), ns, r.GetName())
|
||||
var refs []resid.ItemId
|
||||
|
||||
for _, refid := range r.GetRefBy() {
|
||||
ref := m[refid]
|
||||
ns, _ := ref.GetFieldValue("metadata.namespace")
|
||||
refs = append(refs, resid.NewItemId(ref.GetGvk(), ns, ref.GetName()))
|
||||
}
|
||||
invty.Current[item] = refs
|
||||
keys = append(keys, item.String())
|
||||
}
|
||||
h, err := hasher.SortArrayAndComputeHash(keys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
args := &types.ConfigMapArgs{}
|
||||
args.Name = tf.cmName
|
||||
args.Namespace = tf.cmNamespace
|
||||
opts := &types.GeneratorOptions{
|
||||
Annotations: make(map[string]string),
|
||||
}
|
||||
opts.Annotations[inventory.HashAnnotation] = h
|
||||
err = invty.UpdateAnnotations(opts.Annotations)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
kf := kunstruct.NewKunstructuredFactoryImpl()
|
||||
k, err := kf.MakeConfigMap(tf.ldr, opts, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tf.garbagePolicy == types.GarbageCollect {
|
||||
for k := range m {
|
||||
delete(m, k)
|
||||
}
|
||||
}
|
||||
|
||||
id := resid.NewResIdWithPrefixNamespace(
|
||||
gvk.Gvk{
|
||||
Version: "v1",
|
||||
Kind: "ConfigMap",
|
||||
},
|
||||
tf.cmName,
|
||||
"", tf.cmNamespace)
|
||||
if _, ok := m[id]; ok {
|
||||
return fmt.Errorf("id %v is already used, please use a different name in the prune field", id)
|
||||
}
|
||||
m[id] = resource.NewFactory(kf).FromKunstructured(k)
|
||||
return nil
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package inventory
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/gvk"
|
||||
"sigs.k8s.io/kustomize/pkg/loader"
|
||||
"sigs.k8s.io/kustomize/pkg/resid"
|
||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||
"sigs.k8s.io/kustomize/pkg/resource"
|
||||
"sigs.k8s.io/kustomize/pkg/types"
|
||||
"sigs.k8s.io/kustomize/pkg/validators"
|
||||
)
|
||||
|
||||
var secret = gvk.Gvk{Version: "v1", Kind: "Secret"}
|
||||
var cmap = gvk.Gvk{Version: "v1", Kind: "ConfigMap"}
|
||||
var deploy = gvk.Gvk{Group: "apps", Version: "v1", Kind: "Deployment"}
|
||||
|
||||
func makeResMap() resmap.ResMap {
|
||||
rf := resource.NewFactory(
|
||||
kunstruct.NewKunstructuredFactoryImpl())
|
||||
objs := resmap.ResMap{
|
||||
resid.NewResId(cmap, "cm1"): rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm1",
|
||||
},
|
||||
}),
|
||||
resid.NewResId(secret, "secret1"): rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Secret",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "secret1",
|
||||
},
|
||||
}),
|
||||
resid.NewResId(deploy, "deploy1"): rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "deploy1",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"template": map[string]interface{}{
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "nginx",
|
||||
"image": "nginx:1.7.9",
|
||||
"env": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "CM_FOO",
|
||||
"valueFrom": map[string]interface{}{
|
||||
"configMapKeyRef": map[string]interface{}{
|
||||
"name": "cm1",
|
||||
"key": "somekey",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"envFrom": []interface{}{
|
||||
map[string]interface{}{
|
||||
"configMapRef": map[string]interface{}{
|
||||
"name": "cm1",
|
||||
"key": "somekey",
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"secretRef": map[string]interface{}{
|
||||
"name": "secret1",
|
||||
"key": "somekey",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
objs[resid.NewResId(cmap, "cm1")].AppendRefBy(resid.NewResId(deploy, "deploy1"))
|
||||
objs[resid.NewResId(secret, "secret1")].AppendRefBy(resid.NewResId(deploy, "deploy1"))
|
||||
return objs
|
||||
}
|
||||
|
||||
func TestInventoryTransformer(t *testing.T) {
|
||||
rf := resource.NewFactory(
|
||||
kunstruct.NewKunstructuredFactoryImpl())
|
||||
ldr := loader.NewFileLoaderAtCwd(validators.MakeFakeValidator(), fs.MakeFakeFS())
|
||||
|
||||
// hash is derived based on all keys in the Inventory
|
||||
// It is added to annotations as
|
||||
// kustomize.config.k8s.io/InventoryHash: hash
|
||||
// When seeing the same annotation, prune binary assumes no
|
||||
// clean up is needed
|
||||
hash := "h44788gt7g"
|
||||
|
||||
// inventory is the derived json string for an Inventory object
|
||||
// It is added to annotations as
|
||||
// kustomize.config.k8s.io/Inventory: inventory
|
||||
inventory := "{\"current\":{\"apps_v1_Deployment|~X|deploy1\":null,\"~G_v1_ConfigMap|~X|cm1\":[{\"group\":\"apps\",\"version\":\"v1\",\"kind\":\"Deployment\",\"name\":\"deploy1\"}],\"~G_v1_Secret|~X|secret1\":[{\"group\":\"apps\",\"version\":\"v1\",\"kind\":\"Deployment\",\"name\":\"deploy1\"}]}}" // nolint
|
||||
|
||||
// This is the root or inventory object which tracks all
|
||||
// the applied resources - this is the thing we expect the transformer to create.
|
||||
pruneMap := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "pruneCM",
|
||||
"namespace": "default",
|
||||
"annotations": map[string]interface{}{
|
||||
"kustomize.config.k8s.io/Inventory": inventory,
|
||||
"kustomize.config.k8s.io/InventoryHash": hash,
|
||||
},
|
||||
},
|
||||
})
|
||||
expected := resmap.ResMap{
|
||||
resid.NewResIdWithPrefixNamespace(cmap, "pruneCM", "", "default"): pruneMap,
|
||||
}
|
||||
|
||||
p := &types.Inventory{
|
||||
Type: "ConfigMap",
|
||||
ConfigMap: types.NameArgs{
|
||||
Name: "pruneCM",
|
||||
Namespace: "default",
|
||||
},
|
||||
}
|
||||
objs := makeResMap()
|
||||
|
||||
// include the original resmap; only return the ConfigMap for pruning
|
||||
tran := NewTransformer(p, ldr, "default", types.GarbageCollect)
|
||||
tran.Transform(objs)
|
||||
|
||||
if !reflect.DeepEqual(objs, expected) {
|
||||
err := expected.ErrorIfNotEqual(objs)
|
||||
t.Fatalf("actual doesn't match expected: %v", err)
|
||||
}
|
||||
|
||||
objs = makeResMap()
|
||||
expected = objs.DeepCopy(rf)
|
||||
expected[resid.NewResIdWithPrefixNamespace(cmap, "pruneCM", "", "default")] = pruneMap
|
||||
// append the ConfigMap for pruning to the original resmap
|
||||
tran = NewTransformer(p, ldr, "default", types.GarbageIgnore)
|
||||
tran.Transform(objs)
|
||||
|
||||
if !reflect.DeepEqual(objs, expected) {
|
||||
err := expected.ErrorIfNotEqual(objs)
|
||||
t.Fatalf("actual doesn't match expected: %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user