From 5000a2e5035ab39eece7d74001fbce68a3839087 Mon Sep 17 00:00:00 2001 From: Damien Robichaud Date: Wed, 29 May 2019 18:27:39 -0700 Subject: [PATCH] Implement replica transformer as patch alternative --- pkg/replica/replica.go | 13 +++++ pkg/target/kusttarget_configplugin.go | 22 +++++++ pkg/transformers/config/transformerconfig.go | 2 + pkg/types/kustomization.go | 5 ++ plugin/builtin/ReplicaCountTransformer.go | 57 ++++++++++++++++++ .../ReplicaCountTransformer.go | 58 +++++++++++++++++++ .../ReplicaCountTransformer_test.go | 49 ++++++++++++++++ 7 files changed, 206 insertions(+) create mode 100644 pkg/replica/replica.go create mode 100644 plugin/builtin/ReplicaCountTransformer.go create mode 100644 plugin/builtin/replicacounttransformer/ReplicaCountTransformer.go create mode 100644 plugin/builtin/replicacounttransformer/ReplicaCountTransformer_test.go diff --git a/pkg/replica/replica.go b/pkg/replica/replica.go new file mode 100644 index 000000000..90ce319e6 --- /dev/null +++ b/pkg/replica/replica.go @@ -0,0 +1,13 @@ +package replica + +// Replica specifies a modification to a replica config. +// The number of replicas of a resource whose name matches will be set to count. +// This struct is used by the ReplicaCountTransform, and is meant to supplement +// the existing patch functionality with a simpler syntax for replica configuration. +type Replica struct { + // The name of the resource to change the replica count + Name string `json:"name,omitempty" yaml:"name,omitempty"` + + // The number of replicas required. + Count uint `json:"count,omitempty" yaml:"count,omitempty"` +} diff --git a/pkg/target/kusttarget_configplugin.go b/pkg/target/kusttarget_configplugin.go index 71dcd0454..5afe53541 100644 --- a/pkg/target/kusttarget_configplugin.go +++ b/pkg/target/kusttarget_configplugin.go @@ -7,6 +7,7 @@ import ( "github.com/pkg/errors" "sigs.k8s.io/kustomize/pkg/image" "sigs.k8s.io/kustomize/pkg/plugins" + "sigs.k8s.io/kustomize/pkg/replica" "sigs.k8s.io/kustomize/pkg/transformers" "sigs.k8s.io/kustomize/pkg/transformers/config" "sigs.k8s.io/kustomize/pkg/types" @@ -69,6 +70,7 @@ func (kt *KustTarget) configureBuiltinTransformers( kt.configureBuiltinLabelTransformer, kt.configureBuiltinAnnotationsTransformer, kt.configureBuiltinPatchJson6902Transformer, + kt.configureBuiltinReplicaCountTransformer, } var result []transformers.Transformer for _, f := range configurators { @@ -233,6 +235,26 @@ func (kt *KustTarget) configureBuiltinImageTagTransformer( return } +func (kt *KustTarget) configureBuiltinReplicaCountTransformer( + tConfig *config.TransformerConfig) ( + result []transformers.Transformer, err error) { + var c struct { + Replica replica.Replica + FieldSpecs []config.FieldSpec + } + for _, args := range kt.kustomization.Replicas { + c.Replica = args + c.FieldSpecs = tConfig.Replicas + p := builtin.NewReplicaCountTransformerPlugin() + err = kt.configureBuiltinPlugin(p, c, "replica") + if err != nil { + return nil, err + } + result = append(result, p) + } + return +} + func (kt *KustTarget) configureBuiltinPlugin( p plugins.Configurable, c interface{}, id string) (err error) { var y []byte diff --git a/pkg/transformers/config/transformerconfig.go b/pkg/transformers/config/transformerconfig.go index a00c6da66..3e47d1401 100644 --- a/pkg/transformers/config/transformerconfig.go +++ b/pkg/transformers/config/transformerconfig.go @@ -35,6 +35,7 @@ type TransformerConfig struct { NameReference nbrSlice `json:"nameReference,omitempty" yaml:"nameReference,omitempty"` VarReference fsSlice `json:"varReference,omitempty" yaml:"varReference,omitempty"` Images fsSlice `json:"images,omitempty" yaml:"images,omitempty"` + Replicas fsSlice `json:"replicas,omitempty" yaml:"replicas,omitempty"` } // MakeEmptyConfig returns an empty TransformerConfig object @@ -61,6 +62,7 @@ func (t *TransformerConfig) sortFields() { sort.Sort(t.NameReference) sort.Sort(t.VarReference) sort.Sort(t.Images) + sort.Sort(t.Replicas) } // AddPrefixFieldSpec adds a FieldSpec to NamePrefix diff --git a/pkg/types/kustomization.go b/pkg/types/kustomization.go index 86fd1f985..acaa47c5f 100644 --- a/pkg/types/kustomization.go +++ b/pkg/types/kustomization.go @@ -22,6 +22,7 @@ import ( "sigs.k8s.io/kustomize/pkg/gvk" "sigs.k8s.io/kustomize/pkg/image" + "sigs.k8s.io/kustomize/pkg/replica" ) const ( @@ -79,6 +80,10 @@ type Kustomization struct { // patch, but this operator is simpler to specify. Images []image.Image `json:"images,omitempty" yaml:"images,omitempty"` + // Replicas is a list of {resourcename, count} that allows for simpler replica + // specification. This can also be done with a patch. + Replicas []replica.Replica `json:"replicas,omitempty" yaml:"replicas,omitempty"` + // Vars allow things modified by kustomize to be injected into a // container specification. A var is a name (e.g. FOO) associated // with a field in a specific resource instance. The field must diff --git a/plugin/builtin/ReplicaCountTransformer.go b/plugin/builtin/ReplicaCountTransformer.go new file mode 100644 index 000000000..41412deb0 --- /dev/null +++ b/plugin/builtin/ReplicaCountTransformer.go @@ -0,0 +1,57 @@ +// Code generated by pluginator on ReplicaCountTransformer; DO NOT EDIT. +package builtin + +import ( + "github.com/pkg/errors" + "sigs.k8s.io/kustomize/pkg/ifc" + "sigs.k8s.io/kustomize/pkg/replica" + "sigs.k8s.io/kustomize/pkg/resid" + "sigs.k8s.io/kustomize/pkg/resmap" + "sigs.k8s.io/kustomize/pkg/transformers/config" + "sigs.k8s.io/yaml" +) + +// Find matching replicas declarations and replace +// the count. +type ReplicaCountTransformerPlugin struct { + Replica replica.Replica `json:"replica,omitempty" yaml:"replica,omitempty"` + FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"` +} + +func NewReplicaCountTransformerPlugin() *ReplicaCountTransformerPlugin { + return &ReplicaCountTransformerPlugin{} +} + +func (p *ReplicaCountTransformerPlugin) Config( + ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) { + + p.Replica = replica.Replica{} + p.FieldSpecs = nil + return yaml.Unmarshal(c, p) +} + +func (p *ReplicaCountTransformerPlugin) Transform(m resmap.ResMap) error { + matcher := func(r resid.ResId) bool { + return r.ItemId.Name == p.Replica.Name + } + + for _, r := range m.GetMatchingIds(matcher) { + kMap := m[r].Kunstructured.Map() + + specInterface, ok := kMap["spec"] + if !ok { + return errors.New("'spec' not specified, replicas cannot be modified") + } + + if spec, ok := specInterface.(map[string]interface{}); ok { + spec["replicas"] = p.Replica.Count + kMap["spec"] = spec + } else { + return errors.New("'spec' not structured as expected") + } + + m[r].Kunstructured.SetMap(kMap) + } + + return nil +} diff --git a/plugin/builtin/replicacounttransformer/ReplicaCountTransformer.go b/plugin/builtin/replicacounttransformer/ReplicaCountTransformer.go new file mode 100644 index 000000000..d78e0237b --- /dev/null +++ b/plugin/builtin/replicacounttransformer/ReplicaCountTransformer.go @@ -0,0 +1,58 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +//go:generate go run sigs.k8s.io/kustomize/plugin/pluginator +package main + +import ( + "github.com/pkg/errors" + "sigs.k8s.io/kustomize/pkg/ifc" + "sigs.k8s.io/kustomize/pkg/replica" + "sigs.k8s.io/kustomize/pkg/resid" + "sigs.k8s.io/kustomize/pkg/resmap" + "sigs.k8s.io/kustomize/pkg/transformers/config" + "sigs.k8s.io/yaml" +) + +// Find matching replicas declarations and replace the count. +// Eases the kustomization configuration of replica changes. +type plugin struct { + Replica replica.Replica `json:"replica,omitempty" yaml:"replica,omitempty"` + FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"` +} + +var KustomizePlugin plugin + +func (p *plugin) Config( + ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) { + + p.Replica = replica.Replica{} + p.FieldSpecs = nil + return yaml.Unmarshal(c, p) +} + +func (p *plugin) Transform(m resmap.ResMap) error { + matcher := func(r resid.ResId) bool { + return r.ItemId.Name == p.Replica.Name + } + + for _, r := range m.GetMatchingIds(matcher) { + kMap := m[r].Kunstructured.Map() + + specInterface, ok := kMap["spec"] + if !ok { + return errors.New("'spec' not specified, replicas cannot be modified") + } + + if spec, ok := specInterface.(map[string]interface{}); ok { + spec["replicas"] = p.Replica.Count + kMap["spec"] = spec + } else { + return errors.New("'spec' not structured as expected") + } + + m[r].Kunstructured.SetMap(kMap) + } + + return nil +} diff --git a/plugin/builtin/replicacounttransformer/ReplicaCountTransformer_test.go b/plugin/builtin/replicacounttransformer/ReplicaCountTransformer_test.go new file mode 100644 index 000000000..3d22c30f5 --- /dev/null +++ b/plugin/builtin/replicacounttransformer/ReplicaCountTransformer_test.go @@ -0,0 +1,49 @@ +// 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 TestReplicaCountTransformer(t *testing.T) { + tc := plugin.NewEnvForTest(t).Set() + defer tc.Reset() + + tc.BuildGoPlugin( + "builtin", "", "ReplicaCountTransformer") + + th := kusttest_test.NewKustTestPluginHarness(t, "/app") + + rm := th.LoadAndRunTransformer(` +apiVersion: builtin +kind: ReplicaCountTransformer +metadata: + name: notImportantHere +replica: + name: deploy1 + count: 23 +`, ` +group: apps +apiVersion: v1 +kind: Deployment +metadata: + name: deploy1 +spec: + replicas: 1 +`) + + th.AssertActualEqualsExpected(rm, ` +apiVersion: v1 +group: apps +kind: Deployment +metadata: + name: deploy1 +spec: + replicas: 23 +`) +}