Merge branch 'master' into add-skip-validation-flag-to-edit-add-resource

This commit is contained in:
Yigit Demirbas
2023-10-02 09:03:14 +02:00
committed by GitHub
77 changed files with 5110 additions and 293 deletions

View File

@@ -26,7 +26,7 @@ jobs:
compare-imports: true
print-compatible: true
- name: Report failure
uses: nashmaniac/create-issue-action@v1.1
uses: nashmaniac/create-issue-action@v1.2
# Only report failures of pushes (PRs have are visible through the Checks section) to the default branch
if: failure() && github.event_name == 'push' && github.ref == 'refs/heads/master'
with:

View File

@@ -59,6 +59,113 @@ Kustomize follows the [Kubernetes Community Membership] contributor ladder. Role
The kyaml module within the Kustomize repo has additional owners following the same ladder.
For the kustomize project, we have defined some specific guidelines on each step of the ladder:
To reach reviewer status, you must:
- Have been actively involved in kustomize for 3+ months
- Review at least 8 PRs that have been driven through to completion (see the reviewer guide below)
- Author at least 5 PRs that have been approved and merged
- Be a member of the kubernetes-sigs org. This should not be a blocker though, as once you meet the requirements for reviewer here,
the existing kustomize maintainers will be happy to sponsor your request to join the kubernetes-sigs org.
- Once you have met the above requirements, you may submit a PR adding yourself to the kustomize reviewers list, with links to your
contributions in the description.
To reach approver status, you must:
- Meet all the requirements of a reviewer
- Have been actively involved in kustomize for 6+ months
- Review at least 15 PRs that have been driven through to completion (see the reviewer guide below)
- Authored PRs meeting *either* of the following requirements:
- 15 PRs that have been approved and merged
- *OR* 10 PRs that have been approved and merged where some were more difficult, required greater thought/design,
or built up to larger features/long-term goals.
- File 3 issues. This can be any number of things, including but not limited to:
- Bugs with kustomize usage that you've found
- CI or release improvements
- Creating subtasks of a larger feature or project that you are in charge of.
- Long term improvements for the health of the project
- Triage at least 10 untriaged issues, including at least 1 feature request. The kustomize bug scrub is a great place to get practice with doing this, but you can
also follow the triage guide below to get started on your own.
- Demonstrate deeper understanding of kustomize goals. This can take many forms and is a bit subjective, but here are a few examples:
- saying no to an eschewed feature, instead recommending an alternative solution that is more aligned with the declarative configuration model
- active participation in discussion on a feature request issue
- filing an issue describing a long term problem and solution aligned with kustomize goals, for example: https://github.com/kubernetes-sigs/kustomize/issues/5140
- writing up KEPs for features that will improve the kustomize workflow while being aligned with kustomize goals, for example: https://github.com/kubernetes-sigs/kustomize/pull/4558
- Regularly interact with the existing kustomize maintainers, with clear communication about what you are working on or planning to work on. The kustomize
maintainers should know who you are and be familiar with your contributions.
- If you meet *most* of the above requirements while going above and beyond in a few areas, we will still consider your request to become an approver even
if you are missing one or two of the requirements. Please contact the maintainers directly to ask about getting approver status if you fall into this category.
- Otherwise, once you meet all the above requirements, you may:
- request to be added to the kustomize maintainer meeting that occurs each week with the kustomize PMs.
- submit a PR adding yourself to the kustomize approvers list, with links to your contributions in the description.
To reach owner status, you must:
- Meet all the requirements of an approver
- Have been actively involved with kustomize for 1+ year
- Assisted the current owner in driving the roadmap. This can be explicit or implicit help, such as:
- Editing the roadmap directly
- Reviewing the roadmap
- Providing suggestions for issues or prioritization in meetings that indirectly influence the roadmap
- Regularly triage issues and attend the kustomize bug scrub
- Regularly review PRs (1-2 a week)
- Periodically lead the kustomize bug scrub
- Periodically release kustomize (ensuring that there are no release blockers and that release notes are clean)
- Be the primary owner or point of contact for a particular project or area of code
- Ideally, there should be 2-3 owners at a time. Reach out to the current owners if you are interested in ownership. These
requirements are not strict and evaluation is somewhat subjective.
## Reviewer guide
Please watch this talk on how to review code from Tim Hockin: https://www.youtube.com/watch?v=OZVv7-o8i40
For reviewing PRs in kustomize, we have some specific guidelines:
- If the PR is introducing a new feature:
- *It must be implementing an issue that has already been triage/accepted or
a KEP that has been approved.* If it is not, then request the PR author to first file an issue.
- The PR must include thorough tests for the new feature, including unit and integration tests
- The code must be clean and readable, with thought given to how we will maintain the code in the future
- If the feature requires being broken up into multiple PRs to ease review, the feature should not be exposed to users
until the feature is completed in the last PR. For example, while we were building `kustomize localize`, we
built the feature almost entirely under the `api` module as a library with all the needed tests. There was no way
for users to invoke the localize code until the last PR that actually exposed the `kustomize localize` command in the
kustomize binary. This allowed us to continue development of `kustomize localize` without blocking kustomize releases.
If this type of development is not possible, then new features requiring multiple PRs should be
developed in their own feature branch.
- If the PR is introducing a bug fix:
- If the PR is not fixing an issue that has already been triage/accepted, follow the triage guide below on bug
fixes to decide if this is a PR we want to accept.
- The PR should have two distinct commits:
- The first commit should add a test demonstrating incorrect behavior
- The second commit should include the bug fix
- Some sample PRs:
- https://github.com/kubernetes-sigs/kustomize/pull/5263/commits
- https://github.com/kubernetes-sigs/kustomize/pull/3931/commits
- The regression test is absolutely required, and we cannot accept bug fixes without tests.
- If the PR is introducing a performance improvement:
- The PR description should give an indication of how much the performance is being improved and how we
can measure it - benchmark tests are fantastic.
- Other PRs (documentation, CI improvements, etc.) should be reviewed based on your best judgment.
## Triage guide
The possible triage labels are listed here: https://github.com/kubernetes-sigs/kustomize/labels?q=triage.
Triaging a feature request means:
- Understand what the user is asking for, and their use case.
- Verify that it is not an [eschewed feature](https://kubectl.docs.kubernetes.io/faq/kustomize/eschewedfeatures/#build-time-side-effects-from-cli-args-or-env-variables)
- Verify that it is not a duplicate issue.
- Look into workarounds. Is there another way that the user can achieve their use case with existing features?
- If you are new to this role, prior to leaving a comment on the issue, please bring it to weekly standup
for group discussion to make sure that we are all on the same page.
- Once you feel ready, you can label it with a triage label. Here's an [example](https://github.com/kubernetes-sigs/kustomize/issues/5049). You can also
look at other feature request issues to see how they were triaged and resolved. There are a few different triage labels that you can use, you can see the
full list [here](https://github.com/kubernetes-sigs/kustomize/labels?q=triage).
Triaging a bug means:
- First, verify that you can reproduce the issue. If you cannot reproduce the issue or need more information to give
it a go, triage it accordingly.
- Try to understand if this is really a bug or if this is intended behavior from kustomize. If it seems like intended
behavior, do your best to explain to the user why this is the case.
- If it seems to be a genuine bug, you can /triage accept the issue. In addition, investigate if there are workarounds or
alternative solutions for the user that they can try until the issue gets resolved.
Administrative notes:
- The [OWNERS file spec] is a useful resources in making changes.
@@ -66,23 +173,16 @@ Administrative notes:
## Project/Product Managers
Kustomize will have opportunities to join in a project/product manager role. You can
typically start working on this role as part of a kustomize training cohort, so please
keep an eye out for that or reach out to the leads if you are interested in this type of
work. Expectations for this role are:
Kustomize will have opportunities to join in a project/product manager role. You can reach out to
the existing kustomize maintainers if you are interested in this type of role. Project management work
can greatly help supplement your contributions as you climb from reviewer to approver
to owner.
Expectations for this role are:
- Triage 1 feature request each week, and bring it to weekly stand-up for discussion. Feature
requests are issues labeled kind/feature, and you can find them [here](https://github.com/kubernetes-sigs/kustomize/issues?q=is%3Aissue+is%3Aopen+kind+feature+label%3Akind%2Ffeature).
Triaging a feature request means:
- Understand what the user is asking for, and their use case.
- Verify that it is not an [eschewed feature](https://kubectl.docs.kubernetes.io/faq/kustomize/eschewedfeatures/#build-time-side-effects-from-cli-args-or-env-variables)
- Verify that it is not a duplicate issue.
- Look into workarounds. Is there another way that the user can achieve their use case with existing features?
- If you are new to this role, prior to leaving a comment on the issue, please bring it to weekly standup
for group discussion to make sure that we are all on the same page.
- Once you feel ready, you can label it with a triage label. Here's an [example](https://github.com/kubernetes-sigs/kustomize/issues/5049). You can also
look at other feature request issues to see how they were triaged and resolved. There are a few different triage labels that you can use, you can see the
full list [here](https://github.com/kubernetes-sigs/kustomize/labels?q=triage).
Please view the above triage guide for details on how to approach feature request triage.
- Monitor the kustomize Slack channel and try to help users if you can. It is a pretty
active channel, so responding to 4-5 users per week is sufficient even if some
questions go unanswered. If there is an interesting topic or a recurring problem that many

View File

@@ -8,6 +8,7 @@ aliases:
- knverey
- natasha41575
- annasong20
- koba1t
kustomize-reviewers:
- knverey
- natasha41575

View File

@@ -36,11 +36,16 @@ be updated on a regular basis going forward, and such updates
will be reflected in the Kubernetes release notes.
| Kubectl version | Kustomize version |
| --- | --- |
| < v1.14 | n/a |
| v1.14-v1.20 | v2.0.3 |
| v1.21 | v4.0.5 |
| v1.22 | v4.2.0 |
| --------------- | ----------------- |
| < v1.14 | n/a |
| v1.14-v1.20 | v2.0.3 |
| v1.21 | v4.0.5 |
| v1.22 | v4.2.0 |
| v1.23 | v4.4.1 |
| v1.24 | v4.5.4 |
| v1.25 | v4.5.7 |
| v1.26 | v4.5.7 |
| v1.27 | v5.0.1 |
[v2.0.3]: https://github.com/kubernetes-sigs/kustomize/releases/tag/v2.0.3
[#2506]: https://github.com/kubernetes-sigs/kustomize/issues/2506
@@ -63,7 +68,37 @@ This file should declare those resources, and any
customization to apply to them, e.g. _add a common
label_.
![base image][imageBase]
```
base: kustomization + resources
kustomization.yaml deployment.yaml service.yaml
+---------------------------------------------+ +-------------------------------------------------------+ +-----------------------------------+
| apiVersion: kustomize.config.k8s.io/v1beta1 | | apiVersion: apps/v1 | | apiVersion: v1 |
| kind: Kustomization | | kind: Deployment | | kind: Service |
|.commonLabels: | | metadata: | | metadata: |
| app: myapp | | name: myapp | | name: myapp |
| resources: | | spec: | | spec: |
| - deployment.yaml | | selector: | | selector: |
| - service.yaml | | matchLabels: | | app: myapp |
| configMapGenerator: | | app: myapp | | ports: |
| - name: myapp-map | | template: | | - port: 6060 |
| literals: | | metadata: | | targetPort: 6060 |
| - KEY=value | | labels: | +-----------------------------------+
+---------------------------------------------+ | app: myapp |
| spec: |
| containers: |
| - name: myapp |
| image: myapp |
| resources: |
| limits: |
| memory: "128Mi" |
| cpu: "500m" |
| ports: |
| - containerPort: 6060 |
+-------------------------------------------------------+
```
File structure:
@@ -99,20 +134,41 @@ Manage traditional [variants] of a configuration - like
_development_, _staging_ and _production_ - using
[overlays] that modify a common [base].
![overlay image][imageOverlay]
```
overlay: kustomization + patches
kustomization.yaml replica_count.yaml cpu_count.yaml
+-----------------------------------------------+ +-------------------------------+ +------------------------------------------+
| apiVersion: kustomize.config.k8s.io/v1beta1 | | apiVersion: apps/v1 | | apiVersion: apps/v1 |
| kind: Kustomization | | kind: Deployment | | kind: Deployment |
| commonLabels: | | metadata: | | metadata: |
| variant: prod | | name: myapp | | name: myapp |
| resources: | | spec: | | spec: |
| - ../../base | | replicas: 80 | | template: |
| patches: | +-------------------------------+ | spec: |
| - path: replica_count.yaml | | containers: |
| - path: cpu_count.yaml | | - name: myapp |
+-----------------------------------------------+ | resources: |
| limits: |
| memory: "128Mi" |
| cpu: "7000m" |
+------------------------------------------+
```
File structure:
> ```
> ~/someApp
> ├── base
>    ├── deployment.yaml
>    ├── kustomization.yaml
>    └── service.yaml
> ├── deployment.yaml
> ├── kustomization.yaml
> └── service.yaml
> └── overlays
> ├── development
>    ├── cpu_count.yaml
>    ├── kustomization.yaml
>    └── replica_count.yaml
> ├── cpu_count.yaml
> ├── kustomization.yaml
> └── replica_count.yaml
> └── production
> ├── cpu_count.yaml
> ├── kustomization.yaml
@@ -166,8 +222,6 @@ is governed by the [Kubernetes Code of Conduct].
[applied]: https://kubectl.docs.kubernetes.io/references/kustomize/glossary/#apply
[base]: https://kubectl.docs.kubernetes.io/references/kustomize/glossary/#base
[declarative configuration]: https://kubectl.docs.kubernetes.io/references/kustomize/glossary/#declarative-application-management
[imageBase]: images/base.jpg
[imageOverlay]: images/overlay.jpg
[kubectl announcement]: https://kubernetes.io/blog/2019/03/25/kubernetes-1-14-release-announcement
[kubernetes documentation]: https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/
[kubernetes style]: https://kubectl.docs.kubernetes.io/references/kustomize/glossary/#kubernetes-style-object

View File

@@ -9,8 +9,8 @@ import (
"github.com/stretchr/testify/require"
. "sigs.k8s.io/kustomize/api/internal/accumulator"
"sigs.k8s.io/kustomize/api/internal/loader"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
"sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/filesys"
"sigs.k8s.io/kustomize/kyaml/resid"

View File

@@ -10,7 +10,7 @@ import (
"github.com/stretchr/testify/assert"
. "sigs.k8s.io/kustomize/api/internal/generators"
"sigs.k8s.io/kustomize/api/kv"
"sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/pkg/loader"
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/filesys"

View File

@@ -10,7 +10,7 @@ import (
"github.com/stretchr/testify/assert"
. "sigs.k8s.io/kustomize/api/internal/generators"
"sigs.k8s.io/kustomize/api/kv"
"sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/pkg/loader"
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/filesys"

View File

@@ -25,7 +25,7 @@ func IsRemoteFile(path string) bool {
return err == nil && (u.Scheme == "http" || u.Scheme == "https")
}
// fileLoader is a kustomization's interface to files.
// FileLoader is a kustomization's interface to files.
//
// The directory in which a kustomization file sits
// is referred to below as the kustomization's _root_.
@@ -38,49 +38,48 @@ func IsRemoteFile(path string) bool {
//
// * supplemental data paths
//
// `Load` is used to visit these paths.
// `Load` is used to visit these paths.
//
// These paths refer to resources, patches,
// data for ConfigMaps and Secrets, etc.
// These paths refer to resources, patches,
// data for ConfigMaps and Secrets, etc.
//
// The loadRestrictor may disallow certain paths
// or classes of paths.
// The loadRestrictor may disallow certain paths
// or classes of paths.
//
// * bases (other kustomizations)
//
// `New` is used to load bases.
// `New` is used to load bases.
//
// A base can be either a remote git repo URL, or
// a directory specified relative to the current
// root. In the former case, the repo is locally
// cloned, and the new loader is rooted on a path
// in that clone.
// A base can be either a remote git repo URL, or
// a directory specified relative to the current
// root. In the former case, the repo is locally
// cloned, and the new loader is rooted on a path
// in that clone.
//
// As loaders create new loaders, a root history
// is established, and used to disallow:
// As loaders create new loaders, a root history
// is established, and used to disallow:
//
// - A base that is a repository that, in turn,
// specifies a base repository seen previously
// in the loading stack (a cycle).
// - A base that is a repository that, in turn,
// specifies a base repository seen previously
// in the loading stack (a cycle).
//
// - An overlay depending on a base positioned at
// or above it. I.e. '../foo' is OK, but '.',
// '..', '../..', etc. are disallowed. Allowing
// such a base has no advantages and encourages
// cycles, particularly if some future change
// were to introduce globbing to file
// specifications in the kustomization file.
// - An overlay depending on a base positioned at
// or above it. I.e. '../foo' is OK, but '.',
// '..', '../..', etc. are disallowed. Allowing
// such a base has no advantages and encourages
// cycles, particularly if some future change
// were to introduce globbing to file
// specifications in the kustomization file.
//
// These restrictions assure that kustomizations
// are self-contained and relocatable, and impose
// some safety when relying on remote kustomizations,
// e.g. a remotely loaded ConfigMap generator specified
// to read from /etc/passwd will fail.
//
type fileLoader struct {
type FileLoader struct {
// Loader that spawned this loader.
// Used to avoid cycles.
referrer *fileLoader
referrer *FileLoader
// An absolute, cleaned path to a directory.
// The Load function will read non-absolute
@@ -107,23 +106,9 @@ type fileLoader struct {
cleaner func() error
}
// NewFileLoaderAtCwd returns a loader that loads from PWD.
// A convenience for kustomize edit commands.
func NewFileLoaderAtCwd(fSys filesys.FileSystem) *fileLoader {
return newLoaderOrDie(
RestrictionRootOnly, fSys, filesys.SelfDir)
}
// NewFileLoaderAtRoot returns a loader that loads from "/".
// A convenience for tests.
func NewFileLoaderAtRoot(fSys filesys.FileSystem) *fileLoader {
return newLoaderOrDie(
RestrictionRootOnly, fSys, filesys.Separator)
}
// Repo returns the absolute path to the repo that contains Root if this fileLoader was created from a url
// or the empty string otherwise.
func (fl *fileLoader) Repo() string {
func (fl *FileLoader) Repo() string {
if fl.repoSpec != nil {
return fl.repoSpec.Dir.String()
}
@@ -132,13 +117,13 @@ func (fl *fileLoader) Repo() string {
// Root returns the absolute path that is prepended to any
// relative paths used in Load.
func (fl *fileLoader) Root() string {
func (fl *FileLoader) Root() string {
return fl.root.String()
}
func newLoaderOrDie(
func NewLoaderOrDie(
lr LoadRestrictorFunc,
fSys filesys.FileSystem, path string) *fileLoader {
fSys filesys.FileSystem, path string) *FileLoader {
root, err := filesys.ConfirmDir(fSys, path)
if err != nil {
log.Fatalf("unable to make loader at '%s'; %v", path, err)
@@ -147,12 +132,12 @@ func newLoaderOrDie(
lr, root, fSys, nil, git.ClonerUsingGitExec)
}
// newLoaderAtConfirmedDir returns a new fileLoader with given root.
// newLoaderAtConfirmedDir returns a new FileLoader with given root.
func newLoaderAtConfirmedDir(
lr LoadRestrictorFunc,
root filesys.ConfirmedDir, fSys filesys.FileSystem,
referrer *fileLoader, cloner git.Cloner) *fileLoader {
return &fileLoader{
referrer *FileLoader, cloner git.Cloner) *FileLoader {
return &FileLoader{
loadRestrictor: lr,
root: root,
referrer: referrer,
@@ -164,7 +149,7 @@ func newLoaderAtConfirmedDir(
// New returns a new Loader, rooted relative to current loader,
// or rooted in a temp directory holding a git repo clone.
func (fl *fileLoader) New(path string) (ifc.Loader, error) {
func (fl *FileLoader) New(path string) (ifc.Loader, error) {
if path == "" {
return nil, errors.Errorf("new root cannot be empty")
}
@@ -200,7 +185,7 @@ func (fl *fileLoader) New(path string) (ifc.Loader, error) {
// directory holding a cloned git repo.
func newLoaderAtGitClone(
repoSpec *git.RepoSpec, fSys filesys.FileSystem,
referrer *fileLoader, cloner git.Cloner) (ifc.Loader, error) {
referrer *FileLoader, cloner git.Cloner) (ifc.Loader, error) {
cleaner := repoSpec.Cleaner(fSys)
err := cloner(repoSpec)
if err != nil {
@@ -229,7 +214,7 @@ func newLoaderAtGitClone(
return nil, fmt.Errorf("%q refers to directory outside of repo %q", repoSpec.AbsPath(),
repoSpec.CloneDir())
}
return &fileLoader{
return &FileLoader{
// Clones never allowed to escape root.
loadRestrictor: RestrictionRootOnly,
root: root,
@@ -241,7 +226,7 @@ func newLoaderAtGitClone(
}, nil
}
func (fl *fileLoader) errIfGitContainmentViolation(
func (fl *FileLoader) errIfGitContainmentViolation(
base filesys.ConfirmedDir) error {
containingRepo := fl.containingRepo()
if containingRepo == nil {
@@ -259,7 +244,7 @@ func (fl *fileLoader) errIfGitContainmentViolation(
// Looks back through referrers for a git repo, returning nil
// if none found.
func (fl *fileLoader) containingRepo() *git.RepoSpec {
func (fl *FileLoader) containingRepo() *git.RepoSpec {
if fl.repoSpec != nil {
return fl.repoSpec
}
@@ -271,7 +256,7 @@ func (fl *fileLoader) containingRepo() *git.RepoSpec {
// errIfArgEqualOrHigher tests whether the argument,
// is equal to or above the root of any ancestor.
func (fl *fileLoader) errIfArgEqualOrHigher(
func (fl *FileLoader) errIfArgEqualOrHigher(
candidateRoot filesys.ConfirmedDir) error {
if fl.root.HasPrefix(candidateRoot) {
return fmt.Errorf(
@@ -288,7 +273,7 @@ func (fl *fileLoader) errIfArgEqualOrHigher(
// I.e. Allow a distinction between git URI with
// path foo and tag bar and a git URI with the same
// path but a different tag?
func (fl *fileLoader) errIfRepoCycle(newRepoSpec *git.RepoSpec) error {
func (fl *FileLoader) errIfRepoCycle(newRepoSpec *git.RepoSpec) error {
// TODO(monopole): Use parsed data instead of Raw().
if fl.repoSpec != nil &&
strings.HasPrefix(fl.repoSpec.Raw(), newRepoSpec.Raw()) {
@@ -305,7 +290,7 @@ func (fl *fileLoader) errIfRepoCycle(newRepoSpec *git.RepoSpec) error {
// Load returns the content of file at the given path,
// else an error. Relative paths are taken relative
// to the root.
func (fl *fileLoader) Load(path string) ([]byte, error) {
func (fl *FileLoader) Load(path string) ([]byte, error) {
if IsRemoteFile(path) {
return fl.httpClientGetContent(path)
}
@@ -319,7 +304,7 @@ func (fl *fileLoader) Load(path string) ([]byte, error) {
return fl.fSys.ReadFile(path)
}
func (fl *fileLoader) httpClientGetContent(path string) ([]byte, error) {
func (fl *FileLoader) httpClientGetContent(path string) ([]byte, error) {
var hc *http.Client
if fl.http != nil {
hc = fl.http
@@ -344,6 +329,6 @@ func (fl *fileLoader) httpClientGetContent(path string) ([]byte, error) {
}
// Cleanup runs the cleaner.
func (fl *fileLoader) Cleanup() error {
func (fl *FileLoader) Cleanup() error {
return fl.cleaner()
}

View File

@@ -93,8 +93,9 @@ func MakeFakeFs(td []testData) filesys.FileSystem {
return fSys
}
func makeLoader() *fileLoader {
return NewFileLoaderAtRoot(MakeFakeFs(testCases))
func makeLoader() *FileLoader {
return NewLoaderOrDie(
RestrictionRootOnly, MakeFakeFs(testCases), filesys.Separator)
}
func TestLoaderLoad(t *testing.T) {
@@ -226,7 +227,7 @@ func TestLoaderLocalScheme(t *testing.T) {
dir.Join(filepath.Join(parts...)),
[]byte(content),
))
actualContent, err := newLoaderOrDie(RestrictionRootOnly,
actualContent, err := NewLoaderOrDie(RestrictionRootOnly,
fSys,
dir.String(),
).Load(strings.Join(parts, "//"))
@@ -240,7 +241,7 @@ func TestLoaderLocalScheme(t *testing.T) {
"root",
}
require.NoError(t, fSys.MkdirAll(dir.Join(filepath.Join(parts...))))
ldr, err := newLoaderOrDie(RestrictionRootOnly,
ldr, err := NewLoaderOrDie(RestrictionRootOnly,
fSys,
dir.String(),
).New(strings.Join(parts, "//"))
@@ -322,7 +323,7 @@ func TestRestrictionRootOnlyInRealLoader(t *testing.T) {
var l ifc.Loader
l = newLoaderOrDie(RestrictionRootOnly, fSys, dir)
l = NewLoaderOrDie(RestrictionRootOnly, fSys, dir)
l = doSanityChecksAndDropIntoBase(t, l)
@@ -343,7 +344,7 @@ func TestRestrictionNoneInRealLoader(t *testing.T) {
var l ifc.Loader
l = newLoaderOrDie(RestrictionNone, fSys, dir)
l = NewLoaderOrDie(RestrictionNone, fSys, dir)
l = doSanityChecksAndDropIntoBase(t, l)
@@ -442,7 +443,7 @@ func TestLoaderDisallowsLocalBaseFromRemoteOverlay(t *testing.T) {
// Establish that a local overlay can navigate
// to the local bases.
l1 = newLoaderOrDie(
l1 = NewLoaderOrDie(
RestrictionRootOnly, fSys, cloneRoot+"/foo/overlay")
require.Equal(cloneRoot+"/foo/overlay", l1.Root())
@@ -600,7 +601,8 @@ func TestLoaderHTTP(t *testing.T) {
},
}
l1 := NewFileLoaderAtRoot(MakeFakeFs(testCasesFile))
l1 := NewLoaderOrDie(
RestrictionRootOnly, MakeFakeFs(testCasesFile), filesys.Separator)
require.Equal("/", l1.Root())
for _, x := range testCasesFile {

View File

@@ -11,8 +11,8 @@ import (
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/internal/generators"
"sigs.k8s.io/kustomize/api/internal/loader"
"sigs.k8s.io/kustomize/api/internal/target"
"sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/provider"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"

View File

@@ -8,7 +8,7 @@ import (
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/internal/git"
"sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/internal/loader"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/filesys"
)

View File

@@ -7,7 +7,7 @@ import (
"reflect"
"testing"
"sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/internal/loader"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/filesys"
"sigs.k8s.io/kustomize/kyaml/resid"

View File

@@ -10,10 +10,10 @@ import (
"testing"
"github.com/stretchr/testify/require"
fLdr "sigs.k8s.io/kustomize/api/internal/loader"
. "sigs.k8s.io/kustomize/api/internal/plugins/execplugin"
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
"sigs.k8s.io/kustomize/api/internal/plugins/utils"
fLdr "sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/provider"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"

View File

@@ -7,8 +7,8 @@ import (
"testing"
"github.com/stretchr/testify/require"
"sigs.k8s.io/kustomize/api/internal/loader"
. "sigs.k8s.io/kustomize/api/internal/plugins/loader"
"sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/provider"
"sigs.k8s.io/kustomize/api/resmap"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"

View File

@@ -13,12 +13,12 @@ import (
"sigs.k8s.io/kustomize/api/internal/accumulator"
"sigs.k8s.io/kustomize/api/internal/builtins"
"sigs.k8s.io/kustomize/api/internal/kusterr"
load "sigs.k8s.io/kustomize/api/internal/loader"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers"
"sigs.k8s.io/kustomize/api/internal/plugins/loader"
"sigs.k8s.io/kustomize/api/internal/utils"
"sigs.k8s.io/kustomize/api/konfig"
load "sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"

View File

@@ -13,7 +13,7 @@ import (
"github.com/stretchr/testify/require"
"sigs.k8s.io/kustomize/api/ifc"
. "sigs.k8s.io/kustomize/api/internal/target"
"sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/pkg/loader"
"sigs.k8s.io/kustomize/api/provider"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"

View File

@@ -6,9 +6,9 @@ package target_test
import (
"testing"
fLdr "sigs.k8s.io/kustomize/api/internal/loader"
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
"sigs.k8s.io/kustomize/api/internal/target"
fLdr "sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/provider"
"sigs.k8s.io/kustomize/api/resmap"
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"

View File

@@ -8,8 +8,8 @@ import (
"strings"
"testing"
"sigs.k8s.io/kustomize/api/internal/loader"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/loader"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)

View File

@@ -8,11 +8,11 @@ import (
"log"
"sigs.k8s.io/kustomize/api/internal/builtins"
fLdr "sigs.k8s.io/kustomize/api/internal/loader"
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
"sigs.k8s.io/kustomize/api/internal/target"
"sigs.k8s.io/kustomize/api/internal/utils"
"sigs.k8s.io/kustomize/api/konfig"
fLdr "sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/provenance"
"sigs.k8s.io/kustomize/api/provider"
"sigs.k8s.io/kustomize/api/resmap"

View File

@@ -16,8 +16,8 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"sigs.k8s.io/kustomize/api/internal/loader"
"sigs.k8s.io/kustomize/api/krusty"
"sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/resmap"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
"sigs.k8s.io/kustomize/kyaml/yaml"

View File

@@ -8,7 +8,7 @@ import (
"testing"
"github.com/stretchr/testify/require"
ldr "sigs.k8s.io/kustomize/api/loader"
ldr "sigs.k8s.io/kustomize/api/pkg/loader"
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/filesys"

24
api/pkg/loader/loader.go Normal file
View File

@@ -0,0 +1,24 @@
// Copyright 2023 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package pkg has all the helpers to interact with the api.
package loader
import (
"sigs.k8s.io/kustomize/api/internal/loader"
"sigs.k8s.io/kustomize/kyaml/filesys"
)
// NewFileLoaderAtCwd returns a loader that loads from PWD.
// A convenience for kustomize edit commands.
func NewFileLoaderAtCwd(fSys filesys.FileSystem) *loader.FileLoader {
return loader.NewLoaderOrDie(
loader.RestrictionRootOnly, fSys, filesys.SelfDir)
}
// NewFileLoaderAtRoot returns a loader that loads from "/".
// A convenience for tests.
func NewFileLoaderAtRoot(fSys filesys.FileSystem) *loader.FileLoader {
return loader.NewLoaderOrDie(
loader.RestrictionRootOnly, fSys, filesys.Separator)
}

View File

@@ -9,8 +9,9 @@ import (
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/api/ifc"
loader "sigs.k8s.io/kustomize/api/internal/loader"
"sigs.k8s.io/kustomize/api/kv"
"sigs.k8s.io/kustomize/api/loader"
ldrpkg "sigs.k8s.io/kustomize/api/pkg/loader"
. "sigs.k8s.io/kustomize/api/resmap"
resmaptest_test "sigs.k8s.io/kustomize/api/testutils/resmaptest"
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
@@ -249,7 +250,7 @@ func TestNewResMapFromSecretArgs(t *testing.T) {
actual, err := rmF.NewResMapFromSecretArgs(
kv.NewLoader(
loader.NewFileLoaderAtRoot(fSys),
ldrpkg.NewFileLoaderAtRoot(fSys),
valtest_test.MakeFakeValidator()), secrets)
if err != nil {
t.Fatalf("unexpected error: %v", err)

View File

@@ -9,7 +9,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/internal/loader"
. "sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/filesys"

View File

@@ -11,9 +11,9 @@ import (
"testing"
"sigs.k8s.io/kustomize/api/ifc"
fLdr "sigs.k8s.io/kustomize/api/internal/loader"
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
"sigs.k8s.io/kustomize/api/konfig"
fLdr "sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/provider"
"sigs.k8s.io/kustomize/api/resmap"
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"

View File

@@ -7,6 +7,7 @@ github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCv
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
@@ -31,20 +32,28 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.starlark.net v0.0.0-20190528202925-30ae18b8564f/go.mod h1:c1/X6cHgvdXj6pUlmWKMkuqRnW4K8x2vwt6JAaaircg=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

View File

@@ -11,7 +11,7 @@ import (
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/loader"
ldrhelper "sigs.k8s.io/kustomize/api/pkg/loader"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/kustfile"
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/util"

View File

@@ -8,7 +8,7 @@ import (
"log"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/pkg/loader"
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/kustfile"
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/util"
"sigs.k8s.io/kustomize/kyaml/filesys"

View File

@@ -34,10 +34,11 @@ func (k kindOfAdd) String() string {
}
type addMetadataOptions struct {
force bool
metadata map[string]string
mapValidator func(map[string]string) error
kind kindOfAdd
force bool
metadata map[string]string
mapValidator func(map[string]string) error
kind kindOfAdd
labelsWithoutSelector bool
}
// newCmdAddAnnotation adds one or more commonAnnotations to the kustomization file.
@@ -79,6 +80,9 @@ func newCmdAddLabel(fSys filesys.FileSystem, v func(map[string]string) error) *c
cmd.Flags().BoolVarP(&o.force, "force", "f", false,
"overwrite commonLabel if it already exists",
)
cmd.Flags().BoolVar(&o.labelsWithoutSelector, "without-selector", false,
"using add labels without selector option",
)
return cmd
}
@@ -127,6 +131,10 @@ func (o *addMetadataOptions) addAnnotations(m *types.Kustomization) error {
}
func (o *addMetadataOptions) addLabels(m *types.Kustomization) error {
if o.labelsWithoutSelector {
m.Labels = append(m.Labels, types.Label{Pairs: make(map[string]string), IncludeSelectors: false})
return o.writeToMap(m.Labels[len(m.Labels)-1].Pairs, label)
}
if m.CommonLabels == nil {
m.CommonLabels = make(map[string]string)
}

View File

@@ -274,3 +274,27 @@ func TestAddLabelForce(t *testing.T) {
assert.NoError(t, cmd.RunE(cmd, args))
v.VerifyCall()
}
func TestAddLabelWithoutSelector(t *testing.T) {
var o addMetadataOptions
o.labelsWithoutSelector = true
m := makeKustomization(t)
o.metadata = map[string]string{"new": "label"}
assert.NoError(t, o.addLabels(m))
assert.Equal(t, m.Labels[0], types.Label{Pairs: map[string]string{"new": "label"}})
}
func TestAddLabelWithoutSelectorAddLabel(t *testing.T) {
var o addMetadataOptions
o.metadata = map[string]string{"owls": "cute", "otters": "adorable"}
o.labelsWithoutSelector = true
m := makeKustomization(t)
assert.NoError(t, o.addLabels(m))
// adding new labels should work
o.metadata = map[string]string{"new": "label"}
assert.NoError(t, o.addLabels(m))
assert.Equal(t, m.Labels[0], types.Label{Pairs: map[string]string{"owls": "cute", "otters": "adorable"}})
assert.Equal(t, m.Labels[1], types.Label{Pairs: map[string]string{"new": "label"}})
}

View File

@@ -8,7 +8,7 @@ import (
"log"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/api/loader"
ldrhelper "sigs.k8s.io/kustomize/api/pkg/loader"
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/kustfile"
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/util"
"sigs.k8s.io/kustomize/kyaml/filesys"

View File

@@ -4,6 +4,8 @@
package add
import (
"fmt"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/resource"
@@ -16,8 +18,9 @@ import (
func newCmdAddConfigMap(
fSys filesys.FileSystem,
ldr ifc.KvLoader,
rf *resource.Factory) *cobra.Command {
var flags flagsAndArgs
rf *resource.Factory,
) *cobra.Command {
var flags configmapSecretFlagsAndArgs
cmd := &cobra.Command{
Use: "configmap NAME [--behavior={create|merge|replace}] [--from-file=[key=]source] [--from-literal=key1=value1]",
Short: "Adds a configmap to the kustomization file",
@@ -36,63 +39,35 @@ func newCmdAddConfigMap(
kustomize edit add configmap my-configmap --behavior=merge --from-env-file=env/path.env
`,
RunE: func(_ *cobra.Command, args []string) error {
err := flags.ExpandFileSource(fSys)
if err != nil {
return err
}
err = flags.Validate(args)
if err != nil {
return err
}
// Load the kustomization file.
mf, err := kustfile.NewKustomizationFile(fSys)
if err != nil {
return err
}
kustomization, err := mf.Read()
if err != nil {
return err
}
// Add the flagsAndArgs map to the kustomization file.
err = addConfigMap(ldr, kustomization, flags, rf)
if err != nil {
return err
}
// Write out the kustomization file with added configmap.
return mf.Write(kustomization)
return runEditAddConfigMap(flags, fSys, args, ldr, rf)
},
}
cmd.Flags().StringSliceVar(
&flags.FileSources,
"from-file",
fromFileFlag,
[]string{},
"Key file can be specified using its file path, in which case file basename will be used as configmap "+
"key, or optionally with a key and file path, in which case the given key will be used. Specifying a "+
"directory will iterate each named file in the directory whose basename is a valid configmap key.")
cmd.Flags().StringArrayVar(
&flags.LiteralSources,
"from-literal",
fromLiteralFlag,
[]string{},
"Specify a key and literal value to insert in configmap (i.e. mykey=somevalue)")
cmd.Flags().StringVar(
&flags.EnvFileSource,
"from-env-file",
fromEnvFileFlag,
"",
"Specify the path to a file to read lines of key=val pairs to create a configmap (i.e. a Docker .env file).")
cmd.Flags().BoolVar(
&flags.DisableNameSuffixHash,
"disableNameSuffixHash",
flagDisableNameSuffixHash,
false,
"Disable the name suffix for the configmap")
cmd.Flags().StringVar(
&flags.Behavior,
"behavior",
flagBehavior,
"",
"Specify the behavior for config map generation, i.e whether to create a new configmap (the default), "+
"to merge with a previously defined one, or to replace an existing one. Merge and replace should be used only "+
@@ -101,15 +76,60 @@ func newCmdAddConfigMap(
return cmd
}
func runEditAddConfigMap(
flags configmapSecretFlagsAndArgs,
fSys filesys.FileSystem,
args []string,
ldr ifc.KvLoader,
rf *resource.Factory,
) error {
err := flags.ExpandFileSource(fSys)
if err != nil {
return fmt.Errorf("failed to expand file source: %w", err)
}
err = flags.Validate(args)
if err != nil {
return fmt.Errorf("failed to validate flags: %w", err)
}
// Load the kustomization file.
mf, err := kustfile.NewKustomizationFile(fSys)
if err != nil {
return fmt.Errorf("failed to load kustomization file: %w", err)
}
kustomization, err := mf.Read()
if err != nil {
return fmt.Errorf("failed to read kustomization file: %w", err)
}
// Add the configmapSecretFlagsAndArgs map to the kustomization file.
err = addConfigMap(ldr, kustomization, flags, rf)
if err != nil {
return fmt.Errorf("failed to create configmap: %w", err)
}
// Write out the kustomization file with added configmap.
err = mf.Write(kustomization)
if err != nil {
return fmt.Errorf("failed to write kustomization file: %w", err)
}
return nil
}
// addConfigMap adds a configmap to a kustomization file.
// Note: error may leave kustomization file in an undefined state.
// Suggest passing a copy of kustomization file.
func addConfigMap(
ldr ifc.KvLoader,
k *types.Kustomization,
flags flagsAndArgs, rf *resource.Factory) error {
flags configmapSecretFlagsAndArgs,
rf *resource.Factory,
) error {
args := findOrMakeConfigMapArgs(k, flags.Name)
mergeFlagsIntoCmArgs(args, flags)
mergeFlagsIntoGeneratorArgs(&args.GeneratorArgs, flags)
// Validate by trying to create corev1.configmap.
args.Options = types.MergeGlobalOptionsIntoLocal(
args.Options, k.GeneratorOptions)
@@ -124,30 +144,9 @@ func findOrMakeConfigMapArgs(m *types.Kustomization, name string) *types.ConfigM
}
}
// config map not found, create new one and add it to the kustomization file.
cm := &types.ConfigMapArgs{GeneratorArgs: types.GeneratorArgs{Name: name}}
cm := &types.ConfigMapArgs{
GeneratorArgs: types.GeneratorArgs{Name: name},
}
m.ConfigMapGenerator = append(m.ConfigMapGenerator, *cm)
return &m.ConfigMapGenerator[len(m.ConfigMapGenerator)-1]
}
func mergeFlagsIntoCmArgs(args *types.ConfigMapArgs, flags flagsAndArgs) {
if len(flags.LiteralSources) > 0 {
args.LiteralSources = append(
args.LiteralSources, flags.LiteralSources...)
}
if len(flags.FileSources) > 0 {
args.FileSources = append(
args.FileSources, flags.FileSources...)
}
if flags.EnvFileSource != "" {
args.EnvSources = append(
args.EnvSources, flags.EnvFileSource)
}
if flags.DisableNameSuffixHash {
args.Options = &types.GeneratorOptions{
DisableNameSuffixHash: true,
}
}
if flags.Behavior != "" {
args.Behavior = flags.Behavior
}
}

View File

@@ -13,8 +13,17 @@ import (
"sigs.k8s.io/kustomize/kyaml/filesys"
)
// flagsAndArgs encapsulates the options for add secret/configmap commands.
type flagsAndArgs struct {
const (
fromFileFlag = "from-file"
fromLiteralFlag = "from-literal"
fromEnvFileFlag = "from-env-file"
flagDisableNameSuffixHash = "disableNameSuffixHash"
flagBehavior = "behavior"
flagFormat = "--%s=%s"
)
// configmapSecretFlagsAndArgs encapsulates the options for add secret/configmap commands.
type configmapSecretFlagsAndArgs struct {
// Name of configMap/Secret (required)
Name string
// FileSources to derive the configMap/Secret from (optional)
@@ -35,7 +44,7 @@ type flagsAndArgs struct {
}
// Validate validates required fields are set to support structured generation.
func (a *flagsAndArgs) Validate(args []string) error {
func (a *configmapSecretFlagsAndArgs) Validate(args []string) error {
if len(args) != 1 {
return fmt.Errorf("name must be specified once")
}
@@ -71,7 +80,7 @@ func (a *flagsAndArgs) Validate(args []string) error {
// and the key, if missing, is the same as the value.
// In the case where the key is explicitly declared,
// the globbing, if present, must have exactly one match.
func (a *flagsAndArgs) ExpandFileSource(fSys filesys.FileSystem) error {
func (a *configmapSecretFlagsAndArgs) ExpandFileSource(fSys filesys.FileSystem) error {
var results []string
for _, pattern := range a.FileSources {
var patterns []string
@@ -105,3 +114,26 @@ func (a *flagsAndArgs) ExpandFileSource(fSys filesys.FileSystem) error {
a.FileSources = results
return nil
}
func mergeFlagsIntoGeneratorArgs(args *types.GeneratorArgs, flags configmapSecretFlagsAndArgs) {
if len(flags.LiteralSources) > 0 {
args.LiteralSources = append(
args.LiteralSources, flags.LiteralSources...)
}
if len(flags.FileSources) > 0 {
args.FileSources = append(
args.FileSources, flags.FileSources...)
}
if flags.EnvFileSource != "" {
args.EnvSources = append(
args.EnvSources, flags.EnvFileSource)
}
if flags.DisableNameSuffixHash {
args.Options = &types.GeneratorOptions{
DisableNameSuffixHash: true,
}
}
if flags.Behavior != "" {
args.Behavior = flags.Behavior
}
}

View File

@@ -7,31 +7,30 @@ import (
"reflect"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"sigs.k8s.io/kustomize/kyaml/filesys"
)
func TestDataValidation_NoName(t *testing.T) {
fa := flagsAndArgs{}
assert.Error(t, fa.Validate([]string{}))
fa := configmapSecretFlagsAndArgs{}
require.Error(t, fa.Validate([]string{}))
}
func TestDataValidation_MoreThanOneName(t *testing.T) {
fa := flagsAndArgs{}
fa := configmapSecretFlagsAndArgs{}
assert.Error(t, fa.Validate([]string{"name", "othername"}))
require.Error(t, fa.Validate([]string{"name", "othername"}))
}
func TestDataConfigValidation_Flags(t *testing.T) {
tests := []struct {
name string
fa flagsAndArgs
fa configmapSecretFlagsAndArgs
shouldFail bool
}{
{
name: "env-file-source and literal are both set",
fa: flagsAndArgs{
fa: configmapSecretFlagsAndArgs{
LiteralSources: []string{"one", "two"},
EnvFileSource: "three",
},
@@ -39,7 +38,7 @@ func TestDataConfigValidation_Flags(t *testing.T) {
},
{
name: "env-file-source and from-file are both set",
fa: flagsAndArgs{
fa: configmapSecretFlagsAndArgs{
FileSources: []string{"one", "two"},
EnvFileSource: "three",
},
@@ -47,12 +46,12 @@ func TestDataConfigValidation_Flags(t *testing.T) {
},
{
name: "we don't have any option set",
fa: flagsAndArgs{},
fa: configmapSecretFlagsAndArgs{},
shouldFail: true,
},
{
name: "we have from-file and literal ",
fa: flagsAndArgs{
fa: configmapSecretFlagsAndArgs{
LiteralSources: []string{"one", "two"},
FileSources: []string{"three", "four"},
},
@@ -60,7 +59,7 @@ func TestDataConfigValidation_Flags(t *testing.T) {
},
{
name: "correct behavior",
fa: flagsAndArgs{
fa: configmapSecretFlagsAndArgs{
EnvFileSource: "foo",
Behavior: "merge",
},
@@ -68,7 +67,7 @@ func TestDataConfigValidation_Flags(t *testing.T) {
},
{
name: "incorrect behavior",
fa: flagsAndArgs{
fa: configmapSecretFlagsAndArgs{
EnvFileSource: "foo",
Behavior: "merge-unknown",
},
@@ -79,9 +78,9 @@ func TestDataConfigValidation_Flags(t *testing.T) {
for _, test := range tests {
err := test.fa.Validate([]string{"name"})
if test.shouldFail {
assert.Error(t, err)
require.Error(t, err)
} else {
assert.NoError(t, err)
require.NoError(t, err)
}
}
}
@@ -94,7 +93,7 @@ func TestExpandFileSource(t *testing.T) {
require.NoError(t, err)
_, err = fSys.Create("dir/readme")
require.NoError(t, err)
fa := flagsAndArgs{
fa := configmapSecretFlagsAndArgs{
FileSources: []string{"dir/fa*"},
}
err = fa.ExpandFileSource(fSys)
@@ -118,7 +117,7 @@ func TestExpandFileSourceWithKey(t *testing.T) {
require.NoError(t, err)
_, err = fSys.Create("dir/readme")
require.NoError(t, err)
fa := flagsAndArgs{
fa := configmapSecretFlagsAndArgs{
FileSources: []string{"foo-key=dir/fa*", "bar-key=dir/foobar", "dir/simplebar"},
}
err = fa.ExpandFileSource(fSys)
@@ -141,7 +140,7 @@ func TestExpandFileSourceWithKeyAndError(t *testing.T) {
require.NoError(t, err)
_, err = fSys.Create("dir/readme")
require.NoError(t, err)
fa := flagsAndArgs{
fa := configmapSecretFlagsAndArgs{
FileSources: []string{"foo-key=dir/fa*"},
}
err = fa.ExpandFileSource(fSys)

View File

@@ -4,13 +4,18 @@
package add
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"sigs.k8s.io/kustomize/api/kv"
"sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/pkg/loader"
"sigs.k8s.io/kustomize/api/provider"
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/kustfile"
testutils_test "sigs.k8s.io/kustomize/kustomize/v5/commands/internal/testutils"
"sigs.k8s.io/kustomize/kyaml/filesys"
)
@@ -47,10 +52,10 @@ func TestMergeFlagsIntoConfigMapArgs_LiteralSources(t *testing.T) {
args := findOrMakeConfigMapArgs(k, "foo")
mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
flagsAndArgs{LiteralSources: []string{"k1=v1"}})
configmapSecretFlagsAndArgs{LiteralSources: []string{"k1=v1"}})
mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
flagsAndArgs{LiteralSources: []string{"k2=v2"}})
configmapSecretFlagsAndArgs{LiteralSources: []string{"k2=v2"}})
assert.Equal(t, "k1=v1", k.ConfigMapGenerator[0].LiteralSources[0])
assert.Equal(t, "k2=v2", k.ConfigMapGenerator[0].LiteralSources[1])
}
@@ -60,10 +65,10 @@ func TestMergeFlagsIntoConfigMapArgs_FileSources(t *testing.T) {
args := findOrMakeConfigMapArgs(k, "foo")
mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
flagsAndArgs{FileSources: []string{"file1"}})
configmapSecretFlagsAndArgs{FileSources: []string{"file1"}})
mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
flagsAndArgs{FileSources: []string{"file2"}})
configmapSecretFlagsAndArgs{FileSources: []string{"file2"}})
assert.Equal(t, "file1", k.ConfigMapGenerator[0].FileSources[0])
assert.Equal(t, "file2", k.ConfigMapGenerator[0].FileSources[1])
}
@@ -73,10 +78,10 @@ func TestMergeFlagsIntoConfigMapArgs_EnvSource(t *testing.T) {
args := findOrMakeConfigMapArgs(k, "foo")
mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
flagsAndArgs{EnvFileSource: "env1"})
configmapSecretFlagsAndArgs{EnvFileSource: "env1"})
mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
flagsAndArgs{EnvFileSource: "env2"})
configmapSecretFlagsAndArgs{EnvFileSource: "env2"})
assert.Equal(t, "env1", k.ConfigMapGenerator[0].EnvSources[0])
assert.Equal(t, "env2", k.ConfigMapGenerator[0].EnvSources[1])
}
@@ -85,7 +90,7 @@ func TestMergeFlagsIntoConfigMapArgs_Behavior(t *testing.T) {
k := &types.Kustomization{}
args := findOrMakeConfigMapArgs(k, "foo")
createBehaviorFlags := flagsAndArgs{
createBehaviorFlags := configmapSecretFlagsAndArgs{
Behavior: "create",
EnvFileSource: "env1",
}
@@ -94,7 +99,7 @@ func TestMergeFlagsIntoConfigMapArgs_Behavior(t *testing.T) {
createBehaviorFlags)
assert.Equal(t, "create", k.ConfigMapGenerator[0].Behavior)
mergeBehaviorFlags := flagsAndArgs{
mergeBehaviorFlags := configmapSecretFlagsAndArgs{
Behavior: "merge",
EnvFileSource: "env1",
}
@@ -103,7 +108,7 @@ func TestMergeFlagsIntoConfigMapArgs_Behavior(t *testing.T) {
mergeBehaviorFlags)
assert.Equal(t, "merge", k.ConfigMapGenerator[0].Behavior)
replaceBehaviorFlags := flagsAndArgs{
replaceBehaviorFlags := configmapSecretFlagsAndArgs{
Behavior: "replace",
EnvFileSource: "env1",
}
@@ -112,3 +117,144 @@ func TestMergeFlagsIntoConfigMapArgs_Behavior(t *testing.T) {
replaceBehaviorFlags)
assert.Equal(t, "replace", k.ConfigMapGenerator[0].Behavior)
}
// TestEditAddConfigMapWithLiteralSource executes the same command flow as the CLI invocation
// with a --from-literal flag
func TestEditAddConfigMapWithLiteralSource(t *testing.T) {
const (
configMapName = "test-kustomization"
literalSource = "test-key=test-value"
)
fSys := filesys.MakeEmptyDirInMemory()
testutils_test.WriteTestKustomization(fSys)
pvd := provider.NewDefaultDepProvider()
ldr := kv.NewLoader(loader.NewFileLoaderAtCwd(fSys), pvd.GetFieldValidator())
args := []string{
configMapName,
fmt.Sprintf(flagFormat, fromLiteralFlag, literalSource),
}
cmd := newCmdAddConfigMap(fSys, ldr, pvd.GetResourceFactory())
cmd.SetArgs(args)
require.NoError(t, cmd.Execute())
_, err := testutils_test.ReadTestKustomization(fSys)
require.NoError(t, err)
mf, err := kustfile.NewKustomizationFile(fSys)
require.NoError(t, err)
kustomization, err := mf.Read()
require.NoError(t, err)
require.NotNil(t, kustomization)
require.NotEmpty(t, kustomization.ConfigMapGenerator)
require.Equal(t, 1, len(kustomization.ConfigMapGenerator))
newCmGenerator := kustomization.ConfigMapGenerator[0]
require.NotNil(t, newCmGenerator)
require.Equal(t, configMapName, newCmGenerator.Name)
require.Contains(t, newCmGenerator.LiteralSources, literalSource)
}
// TestEditAddConfigMapWithEnvSource executes the same command flow as the CLI invocation
// with a --from-env-file flag
func TestEditAddConfigMapWithEnvSource(t *testing.T) {
const (
configMapName = "test-kustomization"
envSource = "test-env-source"
)
fSys := filesys.MakeEmptyDirInMemory()
testutils_test.WriteTestKustomization(fSys)
pvd := provider.NewDefaultDepProvider()
ldr := kv.NewLoader(loader.NewFileLoaderAtCwd(fSys), pvd.GetFieldValidator())
envFileContent, err := fSys.Create("test-env-source")
require.NoError(t, err)
_, err = envFileContent.Write([]byte("TEST=value"))
require.NoError(t, err)
err = envFileContent.Close()
require.NoError(t, err)
args := []string{
configMapName,
fmt.Sprintf(flagFormat, fromEnvFileFlag, envSource),
}
cmd := newCmdAddConfigMap(fSys, ldr, pvd.GetResourceFactory())
cmd.SetArgs(args)
require.NoError(t, cmd.Execute())
_, err = testutils_test.ReadTestKustomization(fSys)
require.NoError(t, err)
mf, err := kustfile.NewKustomizationFile(fSys)
require.NoError(t, err)
kustomization, err := mf.Read()
require.NoError(t, err)
require.NotNil(t, kustomization)
require.NotEmpty(t, kustomization.ConfigMapGenerator)
require.Equal(t, 1, len(kustomization.ConfigMapGenerator))
newCmGenerator := kustomization.ConfigMapGenerator[0]
require.NotNil(t, newCmGenerator)
require.Equal(t, configMapName, newCmGenerator.Name)
require.Contains(t, newCmGenerator.EnvSources, envSource)
}
// TestEditAddConfigMapWithFileSource executes the same command flow as the CLI invocation
// with a --from-file flag
func TestEditAddConfigMapWithFileSource(t *testing.T) {
const (
configMapName = "test-kustomization"
fileSource = "test-file-source"
)
fSys := filesys.MakeEmptyDirInMemory()
testutils_test.WriteTestKustomization(fSys)
pvd := provider.NewDefaultDepProvider()
ldr := kv.NewLoader(loader.NewFileLoaderAtCwd(fSys), pvd.GetFieldValidator())
fileContent, err := fSys.Create("test-file-source")
require.NoError(t, err)
_, err = fileContent.Write([]byte("any content here"))
require.NoError(t, err)
err = fileContent.Close()
require.NoError(t, err)
args := []string{
configMapName,
fmt.Sprintf(flagFormat, fromFileFlag, fileSource),
}
cmd := newCmdAddConfigMap(fSys, ldr, pvd.GetResourceFactory())
cmd.SetArgs(args)
require.NoError(t, cmd.Execute())
_, err = testutils_test.ReadTestKustomization(fSys)
require.NoError(t, err)
mf, err := kustfile.NewKustomizationFile(fSys)
require.NoError(t, err)
kustomization, err := mf.Read()
require.NoError(t, err)
require.NotNil(t, kustomization)
require.NotEmpty(t, kustomization.ConfigMapGenerator)
require.Equal(t, 1, len(kustomization.ConfigMapGenerator))
newCmGenerator := kustomization.ConfigMapGenerator[0]
require.NotNil(t, newCmGenerator)
require.Equal(t, configMapName, newCmGenerator.Name)
require.Contains(t, newCmGenerator.FileSources, fileSource)
}

View File

@@ -4,6 +4,8 @@
package add
import (
"fmt"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/resource"
@@ -16,8 +18,9 @@ import (
func newCmdAddSecret(
fSys filesys.FileSystem,
ldr ifc.KvLoader,
rf *resource.Factory) *cobra.Command {
var flags flagsAndArgs
rf *resource.Factory,
) *cobra.Command {
var flags configmapSecretFlagsAndArgs
cmd := &cobra.Command{
Use: "secret NAME [--from-file=[key=]source] [--from-literal=key1=value1] [--type=Opaque|kubernetes.io/tls]",
Short: "Adds a secret to the kustomization file.",
@@ -33,53 +36,25 @@ func newCmdAddSecret(
kustomize edit add secret my-secret --from-env-file=env/path.env
`,
RunE: func(_ *cobra.Command, args []string) error {
err := flags.ExpandFileSource(fSys)
if err != nil {
return err
}
err = flags.Validate(args)
if err != nil {
return err
}
// Load the kustomization file.
mf, err := kustfile.NewKustomizationFile(fSys)
if err != nil {
return err
}
kustomization, err := mf.Read()
if err != nil {
return err
}
// Add the flagsAndArgs map to the kustomization file.
err = addSecret(ldr, kustomization, flags, rf)
if err != nil {
return err
}
// Write out the kustomization file with added secret.
return mf.Write(kustomization)
return runEditAddSecret(flags, fSys, args, ldr, rf)
},
}
cmd.Flags().StringSliceVar(
&flags.FileSources,
"from-file",
fromFileFlag,
[]string{},
"Key file can be specified using its file path, in which case file basename will be used as secret "+
"key, or optionally with a key and file path, in which case the given key will be used. Specifying a "+
"directory will iterate each named file in the directory whose basename is a valid secret key.")
cmd.Flags().StringArrayVar(
&flags.LiteralSources,
"from-literal",
fromLiteralFlag,
[]string{},
"Specify a key and literal value to insert in secret (i.e. mykey=somevalue)")
cmd.Flags().StringVar(
&flags.EnvFileSource,
"from-env-file",
fromEnvFileFlag,
"",
"Specify the path to a file to read lines of key=val pairs to create a secret (i.e. a Docker .env file).")
cmd.Flags().StringVar(
@@ -94,20 +69,63 @@ func newCmdAddSecret(
"Specify the namespace of the secret")
cmd.Flags().BoolVar(
&flags.DisableNameSuffixHash,
"disableNameSuffixHash",
flagDisableNameSuffixHash,
false,
"Disable the name suffix for the secret")
return cmd
}
func runEditAddSecret(
flags configmapSecretFlagsAndArgs,
fSys filesys.FileSystem,
args []string,
ldr ifc.KvLoader,
rf *resource.Factory,
) error {
err := flags.ExpandFileSource(fSys)
if err != nil {
return fmt.Errorf("failed to expand file source: %w", err)
}
err = flags.Validate(args)
if err != nil {
return fmt.Errorf("failed to validate flags: %w", err)
}
// Load the kustomization file.
mf, err := kustfile.NewKustomizationFile(fSys)
if err != nil {
return fmt.Errorf("failed to load kustomization file: %w", err)
}
kustomization, err := mf.Read()
if err != nil {
return fmt.Errorf("failed to read kustomization file: %w", err)
}
// Add the configmapSecretFlagsAndArgs map to the kustomization file.
err = addSecret(ldr, kustomization, flags, rf)
if err != nil {
return fmt.Errorf("failed to create secret: %w", err)
}
// Write out the kustomization file with added secret.
err = mf.Write(kustomization)
if err != nil {
return fmt.Errorf("failed to write kustomization file: %w", err)
}
return nil
}
// addSecret adds a secret to a kustomization file.
// Note: error may leave kustomization file in an undefined state.
// Suggest passing a copy of kustomization file.
func addSecret(
ldr ifc.KvLoader,
k *types.Kustomization,
flags flagsAndArgs, rf *resource.Factory) error {
flags configmapSecretFlagsAndArgs, rf *resource.Factory) error {
args := findOrMakeSecretArgs(k, flags.Name, flags.Namespace, flags.Type)
mergeFlagsIntoGeneratorArgs(&args.GeneratorArgs, flags)
// Validate by trying to create corev1.secret.
@@ -131,26 +149,3 @@ func findOrMakeSecretArgs(m *types.Kustomization, name, namespace, secretType st
m.SecretGenerator = append(m.SecretGenerator, *secret)
return &m.SecretGenerator[len(m.SecretGenerator)-1]
}
func mergeFlagsIntoGeneratorArgs(args *types.GeneratorArgs, flags flagsAndArgs) {
if len(flags.LiteralSources) > 0 {
args.LiteralSources = append(
args.LiteralSources, flags.LiteralSources...)
}
if len(flags.FileSources) > 0 {
args.FileSources = append(
args.FileSources, flags.FileSources...)
}
if flags.EnvFileSource != "" {
args.EnvSources = append(
args.EnvSources, flags.EnvFileSource)
}
if flags.DisableNameSuffixHash {
args.Options = &types.GeneratorOptions{
DisableNameSuffixHash: true,
}
}
if flags.Behavior != "" {
args.Behavior = flags.Behavior
}
}

View File

@@ -4,13 +4,18 @@
package add
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"sigs.k8s.io/kustomize/api/kv"
"sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/pkg/loader"
"sigs.k8s.io/kustomize/api/provider"
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/kustfile"
testutils_test "sigs.k8s.io/kustomize/kustomize/v5/commands/internal/testutils"
"sigs.k8s.io/kustomize/kyaml/filesys"
)
@@ -48,10 +53,10 @@ func TestMergeFlagsIntoSecretArgs_LiteralSources(t *testing.T) {
args := findOrMakeSecretArgs(k, "foo", "bar", "forbidden")
mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
flagsAndArgs{LiteralSources: []string{"k1=v1"}})
configmapSecretFlagsAndArgs{LiteralSources: []string{"k1=v1"}})
mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
flagsAndArgs{LiteralSources: []string{"k2=v2"}})
configmapSecretFlagsAndArgs{LiteralSources: []string{"k2=v2"}})
assert.Equal(t, "k1=v1", k.SecretGenerator[0].LiteralSources[0])
assert.Equal(t, "k2=v2", k.SecretGenerator[0].LiteralSources[1])
}
@@ -61,10 +66,10 @@ func TestMergeFlagsIntoSecretArgs_FileSources(t *testing.T) {
args := findOrMakeSecretArgs(k, "foo", "bar", "forbidden")
mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
flagsAndArgs{FileSources: []string{"file1"}})
configmapSecretFlagsAndArgs{FileSources: []string{"file1"}})
mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
flagsAndArgs{FileSources: []string{"file2"}})
configmapSecretFlagsAndArgs{FileSources: []string{"file2"}})
assert.Equal(t, "file1", k.SecretGenerator[0].FileSources[0])
assert.Equal(t, "file2", k.SecretGenerator[0].FileSources[1])
}
@@ -74,10 +79,10 @@ func TestMergeFlagsIntoSecretArgs_EnvSource(t *testing.T) {
args := findOrMakeSecretArgs(k, "foo", "bar", "forbidden")
mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
flagsAndArgs{EnvFileSource: "env1"})
configmapSecretFlagsAndArgs{EnvFileSource: "env1"})
mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
flagsAndArgs{EnvFileSource: "env2"})
configmapSecretFlagsAndArgs{EnvFileSource: "env2"})
assert.Equal(t, "env1", k.SecretGenerator[0].EnvSources[0])
assert.Equal(t, "env2", k.SecretGenerator[0].EnvSources[1])
}
@@ -87,6 +92,147 @@ func TestMergeFlagsIntoSecretArgs_DisableNameSuffixHash(t *testing.T) {
args := findOrMakeSecretArgs(k, "foo", "bar", "forbidden")
mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
flagsAndArgs{DisableNameSuffixHash: true})
configmapSecretFlagsAndArgs{DisableNameSuffixHash: true})
assert.True(t, k.SecretGenerator[0].Options.DisableNameSuffixHash)
}
// TestEditAddSecretWithLiteralSource executes the same command flow as the CLI invocation
// with a --from-literal flag
func TestEditAddSecretWithLiteralSource(t *testing.T) {
const (
secretName = "test-kustomization"
literalSource = "test-key=test-value"
)
fSys := filesys.MakeEmptyDirInMemory()
testutils_test.WriteTestKustomization(fSys)
pvd := provider.NewDefaultDepProvider()
ldr := kv.NewLoader(loader.NewFileLoaderAtCwd(fSys), pvd.GetFieldValidator())
args := []string{
secretName,
fmt.Sprintf(flagFormat, fromLiteralFlag, literalSource),
}
cmd := newCmdAddSecret(fSys, ldr, pvd.GetResourceFactory())
cmd.SetArgs(args)
require.NoError(t, cmd.Execute())
_, err := testutils_test.ReadTestKustomization(fSys)
require.NoError(t, err)
mf, err := kustfile.NewKustomizationFile(fSys)
require.NoError(t, err)
kustomization, err := mf.Read()
require.NoError(t, err)
require.NotNil(t, kustomization)
require.NotEmpty(t, kustomization.SecretGenerator)
require.Equal(t, 1, len(kustomization.SecretGenerator))
newSecretGenerator := kustomization.SecretGenerator[0]
require.NotNil(t, newSecretGenerator)
require.Equal(t, secretName, newSecretGenerator.Name)
require.Contains(t, newSecretGenerator.LiteralSources, literalSource)
}
// TestEditAddSecretWithEnvSource executes the same command flow as the CLI invocation
// with a --from-env-file flag
func TestEditAddSecretWithEnvSource(t *testing.T) {
const (
secretName = "test-kustomization"
envSource = "test-env-source"
)
fSys := filesys.MakeEmptyDirInMemory()
testutils_test.WriteTestKustomization(fSys)
pvd := provider.NewDefaultDepProvider()
ldr := kv.NewLoader(loader.NewFileLoaderAtCwd(fSys), pvd.GetFieldValidator())
envFileContent, err := fSys.Create("test-env-source")
require.NoError(t, err)
_, err = envFileContent.Write([]byte("TEST=value"))
require.NoError(t, err)
err = envFileContent.Close()
require.NoError(t, err)
args := []string{
secretName,
fmt.Sprintf(flagFormat, fromEnvFileFlag, envSource),
}
cmd := newCmdAddSecret(fSys, ldr, pvd.GetResourceFactory())
cmd.SetArgs(args)
require.NoError(t, cmd.Execute())
_, err = testutils_test.ReadTestKustomization(fSys)
require.NoError(t, err)
mf, err := kustfile.NewKustomizationFile(fSys)
require.NoError(t, err)
kustomization, err := mf.Read()
require.NoError(t, err)
require.NotNil(t, kustomization)
require.NotEmpty(t, kustomization.SecretGenerator)
require.Equal(t, 1, len(kustomization.SecretGenerator))
newSecretGenerator := kustomization.SecretGenerator[0]
require.NotNil(t, newSecretGenerator)
require.Equal(t, secretName, newSecretGenerator.Name)
require.Contains(t, newSecretGenerator.EnvSources, envSource)
}
// TestEditAddSecretWithFileSource executes the same command flow as the CLI invocation
// with a --from-file flag
func TestEditAddSecretWithFileSource(t *testing.T) {
const (
secretName = "test-kustomization"
fileSource = "test-file-source"
)
fSys := filesys.MakeEmptyDirInMemory()
testutils_test.WriteTestKustomization(fSys)
pvd := provider.NewDefaultDepProvider()
ldr := kv.NewLoader(loader.NewFileLoaderAtCwd(fSys), pvd.GetFieldValidator())
fileContent, err := fSys.Create("test-file-source")
require.NoError(t, err)
_, err = fileContent.Write([]byte("any content here"))
require.NoError(t, err)
err = fileContent.Close()
require.NoError(t, err)
args := []string{
secretName,
fmt.Sprintf(flagFormat, fromFileFlag, fileSource),
}
cmd := newCmdAddSecret(fSys, ldr, pvd.GetResourceFactory())
cmd.SetArgs(args)
require.NoError(t, cmd.Execute())
_, err = testutils_test.ReadTestKustomization(fSys)
require.NoError(t, err)
mf, err := kustfile.NewKustomizationFile(fSys)
require.NoError(t, err)
kustomization, err := mf.Read()
require.NoError(t, err)
require.NotNil(t, kustomization)
require.NotEmpty(t, kustomization.SecretGenerator)
require.Equal(t, 1, len(kustomization.SecretGenerator))
newSecretGenerator := kustomization.SecretGenerator[0]
require.NotNil(t, newSecretGenerator)
require.Equal(t, secretName, newSecretGenerator.Name)
require.Contains(t, newSecretGenerator.FileSources, fileSource)
}

View File

@@ -9,7 +9,7 @@ import (
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/kv"
"sigs.k8s.io/kustomize/api/loader"
ldrhelper "sigs.k8s.io/kustomize/api/pkg/loader"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/kustomize/v5/commands/edit/add"
"sigs.k8s.io/kustomize/kustomize/v5/commands/edit/fix"
@@ -43,11 +43,11 @@ func NewCmdEdit(
c.AddCommand(
add.NewCmdAdd(
fSys,
kv.NewLoader(loader.NewFileLoaderAtCwd(fSys), v),
kv.NewLoader(ldrhelper.NewFileLoaderAtCwd(fSys), v),
rf),
set.NewCmdSet(
fSys,
kv.NewLoader(loader.NewFileLoaderAtCwd(fSys), v),
kv.NewLoader(ldrhelper.NewFileLoaderAtCwd(fSys), v),
v),
fix.NewCmdFix(fSys, w),
remove.NewCmdRemove(fSys, v),

View File

@@ -22,6 +22,12 @@ func NewCmdRemove(
kustomize edit remove resource {filepath} {filepath}
kustomize edit remove resource {pattern}
# Removes one or more configmap from the kustomization file
kustomize edit remove configmap {name1},{name2}
# Removes one or more secret from the kustomization file
kustomize edit remove secret {name1},{name2}
# Removes one or more patches from the kustomization file
kustomize edit remove patch --path {filepath} --group {target group name} --version {target version}
@@ -37,6 +43,8 @@ func NewCmdRemove(
Args: cobra.MinimumNArgs(1),
}
c.AddCommand(
newCmdRemoveConfigMap(fSys),
newCmdRemoveSecret(fSys),
newCmdRemoveResource(fSys),
newCmdRemoveLabel(fSys, v.MakeLabelNameValidator()),
newCmdRemoveAnnotation(fSys, v.MakeAnnotationNameValidator()),

View File

@@ -0,0 +1,99 @@
// Copyright 2023 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package remove
import (
"errors"
"fmt"
"log"
"strings"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/kustfile"
"sigs.k8s.io/kustomize/kyaml/filesys"
)
type removeConfigMapOptions struct {
configMapNamesToRemove []string
}
// newCmdRemoveConfigMap removes configMapGenerator(s) with the specified name(s).
func newCmdRemoveConfigMap(fSys filesys.FileSystem) *cobra.Command {
var o removeConfigMapOptions
cmd := &cobra.Command{
Use: "configmap",
Short: "Removes the specified configmap(s) from " +
konfig.DefaultKustomizationFileName(),
Long: "",
Example: `
remove configmap my-configmap
`,
RunE: func(cmd *cobra.Command, args []string) error {
err := o.Validate(args)
if err != nil {
return err
}
return o.RunRemoveConfigMap(fSys)
},
}
return cmd
}
// Validate validates removeConfigMap command.
func (o *removeConfigMapOptions) Validate(args []string) error {
switch {
case len(args) == 0:
return errors.New("at least one configmap name must be specified")
case len(args) > 1:
return fmt.Errorf("too many arguments: %s; to provide multiple configmaps to remove, please separate configmap names by commas", args)
}
o.configMapNamesToRemove = strings.Split(args[0], ",")
return nil
}
// RunRemoveConfigMap runs ConfigMap command (do real work).
func (o *removeConfigMapOptions) RunRemoveConfigMap(fSys filesys.FileSystem) error {
mf, err := kustfile.NewKustomizationFile(fSys)
if err != nil {
return fmt.Errorf("could not read kustomization file: %w", err)
}
m, err := mf.Read()
if err != nil {
return fmt.Errorf("could not read kustomization file contents: %w", err)
}
foundConfigMaps := make(map[string]struct{})
newConfigMaps := make([]types.ConfigMapArgs, 0, len(m.ConfigMapGenerator))
for _, currentConfigMap := range m.ConfigMapGenerator {
if kustfile.StringInSlice(currentConfigMap.Name, o.configMapNamesToRemove) {
foundConfigMaps[currentConfigMap.Name] = struct{}{}
continue
}
newConfigMaps = append(newConfigMaps, currentConfigMap)
}
if len(foundConfigMaps) == 0 {
return fmt.Errorf("no specified configmap(s) were found in the %s file",
konfig.DefaultKustomizationFileName())
}
for _, name := range o.configMapNamesToRemove {
if _, found := foundConfigMaps[name]; !found {
log.Printf("configmap %s doesn't exist in kustomization file", name)
}
}
m.ConfigMapGenerator = newConfigMaps
err = mf.Write(m)
if err != nil {
return fmt.Errorf("failed to write kustomization file: %w", err)
}
return nil
}

View File

@@ -0,0 +1,116 @@
// Copyright 2023 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package remove //nolint:testpackage
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
testutils_test "sigs.k8s.io/kustomize/kustomize/v5/commands/internal/testutils"
"sigs.k8s.io/kustomize/kyaml/filesys"
)
func TestRemoveConfigMap(t *testing.T) {
const configMapName01 = "example-configmap-01"
const configMapName02 = "example-configmap-02"
tests := map[string]struct {
input string
args []string
expectedOutput string
expectedErr string
}{
"happy path": {
input: fmt.Sprintf(`
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
configMapGenerator:
- name: %s
files:
- application.properties
`, configMapName01),
args: []string{configMapName01},
expectedOutput: `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
`,
},
"multiple": {
input: fmt.Sprintf(`
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
configMapGenerator:
- name: %s
files:
- application.properties
- name: %s
files:
- application.properties
`, configMapName01, configMapName02),
args: []string{
fmt.Sprintf("%s,%s", configMapName01, configMapName02),
},
expectedOutput: `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
`,
},
"miss": {
input: fmt.Sprintf(`
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
configMapGenerator:
- name: %s
files:
- application.properties
`, configMapName01),
args: []string{"foo"},
expectedErr: "no specified configmap(s) were found",
},
"no configmap name specified": {
args: []string{},
expectedErr: "at least one configmap name must be specified",
},
"too many configmap names specified": {
args: []string{"test1", "test2"},
expectedErr: "too many arguments",
},
"one existing and one non-existing": {
input: fmt.Sprintf(`
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
configMapGenerator:
- name: %s
files:
- application.properties
`, configMapName01),
args: []string{fmt.Sprintf("%s,%s", configMapName01, "foo")},
expectedOutput: `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
`,
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
fSys := filesys.MakeFsInMemory()
testutils_test.WriteTestKustomizationWith(fSys, []byte(tc.input))
cmd := newCmdRemoveConfigMap(fSys)
err := cmd.RunE(cmd, tc.args)
if tc.expectedErr != "" {
require.Error(t, err)
require.Contains(t, err.Error(), tc.expectedErr)
return
}
require.NoError(t, err)
content, err := testutils_test.ReadTestKustomization(fSys)
require.NoError(t, err)
require.Equal(t, tc.expectedOutput, string(content))
})
}
}

View File

@@ -0,0 +1,99 @@
// Copyright 2023 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package remove
import (
"errors"
"fmt"
"log"
"strings"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/kustfile"
"sigs.k8s.io/kustomize/kyaml/filesys"
)
type removeSecretOptions struct {
secretNamesToRemove []string
}
// newCmdRemoveSecret removes secretGenerator(s) with the specified name(s).
func newCmdRemoveSecret(fSys filesys.FileSystem) *cobra.Command {
var o removeSecretOptions
cmd := &cobra.Command{
Use: "secret",
Short: "Removes the specified secret(s) from " +
konfig.DefaultKustomizationFileName(),
Long: "",
Example: `
remove secret my-secret
`,
RunE: func(cmd *cobra.Command, args []string) error {
err := o.Validate(args)
if err != nil {
return err
}
return o.RunRemoveSecret(fSys)
},
}
return cmd
}
// Validate validates removeSecret command.
func (o *removeSecretOptions) Validate(args []string) error {
switch {
case len(args) == 0:
return errors.New("at least one secret name must be specified")
case len(args) > 1:
return fmt.Errorf("too many arguments: %s; to provide multiple secrets to remove, please separate secret names by commas", args)
}
o.secretNamesToRemove = strings.Split(args[0], ",")
return nil
}
// RunRemoveSecret runs Secret command (do real work).
func (o *removeSecretOptions) RunRemoveSecret(fSys filesys.FileSystem) error {
mf, err := kustfile.NewKustomizationFile(fSys)
if err != nil {
return fmt.Errorf("could not read kustomization file: %w", err)
}
m, err := mf.Read()
if err != nil {
return fmt.Errorf("could not read kustomization file contents: %w", err)
}
foundSecrets := make(map[string]struct{})
newSecrets := make([]types.SecretArgs, 0, len(m.SecretGenerator))
for _, currentSecret := range m.SecretGenerator {
if kustfile.StringInSlice(currentSecret.Name, o.secretNamesToRemove) {
foundSecrets[currentSecret.Name] = struct{}{}
continue
}
newSecrets = append(newSecrets, currentSecret)
}
if len(foundSecrets) == 0 {
return fmt.Errorf("no specified secret(s) were found in the %s file",
konfig.DefaultKustomizationFileName())
}
for _, name := range o.secretNamesToRemove {
if _, found := foundSecrets[name]; !found {
log.Printf("secret %s doesn't exist in kustomization file", name)
}
}
m.SecretGenerator = newSecrets
err = mf.Write(m)
if err != nil {
return fmt.Errorf("failed to write kustomization file: %w", err)
}
return nil
}

View File

@@ -0,0 +1,116 @@
// Copyright 2023 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package remove //nolint:testpackage
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
testutils_test "sigs.k8s.io/kustomize/kustomize/v5/commands/internal/testutils"
"sigs.k8s.io/kustomize/kyaml/filesys"
)
func TestRemoveSecret(t *testing.T) {
const secretName01 = "example-secret-01"
const secretName02 = "example-secret-02"
tests := map[string]struct {
input string
args []string
expectedOutput string
expectedErr string
}{
"happy path": {
input: fmt.Sprintf(`
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
secretGenerator:
- name: %s
files:
- longsecret.txt
`, secretName01),
args: []string{secretName01},
expectedOutput: `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
`,
},
"multiple": {
input: fmt.Sprintf(`
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
secretGenerator:
- name: %s
files:
- longsecret.txt
- name: %s
files:
- longsecret.txt
`, secretName01, secretName02),
args: []string{
fmt.Sprintf("%s,%s", secretName01, secretName02),
},
expectedOutput: `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
`,
},
"miss": {
input: fmt.Sprintf(`
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
secretGenerator:
- name: %s
files:
- longsecret.txt
`, secretName01),
args: []string{"foo"},
expectedErr: "no specified secret(s) were found",
},
"no secret name specified": {
args: []string{},
expectedErr: "at least one secret name must be specified",
},
"too many secret names specified": {
args: []string{"test1", "test2"},
expectedErr: "too many arguments",
},
"one existing and one non-existing": {
input: fmt.Sprintf(`
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
secretGenerator:
- name: %s
files:
- application.properties
`, secretName01),
args: []string{fmt.Sprintf("%s,%s", secretName01, "foo")},
expectedOutput: `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
`,
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
fSys := filesys.MakeFsInMemory()
testutils_test.WriteTestKustomizationWith(fSys, []byte(tc.input))
cmd := newCmdRemoveSecret(fSys)
err := cmd.RunE(cmd, tc.args)
if tc.expectedErr != "" {
require.Error(t, err)
require.Contains(t, err.Error(), tc.expectedErr)
return
}
require.NoError(t, err)
content, err := testutils_test.ReadTestKustomization(fSys)
require.NoError(t, err)
require.Equal(t, tc.expectedOutput, string(content))
})
}
}

View File

@@ -33,7 +33,7 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/sys v0.12.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/evanphx/json-patch.v5 v5.6.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect

View File

@@ -67,8 +67,8 @@ github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc=
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@@ -2,7 +2,7 @@
title: "Kustomization File"
linkTitle: "Kustomization File"
weight: 1
date: 2023-07-28
date: 2023-09-17
description: >
The Kustomization file is the entry point for Kustomize execution.
---
---

View File

@@ -0,0 +1,24 @@
---
title: "bases"
linkTitle: "bases"
type: docs
weight: 1
description: >
Add resources from a kustomization dir.
---
{{% pageinfo color="warning" %}}
The `bases` field was deprecated in v2.1.0. This field will never be removed from the
kustomize.config.k8s.io/v1beta1 Kustomization API, but it will not be included
in the kustomize.config.k8s.io/v1 Kustomization API. When Kustomization v1 is available,
we will announce the deprecation of the v1beta1 version. There will be at least
two releases between deprecation and removal of Kustomization v1beta1 support from the
kustomize CLI, and removal itself will happen in a future major version bump.
You can run `kustomize edit fix` to automatically convert `bases` to `resources`.
{{% /pageinfo %}}
Move entries into the [resources](/docs/reference/api/kustomization-file/resources)
field. This allows bases - which are still a
[central concept](/docs/concepts/bases) - to be
ordered relative to other input resources.

View File

@@ -0,0 +1,316 @@
---
title: "buildMetadata"
linkTitle: "buildMetadata"
type: docs
weight: 2
description: >
Specify options for including information about the build in annotations or labels.
---
The `buildMetadata` field is a list of strings. The strings can be one of three builtin
options that add some metadata to each resource about how the resource was built.
These options are:
- `managedByLabel`
- `originAnnotations`
- `transformerAnnotations`
It is possible to set one or all of these options in the kustomization file:
```yaml
buildMetadata: [managedByLabel, originAnnotations, transformerAnnotations]
```
### Managed By Label
To mark the resource as having been managed by kustomize, you can specify the `managedByLabel`
option in the `buildMetadata` field of the kustomization:
```yaml
buildMetadata: [managedByLabel]
```
This will add the label `app.kubernetes.io/managed-by` to each resource with the version of kustomize
that has built it. For example, given the following input:
kustomization.yaml
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- service.yaml
buildMetadata: [managedByLabel]
```
service.yaml
```yaml
apiVersion: v1
kind: Service
metadata:
name: myService
spec:
ports:
- port: 7002
```
`kustomize build` will produce a resource with an output like the following:
```yaml
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/managed-by: kustomize-v4.4.1
name: myService
spec:
ports:
- port: 7002
```
### Origin Annotation
To annotate resources with information about their origin, you can specify the `originAnnotations`:
```yaml
buildMetadata: [originAnnotations]
```
When this option is set, generated resources will receive an annotation with key `config.kubernetes.io/origin`,
containing data about the generator that produced it. If the resource is from the `resources` field, this annotation
contains data about the file it originated from.
The possible fields of these annotations are:
- `path`: The path to a resource file itself
- `ref`: If from a remote file or generator, the ref of the repo URL.
- `repo`: If from a remote file or generator, the repo source
- `configuredIn`: If a generated resource, the path to the generator config. If a generator is invoked via a field
in the kustomization file, this would point to the kustomization file itself.
- `configuredBy`: If a generated resource, the ObjectReference of the generator config.
All local file paths are relative to the top-level kustomization, i.e. the kustomization file in the directory upon
which `kustomize build` was invoked. For example, if someone were to run `kustomize build foo`, all file paths
in the annotation output would be relative to`foo/kustomization.yaml`. All remote file paths are relative to the root of the
remote repository. Any fields that are not applicable would be omitted from the final output.
Here is an example of what this would look like:
```yaml
config.kubernetes.io/origin: |
path: path.yaml
ref: v0.0.0
repo: http://github.com/examplerepo
configuredIn: path/to/generatorconfig
configuredBy:
kind: Generator
apiVersion: builtin
name: foo
namespace: default
```
#### Examples
##### Resource declared from `resources`
A kustomization such as the following:
```yaml
resources:
- deployment.yaml
buildMetadata: [originAnnotations]
```
would produce a resource with an annotation like the following:
```yaml
config.kubernetes.io/origin: |
path: deployment.yaml
```
##### Local custom generator
A kustomization such as the following:
```yaml
generators:
- generator.yaml
buildMetadata: [originAnnotations]
```
would produce a resource with an annotation like the following:
```yaml
config.kubernetes.io/origin: |
configuredIn: generator.yaml
configuredBy:
kind: MyGenerator
apiVersion: v1
name: generator
```
##### Remote builtin generator
We have a top-level kustomization such as the following:
```yaml
resources:
- github.com/examplerepo/?ref=v1.0.6
buildMetadata: [originAnnotations]
```
which uses `github.com/examplerepo/?ref=v1.0.6` as a remote base. This remote base has the following kustomization
defined in `github.com/examplerepo/kustomization.yaml`:
```yaml
configMapGenerator:
- name: my-java-server-env-vars
literals:
- JAVA_HOME=/opt/java/jdk
- JAVA_TOOL_OPTIONS=-agentlib:hprof
```
Running `kustomize build` on the top-level kustomization would produce the following output:
```yaml
apiVersion: v1
data:
JAVA_HOME: /opt/java/jdk
JAVA_TOOL_OPTIONS: -agentlib:hprof
kind: ConfigMap
metadata:
name: my-java-server-env-vars-44k658k8gk
annotations:
config.kubernetes.io/origin: |
ref: v1.0.6
repo: github.com/examplerepo
configuredIn: kustomization.yaml
configuredBy:
kind: ConfigMapGenerator
apiVersion: builtin
```
### Transformer Annotations [Alpha]
To annotate resources with information about the transformers that have acted on them, you can add the
`transformerAnnotations` option to the `buildMetadata` field of the kustomization:
```yaml
buildMetadata: [transformerAnnotations]
```
When the `transformerAnnotations` option is set, kustomize will add annotations with information about what transformers
have acted on each resource. Transformers can be invoked either through various fields in the kustomization file
(e.g. the `replacements` field will invoke the ReplacementTransformer), or through the `transformers` field.
The annotation key for transformer annotations will be `config.kubernetes.io/transformations`, which will contain a list of
transformer data. The possible fields in each item in this list is identical to the possible fields in `config.kubernetes.io/origin`,
except that the transformer annotation does not have a `path` field:
The possible fields of these annotations are:
- `path`: The path to a resource file itself
- `ref`: If from a remote file or generator, the ref of the repo URL.
- `repo`: If from a remote file or generator, the repo source
- `configuredIn`: The path to the transformer config. If a transformer is invoked via a field
in the kustomization file, this would point to the kustomization file itself.
- `configuredBy`: The ObjectReference of the transformer config.
All local file paths are relative to the top-level kustomization, i.e. the kustomization file in the directory upon
which `kustomize build` was invoked. For example, if someone were to run `kustomize build foo`, all file paths
in the annotation output would be relative to`foo/kustomization.yaml`. All remote file paths are relative to the root of the
remote repository. Any fields that are not applicable would be omitted from the final output.
Here is an example of what this would look like:
```yaml
config.kubernetes.io/transformations: |
- ref: v0.0.0
repo: http://github.com/examplerepo
configuredIn: path/to/transformerconfig
configuredBy:
kind: Transformer
apiVersion: builtin
name: foo
namespace: default
```
While this field is in alpha, it will receive the `alpha` prefix, so you will see the annotation key
`alpha.config.kubernetes.io/transformations` instead. We are not guaranteeing that the annotation content will be stable during
alpha, and reserve the right to make changes as we evolve the feature.
#### Examples
#### Local custom transformer
A kustomization such as the following:
```yaml
transformers:
- transformer.yaml
buildMetadata: [transformerAnnotations]
```
would produce a resource with an annotation like the following:
```yaml
config.kubernetes.io/transformations: |
- configuredIn: transformer.yaml
configuredBy:
kind: MyTransformer
apiVersion: v1
name: transformer
```
##### Remote builtin transformer + local builtin transformer
We have a top-level kustomization such as the following:
```yaml
resources:
- github.com/examplerepo/?ref=v1.0.6
buildMetadata: [transformerAnnotations]
namespace: my-ns
```
which uses `github.com/examplerepo/?ref=v1.0.6` as a remote base. This remote base has the following kustomization
defined in `github.com/examplerepo/kustomization.yaml`:
```yaml
resources:
- deployment.yaml
namePrefix: pre-
```
`deployment.yaml` contains the following:
```yaml
apiVersion: v1
kind: Deployment
metadata:
name: deploy
```
Running `kustomize build` on the top-level kustomization would produce the following output:
```yaml
apiVersion: v1
kind: Deployment
metadata:
name: pre-deploy
annotations:
config.kubernetes.io/transformations: |
- ref: v1.0.6
repo: github.com/examplerepo
configuredIn: kustomization.yaml
configuredBy:
kind: PrefixSuffixTransformer
apiVersion: builtin
- configuredIn: kustomization.yaml
configuredBy:
kind: NamespaceTransformer
apiVersion: builtin
```

View File

@@ -0,0 +1,58 @@
---
title: "commonAnnotations"
linkTitle: "commonAnnotations"
type: docs
weight: 3
description: >
Add annotations to add all resources.
---
Add annotations to all resources. If the annotation key already is present on the resource,
the value will be overridden.
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
commonAnnotations:
oncallPager: 800-555-1212
```
## Example
### File Input
```yaml
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
commonAnnotations:
oncallPager: 800-555-1212
resources:
- deploy.yaml
```
```yaml
# deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: example
spec:
...
```
### Build Output
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: example
annotations:
oncallPager: 800-555-1212
spec:
...
```

View File

@@ -0,0 +1,107 @@
---
title: "commonLabels"
linkTitle: "commonLabels"
type: docs
weight: 4
description: >
Add labels and selectors to add all resources.
---
[labels]: /docs/reference/api/kustomization-file/labels/
Add labels and selectors to all resources. If the label key already is present on the resource,
the value will be overridden.
An alternative to this field is the [labels] field, which allows adding labels without also automatically
injecting corresponding selectors.
{{% pageinfo color="warning" %}}
Selectors for resources such as Deployments and Services shouldn't be changed once the
resource has been applied to a cluster.
Changing commonLabels to live resources could result in failures.
{{% /pageinfo %}}
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
commonLabels:
someName: someValue
owner: alice
app: bingo
```
## Example
### File Input
```yaml
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
commonLabels:
someName: someValue
owner: alice
app: bingo
resources:
- deploy.yaml
- service.yaml
```
```yaml
# deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: example
```
```yaml
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: example
```
### Build Output
```yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: bingo
owner: alice
someName: someValue
name: example
spec:
selector:
app: bingo
owner: alice
someName: someValue
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: bingo
owner: alice
someName: someValue
name: example
spec:
selector:
matchLabels:
app: bingo
owner: alice
someName: someValue
template:
metadata:
labels:
app: bingo
owner: alice
someName: someValue
```

View File

@@ -0,0 +1,385 @@
---
title: "Components"
linkTitle: "Components"
type: docs
weight: 5
description: >
Compose kustomizations.
---
As of ``v3.7.0`` Kustomize supports a special type of kustomization that allows
one to define reusable pieces of configuration logic that can be included from
multiple overlays.
Components come in handy when dealing with applications that support multiple
optional features and you wish to enable only a subset of them in different
overlays, i.e., different features for different environments or audiences.
For more details regarding this feature you can read the
[Kustomize Components KEP](https://github.com/kubernetes/enhancements/tree/master/keps/sig-cli/1802-kustomize-components)
and the [components concept](/docs/concepts/components/) page.
## Use case
Suppose you've written a very simple Web application:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: example
spec:
template:
spec:
containers:
- name: example
image: example:1.0
```
You want to deploy a **community** edition of this application as SaaS, so you
add support for persistence (e.g. an external database), and bot detection
(e.g. Google reCAPTCHA).
You've now attracted **enterprise** customers who want to deploy it
on-premises, so you add LDAP support, and disable Google reCAPTCHA. At the same
time, the **devs** need to be able to test parts of the application, so they
want to deploy it with some features enabled and others not.
Here's a matrix with the deployments of this application and the features
enabled for each one:
| | External DB | LDAP | reCAPTCHA |
|------------|:------------------:|:------------------:|:------------------:|
| Community | ✔️ | | ✔️ |
| Enterprise | ✔️ | ✔️ | |
| Dev | ✅ | ✅ | ✅ |
(✔️ enabled, ✅: optional)
So, you want to make it easy to deploy your application in any of the above
three environments. Here's how you can do this with Kustomize components: each
opt-in feature gets packaged as a component, so that it can be referred to from
multiple higher-level overlays.
First, define a place to work:
```shell
DEMO_HOME=$(mktemp -d)
```
Define a common **base** that has a `Deployment` and a simple `ConfigMap`, that
is mounted on the application's container.
```bash
BASE=$DEMO_HOME/base
mkdir $BASE
```
```bash
# $BASE/kustomization.yaml
resources:
- deployment.yaml
configMapGenerator:
- name: conf
literals:
- main.conf=|
color=cornflower_blue
log_level=info
```
```bash
# $BASE/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: example
spec:
template:
spec:
containers:
- name: example
image: example:1.0
volumeMounts:
- name: conf
mountPath: /etc/config
volumes:
- name: conf
configMap:
name: conf
```
Define an `external_db` component, using `kind: Component`, that creates a
`Secret` for the DB password and a new entry in the `ConfigMap`:
```shell
EXT_DB=$DEMO_HOME/components/external_db
mkdir -p $EXT_DB
```
```bash
# $EXT_DB/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1alpha1 # <-- Component notation
kind: Component
secretGenerator:
- name: dbpass
files:
- dbpass.txt
patchesStrategicMerge:
- configmap.yaml
patchesJson6902:
- target:
group: apps
version: v1
kind: Deployment
name: example
path: deployment.yaml
```
```bash
# $EXT_DB/deployment.yaml
- op: add
path: /spec/template/spec/volumes/0
value:
name: dbpass
secret:
secretName: dbpass
- op: add
path: /spec/template/spec/containers/0/volumeMounts/0
value:
mountPath: /var/run/secrets/db/
name: dbpass
```
```bash
# $EXT_DB/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: conf
data:
db.conf: |
endpoint=127.0.0.1:1234
name=app
user=admin
pass=/var/run/secrets/db/dbpass.txt
```
Define an `ldap` component, that creates a `Secret` for the LDAP password
and a new entry in the `ConfigMap`:
```shell
LDAP=$DEMO_HOME/components/ldap
mkdir -p $LDAP
```
```bash
# $LDAP/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component
secretGenerator:
- name: ldappass
files:
- ldappass.txt
patchesStrategicMerge:
- configmap.yaml
patchesJson6902:
- target:
group: apps
version: v1
kind: Deployment
name: example
path: deployment.yaml
```
```bash
# $LDAP/deployment.yaml
- op: add
path: /spec/template/spec/volumes/0
value:
name: ldappass
secret:
secretName: ldappass
- op: add
path: /spec/template/spec/containers/0/volumeMounts/0
value:
mountPath: /var/run/secrets/ldap/
name: ldappass
```
```bash
# $LDAP/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: conf
data:
ldap.conf: |
endpoint=ldap://ldap.example.com
bindDN=cn=admin,dc=example,dc=com
pass=/var/run/secrets/ldap/ldappass.txt
```
Define a `recaptcha` component, that creates a `Secret` for the reCAPTCHA
site/secret keys and a new entry in the `ConfigMap`:
```shell
RECAPTCHA=$DEMO_HOME/components/recaptcha
mkdir -p $RECAPTCHA
```
```bash
# $RECAPTCHA/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component
secretGenerator:
- name: recaptcha
files:
- site_key.txt
- secret_key.txt
# Updating the ConfigMap works with generators as well.
configMapGenerator:
- name: conf
behavior: merge
literals:
- recaptcha.conf=|
enabled=true
site_key=/var/run/secrets/recaptcha/site_key.txt
secret_key=/var/run/secrets/recaptcha/secret_key.txt
patchesJson6902:
- target:
group: apps
version: v1
kind: Deployment
name: example
path: deployment.yaml
```
```bash
# $RECAPTCHA/deployment.yaml
- op: add
path: /spec/template/spec/volumes/0
value:
name: recaptcha
secret:
secretName: recaptcha
- op: add
path: /spec/template/spec/containers/0/volumeMounts/0
value:
mountPath: /var/run/secrets/recaptcha/
name: recaptcha
```
Define a `community` variant, that bundles the external DB and reCAPTCHA
components:
```shell
COMMUNITY=$DEMO_HOME/overlays/community
mkdir -p $COMMUNITY
```
```bash
# $COMMUNITY/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
components:
- ../../components/external_db
- ../../components/recaptcha
```
Define an `enterprise` overlay, that bundles the external DB and LDAP
components:
```shell
ENTERPRISE=$DEMO_HOME/overlays/enterprise
mkdir -p $ENTERPRISE
```
```bash
# $ENTERPRISE/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
components:
- ../../components/external_db
- ../../components/ldap
```
Define a `dev` overlay, that points to all the components and has LDAP
disabled:
```shell
DEV=$DEMO_HOME/overlays/dev
mkdir -p $DEV
```
```bash
# $DEV/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
components:
- ../../components/external_db
#- ../../components/ldap
- ../../components/recaptcha
```
Now, the workspace has the following directories:
```shell
├── base
│ ├── deployment.yaml
│ └── kustomization.yaml
├── components
│ ├── external_db
│ │ ├── configmap.yaml
│ │ ├── dbpass.txt
│ │ ├── deployment.yaml
│ │ └── kustomization.yaml
│ ├── ldap
│ │ ├── configmap.yaml
│ │ ├── deployment.yaml
│ │ ├── kustomization.yaml
│ │ └── ldappass.txt
│ └── recaptcha
│ ├── deployment.yaml
│ ├── kustomization.yaml
│ ├── secret_key.txt
│ └── site_key.txt
└── overlays
├── community
│ └── kustomization.yaml
├── dev
│ └── kustomization.yaml
└── enterprise
└── kustomization.yaml
```
With this structure, you can generate the YAML manifests for each deployment
using `kustomize build`:
```shell
kustomize build overlays/community
kustomize build overlays/enterprise
kustomize build overlays/dev
```

View File

@@ -0,0 +1,359 @@
---
title: "configMapGenerator"
linkTitle: "configMapGenerator"
type: docs
weight: 6
description: >
Generate ConfigMap resources.
---
Each entry in this list results in the creation of
one ConfigMap resource (it's a generator of n maps).
The example below creates four ConfigMaps:
- first, with the names and contents of the given files
- second, with key/value as data using key/value pairs from files
- third, also with key/value as data, directly specified using `literals`
- and a fourth, which sets an annotation and label via `options` for that single ConfigMap
Each configMapGenerator item accepts a parameter of
`behavior: [create|replace|merge]`.
This allows an overlay to modify or
replace an existing configMap from the parent.
Also, each entry has an `options` field, that has the
same subfields as the kustomization file's `generatorOptions` field.
This `options` field allows one to add labels and/or
annotations to the generated instance, or to individually
disable the name suffix hash for that instance.
Labels and annotations added here will not be overwritten
by the global options associated with the kustomization
file `generatorOptions` field. However, due to how
booleans behave, if the global `generatorOptions` field
specifies `disableNameSuffixHash: true`, this will
trump any attempt to locally override it.
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# These labels are added to all configmaps and secrets.
generatorOptions:
labels:
fruit: apple
configMapGenerator:
- name: my-java-server-props
behavior: merge
files:
- application.properties
- more.properties
- name: my-java-server-env-file-vars
envs:
- my-server-env.properties
- more-server-props.env
- name: my-java-server-env-vars
literals:
- JAVA_HOME=/opt/java/jdk
- JAVA_TOOL_OPTIONS=-agentlib:hprof
options:
disableNameSuffixHash: true
labels:
pet: dog
- name: dashboards
files:
- mydashboard.json
options:
annotations:
dashboard: "1"
labels:
app.kubernetes.io/name: "app1"
```
It is also possible to
[define a key](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#define-the-key-to-use-when-creating-a-configmap-from-a-file)
to set a name different than the filename.
The example below creates a ConfigMap
with the name of file as `myFileName.ini`
while the _actual_ filename from which the
configmap is created is `whatever.ini`.
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
configMapGenerator:
- name: app-whatever
files:
- myFileName.ini=whatever.ini
```
## ConfigMap `from File`
ConfigMap Resources may be generated from files - such as a java `.properties` file. To generate a ConfigMap
Resource for a file, add an entry to `configMapGenerator` with the filename.
**Example:** Generate a ConfigMap with a data item containing the contents of a file.
The ConfigMaps will have data values populated from the file contents. The contents of each file will
appear as a single data item in the ConfigMap keyed by the filename.
The example illustrates how you can create ConfigMaps from File using Generators.
### File Input
```yaml
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
configMapGenerator:
- name: my-application-properties
files:
- application.properties
```
```yaml
# application.properties
FOO=Bar
```
### Build Output
```yaml
apiVersion: v1
data:
application.properties: |-
FOO=Bar
kind: ConfigMap
metadata:
name: my-application-properties-f7mm6mhf59
```
## ConfigMap `from Literals`
ConfigMap Resources may be generated from literal key-value pairs - such as `JAVA_HOME=/opt/java/jdk`.
To generate a ConfigMap Resource from literal key-value pairs, add an entry to `configMapGenerator` with a
list of `literals`.
{{< alert color="success" title="Literal Syntax" >}}
- The key/value are separated by a `=` sign (left side is the key)
- The value of each literal will appear as a data item in the ConfigMap keyed by its key.
{{< /alert >}}
**Example:** Create a ConfigMap with 2 data items generated from literals.
The example illustrates how you can create ConfigMaps from Literals using Generators.
### File Input
```yaml
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
configMapGenerator:
- name: my-java-server-env-vars
literals:
- JAVA_HOME=/opt/java/jdk
- JAVA_TOOL_OPTIONS=-agentlib:hprof
```
### Build Output
```yaml
apiVersion: v1
data:
JAVA_HOME: /opt/java/jdk
JAVA_TOOL_OPTIONS: -agentlib:hprof
kind: ConfigMap
metadata:
name: my-java-server-env-vars-44k658k8gk
```
## ConfigMap `from env file`
ConfigMap Resources may be generated from key-value pairs much the same as using the literals option
but taking the key-value pairs from an environment file. These generally end in `.env`.
To generate a ConfigMap Resource from an environment file, add an entry to `configMapGenerator` with a
single `envs` entry, e.g. `envs: [ 'config.env' ]`.
{{< alert color="success" title="Environment File Syntax" >}}
- The key/value pairs inside of the environment file are separated by a `=` sign (left side is the key)
- The value of each line will appear as a data item in the ConfigMap keyed by its key.
- Pairs may span a single line only.
{{< /alert >}}
**Example:** Create a ConfigMap with 3 data items generated from an environment file.
### File Input
```yaml
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
configMapGenerator:
- name: tracing-options
envs:
- tracing.env
```
```bash
# tracing.env
ENABLE_TRACING=true
SAMPLER_TYPE=probabilistic
SAMPLER_PARAMETERS=0.1
```
### Build Output
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
# The name has had a suffix applied
name: tracing-options-6bh8gkdf7k
# The data has been populated from each literal pair
data:
ENABLE_TRACING: "true"
SAMPLER_TYPE: "probabilistic"
SAMPLER_PARAMETERS: "0.1"
```
## Overriding Base ConfigMap Values
ConfigMap values from bases may be overridden by adding another generator for the ConfigMap
in the overlay and specifying the `behavior` field. `behavior` may be
one of:
* `create` (default value): used to create a new ConfigMap. A name conflict error will be thrown if a ConfigMap with the same name and namespace already exists.
* `replace`: replace an existing ConfigMap from the base.
* `merge`: add or update the values in an existing ConfigMap from the base.
When updating an existing ConfigMap with the `merge` or `replace` strategies, you must ensure that both the name and namespace match the ConfigMap you're targeting. For example, if the namespace is unspecified in the base, you should not specify it in the overlay. Conversely, if it is specified in the base, you must specify it in the overlay as well. This is true even if the overlay Kustomization includes a namespace, because configMapGenerator runs before the namespace transformer.
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: my-new-namespace
resources:
- ../base
configMapGenerator:
- name: existing-name
namespace: existing-ns # needs to match target ConfigMap from base
behavior: replace
literals:
- ENV=dev
```
{{< alert color="warning" title="Name suffixing with overlay configMapGenerator" >}}
When using configMapGenerator to override values of an existing ConfigMap, the overlay configMapGenerator does not cause suffixing of the existing ConfigMap's name to occur. To take advantage of name suffixing, use configMapGenerator in the base, and the overlay generator will correctly update the suffix based on the new content.
{{< /alert >}}
## Propagating the Name Suffix
Workloads that reference the ConfigMap or Secret will need to know the name of the generated Resource,
including the suffix. Kustomize takes care of this automatically by identifying
references to generated ConfigMaps and Secrets, and updating them.
In the following example, the generated ConfigMap name will be `my-java-server-env-vars` with a suffix unique to its contents.
Changes to the contents will change the name suffix, resulting in the creation of a new ConfigMap,
which Kustomize will transform Workloads to point to.
The PodTemplate volume references the ConfigMap by the name specified in the generator (excluding the suffix).
Kustomize will update the name to include the suffix applied to the ConfigMap name.
**Input:** The kustomization.yaml and deployment.yaml files
```yaml
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
configMapGenerator:
- name: my-java-server-env-vars
literals:
- JAVA_HOME=/opt/java/jdk
- JAVA_TOOL_OPTIONS=-agentlib:hprof
resources:
- deployment.yaml
```
```yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment
labels:
app: test
spec:
selector:
matchLabels:
app: test
template:
metadata:
labels:
app: test
spec:
containers:
- name: container
image: registry.k8s.io/busybox
command: [ "/bin/sh", "-c", "ls /etc/config/" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: my-java-server-env-vars
```
**Result:** The output of the Kustomize build.
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
# The name has been updated to include the suffix
name: my-java-server-env-vars-k44mhd6h5f
data:
JAVA_HOME: /opt/java/jdk
JAVA_TOOL_OPTIONS: -agentlib:hprof
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: test
name: test-deployment
spec:
selector:
matchLabels:
app: test
template:
metadata:
labels:
app: test
spec:
containers:
- command:
- /bin/sh
- -c
- ls /etc/config/
image: registry.k8s.io/busybox
name: container
volumeMounts:
- mountPath: /etc/config
name: config-volume
volumes:
- configMap:
# The name has been updated to include the
# suffix matching the ConfigMap
name: my-java-server-env-vars-k44mhd6h5f
name: config-volume
```

View File

@@ -0,0 +1,41 @@
---
title: "crds"
linkTitle: "crds"
type: docs
weight: 7
description: >
Adding CRD support
---
Each entry in this list should be a relative path to
a file for custom resource definition (CRD).
The presence of this field is to allow kustomize be
aware of CRDs and apply proper
transformation for any objects in those types.
Typical use case: A CRD object refers to a
ConfigMap object. In a kustomization, the ConfigMap
object name may change by adding namePrefix,
nameSuffix, or hashing. The name reference for this
ConfigMap object in CRD object need to be updated
with namePrefix, nameSuffix, or hashing in the
same way.
The annotations can be put into openAPI definitions are:
- "x-kubernetes-annotation": ""
- "x-kubernetes-label-selector": ""
- "x-kubernetes-identity": ""
- "x-kubernetes-object-ref-api-version": "v1",
- "x-kubernetes-object-ref-kind": "Secret",
- "x-kubernetes-object-ref-name-key": "name",
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
crds:
- crds/typeA.yaml
- crds/typeB.yaml
```

View File

@@ -0,0 +1,115 @@
---
title: "generatorOptions"
linkTitle: "generatorOptions"
type: docs
weight: 8
description: >
Control behavior of [ConfigMap](https://kubernetes.io/docs/concepts/configuration/configmap/) and
[Secret](https://kubernetes.io/docs/concepts/configuration/secret/) generators.
---
Additionally, generatorOptions can be set on a per resource level within each
generator. For details on per-resource generatorOptions usage see
[configMapGenerator](/docs/reference/api/kustomization-file/configmapgenerator/) and see [secretGenerator](/docs/reference/api/kustomization-file/secretgenerator/).
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
generatorOptions:
# labels to add to all generated resources
labels:
kustomize.generated.resources: somevalue
# annotations to add to all generated resources
annotations:
kustomize.generated.resource: somevalue
# disableNameSuffixHash is true disables the default behavior of adding a
# suffix to the names of generated resources that is a hash of
# the resource contents.
disableNameSuffixHash: true
# if set to true, the immutable property is added to generated resources
immutable: true
```
## Example I
Using ConfigMap
### Input Files
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
configMapGenerator:
- name: my-application-properties
files:
- application.properties
generatorOptions:
labels:
kustomize.generated.resources: config-label
annotations:
kustomize.generated.resource: config-annotation
```
```yaml
# application.properties
FOO=Bar
```
### Output File
```yaml
apiVersion: v1
data:
application.properties: |-
# application.properties
FOO=Bar
kind: ConfigMap
metadata:
annotations:
kustomize.generated.resource: config-annotation
labels:
kustomize.generated.resources: config-label
name: my-application-properties-f7mm6mhf59
```
## Example II
Using Secrets
### Input Files
```yaml
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
secretGenerator:
- name: app-tls
files:
- "tls.cert"
- "tls.key"
type: "kubernetes.io/tls"
generatorOptions:
labels:
kustomize.generated.resources: secret-label
annotations:
kustomize.generated.resource: secret-annotation
disableNameSuffixHash: true
```
### Output File
```yaml
apiVersion: v1
data:
tls.cert: TFMwdExTMUNSVWQuLi50Q2c9PQ==
tls.key: TFMwdExTMUNSVWQuLi4wdExRbz0=
kind: Secret
metadata:
annotations:
kustomize.generated.resource: secret-annotation
labels:
kustomize.generated.resources: secret-label
name: app-tls
type: kubernetes.io/tls
```

View File

@@ -0,0 +1,46 @@
---
title: "helmCharts"
linkTitle: "helmCharts"
type: docs
weight: 8
description: >
Helm chart inflation generator.
---
[kustomize builtins]: https://kubectl.docs.kubernetes.io/references/kustomize/builtins/#_helmchartinflationgenerator_
[Helm support long term plan]: https://github.com/kubernetes-sigs/kustomize/issues/4401
## Helm Chart Inflation Generator
Kustomize has limited support for helm chart inflation through the `helmCharts` field.
You can read a detailed description of this field in the docs about [kustomize builtins].
To enable the helm chart inflation generator, you have to specify the `enable-helm` flag as follows:
```sh
kustomize build --enable-helm
```
## Long term support
The helm chart inflation generator in kustomize is intended to be a limited subset of helm features to help with
getting started with kustomize, and we cannot support the entire helm feature set.
### The current builtin
For enhancements to the helm chart inflation generator feature, we will only support the following changes:
- bug fixes
- critical security issues
- additional fields that are analogous to flags passed to `helm template`, except for flags such as `post-renderer`
that allow arbitrary commands to be executed
We will not add support for:
- private repository or registry authentication
- OCI registries
- other large features that increase the complexity of the feature and/or have significant security implications
### Future support
The next iteration of the helm inflation generator will take the form of a KRM function, which will have
no such restrictions on what types of features we can add and support. You can see more details in
the [Helm support long term plan].

View File

@@ -0,0 +1,169 @@
---
title: "images"
linkTitle: "images"
type: docs
weight: 9
description: >
Modify the name, tags and/or digest for images.
---
Images modify the name, tags and/or digest for images without creating patches.
One can change the `image` in the following ways (Refer the following example to know exactly how this is done):
- `postgres:8` to `my-registry/my-postgres:v1`,
- nginx tag `1.7.9` to `1.8.0`,
- image name `my-demo-app` to `my-app`,
- alpine's tag `3.7` to a digest value
It is possible to set image tags for container images through
the `kustomization.yaml` using the `images` field. When `images` are
specified, Apply will override the images whose image name matches `name` with a new
tag.
| Field | Description | Example Field | Example Result |
|-----------|--------------------------------------------------------------------------|----------| --- |
| `name` | Match images with this image name| `name: nginx`| |
| `newTag` | Override the image **tag** or **digest** for images whose image name matches `name` | `newTag: new` | `nginx:old` -> `nginx:new` |
| `newName` | Override the image **name** for images whose image name matches `name` | `newName: nginx-special` | `nginx:old` -> `nginx-special:old` |
## Example
### File Input
```yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: the-deployment
spec:
template:
spec:
containers:
- name: mypostgresdb
image: postgres:8
- name: nginxapp
image: nginx:1.7.9
- name: myapp
image: my-demo-app:latest
- name: alpine-app
image: alpine:3.7
```
```yaml
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
images:
- name: postgres
newName: my-registry/my-postgres
newTag: v1
- name: nginx
newTag: 1.8.0
- name: my-demo-app
newName: my-app
- name: alpine
digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3
resources:
- deployment.yaml
```
### Build Output
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: the-deployment
spec:
template:
spec:
containers:
- image: my-registry/my-postgres:v1
name: mypostgresdb
- image: nginx:1.8.0
name: nginxapp
- image: my-app:latest
name: myapp
- image: alpine@sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3
name: alpine-app
```
## Setting a Name
The name for an image may be set by specifying `newName` and the name of the old container image.
```yaml
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
images:
- name: mycontainerregistry/myimage
newName: differentregistry/myimage
```
## Setting a Tag
The tag for an image may be set by specifying `newTag` and the name of the container image.
```yaml
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
images:
- name: mycontainerregistry/myimage
newTag: v1
```
## Setting a Digest
The digest for an image may be set by specifying `digest` and the name of the container image.
```yaml
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
images:
- name: alpine
digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3
```
## Setting a Tag from the latest commit SHA
A common CI/CD pattern is to tag container images with the git commit SHA of source code. e.g. if
the image name is `foo` and an image was built for the source code at commit `1bb359ccce344ca5d263cd257958ea035c978fd3`
then the container image would be `foo:1bb359ccce344ca5d263cd257958ea035c978fd3`.
A simple way to push an image that was just built without manually updating the image tags is to
[download the kustomize standalone](/docs/getting-started/installation/) tool and run
`kustomize edit set image` command to update the tags for you.
**Example:** Set the latest git commit SHA as the image tag for `foo` images.
```bash
kustomize edit set image foo:$(git log -n 1 --pretty=format:"%H")
kubectl apply -f .
```
## Setting a Tag from an Environment Variable
It is also possible to set a Tag from an environment variable using the same technique for setting from a commit SHA.
**Example:** Set the tag for the `foo` image to the value in the environment variable `FOO_IMAGE_TAG`.
```bash
kustomize edit set image foo:$FOO_IMAGE_TAG
kubectl apply -f .
```
{{< alert color="success" title="Committing Image Tag Updates" >}}
The `kustomization.yaml` changes *may* be committed back to git so that they
can be audited. When committing the image tag updates that have already
been pushed by a CI/CD system, be careful not to trigger new builds +
deployments for these changes.
{{< /alert >}}

View File

@@ -0,0 +1,237 @@
---
title: "labels"
linkTitle: "labels"
type: docs
weight: 10
description: >
Add labels and optionally selectors to all resources.
---
A field that allows adding labels without also automatically injecting corresponding selectors.
This can be used instead of the `commonLabels` field, which always adds selectors.
{{% pageinfo color="warning" %}}
Selectors for resources such as Deployments and Services shouldn't be changed once the
resource has been applied to a cluster.
Changing `includeSelectors` to `true` or changing labels when `includeSelectors` is `true` in live resources
is equivalent to changing `commonLabels` and could result in failures.
{{% /pageinfo %}}
The following flags are available:
* `includeTemplates`: When set will also apply labels to metadata/labels and spec/template/metadata/labels. This can be used to add labels to Pods from owner resources, such as Deployments and StatefulSets, without modifying selectors. False by default.
* `includeSelectors`: When set will apply labels to metadata/labels, selectors, and spec/template/metadata/labels. False by default.
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
labels:
- pairs:
someName: someValue
owner: alice
app: bingo
includeSelectors: true # <-- false by default
includeTemplates: true # <-- false by default
```
## Example 1 - selectors and templates NOT modified
### File Input
```yaml
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
labels:
- pairs:
someName: someValue
owner: alice
app: bingo
resources:
- deploy.yaml
- service.yaml
```
```yaml
# deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: example
```
```yaml
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: example
```
### Build Output
```yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: bingo
owner: alice
someName: someValue
name: example
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: bingo
owner: alice
someName: someValue
name: example
```
## Example 2 - selectors modified
### File Input
```yaml
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
labels:
- pairs:
someName: someValue
owner: alice
app: bingo
includeSelectors: true
resources:
- deploy.yaml
- service.yaml
```
```yaml
# deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: example
```
```yaml
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: example
```
### Build Output
```yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: bingo
owner: alice
someName: someValue
name: example
spec:
selector:
app: bingo
owner: alice
someName: someValue
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: bingo
owner: alice
someName: someValue
name: example
spec:
selector:
matchLabels:
app: bingo
owner: alice
someName: someValue
template:
metadata:
labels:
app: bingo
owner: alice
someName: someValue
```
## Example 3 - templates modified
### File Input
```yaml
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
labels:
- pairs:
someName: someValue
owner: alice
app: bingo
includeTemplates: true
resources:
- deploy.yaml
- service.yaml
```
```yaml
# deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: example
```
```yaml
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: example
```
### Build Output
```yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: bingo
owner: alice
someName: someValue
name: example
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: bingo
owner: alice
someName: someValue
name: example
spec:
template:
metadata:
labels:
app: bingo
owner: alice
someName: someValue
```

View File

@@ -0,0 +1,64 @@
---
title: "namePrefix"
linkTitle: "namePrefix"
type: docs
weight: 11
description: >
Prepends the value to the names of all resources and references.
---
As `namePrefix` is self explanatory, it helps adding prefix to names in the defined yaml files.
## Example
### File Input
```yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: the-deployment
spec:
replicas: 5
template:
containers:
- name: the-container
image: registry/container:latest
```
```yaml
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namePrefix: custom-prefix-
resources:
- deployment.yaml
```
### Build Output
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: custom-prefix-the-deployment
spec:
replicas: 5
template:
containers:
- image: registry/container:latest
name: the-container
```
{{< alert color="success" title="References" >}}
Apply will propagate the `namePrefix` to any place Resources within the project are referenced by other Resources
including:
- Service references from StatefulSets
- ConfigMap references from PodSpecs
- Secret references from PodSpecs
{{< /alert >}}

View File

@@ -0,0 +1,57 @@
---
title: "nameSuffix"
linkTitle: "nameSuffix"
type: docs
weight: 13
description: >
Appends the value to the names of all resources and references.
---
As `nameSuffix` is self explanatory, it helps adding suffix to names in the defined yaml files.
**Note:** The suffix is appended before the content hash if the resource type is ConfigMap or Secret.
## Example
### File Input
```yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: the-deployment
spec:
replicas: 5
template:
containers:
- name: the-container
image: registry/container:latest
```
```yaml
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
nameSuffix: -custom-suffix
resources:
- deployment.yaml
```
### Build Output
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: the-deployment-custom-suffix
spec:
replicas: 5
template:
containers:
- image: registry/container:latest
name: the-container
```

View File

@@ -0,0 +1,58 @@
---
title: "namespace"
linkTitle: "namespace"
type: docs
weight: 12
description: >
Adds namespace to all resources.
---
Will override the existing namespace if it is set on a resource, or add it
if it is not set on a resource.
## Example
### File Input
```yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: the-deployment
namespace: the-namespace
spec:
replicas: 5
template:
containers:
- name: the-container
image: registry/container:latest
```
```yaml
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: kustomize-namespace
resources:
- deployment.yaml
```
### Build Output
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: the-deployment
namespace: kustomize-namespace
spec:
replicas: 5
template:
containers:
- image: registry/container:latest
name: the-container
```

View File

@@ -0,0 +1,217 @@
---
title: "openapi"
linkTitle: "openapi"
type: docs
weight: 14
description: >
Specify where kustomize gets its OpenAPI schema.
---
Kustomize uses kubernetes OpenAPI data to get merge key and patch strategy
information about resource types. Kustomize has an OpenAPI schema builtin,
but this schema only has information about builtin kubernetes types. If
you need to provide merge key and patch strategy information about custom
resource types, you will have to provide your own OpenAPI schema to do so.
In your kustomization file, you can specify where kustomize should get
its OpenAPI schema via an `openapi` field. For example:
```yaml
resources:
- my_resource.yaml
openapi:
path: my_schema.json
```
The `openapi` field of a kustomization file can either a path to a custom schema
file, as in the example above. It can also be used to explicitly tell kustomize to
use a builtin kubernetes OpenAPI schema:
```yaml
resources:
- my_resource.yaml
openapi:
version: v1.20.4
```
You can see what builtin kubernetes OpenAPI schemas are available with the command
`kustomize openapi info`.
Here is an example of a custom resource we might want to edit with a custom OpenAPI schema
file. It looks like this:
```yaml
apiVersion: example.com/v1alpha1
kind: MyResource
metadata:
name: service
spec:
template:
spec:
containers:
- name: server
image: server
command: example
ports:
- name: grpc
protocol: TCP
containerPort: 8080
```
This resource has an image field. Let's change its value from `server`
to `nginx` with a patch. You can get an OpenAPI document like this from
your locally favored cluster with the command `kustomize openapi fetch`.
Kustomize will use the OpenAPI extensions `x-kubernetes-patch-merge-key` and
`x-kubernetes-patch-strategy` to perform a strategic merge.
`x-kubernetes-patch-strategy` should be set to "merge", and you can set your
merge key to whatever you like.
Below, our custom resource inherits merge keys from PodTemplateSpec. In the
definition of "io.k8s.api.core.v1.Container", the `ports` field has its merge
key set to "containerPort":
```json
{
"definitions": {
"v1alpha1.MyResource": {
"properties": {
"apiVersion": {
"type": "string"
},
"kind": {
"type": "string"
},
"metadata": {
"type": "object"
},
"spec": {
"properties": {
"template": {
"\$ref": "#/definitions/io.k8s.api.core.v1.PodTemplateSpec"
}
},
"type": "object"
},
"status": {
"properties": {
"success": {
"type": "boolean"
}
},
"type": "object"
}
},
"type": "object",
"x-kubernetes-group-version-kind": [
{
"group": "example.com",
"kind": "MyResource",
"version": "v1alpha1"
}
]
},
"io.k8s.api.core.v1.PodTemplateSpec": {
"properties": {
"metadata": {
"\$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta"
},
"spec": {
"\$ref": "#/definitions/io.k8s.api.core.v1.PodSpec"
}
},
"type": "object"
},
"io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta": {
"properties": {
"name": {
"type": "string"
}
},
"type": "object"
},
"io.k8s.api.core.v1.PodSpec": {
"properties": {
"containers": {
"items": {
"\$ref": "#/definitions/io.k8s.api.core.v1.Container"
},
"type": "array",
"x-kubernetes-patch-merge-key": "name",
"x-kubernetes-patch-strategy": "merge"
}
},
"type": "object"
},
"io.k8s.api.core.v1.Container": {
"properties": {
"command": {
"items": {
"type": "string"
},
"type": "array"
},
"image": {
"type": "string"
},
"name": {
"type": "string"
},
"ports": {
"items": {
"\$ref": "#/definitions/io.k8s.api.core.v1.ContainerPort"
},
"type": "array",
"x-kubernetes-list-map-keys": [
"containerPort",
"protocol"
],
"x-kubernetes-list-type": "map",
"x-kubernetes-patch-merge-key": "containerPort",
"x-kubernetes-patch-strategy": "merge"
}
},
"type": "object"
},
"io.k8s.api.core.v1.ContainerPort": {
"properties": {
"containerPort": {
"format": "int32",
"type": "integer"
},
"name": {
"type": "string"
},
"protocol": {
"type": "string"
}
},
"type": "object"
}
}
}
```
Then, our kustomization file to do the patch can be as follows:
```yaml
resources:
- my_resource.yaml
openapi:
path: my_schema.json
patchesStrategicMerge:
- |-
apiVersion: example.com/v1alpha1
kind: MyResource
metadata:
name: service
spec:
template:
spec:
containers:
- name: server
image: nginx
```

View File

@@ -0,0 +1,280 @@
---
title: "patches"
linkTitle: "patches"
type: docs
weight: 15
description: >
Patch resources
---
[strategic merge]: /docs/reference/api/kustomization-file/patchesstrategicmerge/
[JSON6902]: /docs/reference/api/kustomization-file/patchesjson6902/
Patches (also called overlays) add or override fields on resources. They are provided using the
`patches` Kustomization field.
The `patches` field contains a list of patches to be applied in the order they are specified.
Each patch may:
- be either a [strategic merge] patch, or a [JSON6902] patch
- be either a file, or an inline string
- target a single resource or multiple resources
The patch target selects resources by `group`, `version`, `kind`, `name`, `namespace`, `labelSelector` and
`annotationSelector`. Any resource which matches all the **specified** fields has the patch applied
to it (regular expressions).
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patches:
- path: patch.yaml
target:
group: apps
version: v1
kind: Deployment
name: deploy.*
labelSelector: "env=dev"
annotationSelector: "zone=west"
- patch: |-
- op: replace
path: /some/existing/path
value: new value
target:
kind: MyKind
labelSelector: "env=dev"
```
The `name` and `namespace` fields of the patch target selector are
automatically anchored regular expressions. This means that the value `myapp`
is equivalent to `^myapp$`.
## Name and kind changes
With `patches` it is possible to override the kind or name of the resource it is
editing with the options `allowNameChange` and `allowKindChange`. For example:
```yaml
resources:
- deployment.yaml
patches:
- path: patch.yaml
target:
kind: Deployment
options:
allowNameChange: true
allowKindChange: true
```
By default, these fields are false and the patch will leave the kind and name of the resource untouched.
## Name references
A patch can refer to a resource by any of its previous names or kinds.
For example, if a resource has gone through name-prefix transformations, it can refer to the
resource by its current name, original name, or any intermediate name that it had.
## Patching custom resources
[Strategic merge] patches may require additional configuration via [openapi](../openapi) field to work as expected with custom resources. For example, if a resource uses a merge key other than `name` or needs a list to be merged rather than replaced, Kustomize needs openapi information informing it about this.
[JSON6902] patch usage is the same for built-in and custom resources.
## Examples
Consider the following `deployment.yaml` common for all examples:
```yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: dummy-app
labels:
app.kubernetes.io/name: nginx
spec:
selector:
matchLabels:
app.kubernetes.io/name: nginx
template:
metadata:
labels:
app.kubernetes.io/name: nginx
spec:
containers:
- name: nginx
image: nginx:stable
ports:
- name: http
containerPort: 80
```
### Intents
- Make the container image point to a specific version and not to the latest container in the registry.
- Adding a standard label containing the deployed version.
There are multiple possible strategies that all achieve the same results.
### Patch using Inline Strategic Merge
```yaml
# kustomization.yaml
resources:
- deployment.yaml
patches:
- patch: |-
apiVersion: apps/v1
kind: Deployment
metadata:
name: dummy-app
labels:
app.kubernetes.io/version: 1.21.0
- patch: |-
apiVersion: apps/v1
kind: Deployment
metadata:
name: not-used
spec:
template:
spec:
containers:
- name: nginx
image: nginx:1.21.0
target:
labelSelector: "app.kubernetes.io/name=nginx"
```
If a `target` is specified, the `name` contained in the metadata is required but not used.
### Patch using Inline JSON6902
```yaml
# kustomization.yaml
resources:
- deployment.yaml
patches:
- patch: |-
- op: add
path: /metadata/labels/app.kubernetes.io~1version
value: 1.21.0
target:
group: apps
version: v1
kind: Deployment
- patch: |-
- op: replace
path: /spec/template/spec/containers/0/image
value: nginx:1.21.0
target:
labelSelector: "app.kubernetes.io/name=nginx"
```
The `target` field is always required for JSON6902 patches.
A special replacement character `~1` is used to replace `/` in label name.
### Patch using Path Strategic Merge
```yaml
# kustomization.yaml
resources:
- deployment.yaml
patches:
- path: add-label.patch.yaml
- path: fix-version.patch.yaml
target:
labelSelector: "app.kubernetes.io/name=nginx"
```
As with the Inline Strategic Merge, the `target` field can be omitted.
In that case, the target resource is matched using
the `apiVersion`, `kind` and `name` from the patch.
```yaml
# add-label.patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: dummy-app
labels:
app.kubernetes.io/version: 1.21.0
```
```yaml
# fix-version.patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: not-used
spec:
template:
spec:
containers:
- name: nginx
image: nginx:1.21.0
```
As with the Inline Strategic Merge, the `name` field in the patch is not used when a `target` is specified.
### Patch using Path JSON6902
```yaml
# kustomization.yaml
resources:
- deployment.yaml
patches:
- path: add-label.patch.json
target:
group: apps
version: v1
kind: Deployment
- path: fix-version.patch.yaml
target:
labelSelector: "app.kubernetes.io/name=nginx"
```
As with Inline JSON6902, the `target` field is mandatory.
```yaml
# add-label.patch.json
[
{"op": "add", "path": "/metadata/labels/app.kubernetes.io~1version", "value": "1.21.0"}
]
```
```yaml
# fix-version.patch.yaml
- op: replace
path: /spec/template/spec/containers/0/image
value: nginx:1.21.0
```
External patch file can be written both as YAML or JSON.
The content must follow the JSON6902 standard.
### Build Output
All four patches strategies lead to the exact same output:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/name: nginx
app.kubernetes.io/version: 1.21.0
name: dummy-app
spec:
selector:
matchLabels:
app.kubernetes.io/name: nginx
template:
metadata:
labels:
app.kubernetes.io/name: nginx
spec:
containers:
- image: nginx:1.21.0
name: nginx
ports:
- containerPort: 80
name: http
```

View File

@@ -0,0 +1,80 @@
---
title: "patchesStrategicMerge"
linkTitle: "patchesStrategicMerge"
type: docs
weight: 17
description: >
Patch resources using the strategic merge patch standard.
---
{{% pageinfo color="warning" %}}
The `patchesStrategicMerge` field was deprecated in v5.0.0. This field will never be removed from the
kustomize.config.k8s.io/v1beta1 Kustomization API, but it will not be included
in the kustomize.config.k8s.io/v1 Kustomization API. When Kustomization v1 is available,
we will announce the deprecation of the v1beta1 version. There will be at least
two releases between deprecation and removal of Kustomization v1beta1 support from the
kustomize CLI, and removal itself will happen in a future major version bump.
Please move your `patchesStrategicMerge` into
the [patches](/docs/reference/api/kustomization-file/patches) field. This field supports patchesStrategicMerge,
but with slightly different syntax. You can run `kustomize edit fix` to automatically convert
`patchesStrategicMerge` to `patches`.
{{% /pageinfo %}}
Each entry in this list should be either a relative
file path or an inline content
resolving to a partial or complete resource
definition.
The names in these (possibly partial) resource
files must match names already loaded via the
`resources` field. These entries are used to
_patch_ (modify) the known resources.
Small patches that do one thing are best, e.g. modify
a memory request/limit, change an env var in a
ConfigMap, etc. Small patches are easy to review and
easy to mix together in overlays.
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patchesStrategicMerge:
- service_port_8888.yaml
- deployment_increase_replicas.yaml
- deployment_increase_memory.yaml
```
The patch content can be a inline string as well.
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patchesStrategicMerge:
- |-
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
image: nignx:latest
```
Note that kustomize does not support more than one patch
for the same object that contain a _delete_ directive. To remove
several fields / slice elements from an object create a single
patch that performs all the needed deletions.
A patch can refer to a resource by any of its previous names or kinds.
For example, if a resource has gone through name-prefix transformations, it can refer to the
resource by its current name, original name, or any intermediate name that it had.
## Patching custom resources
Strategic merge patches may require additional configuration via [openapi](../openapi) field to work as expected with custom resources. For example, if a resource uses a merge key other than `name` or needs a list to be merged rather than replaced, Kustomize needs openapi information informing it about this.

View File

@@ -0,0 +1,111 @@
---
title: "patchesJson6902"
linkTitle: "patchesJson6902"
type: docs
weight: 16
description: >
Patch resources using the [json 6902 standard](https://tools.ietf.org/html/rfc6902)
---
{{% pageinfo color="warning" %}}
The `patchesJson6902` field was deprecated in v5.0.0. This field will never be removed from the
kustomize.config.k8s.io/v1beta1 Kustomization API, but it will not be included
in the kustomize.config.k8s.io/v1 Kustomization API. When Kustomization v1 is available,
we will announce the deprecation of the v1beta1 version. There will be at least
two releases between deprecation and removal of Kustomization v1beta1 support from the
kustomize CLI, and removal itself will happen in a future major version bump.
Please move your `patchesJson6902` into
the [patches](/docs/reference/api/kustomization-file/patches) field. This field supports patchesJson6902,
but with slightly different syntax. You can run `kustomize edit fix` to automatically convert
`patchesJson6902` to `patches`.
{{% /pageinfo %}}
Each entry in this list should resolve to a kubernetes object and a JSON patch that will be applied
to the object.
The JSON patch is documented at <https://tools.ietf.org/html/rfc6902>
target field points to a kubernetes object within the same kustomization
by the object's group, version, kind, name and namespace.
path field is a relative file path of a JSON patch file.
The content in this patch file can be either in JSON format as
```json
[
{"op": "add", "path": "/some/new/path", "value": "value"},
{"op": "replace", "path": "/some/existing/path", "value": "new value"},
{"op": "copy", "from": "/some/existing/path", "path": "/some/path"},
{"op": "move", "from": "/some/existing/path", "path": "/some/existing/destination/path"},
{"op": "remove", "path": "/some/existing/path"},
{"op": "test", "path": "/some/path", "value": "my-node-value"}
]
```
or in YAML format as
```yaml
# add: creates a new entry with a given value
- op: add
path: /some/new/path
value: value
# replace: replaces the value of the node with the new specified value
- op: replace
path: /some/existing/path
value: new value
# copy: copies the value specified in from to the destination path
- op: copy
from: /some/existing/path
path: /some/path
# move: moves the node specified in from to the destination path
- op: move
from: /some/existing/path
path: /some/existing/destination/path
# remove: delete's the node('s subtree)
- op: remove
path: /some/path
# test: check if the specified node has the specified value, if the value differs it will throw an error
- op: test
path: /some/path
value: "my-node-value"
```
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patchesJson6902:
- target:
version: v1
kind: Deployment
name: my-deployment
path: add_init_container.yaml
- target:
version: v1
kind: Service
name: my-service
path: add_service_annotation.yaml
```
The patch content can be an inline string as well:
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patchesJson6902:
- target:
version: v1
kind: Deployment
name: my-deployment
patch: |-
- op: add
path: /some/new/path
value: value
- op: replace
path: /some/existing/path
value: "new value"
```
A patch can refer to a resource by any of its previous names or kinds.
For example, if a resource has gone through name-prefix transformations, it can refer to the
resource by its current name, original name, or any intermediate name that it had.

View File

@@ -0,0 +1,387 @@
---
title: "replacements"
linkTitle: "replacements"
type: docs
weight: 18
description: >
Substitute field(s) in N target(s) with a field from a source.
---
Replacements are used to copy fields from one source into any
number of specified targets.
\
The `replacements` field can support a path to a replacement:
`kustomization.yaml`
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
replacements:
- path: replacement.yaml
```
`replacement.yaml`
```yaml
source:
kind: Deployment
fieldPath: metadata.name
targets:
- select:
name: my-resource
```
\
Alternatively, `replacements` supports inline replacements:
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
replacements:
- source:
kind: Deployment
fieldPath: metadata.name
targets:
- select:
name: my-resource
```
### Syntax
The full schema of `replacements` is as follows:
```yaml
replacements:
- source:
group: string
version: string
kind: string
name: string
namespace: string
fieldPath: string
options:
delimiter: string
index: int
create: bool
targets:
- select:
group: string
version: string
kind: string
name: string
namespace: string
reject:
- group: string
version: string
kind: string
name: string
namespace: string
fieldPaths:
- string
options:
delimiter: string
index: int
create: bool
```
### Field Descriptions
| Field | Required| Description | Default |
| -----------: | :----: | ----------- | ---- |
| `source`| ✔️ | The source of the value |
| `target`| ✔️ | The N fields to write the value to |
| `group` | | The group of the referent |
| `version`| | The version of the referent
|`kind` | | The kind of the referent
|`name` | | The name of the referent
|`namespace`| | The namespace of the referent
|`select` | ✔️ |Include objects that match this
|`reject`| |Exclude objects that match this
|`fieldPath`| | The structured path to the source value | `metadata.name`
|`fieldPaths`| | The structured path(s) to the target nodes | `metadata.name`
|`options`| | Options used to refine interpretation of the field
|`delimiter`| | Used to split/join the field
|`index`| | Which position in the split to consider | `0`
|`create`| | If target field is missing, add it | `false`
#### Source
The source field is a selector that determines the source of the value by finding a
match to the specified GVKNN. All the subfields of `source` are optional,
but the source selection must resolve to a single resource.
#### Targets
Replacements will be applied to all targets that are matched by the `select` field and
are NOT matched by the `reject` field, and will be applied to all listed `fieldPaths`.
##### Select
You can use any of the following fields to select the targets to replace:
`group`, `version`, `kind`, `name`, `namespace`
For example, the following will select all the Deployments as targets of replacement.
```yaml
select:
kind: Deployment
```
Also, you can use multiple fields together to select only the resources that match all the conditions.
For example, the following will select only the Deployments that are named my-deploy:
```yaml
select:
- kind: Deployment
name: my-deploy
```
Moreover, when the selected target is going to be transformed during the kustomization process,
you can use either the original or the transformed resource id to select it.
For example, the name of the target could be changed because of the `namePrefix` field, as below:
```yaml
namePrefix: my-
```
In this case, below will be enough if we wanted to select all the targets that were originally named deploy:
```yaml
select:
- name: deploy
```
Alternatively, using the transformed name with the prefix will produce the same behaviour.
So the following case will select all the resources that *will be* named my-deploy,
along with all the resources that *were* originally named my-deploy.
```yaml
select:
- name: my-deploy
```
##### Reject
The reject field is a selector that drops targets selected by select, overruling their selection.
For example, if we wanted to reject all Deployments named my-deploy:
```yaml
reject:
- kind: Deployment
name: my-deploy
```
This is distinct from the following:
```yaml
reject:
- kind: Deployment
- name: my-deploy
```
The first case would only reject resources that are both of kind Deployment and named my-deploy. The second case would reject all Deployments, and all resources named my-deploy.
We can also reject more than one kind, name, etc. For example:
```yaml
reject:
- kind: Deployment
- kind: StatefulSet
```
Moreover, when the selected target is going to be transformed during the kustomization process,
you can use either the original or the transformed resource id to reject it.
For example, the name of the target could be changed because of the `nameSuffix` field, as below:
```yaml
nameSuffix: -dev
```
You can use the original target name to prevent it from going through any replacement.
```yaml
reject:
- name: my-deploy
```
Alternatively, using the transformed name with the suffix will produce the same behaviour.
```yaml
reject:
- name: my-deploy-dev
```
#### Delimiter
This field is intended to be used in conjunction with the `index` field for partial string replacement.
For example, say we have a value:
`path: my/path/VALUE`
In our replacement target, we can specify something like:
```yaml
options:
delimiter: '/'
index: 2
```
and it would replace VALUE, e.g. `path: my/path/NEW_VALUE`.
#### Index
This field is intended to be used in conjunction with the `delimiter` field described above for partial string
replacement. The default value is 0.
If the index is out of bounds, behavior depends on whether it is in a source or target. In a source, an index out of bounds
will throw an error. For a target, a value less than 0 will cause the target to be prefixed, and a value beyond
the length of the split will cause the target to be suffixed.
If the fields `index` and `delimiter` are specified on sources or targets that are not scalar values (e.g. mapping or list values),
kustomize will throw an error.
#### Field Path format
The fieldPath and fieldPaths fields support a format of a '.'-separated path to a value. For example, the default:
`metadata.name`
You can escape the '.' one of two ways. For example, say we have the following resource:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
config.kubernetes.io/local-config: true # this is what we want to target
```
We can express our path:
1. With a '\\': `metadata.annotations.config\.kubernetes\.io/local-config`
2. With '[]': `metadata.annotations.[config.kubernetes.io/local-config]`
Strings are used for mapping nodes. For sequence nodes, we support three options:
1. Index by number: `spec.template.spec.containers.1.image`
2. Index by key-value pair: `spec.template.spec.containers.[name=nginx].image`. If the key-value pair matches multiple elements in the sequence node, all matching elements will be targetted.
3. Index with a wildcard match: `spec.template.spec.containers.*.env.[name=TARGET_ENV].value`. This will target every element in the list.
### Example
For example, suppose one specifies the name of a k8s Secret object in a container's
environment variable as follows:
`job.yaml`
```yaml
apiVersion: batch/v1
kind: Job
metadata:
name: hello
spec:
template:
spec:
containers:
- image: myimage
name: hello
env:
- name: SECRET_TOKEN
value: SOME_SECRET_NAME
```
Suppose you have the following resources:
`resources.yaml`
```yaml
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- image: busybox
name: myapp-container
restartPolicy: OnFailure
---
apiVersion: v1
kind: Secret
metadata:
name: my-secret
```
To (1) replace the value of SOME_SECRET_NAME with the name of my-secret, and (2) to add
a restartPolicy copied from my-pod, you can do the following:
`kustomization.yaml`
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- resources.yaml
- job.yaml
replacements:
- path: my-replacement.yaml
- source:
kind: Secret
name: my-secret
targets:
- select:
name: hello
kind: Job
fieldPaths:
- spec.template.spec.containers.[name=hello].env.[name=SECRET_TOKEN].value
```
`my-replacement.yaml`
```yaml
source:
kind: Pod
name: my-pod
fieldPath: spec.restartPolicy
targets:
- select:
name: hello
kind: Job
fieldPaths:
- spec.template.spec.restartPolicy
options:
create: true
```
The output of `kustomize build` will be:
```yaml
apiVersion: v1
kind: Secret
metadata:
name: my-secret
---
apiVersion: batch/v1
kind: Job
metadata:
name: hello
spec:
template:
spec:
containers:
- env:
- name: SECRET_TOKEN
value: my-secret # this value is copied from my-secret
image: myimage
name: hello
restartPolicy: OnFailure # this value is copied from my-pod
---
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- image: busybox
name: myapp-container
restartPolicy: OnFailure
```

View File

@@ -0,0 +1,90 @@
---
title: "replicas"
linkTitle: "replicas"
type: docs
weight: 19
description: >
Change the number of replicas for a resource.
---
Given this kubernetes Deployment fragment:
```yaml
kind: Deployment
metadata:
name: deployment-name
spec:
replicas: 3
```
one can change the number of replicas to 5
by adding the following to your kustomization:
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
replicas:
- name: deployment-name
count: 5
```
This field accepts a list, so many resources can
be modified at the same time.
As this declaration does not take in a `kind:` nor a `group:`
it will match any `group` and `kind` that has a matching name and
that is one of:
- `Deployment`
- `ReplicationController`
- `ReplicaSet`
- `StatefulSet`
For more complex use cases, revert to using a patch.
## Example
### Input File
```yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: the-deployment
spec:
replicas: 5
template:
containers:
- name: the-container
image: registry/container:latest
```
```yaml
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
replicas:
- name: the-deployment
count: 10
resources:
- deployment.yaml
```
### Output
```yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: the-deployment
spec:
replicas: 10
template:
containers:
- name: the-container
image: registry/container:latest
```

View File

@@ -0,0 +1,35 @@
---
title: "resources"
linkTitle: "resources"
type: docs
weight: 20
description: >
Resources to include.
---
Each entry in this list must be a path to a _file_, or a path (or URL) referring to another
kustomization _directory_, e.g.
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- myNamespace.yaml
- sub-dir/some-deployment.yaml
- ../../commonbase
- github.com/kubernetes-sigs/kustomize/examples/multibases?ref=v1.0.6
- deployment.yaml
- github.com/kubernets-sigs/kustomize/examples/helloWorld?ref=test-branch
```
Resources will be read and processed in depth-first order.
Files should contain k8s resources in YAML form. A file may contain multiple resources separated by
the document marker `---`. File paths should be specified _relative_ to the directory holding the
kustomization file containing the `resources` field.
Directory specification can be relative, absolute, or part of a URL. URL specifications should
follow the [hashicorp URL] format. The directory must contain a `kustomization.yaml` file.
[hashicorp URL]: https://github.com/hashicorp/go-getter#url-format

View File

@@ -0,0 +1,95 @@
---
title: "secretGenerator"
linkTitle: "secretGenerator"
type: docs
weight: 21
description: >
Generate Secret resources.
---
Each entry in the argument list results in the creation of one Secret resource (it's a generator of N secrets).
This works like the [configMapGenerator](/docs/reference/api/kustomization-file/configmapgenerator).
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
secretGenerator:
- name: app-tls
files:
- secret/tls.crt
- secret/tls.key
type: "kubernetes.io/tls"
- name: app-tls-namespaced
# you can define a namespace to generate
# a secret in, defaults to: "default"
namespace: apps
files:
- tls.crt=catsecret/tls.crt
- tls.key=secret/tls.key
type: "kubernetes.io/tls"
- name: env_file_secret
envs:
- env.txt
type: Opaque
- name: secret-with-annotation
files:
- app-config.yaml
type: Opaque
options:
annotations:
app_config: "true"
labels:
app.kubernetes.io/name: "app2"
```
Secret Resources may be generated much like ConfigMaps can. This includes generating them
from literals, files or environment files.
{{< alert color="success" title="Secret Syntax" >}}
Secret type is set using the `type` field.
{{< /alert >}}
## Example
### File Input
```yaml
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
secretGenerator:
- name: app-tls
files:
- "tls.crt"
- "tls.key"
type: "kubernetes.io/tls"
```
```yaml
# tls.crt
LS0tLS1CRUd...tCg==
```
```yaml
# tls.key
LS0tLS1CRUd...0tLQo=
```
### Build Output
```yaml
apiVersion: v1
data:
tls.crt: TFMwdExTMUNSVWQuLi50Q2c9PQ==
tls.key: TFMwdExTMUNSVWQuLi4wdExRbz0=
kind: Secret
metadata:
name: app-tls-c888dfbhf8
type: kubernetes.io/tls
```
{{< alert color="warning" title="Important" >}}
It is important to note that the secrets are `base64` encoded
{{< /alert >}}

View File

@@ -0,0 +1,118 @@
---
title: "sortOptions"
linkTitle: "sortOptions"
type: docs
weight: 22
description: >
Change the strategy used to sort resources at the end of the Kustomize build.
---
The `sortOptions` field is used to sort the resources kustomize outputs. It is
available in kustomize v5.0.0+.
IMPORTANT:
- Currently, this field is respected only in the top-level Kustomization (that
is, the immediate target of `kustomize build`). Any instances of the field in
Kustomizations further down the build chain (for example, in bases included
through the `resources` field) will be ignored.
- This field is the endorsed way to sort resources. It should be used instead of
the `--reorder` CLI flag, which is deprecated.
Currently, we support the following sort options:
- `legacy`
- `fifo`
```yaml
kind: Kustomization
sortOptions:
order: legacy | fifo # "legacy" is the default
```
## FIFO Sorting
In `fifo` order, kustomize does not change the order of resources. They appear
in the order they are loaded in `resources`.
### Example 1: FIFO Sorting
```yaml
kind: Kustomization
sortOptions:
order: fifo
```
## Legacy Sorting
The `legacy` sort is the default order, and is used when the sortOrder field is
unspecified.
In `legacy` order, kustomize sorts resources by using two priority lists:
- An `orderFirst` list for resources which should be first in the output.
- An `orderLast` list for resources which should be last in the output.
- Resources not on the lists will appear in between, sorted using their apiVersion and kind fields.
### Example 2: Legacy Sorting with orderFirst / orderLast lists
In this example, we use the `legacy` sort order to output `Namespace` objects
first and `Deployment` objects last.
```yaml
kind: Kustomization
sortOptions:
order: legacy
legacySortOptions:
orderFirst:
- Namespace
orderLast:
- Deployment
```
### Example 3: Default Legacy Sorting
If you specify `legacy` sort order without any arguments for the lists,
kustomize will fall back to the lists we were using before introducing this
feature. Since legacy sort is the default, this is also equivalent to not
specifying the field at all.
These two configs are equivalent:
```yaml
kind: Kustomization
sortOptions:
order: legacy
```
is equivalent to:
```yaml
kind: Kustomization
sortOptions:
order: legacy
legacySortOptions:
orderFirst:
- Namespace
- ResourceQuota
- StorageClass
- CustomResourceDefinition
- ServiceAccount
- PodSecurityPolicy
- Role
- ClusterRole
- RoleBinding
- ClusterRoleBinding
- ConfigMap
- Secret
- Endpoints
- Service
- LimitRange
- PriorityClass
- PersistentVolume
- PersistentVolumeClaim
- Deployment
- StatefulSet
- CronJob
- PodDisruptionBudget
orderLast:
- MutatingWebhookConfiguration
- ValidatingWebhookConfiguration
```

View File

@@ -0,0 +1,335 @@
---
title: "vars"
linkTitle: "vars"
type: docs
weight: 23
description: >
Substitute name references.
---
[replacements]: /docs/reference/api/kustomization-file/replacements/
{{% pageinfo color="warning" %}}
The `vars` field was deprecated in v5.0.0. This field will never be removed from the
kustomize.config.k8s.io/v1beta1 Kustomization API, but it will not be included
in the kustomize.config.k8s.io/v1 Kustomization API. When Kustomization v1 is available,
we will announce the deprecation of the v1beta1 version. There will be at least
two releases between deprecation and removal of Kustomization v1beta1 support from the
kustomize CLI, and removal itself will happen in a future major version bump.
Please try to migrate to the
the [replacements](/docs/reference/api/kustomization-file/replacements) field. If you are
unable to restructure your configuration to use replacements instead of vars, please
ask for help in slack or file an issue for guidance.
We are experimentally attempting to
automatically convert `vars` to `replacements` with `kustomize edit fix --vars`. However,
converting vars to replacements in this way will potentially overwrite many resource files
and the resulting files may not produce the same output when `kustomize build` is run.
We recommend doing this in a clean git repository where the change is easy to undo.
{{% /pageinfo %}}
Vars are used to capture text from one resource's field
and insert that text elsewhere - a reflection feature.
For example, suppose one specifies the name of a k8s Service
object in a container's command line, and the name of a
k8s Secret object in a container's environment variable,
so that the following would work:
```yaml
containers:
- image: myimage
command: ["start", "--host", "$(MY_SERVICE_NAME)"]
env:
- name: SECRET_TOKEN
value: $(SOME_SECRET_NAME)
```
To do so, add an entry to `vars:` as follows:
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
vars:
- name: SOME_SECRET_NAME
objref:
kind: Secret
name: my-secret
apiVersion: v1
- name: MY_SERVICE_NAME
objref:
kind: Service
name: my-service
apiVersion: v1
fieldref:
fieldpath: metadata.name
- name: ANOTHER_DEPLOYMENTS_POD_RESTART_POLICY
objref:
kind: Deployment
name: my-deployment
apiVersion: apps/v1
fieldref:
fieldpath: spec.template.spec.restartPolicy
```
A var is a tuple of variable name, object
reference and field reference within that object.
That's where the text is found.
The field reference is optional; it defaults to
`metadata.name`, a normal default, since kustomize
is used to generate or modify the names of
resources.
At time of writing, only string type fields are
supported. No ints, bools, arrays etc. It's not
possible to, say, extract the name of the image in
container number 2 of some pod template.
A variable reference, i.e. the string '$(FOO)',
can only be placed in particular fields of
particular objects as specified by kustomize's
configuration data.
The default config data for vars is at [/api/konfig/builtinpluginconsts/varreference.go](https://github.com/kubernetes-sigs/kustomize/blob/master/api/konfig/builtinpluginconsts/varreference.go)
Long story short, the default targets are all
container command args and env value fields.
Vars should _not_ be used for inserting names in
places where kustomize is already handling that
job. E.g., a Deployment may reference a ConfigMap
by name, and if kustomize changes the name of a
ConfigMap, it knows to change the name reference
in the Deployment.
### Convert vars to replacements
There are plans to deprecate vars, so we recommend migration to [replacements] as early as possible.
#### Simple migration example
Let's first take a simple example of how to manually do this conversion. Suppose we have a container
referencing secret (similar to the above example):
`pod.yaml`
```yaml
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- image: myimage
name: hello
env:
- name: SECRET_TOKEN
value: $(SOME_SECRET_NAME)
```
and we are using vars as follows:
`kustomization.yaml`
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- pod.yaml
- secret.yaml
vars:
- name: SOME_SECRET_NAME
objref:
kind: Secret
name: my-secret
apiVersion: v1
```
In order to convert `vars` to `replacements`, we have to:
1. Replace every instance of $(SOME_SECRET_NAME) with any arbitrary placeholder value.
2. Convert the vars `objref` field to a [replacements] `source` field.
3. Replace the vars `name` fied with a [replacements] `targets` field that points to
every instance of the placeholder value in step 1.
In our simple example here, this would look like the following:
`pod.yaml`
```yaml
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- image: myimage
name: hello
env:
- name: SECRET_TOKEN
value: SOME_PLACEHOLDER_VALUE
```
`kustomization.yaml`
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- pod.yaml
- secret.yaml
replacements:
- source:
kind: Secret
name: my-secret
version: v1
targets:
- select:
kind: Pod
name: my-pod
fieldPaths:
- spec.containers.[name=hello].env.[name=SECRET_TOKEN].value
```
#### More complex migration example
Let's take a more complex usage of vars and convert it to [replacements]. We are going
to convert the vars in the [wordpress example](https://github.com/kubernetes-sigs/kustomize/tree/master/examples/wordpress)
to replacements.
The wordpress example has the following directory structure:
```
.
├── README.md
├── kustomization.yaml
├── mysql
│   ├── deployment.yaml
│   ├── kustomization.yaml
│   ├── secret.yaml
│   └── service.yaml
├── patch.yaml
└── wordpress
├── deployment.yaml
├── kustomization.yaml
└── service.yaml
```
where `patch.yaml` has the following contents:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
spec:
template:
spec:
initContainers:
- name: init-command
image: debian
command: ["/bin/sh"]
args: ["-c", "echo $(WORDPRESS_SERVICE); echo $(MYSQL_SERVICE)"]
containers:
- name: wordpress
env:
- name: WORDPRESS_DB_HOST
value: $(MYSQL_SERVICE)
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-pass
key: password
```
and the top level `kustomization.yaml` has the following contents:
```
resources:
- wordpress
- mysql
patchesStrategicMerge:
- patch.yaml
namePrefix: demo-
vars:
- name: WORDPRESS_SERVICE
objref:
kind: Service
name: wordpress
apiVersion: v1
- name: MYSQL_SERVICE
objref:
kind: Service
name: mysql
apiVersion: v1
```
In this example, the patch is used to:
- Add an initial container to show the mysql service name
- Add environment variable that allow wordpress to find the mysql database
We can convert vars to replacements in this more complex case too, by taking the same steps as
the previous example. To do this, we can change the contents of `patch.yaml` to:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
spec:
template:
spec:
initContainers:
- name: init-command
image: debian
command: ["/bin/sh"]
args: ["-c", "echo", "WORDPRESS_SERVICE", ";", "echo", "MYSQL_SERVICE"]
containers:
- name: wordpress
env:
- name: WORDPRESS_DB_HOST
value: MYSQL_SERVICE
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-pass
key: password
```
Then, in our kustomization, we can have our replacements:
`kustomization.yaml`
```yaml
resources:
- wordpress
- mysql
patchesStrategicMerge:
- patch.yaml
namePrefix: demo-
replacements:
- source:
name: demo-wordpress
kind: Service
version: v1
targets:
- select:
kind: Deployment
name: demo-wordpress
fieldPaths:
- spec.template.spec.initContainers.[name=init-command].args.2
- source:
name: demo-mysql
kind: Service
version: v1
targets:
- select:
kind: Deployment
name: demo-wordpress
fieldPaths:
- spec.template.spec.initContainers.[name=init-command].args.5
- spec.template.spec.containers.[name=wordpress].env.[name=WORDPRESS_DB_HOST].value
```

View File

@@ -4,5 +4,75 @@ linkTitle: "CLI"
weight: 3
date: 2023-07-28
description: >
The command line tools to interact with Kustomize.
---
Reference for the Command Line Interface.
---
This overview covers `kustomize` syntax, describes the command operations, and provides common examples.
## Syntax
Use the following syntax to run `kustomize` commands from your terminal window:
```bash
kustomize [command]
```
The `command` flag specifies the operation that you want to perform, for example `create`, `build`, `cfg`.
If you need help, run `kustomize help` from the terminal window.
## Operations
The following table includes short descriptions and the general syntax for all the `kustomize` operations.
Operation | Syntax | Description
--- | --- | ---
build | `kustomize build DIR [flags]` | Build a kustomization target from a directory or URL.
cfg | `kustomize cfg [command]` | Commands for reading and writing configuration.
completion | `kustomize completion` [bash\|zsh\|fish\|powershell] | Generate shell completion script.
create | `kustomize create [flags]` | Create a new kustomization in the current directory.
edit | `kustomize edit [command]` | Edits a kustomization file.
fn | `kustomize fn [command]` | Commands for running functions against configuration.
localize | `kustomize localize [target [destination]] [flags]` | [Alpha] Creates localized copy of target kustomization root at destination.
version | `kustomize version [flags]` | Prints the kustomize version.
## Examples: Common Operations
Use the following set of examples to help you familiarize yourself with running the commonly used `kustomize` operations:
`kustomize build` - Build a kustomization target from a directory or URL.
```bash
# Build the current working directory
kustomize build
# Build some shared configuration directory
kustomize build /home/config/production
# Build from github
kustomize build https://github.com/kubernetes-sigs/kustomize.git/examples/helloWorld?ref=v1.0.6
```
`kustomize create` - Create a new kustomization in the current directory.
```bash
# Create an empty kustomization.yaml file
kustomize create
# Create a new overlay from the base '../base".
kustomize create --resources ../base
# Create a new kustomization detecting resources in the current directory.
kustomize create --autodetect
# Create a new kustomization with multiple resources and fields set.
kustomize create --resources deployment.yaml,service.yaml,../base --namespace staging --nameprefix acme-
```
`kustomize edit` - Edits a kustomization file.
```bash
# Adds a configmap to the kustomization file
kustomize edit add configmap NAME --from-literal=k=v
# Sets the nameprefix field
kustomize edit set nameprefix <prefix-value>
# Sets the namesuffix field
kustomize edit set namesuffix <suffix-value>
```