Convert inventory transformer to plugin, reduce k8sdeps.

This commit is contained in:
Jeffrey Regan
2019-05-31 13:46:35 -07:00
committed by jregan
parent 115a0bc560
commit 81c98c855f
14 changed files with 491 additions and 328 deletions

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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)
}
}