diff --git a/docs/fields.md b/docs/fields.md index 39d4e5dd3..48f9832a1 100644 --- a/docs/fields.md +++ b/docs/fields.md @@ -36,6 +36,7 @@ What transformations (customizations) should be applied? | [nameSuffix](#namesuffix) | string | The value is appended to the names of all resources. | | [commonLabels](#commonlabels) | string | Adds annotions (non-identifying metadata) to add all resources. Like labels, these are key value pairs. | | [images](#images) | list | Images modify the name, tags and/or digest for images without creating patches. | +| [replicas](#replicas) | list | Replicas modify the number of replicas for a resource without creating patches. | |[patchesStrategicMerge](#patchesstrategicmerge)| list |Each entry in this list should resolve to a partial or complete resource definition file.| |[patchesJson6902](#patchesjson6902)| list |Each entry in this list should resolve to a kubernetes object and a JSON patch that will be applied to the object.| |[transformers](#transformers)|list|[plugin](plugins.md) configuration files| @@ -236,6 +237,24 @@ images: digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3 ``` +### replicas + +Replicas modify the number of replicas for a resource without creating patches. +E.g. Given this kubernetes Deployment fragment: +``` +metadata: + name: deployment-name +spec: + replicas: 3 +``` + +one can change the number of replicas to 5 with the following *kustomization*: +``` +replicas: +- name: deployment-name + count: 5 +``` +note that replicas is a list, so many replicas can be modified at the same time. ### kind diff --git a/pkg/target/kusttarget_configplugin.go b/pkg/target/kusttarget_configplugin.go index 71dcd0454..a6371089a 100644 --- a/pkg/target/kusttarget_configplugin.go +++ b/pkg/target/kusttarget_configplugin.go @@ -69,6 +69,7 @@ func (kt *KustTarget) configureBuiltinTransformers( kt.configureBuiltinLabelTransformer, kt.configureBuiltinAnnotationsTransformer, kt.configureBuiltinPatchJson6902Transformer, + kt.configureBuiltinReplicaCountTransformer, } var result []transformers.Transformer for _, f := range configurators { @@ -78,6 +79,7 @@ func (kt *KustTarget) configureBuiltinTransformers( } result = append(result, r...) } + return result, nil } @@ -233,6 +235,24 @@ func (kt *KustTarget) configureBuiltinImageTagTransformer( return } +func (kt *KustTarget) configureBuiltinReplicaCountTransformer( + tConfig *config.TransformerConfig) ( + result []transformers.Transformer, err error) { + var c struct { + Replica types.Replica + } + for _, args := range kt.kustomization.Replicas { + c.Replica = args + 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/types/kustomization.go b/pkg/types/kustomization.go index 86fd1f985..eb6fc2af2 100644 --- a/pkg/types/kustomization.go +++ b/pkg/types/kustomization.go @@ -79,6 +79,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 `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 @@ -355,3 +359,15 @@ type PatchTarget struct { // stategic merge patch with the format // https://github.com/kubernetes/community/blob/master/contributors/devel/strategic-merge-patch.md type PatchStrategicMerge string + +// 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/plugin/builtin/ReplicaCountTransformer.go b/plugin/builtin/ReplicaCountTransformer.go new file mode 100644 index 000000000..018079189 --- /dev/null +++ b/plugin/builtin/ReplicaCountTransformer.go @@ -0,0 +1,59 @@ +// Code generated by pluginator on ReplicaCountTransformer; DO NOT EDIT. +package builtin + +import ( + "fmt" + + "sigs.k8s.io/kustomize/pkg/ifc" + "sigs.k8s.io/kustomize/pkg/resid" + "sigs.k8s.io/kustomize/pkg/resmap" + "sigs.k8s.io/kustomize/pkg/types" + "sigs.k8s.io/yaml" +) + +const ( + fldReplica = "replicas" + fldSpec = "spec" +) + +// Find matching replicas declarations and replace the count. +// Eases the kustomization configuration of replica changes. +type ReplicaCountTransformerPlugin struct { + Replica types.Replica `json:"replica,omitempty" yaml:"replica,omitempty"` +} + +func NewReplicaCountTransformerPlugin() *ReplicaCountTransformerPlugin { + return &ReplicaCountTransformerPlugin{} +} + +func (p *ReplicaCountTransformerPlugin) Config( + ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) { + + p.Replica = types.Replica{} + 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].Map() + + specInterface, ok := kMap[fldSpec] + if !ok { + return fmt.Errorf("object %s missing field %s, cannot update %s", + p.Replica.Name, fldSpec, fldReplica) + } + + if spec, ok := specInterface.(map[string]interface{}); ok { + spec[fldReplica] = p.Replica.Count + kMap[fldSpec] = spec + } else { + return fmt.Errorf("object %s has a malformed %s", p.Replica.Name, fldSpec) + } + } + + return nil +} diff --git a/plugin/builtin/replicacounttransformer/ReplicaCountTransformer.go b/plugin/builtin/replicacounttransformer/ReplicaCountTransformer.go new file mode 100644 index 000000000..d50fc2af6 --- /dev/null +++ b/plugin/builtin/replicacounttransformer/ReplicaCountTransformer.go @@ -0,0 +1,60 @@ +// 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/resid" + "sigs.k8s.io/kustomize/pkg/resmap" + "sigs.k8s.io/kustomize/pkg/types" + "sigs.k8s.io/yaml" +) + +const ( + fldReplica = "replicas" + fldSpec = "spec" +) + +// Find matching replicas declarations and replace the count. +// Eases the kustomization configuration of replica changes. +type plugin struct { + Replica types.Replica `json:"replica,omitempty" yaml:"replica,omitempty"` +} + +var KustomizePlugin plugin + +func (p *plugin) Config( + ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) { + + p.Replica = types.Replica{} + 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].Map() + + specInterface, ok := kMap[fldSpec] + if !ok { + return fmt.Errorf("object %s missing field %s, cannot update %s", + p.Replica.Name, fldSpec, fldReplica) + } + + if spec, ok := specInterface.(map[string]interface{}); ok { + spec[fldReplica] = p.Replica.Count + kMap[fldSpec] = spec + } else { + return fmt.Errorf("object %s has a malformed %s", p.Replica.Name, fldSpec) + } + } + + 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 +`) +}