Move hashing transformer out of k8sdeps.

This commit is contained in:
Jeffrey Regan
2019-05-29 10:01:52 -07:00
parent 4812ddff9f
commit fd2248e7c2
14 changed files with 205 additions and 201 deletions

View File

@@ -18,13 +18,20 @@ import (
// KunstructuredFactoryImpl hides construction using apimachinery types.
type KunstructuredFactoryImpl struct {
hasher *kustHash
}
var _ ifc.KunstructuredFactory = &KunstructuredFactoryImpl{}
// NewKunstructuredFactoryImpl returns a factory.
func NewKunstructuredFactoryImpl() ifc.KunstructuredFactory {
return &KunstructuredFactoryImpl{}
return &KunstructuredFactoryImpl{hasher: NewKustHash()}
}
// Hasher returns a kunstructured hasher
// input: kunstructured; output: string hash.
func (kf *KunstructuredFactoryImpl) Hasher() ifc.KunstructuredHasher {
return kf.hasher
}
// SliceFromBytes returns a slice of Kunstructured.

View File

@@ -1,7 +1,7 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package hash
package kunstruct
import (
"encoding/json"
@@ -10,6 +10,7 @@ import (
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/kustomize/pkg/hasher"
"sigs.k8s.io/kustomize/pkg/ifc"
)
// kustHash computes a hash of an unstructured object.
@@ -21,9 +22,9 @@ func NewKustHash() *kustHash {
}
// Hash returns a hash of either a ConfigMap or a Secret
func (h *kustHash) Hash(m map[string]interface{}) (string, error) {
func (h *kustHash) Hash(m ifc.Kunstructured) (string, error) {
u := unstructured.Unstructured{
Object: m,
Object: m.Map(),
}
kind := u.GetKind()
switch kind {
@@ -42,7 +43,8 @@ func (h *kustHash) Hash(m map[string]interface{}) (string, error) {
return secretHash(sec)
default:
return "", fmt.Errorf(
"type %s is not supported for hashing in %v", kind, m)
"type %s is not supported for hashing in %v",
kind, m.Map())
}
}

View File

@@ -1,7 +1,7 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package hash
package kunstruct
import (
"reflect"

View File

@@ -5,7 +5,6 @@
package transformer
import (
"sigs.k8s.io/kustomize/k8sdeps/transformer/hash"
"sigs.k8s.io/kustomize/k8sdeps/transformer/inventory"
"sigs.k8s.io/kustomize/k8sdeps/transformer/patch"
"sigs.k8s.io/kustomize/pkg/ifc"
@@ -29,11 +28,6 @@ func (p *FactoryImpl) MakePatchTransformer(
return patch.NewTransformer(slice, rf)
}
// MakeHashTransformer makes a new name hash transformer
func (p *FactoryImpl) MakeHashTransformer() transformers.Transformer {
return hash.NewTransformer()
}
func (p *FactoryImpl) MakeInventoryTransformer(
arg *types.Inventory,
ldr ifc.Loader,

View File

@@ -1,34 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package hash
import (
"fmt"
"sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/transformers"
)
type transformer struct{}
var _ transformers.Transformer = &transformer{}
// NewTransformer make a hash transformer.
func NewTransformer() transformers.Transformer {
return &transformer{}
}
// Transform appends hash to generated resources.
func (tf *transformer) Transform(m resmap.ResMap) error {
for _, res := range m {
if res.NeedHashSuffix() {
h, err := NewKustHash().Hash(res.Map())
if err != nil {
return err
}
res.SetName(fmt.Sprintf("%s-%s", res.GetName(), h))
}
}
return nil
}

View File

@@ -1,149 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package hash
import (
"reflect"
"testing"
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/pkg/resid"
"sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/resource"
"sigs.k8s.io/kustomize/pkg/types"
)
func TestNameHashTransformer(t *testing.T) {
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(deploy, "deploy1"): rf.FromMap(
map[string]interface{}{
"group": "apps",
"apiVersion": "v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": "deploy1",
},
"spec": map[string]interface{}{
"template": map[string]interface{}{
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"old-label": "old-value",
},
},
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"name": "nginx",
"image": "nginx:1.7.9",
},
},
},
},
},
}),
resid.NewResId(service, "svc1"): rf.FromMap(
map[string]interface{}{
"apiVersion": "v1",
"kind": "Service",
"metadata": map[string]interface{}{
"name": "svc1",
},
"spec": map[string]interface{}{
"ports": []interface{}{
map[string]interface{}{
"name": "port1",
"port": "12345",
},
},
},
}),
resid.NewResId(secret, "secret1"): rf.FromMapAndOption(
map[string]interface{}{
"apiVersion": "v1",
"kind": "Secret",
"metadata": map[string]interface{}{
"name": "secret1",
},
}, &types.GeneratorArgs{Behavior: "create"}, &types.GeneratorOptions{DisableNameSuffixHash: false}),
}
expected := resmap.ResMap{
resid.NewResId(cmap, "cm1"): rf.FromMap(
map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{
"name": "cm1",
},
}),
resid.NewResId(deploy, "deploy1"): rf.FromMap(
map[string]interface{}{
"group": "apps",
"apiVersion": "v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": "deploy1",
},
"spec": map[string]interface{}{
"template": map[string]interface{}{
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"old-label": "old-value",
},
},
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"name": "nginx",
"image": "nginx:1.7.9",
},
},
},
},
},
}),
resid.NewResId(service, "svc1"): rf.FromMap(
map[string]interface{}{
"apiVersion": "v1",
"kind": "Service",
"metadata": map[string]interface{}{
"name": "svc1",
},
"spec": map[string]interface{}{
"ports": []interface{}{
map[string]interface{}{
"name": "port1",
"port": "12345",
},
},
},
}),
resid.NewResId(secret, "secret1"): rf.FromMapAndOption(
map[string]interface{}{
"apiVersion": "v1",
"kind": "Secret",
"metadata": map[string]interface{}{
"name": "secret1-7kc45hd5f7",
},
}, &types.GeneratorArgs{Behavior: "create"}, &types.GeneratorOptions{DisableNameSuffixHash: false}),
}
tran := NewTransformer()
tran.Transform(objs)
if !reflect.DeepEqual(objs, expected) {
err := expected.ErrorIfNotEqual(objs)
t.Fatalf("actual doesn't match expected: %v", err)
}
}

View File

@@ -58,6 +58,7 @@ type Kunstructured interface {
type KunstructuredFactory interface {
SliceFromBytes([]byte) ([]Kunstructured, error)
FromMap(m map[string]interface{}) Kunstructured
Hasher() KunstructuredHasher
MakeConfigMap(
ldr Loader,
options *types.GeneratorOptions,
@@ -68,5 +69,11 @@ type KunstructuredFactory interface {
args *types.SecretArgs) (Kunstructured, error)
}
// KunstructuredHasher returns a hash of the argument
// or an error.
type KunstructuredHasher interface {
Hash(Kunstructured) (string, error)
}
// See core.v1.SecretTypeOpaque
const SecretTypeOpaque = "Opaque"

View File

@@ -14,7 +14,6 @@ import (
// Factory makes transformers
type Factory interface {
MakePatchTransformer(slice []*resource.Resource, rf *resource.Factory) (transformers.Transformer, error)
MakeHashTransformer() transformers.Transformer
MakeInventoryTransformer(
p *types.Inventory,
ldr ifc.Loader,

View File

@@ -37,6 +37,10 @@ func NewFactory(kf ifc.KunstructuredFactory) *Factory {
return &Factory{kf: kf}
}
func (rf *Factory) Hasher() ifc.KunstructuredHasher {
return rf.kf.Hasher()
}
// FromMap returns a new instance of Resource.
func (rf *Factory) FromMap(m map[string]interface{}) *Resource {
return &Resource{

View File

@@ -21,6 +21,7 @@ import (
"sigs.k8s.io/kustomize/pkg/transformers"
"sigs.k8s.io/kustomize/pkg/transformers/config"
"sigs.k8s.io/kustomize/pkg/types"
"sigs.k8s.io/kustomize/plugin/builtin"
"sigs.k8s.io/yaml"
)
@@ -126,10 +127,18 @@ func (kt *KustTarget) makeCustomizedResMap(
if err != nil {
return nil, err
}
err = ra.Transform(kt.tFactory.MakeHashTransformer())
// This must be done last, and not as part of
// the recursion implicit in AccumulateTarget.
p := builtin.NewHashTransformerPlugin()
err = kt.configureBuiltinPlugin(p, nil, "hash")
if err != nil {
return nil, err
}
err = ra.Transform(p)
if err != nil {
return nil, err
}
// Given that names have changed (prefixs/suffixes added),
// fix all the back references to those names.
err = ra.FixBackReferences()

View File

@@ -234,10 +234,14 @@ func (kt *KustTarget) configureBuiltinImageTagTransformer(
}
func (kt *KustTarget) configureBuiltinPlugin(
p plugins.Configurable, c interface{}, id string) error {
y, err := yaml.Marshal(c)
if err != nil {
return errors.Wrapf(err, "builtin %s marshal", id)
p plugins.Configurable, c interface{}, id string) (err error) {
var y []byte
if c != nil {
y, err = yaml.Marshal(c)
if err != nil {
return errors.Wrapf(
err, "builtin %s marshal", id)
}
}
err = p.Config(kt.ldr, kt.rFactory, y)
if err != nil {

View File

@@ -0,0 +1,36 @@
// Code generated by pluginator on HashTransformer; DO NOT EDIT.
package builtin
import (
"fmt"
"sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/resmap"
)
type HashTransformerPlugin struct {
hasher ifc.KunstructuredHasher
}
func NewHashTransformerPlugin() *HashTransformerPlugin {
return &HashTransformerPlugin{}
}
func (p *HashTransformerPlugin) Config(
ldr ifc.Loader, rf *resmap.Factory, config []byte) (err error) {
p.hasher = rf.RF().Hasher()
return nil
}
// Transform appends hash to generated resources.
func (p *HashTransformerPlugin) Transform(m resmap.ResMap) error {
for _, res := range m {
if res.NeedHashSuffix() {
h, err := p.hasher.Hash(res)
if err != nil {
return err
}
res.SetName(fmt.Sprintf("%s-%s", res.GetName(), h))
}
}
return nil
}

View File

@@ -0,0 +1,38 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
//go:generate go run sigs.k8s.io/kustomize/plugin/pluginator
package main
import (
"fmt"
"sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/resmap"
)
type plugin struct {
hasher ifc.KunstructuredHasher
}
var KustomizePlugin plugin
func (p *plugin) Config(
ldr ifc.Loader, rf *resmap.Factory, config []byte) (err error) {
p.hasher = rf.RF().Hasher()
return nil
}
// Transform appends hash to generated resources.
func (p *plugin) Transform(m resmap.ResMap) error {
for _, res := range m {
if res.NeedHashSuffix() {
h, err := p.hasher.Hash(res)
if err != nil {
return err
}
res.SetName(fmt.Sprintf("%s-%s", res.GetName(), h))
}
}
return nil
}

View File

@@ -0,0 +1,87 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package main_test
import (
"testing"
"sigs.k8s.io/kustomize/pkg/kusttest"
"sigs.k8s.io/kustomize/plugin"
)
func TestHashTransformer(t *testing.T) {
tc := plugin.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
"builtin", "", "HashTransformer")
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
rm := th.LoadAndRunTransformer(`
apiVersion: builtin
kind: HashTransformer
metadata:
name: myMapGen
name: myMap
envs:
- devops.env
- uxteam.env
literals:
- FRUIT=apple
- VEGETABLE=carrot
`, `
apiVersion: v1
kind: ConfigMap
metadata:
name: cm1
---
apiVersion: v1
kind: Secret
metadata:
name: secret1
---
apiVersion: v1
group: apps
kind: Deployment
metadata:
name: deploy1
spec:
template:
metadata:
labels:
old-lab: old-val
spec:
containers:
- name: ngnix
image: nginx:1.7.9
`)
th.AssertActualEqualsExpected(rm, `
apiVersion: v1
kind: ConfigMap
metadata:
name: cm1
---
apiVersion: v1
kind: Secret
metadata:
name: secret1
---
apiVersion: v1
group: apps
kind: Deployment
metadata:
name: deploy1
spec:
template:
metadata:
labels:
old-lab: old-val
spec:
containers:
- image: nginx:1.7.9
name: ngnix
`)
}