Simplify code base.

- In ResMap, drop concept of internal Id to Resource
   map.  The ResMap is now (just) a list, allowing only
   very particular edits.

 - Resources should now be maintained in the order
   loaded.  A later PR can adjust tests to remove the
   internal legacy sorting, and confirm order-out is
   predictable from order-in.  The PR would suppress
   the sort in tests, and reorder the output to make
   all tests pass again, and confirm that the new order
   matched depth-first input traversal.  The FromMap
   fixture function was removed from all test inputs to
   establish a predictable input order.

 - Resources now have two 'Ids', OriginalId and
   CurrentId.  The former is fixed as
   GVK-name-namespace at load time, the latter changes
   during transformations.  The latter can be used to
   narrow name references when the former maps to
   multiple resources.  We allow bases to be loaded
   more than once in a build (a diamond pattern), so
   the OriginalId is not unique across the resources
   set.  The CurrentId is (and must be) unique, but is
   constantly mutating.  Failing to make this
   distinction clear, and attempting to maintain a
   mapping from a single mutating Id to a resource was
   making the code too complex.

 - Drop prefix/suffix from ResId - the ResId is now
   immutable.  A later PR can remove the distinction
   with ItemId.

 - This PR increases coverage of ResMap is since this
   is a large refactor.  Higher level tests didn't need
   much change outside reordering of results at the
   resource level.
This commit is contained in:
Jeffrey Regan
2019-06-12 11:29:57 -07:00
parent 624aa5290e
commit 3a01a63a01
75 changed files with 2481 additions and 2962 deletions

View File

@@ -15,6 +15,7 @@ type AnnotationsTransformerPlugin struct {
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
//noinspection GoUnusedGlobalVariable
func NewAnnotationsTransformerPlugin() *AnnotationsTransformerPlugin {
return &AnnotationsTransformerPlugin{}
}

View File

@@ -15,6 +15,7 @@ type ConfigMapGeneratorPlugin struct {
types.ConfigMapArgs
}
//noinspection GoUnusedGlobalVariable
func NewConfigMapGeneratorPlugin() *ConfigMapGeneratorPlugin {
return &ConfigMapGeneratorPlugin{}
}

View File

@@ -12,6 +12,7 @@ type HashTransformerPlugin struct {
hasher ifc.KunstructuredHasher
}
//noinspection GoUnusedGlobalVariable
func NewHashTransformerPlugin() *HashTransformerPlugin {
return &HashTransformerPlugin{}
}

View File

@@ -17,6 +17,7 @@ type ImageTagTransformerPlugin struct {
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
//noinspection GoUnusedGlobalVariable
func NewImageTagTransformerPlugin() *ImageTagTransformerPlugin {
return &ImageTagTransformerPlugin{}
}

View File

@@ -3,7 +3,6 @@ package builtin
import (
"fmt"
"strings"
"sigs.k8s.io/kustomize/pkg/resource"
@@ -24,6 +23,7 @@ type InventoryTransformerPlugin struct {
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
}
//noinspection GoUnusedGlobalVariable
func NewInventoryTransformerPlugin() *InventoryTransformerPlugin {
return &InventoryTransformerPlugin{}
}
@@ -98,32 +98,33 @@ func makeInventory(m resmap.ResMap) (
inv = inventory.NewInventory()
var keys []string
for _, r := range m.Resources() {
ns := getNamespace(r)
item := resid.NewItemId(r.GetGvk(), ns, r.GetName())
ns := r.GetNamespace()
item := resid.NewResIdWithNamespace(r.GetGvk(), r.GetName(), ns)
if _, ok := inv.Current[item]; ok {
return nil, "", fmt.Errorf(
"item '%v' already in inventory", item)
}
inv.Current[item] = computeRefs(r, m)
inv.Current[item], err = computeRefs(r, m)
if err != nil {
return nil, "", err
}
keys = append(keys, item.String())
}
h, err := hasher.SortArrayAndComputeHash(keys)
return inv, h, err
}
func getNamespace(r *resource.Resource) string {
ns, err := r.GetFieldValue("metadata.namespace")
if err != nil && !strings.Contains(err.Error(), "no field named") {
panic(err)
}
return ns
}
func computeRefs(r *resource.Resource, m resmap.ResMap) (refs []resid.ItemId) {
func computeRefs(
r *resource.Resource, m resmap.ResMap) (refs []resid.ResId, err error) {
for _, refid := range r.GetRefBy() {
ref := m.GetById(refid)
ns := getNamespace(ref)
refs = append(refs, resid.NewItemId(ref.GetGvk(), ns, ref.GetName()))
ref, err := m.GetByCurrentId(refid)
if err != nil {
return nil, err
}
refs = append(
refs,
resid.NewResIdWithNamespace(
ref.GetGvk(), ref.GetName(), ref.GetNamespace()))
}
return
}

View File

@@ -15,6 +15,7 @@ type LabelTransformerPlugin struct {
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
//noinspection GoUnusedGlobalVariable
func NewLabelTransformerPlugin() *LabelTransformerPlugin {
return &LabelTransformerPlugin{}
}

View File

@@ -2,6 +2,7 @@
package builtin
import (
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/resource"
@@ -15,6 +16,7 @@ import (
// (like ValidatingWebhookConfiguration) last.
type LegacyOrderTransformerPlugin struct{}
//noinspection GoUnusedGlobalVariable
func NewLegacyOrderTransformerPlugin() *LegacyOrderTransformerPlugin {
return &LegacyOrderTransformerPlugin{}
}
@@ -25,16 +27,19 @@ func (p *LegacyOrderTransformerPlugin) Config(
return nil
}
func (p *LegacyOrderTransformerPlugin) Transform(m resmap.ResMap) error {
func (p *LegacyOrderTransformerPlugin) Transform(m resmap.ResMap) (err error) {
resources := make([]*resource.Resource, m.Size())
ids := m.AllIds()
sort.Sort(resmap.IdSlice(ids))
for i, id := range ids {
resources[i] = m.GetById(id)
resources[i], err = m.GetByCurrentId(id)
if err != nil {
return errors.Wrap(err, "expected match for sorting")
}
}
m.Clear()
for i, id := range ids {
m.AppendWithId(id, resources[i])
for _, r := range resources {
m.Append(r)
}
return nil
}

View File

@@ -15,6 +15,7 @@ type NamespaceTransformerPlugin struct {
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
//noinspection GoUnusedGlobalVariable
func NewNamespaceTransformerPlugin() *NamespaceTransformerPlugin {
return &NamespaceTransformerPlugin{}
}

View File

@@ -14,6 +14,7 @@ type PatchJson6902TransformerPlugin struct {
Patches []types.PatchJson6902 `json:"patches,omitempty" yaml:"patches,omitempty"`
}
//noinspection GoUnusedGlobalVariable
func NewPatchJson6902TransformerPlugin() *PatchJson6902TransformerPlugin {
return &PatchJson6902TransformerPlugin{}
}

View File

@@ -7,6 +7,7 @@ import (
"sigs.k8s.io/kustomize/pkg/gvk"
"sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/resid"
"sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/transformers"
"sigs.k8s.io/kustomize/pkg/transformers/config"
@@ -20,6 +21,7 @@ type PrefixSuffixTransformerPlugin struct {
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
//noinspection GoUnusedGlobalVariable
func NewPrefixSuffixTransformerPlugin() *PrefixSuffixTransformerPlugin {
return &PrefixSuffixTransformerPlugin{}
}
@@ -50,46 +52,54 @@ func (p *PrefixSuffixTransformerPlugin) Transform(m resmap.ResMap) error {
if len(p.Prefix) == 0 && len(p.Suffix) == 0 {
return nil
}
// Fill map "mf" with entries subject to name modification, and
// delete these entries from "m", so that for now m retains only
// the entries whose names will not be modified.
mf := resmap.New()
for id, r := range m.AsMap() {
found := false
for _, path := range prefixSuffixFieldSpecsToSkip {
if id.Gvk().IsSelected(&path.Gvk) {
found = true
break
}
for _, r := range m.Resources() {
if p.shouldSkip(r.OrgId()) {
continue
}
if !found {
mf.AppendWithId(id, r)
m.Remove(id)
fs, ok := p.shouldInclude(r.OrgId())
if !ok {
continue
}
}
for id, r := range mf.AsMap() {
objMap := r.Map()
for _, path := range p.FieldSpecs {
if !id.Gvk().IsSelected(&path.Gvk) {
continue
}
err := transformers.MutateField(
objMap,
path.PathSlice(),
path.CreateIfNotPresent,
p.addPrefixSuffix)
if err != nil {
return err
}
newId := id.CopyWithNewPrefixSuffix(p.Prefix, p.Suffix)
m.AppendWithId(newId, r)
if smellsLikeANameChange(fs) {
r.AddNamePrefix(p.Prefix)
r.AddNameSuffix(p.Suffix)
}
err := transformers.MutateField(
r.Map(),
fs.PathSlice(),
fs.CreateIfNotPresent,
p.addPrefixSuffix)
if err != nil {
return err
}
}
return nil
}
func smellsLikeANameChange(fs *config.FieldSpec) bool {
return fs.Path == "metadata/name"
}
func (p *PrefixSuffixTransformerPlugin) shouldInclude(
id resid.ResId) (*config.FieldSpec, bool) {
for _, path := range p.FieldSpecs {
if id.IsSelected(&path.Gvk) {
return &path, true
}
}
return nil, false
}
func (p *PrefixSuffixTransformerPlugin) shouldSkip(
id resid.ResId) bool {
for _, path := range prefixSuffixFieldSpecsToSkip {
if id.IsSelected(&path.Gvk) {
return true
}
}
return false
}
func (p *PrefixSuffixTransformerPlugin) addPrefixSuffix(
in interface{}) (interface{}, error) {
s, ok := in.(string)

View File

@@ -22,6 +22,7 @@ type ReplicaCountTransformerPlugin struct {
Replica types.Replica `json:"replica,omitempty" yaml:"replica,omitempty"`
}
//noinspection GoUnusedGlobalVariable
func NewReplicaCountTransformerPlugin() *ReplicaCountTransformerPlugin {
return &ReplicaCountTransformerPlugin{}
}
@@ -35,11 +36,11 @@ func (p *ReplicaCountTransformerPlugin) Config(
func (p *ReplicaCountTransformerPlugin) Transform(m resmap.ResMap) error {
matcher := func(r resid.ResId) bool {
return r.ItemId.Name == p.Replica.Name
return r.Name == p.Replica.Name
}
for _, id := range m.GetMatchingIds(matcher) {
kMap := m.GetById(id).Map()
for _, r := range m.GetMatchingResourcesByOriginalId(matcher) {
kMap := r.Map()
specInterface, ok := kMap[fldSpec]
if !ok {

View File

@@ -15,6 +15,7 @@ type SecretGeneratorPlugin struct {
types.SecretArgs
}
//noinspection GoUnusedGlobalVariable
func NewSecretGeneratorPlugin() *SecretGeneratorPlugin {
return &SecretGeneratorPlugin{}
}

View File

@@ -18,6 +18,7 @@ type plugin struct {
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
//noinspection GoUnusedGlobalVariable
var KustomizePlugin plugin
func (p *plugin) Config(

View File

@@ -18,6 +18,7 @@ type plugin struct {
types.ConfigMapArgs
}
//noinspection GoUnusedGlobalVariable
var KustomizePlugin plugin
func (p *plugin) Config(

View File

@@ -15,6 +15,7 @@ type plugin struct {
hasher ifc.KunstructuredHasher
}
//noinspection GoUnusedGlobalVariable
var KustomizePlugin plugin
func (p *plugin) Config(

View File

@@ -20,6 +20,7 @@ type plugin struct {
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
//noinspection GoUnusedGlobalVariable
var KustomizePlugin plugin
func (p *plugin) Config(

View File

@@ -6,7 +6,6 @@ package main
import (
"fmt"
"strings"
"sigs.k8s.io/kustomize/pkg/resource"
@@ -27,6 +26,7 @@ type plugin struct {
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
}
//noinspection GoUnusedGlobalVariable
var KustomizePlugin plugin
func (p *plugin) Config(
@@ -99,32 +99,33 @@ func makeInventory(m resmap.ResMap) (
inv = inventory.NewInventory()
var keys []string
for _, r := range m.Resources() {
ns := getNamespace(r)
item := resid.NewItemId(r.GetGvk(), ns, r.GetName())
ns := r.GetNamespace()
item := resid.NewResIdWithNamespace(r.GetGvk(), r.GetName(), ns)
if _, ok := inv.Current[item]; ok {
return nil, "", fmt.Errorf(
"item '%v' already in inventory", item)
}
inv.Current[item] = computeRefs(r, m)
inv.Current[item], err = computeRefs(r, m)
if err != nil {
return nil, "", err
}
keys = append(keys, item.String())
}
h, err := hasher.SortArrayAndComputeHash(keys)
return inv, h, err
}
func getNamespace(r *resource.Resource) string {
ns, err := r.GetFieldValue("metadata.namespace")
if err != nil && !strings.Contains(err.Error(), "no field named") {
panic(err)
}
return ns
}
func computeRefs(r *resource.Resource, m resmap.ResMap) (refs []resid.ItemId) {
func computeRefs(
r *resource.Resource, m resmap.ResMap) (refs []resid.ResId, err error) {
for _, refid := range r.GetRefBy() {
ref := m.GetById(refid)
ns := getNamespace(ref)
refs = append(refs, resid.NewItemId(ref.GetGvk(), ns, ref.GetName()))
ref, err := m.GetByCurrentId(refid)
if err != nil {
return nil, err
}
refs = append(
refs,
resid.NewResIdWithNamespace(
ref.GetGvk(), ref.GetName(), ref.GetNamespace()))
}
return
}

View File

@@ -18,6 +18,7 @@ type plugin struct {
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
//noinspection GoUnusedGlobalVariable
var KustomizePlugin plugin
func (p *plugin) Config(

View File

@@ -5,6 +5,7 @@
package main
import (
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/resource"
@@ -18,6 +19,7 @@ import (
// (like ValidatingWebhookConfiguration) last.
type plugin struct{}
//noinspection GoUnusedGlobalVariable
var KustomizePlugin plugin
// Nothing needed for configuration.
@@ -26,16 +28,19 @@ func (p *plugin) Config(
return nil
}
func (p *plugin) Transform(m resmap.ResMap) error {
func (p *plugin) Transform(m resmap.ResMap) (err error) {
resources := make([]*resource.Resource, m.Size())
ids := m.AllIds()
sort.Sort(resmap.IdSlice(ids))
for i, id := range ids {
resources[i] = m.GetById(id)
resources[i], err = m.GetByCurrentId(id)
if err != nil {
return errors.Wrap(err, "expected match for sorting")
}
}
m.Clear()
for i, id := range ids {
m.AppendWithId(id, resources[i])
for _, r := range resources {
m.Append(r)
}
return nil
}

View File

@@ -18,6 +18,7 @@ type plugin struct {
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
//noinspection GoUnusedGlobalVariable
var KustomizePlugin plugin
func (p *plugin) Config(

View File

@@ -17,6 +17,7 @@ type plugin struct {
Patches []types.PatchJson6902 `json:"patches,omitempty" yaml:"patches,omitempty"`
}
//noinspection GoUnusedGlobalVariable
var KustomizePlugin plugin
func (p *plugin) Config(

View File

@@ -10,6 +10,7 @@ import (
"sigs.k8s.io/kustomize/pkg/gvk"
"sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/resid"
"sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/transformers"
"sigs.k8s.io/kustomize/pkg/transformers/config"
@@ -23,6 +24,7 @@ type plugin struct {
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
//noinspection GoUnusedGlobalVariable
var KustomizePlugin plugin
// Not placed in a file yet due to lack of demand.
@@ -51,46 +53,54 @@ func (p *plugin) Transform(m resmap.ResMap) error {
if len(p.Prefix) == 0 && len(p.Suffix) == 0 {
return nil
}
// Fill map "mf" with entries subject to name modification, and
// delete these entries from "m", so that for now m retains only
// the entries whose names will not be modified.
mf := resmap.New()
for id, r := range m.AsMap() {
found := false
for _, path := range prefixSuffixFieldSpecsToSkip {
if id.Gvk().IsSelected(&path.Gvk) {
found = true
break
}
for _, r := range m.Resources() {
if p.shouldSkip(r.OrgId()) {
continue
}
if !found {
mf.AppendWithId(id, r)
m.Remove(id)
fs, ok := p.shouldInclude(r.OrgId())
if !ok {
continue
}
}
for id, r := range mf.AsMap() {
objMap := r.Map()
for _, path := range p.FieldSpecs {
if !id.Gvk().IsSelected(&path.Gvk) {
continue
}
err := transformers.MutateField(
objMap,
path.PathSlice(),
path.CreateIfNotPresent,
p.addPrefixSuffix)
if err != nil {
return err
}
newId := id.CopyWithNewPrefixSuffix(p.Prefix, p.Suffix)
m.AppendWithId(newId, r)
if smellsLikeANameChange(fs) {
r.AddNamePrefix(p.Prefix)
r.AddNameSuffix(p.Suffix)
}
err := transformers.MutateField(
r.Map(),
fs.PathSlice(),
fs.CreateIfNotPresent,
p.addPrefixSuffix)
if err != nil {
return err
}
}
return nil
}
func smellsLikeANameChange(fs *config.FieldSpec) bool {
return fs.Path == "metadata/name"
}
func (p *plugin) shouldInclude(
id resid.ResId) (*config.FieldSpec, bool) {
for _, path := range p.FieldSpecs {
if id.IsSelected(&path.Gvk) {
return &path, true
}
}
return nil, false
}
func (p *plugin) shouldSkip(
id resid.ResId) bool {
for _, path := range prefixSuffixFieldSpecsToSkip {
if id.IsSelected(&path.Gvk) {
return true
}
}
return false
}
func (p *plugin) addPrefixSuffix(
in interface{}) (interface{}, error) {
s, ok := in.(string)

View File

@@ -25,6 +25,7 @@ type plugin struct {
Replica types.Replica `json:"replica,omitempty" yaml:"replica,omitempty"`
}
//noinspection GoUnusedGlobalVariable
var KustomizePlugin plugin
func (p *plugin) Config(
@@ -36,11 +37,11 @@ func (p *plugin) Config(
func (p *plugin) Transform(m resmap.ResMap) error {
matcher := func(r resid.ResId) bool {
return r.ItemId.Name == p.Replica.Name
return r.Name == p.Replica.Name
}
for _, id := range m.GetMatchingIds(matcher) {
kMap := m.GetById(id).Map()
for _, r := range m.GetMatchingResourcesByOriginalId(matcher) {
kMap := r.Map()
specInterface, ok := kMap[fldSpec]
if !ok {

View File

@@ -18,6 +18,7 @@ type plugin struct {
types.SecretArgs
}
//noinspection GoUnusedGlobalVariable
var KustomizePlugin plugin
func (p *plugin) Config(