Compare commits

..

1 Commits

Author SHA1 Message Date
Jeff Regan
f59f12947b Update release instructions. 2020-08-28 11:39:17 -07:00
790 changed files with 47441 additions and 481678 deletions

View File

@@ -1,8 +0,0 @@
.github
docs
examples
functions
hack
site
travis
*.md

View File

@@ -1,68 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ""
labels:
- kind/bug
assignees: ""
---
<!--
Please read this page: https://kubernetes-sigs.github.io/kustomize/contributing/bugs/ before
filing a bug
-->
<!-- Feel free to skip the sections if they are not applicable. -->
**Describe the bug**
<!-- A clear and concise description of what the bug is. -->
**Files that can reproduce the issue**
<!--
We cannot figure out or fix the issue if we don't know how to reproduce. Please
provide a minimum set of files that can reproduce the issue. You can paste the
file contents here or provide a link to a tarball or git repo.
Example:
kustomization.yaml
```
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
...
```
resources.yaml
```
apiVersion: v1
kind: Deployment
...
```
...
-->
**Expected output**
<!-- What's the expected output? -->
**Actual output**
<!-- What's the actual output? -->
**Kustomize version**
<!-- Please use the latest version when it's possible. -->
**Platform**
<!-- Linux/macOS/Windows? -->
**Additional context**
<!-- Add any other context about the problem here. -->

View File

@@ -1 +0,0 @@
blank_issues_enabled: true

View File

@@ -1,26 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ""
labels:
- kind/feature
assignees: ""
---
<!-- Feel free to skip the sections if they are not applicable. -->
**Is your feature request related to a problem? Please describe.**
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
**Describe the solution you'd like**
<!-- A clear and concise description of what you want to happen. -->
**Describe alternatives you've considered**
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
**Additional context**
<!-- Add any other context or screenshots about the feature request here. -->

View File

@@ -1,9 +0,0 @@
---
name: Question
about: Ask a question about the kustomize
title: "[Question]"
labels: ""
assignees: ""
---
<!-- Please describe your question here -->

View File

@@ -23,7 +23,7 @@ jobs:
uses: actions/checkout@v2
- name: Lint
run: ./scripts/kyaml-pre-commit.sh
run: ./travis/kyaml-pre-commit.sh
env:
KUSTOMIZE_DOCKER_E2E: false # don't need to do e2e tests for linting

125
Makefile
View File

@@ -6,17 +6,6 @@
MYGOBIN := $(shell go env GOPATH)/bin
SHELL := /bin/bash
export PATH := $(MYGOBIN):$(PATH)
MODULES := '"cmd/config" "api/" "kustomize/" "kyaml/"'
# Provide defaults for REPO_OWNER and REPO_NAME if not present.
# Typically these values would be provided by Prow.
ifndef REPO_OWNER
REPO_OWNER := "kubernetes-sigs"
endif
ifndef REPO_NAME
REPO_NAME := "kustomize"
endif
.PHONY: all
all: verify-kustomize
@@ -26,19 +15,18 @@ verify-kustomize: \
lint-kustomize \
test-unit-kustomize-all \
test-examples-kustomize-against-HEAD \
test-examples-kustomize-against-3.8.6
test-examples-kustomize-against-3.8.0
# The following target referenced by a file in
# https://github.com/kubernetes/test-infra/tree/master/config/jobs/kubernetes-sigs/kustomize
.PHONY: prow-presubmit-check
prow-presubmit-check: \
lint-kustomize \
test-multi-module \
test-unit-kustomize-all \
test-unit-cmd-all \
test-go-mod \
test-examples-kustomize-against-HEAD \
test-examples-kustomize-against-3.8.6
test-examples-kustomize-against-3.8.0
.PHONY: verify-kustomize-e2e
verify-kustomize-e2e: test-examples-e2e-kustomize
@@ -57,37 +45,34 @@ $(MYGOBIN)/golangci-lint-kustomize:
GO111MODULE=on go build -tags=tools -o $(MYGOBIN)/golangci-lint-kustomize github.com/golangci/golangci-lint/cmd/golangci-lint; \
)
# Install from version specified in api/go.mod.
# Version pinned by api/go.mod
$(MYGOBIN)/mdrip:
cd api; \
go install github.com/monopole/mdrip
# Install from version specified in api/go.mod.
# Version pinned by api/go.mod
$(MYGOBIN)/stringer:
cd api; \
go install golang.org/x/tools/cmd/stringer
# Install from version specified in api/go.mod.
# Version pinned by api/go.mod
$(MYGOBIN)/goimports:
cd api; \
go install golang.org/x/tools/cmd/goimports
# Build from local source.
$(MYGOBIN)/gorepomod:
cd cmd/gorepomod; \
# Install resource from whatever is checked out.
$(MYGOBIN)/resource:
cd cmd/resource; \
go install .
# Build from local source.
# To pin pluginator, use this recipe instead:
# cd api;
# go install sigs.k8s.io/kustomize/pluginator/v2
$(MYGOBIN)/pluginator:
cd cmd/pluginator; \
cd pluginator; \
go install .
# Build from local source.
$(MYGOBIN)/prchecker:
cd cmd/prchecker; \
go install .
# Build from local source.
# Install kustomize from whatever is checked out.
$(MYGOBIN)/kustomize:
cd kustomize; \
go install .
@@ -96,13 +81,9 @@ $(MYGOBIN)/kustomize:
install-tools: \
$(MYGOBIN)/goimports \
$(MYGOBIN)/golangci-lint-kustomize \
$(MYGOBIN)/gh \
$(MYGOBIN)/gorepomod \
$(MYGOBIN)/mdrip \
$(MYGOBIN)/pluginator \
$(MYGOBIN)/prchecker \
$(MYGOBIN)/stringer \
$(MYGOBIN)/helm
$(MYGOBIN)/stringer
### Begin kustomize plugin rules.
#
@@ -144,8 +125,7 @@ _builtinplugins = \
PrefixSuffixTransformer.go \
ReplicaCountTransformer.go \
SecretGenerator.go \
ValueAddTransformer.go \
HelmChartInflationGenerator.go
ValueAddTransformer.go
# Maintaining this explicit list of generated files, and
# adding it as a dependency to a few targets, to assure
@@ -171,7 +151,6 @@ $(pGen)/PrefixSuffixTransformer.go: $(pSrc)/prefixsuffixtransformer/PrefixSuffix
$(pGen)/ReplicaCountTransformer.go: $(pSrc)/replicacounttransformer/ReplicaCountTransformer.go
$(pGen)/SecretGenerator.go: $(pSrc)/secretgenerator/SecretGenerator.go
$(pGen)/ValueAddTransformer.go: $(pSrc)/valueaddtransformer/ValueAddTransformer.go
$(pGen)/HelmChartInflationGenerator.go: $(pSrc)/helmchartinflationgenerator/HelmChartInflationGenerator.go
# The (verbose but portable) Makefile way to convert to lowercase.
toLowerCase = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$1))))))))))))))))))))))))))
@@ -190,27 +169,24 @@ $(pGen)/%.go: $(MYGOBIN)/pluginator
.PHONY: generate-kustomize-builtin-plugins
generate-kustomize-builtin-plugins: $(builtinplugins)
.PHONY: build-kustomize-external-go-plugin
build-kustomize-external-go-plugin:
.PHONY: kustomize-external-go-plugin-build
kustomize-external-go-plugin-build:
./hack/buildExternalGoPlugins.sh ./plugin
.PHONY: clean-kustomize-external-go-plugin
clean-kustomize-external-go-plugin:
.PHONY: kustomize-external-go-plugin-clean
kustomize-external-go-plugin-clean:
./hack/buildExternalGoPlugins.sh ./plugin clean
### End kustomize plugin rules.
.PHONY: lint-kustomize
lint-kustomize: install-tools $(builtinplugins)
cd api; $(MYGOBIN)/golangci-lint-kustomize \
-c ../.golangci-kustomize.yml \
run ./...
cd kustomize; $(MYGOBIN)/golangci-lint-kustomize \
-c ../.golangci-kustomize.yml \
run ./...
cd cmd/pluginator; $(MYGOBIN)/golangci-lint-kustomize \
-c ../../.golangci-kustomize.yml \
run ./...
cd api; \
$(MYGOBIN)/golangci-lint-kustomize -c ../.golangci-kustomize.yml run ./...
cd kustomize; \
$(MYGOBIN)/golangci-lint-kustomize -c ../.golangci-kustomize.yml run ./...
cd pluginator; \
$(MYGOBIN)/golangci-lint-kustomize -c ../.golangci-kustomize.yml run ./...
# Used to add non-default compilation flags when experimenting with
# plugin-to-api compatibility checks.
@@ -218,10 +194,6 @@ lint-kustomize: install-tools $(builtinplugins)
build-kustomize-api: $(builtinplugins)
cd api; go build ./...
.PHONY: generate-kustomize-api
generate-kustomize-api:
cd api; go generate ./...
.PHONY: test-unit-kustomize-api
test-unit-kustomize-api: build-kustomize-api
cd api; go test ./... -ldflags "-X sigs.k8s.io/kustomize/api/provenance.version=v444.333.222"
@@ -241,23 +213,10 @@ test-unit-kustomize-all: \
test-unit-kustomize-plugins
test-unit-cmd-all:
./scripts/kyaml-pre-commit.sh
./travis/kyaml-pre-commit.sh
test-go-mod:
./scripts/check-go-mod.sh
# Environment variables are defined at
# https://github.com/kubernetes/test-infra/blob/master/prow/jobs.md#job-environment-variables
.PHONY: test-multi-module
test-multi-module: $(MYGOBIN)/prchecker
( \
export MYGOBIN=$(MYGOBIN); \
export REPO_OWNER=$(REPO_OWNER); \
export REPO_NAME=$(REPO_NAME); \
export PULL_NUMBER=$(PULL_NUMBER); \
export MODULES=$(MODULES); \
./scripts/check-multi-module.sh; \
)
./travis/check-go-mod.sh
.PHONY:
test-examples-e2e-kustomize: $(MYGOBIN)/mdrip $(MYGOBIN)/kind
@@ -274,10 +233,10 @@ test-examples-kustomize-against-HEAD: $(MYGOBIN)/kustomize $(MYGOBIN)/mdrip
./hack/testExamplesAgainstKustomize.sh HEAD
.PHONY:
test-examples-kustomize-against-3.8.6: $(MYGOBIN)/mdrip
test-examples-kustomize-against-3.8.0: $(MYGOBIN)/mdrip
( \
set -e; \
tag=v3.8.6; \
tag=v3.8.0; \
/bin/rm -f $(MYGOBIN)/kustomize; \
echo "Installing kustomize $$tag."; \
GO111MODULE=on go get sigs.k8s.io/kustomize/kustomize/v3@$${tag}; \
@@ -324,16 +283,16 @@ $(MYGOBIN)/helmV3:
( \
set -e; \
d=$(shell mktemp -d); cd $$d; \
tgzFile=helm-v3.4.0-linux-amd64.tar.gz; \
tgzFile=helm-v3.2.0-rc.1-linux-amd64.tar.gz; \
wget https://get.helm.sh/$$tgzFile; \
tar -xvzf $$tgzFile; \
mv linux-amd64/helm $(MYGOBIN)/helmV3; \
rm -rf $$d \
)
# Default version of helm is v3.
$(MYGOBIN)/helm: $(MYGOBIN)/helmV3
ln -s $(MYGOBIN)/helmV3 $(MYGOBIN)/helm
# Default version of helm is v2 for the time being.
$(MYGOBIN)/helm: $(MYGOBIN)/helmV2
ln -s $(MYGOBIN)/helmV2 $(MYGOBIN)/helm
$(MYGOBIN)/kind:
( \
@@ -345,28 +304,14 @@ $(MYGOBIN)/kind:
rm -rf $$d; \
)
# linux only.
$(MYGOBIN)/gh:
( \
set -e; \
d=$(shell mktemp -d); cd $$d; \
tgzFile=gh_1.0.0_linux_amd64.tar.gz; \
wget https://github.com/cli/cli/releases/download/v1.0.0/$$tgzFile; \
tar -xvzf $$tgzFile; \
mv gh_1.0.0_linux_amd64/bin/gh $(MYGOBIN)/gh; \
rm -rf $$d \
)
.PHONY: clean
clean: clean-kustomize-external-go-plugin
clean: kustomize-external-go-plugin-clean
go clean --cache
rm -f $(builtinplugins)
rm -f $(MYGOBIN)/pluginator
rm -f $(MYGOBIN)/kustomize
rm -f $(MYGOBIN)/golangci-lint-kustomize
# Handle pluginator manually.
# rm -f $(MYGOBIN)/pluginator
# Nuke the site from orbit. It's the only way to be sure.
.PHONY: nuke
nuke: clean

View File

@@ -11,4 +11,3 @@ aliases:
- pwittrock
- mortent
- phanimarupaka
- Shell32-Natsu

View File

@@ -20,20 +20,15 @@ This tool is sponsored by [sig-cli] ([KEP]).
## kubectl integration
The kustomize build flow at [v2.0.3] was added
to [kubectl v1.14][kubectl announcement]. The kustomize
flow in kubectl has remained frozen at v2.0.3 while work
to extract kubectl from the k/k repo, and work to remove
kustomize's dependence on core k/k code ([#2506]) has proceeded.
The reintegration effort is tracked in [#1500] (and its blocking
issues).
Since [v1.14][kubectl announcement] the kustomize build system has been included in kubectl.
[v2.0.3]: /../../tree/v2.0.3
[#2506]: https://github.com/kubernetes-sigs/kustomize/issues/2506
[#1500]: https://github.com/kubernetes-sigs/kustomize/issues/1500
| kubectl version | kustomize version |
|---------|--------|
| v1.16.0 | [v2.0.3](/../../tree/v2.0.3) |
| v1.15.x | [v2.0.3](/../../tree/v2.0.3) |
| v1.14.x | [v2.0.3](/../../tree/v2.0.3) |
For examples and guides for using the kubectl integration please
see the [kubectl book] or the [kubernetes documentation].
For examples and guides for using the kubectl integration please see the [kubectl book] or the [kubernetes documentation].
## Usage
@@ -153,7 +148,7 @@ is governed by the [Kubernetes Code of Conduct].
[imageBase]: docs/images/base.jpg
[imageOverlay]: docs/images/overlay.jpg
[kubectl announcement]: https://kubernetes.io/blog/2019/03/25/kubernetes-1-14-release-announcement
[kubectl book]: https://kubectl.docs.kubernetes.io/guides/introduction/kustomize/
[kubectl book]: https://kubectl.docs.kubernetes.io/pages/app_customization/introduction.html
[kubernetes documentation]: https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/
[kubernetes style]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#kubernetes-style-object
[kustomization]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#kustomization

View File

@@ -1,179 +0,0 @@
// Code generated by pluginator on HelmChartInflationGenerator; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
package builtins
import (
"bytes"
"fmt"
"os"
"os/exec"
"path"
"regexp"
"strings"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/yaml"
)
// HelmChartInflationGeneratorPlugin is a plugin to generate resources
// from a remote or local helm chart.
type HelmChartInflationGeneratorPlugin struct {
h *resmap.PluginHelpers
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
runHelmCommand func([]string) ([]byte, error)
types.HelmChartArgs
tmpDir string
}
var KustomizePlugin HelmChartInflationGeneratorPlugin
// Config uses the input plugin configurations `config` to setup the generator
// options
func (p *HelmChartInflationGeneratorPlugin) Config(h *resmap.PluginHelpers, config []byte) error {
p.h = h
err := yaml.Unmarshal(config, p)
if err != nil {
return err
}
tmpDir, err := filesys.NewTmpConfirmedDir()
if err != nil {
return err
}
p.tmpDir = string(tmpDir)
if p.ChartName == "" {
return fmt.Errorf("chartName cannot be empty")
}
if p.ChartHome == "" {
p.ChartHome = path.Join(p.tmpDir, "chart")
}
if p.ChartRepoName == "" {
p.ChartRepoName = "stable"
}
if p.HelmBin == "" {
p.HelmBin = "helm"
}
if p.HelmHome == "" {
p.HelmHome = path.Join(p.tmpDir, ".helm")
}
if p.Values == "" {
p.Values = path.Join(p.ChartHome, p.ChartName, "values.yaml")
}
// runHelmCommand will run `helm` command with args provided. Return stdout
// and error if there is any.
p.runHelmCommand = func(args []string) ([]byte, error) {
stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer)
cmd := exec.Command(p.HelmBin, args...)
cmd.Stdout = stdout
cmd.Stderr = stderr
cmd.Env = append(cmd.Env,
fmt.Sprintf("HELM_CONFIG_HOME=%s", p.HelmHome),
fmt.Sprintf("HELM_CACHE_HOME=%s/.cache", p.HelmHome),
fmt.Sprintf("HELM_DATA_HOME=%s/.data", p.HelmHome),
)
err := cmd.Run()
if err != nil {
return stdout.Bytes(),
errors.Wrap(
fmt.Errorf("failed to run command %s %s", p.HelmBin, strings.Join(args, " ")),
stderr.String(),
)
}
return stdout.Bytes(), nil
}
return nil
}
// Generate implements generator
func (p *HelmChartInflationGeneratorPlugin) Generate() (resmap.ResMap, error) {
// cleanup
defer os.RemoveAll(p.tmpDir)
// check helm version. we only support V3
err := p.checkHelmVersion()
if err != nil {
return nil, err
}
// pull the chart
if !p.checkLocalChart() {
_, err := p.runHelmCommand(p.getPullCommandArgs())
if err != nil {
return nil, err
}
}
// render the charts
stdout, err := p.runHelmCommand(p.getTemplateCommandArgs())
if err != nil {
return nil, err
}
return p.h.ResmapFactory().NewResMapFromBytes(stdout)
}
func (p *HelmChartInflationGeneratorPlugin) getTemplateCommandArgs() []string {
args := []string{"template"}
if p.ReleaseName != "" {
args = append(args, p.ReleaseName)
}
args = append(args, path.Join(p.ChartHome, p.ChartName))
if p.ReleaseNamespace != "" {
args = append(args, "--namespace", p.ReleaseNamespace)
}
if p.Values != "" {
args = append(args, "--values", p.Values)
}
args = append(args, p.ExtraArgs...)
return args
}
func (p *HelmChartInflationGeneratorPlugin) getPullCommandArgs() []string {
args := []string{"pull", "--untar", "--untardir", p.ChartHome}
chartName := fmt.Sprintf("%s/%s", p.ChartRepoName, p.ChartName)
if p.ChartVersion != "" {
args = append(args, "--version", p.ChartVersion)
}
if p.ChartRepoURL != "" {
args = append(args, "--repo", p.ChartRepoURL)
chartName = p.ChartName
}
args = append(args, chartName)
return args
}
// checkLocalChart will return true if the chart does exist in
// local chart home.
func (p *HelmChartInflationGeneratorPlugin) checkLocalChart() bool {
path := path.Join(p.ChartHome, p.ChartName)
s, err := os.Stat(path)
if err != nil {
return false
}
return s.IsDir()
}
// checkHelmVersion will return an error if the helm version is not V3
func (p *HelmChartInflationGeneratorPlugin) checkHelmVersion() error {
stdout, err := p.runHelmCommand([]string{"version", "-c", "--short"})
if err != nil {
return err
}
r, err := regexp.Compile(`v\d+(\.\d+)+`)
if err != nil {
return err
}
v := string(r.Find(stdout))[1:]
majorVersion := strings.Split(v, ".")[0]
if majorVersion != "3" {
return fmt.Errorf("this plugin requires helm V3 but got v%s", v)
}
return nil
}
func NewHelmChartInflationGeneratorPlugin() resmap.GeneratorPlugin {
return &HelmChartInflationGeneratorPlugin{}
}

View File

@@ -31,15 +31,14 @@ func (p *ImageTagTransformerPlugin) Config(
func (p *ImageTagTransformerPlugin) Transform(m resmap.ResMap) error {
for _, r := range m.Resources() {
// traverse all fields at first
err := filtersutil.ApplyToJSON(imagetag.LegacyFilter{
ImageTag: p.ImageTag,
}, r)
if err != nil {
return err
}
// then use user specified field specs
err = filtersutil.ApplyToJSON(imagetag.Filter{
// If you're here because someone expected any field containing
// the string "containers" or "initContainers" to get an image
// update (not just spec/template/spec/containers[], etc.) then
// a code change is needed. See api/filters/imagetag/legacy
// for the start of an implementation that won't use an
// allowlist like FsSlice, and instead walks the object looking
// for fields named containers or initContainers.
err := filtersutil.ApplyToJSON(imagetag.Filter{
ImageTag: p.ImageTag,
FsSlice: p.FieldSpecs,
}, r)

View File

@@ -7,7 +7,9 @@ import (
"fmt"
"sigs.k8s.io/kustomize/api/filters/namespace"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/filtersutil"
"sigs.k8s.io/yaml"
@@ -31,7 +33,7 @@ func (p *NamespaceTransformerPlugin) Transform(m resmap.ResMap) error {
return nil
}
for _, r := range m.Resources() {
if r.IsEmpty() {
if len(r.Map()) == 0 {
// Don't mutate empty objects?
continue
}
@@ -51,6 +53,74 @@ func (p *NamespaceTransformerPlugin) Transform(m resmap.ResMap) error {
return nil
}
// Special casing metadata.namespace since
// all objects have it, even "ClusterKind" objects
// that don't exist in a namespace (the Namespace
// object itself doesn't live in a namespace).
func (p *NamespaceTransformerPlugin) applicableFieldSpecs(id resid.ResId) []types.FieldSpec {
var res []types.FieldSpec
for _, fs := range p.FieldSpecs {
if id.IsSelected(&fs.Gvk) &&
(fs.Path != types.MetadataNamespacePath ||
(fs.Path == types.MetadataNamespacePath && id.IsNamespaceableKind())) {
res = append(res, fs)
}
}
return res
}
func (p *NamespaceTransformerPlugin) changeNamespace(
_ *resource.Resource) func(in interface{}) (interface{}, error) {
return func(in interface{}) (interface{}, error) {
switch in.(type) {
case string:
// will happen when the metadata/namespace
// value is replaced
return p.Namespace, nil
case []interface{}:
l, _ := in.([]interface{})
for idx, item := range l {
switch item.(type) {
case map[string]interface{}:
// Will happen when mutating the subjects
// field of ClusterRoleBinding and RoleBinding
inMap, _ := item.(map[string]interface{})
if _, ok := inMap["name"]; !ok {
continue
}
name, ok := inMap["name"].(string)
if !ok {
continue
}
// The only case we need to force the namespace
// if for the "service account". "default" is
// kind of hardcoded here for right now.
if name != "default" {
continue
}
inMap["namespace"] = p.Namespace
l[idx] = inMap
default:
// nothing to do for right now
}
}
return in, nil
case map[string]interface{}:
// Will happen if the createField=true
// when the namespace is added to the
// object
inMap := in.(map[string]interface{})
if len(inMap) == 0 {
return p.Namespace, nil
} else {
return in, nil
}
default:
return in, nil
}
}
}
func NewNamespaceTransformerPlugin() resmap.TransformerPlugin {
return &NamespaceTransformerPlugin{}
}

View File

@@ -10,6 +10,7 @@ import (
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/filters/patchjson6902"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/filtersutil"
@@ -19,9 +20,9 @@ import (
type PatchJson6902TransformerPlugin struct {
ldr ifc.Loader
decodedPatch jsonpatch.Patch
Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"`
Path string `json:"path,omitempty" yaml:"path,omitempty"`
JsonOp string `json:"jsonOp,omitempty" yaml:"jsonOp,omitempty"`
Target types.PatchTarget `json:"target,omitempty" yaml:"target,omitempty"`
Path string `json:"path,omitempty" yaml:"path,omitempty"`
JsonOp string `json:"jsonOp,omitempty" yaml:"jsonOp,omitempty"`
}
func (p *PatchJson6902TransformerPlugin) Config(
@@ -71,22 +72,22 @@ func (p *PatchJson6902TransformerPlugin) Config(
}
func (p *PatchJson6902TransformerPlugin) Transform(m resmap.ResMap) error {
if p.Target == nil {
return fmt.Errorf("must specify a target for patch %s", p.JsonOp)
}
resources, err := m.Select(*p.Target)
id := resid.NewResIdWithNamespace(
resid.Gvk{
Group: p.Target.Group,
Version: p.Target.Version,
Kind: p.Target.Kind,
},
p.Target.Name,
p.Target.Namespace,
)
obj, err := m.GetById(id)
if err != nil {
return err
}
for _, res := range resources {
err = filtersutil.ApplyToJSON(patchjson6902.Filter{
Patch: p.JsonOp,
}, res)
if err != nil {
return err
}
}
return nil
return filtersutil.ApplyToJSON(patchjson6902.Filter{
Patch: p.JsonOp,
}, obj)
}
func NewPatchJson6902TransformerPlugin() resmap.TransformerPlugin {

View File

@@ -5,10 +5,14 @@ package builtins
import (
"fmt"
"strings"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/filters/patchstrategicmerge"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/filtersutil"
"sigs.k8s.io/yaml"
)
@@ -31,11 +35,6 @@ func (p *PatchStrategicMergeTransformerPlugin) Config(
}
if len(p.Paths) != 0 {
for _, onePath := range p.Paths {
// The following oddly attempts to interpret a path string as an
// actual patch (instead of as a path to a file containing a patch).
// All tests pass if this code is commented out. This code should
// be deleted; the user should use the Patches field which
// exists for this purpose (inline patch declaration).
res, err := p.h.ResmapFactory().RF().SliceFromBytes([]byte(onePath))
if err == nil {
p.loadedPatches = append(p.loadedPatches, res...)
@@ -74,10 +73,44 @@ func (p *PatchStrategicMergeTransformerPlugin) Transform(m resmap.ResMap) error
if err != nil {
return err
}
if err = m.ApplySmPatch(
resource.MakeIdSet([]*resource.Resource{target}), patch); err != nil {
patchCopy := patch.DeepCopy()
patchCopy.SetName(target.GetName())
patchCopy.SetNamespace(target.GetNamespace())
patchCopy.SetGvk(target.GetGvk())
node, err := filtersutil.GetRNode(patchCopy)
if err != nil {
return err
}
err = filtersutil.ApplyToJSON(patchstrategicmerge.Filter{
Patch: node,
}, target)
if err != nil {
// Check for an error string from UnmarshalJSON that's indicative
// of an object that's missing basic KRM fields, and thus may have been
// entirely deleted (an acceptable outcome). This error handling should
// be deleted along with use of ResMap and apimachinery functions like
// UnmarshalJSON.
if !strings.Contains(err.Error(), "Object 'Kind' is missing") {
// Some unknown error, let it through.
return err
}
if len(target.Map()) != 0 {
return errors.Wrapf(
err, "with unexpectedly non-empty object map of size %d",
len(target.Map()))
}
// Fall through to handle deleted object.
}
if len(target.Map()) == 0 {
// This means all fields have been removed from the object.
// This can happen if a patch required deletion of the
// entire resource (not just a part of it). This means
// the overall resmap must shrink by one.
err = m.Remove(target.CurId())
if err != nil {
return err
}
}
}
return nil
}

View File

@@ -9,6 +9,7 @@ import (
jsonpatch "github.com/evanphx/json-patch"
"sigs.k8s.io/kustomize/api/filters/patchjson6902"
"sigs.k8s.io/kustomize/api/filters/patchstrategicmerge"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
@@ -39,6 +40,7 @@ func (p *PatchTransformerPlugin) Config(
return fmt.Errorf(
"patch and path can't be set at the same time\n%s", string(c))
}
if p.Path != "" {
loaded, loadErr := h.Loader().Load(p.Path)
if loadErr != nil {
@@ -85,13 +87,36 @@ func (p *PatchTransformerPlugin) transformStrategicMerge(m resmap.ResMap, patch
if err != nil {
return err
}
return target.ApplySmPatch(patch)
return p.applySMPatch(target, patch)
}
selected, err := m.Select(*p.Target)
resources, err := m.Select(*p.Target)
if err != nil {
return err
}
return m.ApplySmPatch(resource.MakeIdSet(selected), patch)
for _, res := range resources {
patchCopy := patch.DeepCopy()
patchCopy.SetName(res.GetName())
patchCopy.SetNamespace(res.GetNamespace())
patchCopy.SetGvk(res.GetGvk())
err := p.applySMPatch(res, patchCopy)
if err != nil {
return err
}
}
return nil
}
// applySMPatch applies the provided strategic merge patch to the
// given resource.
func (p *PatchTransformerPlugin) applySMPatch(resource, patch *resource.Resource) error {
node, err := filtersutil.GetRNode(patch)
if err != nil {
return err
}
return filtersutil.ApplyToJSON(patchstrategicmerge.Filter{
Patch: node,
}, resource)
}
// transformJson6902 applies the provided json6902 patch

View File

@@ -51,9 +51,6 @@ func (fltr Filter) filter(obj *yaml.RNode) error {
// found the field -- set its value
return fltr.SetValue(obj)
}
if obj.IsTaggedNull() {
return nil
}
switch obj.YNode().Kind {
case yaml.SequenceNode:
return fltr.seq(obj)
@@ -70,7 +67,7 @@ func (fltr Filter) field(obj *yaml.RNode) error {
// lookup the field matching the next path element
var lookupField yaml.Filter
var kind yaml.Kind
tag := yaml.NodeTagEmpty
tag := "" // TODO: change to yaml.NodeTagEmpty
switch {
case !fltr.FieldSpec.CreateIfNotPresent || fltr.CreateKind == 0 || isSeq:
// dont' create the field if we don't find it
@@ -98,10 +95,9 @@ func (fltr Filter) field(obj *yaml.RNode) error {
return errors.WrapPrefixf(err, "fieldName: %s", fieldName)
}
// if the value exists, but is null and kind is set,
// then change it to the creation type
// if the value exists, but is null, then change it to the creation type
// TODO: update yaml.LookupCreate to support this
if field.YNode().Tag == yaml.NodeTagNull && yaml.IsCreate(kind) {
if field.YNode().Tag == yaml.NodeTagNull {
field.YNode().Kind = kind
field.YNode().Tag = tag
}

View File

@@ -433,6 +433,7 @@ spec:
SetValue: filtersutil.SetScalar("bar"),
CreateKind: yaml.ScalarNode,
},
error: "obj '' at path 'spec/containers/image': expected sequence or mapping node",
},
{
name: "filedname with slash '/'",

View File

@@ -1,9 +1,7 @@
package nameref
import (
"encoding/json"
"fmt"
"strings"
"sigs.k8s.io/kustomize/api/filters/fieldspec"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
@@ -11,7 +9,6 @@ import (
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
kyaml_filtersutil "sigs.k8s.io/kustomize/kyaml/filtersutil"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
@@ -22,7 +19,6 @@ type Filter struct {
Referrer *resource.Resource
Target resid.Gvk
ReferralCandidates resmap.ResMap
isRoleRef bool
}
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
@@ -41,9 +37,6 @@ func (f Filter) set(node *yaml.RNode) error {
if yaml.IsMissingOrNull(node) {
return nil
}
if strings.HasSuffix(f.FieldSpec.Path, "roleRef/name") {
f.isRoleRef = true
}
switch node.YNode().Kind {
case yaml.ScalarNode:
return f.setScalar(node)
@@ -72,7 +65,6 @@ func (f Filter) setMapping(node *yaml.RNode) error {
f.Referrer,
f.Target,
f.ReferralCandidates,
f.isRoleRef,
)
}
@@ -83,7 +75,6 @@ func (f Filter) setScalar(node *yaml.RNode) error {
f.Target,
f.ReferralCandidates,
f.ReferralCandidates.Resources(),
f.isRoleRef,
)
if err != nil {
return err
@@ -95,56 +86,14 @@ func (f Filter) setScalar(node *yaml.RNode) error {
return nil
}
// getRoleRefGvk returns a Gvk in the roleRef field. Return error
// if the roleRef, roleRef/apiGroup or roleRef/kind is missing.
func getRoleRefGvk(res json.Marshaler) (*resid.Gvk, error) {
n, err := kyaml_filtersutil.GetRNode(res)
if err != nil {
return nil, err
}
roleRef, err := n.Pipe(yaml.Lookup("roleRef"))
if err != nil {
return nil, err
}
if roleRef.IsNil() {
return nil, fmt.Errorf("roleRef cannot be found in %s", n.MustString())
}
apiGroup, err := roleRef.Pipe(yaml.Lookup("apiGroup"))
if err != nil {
return nil, err
}
if apiGroup.IsNil() {
return nil, fmt.Errorf("apiGroup cannot be found in roleRef %s", roleRef.MustString())
}
kind, err := roleRef.Pipe(yaml.Lookup("kind"))
if err != nil {
return nil, err
}
if kind.IsNil() {
return nil, fmt.Errorf("kind cannot be found in roleRef %s", roleRef.MustString())
}
return &resid.Gvk{
Group: apiGroup.YNode().Value,
Kind: kind.YNode().Value,
}, nil
}
func filterReferralCandidates(
referrer *resource.Resource,
matches []*resource.Resource,
target resid.Gvk,
) []*resource.Resource {
matches []*resource.Resource) []*resource.Resource {
var ret []*resource.Resource
for _, m := range matches {
// If target kind is not ServiceAccount, we shouldn't consider condidates which
// doesn't have same namespace.
if target.Kind != "ServiceAccount" && m.GetNamespace() != referrer.GetNamespace() {
continue
if referrer.PrefixesSuffixesEquals(m) {
ret = append(ret, m)
}
if !referrer.PrefixesSuffixesEquals(m) {
continue
}
ret = append(ret, m)
}
return ret
}
@@ -160,27 +109,16 @@ func selectReferral(
referrer *resource.Resource,
target resid.Gvk,
referralCandidates resmap.ResMap,
referralCandidateSubset []*resource.Resource,
isRoleRef bool) (string, string, error) {
var roleRefGvk *resid.Gvk
if isRoleRef {
var err error
roleRefGvk, err = getRoleRefGvk(referrer)
if err != nil {
return "", "", err
}
}
referralCandidateSubset []*resource.Resource) (string, string, error) {
for _, res := range referralCandidateSubset {
id := res.OrgId()
// If the we are processing a roleRef, the apiGroup and Kind in the
// roleRef are needed to be considered.
if (!isRoleRef || id.IsSelected(roleRefGvk)) &&
id.IsSelected(&target) && res.GetOriginalName() == oldName {
if id.IsSelected(&target) && res.GetOriginalName() == oldName {
matches := referralCandidates.GetMatchingResourcesByOriginalId(id.Equals)
// If there's more than one match,
// filter the matches by prefix and suffix
if len(matches) > 1 {
filteredMatches := filterReferralCandidates(referrer, matches, target)
filteredMatches := filterReferralCandidates(referrer, matches)
if len(filteredMatches) > 1 {
return "", "", fmt.Errorf(
"multiple matches for %s:\n %v",
@@ -209,11 +147,10 @@ func getSimpleNameField(
referrer *resource.Resource,
target resid.Gvk,
referralCandidates resmap.ResMap,
referralCandidateSubset []*resource.Resource,
isRoleRef bool) (string, error) {
referralCandidateSubset []*resource.Resource) (string, error) {
newName, _, err := selectReferral(oldName, referrer, target,
referralCandidates, referralCandidateSubset, isRoleRef)
referralCandidates, referralCandidateSubset)
return newName, err
}
@@ -232,8 +169,7 @@ func setNameAndNs(
in *yaml.RNode,
referrer *resource.Resource,
target resid.Gvk,
referralCandidates resmap.ResMap,
isRoleRef bool) error {
referralCandidates resmap.ResMap) error {
if in.YNode().Kind != yaml.MappingNode {
return fmt.Errorf("expect a mapping node")
@@ -269,7 +205,7 @@ func setNameAndNs(
oldName := nameNode.YNode().Value
newname, newnamespace, err := selectReferral(oldName, referrer, target,
referralCandidates, subset, isRoleRef)
referralCandidates, subset)
if err != nil {
return err
}

View File

@@ -5,9 +5,10 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/api/provider"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
"sigs.k8s.io/kustomize/api/types"
)
@@ -167,44 +168,6 @@ metadata:
map:
name: newName
namespace: oldNs
`,
filter: Filter{
FieldSpec: types.FieldSpec{Path: "map"},
Target: resid.Gvk{
Group: "apps",
Version: "v1",
Kind: "Secret",
},
},
},
"null value": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
map:
name: null
`,
candidates: `
apiVersion: apps/v1
kind: Secret
metadata:
name: newName
---
apiVersion: apps/v1
kind: NotSecret
metadata:
name: newName2
`,
originalNames: []string{"oldName", ""},
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
map:
name: null
`,
filter: Filter{
FieldSpec: types.FieldSpec{Path: "map"},
@@ -219,7 +182,7 @@ map:
for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
factory := provider.NewDefaultDepProvider().GetResourceFactory()
factory := resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())
referrer, err := factory.FromBytes([]byte(tc.input))
if err != nil {
t.Fatal(err)
@@ -254,6 +217,27 @@ func TestNamerefFilterUnhappy(t *testing.T) {
filter Filter
originalNames []string
}{
"invalid node type": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
ref:
name: null
`,
candidates: "",
originalNames: []string{},
expected: "obj '' at path 'ref/name': node is expected to be either a string or a slice of string or a map of string",
filter: Filter{
FieldSpec: types.FieldSpec{Path: "ref/name"},
Target: resid.Gvk{
Group: "apps",
Version: "v1",
Kind: "Secret",
},
},
},
"multiple match": {
input: `
apiVersion: apps/v1
@@ -320,7 +304,7 @@ metadata:
for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
factory := provider.NewDefaultDepProvider().GetResourceFactory()
factory := resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())
referrer, err := factory.FromBytes([]byte(tc.input))
if err != nil {
t.Fatal(err)
@@ -731,7 +715,7 @@ ref:
for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
factory := provider.NewDefaultDepProvider().GetResourceFactory()
factory := resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())
referrer, err := factory.FromBytes([]byte(tc.input))
if err != nil {
t.Fatal(err)

View File

@@ -69,7 +69,7 @@ func (ns Filter) hacks(obj *yaml.RNode) error {
// metaNamespaceHack is a hack for implementing the namespace transform
// for the metadata.namespace field on namespace scoped resources.
// namespace scoped resources are determined by NOT being present
// in a hard-coded list of cluster-scoped resource types (by apiVersion and kind).
// in a blacklist of cluster-scoped resource types (by apiVersion and kind).
//
// This hack should be updated to allow individual resources to specify
// if they are cluster scoped through either an annotation on the resources,

View File

@@ -194,47 +194,47 @@ metadata:
{
name: "update-clusterrolebinding",
input: `
apiVersion: rbac.authorization.k8s.io/v1
apiVersion: example.com/v1
kind: ClusterRoleBinding
subjects:
- name: default
---
apiVersion: rbac.authorization.k8s.io/v1
apiVersion: example.com/v1
kind: ClusterRoleBinding
subjects:
- name: default
namespace: foo
---
apiVersion: rbac.authorization.k8s.io/v1
apiVersion: example.com/v1
kind: ClusterRoleBinding
subjects:
- name: something
---
apiVersion: rbac.authorization.k8s.io/v1
apiVersion: example.com/v1
kind: ClusterRoleBinding
subjects:
- name: something
namespace: foo
`,
expected: `
apiVersion: rbac.authorization.k8s.io/v1
apiVersion: example.com/v1
kind: ClusterRoleBinding
subjects:
- name: default
namespace: bar
---
apiVersion: rbac.authorization.k8s.io/v1
apiVersion: example.com/v1
kind: ClusterRoleBinding
subjects:
- name: default
namespace: bar
---
apiVersion: rbac.authorization.k8s.io/v1
apiVersion: example.com/v1
kind: ClusterRoleBinding
subjects:
- name: something
---
apiVersion: rbac.authorization.k8s.io/v1
apiVersion: example.com/v1
kind: ClusterRoleBinding
subjects:
- name: something

View File

@@ -18,12 +18,7 @@ var _ kio.Filter = Filter{}
func (pf Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
var result []*yaml.RNode
for i := range nodes {
r, err := merge2.Merge(
pf.Patch, nodes[i],
yaml.MergeOptions{
ListIncreaseDirection: yaml.MergeOptionsListPrepend,
},
)
r, err := merge2.Merge(pf.Patch, nodes[i])
if err != nil {
return nil, err
}

View File

@@ -15,78 +15,6 @@ func TestFilter(t *testing.T) {
patch *yaml.RNode
expected string
}{
"nullMapEntry1": {
input: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: my-foo
spec:
bar:
B:
C: Z
`,
patch: yaml.MustParse(`
apiVersion: example.com/v1
kind: Foo
metadata:
name: my-foo
spec:
bar:
C: Z
D: W
baz:
hello: world
`),
expected: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: my-foo
spec:
bar:
C: Z
D: W
baz:
hello: world
`,
},
"nullMapEntry2": {
input: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: my-foo
spec:
bar:
C: Z
D: W
baz:
hello: world
`,
patch: yaml.MustParse(`
apiVersion: example.com/v1
kind: Foo
metadata:
name: my-foo
spec:
bar:
B:
C: Z
`),
expected: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: my-foo
spec:
bar:
C: Z
D: W
baz:
hello: world
`,
},
"simple patch": {
input: `
apiVersion: apps/v1
@@ -139,10 +67,10 @@ spec:
template:
spec:
containers:
- name: foo0
- name: foo1
- name: foo2
- name: foo3
- name: foo0
`,
},
"volumes patch": {
@@ -179,10 +107,10 @@ spec:
template:
spec:
volumes:
- name: foo0
- name: foo1
- name: foo2
- name: foo3
- name: foo0
`,
},
"nested patch": {
@@ -214,441 +142,6 @@ spec:
- name: nginx
args:
- def
`,
},
"remove mapping - directive": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
template:
spec:
containers:
- name: test
image: test
`,
patch: yaml.MustParse(`
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
template:
spec:
containers:
- name: test
image: test
$patch: delete
`),
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
template:
spec:
containers: []
`,
},
"replace mapping - directive": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
template:
spec:
containers:
- name: test
image: test
`,
patch: yaml.MustParse(`
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
template:
spec:
$patch: replace
containers:
- name: new
`),
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
template:
spec:
containers:
- name: new
`,
},
"merge mapping - directive": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
template:
spec:
containers:
- name: test
image: test
`,
patch: yaml.MustParse(`
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
template:
spec:
containers:
- name: test
image: test1
$patch: merge
`),
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
template:
spec:
containers:
- name: test
image: test1
`,
},
"remove list - directive": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
template:
spec:
containers:
- name: test
image: test
`,
patch: yaml.MustParse(`
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
template:
spec:
containers:
- whatever
- $patch: delete
`),
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
template:
spec: {}
`,
},
"replace list - directive": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
template:
spec:
containers:
- name: test
image: test
`,
patch: yaml.MustParse(`
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
template:
spec:
containers:
- name: replace
image: replace
- $patch: replace
`),
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
template:
spec:
containers:
- name: replace
image: replace
`,
},
"merge list - directive": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
template:
spec:
containers:
- name: test
image: test
`,
patch: yaml.MustParse(`
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
template:
spec:
containers:
- name: test2
image: test2
- $patch: merge
`),
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
template:
spec:
containers:
- name: test2
image: test2
- name: test
image: test
`,
},
"list map keys - add a port, no names": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment
spec:
template:
spec:
containers:
- image: test-image
name: test-deployment
ports:
- containerPort: 8080
protocol: TCP
`,
patch: yaml.MustParse(`
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment
spec:
template:
spec:
containers:
- image: test-image
name: test-deployment
ports:
- containerPort: 8080
protocol: UDP
- containerPort: 80
protocol: UDP
`),
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment
spec:
template:
spec:
containers:
- image: test-image
name: test-deployment
ports:
- containerPort: 8080
protocol: UDP
- containerPort: 80
protocol: UDP
- containerPort: 8080
protocol: TCP
`,
},
"list map keys - add name to port": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment
spec:
template:
spec:
containers:
- image: test-image
name: test-deployment
ports:
- containerPort: 8080
protocol: UDP
- containerPort: 8080
protocol: TCP
`,
patch: yaml.MustParse(`
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment
spec:
template:
spec:
containers:
- image: test-image
name: test-deployment
ports:
- containerPort: 8080
protocol: UDP
name: UDP-name-patch
`),
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment
spec:
template:
spec:
containers:
- image: test-image
name: test-deployment
ports:
- containerPort: 8080
protocol: UDP
name: UDP-name-patch
- containerPort: 8080
protocol: TCP
`,
},
"list map keys - replace port name": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment
spec:
template:
spec:
containers:
- image: test-image
name: test-deployment
ports:
- containerPort: 8080
protocol: UDP
name: UDP-name-original
- containerPort: 8080
protocol: TCP
name: TCP-name-original
`,
patch: yaml.MustParse(`
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment
spec:
template:
spec:
containers:
- image: test-image
name: test-deployment
ports:
- containerPort: 8080
protocol: UDP
name: UDP-name-patch
`),
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment
spec:
template:
spec:
containers:
- image: test-image
name: test-deployment
ports:
- containerPort: 8080
protocol: UDP
name: UDP-name-patch
- containerPort: 8080
protocol: TCP
name: TCP-name-original
`,
},
"list map keys - add a port, no protocol": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment
spec:
template:
spec:
containers:
- image: test-image
name: test-deployment
ports:
- containerPort: 8080
`,
patch: yaml.MustParse(`
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment
spec:
template:
spec:
containers:
- image: test-image
name: test-deployment
ports:
- containerPort: 80
`),
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment
spec:
template:
spec:
containers:
- image: test-image
name: test-deployment
ports:
- containerPort: 80
- containerPort: 8080
`,
},
}

View File

@@ -188,26 +188,6 @@ data:
FieldSpec: types.FieldSpec{Path: "data/slice2"},
},
},
"null value": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
data:
FOO: null`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
data:
FOO: null`,
filter: Filter{
MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{}),
FieldSpec: types.FieldSpec{Path: "data/FOO"},
},
},
}
for tn, tc := range testCases {
@@ -280,6 +260,20 @@ data:
FieldSpec: types.FieldSpec{Path: "data"},
},
},
"null input": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
data:
FOO: null`,
expectedError: "obj '' at path 'data/FOO': invalid type encountered 0",
filter: Filter{
MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{}),
FieldSpec: types.FieldSpec{Path: "data/FOO"},
},
},
}
for tn, tc := range testCases {

View File

@@ -1,25 +1,24 @@
module sigs.k8s.io/kustomize/api
go 1.15
go 1.14
require (
github.com/evanphx/json-patch v4.5.0+incompatible
github.com/go-errors/errors v1.0.1
github.com/go-openapi/spec v0.19.5
github.com/golangci/golangci-lint v1.21.0
github.com/google/go-cmp v0.3.0
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/hashicorp/go-multierror v1.1.0
github.com/pkg/errors v0.8.1
github.com/stretchr/testify v1.4.0
github.com/yujunz/go-getter v1.5.1-lite.0.20201201013212-6d9c071adddf
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e
github.com/yujunz/go-getter v1.4.1-lite
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff
gopkg.in/yaml.v2 v2.3.0
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71
k8s.io/api v0.17.0
k8s.io/apimachinery v0.17.0
k8s.io/client-go v0.17.0
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a
sigs.k8s.io/kustomize/kyaml v0.10.3
sigs.k8s.io/kustomize/kyaml v0.6.1
sigs.k8s.io/yaml v1.2.0
)
replace sigs.k8s.io/kustomize/kyaml v0.6.1 => ../kyaml

View File

@@ -158,7 +158,6 @@ github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUD
github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
github.com/go-toolsmith/typep v1.0.0 h1:zKymWyA1TRYvqYrYDrfEMZULyrhcnGY3x7LDKU2XQaA=
github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU=
github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b h1:ekuhfTjngPhisSjOJ0QWKpPQE8/rbknHaes6WVJj5Hw=
@@ -167,7 +166,6 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -227,7 +225,6 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3 h1:JVnpOZS+qxli+rgVl98ILOXVNbW+kb5wcxeGx8ShUIw=
github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
@@ -235,12 +232,8 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0=
@@ -290,7 +283,6 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI=
github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb h1:RHba4YImhrUVQDHUCe2BNSOz4tVy2yGyXhvYDvxGgeE=
github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
@@ -315,8 +307,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
github.com/mozilla/tls-observatory v0.0.0-20190404164649-a3c1b6cfecfd/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@@ -369,7 +359,6 @@ github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e h1:MZM7FHLqUHYI0Y/mQAt
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041 h1:llrF3Fs4018ePo4+G/HV/uQUqEI1HMDjCeOf2V6puPc=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
@@ -411,8 +400,8 @@ github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiff
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ=
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok=
github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
github.com/ultraware/funlen v0.0.2 h1:Av96YVBwwNSe4MLR7iI/BIa3VyI7/djnto/pK3Uxbdo=
github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
github.com/ultraware/whitespace v0.0.4 h1:If7Va4cM03mpgrNH9k49/VOicWpGoG70XPBFFODYDsg=
@@ -428,8 +417,8 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI=
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yujunz/go-getter v1.5.1-lite.0.20201201013212-6d9c071adddf h1:gvEmqF83GB8R5XtrMseJb6A6R0OCtNAS8f4TmZg2dGc=
github.com/yujunz/go-getter v1.5.1-lite.0.20201201013212-6d9c071adddf/go.mod h1:bL0Pr07HEdsMZ1WBqZIxXj96r5LnFsY4LgPaPEGkw1k=
github.com/yujunz/go-getter v1.4.1-lite h1:FhvNc94AXMZkfqUwfMKhnQEC9phkphSGdPTL7tIdhOM=
github.com/yujunz/go-getter v1.4.1-lite/go.mod h1:sbmqxXjyLunH1PkF3n7zSlnVeMvmYUuIl9ZVs/7NyCc=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
@@ -537,8 +526,6 @@ golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20190930201159-7c411dea38b0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff h1:XdBG6es/oFDr1HwaxkxgVve7NB281QhxgK/i4voubFs=
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e h1:aZzprAO9/8oim3qStq3wc1Xuxx4QmAGriC4VU4ojemQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
@@ -566,7 +553,6 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
@@ -598,8 +584,6 @@ mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphD
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f h1:Cq7MalBHYACRd6EesksG1Q8EoIAKOsiZviGKbOLIej4=
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw=
sigs.k8s.io/kustomize/kyaml v0.10.3 h1:ARSJUMN/c3k31DYxRfZ+vp/UepUQjg9zCwny7Oj908I=
sigs.k8s.io/kustomize/kyaml v0.10.3/go.mod h1:RA+iCHA2wPCOfv6uG6TfXXWhYsHpgErq/AljxWKuxtg=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=

View File

@@ -8,14 +8,17 @@ import (
"testing"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
"sigs.k8s.io/kustomize/api/provider"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
resmaptest_test "sigs.k8s.io/kustomize/api/testutils/resmaptest"
)
func TestNameReferenceHappyRun(t *testing.T) {
m := resmaptest_test.NewRmBuilderDefault(t).AddWithName(
rf := resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl())
m := resmaptest_test.NewRmBuilder(t, rf).AddWithName(
"cm1",
map[string]interface{}{
"apiVersion": "v1",
@@ -258,8 +261,7 @@ func TestNameReferenceHappyRun(t *testing.T) {
},
}).ResMap()
expected := resmaptest_test.NewSeededRmBuilderDefault(
t, m.ShallowCopy()).ReplaceResource(
expected := resmaptest_test.NewSeededRmBuilder(t, rf, m.ShallowCopy()).ReplaceResource(
map[string]interface{}{
"group": "apps",
"apiVersion": "v1",
@@ -473,12 +475,14 @@ func TestNameReferenceHappyRun(t *testing.T) {
}
func TestNameReferenceUnhappyRun(t *testing.T) {
rf := resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl())
tests := []struct {
resMap resmap.ResMap
expectedErr string
}{
{
resMap: resmaptest_test.NewRmBuilderDefault(t).Add(
resMap: resmaptest_test.NewRmBuilder(t, rf).Add(
map[string]interface{}{
"apiVersion": "rbac.authorization.k8s.io/v1",
"kind": "ClusterRole",
@@ -498,7 +502,7 @@ func TestNameReferenceUnhappyRun(t *testing.T) {
}).ResMap(),
expectedErr: "is expected to be"},
{
resMap: resmaptest_test.NewRmBuilderDefault(t).Add(
resMap: resmaptest_test.NewRmBuilder(t, rf).Add(
map[string]interface{}{
"apiVersion": "rbac.authorization.k8s.io/v1",
"kind": "ClusterRole",
@@ -534,7 +538,8 @@ func TestNameReferenceUnhappyRun(t *testing.T) {
}
func TestNameReferencePersistentVolumeHappyRun(t *testing.T) {
rf := provider.NewDefaultDepProvider().GetResourceFactory()
rf := resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl())
v1 := rf.FromMapWithName(
"volume1",
@@ -659,7 +664,9 @@ const (
// object with the same original names (uniquename) in different namespaces
// and with different current Id.
func TestNameReferenceNamespace(t *testing.T) {
m := resmaptest_test.NewRmBuilderDefault(t).
rf := resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl())
m := resmaptest_test.NewRmBuilder(t, rf).
// Add ConfigMap with the same org name in noNs, "ns1" and "ns2" namespaces
AddWithName(orgname, map[string]interface{}{
"apiVersion": "v1",
@@ -708,7 +715,7 @@ func TestNameReferenceNamespace(t *testing.T) {
AddWithNsAndName(ns1, orgname, deploymentMap(ns1, prefixedname, orgname, orgname)).
AddWithNsAndName(ns2, orgname, deploymentMap(ns2, suffixedname, orgname, orgname)).ResMap()
expected := resmaptest_test.NewSeededRmBuilderDefault(t, m.ShallowCopy()).
expected := resmaptest_test.NewSeededRmBuilder(t, rf, m.ShallowCopy()).
ReplaceResource(deploymentMap(defaultNs, modifiedname, modifiedname, modifiedname)).
ReplaceResource(deploymentMap(ns1, prefixedname, prefixedname, prefixedname)).
ReplaceResource(deploymentMap(ns2, suffixedname, suffixedname, suffixedname)).ResMap()
@@ -728,7 +735,9 @@ func TestNameReferenceNamespace(t *testing.T) {
// object with the same original names (uniquename) in different namespaces
// and with different current Id.
func TestNameReferenceClusterWide(t *testing.T) {
m := resmaptest_test.NewRmBuilderDefault(t).
rf := resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl())
m := resmaptest_test.NewRmBuilder(t, rf).
// Add ServiceAccount with the same org name in noNs, "ns1" and "ns2" namespaces
AddWithName(orgname, map[string]interface{}{
"apiVersion": "v1",
@@ -780,9 +789,9 @@ func TestNameReferenceClusterWide(t *testing.T) {
"name": modifiedname,
},
"roleRef": map[string]interface{}{
"apiGroup": "rbac.authorization.k8s.io",
"kind": "ClusterRole",
"name": orgname,
"apiVersion": "rbac.authorization.k8s.io/v1",
"kind": "ClusterRole",
"name": orgname,
},
"subjects": []interface{}{
map[string]interface{}{
@@ -807,7 +816,7 @@ func TestNameReferenceClusterWide(t *testing.T) {
},
}}).ResMap()
expected := resmaptest_test.NewSeededRmBuilderDefault(t, m.ShallowCopy()).
expected := resmaptest_test.NewSeededRmBuilder(t, rf, m.ShallowCopy()).
ReplaceResource(
map[string]interface{}{
"apiVersion": "rbac.authorization.k8s.io/v1",
@@ -836,9 +845,9 @@ func TestNameReferenceClusterWide(t *testing.T) {
"name": modifiedname,
},
"roleRef": map[string]interface{}{
"apiGroup": "rbac.authorization.k8s.io",
"kind": "ClusterRole",
"name": modifiedname,
"apiVersion": "rbac.authorization.k8s.io/v1",
"kind": "ClusterRole",
"name": modifiedname,
},
// The following tests required a change in
// getNameFunc implementation in order to leverage
@@ -889,7 +898,9 @@ func TestNameReferenceClusterWide(t *testing.T) {
// object with the same original names (uniquename) in different namespaces
// and with different current Id.
func TestNameReferenceNamespaceTransformation(t *testing.T) {
m := resmaptest_test.NewRmBuilderDefault(t).
rf := resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl())
m := resmaptest_test.NewRmBuilder(t, rf).
AddWithNsAndName(ns4, orgname, map[string]interface{}{
"apiVersion": "v1",
"kind": "Secret",
@@ -926,9 +937,9 @@ func TestNameReferenceNamespaceTransformation(t *testing.T) {
"name": modifiedname,
},
"roleRef": map[string]interface{}{
"apiGroup": "rbac.authorization.k8s.io",
"kind": "ClusterRole",
"name": orgname,
"apiVersion": "rbac.authorization.k8s.io/v1",
"kind": "ClusterRole",
"name": orgname,
},
"subjects": []interface{}{
map[string]interface{}{
@@ -953,7 +964,7 @@ func TestNameReferenceNamespaceTransformation(t *testing.T) {
},
}}).ResMap()
expected := resmaptest_test.NewSeededRmBuilderDefault(t, m.ShallowCopy()).
expected := resmaptest_test.NewSeededRmBuilder(t, rf, m.ShallowCopy()).
ReplaceResource(
map[string]interface{}{
"apiVersion": "rbac.authorization.k8s.io/v1",
@@ -962,9 +973,9 @@ func TestNameReferenceNamespaceTransformation(t *testing.T) {
"name": modifiedname,
},
"roleRef": map[string]interface{}{
"apiGroup": "rbac.authorization.k8s.io",
"kind": "ClusterRole",
"name": modifiedname,
"apiVersion": "rbac.authorization.k8s.io/v1",
"kind": "ClusterRole",
"name": modifiedname,
},
// The following tests required a change in
// getNameFunc implementation in order to leverage
@@ -1015,7 +1026,9 @@ func TestNameReferenceNamespaceTransformation(t *testing.T) {
// It validates the change done is IsSameFuzzyNamespace which
// uses the IsNsEquals method instead of the simple == operator.
func TestNameReferenceCandidateSelection(t *testing.T) {
m := resmaptest_test.NewRmBuilderDefault(t).
rf := resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl())
m := resmaptest_test.NewRmBuilder(t, rf).
AddWithName("cm1", map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
@@ -1032,7 +1045,7 @@ func TestNameReferenceCandidateSelection(t *testing.T) {
AddWithName("deploy1", deploymentMap("", "p1-deploy1", "cm1", "secret1")).
ResMap()
expected := resmaptest_test.NewSeededRmBuilderDefault(t, m.ShallowCopy()).
expected := resmaptest_test.NewSeededRmBuilder(t, rf, m.ShallowCopy()).
ReplaceResource(deploymentMap("", "p1-deploy1", "p1-cm1-hash", "p1-secret1-hash")).
ResMap()

View File

@@ -7,8 +7,10 @@ import (
"reflect"
"testing"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
resmaptest_test "sigs.k8s.io/kustomize/api/testutils/resmaptest"
"sigs.k8s.io/kustomize/api/types"
)
@@ -44,7 +46,8 @@ func TestRefVarTransformer(t *testing.T) {
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/interface"},
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/num"},
},
res: resmaptest_test.NewRmBuilderDefault(t).
res: resmaptest_test.NewRmBuilder(
t, resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())).
Add(map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
@@ -74,7 +77,8 @@ func TestRefVarTransformer(t *testing.T) {
}}).ResMap(),
},
expected: expected{
res: resmaptest_test.NewRmBuilderDefault(t).
res: resmaptest_test.NewRmBuilder(
t, resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())).
Add(map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
@@ -112,7 +116,8 @@ func TestRefVarTransformer(t *testing.T) {
fs: []types.FieldSpec{
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/slice"},
},
res: resmaptest_test.NewRmBuilderDefault(t).
res: resmaptest_test.NewRmBuilder(
t, resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())).
Add(map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
@@ -127,25 +132,14 @@ func TestRefVarTransformer(t *testing.T) {
' at path 'data/slice': invalid value type expect a string`,
},
{
description: "var replacement in nil",
description: "var replacement panic in nil",
given: given{
varMap: map[string]interface{}{},
fs: []types.FieldSpec{
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/nil"},
},
res: resmaptest_test.NewRmBuilderDefault(t).
Add(map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{
"name": "cm1",
},
"data": map[string]interface{}{
"nil": nil, // noticeably *not* a []string
}}).ResMap(),
},
expected: expected{
res: resmaptest_test.NewRmBuilderDefault(t).
res: resmaptest_test.NewRmBuilder(
t, resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())).
Add(map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
@@ -156,6 +150,7 @@ func TestRefVarTransformer(t *testing.T) {
"nil": nil, // noticeably *not* a []string
}}).ResMap(),
},
errMessage: `obj '' at path 'data/nil': invalid type encountered 0`,
},
}

View File

@@ -12,7 +12,7 @@ import (
. "sigs.k8s.io/kustomize/api/internal/accumulator"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
"sigs.k8s.io/kustomize/api/provider"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
@@ -20,14 +20,16 @@ import (
"sigs.k8s.io/kustomize/api/types"
)
func makeResAccumulator(t *testing.T) *ResAccumulator {
func makeResAccumulator(t *testing.T) (*ResAccumulator, *resource.Factory) {
ra := MakeEmptyAccumulator()
err := ra.MergeConfig(builtinconfig.MakeDefaultConfig())
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
rf := resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl())
err = ra.AppendAll(
resmaptest_test.NewRmBuilderDefault(t).
resmaptest_test.NewRmBuilder(t, rf).
Add(map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
@@ -64,11 +66,11 @@ func makeResAccumulator(t *testing.T) *ResAccumulator {
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
return ra
return ra, rf
}
func TestResolveVarsHappy(t *testing.T) {
ra := makeResAccumulator(t)
ra, _ := makeResAccumulator(t)
err := ra.MergeVars([]types.Var{
{
Name: "SERVICE_ONE",
@@ -97,7 +99,7 @@ func TestResolveVarsHappy(t *testing.T) {
}
func TestResolveVarsOneUnused(t *testing.T) {
ra := makeResAccumulator(t)
ra, _ := makeResAccumulator(t)
err := ra.MergeVars([]types.Var{
{
Name: "SERVICE_ONE",
@@ -138,10 +140,11 @@ func expectLog(t *testing.T, log bytes.Buffer, expect string) {
}
func TestResolveVarsVarNeedsDisambiguation(t *testing.T) {
ra := makeResAccumulator(t)
ra, rf := makeResAccumulator(t)
rm0 := resmap.New()
err := rm0.Append(
provider.NewDefaultDepProvider().GetResourceFactory().FromMap(
rf.FromMap(
map[string]interface{}{
"apiVersion": "v1",
"kind": "Service",
@@ -210,7 +213,8 @@ func makeVarToNamepaceAndPath(
}
func TestResolveVarConflicts(t *testing.T) {
rf := provider.NewDefaultDepProvider().GetResourceFactory()
rf := resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())
// create configmaps in foo and bar namespaces with `data.provider` values.
fooAws := makeNamespacedConfigMapWithDataProviderValue("foo", "aws")
barAws := makeNamespacedConfigMapWithDataProviderValue("bar", "aws")
@@ -257,7 +261,7 @@ func TestResolveVarConflicts(t *testing.T) {
}
func TestResolveVarsGoodResIdBadField(t *testing.T) {
ra := makeResAccumulator(t)
ra, _ := makeResAccumulator(t)
err := ra.MergeVars([]types.Var{
{
Name: "SERVICE_ONE",
@@ -282,7 +286,7 @@ func TestResolveVarsGoodResIdBadField(t *testing.T) {
}
func TestResolveVarsUnmappableVar(t *testing.T) {
ra := makeResAccumulator(t)
ra, _ := makeResAccumulator(t)
err := ra.MergeVars([]types.Var{
{
Name: "SERVICE_THREE",
@@ -306,7 +310,7 @@ func TestResolveVarsUnmappableVar(t *testing.T) {
}
func TestResolveVarsWithNoambiguation(t *testing.T) {
ra1 := makeResAccumulator(t)
ra1, rf := makeResAccumulator(t)
err := ra1.MergeVars([]types.Var{
{
Name: "SERVICE_ONE",
@@ -323,7 +327,7 @@ func TestResolveVarsWithNoambiguation(t *testing.T) {
// Create another accumulator having a resource with different prefix
ra2 := MakeEmptyAccumulator()
m := resmaptest_test.NewRmBuilderDefault(t).
m := resmaptest_test.NewRmBuilder(t, rf).
Add(map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",

View File

@@ -1,23 +0,0 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package conflict
import (
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resource"
)
type cdFactory struct{}
var _ resource.ConflictDetectorFactory = &cdFactory{}
// NewFactory returns a new conflict detector factory.
func NewFactory() resource.ConflictDetectorFactory {
return &cdFactory{}
}
// New returns an instance of smPatchMergeOnlyDetector.
func (c cdFactory) New(_ resid.Gvk) (resource.ConflictDetector, error) {
return &smPatchMergeOnlyDetector{}, nil
}

View File

@@ -1,28 +0,0 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package conflict
import (
"sigs.k8s.io/kustomize/api/resource"
)
// smPatchMergeOnlyDetector ignores conflicts,
// but does real strategic merge patching.
// This is part of an effort to eliminate dependence on
// apimachinery package to allow kustomize integration
// into kubectl (#2506 and #1500)
type smPatchMergeOnlyDetector struct{}
var _ resource.ConflictDetector = &smPatchMergeOnlyDetector{}
func (c *smPatchMergeOnlyDetector) HasConflict(
_, _ *resource.Resource) (bool, error) {
return false, nil
}
func (c *smPatchMergeOnlyDetector) MergePatches(
r, patch *resource.Resource) (*resource.Resource, error) {
err := r.ApplySmPatch(patch)
return r, err
}

View File

@@ -217,7 +217,7 @@ overview of each component with the following sections going into more details.
The overall structure is outlined in the following figure:
![overview](
https://github.com/kubernetes-sigs/kustomize/blob/master/api/internal/crawl/pictures/token_config.png)
https://sigs.k8s.io/kustomize/internal/tools/pictures/sys_arch.png)
#### Crawler
The leftmost component consists of a crawler with an http cache of GitHub

View File

@@ -7,13 +7,14 @@ import (
"sort"
"strings"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/provider"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/yaml"
)
var fileReader = kunstruct.NewKunstructuredFactoryImpl()
// This document is meant to be used at the elasticsearch document type.
// Fields are serialized as-is to elasticsearch, where indices are built
// to facilitate text search queries. Identifiers, Values, FilePath,
@@ -41,7 +42,6 @@ type KustomizationDocument struct {
Kinds []string `json:"kinds,omitempty"`
Identifiers []string `json:"identifiers,omitempty"`
Values []string `json:"values,omitempty"`
resFactory *resource.Factory
}
type set map[string]struct{}
@@ -52,7 +52,6 @@ func (doc *KustomizationDocument) Copy() *KustomizationDocument {
Kinds: doc.Kinds,
Identifiers: doc.Identifiers,
Values: doc.Values,
resFactory: provider.NewDefaultDepProvider().GetResourceFactory(),
}
}
@@ -151,7 +150,7 @@ func (doc *KustomizationDocument) readBytes() ([]map[string]interface{}, error)
}
configs := make([]map[string]interface{}, 0)
ks, err := doc.resFactory.SliceFromBytes(data)
ks, err := fileReader.SliceFromBytes(data)
if err != nil {
return nil, fmt.Errorf("unable to parse resource: %v", err)
}

View File

@@ -1,6 +1,6 @@
module sigs.k8s.io/kustomize/api/internal/crawl
go 1.15
go 1.14
require (
github.com/elastic/go-elasticsearch/v6 v6.8.5

View File

@@ -145,7 +145,6 @@ github.com/go-toolsmith/pkgload v0.0.0-20181119091011-e9e65178eee8/go.mod h1:WoM
github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc=
github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU=
github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -207,10 +206,8 @@ github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:Fecb
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0=
@@ -254,7 +251,6 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI=
github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
@@ -275,8 +271,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
github.com/mozilla/tls-observatory v0.0.0-20190404164649-a3c1b6cfecfd/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@@ -319,7 +313,6 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/securego/gosec v0.0.0-20191002120514-e680875ea14d/go.mod h1:w5+eXa0mYznDkHaMCXA4XYffjlH+cy1oyKbfzJXa2Do=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
@@ -358,8 +351,8 @@ github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiff
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ=
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok=
github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA=
github.com/uudashr/gocognit v0.0.0-20190926065955-1655d0de0517/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM=
@@ -372,8 +365,8 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI=
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yujunz/go-getter v1.5.1-lite.0.20201201013212-6d9c071adddf h1:gvEmqF83GB8R5XtrMseJb6A6R0OCtNAS8f4TmZg2dGc=
github.com/yujunz/go-getter v1.5.1-lite.0.20201201013212-6d9c071adddf/go.mod h1:bL0Pr07HEdsMZ1WBqZIxXj96r5LnFsY4LgPaPEGkw1k=
github.com/yujunz/go-getter v1.4.1-lite h1:FhvNc94AXMZkfqUwfMKhnQEC9phkphSGdPTL7tIdhOM=
github.com/yujunz/go-getter v1.4.1-lite/go.mod h1:sbmqxXjyLunH1PkF3n7zSlnVeMvmYUuIl9ZVs/7NyCc=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
@@ -477,7 +470,6 @@ golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDq
golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190930201159-7c411dea38b0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
@@ -506,7 +498,6 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
@@ -533,8 +524,8 @@ k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw=
sigs.k8s.io/kustomize/kyaml v0.10.3 h1:ARSJUMN/c3k31DYxRfZ+vp/UepUQjg9zCwny7Oj908I=
sigs.k8s.io/kustomize/kyaml v0.10.3/go.mod h1:RA+iCHA2wPCOfv6uG6TfXXWhYsHpgErq/AljxWKuxtg=
sigs.k8s.io/kustomize/kyaml v0.6.1 h1:mwffj5vt3MPdbWV3fZnnwol8SO7sUoGdgejBlvseyak=
sigs.k8s.io/kustomize/kyaml v0.6.1/go.mod h1:bEzbO5pN9OvlEeCLvFHo8Pu7SA26Herc2m60UeWZBdI=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=

View File

@@ -1,51 +0,0 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package generators
import (
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// MakeConfigMap makes a configmap.
//
// ConfigMap: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#configmap-v1-core
//
// ConfigMaps and Secrets are similar.
//
// Both objects have a `data` field, which contains a map from keys to
// values that must be UTF-8 valid strings. Such data might be simple text,
// or whoever made the data may have done so by performing a base64 encoding
// on binary data. Regardless, k8s has no means to know this, so it treats
// the data field as a string.
//
// The ConfigMap has an additional field `binaryData`, also a map, but its
// values are _intended_ to be interpreted as a base64 encoding of []byte,
// by whatever makes use of the ConfigMap.
//
// In a ConfigMap, any key used in `data` cannot also be used in `binaryData`
// and vice-versa. A key must be unique across both maps.
func MakeConfigMap(
ldr ifc.KvLoader, args *types.ConfigMapArgs) (rn *yaml.RNode, err error) {
rn, err = makeBaseNode("ConfigMap", args.Name, args.Namespace)
if err != nil {
return nil, err
}
m, err := makeValidatedDataMap(ldr, args.Name, args.KvPairSources)
if err != nil {
return nil, err
}
for _, k := range filtersutil.SortedMapKeys(m) {
fldName, vrN := makeConfigMapValueRNode(m[k])
if _, err = rn.Pipe(
yaml.LookupCreate(yaml.MappingNode, fldName),
yaml.SetField(k, vrN)); err != nil {
return nil, err
}
}
copyLabelsAndAnnotations(rn, args.Options)
return rn, err
}

View File

@@ -1,223 +0,0 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package generators_test
import (
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/api/filesys"
. "sigs.k8s.io/kustomize/api/internal/generators"
"sigs.k8s.io/kustomize/api/kv"
"sigs.k8s.io/kustomize/api/loader"
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
"sigs.k8s.io/kustomize/api/types"
)
var binaryHello = []byte{
0xff, // non-utf8
0x68, // h
0x65, // e
0x6c, // l
0x6c, // l
0x6f, // o
}
func manyHellos(count int) (result []byte) {
for i := 0; i < count; i++ {
result = append(result, binaryHello...)
}
return
}
func TestMakeConfigMap(t *testing.T) {
type expected struct {
out string
errMsg string
}
testCases := map[string]struct {
args types.ConfigMapArgs
exp expected
}{
"construct config map from env": {
args: types.ConfigMapArgs{
GeneratorArgs: types.GeneratorArgs{
Name: "envConfigMap",
KvPairSources: types.KvPairSources{
EnvSources: []string{
filepath.Join("configmap", "app.env"),
},
},
},
},
exp: expected{
out: `apiVersion: v1
kind: ConfigMap
metadata:
name: envConfigMap
data:
DB_PASSWORD: qwerty
DB_USERNAME: admin
`,
},
},
"construct config map from text file": {
args: types.ConfigMapArgs{
GeneratorArgs: types.GeneratorArgs{
Name: "fileConfigMap1",
KvPairSources: types.KvPairSources{
FileSources: []string{
filepath.Join("configmap", "app-init.ini"),
},
},
},
},
exp: expected{
out: `apiVersion: v1
kind: ConfigMap
metadata:
name: fileConfigMap1
data:
app-init.ini: |
FOO=bar
BAR=baz
`,
},
},
"construct config map from text and binary file": {
args: types.ConfigMapArgs{
GeneratorArgs: types.GeneratorArgs{
Name: "fileConfigMap2",
KvPairSources: types.KvPairSources{
FileSources: []string{
filepath.Join("configmap", "app-init.ini"),
filepath.Join("configmap", "app.bin"),
},
},
},
},
exp: expected{
out: `apiVersion: v1
kind: ConfigMap
metadata:
name: fileConfigMap2
data:
app-init.ini: |
FOO=bar
BAR=baz
binaryData:
app.bin: |
/2hlbGxv/2hlbGxv/2hlbGxv/2hlbGxv/2hlbGxv/2hlbGxv/2hlbGxv/2hlbGxv/2hlbG
xv/2hlbGxv/2hlbGxv/2hlbGxv/2hlbGxv/2hlbGxv/2hlbGxv/2hlbGxv/2hlbGxv/2hl
bGxv/2hlbGxv/2hlbGxv/2hlbGxv/2hlbGxv/2hlbGxv/2hlbGxv/2hlbGxv/2hlbGxv/2
hlbGxv/2hlbGxv/2hlbGxv/2hlbGxv
`,
},
},
"construct config map from literal": {
args: types.ConfigMapArgs{
GeneratorArgs: types.GeneratorArgs{
Name: "literalConfigMap1",
KvPairSources: types.KvPairSources{
LiteralSources: []string{"a=x", "b=y", "c=\"Hello World\"", "d='true'"},
},
Options: &types.GeneratorOptions{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
exp: expected{
out: `apiVersion: v1
kind: ConfigMap
metadata:
name: literalConfigMap1
labels:
foo: 'bar'
data:
a: x
b: y
c: Hello World
d: "true"
`,
},
},
"construct config map from literal with GeneratorOptions in ConfigMapArgs": {
args: types.ConfigMapArgs{
GeneratorArgs: types.GeneratorArgs{
Name: "literalConfigMap2",
KvPairSources: types.KvPairSources{
LiteralSources: []string{"a=x", "b=y", "c=\"Hello World\"", "d='true'"},
},
Options: &types.GeneratorOptions{
Labels: map[string]string{
"veggie": "celery",
"dog": "beagle",
"cat": "annoying",
},
Annotations: map[string]string{
"river": "Missouri",
"city": "Iowa City",
},
},
},
},
exp: expected{
out: `apiVersion: v1
kind: ConfigMap
metadata:
name: literalConfigMap2
labels:
cat: 'annoying'
dog: 'beagle'
veggie: 'celery'
annotations:
city: 'Iowa City'
river: 'Missouri'
data:
a: x
b: y
c: Hello World
d: "true"
`,
},
},
}
fSys := filesys.MakeFsInMemory()
fSys.WriteFile(
filesys.RootedPath("configmap", "app.env"),
[]byte("DB_USERNAME=admin\nDB_PASSWORD=qwerty\n"))
fSys.WriteFile(
filesys.RootedPath("configmap", "app-init.ini"),
[]byte("FOO=bar\nBAR=baz\n"))
fSys.WriteFile(
filesys.RootedPath("configmap", "app.bin"),
manyHellos(30))
kvLdr := kv.NewLoader(
loader.NewFileLoaderAtRoot(fSys),
valtest_test.MakeFakeValidator())
for n := range testCases {
tc := testCases[n]
t.Run(n, func(t *testing.T) {
rn, err := MakeConfigMap(kvLdr, &tc.args)
if err != nil {
if !assert.EqualError(t, err, tc.exp.errMsg) {
t.FailNow()
}
return
}
if tc.exp.errMsg != "" {
t.Fatalf("%s: should return error '%s'", n, tc.exp.errMsg)
}
output := rn.MustString()
if !assert.Equal(t, tc.exp.out, output) {
t.FailNow()
}
})
}
}

View File

@@ -1,60 +0,0 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package generators
import (
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// MakeSecret makes a kubernetes Secret.
//
// Secret: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#secret-v1-core
//
// ConfigMaps and Secrets are similar.
//
// Like a ConfigMap, a Secret has a `data` field, but unlike a ConfigMap it has
// no `binaryData` field.
//
// All of a Secret's data is assumed to be opaque in nature, and assumed to be
// base64 encoded from its original representation, regardless of whether the
// original data was UTF-8 text or binary.
//
// This encoding provides no secrecy. It's just a neutral, common means to
// represent opaque text and binary data. Beneath the base64 encoding
// is presumably further encoding under control of the Secret's consumer.
//
// A Secret has string field `type` which holds an identifier, used by the
// client, to choose the algorithm to interpret the `data` field. Kubernetes
// cannot make use of this data; it's up to a controller or some pod's service
// to interpret the value, using `type` as a clue as to how to do this.
func MakeSecret(
ldr ifc.KvLoader, args *types.SecretArgs) (rn *yaml.RNode, err error) {
rn, err = makeBaseNode("Secret", args.Name, args.Namespace)
if err != nil {
return nil, err
}
if _, err := rn.Pipe(
yaml.FieldSetter{
Name: "type",
Value: yaml.NewStringRNode("Opaque")}); err != nil {
return nil, err
}
m, err := makeValidatedDataMap(ldr, args.Name, args.KvPairSources)
if err != nil {
return nil, err
}
for _, k := range filtersutil.SortedMapKeys(m) {
vrN := makeSecretValueRNode(m[k])
if _, err = rn.Pipe(
yaml.LookupCreate(yaml.MappingNode, yaml.DataField),
yaml.SetField(k, vrN)); err != nil {
return nil, err
}
}
copyLabelsAndAnnotations(rn, args.Options)
return rn, err
}

View File

@@ -1,203 +0,0 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package generators_test
import (
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/api/filesys"
. "sigs.k8s.io/kustomize/api/internal/generators"
"sigs.k8s.io/kustomize/api/kv"
"sigs.k8s.io/kustomize/api/loader"
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
"sigs.k8s.io/kustomize/api/types"
)
func TestMakeSecret(t *testing.T) {
type expected struct {
out string
errMsg string
}
testCases := map[string]struct {
args types.SecretArgs
exp expected
}{
"construct secret from env": {
args: types.SecretArgs{
GeneratorArgs: types.GeneratorArgs{
Name: "envSecret",
KvPairSources: types.KvPairSources{
EnvSources: []string{
filepath.Join("secret", "app.env"),
},
},
},
},
exp: expected{
out: `apiVersion: v1
kind: Secret
metadata:
name: envSecret
type: Opaque
data:
DB_PASSWORD: cXdlcnR5
DB_USERNAME: YWRtaW4=
`,
},
},
"construct secret from text file": {
args: types.SecretArgs{
GeneratorArgs: types.GeneratorArgs{
Name: "fileSecret1",
KvPairSources: types.KvPairSources{
FileSources: []string{
filepath.Join("secret", "app-init.ini"),
},
},
},
},
exp: expected{
out: `apiVersion: v1
kind: Secret
metadata:
name: fileSecret1
type: Opaque
data:
app-init.ini: Rk9PPWJhcgpCQVI9YmF6Cg==
`,
},
},
"construct secret from text and binary file": {
args: types.SecretArgs{
GeneratorArgs: types.GeneratorArgs{
Name: "fileSecret2",
KvPairSources: types.KvPairSources{
FileSources: []string{
filepath.Join("secret", "app-init.ini"),
filepath.Join("secret", "app.bin"),
},
},
},
},
exp: expected{
out: `apiVersion: v1
kind: Secret
metadata:
name: fileSecret2
type: Opaque
data:
app-init.ini: Rk9PPWJhcgpCQVI9YmF6Cg==
app.bin: //0=
`,
},
},
"construct secret from literal": {
args: types.SecretArgs{
GeneratorArgs: types.GeneratorArgs{
Name: "literalSecret1",
KvPairSources: types.KvPairSources{
LiteralSources: []string{"a=x", "b=y", "c=\"Hello World\"", "d='true'"},
},
Options: &types.GeneratorOptions{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
exp: expected{
out: `apiVersion: v1
kind: Secret
metadata:
name: literalSecret1
labels:
foo: 'bar'
type: Opaque
data:
a: eA==
b: eQ==
c: SGVsbG8gV29ybGQ=
d: dHJ1ZQ==
`,
},
},
"construct secret from literal with GeneratorOptions in SecretArgs": {
args: types.SecretArgs{
GeneratorArgs: types.GeneratorArgs{
Name: "literalSecret2",
KvPairSources: types.KvPairSources{
LiteralSources: []string{"a=x", "b=y", "c=\"Hello World\"", "d='true'"},
},
Options: &types.GeneratorOptions{
Labels: map[string]string{
"veggie": "celery",
"dog": "beagle",
"cat": "annoying",
},
Annotations: map[string]string{
"river": "Missouri",
"city": "Iowa City",
},
},
},
},
exp: expected{
out: `apiVersion: v1
kind: Secret
metadata:
name: literalSecret2
labels:
cat: 'annoying'
dog: 'beagle'
veggie: 'celery'
annotations:
city: 'Iowa City'
river: 'Missouri'
type: Opaque
data:
a: eA==
b: eQ==
c: SGVsbG8gV29ybGQ=
d: dHJ1ZQ==
`,
},
},
}
fSys := filesys.MakeFsInMemory()
fSys.WriteFile(
filesys.RootedPath("secret", "app.env"),
[]byte("DB_USERNAME=admin\nDB_PASSWORD=qwerty\n"))
fSys.WriteFile(
filesys.RootedPath("secret", "app-init.ini"),
[]byte("FOO=bar\nBAR=baz\n"))
fSys.WriteFile(
filesys.RootedPath("secret", "app.bin"),
[]byte{0xff, 0xfd})
kvLdr := kv.NewLoader(
loader.NewFileLoaderAtRoot(fSys),
valtest_test.MakeFakeValidator())
for n := range testCases {
tc := testCases[n]
t.Run(n, func(t *testing.T) {
rn, err := MakeSecret(kvLdr, &tc.args)
if err != nil {
if !assert.EqualError(t, err, tc.exp.errMsg) {
t.FailNow()
}
return
}
if tc.exp.errMsg != "" {
t.Fatalf("%s: should return error '%s'", n, tc.exp.errMsg)
}
output := rn.MustString()
if !assert.Equal(t, tc.exp.out, output) {
t.FailNow()
}
})
}
}

View File

@@ -1,139 +0,0 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package generators
import (
"encoding/base64"
"fmt"
"strings"
"unicode/utf8"
"github.com/go-errors/errors"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
func makeBaseNode(kind, name, namespace string) (*yaml.RNode, error) {
rn, err := yaml.Parse(fmt.Sprintf(`
apiVersion: v1
kind: %s
`, kind))
if err != nil {
return nil, err
}
if name == "" {
return nil, errors.Errorf("a configmap must have a name")
}
if _, err := rn.Pipe(yaml.SetK8sName(name)); err != nil {
return nil, err
}
if namespace != "" {
if _, err := rn.Pipe(yaml.SetK8sNamespace(namespace)); err != nil {
return nil, err
}
}
return rn, nil
}
func makeValidatedDataMap(
ldr ifc.KvLoader, name string, sources types.KvPairSources) (map[string]string, error) {
pairs, err := ldr.Load(sources)
if err != nil {
return nil, errors.WrapPrefix(err, "loading KV pairs", 0)
}
knownKeys := make(map[string]string)
for _, p := range pairs {
// legal key: alphanumeric characters, '-', '_' or '.'
if err := ldr.Validator().ErrIfInvalidKey(p.Key); err != nil {
return nil, err
}
if _, ok := knownKeys[p.Key]; ok {
return nil, errors.Errorf(
"configmap %s illegally repeats the key `%s`", name, p.Key)
}
knownKeys[p.Key] = p.Value
}
return knownKeys, nil
}
// copyLabelsAndAnnotations copies labels and annotations from
// GeneratorOptions into the given object.
func copyLabelsAndAnnotations(
rn *yaml.RNode, opts *types.GeneratorOptions) error {
if opts == nil {
return nil
}
for _, k := range filtersutil.SortedMapKeys(opts.Labels) {
v := opts.Labels[k]
if _, err := rn.Pipe(yaml.SetLabel(k, v)); err != nil {
return err
}
}
for _, k := range filtersutil.SortedMapKeys(opts.Annotations) {
v := opts.Annotations[k]
if _, err := rn.Pipe(yaml.SetAnnotation(k, v)); err != nil {
return err
}
}
return nil
}
// In a secret, all data is base64 encoded, regardless of its conformance
// or lack thereof to UTF-8.
func makeSecretValueRNode(s string) *yaml.RNode {
yN := &yaml.Node{Kind: yaml.ScalarNode}
// Purposely don't use YAML tags to identify the data as being plain text or
// binary. It kubernetes Secrets the values in the `data` map are expected
// to be base64 encoded, and in ConfigMaps that same can be said for the
// values in the `binaryData` field.
yN.Tag = yaml.NodeTagString
yN.Value = encodeBase64(s)
if strings.Contains(yN.Value, "\n") {
yN.Style = yaml.LiteralStyle
}
return yaml.NewRNode(yN)
}
func makeConfigMapValueRNode(s string) (field string, rN *yaml.RNode) {
yN := &yaml.Node{Kind: yaml.ScalarNode}
yN.Tag = yaml.NodeTagString
if utf8.ValidString(s) {
field = yaml.DataField
yN.Value = s
} else {
field = yaml.BinaryDataField
yN.Value = encodeBase64(s)
}
if strings.Contains(yN.Value, "\n") {
yN.Style = yaml.LiteralStyle
}
return field, yaml.NewRNode(yN)
}
// encodeBase64 encodes s as base64 that is broken up into multiple lines
// as appropriate for the resulting length.
func encodeBase64(s string) string {
const lineLen = 70
encLen := base64.StdEncoding.EncodedLen(len(s))
lines := encLen/lineLen + 1
buf := make([]byte, encLen*2+lines)
in := buf[0:encLen]
out := buf[encLen:]
base64.StdEncoding.Encode(in, []byte(s))
k := 0
for i := 0; i < len(in); i += lineLen {
j := i + lineLen
if j > len(in) {
j = len(in)
}
k += copy(out[k:], in[i:j])
if lines > 1 {
out[k] = '\n'
k++
}
}
return string(out[:k])
}

View File

@@ -27,35 +27,22 @@ func ClonerUsingGitExec(repoSpec *RepoSpec) error {
return err
}
if repoSpec.Ref == "" {
repoSpec.Ref = "master"
}
cmd := exec.Command(
gitProgram,
"init",
"clone",
"--depth=1",
repoSpec.CloneSpec(),
repoSpec.Dir.String())
out, err := cmd.CombinedOutput()
if err != nil {
log.Printf("Error initializing git repo: %s", out)
log.Printf("Error cloning git repo: %s", out)
return errors.Wrapf(
err,
"trouble initializing git repo in %s",
repoSpec.Dir.String())
}
cmd = exec.Command(
gitProgram,
"remote",
"add",
"origin",
repoSpec.CloneSpec())
cmd.Dir = repoSpec.Dir.String()
out, err = cmd.CombinedOutput()
if err != nil {
log.Printf("Error adding remote: %s", out)
return errors.Wrapf(err, "trouble adding remote %s", repoSpec.CloneSpec())
}
ref := "HEAD"
if repoSpec.Ref != "" {
ref = repoSpec.Ref
"trouble cloning git repo %v in %s",
repoSpec.CloneSpec(), repoSpec.Dir.String())
}
cmd = exec.Command(
@@ -63,12 +50,12 @@ func ClonerUsingGitExec(repoSpec *RepoSpec) error {
"fetch",
"--depth=1",
"origin",
ref)
repoSpec.Ref)
cmd.Dir = repoSpec.Dir.String()
out, err = cmd.CombinedOutput()
if err != nil {
log.Printf("Error fetching ref: %s", out)
return errors.Wrapf(err, "trouble fetching %s", ref)
return errors.Wrapf(err, "trouble fetching %s", repoSpec.Ref)
}
cmd = exec.Command(
@@ -79,7 +66,7 @@ func ClonerUsingGitExec(repoSpec *RepoSpec) error {
out, err = cmd.CombinedOutput()
if err != nil {
log.Printf("Error checking out ref: %s", out)
return errors.Wrapf(err, "trouble checking out %s", ref)
return errors.Wrapf(err, "trouble checking out %s", repoSpec.Ref)
}
cmd = exec.Command(

View File

@@ -1,43 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package conflict
import (
"encoding/json"
jsonpatch "github.com/evanphx/json-patch"
"k8s.io/apimachinery/pkg/util/mergepatch"
"sigs.k8s.io/kustomize/api/resource"
)
// conflictDetectorJson detects conflicts in a list of JSON patches.
type conflictDetectorJson struct {
resourceFactory *resource.Factory
}
var _ resource.ConflictDetector = &conflictDetectorJson{}
func (cd *conflictDetectorJson) HasConflict(
p1, p2 *resource.Resource) (bool, error) {
return mergepatch.HasConflicts(p1.Map(), p2.Map())
}
func (cd *conflictDetectorJson) MergePatches(
patch1, patch2 *resource.Resource) (*resource.Resource, error) {
baseBytes, err := json.Marshal(patch1.Map())
if err != nil {
return nil, err
}
patchBytes, err := json.Marshal(patch2.Map())
if err != nil {
return nil, err
}
mergedBytes, err := jsonpatch.MergeMergePatches(baseBytes, patchBytes)
if err != nil {
return nil, err
}
mergedMap := make(map[string]interface{})
err = json.Unmarshal(mergedBytes, &mergedMap)
return cd.resourceFactory.FromMap(mergedMap), err
}

View File

@@ -1,65 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package conflict
import (
"fmt"
"k8s.io/apimachinery/pkg/util/strategicpatch"
"sigs.k8s.io/kustomize/api/resource"
)
// conflictDetectorSm detects conflicts in a list of strategic merge patches.
type conflictDetectorSm struct {
lookupPatchMeta strategicpatch.LookupPatchMeta
resourceFactory *resource.Factory
}
var _ resource.ConflictDetector = &conflictDetectorSm{}
func (cd *conflictDetectorSm) HasConflict(
p1, p2 *resource.Resource) (bool, error) {
return strategicpatch.MergingMapsHaveConflicts(
p1.Map(), p2.Map(), cd.lookupPatchMeta)
}
func (cd *conflictDetectorSm) MergePatches(
patch1, patch2 *resource.Resource) (*resource.Resource, error) {
if cd.hasDeleteDirectiveMarker(patch2.Map()) {
if cd.hasDeleteDirectiveMarker(patch1.Map()) {
return nil, fmt.Errorf(
"cannot merge patches both containing '$patch: delete' directives")
}
patch1, patch2 = patch2, patch1
}
mergedMap, err := strategicpatch.MergeStrategicMergeMapPatchUsingLookupPatchMeta(
cd.lookupPatchMeta, patch1.Map(), patch2.Map())
return cd.resourceFactory.FromMap(mergedMap), err
}
func (cd *conflictDetectorSm) hasDeleteDirectiveMarker(
patch map[string]interface{}) bool {
if v, ok := patch["$patch"]; ok && v == "delete" {
return true
}
for _, v := range patch {
switch typedV := v.(type) {
case map[string]interface{}:
if cd.hasDeleteDirectiveMarker(typedV) {
return true
}
case []interface{}:
for _, sv := range typedV {
typedE, ok := sv.(map[string]interface{})
if !ok {
break
}
if cd.hasDeleteDirectiveMarker(typedE) {
return true
}
}
}
}
return false
}

View File

@@ -1,45 +0,0 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package conflict
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
sp "k8s.io/apimachinery/pkg/util/strategicpatch"
"k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resource"
)
type cdFactory struct {
rf *resource.Factory
}
var _ resource.ConflictDetectorFactory = &cdFactory{}
// NewFactory returns a conflict detector factory.
// The detector uses a resource factory to convert resources to/from
// json/yaml/maps representations.
func NewFactory(rf *resource.Factory) resource.ConflictDetectorFactory {
return &cdFactory{rf: rf}
}
// New returns a conflict detector that's aware of the GVK type.
func (f *cdFactory) New(gvk resid.Gvk) (resource.ConflictDetector, error) {
// Convert to apimachinery representation of object
obj, err := scheme.Scheme.New(schema.GroupVersionKind{
Group: gvk.Group,
Version: gvk.Version,
Kind: gvk.Kind,
})
if err == nil {
meta, err := sp.NewPatchMetaFromStruct(obj)
return &conflictDetectorSm{
lookupPatchMeta: meta, resourceFactory: f.rf}, err
}
if runtime.IsNotRegisteredError(err) {
return &conflictDetectorJson{resourceFactory: f.rf}, nil
}
return nil, err
}

View File

@@ -0,0 +1,239 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package merge
import (
"encoding/json"
"fmt"
jsonpatch "github.com/evanphx/json-patch"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/mergepatch"
"k8s.io/apimachinery/pkg/util/strategicpatch"
"k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
)
type conflictDetector interface {
hasConflict(patch1, patch2 *resource.Resource) (bool, error)
findConflict(
conflictingPatchIdx int,
patches []*resource.Resource) (*resource.Resource, error)
mergePatches(patch1, patch2 *resource.Resource) (*resource.Resource, error)
}
type jsonMergePatch struct {
resourceFactory *resource.Factory
}
var _ conflictDetector = &jsonMergePatch{}
func newJMPConflictDetector(rf *resource.Factory) conflictDetector {
return &jsonMergePatch{resourceFactory: rf}
}
func (jmp *jsonMergePatch) hasConflict(
patch1, patch2 *resource.Resource) (bool, error) {
return mergepatch.HasConflicts(patch1.Map(), patch2.Map())
}
func (jmp *jsonMergePatch) findConflict(
conflictingPatchIdx int,
patches []*resource.Resource) (*resource.Resource, error) {
for i, patch := range patches {
if i == conflictingPatchIdx {
continue
}
if !patches[conflictingPatchIdx].OrgId().Equals(patch.OrgId()) {
continue
}
conflict, err := mergepatch.HasConflicts(
patch.Map(),
patches[conflictingPatchIdx].Map())
if err != nil {
return nil, err
}
if conflict {
return patch, nil
}
}
return nil, nil
}
func (jmp *jsonMergePatch) mergePatches(
patch1, patch2 *resource.Resource) (*resource.Resource, error) {
baseBytes, err := json.Marshal(patch1.Map())
if err != nil {
return nil, err
}
patchBytes, err := json.Marshal(patch2.Map())
if err != nil {
return nil, err
}
mergedBytes, err := jsonpatch.MergeMergePatches(baseBytes, patchBytes)
if err != nil {
return nil, err
}
mergedMap := make(map[string]interface{})
err = json.Unmarshal(mergedBytes, &mergedMap)
return jmp.resourceFactory.FromMap(mergedMap), err
}
type strategicMergePatch struct {
lookupPatchMeta strategicpatch.LookupPatchMeta
rf *resource.Factory
}
var _ conflictDetector = &strategicMergePatch{}
func newSMPConflictDetector(
versionedObj runtime.Object,
rf *resource.Factory) (conflictDetector, error) {
lookupPatchMeta, err := strategicpatch.NewPatchMetaFromStruct(versionedObj)
return &strategicMergePatch{lookupPatchMeta: lookupPatchMeta, rf: rf}, err
}
func (smp *strategicMergePatch) hasConflict(
p1, p2 *resource.Resource) (bool, error) {
return strategicpatch.MergingMapsHaveConflicts(
p1.Map(), p2.Map(), smp.lookupPatchMeta)
}
func (smp *strategicMergePatch) findConflict(
conflictingPatchIdx int,
patches []*resource.Resource) (*resource.Resource, error) {
for i, patch := range patches {
if i == conflictingPatchIdx {
continue
}
if !patches[conflictingPatchIdx].OrgId().Equals(patch.OrgId()) {
continue
}
conflict, err := strategicpatch.MergingMapsHaveConflicts(
patch.Map(),
patches[conflictingPatchIdx].Map(),
smp.lookupPatchMeta)
if err != nil {
return nil, err
}
if conflict {
return patch, nil
}
}
return nil, nil
}
func (smp *strategicMergePatch) mergePatches(
patch1, patch2 *resource.Resource) (*resource.Resource, error) {
if hasDeleteDirectiveMarker(patch2.Map()) {
if hasDeleteDirectiveMarker(patch1.Map()) {
return nil, fmt.Errorf(
"cannot merge patches both containing '$patch: delete' directives")
}
patch1, patch2 = patch2, patch1
}
mergeJSONMap, err := strategicpatch.MergeStrategicMergeMapPatchUsingLookupPatchMeta(
smp.lookupPatchMeta, patch1.Map(), patch2.Map())
return smp.rf.FromMap(mergeJSONMap), err
}
type merginatorImpl struct {
rf *resource.Factory
}
// NewMerginator returns a new implementation of resmap.Merginator.
func NewMerginator(rf *resource.Factory) resmap.Merginator {
return &merginatorImpl{rf: rf}
}
var _ resmap.Merginator = (*merginatorImpl)(nil)
// Merge merges the incoming resources into a new resmap.ResMap.
// Returns an error on conflict.
func (m *merginatorImpl) Merge(
patches []*resource.Resource) (resmap.ResMap, error) {
rc := resmap.New()
for ix, patch := range patches {
id := patch.OrgId()
existing := rc.GetMatchingResourcesByOriginalId(id.Equals)
if len(existing) == 0 {
rc.Append(patch)
continue
}
if len(existing) > 1 {
return nil, fmt.Errorf("self conflict in patches")
}
versionedObj, err := scheme.Scheme.New(toSchemaGvk(id.Gvk))
if err != nil && !runtime.IsNotRegisteredError(err) {
return nil, err
}
var cd conflictDetector
if err != nil {
cd = newJMPConflictDetector(m.rf)
} else {
cd, err = newSMPConflictDetector(versionedObj, m.rf)
if err != nil {
return nil, err
}
}
conflict, err := cd.hasConflict(existing[0], patch)
if err != nil {
return nil, err
}
if conflict {
conflictingPatch, err := cd.findConflict(ix, patches)
if err != nil {
return nil, err
}
return nil, fmt.Errorf(
"conflict between %#v and %#v",
conflictingPatch.Map(), patch.Map())
}
merged, err := cd.mergePatches(existing[0], patch)
if err != nil {
return nil, err
}
rc.Replace(merged)
}
return rc, nil
}
// toSchemaGvk converts to a schema.GroupVersionKind.
func toSchemaGvk(x resid.Gvk) schema.GroupVersionKind {
return schema.GroupVersionKind{
Group: x.Group,
Version: x.Version,
Kind: x.Kind,
}
}
func hasDeleteDirectiveMarker(patch map[string]interface{}) bool {
if v, ok := patch["$patch"]; ok && v == "delete" {
return true
}
for _, v := range patch {
switch typedV := v.(type) {
case map[string]interface{}:
if hasDeleteDirectiveMarker(typedV) {
return true
}
case []interface{}:
for _, sv := range typedV {
typedE, ok := sv.(map[string]interface{})
if !ok {
break
}
if hasDeleteDirectiveMarker(typedE) {
return true
}
}
}
}
return false
}

View File

@@ -0,0 +1,25 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package merge
import (
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
)
// Merginator implements resmap.Merginator using kyaml libs.
type Merginator struct {
}
var _ resmap.Merginator = (*Merginator)(nil)
func NewMerginator(_ *resource.Factory) *Merginator {
return &Merginator{}
}
// Merge implements resmap.Merginator
func (m Merginator) Merge(
resources []*resource.Resource) (resmap.ResMap, error) {
panic("TODO(#Merginator): implement Merge")
}

View File

@@ -0,0 +1,4 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package merge_test

View File

@@ -23,12 +23,11 @@ func _() {
_ = x[ReplicaCountTransformer-12]
_ = x[SecretGenerator-13]
_ = x[ValueAddTransformer-14]
_ = x[HelmChartInflationGenerator-15]
}
const _BuiltinPluginType_name = "UnknownAnnotationsTransformerConfigMapGeneratorHashTransformerImageTagTransformerLabelTransformerLegacyOrderTransformerNamespaceTransformerPatchJson6902TransformerPatchStrategicMergeTransformerPatchTransformerPrefixSuffixTransformerReplicaCountTransformerSecretGeneratorValueAddTransformerHelmChartInflationGenerator"
const _BuiltinPluginType_name = "UnknownAnnotationsTransformerConfigMapGeneratorHashTransformerImageTagTransformerLabelTransformerLegacyOrderTransformerNamespaceTransformerPatchJson6902TransformerPatchStrategicMergeTransformerPatchTransformerPrefixSuffixTransformerReplicaCountTransformerSecretGeneratorValueAddTransformer"
var _BuiltinPluginType_index = [...]uint16{0, 7, 29, 47, 62, 81, 97, 119, 139, 163, 193, 209, 232, 255, 270, 289, 316}
var _BuiltinPluginType_index = [...]uint16{0, 7, 29, 47, 62, 81, 97, 119, 139, 163, 193, 209, 232, 255, 270, 289}
func (i BuiltinPluginType) String() string {
if i < 0 || i >= BuiltinPluginType(len(_BuiltinPluginType_index)-1) {

View File

@@ -27,7 +27,6 @@ const (
ReplicaCountTransformer
SecretGenerator
ValueAddTransformer
HelmChartInflationGenerator
)
var stringToBuiltinPluginTypeMap map[string]BuiltinPluginType
@@ -56,9 +55,8 @@ func GetBuiltinPluginType(n string) BuiltinPluginType {
}
var GeneratorFactories = map[BuiltinPluginType]func() resmap.GeneratorPlugin{
ConfigMapGenerator: builtins.NewConfigMapGeneratorPlugin,
SecretGenerator: builtins.NewSecretGeneratorPlugin,
HelmChartInflationGenerator: builtins.NewHelmChartInflationGeneratorPlugin,
ConfigMapGenerator: builtins.NewConfigMapGeneratorPlugin,
SecretGenerator: builtins.NewSecretGeneratorPlugin,
}
var TransformerFactories = map[BuiltinPluginType]func() resmap.TransformerPlugin{

View File

@@ -94,7 +94,7 @@ TO GENERATE CODE
cd $repo/plugin/builtin
go generate ./...
See scripts/kyaml-pre-commit.sh for canonical way
See travis/kyaml-pre-commit.sh for canonical way
to execute the above.
This creates

View File

@@ -9,7 +9,6 @@ import (
"io/ioutil"
"os"
"os/exec"
"runtime"
"strings"
"github.com/google/shlex"
@@ -51,14 +50,7 @@ func (p *ExecPlugin) ErrIfNotExecutable() error {
if err != nil {
return err
}
// In Windows, it is not possible to determine whether a
// file is executable through file mode.
// TODO: provide for setting the executable FileMode bit on Windows
// The (fs *fileStat) Mode() (m FileMode) {} function in
// https://golang.org/src/os/types_windows.go
// lacks the ability to set the FileMode executable bit in response
// to file data on Windows.
if f.Mode()&0111 == 0000 && runtime.GOOS != "windows" {
if f.Mode()&0111 == 0000 {
return fmt.Errorf("unexecutable plugin at: %s", p.path)
}
return nil

View File

@@ -4,19 +4,18 @@
package execplugin_test
import (
"path/filepath"
"runtime"
"strings"
"testing"
"sigs.k8s.io/kustomize/api/filesys"
. "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"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"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"
"sigs.k8s.io/kustomize/api/resource"
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
)
func TestExecPluginConfig(t *testing.T) {
@@ -31,9 +30,10 @@ s/$BAR/bar baz/g
if err != nil {
t.Fatal(err)
}
pvd := provider.NewDefaultDepProvider()
rf := resmap.NewFactory(
pvd.GetResourceFactory(), pvd.GetConflictDetectorFactory())
resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl()), nil)
v := valtest_test.MakeFakeValidator()
pluginConfig := rf.RF().FromMap(
map[string]interface{}{
"apiVersion": "someteam.example.com/v1",
@@ -59,7 +59,7 @@ s/$BAR/bar baz/g
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
p.Config(resmap.NewPluginHelpers(ldr, pvd.GetFieldValidator(), rf), yaml)
p.Config(resmap.NewPluginHelpers(ldr, v, rf), yaml)
expected := "someteam.example.com/v1/sedtransformer/SedTransformer"
if !strings.HasSuffix(p.Path(), expected) {
@@ -89,32 +89,3 @@ metadata:
t.Fatalf("unexpected arg array: %#v", p.Args())
}
}
func TestExecPlugin_ErrIfNotExecutable(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skipf("always returns nil on Windows")
}
srcRoot, err := utils.DeterminePluginSrcRoot(filesys.MakeFsOnDisk())
if err != nil {
t.Error(err)
}
// Test unexecutable plugin
unexecutablePlugin := filepath.Join(
srcRoot, "builtin", "", "secretgenerator", "SecretGenerator.so")
p := NewExecPlugin(unexecutablePlugin)
err = p.ErrIfNotExecutable()
if err == nil {
t.Fatalf("unexpected err: %v", err)
}
// Test executable plugin
executablePlugin := filepath.Join(
srcRoot, "someteam.example.com", "v1", "bashedconfigmap", "BashedConfigMap")
p = NewExecPlugin(executablePlugin)
err = p.ErrIfNotExecutable()
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
}

View File

@@ -74,10 +74,10 @@ func NewFnPlugin(o *types.FnPluginLoadingOptions) *FnPlugin {
runFns: runfn.RunFns{
Functions: []*yaml.RNode{},
Network: o.Network,
NetworkName: o.NetworkName,
EnableStarlark: o.EnableStar,
EnableExec: o.EnableExec,
StorageMounts: toStorageMounts(o.Mounts),
Env: o.Env,
},
}
}

View File

@@ -8,10 +8,11 @@ import (
"sigs.k8s.io/kustomize/api/filesys"
. "sigs.k8s.io/kustomize/api/internal/plugins/loader"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/provider"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
"sigs.k8s.io/kustomize/api/types"
@@ -50,9 +51,8 @@ func TestLoader(t *testing.T) {
BuildGoPlugin("builtin", "", "SecretGenerator").
BuildGoPlugin("someteam.example.com", "v1", "SomeServiceGenerator")
defer th.Reset()
p := provider.NewDefaultDepProvider()
rmF := resmap.NewFactory(
p.GetResourceFactory(), p.GetConflictDetectorFactory())
rmF := resmap.NewFactory(resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl()), nil)
fLdr, err := loader.NewLoader(
loader.RestrictionRootOnly,
filesys.Separator, filesys.MakeFsInMemory())
@@ -65,8 +65,8 @@ func TestLoader(t *testing.T) {
t.Fatal(err)
}
for _, behavior := range []types.BuiltinPluginLoadingOptions{
/* types.BploUseStaticallyLinked,
types.BploLoadFromFileSys */} {
types.BploUseStaticallyLinked,
types.BploLoadFromFileSys} {
c, err := konfig.EnabledPluginConfig(behavior)
if err != nil {
t.Fatal(err)

View File

@@ -9,10 +9,9 @@ import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/provider"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
@@ -65,7 +64,7 @@ func strptr(s string) *string {
}
func TestUpdateResourceOptions(t *testing.T) {
rf := provider.NewDefaultDepProvider().GetResourceFactory()
rf := resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())
in := resmap.New()
expected := resmap.New()
cases := []struct {
@@ -88,12 +87,28 @@ func TestUpdateResourceOptions(t *testing.T) {
expected.Append(makeConfigMapOptions(rf, name, c.behavior, !c.needsHash))
}
actual, err := UpdateResourceOptions(in)
assert.NoError(t, err)
assert.NoError(t, expected.ErrorIfNotEqualLists(actual))
if err != nil {
t.Fatalf("unexpected error: %v", err.Error())
}
for i, a := range expected.Resources() {
b := actual.GetByIndex(i)
if b == nil {
t.Fatalf("resource %d missing from processed map", i)
}
if !a.Equals(b) {
t.Errorf("expected %v got %v", a, b)
}
if a.NeedHashSuffix() != b.NeedHashSuffix() {
t.Errorf("")
}
if a.Behavior() != b.Behavior() {
t.Errorf("expected %v got %v", a.Behavior(), b.Behavior())
}
}
}
func TestUpdateResourceOptionsWithInvalidHashAnnotationValues(t *testing.T) {
rf := provider.NewDefaultDepProvider().GetResourceFactory()
rf := resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())
cases := []string{
"",
"FaLsE",

View File

@@ -8,7 +8,6 @@ import (
"fmt"
"strings"
"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/builtins"
"sigs.k8s.io/kustomize/api/ifc"
@@ -235,18 +234,7 @@ func (kt *KustTarget) runGenerators(
func (kt *KustTarget) configureExternalGenerators() ([]resmap.Generator, error) {
ra := accumulator.MakeEmptyAccumulator()
var generatorPaths []string
for _, p := range kt.kustomization.Generators {
// handle inline generators
rm, err := kt.rFactory.NewResMapFromBytes([]byte(p))
if err != nil {
// not an inline config
generatorPaths = append(generatorPaths, p)
continue
}
ra.AppendAll(rm)
}
ra, err := kt.accumulateResources(ra, generatorPaths)
ra, err := kt.accumulateResources(ra, kt.kustomization.Generators)
if err != nil {
return nil, err
}
@@ -271,18 +259,7 @@ func (kt *KustTarget) runTransformers(ra *accumulator.ResAccumulator) error {
func (kt *KustTarget) configureExternalTransformers(transformers []string) ([]resmap.Transformer, error) {
ra := accumulator.MakeEmptyAccumulator()
var transformerPaths []string
for _, p := range transformers {
// handle inline transformers
rm, err := kt.rFactory.NewResMapFromBytes([]byte(p))
if err != nil {
// not an inline config
transformerPaths = append(transformerPaths, p)
continue
}
ra.AppendAll(rm)
}
ra, err := kt.accumulateResources(ra, transformerPaths)
ra, err := kt.accumulateResources(ra, transformers)
if err != nil {
return nil, err
@@ -336,18 +313,12 @@ func (kt *KustTarget) accumulateResources(
if errF := kt.accumulateFile(ra, path); errF != nil {
ldr, errL := kt.ldr.New(path)
if errL != nil {
return nil, multierror.Append(
fmt.Errorf("accumulateFile error: %q", errF),
fmt.Errorf("loader.New error: %q", errL),
)
return nil, fmt.Errorf("accumulateFile %q, loader.New %q", errF, errL)
}
var errD error
ra, errD = kt.accumulateDirectory(ra, ldr, false)
if errD != nil {
return nil, multierror.Append(
fmt.Errorf("accumulateFile error: %q", errF),
fmt.Errorf("accumulateDirector error: %q", errD),
)
return nil, fmt.Errorf("accumulateFile %q, accumulateDirector: %q", errF, errD)
}
}
}

View File

@@ -32,7 +32,6 @@ func (kt *KustTarget) configureBuiltinGenerators() (
for _, bpt := range []builtinhelpers.BuiltinPluginType{
builtinhelpers.ConfigMapGenerator,
builtinhelpers.SecretGenerator,
builtinhelpers.HelmChartInflationGenerator,
} {
r, err := generatorConfigurators[bpt](
kt, bpt, builtinhelpers.GeneratorFactories[bpt])
@@ -111,23 +110,6 @@ var generatorConfigurators = map[builtinhelpers.BuiltinPluginType]func(
}
return
},
builtinhelpers.HelmChartInflationGenerator: func(kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f gFactory) (
result []resmap.Generator, err error) {
var c struct {
types.HelmChartArgs
}
for _, args := range kt.kustomization.HelmChartInflationGenerator {
c.HelmChartArgs = args
p := f()
err := kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
}
return
},
}
type tFactory func() resmap.TransformerPlugin
@@ -159,12 +141,12 @@ var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func(
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, _ *builtinconfig.TransformerConfig) (
result []resmap.Transformer, err error) {
var c struct {
Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"`
Path string `json:"path,omitempty" yaml:"path,omitempty"`
JsonOp string `json:"jsonOp,omitempty" yaml:"jsonOp,omitempty"`
Target types.PatchTarget `json:"target,omitempty" yaml:"target,omitempty"`
Path string `json:"path,omitempty" yaml:"path,omitempty"`
JsonOp string `json:"jsonOp,omitempty" yaml:"jsonOp,omitempty"`
}
for _, args := range kt.kustomization.PatchesJson6902 {
c.Target = args.Target
c.Target = *args.Target
c.Path = args.Path
c.JsonOp = args.Patch
p := f()
@@ -183,7 +165,8 @@ var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func(
return
}
var c struct {
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
Patches string `json:"patches,omitempty" yaml:"patches,omitempty"`
}
c.Paths = kt.kustomization.PatchesStrategicMerge
p := f()

View File

@@ -8,10 +8,9 @@ import (
"reflect"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/provider"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
@@ -77,7 +76,8 @@ commonLabels:
}
kt := makeKustTargetWithRf(
t, th.GetFSys(), "/", provider.NewDefaultDepProvider())
t, th.GetFSys(), "/",
resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl()))
for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
th.WriteK("/", tc.content)
@@ -148,8 +148,7 @@ metadata:
{"op": "add", "path": "/spec/replica", "value": "3"}
]`)
pvd := provider.NewDefaultDepProvider()
resFactory := pvd.GetResourceFactory()
resFactory := resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())
resources := []*resource.Resource{
resFactory.FromMapWithName("dply1", map[string]interface{}{
@@ -244,14 +243,19 @@ metadata:
t.Fatalf("unexpected error %v", err)
}
}
expYaml, err := expected.AsYaml()
assert.NoError(t, err)
kt := makeKustTargetWithRf(t, th.GetFSys(), "/whatever", pvd)
assert.NoError(t, kt.Load())
kt := makeKustTargetWithRf(
t, th.GetFSys(), "/whatever", resFactory)
err := kt.Load()
if err != nil {
t.Fatalf("unexpected Resources error %v", err)
}
actual, err := kt.MakeCustomizedResMap()
assert.NoError(t, err)
actYaml, err := actual.AsYaml()
assert.NoError(t, err)
assert.Equal(t, expYaml, actYaml)
if err != nil {
t.Fatalf("unexpected Resources error %v", err)
}
if err = expected.ErrorIfNotEqualLists(actual); err != nil {
t.Fatalf("unexpected inequality: %v", err)
}
}

View File

@@ -7,12 +7,14 @@ import (
"testing"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/internal/k8sdeps/merge"
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
"sigs.k8s.io/kustomize/api/internal/target"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"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"
"sigs.k8s.io/kustomize/api/resource"
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
)
@@ -20,7 +22,9 @@ func makeAndLoadKustTarget(
t *testing.T,
fSys filesys.FileSystem,
root string) *target.KustTarget {
kt := makeKustTargetWithRf(t, fSys, root, provider.NewDefaultDepProvider())
kt := makeKustTargetWithRf(
t, fSys, root,
resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl()))
if err := kt.Load(); err != nil {
t.Fatalf("Unexpected load error %v", err)
}
@@ -31,13 +35,13 @@ func makeKustTargetWithRf(
t *testing.T,
fSys filesys.FileSystem,
root string,
pvd *provider.DepProvider) *target.KustTarget {
resourceFactory *resource.Factory) *target.KustTarget {
ldr, err := fLdr.NewLoader(fLdr.RestrictionRootOnly, root, fSys)
if err != nil {
t.Fatal(err)
}
rf := resmap.NewFactory(
pvd.GetResourceFactory(), pvd.GetConflictDetectorFactory())
resourceFactory, merge.NewMerginator(resourceFactory))
pc := konfig.DisabledPluginConfig()
return target.NewKustTarget(
ldr,

View File

@@ -26,15 +26,13 @@ func newMultiTransformer(t []resmap.Transformer) resmap.Transformer {
return r
}
// Transform applies the member transformers in order to the resources,
// optionally detecting and erroring on commutation conflict.
// Transform prepends the name prefix.
func (o *multiTransformer) Transform(m resmap.ResMap) error {
if o.checkConflictEnabled {
return o.transformWithCheckConflict(m)
}
return o.transform(m)
}
func (o *multiTransformer) transform(m resmap.ResMap) error {
for _, t := range o.transformers {
err := t.Transform(m)

View File

@@ -21,5 +21,5 @@ import (
// major version increments in pluginator with each
// api release to allow this trick to work and not
// introduce cycles.
// _ "sigs.k8s.io/kustomize/cmd/pluginator/v2"
// _ "sigs.k8s.io/kustomize/pluginator/v2"
)

View File

@@ -10,10 +10,6 @@ import (
// FieldValidator implements ifc.Validator to check
// the values of various KRM string fields,
// e.g. labels, annotations, names, namespaces.
//
// TODO: Have this use kyaml/yaml/internal/k8sgen/pkg/labels
// which has label and annotation validation code, but is internal
// so this impl would need to move to kyaml (a fine idea).
type FieldValidator struct {
}

View File

@@ -4,105 +4,38 @@
package wrappy
import (
"fmt"
"sigs.k8s.io/kustomize/api/hasher"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/internal/generators"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/filtersutil"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// WNodeFactory makes instances of WNode.
//
// These instances in turn adapt
// sigs.k8s.io/kustomize/kyaml/yaml.RNode
// to implement ifc.Unstructured.
// This factory is meant to implement ifc.KunstructuredFactory.
//
// This implementation should be thin, as both WNode and WNodeFactory must be
// factored away (deleted) along with ifc.Kunstructured in favor of direct use
// of RNode methods upon completion of
// https://github.com/kubernetes-sigs/kustomize/issues/2506.
//
// See also api/krusty/internal/provider/depprovider.go
type WNodeFactory struct {
}
var _ ifc.KunstructuredFactory = (*WNodeFactory)(nil)
func (k *WNodeFactory) SliceFromBytes(bs []byte) ([]ifc.Kunstructured, error) {
yamlRNodes, err := kio.FromBytes(bs)
if err != nil {
return nil, err
}
var result []ifc.Kunstructured
for i := range yamlRNodes {
rn := yamlRNodes[i]
meta, err := rn.GetValidatedMetadata()
if err != nil {
return nil, err
}
if !shouldDropObject(meta) {
if foundNil, path := rn.HasNilEntryInList(); foundNil {
return nil, fmt.Errorf("empty item at %v in object %v", path, rn)
}
result = append(result, FromRNode(rn))
}
}
return result, nil
}
// shouldDropObject returns true if the resource should not be accumulated.
func shouldDropObject(m yaml.ResourceMeta) bool {
_, y := m.ObjectMeta.Annotations[konfig.IgnoredByKustomizeResourceAnnotation]
return y
panic("TODO(#WNodeFactory): implement SliceFromBytes")
}
func (k *WNodeFactory) FromMap(m map[string]interface{}) ifc.Kunstructured {
rn, err := FromMap(m)
if err != nil {
// TODO(#WNodeFactory): handle or bubble error"
panic(err)
}
return rn
}
// kustHash computes a hash of an unstructured object.
type kustHash struct{}
// Hash returns a hash of the given object
func (h *kustHash) Hash(m ifc.Kunstructured) (string, error) {
node, err := filtersutil.GetRNode(m)
if err != nil {
return "", err
}
return hasher.HashRNode(node)
panic("TODO(#WNodeFactory): implement FromMap")
}
func (k *WNodeFactory) Hasher() ifc.KunstructuredHasher {
return &kustHash{}
panic("TODO(#WNodeFactory): implement Hasher")
}
// MakeConfigMap makes a wrapped configmap.
func (k *WNodeFactory) MakeConfigMap(
ldr ifc.KvLoader, args *types.ConfigMapArgs) (ifc.Kunstructured, error) {
rn, err := generators.MakeConfigMap(ldr, args)
if err != nil {
return nil, err
}
return FromRNode(rn), nil
kvLdr ifc.KvLoader, args *types.ConfigMapArgs) (ifc.Kunstructured, error) {
panic("TODO(#WNodeFactory): implement MakeConfigMap")
}
// MakeSecret makes a wrapped secret.
func (k *WNodeFactory) MakeSecret(
ldr ifc.KvLoader, args *types.SecretArgs) (ifc.Kunstructured, error) {
rn, err := generators.MakeSecret(ldr, args)
if err != nil {
return nil, err
}
return FromRNode(rn), nil
kvLdr ifc.KvLoader, args *types.SecretArgs) (ifc.Kunstructured, error) {
panic("TODO(#WNodeFactory): implement MakeSecret")
}

View File

@@ -2,320 +2,3 @@
// SPDX-License-Identifier: Apache-2.0
package wrappy_test
import (
"fmt"
"reflect"
"testing"
"github.com/stretchr/testify/assert"
. "sigs.k8s.io/kustomize/api/internal/wrappy"
)
func TestHasher(t *testing.T) {
input := `
apiVersion: v1
kind: ConfigMap
metadata:
name: foo
data:
one: ""
binaryData:
two: ""
`
expect := "698h7c7t9m"
factory := &WNodeFactory{}
k, err := factory.SliceFromBytes([]byte(input))
if err != nil {
t.Fatal(err)
}
hasher := factory.Hasher()
result, err := hasher.Hash(k[0])
if err != nil {
t.Fatal(err)
}
if result != expect {
t.Fatalf("expect %s but got %s", expect, result)
}
}
func TestSliceFromBytes(t *testing.T) {
factory := &WNodeFactory{}
testConfigMap :=
map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{
"name": "winnie",
},
}
testConfigMapList :=
map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMapList",
"items": []interface{}{
testConfigMap,
testConfigMap,
},
}
testDeploymentSpec := map[string]interface{}{
"template": map[string]interface{}{
"spec": map[string]interface{}{
"hostAliases": []interface{}{
map[string]interface{}{
"hostnames": []interface{}{
"a.example.com",
},
"ip": "8.8.8.8",
},
},
},
},
}
testDeploymentA := map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": "deployment-a",
},
"spec": testDeploymentSpec,
}
testDeploymentB := map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": "deployment-b",
},
"spec": testDeploymentSpec,
}
testDeploymentList :=
map[string]interface{}{
"apiVersion": "v1",
"kind": "DeploymentList",
"items": []interface{}{
testDeploymentA,
testDeploymentB,
},
}
type expected struct {
out []map[string]interface{}
isErr bool
}
testCases := map[string]struct {
input []byte
exp expected
}{
"garbage": {
input: []byte("garbageIn: garbageOut"),
exp: expected{
isErr: true,
},
},
"noBytes": {
input: []byte{},
exp: expected{
out: []map[string]interface{}{},
},
},
"goodJson": {
input: []byte(`
{"apiVersion":"v1","kind":"ConfigMap","metadata":{"name":"winnie"}}
`),
exp: expected{
out: []map[string]interface{}{testConfigMap},
},
},
"goodYaml1": {
input: []byte(`
apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
`),
exp: expected{
out: []map[string]interface{}{testConfigMap},
},
},
"goodYaml2": {
input: []byte(`
apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
---
apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
`),
exp: expected{
out: []map[string]interface{}{testConfigMap, testConfigMap},
},
},
"localConfigYaml": {
input: []byte(`
apiVersion: v1
kind: ConfigMap
metadata:
name: winnie-skip
annotations:
# this annotation causes the Resource to be ignored by kustomize
config.kubernetes.io/local-config: ""
---
apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
`),
exp: expected{
out: []map[string]interface{}{testConfigMap},
},
},
"garbageInOneOfTwoObjects": {
input: []byte(`
apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
---
WOOOOOOOOOOOOOOOOOOOOOOOOT: woot
`),
exp: expected{
isErr: true,
},
},
"emptyObjects": {
input: []byte(`
---
#a comment
---
`),
exp: expected{
out: []map[string]interface{}{},
},
},
"Missing .metadata.name in object": {
input: []byte(`
apiVersion: v1
kind: Namespace
metadata:
annotations:
foo: bar
`),
exp: expected{
isErr: true,
},
},
"nil value in list": {
input: []byte(`
apiVersion: builtin
kind: ConfigMapGenerator
metadata:
name: kube100-site
labels:
app: web
testList:
- testA
-
`),
exp: expected{
isErr: true,
},
},
"List": {
input: []byte(`
apiVersion: v1
kind: List
items:
- apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
- apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
`),
exp: expected{
out: []map[string]interface{}{
testConfigMap,
testConfigMap},
},
},
"ConfigMapList": {
input: []byte(`
apiVersion: v1
kind: ConfigMapList
items:
- apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
- apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
`),
exp: expected{
out: []map[string]interface{}{testConfigMapList},
},
},
"listWithAnchors": {
input: []byte(`
apiVersion: v1
kind: DeploymentList
items:
- apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-a
spec: &hostAliases
template:
spec:
hostAliases:
- hostnames:
- a.example.com
ip: 8.8.8.8
- apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-b
spec:
<<: *hostAliases
`),
exp: expected{
out: []map[string]interface{}{testDeploymentList},
},
},
}
for n := range testCases {
tc := testCases[n]
t.Run(n, func(t *testing.T) {
rs, err := factory.SliceFromBytes(tc.input)
if err != nil {
assert.True(t, tc.exp.isErr)
return
}
assert.False(t, tc.exp.isErr)
assert.Equal(t, len(tc.exp.out), len(rs))
for i := range rs {
assert.Equal(
t, fmt.Sprintf("%v", tc.exp.out[i]), fmt.Sprintf("%v", rs[i].Map()))
if n != "listWithAnchors" {
// https://github.com/kubernetes-sigs/kustomize/issues/3271
if !reflect.DeepEqual(tc.exp.out[i], rs[i].Map()) {
t.Fatalf("%s:\nexpected: %v\n actual: %v",
n, tc.exp.out[i], rs[i].Map())
}
}
}
})
}
}

View File

@@ -4,9 +4,7 @@
package wrappy
import (
"fmt"
"log"
"strings"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/resid"
@@ -31,14 +29,6 @@ func NewWNode() *WNode {
return FromRNode(yaml.NewRNode(nil))
}
func FromMap(m map[string]interface{}) (*WNode, error) {
n, err := yaml.FromMap(m)
if err != nil {
return nil, err
}
return FromRNode(n), nil
}
func FromRNode(node *yaml.RNode) *WNode {
return &WNode{node: node}
}
@@ -64,41 +54,10 @@ func (wn *WNode) GetAnnotations() map[string]string {
// GetFieldValue implements ifc.Kunstructured.
func (wn *WNode) GetFieldValue(path string) (interface{}, error) {
fields := strings.Split(path, ".")
rn, err := wn.node.Pipe(yaml.Lookup(fields...))
if err != nil {
return nil, err
}
if rn == nil {
return nil, NoFieldError{path}
}
yn := rn.YNode()
// If this is an alias node, resolve it
if yn.Kind == yaml.AliasNode {
yn = yn.Alias
}
// Return value as map for DocumentNode and MappingNode kinds
if yn.Kind == yaml.DocumentNode || yn.Kind == yaml.MappingNode {
var result map[string]interface{}
if err := yn.Decode(&result); err != nil {
return nil, err
}
return result, err
}
// Return value as slice for SequenceNode kind
if yn.Kind == yaml.SequenceNode {
var result []interface{}
for _, node := range yn.Content {
result = append(result, node.Value)
}
return result, nil
}
// Return value value directly for all other (ScalarNode) kinds
return yn.Value, nil
// The argument is a json path, e.g. "metadata.name"
// fields := strings.Split(path, ".")
// return wn.node.Pipe(yaml.Lookup(fields...))
panic("TODO(#WNode): GetFieldValue; implement or drop from API")
}
// GetGvk implements ifc.Kunstructured.
@@ -124,37 +83,18 @@ func (wn *WNode) GetName() string {
}
// GetSlice implements ifc.Kunstructured.
func (wn *WNode) GetSlice(path string) ([]interface{}, error) {
value, err := wn.GetFieldValue(path)
if err != nil {
return nil, err
}
if sliceValue, ok := value.([]interface{}); ok {
return sliceValue, nil
}
return nil, fmt.Errorf("node %s is not a slice", path)
func (wn *WNode) GetSlice(string) ([]interface{}, error) {
panic("TODO(#WNode) GetSlice; implement or drop from API")
}
// GetSlice implements ifc.Kunstructured.
func (wn *WNode) GetString(path string) (string, error) {
value, err := wn.GetFieldValue(path)
if err != nil {
return "", err
}
if v, ok := value.(string); ok {
return v, nil
}
return "", fmt.Errorf("node %s is not a string: %v", path, value)
func (wn *WNode) GetString(string) (string, error) {
panic("TODO(#WNode) GetString; implement or drop from API")
}
// Map implements ifc.Kunstructured.
func (wn *WNode) Map() map[string]interface{} {
var result map[string]interface{}
if err := wn.node.YNode().Decode(&result); err != nil {
// Log and die since interface doesn't allow error.
log.Fatalf("failed to decode ynode: %v", err)
}
return result
panic("TODO(#WNode) Map; implement or drop from API")
}
// MarshalJSON implements ifc.Kunstructured.
@@ -163,65 +103,41 @@ func (wn *WNode) MarshalJSON() ([]byte, error) {
}
// MatchesAnnotationSelector implements ifc.Kunstructured.
func (wn *WNode) MatchesAnnotationSelector(selector string) (bool, error) {
return wn.node.MatchesAnnotationSelector(selector)
func (wn *WNode) MatchesAnnotationSelector(string) (bool, error) {
panic("TODO(#WNode) MatchesAnnotationSelector; implement or drop from API")
}
// MatchesLabelSelector implements ifc.Kunstructured.
func (wn *WNode) MatchesLabelSelector(selector string) (bool, error) {
return wn.node.MatchesLabelSelector(selector)
func (wn *WNode) MatchesLabelSelector(string) (bool, error) {
panic("TODO(#WNode) MatchesLabelSelector; implement or drop from API")
}
// SetAnnotations implements ifc.Kunstructured.
func (wn *WNode) SetAnnotations(annotations map[string]string) {
if err := wn.node.SetAnnotations(annotations); err != nil {
log.Fatal(err) // interface doesn't allow error.
}
func (wn *WNode) SetAnnotations(map[string]string) {
panic("TODO(#WNode) SetAnnotations; implement or drop from API")
}
// SetGvk implements ifc.Kunstructured.
func (wn *WNode) SetGvk(gvk resid.Gvk) {
wn.setMapField(yaml.NewScalarRNode(gvk.Kind), yaml.KindField)
wn.setMapField(
yaml.NewScalarRNode(
fmt.Sprintf("%s/%s", gvk.Group, gvk.Version)), yaml.APIVersionField)
func (wn *WNode) SetGvk(resid.Gvk) {
panic("TODO(#WNode) SetGvk; implement or drop from API")
}
// SetLabels implements ifc.Kunstructured.
func (wn *WNode) SetLabels(labels map[string]string) {
if err := wn.node.SetLabels(labels); err != nil {
log.Fatal(err) // interface doesn't allow error.
}
func (wn *WNode) SetLabels(map[string]string) {
panic("TODO(#WNode) SetLabels; implement or drop from API")
}
// SetName implements ifc.Kunstructured.
func (wn *WNode) SetName(name string) {
wn.setMapField(yaml.NewScalarRNode(name), yaml.MetadataField, yaml.NameField)
func (wn *WNode) SetName(string) {
panic("TODO(#WNode) SetName; implement or drop from API")
}
// SetNamespace implements ifc.Kunstructured.
func (wn *WNode) SetNamespace(ns string) {
if err := wn.node.SetNamespace(ns); err != nil {
log.Fatal(err) // interface doesn't allow error.
}
}
func (wn *WNode) setMapField(value *yaml.RNode, path ...string) {
if err := wn.node.SetMapField(value, path...); err != nil {
// Log and die since interface doesn't allow error.
log.Fatalf("failed to set field %v: %v", path, err)
}
func (wn *WNode) SetNamespace(string) {
panic("TODO(#WNode) SetNamespace; implement or drop from API")
}
// UnmarshalJSON implements ifc.Kunstructured.
func (wn *WNode) UnmarshalJSON(data []byte) error {
return wn.node.UnmarshalJSON(data)
}
type NoFieldError struct {
Field string
}
func (e NoFieldError) Error() string {
return fmt.Sprintf("no field named '%s'", e.Field)
}

View File

@@ -1,15 +1,14 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package wrappy
package wrappy_test
import (
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"gopkg.in/yaml.v3"
"sigs.k8s.io/kustomize/api/resid"
. "sigs.k8s.io/kustomize/api/internal/wrappy"
kyaml "sigs.k8s.io/kustomize/kyaml/yaml"
)
@@ -338,215 +337,3 @@ func TestGettingFields(t *testing.T) {
t.Fatalf("unexpected annotations '%v'", actualMap)
}
}
func TestGetFieldValueReturnsMap(t *testing.T) {
wn := NewWNode()
if err := wn.UnmarshalJSON([]byte(deploymentBiggerJson)); err != nil {
t.Fatalf("unexpected unmarshaljson err: %v", err)
}
expected := map[string]interface{}{
"fruit": "apple",
"veggie": "carrot",
}
actual, err := wn.GetFieldValue("metadata.labels")
if err != nil {
t.Fatalf("error getting field value: %v", err)
}
if diff := cmp.Diff(expected, actual); diff != "" {
t.Fatalf("actual map does not deep equal expected map:\n%v", diff)
}
}
func TestGetFieldValueReturnsSlice(t *testing.T) {
bytes, err := yaml.Marshal(makeBigMap())
if err != nil {
t.Fatalf("unexpected yaml.Marshal err: %v", err)
}
rNode, err := kyaml.Parse(string(bytes))
if err != nil {
t.Fatalf("unexpected yaml.Marshal err: %v", err)
}
wn := FromRNode(rNode)
expected := []interface{}{"idx0", "idx1", "idx2", "idx3"}
actual, err := wn.GetFieldValue("that")
if err != nil {
t.Fatalf("error getting slice: %v", err)
}
if diff := cmp.Diff(expected, actual); diff != "" {
t.Fatalf("actual slice does not deep equal expected slice:\n%v", diff)
}
}
func TestGetFieldValueReturnsString(t *testing.T) {
wn := NewWNode()
if err := wn.UnmarshalJSON([]byte(deploymentBiggerJson)); err != nil {
t.Fatalf("unexpected unmarshaljson err: %v", err)
}
actual, err := wn.GetFieldValue("metadata.labels.fruit")
if err != nil {
t.Fatalf("error getting field value: %v", err)
}
v, ok := actual.(string)
if !ok || v != "apple" {
t.Fatalf("unexpected value '%v'", actual)
}
}
func TestGetFieldValueResolvesAlias(t *testing.T) {
yamlWithAlias := `
foo: &a theValue
bar: *a
`
rNode, err := kyaml.Parse(yamlWithAlias)
if err != nil {
t.Fatalf("unexpected yaml parse error: %v", err)
}
wn := FromRNode(rNode)
actual, err := wn.GetFieldValue("bar")
if err != nil {
t.Fatalf("error getting field value: %v", err)
}
v, ok := actual.(string)
if !ok || v != "theValue" {
t.Fatalf("unexpected value '%v'", actual)
}
}
func TestGetString(t *testing.T) {
wn := NewWNode()
if err := wn.UnmarshalJSON([]byte(deploymentBiggerJson)); err != nil {
t.Fatalf("unexpected unmarshaljson err: %v", err)
}
expected := "carrot"
actual, err := wn.GetString("metadata.labels.veggie")
if err != nil {
t.Fatalf("error getting string: %v", err)
}
if expected != actual {
t.Fatalf("expected '%s', got '%s'", expected, actual)
}
}
func TestGetSlice(t *testing.T) {
bytes, err := yaml.Marshal(makeBigMap())
if err != nil {
t.Fatalf("unexpected yaml.Marshal err: %v", err)
}
rNode, err := kyaml.Parse(string(bytes))
if err != nil {
t.Fatalf("unexpected yaml.Marshal err: %v", err)
}
wn := FromRNode(rNode)
expected := []interface{}{"idx0", "idx1", "idx2", "idx3"}
actual, err := wn.GetSlice("that")
if err != nil {
t.Fatalf("error getting slice: %v", err)
}
if diff := cmp.Diff(expected, actual); diff != "" {
t.Fatalf("actual slice does not deep equal expected slice:\n%v", diff)
}
}
func TestMap(t *testing.T) {
wn := NewWNode()
if err := wn.UnmarshalJSON([]byte(deploymentLittleJson)); err != nil {
t.Fatalf("unexpected unmarshaljson err: %v", err)
}
expected := map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": "homer",
"namespace": "simpsons",
},
}
actual := wn.Map()
if diff := cmp.Diff(expected, actual); diff != "" {
t.Fatalf("actual map does not deep equal expected map:\n%v", diff)
}
}
func TestSetName(t *testing.T) {
wn := NewWNode()
if err := wn.UnmarshalJSON([]byte(deploymentBiggerJson)); err != nil {
t.Fatalf("unexpected unmarshaljson err: %v", err)
}
wn.SetName("marge")
if expected, actual := "marge", wn.GetName(); expected != actual {
t.Fatalf("expected '%s', got '%s'", expected, actual)
}
}
func TestSetNamespace(t *testing.T) {
wn := NewWNode()
if err := wn.UnmarshalJSON([]byte(deploymentBiggerJson)); err != nil {
t.Fatalf("unexpected unmarshaljson err: %v", err)
}
wn.SetNamespace("flanders")
meta, _ := wn.node.GetMeta()
if expected, actual := "flanders", meta.Namespace; expected != actual {
t.Fatalf("expected '%s', got '%s'", expected, actual)
}
}
func TestSetLabels(t *testing.T) {
wn := NewWNode()
if err := wn.UnmarshalJSON([]byte(deploymentBiggerJson)); err != nil {
t.Fatalf("unexpected unmarshaljson err: %v", err)
}
wn.SetLabels(map[string]string{
"label1": "foo",
"label2": "bar",
})
labels := wn.GetLabels()
if expected, actual := 2, len(labels); expected != actual {
t.Fatalf("expected '%d', got '%d'", expected, actual)
}
if expected, actual := "foo", labels["label1"]; expected != actual {
t.Fatalf("expected '%s', got '%s'", expected, actual)
}
if expected, actual := "bar", labels["label2"]; expected != actual {
t.Fatalf("expected '%s', got '%s'", expected, actual)
}
}
func TestGetAnnotations(t *testing.T) {
wn := NewWNode()
if err := wn.UnmarshalJSON([]byte(deploymentBiggerJson)); err != nil {
t.Fatalf("unexpected unmarshaljson err: %v", err)
}
wn.SetAnnotations(map[string]string{
"annotation1": "foo",
"annotation2": "bar",
})
annotations := wn.GetAnnotations()
if expected, actual := 2, len(annotations); expected != actual {
t.Fatalf("expected '%d', got '%d'", expected, actual)
}
if expected, actual := "foo", annotations["annotation1"]; expected != actual {
t.Fatalf("expected '%s', got '%s'", expected, actual)
}
if expected, actual := "bar", annotations["annotation2"]; expected != actual {
t.Fatalf("expected '%s', got '%s'", expected, actual)
}
}
func TestSetGvk(t *testing.T) {
wn := NewWNode()
if err := wn.UnmarshalJSON([]byte(deploymentBiggerJson)); err != nil {
t.Fatalf("unexpected unmarshaljson err: %v", err)
}
wn.SetGvk(resid.GvkFromString("grp_ver_knd"))
gvk := wn.GetGvk()
if expected, actual := "grp", gvk.Group; expected != actual {
t.Fatalf("expected '%s', got '%s'", expected, actual)
}
if expected, actual := "ver", gvk.Version; expected != actual {
t.Fatalf("expected '%s', got '%s'", expected, actual)
}
if expected, actual := "knd", gvk.Kind; expected != actual {
t.Fatalf("expected '%s', got '%s'", expected, actual)
}
}

View File

@@ -14,7 +14,6 @@ import (
"k8s.io/apimachinery/pkg/util/yaml"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/internal/k8sdeps/configmapandsecret"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/types"
)
@@ -117,6 +116,10 @@ func (kf *KunstructuredFactoryImpl) validate(u unstructured.Unstructured) error
return nil
}
// nonKustomizableResourceAnnotation if set on a Resource will cause Kustomize to
// ignore the Resource rather than Kustomize it.
const ignoredByKustomizeResourceAnnotation = "config.kubernetes.io/local-config"
// skipResource returns true if the Resource should not be accumulated
func (kf *KunstructuredFactoryImpl) skipResource(u unstructured.Unstructured) bool {
an := u.GetAnnotations()
@@ -125,7 +128,7 @@ func (kf *KunstructuredFactoryImpl) skipResource(u unstructured.Unstructured) bo
return false
}
// check if the Resource has opt-ed out of kustomize
_, found := an[konfig.IgnoredByKustomizeResourceAnnotation]
_, found := an[ignoredByKustomizeResourceAnnotation]
return found
}

View File

@@ -238,8 +238,6 @@ nameReference:
kind: Ingress
- path: metadata/annotations/nginx.ingress.kubernetes.io\/auth-tls-secret
kind: Ingress
- path: spec/tls/secretName
kind: Ingress
- path: imagePullSecrets/name
kind: ServiceAccount
- path: parameters/secretName
@@ -258,8 +256,6 @@ nameReference:
kind: Service
group: serving.knative.dev
version: v1
- path: spec/azureFile/secretName
kind: PersistentVolume
- kind: Service
version: v1
@@ -271,10 +267,6 @@ nameReference:
kind: Ingress
- path: spec/backend/serviceName
kind: Ingress
- path: spec/rules/http/paths/backend/service/name
kind: Ingress
- path: spec/defaultBackend/service/name
kind: Ingress
- path: spec/service/name
kind: APIService
group: apiregistration.k8s.io
@@ -381,12 +373,5 @@ nameReference:
kind: Job
- path: spec/template/spec/priorityClassName
kind: DaemonSet
- kind: IngressClass
version: v1
group: networking.k8s.io/v1
fieldSpecs:
- path: spec/ingressClassName
kind: Ingress
`
)

View File

@@ -8,9 +8,6 @@ const (
namespace:
- path: metadata/namespace
create: true
- path: metadata/name
kind: Namespace
create: true
- path: subjects
kind: RoleBinding
- path: subjects

View File

@@ -87,9 +87,6 @@ varReference:
- path: spec/template/spec/volumes/nfs/server
kind: Deployment
- path: spec/template/metadata/annotations
kind: Deployment
- path: spec/rules/host
kind: Ingress

View File

@@ -19,32 +19,7 @@ func DefaultKustomizationFileName() string {
return RecognizedKustomizationFileNames()[0]
}
// IfApiMachineryElseKyaml returns true if executing the apimachinery code
// path, else we're executing the kyaml code paths.
func IfApiMachineryElseKyaml(s1, s2 string) string {
if !FlagEnableKyamlDefaultValue {
return s1
}
return s2
}
const (
// FlagEnableKyamlDefaultValue is the default value for the --enable_kyaml
// flag. This value is also used in unit tests. See provider.DepProvider.
//
// TODO(#3304): eliminate branching on this constant.
// Details: https://github.com/kubernetes-sigs/kustomize/issues/3304
//
// All tests should pass for either true or false values
// of this constant, without having to check its value.
// In the cases where there's a different outcome, either decide
// that the difference is acceptable, or make the difference go away.
//
// Historically, tests passed for enable_kyaml == false, i.e. using
// apimachinery libs. This doesn't mean the code was better, it just
// means regression tests preserved those outcomes.
FlagEnableKyamlDefaultValue = false
// An environment variable to consult for kustomization
// configuration data. See:
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
@@ -56,9 +31,6 @@ const (
// A program name, for use in help, finding the XDG_CONFIG_DIR, etc.
ProgramName = "kustomize"
// If a resource has this annotation, kustomize will drop it.
IgnoredByKustomizeResourceAnnotation = "config.kubernetes.io/local-config"
// Label key that indicates the resources are built from Kustomize
ManagedbyLabelKey = "app.kubernetes.io/managed-by"

View File

@@ -9,7 +9,6 @@ import (
"runtime"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers"
"sigs.k8s.io/kustomize/api/types"
)
@@ -158,15 +157,3 @@ func pwdEnv() string {
}
return "PWD"
}
// GetBuiltinPluginNames returns a list of builtin plugin names
func GetBuiltinPluginNames() []string {
var ret []string
for k := range builtinhelpers.GeneratorFactories {
ret = append(ret, k.String())
}
for k := range builtinhelpers.TransformerFactories {
ret = append(ret, k.String())
}
return ret
}

View File

@@ -225,13 +225,13 @@ spec:
spec:
containers:
- env:
- name: foo
value: bar
- name: FOO
valueFrom:
configMapKeyRef:
key: somekey
name: test-infra-app-env-8h5mh7f7ch
- name: foo
value: bar
image: nginx:1.8.0
name: nginx
ports:

View File

@@ -464,50 +464,3 @@ metadata:
name: another-namespace
`)
}
func TestFnContainerEnvVars(t *testing.T) {
skipIfNoDocker(t)
th := kusttest_test.MakeEnhancedHarness(t)
defer th.Reset()
th.WriteK("/app", `
generators:
- gener.yaml
`)
// TODO: cheange image to gcr.io/kpt-functions/templater:stable
// when https://github.com/GoogleContainerTools/kpt-functions-catalog/pull/103
// is merged
th.WriteF("/app/gener.yaml", `
apiVersion: v1
kind: ConfigMap
metadata:
name: demo
annotations:
config.kubernetes.io/function: |
container:
image: quay.io/aodinokov/kpt-templater:0.0.1
envs:
- TESTTEMPLATE=value
data:
template: |
apiVersion: v1
kind: ConfigMap
metadata:
name: env
data:
value: '{{ env "TESTTEMPLATE" }}'
`)
m := th.Run("/app", th.MakeOptionsPluginsEnabled())
th.AssertActualEqualsExpected(m, `
apiVersion: v1
data:
value: value
kind: ConfigMap
metadata:
annotations:
config.kubernetes.io/path: configmap_env.yaml
name: env
`)
}

View File

@@ -385,12 +385,12 @@ spec:
- gcePersistentDisk:
pdName: nginx-persistent-storage
name: nginx-persistent-storage
- configMap:
name: staging-configmap-in-overlay-dc6fm46dhm
name: configmap-in-overlay
- configMap:
name: staging-team-foo-configmap-in-base-hc6g9dk6g9
name: configmap-in-base
- configMap:
name: staging-configmap-in-overlay-dc6fm46dhm
name: configmap-in-overlay
---
apiVersion: v1
kind: Service

View File

@@ -1,622 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package krusty_test
import (
"testing"
"github.com/stretchr/testify/assert"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)
// Regression test for https://github.com/kubernetes-sigs/kustomize/issues/3280
// GVKN shouldn't change with default options
func TestKeepOriginalGVKN(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("apps/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: old-name
spec:
template:
spec:
containers:
- name: nginx
image: nginx
`)
th.WriteF("apps/patch.yaml", `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: new-name
`)
th.WriteK("apps", `
resources:
- deployment.yaml
patches:
- path: patch.yaml
target:
kind: Deployment
`)
m := th.Run("apps", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: old-name
spec:
template:
spec:
containers:
- image: nginx
name: nginx
`)
}
// https://github.com/kubernetes-sigs/kustomize/issues/3280
// These tests document behavior that will change
func TestChangeName(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("apps/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: old-name
spec:
template:
spec:
containers:
- name: nginx
image: nginx
`)
th.WriteF("apps/patch.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: new-name
`)
th.WriteK("apps", `
resources:
- deployment.yaml
patches:
- path: patch.yaml
target:
kind: Deployment
`)
options := th.MakeDefaultOptions()
options.AllowResourceIdChanges = true
// name should become `new-name`
m := th.Run("apps", options)
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: old-name
spec:
template:
spec:
containers:
- image: nginx
name: nginx
`)
}
func TestChangeKind(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("apps/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: old-name
spec:
template:
spec:
containers:
- name: nginx
image: nginx
`)
th.WriteF("apps/patch.yaml", `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: old-name
`)
th.WriteK("apps", `
resources:
- deployment.yaml
patches:
- path: patch.yaml
target:
kind: Deployment
`)
options := th.MakeDefaultOptions()
options.AllowResourceIdChanges = true
// kind should become `StatefulSet`
m := th.Run("apps", options)
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: old-name
spec:
template:
spec:
containers:
- image: nginx
name: nginx
`)
}
func TestChangeNameAndKind(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("apps/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: old-name
spec:
template:
spec:
containers:
- name: nginx
image: nginx
`)
th.WriteF("apps/patch.yaml", `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: new-name
`)
th.WriteK("apps", `
resources:
- deployment.yaml
patches:
- path: patch.yaml
target:
kind: Deployment
`)
options := th.MakeDefaultOptions()
options.AllowResourceIdChanges = true
// kind should become `StatefulSet`
// name should become `new-name`
m := th.Run("apps", options)
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: old-name
spec:
template:
spec:
containers:
- image: nginx
name: nginx
`)
}
// https://github.com/kubernetes-sigs/kustomize/issues/3280
// Should be able to refer to a resource with either its
// original GVKN or its current one
func TestPatchOriginalName(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("base/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: old-name
spec:
template:
spec:
containers:
- name: nginx
image: nginx
`)
th.WriteF("base/patch.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: new-name
`)
th.WriteK("base", `
resources:
- deployment.yaml
patches:
- path: patch.yaml
target:
kind: Deployment
`)
th.WriteK("overlay", `
resources:
- ../base
patchesStrategicMerge:
- depPatch.yaml
`)
th.WriteF("overlay/depPatch.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: old-name
spec:
replicas: 999
`)
options := th.MakeDefaultOptions()
options.AllowResourceIdChanges = true
// name should become `new-name`
m := th.Run("overlay", options)
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: old-name
spec:
replicas: 999
template:
spec:
containers:
- image: nginx
name: nginx
`)
}
func TestPatchNewName(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("base/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: old-name
spec:
template:
spec:
containers:
- name: nginx
image: nginx
`)
th.WriteF("base/patch.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: new-name
`)
th.WriteK("base", `
resources:
- deployment.yaml
patches:
- path: patch.yaml
target:
kind: Deployment
`)
th.WriteK("overlay", `
resources:
- ../base
patchesStrategicMerge:
- depPatch.yaml
`)
th.WriteF("overlay/depPatch.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: new-name
spec:
replicas: 999
`)
options := th.MakeDefaultOptions()
options.AllowResourceIdChanges = true
// depPatch cannot find target with the name `new-name`
// because base/patch.yaml can't yet edit the name
assert.Error(t, th.RunWithErr("overlay", options))
}
func TestPatchOriginalNameAndKind(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("base/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: old-name
spec:
template:
spec:
containers:
- name: nginx
image: nginx
`)
th.WriteF("base/patch.yaml", `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: new-name
`)
th.WriteK("base", `
resources:
- deployment.yaml
patches:
- path: patch.yaml
target:
kind: Deployment
`)
th.WriteK("overlay", `
resources:
- ../base
patchesStrategicMerge:
- depPatch.yaml
`)
th.WriteF("overlay/depPatch.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: old-name
spec:
replicas: 999
`)
options := th.MakeDefaultOptions()
options.AllowResourceIdChanges = true
// kind should become `StatefulSet`
// name should become `new-name`
m := th.Run("overlay", options)
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: old-name
spec:
replicas: 999
template:
spec:
containers:
- image: nginx
name: nginx
`)
}
func TestPatchNewNameAndKind(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("base/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: old-name
spec:
template:
spec:
containers:
- name: nginx
image: nginx
`)
th.WriteF("base/patch.yaml", `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: new-name
`)
th.WriteK("base", `
resources:
- deployment.yaml
patches:
- path: patch.yaml
target:
kind: Deployment
`)
th.WriteK("overlay", `
resources:
- ../base
patchesStrategicMerge:
- depPatch.yaml
`)
th.WriteF("overlay/depPatch.yaml", `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: new-name
spec:
replicas: 999
`)
options := th.MakeDefaultOptions()
options.AllowResourceIdChanges = true
// depPatch cannot find target with kind `StatefulSet` and name `new-name`
// because base/patch.yaml can't yet edit the kind or name
assert.Error(t, th.RunWithErr("overlay", options))
}
// Use original name, but new kind
// Should fail, even after #3280 is done, because this ID is invalid
func TestPatchOriginalNameAndNewKind(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("base/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: old-name
spec:
template:
spec:
containers:
- name: nginx
image: nginx
`)
th.WriteF("base/patch.yaml", `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: new-name
`)
th.WriteK("base", `
resources:
- deployment.yaml
patches:
- path: patch.yaml
target:
kind: Deployment
`)
th.WriteK("overlay", `
resources:
- ../base
patchesStrategicMerge:
- depPatch.yaml
`)
th.WriteF("overlay/depPatch.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: new-name
spec:
replicas: 999
`)
options := th.MakeDefaultOptions()
options.AllowResourceIdChanges = true
// depPatch cannot find target with kind `Deployment` and name `new-name`
// because the resource never had this GVKN
assert.Error(t, th.RunWithErr("overlay", options))
}
// Here is a structure of a kustomization of two components, component1
// and component2, that both use a shared deployment definition, which
// component2 adjusts by changing the kind via a patch. This test case
// checks that it does not have a conflicting definition.
// Currently documents broken behavior.
//
// root
// / \
// component1/overlay component2/overlay
// | |
// component1/base component2/base
// \ /
// base
//
// This is the directory layout:
//
// ├── component1
// │ ├── base
// │ │ └── kustomization.yaml
// │ └── overlay
// │ └── kustomization.yaml
// ├── component2
// │ ├── base
// │ │ └── kustomization.yaml
// │ └── overlay
// │ └── kustomization.yaml
// ├── shared
// │ ├── kustomization.yaml
// │ └── deployment.yaml
// ├── kustomization.yaml
func TestBaseReuseNameAndKindConflict(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteK("/app/shared", `
resources:
- deployment.yaml
`)
th.WriteF("/app/shared/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deploy
spec:
template:
spec:
containers:
- name: nginx
image: nginx
`)
th.WriteK("/app/component1/base", `
resources:
- ../../shared
`)
th.WriteK("/app/component1/overlay", `
resources:
- ../base
namePrefix: overlay-
`)
th.WriteK("/app/component2/base", `
resources:
- ../../shared
patches:
- path: patch.yaml
target:
kind: Deployment
name: my-deploy
`)
th.WriteF("/app/component2/base/patch.yaml", `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-stateful-set
`)
th.WriteK("/app/component2/overlay", `
resources:
- ../base
namePrefix: overlay-
`)
th.WriteK("/app", `
resources:
- component1/overlay
- component2/overlay
`)
options := th.MakeDefaultOptions()
options.AllowResourceIdChanges = true
// Error occurs when app/component2/base tries to load the shared resources
// because the kind is not (yet) allowed to change yet
// so it loads a second Deployment with the name my-deploy
// instead of a StatefulSet as specified by the patch.
// Will be fixed by #3280.
assert.Error(t, th.RunWithErr("overlay", options))
}

View File

@@ -1,103 +0,0 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package krusty_test
/*
import (
"testing"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)
var expected string = `
apiVersion: v1
data:
rcon-password: Q0hBTkdFTUUh
kind: Secret
metadata:
labels:
app: test-minecraft
chart: minecraft-1.2.0
heritage: Helm
release: test
name: test-minecraft
type: Opaque
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
annotations:
volume.alpha.kubernetes.io/storage-class: default
labels:
app: test-minecraft
chart: minecraft-1.2.0
heritage: Helm
release: test
name: test-minecraft-datadir
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Service
metadata:
labels:
app: test-minecraft
chart: minecraft-1.2.0
heritage: Helm
release: test
name: test-minecraft
spec:
ports:
- name: minecraft
port: 25565
protocol: TCP
targetPort: minecraft
selector:
app: test-minecraft
type: LoadBalancer
`
func TestHelmChartInflationGenerator(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteK("/app", `
helmChartInflationGenerator:
- chartName: minecraft
chartRepoUrl: https://kubernetes-charts.storage.googleapis.com
chartVersion: v1.2.0
releaseName: test
releaseNamespace: testNamespace
`)
m := th.Run("/app", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, expected)
}
func TestHelmChartInflationGeneratorAsPlugin(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteK("/app", `
generators:
- helm.yaml
`)
th.WriteF("/app/helm.yaml", `
apiVersion: builtin
kind: HelmChartInflationGenerator
metadata:
name: myMap
chartName: minecraft
chartRepoUrl: https://kubernetes-charts.storage.googleapis.com
chartVersion: v1.2.0
releaseName: test
releaseNamespace: testNamespace
`)
m := th.Run("/app", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, expected)
}
*/

View File

@@ -1,79 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package krusty_test
import (
"testing"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func TestInlineTransformer(t *testing.T) {
th := kusttest_test.MakeEnhancedHarness(t)
defer th.Reset()
th.WriteF("/app/resource.yaml", `
apiVersion: apps/v1
kind: ConfigMap
metadata:
name: whatever
data: {}
`)
th.WriteK("/app", `
resources:
- resource.yaml
transformers:
- |-
apiVersion: builtin
kind: NamespaceTransformer
metadata:
name: not-important-to-example
namespace: test
fieldSpecs:
- path: metadata/namespace
create: true
`)
expected := `
apiVersion: apps/v1
data: {}
kind: ConfigMap
metadata:
name: whatever
namespace: test
`
m := th.Run("/app", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, expected)
}
func TestInlineGenerator(t *testing.T) {
th := kusttest_test.MakeEnhancedHarness(t)
defer th.Reset()
th.WriteK("/app", `
generators:
- |-
apiVersion: builtin
kind: ConfigMapGenerator
metadata:
name: mymap
literals:
- FRUIT=apple
- VEGETABLE=carrot
`)
expected := `
apiVersion: v1
data:
FRUIT: apple
VEGETABLE: carrot
kind: ConfigMap
metadata:
name: mymap-kfd8tf729k
`
m := th.Run("/app", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, expected)
}

View File

@@ -5,13 +5,13 @@ package provider
import (
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/internal/conflict"
k8sconflict "sigs.k8s.io/kustomize/api/internal/k8sdeps/conflict"
"sigs.k8s.io/kustomize/api/internal/k8sdeps/merge"
kmerge "sigs.k8s.io/kustomize/api/internal/merge"
"sigs.k8s.io/kustomize/api/internal/validate"
"sigs.k8s.io/kustomize/api/internal/wrappy"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/api/k8sdeps/validator"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
)
@@ -95,27 +95,17 @@ import (
// would really reduce the work
// (e.g. drop Vars, drop ReplacementTranformer).
//
// - resource.ConflictDetector
// - resmap.Merginator
//
// 1) api/internal/k8sdeps/conflict.conflictDetectorJson
// api/internal/k8sdeps/conflict.conflictDetectorSm
// 1) api/internal/k8sdeps/merge.Merginator
//
// Uses k8s.io/apimachinery/pkg/util/strategicpatch,
// apimachinery/pkg/util/mergepatch, etc. to merge
// resource.Resource instances.
//
// 2) api/internal/conflict.smPatchMergeOnlyDetector
// 2) api/internal/merge.Merginator
//
// At time of writing, this doesn't report conflicts,
// but it does know how to merge patches. Conflict
// reporting isn't vital to kustomize function. It's
// rare that a person would configure one transformer
// with many patches, much less so many that it became
// hard to spot conflicts. In the case of an undetected
// conflict, the last patch applied wins, likely what
// the user wants anyway. Regardless, the effect of this
// is plainly visible and usable in the output, even if
// a conflict happened but wasn't reported as an error.
// At time of writing, this is unimplemented.
//
// - ifc.Validator
//
@@ -126,7 +116,6 @@ import (
//
// 2) api/internal/validate.FieldValidator
//
// See TODO inside the validator for status.
// At time of writing, this is a do-nothing
// validator as it's not critical to kustomize function.
//
@@ -149,20 +138,18 @@ import (
// If you're reading this, plan not done.
//
type DepProvider struct {
kFactory ifc.KunstructuredFactory
resourceFactory *resource.Factory
conflictDectectorFactory resource.ConflictDetectorFactory
fieldValidator ifc.Validator
resourceFactory *resource.Factory
merginator resmap.Merginator
fieldValidator ifc.Validator
}
func makeK8sdepBasedInstances() *DepProvider {
kf := kunstruct.NewKunstructuredFactoryImpl()
rf := resource.NewFactory(kf)
return &DepProvider{
kFactory: kf,
resourceFactory: rf,
conflictDectectorFactory: k8sconflict.NewFactory(rf),
fieldValidator: validator.NewKustValidator(),
resourceFactory: rf,
merginator: merge.NewMerginator(rf),
fieldValidator: validator.NewKustValidator(),
}
}
@@ -170,10 +157,9 @@ func makeKyamlBasedInstances() *DepProvider {
kf := &wrappy.WNodeFactory{}
rf := resource.NewFactory(kf)
return &DepProvider{
kFactory: kf,
resourceFactory: rf,
conflictDectectorFactory: conflict.NewFactory(),
fieldValidator: validate.NewFieldValidator(),
resourceFactory: rf,
merginator: kmerge.NewMerginator(rf),
fieldValidator: validate.NewFieldValidator(),
}
}
@@ -184,20 +170,12 @@ func NewDepProvider(useKyaml bool) *DepProvider {
return makeK8sdepBasedInstances()
}
func NewDefaultDepProvider() *DepProvider {
return NewDepProvider(konfig.FlagEnableKyamlDefaultValue)
}
func (dp *DepProvider) GetKunstructuredFactory() ifc.KunstructuredFactory {
return dp.kFactory
}
func (dp *DepProvider) GetResourceFactory() *resource.Factory {
return dp.resourceFactory
}
func (dp *DepProvider) GetConflictDetectorFactory() resource.ConflictDetectorFactory {
return dp.conflictDectectorFactory
func (dp *DepProvider) GetMerginator() resmap.Merginator {
return dp.merginator
}
func (dp *DepProvider) GetFieldValidator() ifc.Validator {

View File

@@ -1,106 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package krusty_test
import (
"testing"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func writeIssueBase(th kusttest_test.Harness) {
th.WriteK("base", `
nameSuffix: -test-api
resources:
- deploy.yaml
`)
th.WriteF("base/deploy.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
`)
}
func TestIssue2896Base(t *testing.T) {
th := kusttest_test.MakeHarness(t)
writeIssueBase(th)
m := th.Run("base", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: example-test-api
spec:
template:
spec:
containers:
- image: example:1.0
name: example
volumeMounts:
- mountPath: /etc/config
name: conf
volumes:
- configMap:
name: conf
name: conf
`)
}
func TestIssue2896Overlay(t *testing.T) {
th := kusttest_test.MakeHarness(t)
writeIssueBase(th)
th.WriteK("overlay", `
resources:
- ../base
patches:
- patch: |-
apiVersion: apps/v1
kind: Deployment
metadata:
name: example
spec:
template:
spec:
containers:
- name: example
image: example:2.0
`)
m := th.Run("overlay", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: example-test-api
spec:
template:
spec:
containers:
- image: example:2.0
name: example
volumeMounts:
- mountPath: /etc/config
name: conf
volumes:
- configMap:
name: conf
name: conf
`)
}

View File

@@ -1,57 +0,0 @@
package krusty_test
import (
"testing"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func TestKustomizationMetadata(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("/app/resources.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: testing123
spec:
replicas: 1
selector: null
template:
spec:
containers:
- name: event
image: testing123
imagePullPolicy: IfNotPresent
imagePullSecrets: []`)
th.WriteK("/app", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
metadata:
annotations:
config.kubernetes.io/local-config: "true"
labels:
foo: bar
name: test_kustomization
resources:
- resources.yaml
`)
m := th.Run("/app", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: testing123
spec:
replicas: 1
selector: null
template:
spec:
containers:
- image: testing123
imagePullPolicy: IfNotPresent
name: event
imagePullSecrets: []
`)
}

View File

@@ -11,9 +11,9 @@ import (
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
"sigs.k8s.io/kustomize/api/internal/target"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/krusty/internal/provider"
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"
"sigs.k8s.io/kustomize/api/types"
)
@@ -53,7 +53,7 @@ func MakeKustomizer(fSys filesys.FileSystem, o *Options) *Kustomizer {
func (b *Kustomizer) Run(path string) (resmap.ResMap, error) {
resmapFactory := resmap.NewFactory(
b.depProvider.GetResourceFactory(),
b.depProvider.GetConflictDetectorFactory())
b.depProvider.GetMerginator())
lr := fLdr.RestrictionNone
if b.options.LoadRestrictions == types.LoadRestrictionsRootOnly {
lr = fLdr.RestrictionRootOnly
@@ -85,7 +85,7 @@ func (b *Kustomizer) Run(path string) (resmap.ResMap, error) {
t := builtins.LabelTransformerPlugin{
Labels: map[string]string{
konfig.ManagedbyLabelKey: fmt.Sprintf(
"kustomize-%s", provenance.GetProvenance().Semver())},
"kustomize-%s", provenance.GetProvenance().Version)},
FieldSpecs: []types.FieldSpec{{
Path: "metadata/labels",
CreateIfNotPresent: true,

View File

@@ -146,12 +146,12 @@ spec:
- gcePersistentDisk:
pdName: nginx-persistent-storage
name: nginx-persistent-storage
- configMap:
name: a-configmap-in-overlay-dc6fm46dhm
name: configmap-in-overlay
- configMap:
name: a-b-configmap-in-base-798k5k7g9f
name: configmap-in-base
- configMap:
name: a-configmap-in-overlay-dc6fm46dhm
name: configmap-in-overlay
---
apiVersion: v1
kind: Service
@@ -351,12 +351,12 @@ spec:
- gcePersistentDisk:
pdName: nginx-persistent-storage
name: nginx-persistent-storage
- configMap:
name: staging-configmap-in-overlay-dc6fm46dhm
name: configmap-in-overlay
- configMap:
name: staging-team-foo-configmap-in-base-798k5k7g9f
name: configmap-in-base
- configMap:
name: staging-configmap-in-overlay-dc6fm46dhm
name: configmap-in-overlay
---
apiVersion: v1
kind: Service

View File

@@ -159,7 +159,7 @@ subjects:
name: default
namespace: irrelevant
---
apiVersion: admissionregistration.k8s.io/v1
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
name: example
@@ -180,17 +180,15 @@ webhooks:
name: svc3
namespace: random
---
apiVersion: apiextensions.k8s.io/v1
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: crds.my.org
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cr1
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: crb1
@@ -199,7 +197,6 @@ subjects:
name: default
namespace: irrelevant
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv1
@@ -260,7 +257,7 @@ subjects:
name: default
namespace: newnamespace
---
apiVersion: admissionregistration.k8s.io/v1
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
name: p1-example-s1
@@ -281,17 +278,15 @@ webhooks:
namespace: random
name: example3
---
apiVersion: apiextensions.k8s.io/v1
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: crds.my.org
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: p1-cr1-s1
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: p1-crb1-s1
@@ -300,7 +295,6 @@ subjects:
name: default
namespace: newnamespace
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: p1-pv1-s1

View File

@@ -1,287 +0,0 @@
package krusty_test
import (
"testing"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)
// https://github.com/kubernetes-sigs/kustomize/issues/2640
func TestNameUpdateInRoleRef(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("/app/rbac.yaml", `
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: my-role
rules:
- apiGroups:
- '*'
resources:
- '*'
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: my-role
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: my-role
subjects:
- kind: ServiceAccount
name: default
namespace: foo
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: my-role
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: my-role
roleRef:
apiGroup: rbac.authorization.k8s.io
version: v1
kind: Role
name: my-role
subjects:
- kind: ServiceAccount
name: default
`)
th.WriteK("/app", `
namespace: foo
resources:
- rbac.yaml
patches:
- patch: |-
- op: add
path: /metadata/name
value: prefix_my-role
target:
group: rbac.authorization.k8s.io
version: v1
kind: ClusterRole
name: my-role
`)
m := th.Run("/app", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: prefix_my-role
rules:
- apiGroups:
- '*'
resources:
- '*'
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: my-role
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: prefix_my-role
subjects:
- kind: ServiceAccount
name: default
namespace: foo
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: my-role
namespace: foo
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: my-role
namespace: foo
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: my-role
version: v1
subjects:
- kind: ServiceAccount
name: default
namespace: foo
`)
}
// https://github.com/kubernetes-sigs/kustomize/issues/3073
func TestNameUpdateInRoleRef2(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("/app/workloads.yaml", `
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: myapp
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: myapp
rules:
- apiGroups:
- ""
resources:
- nodes/metrics
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: myapp
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: myapp
subjects:
- kind: ServiceAccount
name: myapp
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: myapp
rules:
- apiGroups:
- ""
resources:
- services
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: myapp
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: myapp
subjects:
- kind: ServiceAccount
name: myapp
`)
th.WriteF("/app/suffixTransformer.yaml", `
apiVersion: builtin
kind: PrefixSuffixTransformer
metadata:
name: notImportantHere
suffix: -suffix
fieldSpecs:
- path: metadata/name
kind: ClusterRole
name: myapp
- path: metadata/name
kind: ClusterRoleBinding
name: myapp
`)
th.WriteK("/app", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- workloads.yaml
transformers:
- suffixTransformer.yaml
namespace: test
`)
m := th.Run("/app", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: v1
kind: ServiceAccount
metadata:
name: myapp
namespace: test
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: myapp-suffix
rules:
- apiGroups:
- ""
resources:
- nodes/metrics
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: myapp-suffix
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: myapp-suffix
subjects:
- kind: ServiceAccount
name: myapp
namespace: test
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: myapp
namespace: test
rules:
- apiGroups:
- ""
resources:
- services
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: myapp
namespace: test
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: myapp
subjects:
- kind: ServiceAccount
name: myapp
namespace: test
`)
}

View File

@@ -9,7 +9,7 @@ import (
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func TestNullValues1(t *testing.T) {
func TestNullValues(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("/app/deployment.yaml", `
apiVersion: apps/v1
@@ -62,36 +62,3 @@ spec:
name: example
`)
}
func TestNullValues2(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("deploy.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: test
spec:
template:
spec:
containers:
- name: test
volumes: null
`)
th.WriteK(".", `
resources:
- deploy.yaml
`)
m := th.Run(".", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: test
spec:
template:
spec:
containers:
- name: test
volumes: null
`)
}

View File

@@ -36,21 +36,16 @@ type Options struct {
// When true, use kyaml/ packages to manipulate KRM yaml.
// When false, use k8sdeps/ instead (uses k8s.io/api* packages).
UseKyaml bool
// When true, allow name and kind changing via a patch
// When false, patch name/kind don't overwrite target name/kind
AllowResourceIdChanges bool
}
// MakeDefaultOptions returns a default instance of Options.
func MakeDefaultOptions() *Options {
return &Options{
DoLegacyResourceSort: false,
AddManagedbyLabel: false,
LoadRestrictions: types.LoadRestrictionsRootOnly,
DoPrune: false,
PluginConfig: konfig.DisabledPluginConfig(),
UseKyaml: false,
AllowResourceIdChanges: false,
DoLegacyResourceSort: false,
AddManagedbyLabel: false,
LoadRestrictions: types.LoadRestrictionsRootOnly,
DoPrune: false,
PluginConfig: konfig.DisabledPluginConfig(),
UseKyaml: false,
}
}

View File

@@ -213,132 +213,3 @@ roleRef:
name: my-role-ns2
`)
}
// The ServiceAccount in subjects in role binding can be across namespace
// but the roleRef is not. This test is used to cover such case.
func TestRoleBindingWhenSubjectsAcrossNamespace(t *testing.T) {
th := kusttest_test.MakeEnhancedHarness(t)
defer th.Reset()
th.WriteK("/app", `
resources:
- ./ns1
- ./ns2
`)
th.WriteK("/app/ns1", `
namespace: namespace-1
resources:
- role-ns1.yaml
- rolebinding-ns1.yaml
`)
th.WriteF("/app/ns1/role-ns1.yaml", `
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: testRole
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get"]
`)
th.WriteF("/app/ns1/rolebinding-ns1.yaml", `
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: testRoleBinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: testRole
subjects:
- kind: ServiceAccount
name: testAccount
namespace: namespace-2
`)
th.WriteK("/app/ns2", `
namespace: namespace-2
resources:
- role-ns2.yaml
- rolebinding-ns2.yaml
`)
th.WriteF("/app/ns2/role-ns2.yaml", `
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: testRole
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get"]
`)
th.WriteF("/app/ns2/rolebinding-ns2.yaml", `
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: testRoleBinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: testRole
subjects:
- kind: ServiceAccount
name: testAccount
namespace: namespace-1
`)
m := th.Run("/app", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: testRole
namespace: namespace-1
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: testRoleBinding
namespace: namespace-1
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: testRole
subjects:
- kind: ServiceAccount
name: testAccount
namespace: namespace-2
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: testRole
namespace: namespace-2
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: testRoleBinding
namespace: namespace-2
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: testRole
subjects:
- kind: ServiceAccount
name: testAccount
namespace: namespace-1
`)
}

View File

@@ -215,25 +215,25 @@ spec2:
template:
spec:
containers:
- image: nginx:v2
- image: nginx:v1
name: nginx3
- image: my-nginx:previous
- image: my-nginx:latest
name: nginx4
spec3:
template:
spec:
initContainers:
- image: my-postgres:v3
- image: postgres:alpine-9
name: postgresdb
- image: my-docker@sha256:25a0d4b4
- image: docker:17-git
name: init-docker
- image: myprivaterepohostname:1234/my/image:v1.0.1
- image: myprivaterepohostname:1234/my/image:latest
name: myImage
- image: myprivaterepohostname:1234/my/image:v1.0.1
- image: myprivaterepohostname:1234/my/image
name: myImage2
- image: my-app-image:v1
name: my-app
- image: my-cool-app:latest
- image: gcr.io:8080/my-project/my-cool-app:latest
name: my-cool-app
`)
}

View File

@@ -1969,70 +1969,3 @@ spec:
server: kustomized-nfs-server-service.default.srv.cluster.local
`)
}
func TestDeploymentAnnotations(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteK("/app", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
configMapGenerator:
- name: testConfigMap
envs:
- test.properties
vars:
- name: FOO
objref:
kind: ConfigMap
name: testConfigMap
apiVersion: v1
fieldref:
fieldpath: data.foo
commonAnnotations:
foo: $(FOO)
resources:
- deployment.yaml
`)
th.WriteF("/app/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: test
spec:
template:
spec:
containers:
- name: test
`)
th.WriteF("/app/test.properties", `foo=bar`)
m := th.Run("/app", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
foo: bar
name: test
spec:
template:
metadata:
annotations:
foo: bar
spec:
containers:
- name: test
---
apiVersion: v1
data:
foo: bar
kind: ConfigMap
metadata:
annotations:
foo: bar
name: testConfigMap-798k5k7g9f
`)
}

View File

@@ -20,9 +20,6 @@ type remoteTargetSpec struct {
// Dir is where the resource is saved
Dir filesys.ConfirmedDir
// TempDir is the directory created to hold all resources, including Dir
TempDir filesys.ConfirmedDir
}
// Getter is a function that can gets resource
@@ -34,7 +31,7 @@ func newLoaderAtGetter(raw string, fSys filesys.FileSystem, referrer *fileLoader
}
cleaner := func() error {
return fSys.RemoveAll(rs.TempDir.String())
return fSys.RemoveAll(rs.Dir.String())
}
if err := getter(rs); err != nil {
@@ -58,12 +55,12 @@ func newLoaderAtGetter(raw string, fSys filesys.FileSystem, referrer *fileLoader
func getRemoteTarget(rs *remoteTargetSpec) error {
var err error
rs.TempDir, err = filesys.NewTmpConfirmedDir()
rs.Dir, err = filesys.NewTmpConfirmedDir()
if err != nil {
return err
}
rs.Dir = filesys.ConfirmedDir(rs.TempDir.Join("repo"))
rs.Dir = filesys.ConfirmedDir(rs.Dir.Join("repo"))
// Get the pwd
pwd, err := os.Getwd()
@@ -80,7 +77,6 @@ func getRemoteTarget(rs *remoteTargetSpec) error {
Mode: getter.ClientModeAny,
Detectors: []getter.Detector{
new(getter.GitHubDetector),
new(getter.GitLabDetector),
new(getter.GitDetector),
new(getter.BitBucketDetector),
},

View File

@@ -6,7 +6,6 @@ package provenance
import (
"fmt"
"runtime"
"strings"
)
var (
@@ -58,11 +57,3 @@ func (v Provenance) Short() string {
BuildDate: v.BuildDate,
})
}
// Semver returns the semantic version of kustomize.
// kustomize version is set in format "kustomize/vX.X.X" in every release.
// X.X.X is a semver. If the version string is not in this format,
// return the original version string
func (v Provenance) Semver() string {
return strings.TrimPrefix(v.Version, "kustomize/")
}

View File

@@ -5,9 +5,6 @@ package resid
import (
"strings"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// Gvk identifies a Kubernetes API type.
@@ -80,22 +77,6 @@ func (x Gvk) String() string {
return strings.Join([]string{g, v, k}, fieldSep)
}
// StringWoEmptyField returns a string representation of the GVK. Non-exist
// fields will be omitted.
func (x Gvk) StringWoEmptyField() string {
var s []string
if x.Group != "" {
s = append(s, x.Group)
}
if x.Version != "" {
s = append(s, x.Version)
}
if x.Kind != "" {
s = append(s, x.Kind)
}
return strings.Join(s, fieldSep)
}
// Equals returns true if the Gvk's have equal fields.
func (x Gvk) Equals(o Gvk) bool {
return x.Group == o.Group && x.Version == o.Version && x.Kind == o.Kind
@@ -118,7 +99,6 @@ var orderFirst = []string{
"ClusterRoleBinding",
"ConfigMap",
"Secret",
"Endpoints",
"Service",
"LimitRange",
"PriorityClass",
@@ -191,23 +171,39 @@ func (x Gvk) IsSelected(selector *Gvk) bool {
return true
}
// toKyamlTypeMeta returns a yaml.TypeMeta from x's information.
func (x Gvk) toKyamlTypeMeta() yaml.TypeMeta {
var apiVersion strings.Builder
if x.Group != "" {
apiVersion.WriteString(x.Group)
apiVersion.WriteString("/")
}
apiVersion.WriteString(x.Version)
return yaml.TypeMeta{
APIVersion: apiVersion.String(),
Kind: x.Kind,
}
var notNamespaceableKinds = []string{
"APIService",
"CSIDriver",
"CSINode",
"CertificateSigningRequest",
"Cluster",
"ClusterRole",
"ClusterRoleBinding",
"ComponentStatus",
"CustomResourceDefinition",
"MutatingWebhookConfiguration",
"Namespace",
"Node",
"PersistentVolume",
"PodSecurityPolicy",
"PriorityClass",
"RuntimeClass",
"SelfSubjectAccessReview",
"SelfSubjectRulesReview",
"StorageClass",
"SubjectAccessReview",
"TokenReview",
"ValidatingWebhookConfiguration",
"VolumeAttachment",
}
// IsNamespaceableKind returns true if x is a namespaceable Gvk
// Implements https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/#not-all-objects-are-in-a-namespace
func (x Gvk) IsNamespaceableKind() bool {
isNamespaceScoped, found := openapi.IsNamespaceScoped(x.toKyamlTypeMeta())
return !found || isNamespaceScoped
for _, k := range notNamespaceableKinds {
if k == x.Kind {
return false
}
}
return true
}

View File

@@ -18,8 +18,6 @@ package resid
import (
"testing"
"github.com/stretchr/testify/assert"
)
var equalsTests = []struct {
@@ -80,8 +78,6 @@ var lessThanTests = []struct {
Gvk{Group: "a", Version: "b", Kind: "ValidatingWebhookConfiguration"}},
{Gvk{Group: "a", Version: "b", Kind: "Service"},
Gvk{Group: "a", Version: "b", Kind: "APIService"}},
{Gvk{Group: "a", Version: "b", Kind: "Endpoints"},
Gvk{Group: "a", Version: "b", Kind: "Service"}},
}
func TestIsLessThan1(t *testing.T) {
@@ -98,16 +94,15 @@ func TestIsLessThan1(t *testing.T) {
var stringTests = []struct {
x Gvk
s string
r string
}{
{Gvk{}, "~G_~V_~K", ""},
{Gvk{Kind: "k"}, "~G_~V_k", "k"},
{Gvk{Version: "v"}, "~G_v_~K", "v"},
{Gvk{Version: "v", Kind: "k"}, "~G_v_k", "v_k"},
{Gvk{Group: "g"}, "g_~V_~K", "g"},
{Gvk{Group: "g", Kind: "k"}, "g_~V_k", "g_k"},
{Gvk{Group: "g", Version: "v"}, "g_v_~K", "g_v"},
{Gvk{Group: "g", Version: "v", Kind: "k"}, "g_v_k", "g_v_k"},
{Gvk{}, "~G_~V_~K"},
{Gvk{Kind: "k"}, "~G_~V_k"},
{Gvk{Version: "v"}, "~G_v_~K"},
{Gvk{Version: "v", Kind: "k"}, "~G_v_k"},
{Gvk{Group: "g"}, "g_~V_~K"},
{Gvk{Group: "g", Kind: "k"}, "g_~V_k"},
{Gvk{Group: "g", Version: "v"}, "g_v_~K"},
{Gvk{Group: "g", Version: "v", Kind: "k"}, "g_v_k"},
}
func TestString(t *testing.T) {
@@ -118,14 +113,6 @@ func TestString(t *testing.T) {
}
}
func TestStringWoEmptyField(t *testing.T) {
for _, hey := range stringTests {
if hey.x.StringWoEmptyField() != hey.r {
t.Fatalf("bad string %s for %v '%s'", hey.x.StringWoEmptyField(), hey.x, hey.r)
}
}
}
func TestParseGroupVersion(t *testing.T) {
tests := []struct {
input string
@@ -257,40 +244,3 @@ func TestSelectByGVK(t *testing.T) {
}
}
}
func TestIsNamespaceableKind(t *testing.T) {
testCases := []struct {
name string
gvk Gvk
expected bool
}{
{
"namespaceable resource",
Gvk{Group: "apps", Version: "v1", Kind: "Deployment"},
true,
},
{
"clusterscoped resource",
Gvk{Group: "", Version: "v1", Kind: "Namespace"},
false,
},
{
"unknown resource (should default to namespaceable)",
Gvk{Group: "example1.com", Version: "v1", Kind: "Bar"},
true,
},
{
"unknown resource (should default to namespaceable)",
Gvk{Group: "apps", Version: "v1", Kind: "ClusterRoleBinding"},
true,
},
}
for i := range testCases {
test := testCases[i]
t.Run(test.name, func(t *testing.T) {
isNamespaceable := test.gvk.IsNamespaceableKind()
assert.Equal(t, test.expected, isNamespaceable)
})
}
}

View File

@@ -265,7 +265,7 @@ func TestResIdEquals(t *testing.T) {
Name: "nm",
},
gVknResult: false,
nsEquals: true,
nsEquals: false,
equals: false,
},
{
@@ -376,7 +376,7 @@ func TestEffectiveNamespace(t *testing.T) {
}{
{
id: ResId{
Gvk: Gvk{Group: "", Version: "v1", Kind: "Node"},
Gvk: Gvk{Group: "g", Version: "v", Kind: "Node"},
Name: "nm",
},
expected: TotallyNotANamespace,
@@ -384,7 +384,7 @@ func TestEffectiveNamespace(t *testing.T) {
{
id: ResId{
Namespace: "foo",
Gvk: Gvk{Group: "", Version: "v1", Kind: "Node"},
Gvk: Gvk{Group: "g", Version: "v", Kind: "Node"},
Name: "nm",
},
expected: TotallyNotANamespace,

View File

@@ -9,21 +9,26 @@ import (
"sigs.k8s.io/kustomize/api/internal/kusterr"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// Merginator merges resources.
type Merginator interface {
// Merge creates a new ResMap by merging incoming resources.
// Error if conflict found.
Merge([]*resource.Resource) (ResMap, error)
}
// Factory makes instances of ResMap.
type Factory struct {
// Makes resources.
resF *resource.Factory
// Makes ConflictDetectors.
cdf resource.ConflictDetectorFactory
// Makes ResMaps via merging.
pm Merginator
}
// NewFactory returns a new resmap.Factory.
func NewFactory(
rf *resource.Factory, cdf resource.ConflictDetectorFactory) *Factory {
return &Factory{resF: rf, cdf: cdf}
func NewFactory(rf *resource.Factory, pm Merginator) *Factory {
return &Factory{resF: rf, pm: pm}
}
// RF returns a resource.Factory.
@@ -128,8 +133,8 @@ func (rmF *Factory) FromSecretArgs(
// Merge creates a new ResMap by merging incoming resources.
// Error if conflict found.
func (rmF *Factory) Merge(incoming []*resource.Resource) (ResMap, error) {
return (&merginator{cdf: rmF.cdf}).Merge(incoming)
func (rmF *Factory) Merge(patches []*resource.Resource) (ResMap, error) {
return rmF.pm.Merge(patches)
}
func newResMapFromResourceSlice(
@@ -143,20 +148,3 @@ func newResMapFromResourceSlice(
}
return result, nil
}
// NewResMapFromRNodeSlice returns a ResMap from a slice of RNodes
func (rmF *Factory) NewResMapFromRNodeSlice(rnodes []*yaml.RNode) (ResMap, error) {
var resources []*resource.Resource
for _, rnode := range rnodes {
s, err := rnode.String()
if err != nil {
return nil, err
}
r, err := rmF.resF.FromBytes([]byte(s))
if err != nil {
return nil, err
}
resources = append(resources, r)
}
return newResMapFromResourceSlice(resources)
}

View File

@@ -5,20 +5,18 @@ package resmap_test
import (
"encoding/base64"
"reflect"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/kv"
"sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/resid"
. "sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
resmaptest_test "sigs.k8s.io/kustomize/api/testutils/resmaptest"
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
func TestFromFile(t *testing.T) {
@@ -61,21 +59,29 @@ metadata:
"name": "dply2",
"namespace": "test",
}}).ResMap()
expYaml, err := expected.AsYaml()
assert.NoError(t, err)
fSys := filesys.MakeFsInMemory()
assert.NoError(t, fSys.WriteFile("deployment.yaml", []byte(resourceStr)))
err := fSys.WriteFile("deployment.yaml", []byte(resourceStr))
if err != nil {
t.Fatal(err)
}
ldr, err := loader.NewLoader(
loader.RestrictionRootOnly, filesys.Separator, fSys)
assert.NoError(t, err)
if err != nil {
t.Fatal(err)
}
m, err := rmF.FromFile(ldr, "deployment.yaml")
assert.NoError(t, err)
mYaml, err := m.AsYaml()
assert.NoError(t, err)
assert.Equal(t, expYaml, mYaml)
if err != nil {
t.Fatal(err)
}
if m.Size() != 3 {
t.Fatalf("result should contain 3, but got %d", m.Size())
}
if err := expected.ErrorIfNotEqualLists(m); err != nil {
t.Fatalf("actual doesn't match expected: %v", err)
}
}
func TestFromBytes(t *testing.T) {
@@ -102,15 +108,17 @@ metadata:
"metadata": map[string]interface{}{
"name": "cm2",
}}).ResMap()
expYaml, err := expected.AsYaml()
assert.NoError(t, err)
m, err := rmF.NewResMapFromBytes(encoded)
assert.NoError(t, err)
mYaml, err := m.AsYaml()
assert.NoError(t, err)
assert.Equal(t, expYaml, mYaml)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !reflect.DeepEqual(m, expected) {
t.Fatalf("%#v doesn't match expected %#v", m, expected)
}
}
var cmap = resid.Gvk{Version: "v1", Kind: "ConfigMap"}
func TestNewFromConfigMaps(t *testing.T) {
type testCase struct {
description string
@@ -220,12 +228,12 @@ BAR=baz
}
}
r, err := rmF.NewResMapFromConfigMapArgs(kvLdr, tc.input)
assert.NoError(t, err, tc.description)
rYaml, err := r.AsYaml()
assert.NoError(t, err, tc.description)
expYaml, err := tc.expected.AsYaml()
assert.NoError(t, err, tc.description)
assert.Equal(t, expYaml, rYaml)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if err = tc.expected.ErrorIfNotEqualLists(r); err != nil {
t.Fatalf("testcase: %q, err: %v", tc.description, err)
}
}
}
@@ -254,8 +262,6 @@ func TestNewResMapFromSecretArgs(t *testing.T) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
actYaml, err := actual.AsYaml()
assert.NoError(t, err)
expected := resmaptest_test.NewRmBuilder(t, rf).Add(
map[string]interface{}{
@@ -270,127 +276,7 @@ func TestNewResMapFromSecretArgs(t *testing.T) {
"DB_PASSWORD": base64.StdEncoding.EncodeToString([]byte("somepw")),
},
}).ResMap()
expYaml, err := expected.AsYaml()
assert.NoError(t, err)
assert.Equal(t, string(expYaml), string(actYaml))
}
func TestFromRNodeSlice(t *testing.T) {
input := `apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: namespace-reader
rules:
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- watch
- list
`
rnodes := []*yaml.RNode{
yaml.MustParse(input),
}
rm, err := rmF.NewResMapFromRNodeSlice(rnodes)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
expected := resmaptest_test.NewRmBuilder(t, rf).Add(
map[string]interface{}{
"apiVersion": "rbac.authorization.k8s.io/v1",
"kind": "ClusterRole",
"metadata": map[string]interface{}{
"name": "namespace-reader",
},
"rules": []interface{}{
map[string]interface{}{
"apiGroups": []interface{}{
"",
},
"resources": []interface{}{
"namespaces",
},
"verbs": []interface{}{
"get",
"watch",
"list",
},
},
},
}).ResMap()
if err = expected.ErrorIfNotEqualLists(rm); err != nil {
if err = expected.ErrorIfNotEqualLists(actual); err != nil {
t.Fatalf("error: %s", err)
}
}
func TestMerge_Empty(t *testing.T) {
rm, err := rmF.Merge([]*resource.Resource{})
assert.NoError(t, err)
assert.Equal(t, 0, rm.Size())
}
func TestMerge(t *testing.T) {
var (
err error
yml []byte
r1, r2 *resource.Resource
)
r1, err = rf.FromBytes([]byte(`apiVersion: example.com/v1
kind: Foo
metadata:
name: my-foo
spec:
bar:
B:
C: Z
`))
assert.NoError(t, err)
r2, err = rf.FromBytes([]byte(`apiVersion: example.com/v1
kind: Foo
metadata:
name: my-foo
spec:
bar:
C: Z
D: W
baz:
hello: world
`))
assert.NoError(t, err)
rm, err := rmF.Merge([]*resource.Resource{r1, r2})
assert.NoError(t, err)
yml, err = rm.AsYaml()
assert.NoError(t, err)
assert.Equal(t, konfig.IfApiMachineryElseKyaml(`apiVersion: example.com/v1
kind: Foo
metadata:
name: my-foo
spec:
bar:
B: null
C: Z
D: W
baz:
hello: world
`, `apiVersion: example.com/v1
kind: Foo
metadata:
name: my-foo
spec:
bar:
C: Z
D: W
baz:
hello: world
`), string(yml))
}

View File

@@ -1,118 +0,0 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package resmap
import (
"fmt"
"sigs.k8s.io/kustomize/api/resource"
)
// merginator coordinates merging the resources in incoming to the result.
type merginator struct {
incoming []*resource.Resource
cdf resource.ConflictDetectorFactory
result ResMap
}
func (m *merginator) Merge(in []*resource.Resource) (ResMap, error) {
m.result = New()
m.incoming = in
for index := range m.incoming {
alreadyInResult, err := m.appendIfNoMatch(index)
if err != nil {
return nil, err
}
if alreadyInResult != nil {
// The resource at index has the same resId as a previously
// considered resource.
//
// If they conflict with each other (e.g. they both want to change
// the image name in a Deployment, but to different values),
// return an error.
//
// If they don't conflict, then merge them into a single resource,
// since they both target the same item, and we want cumulative
// behavior. E.g. say both patches modify a map. Without a merge,
// the last patch wins, replacing the entire map.
err = m.mergeWithExisting(index, alreadyInResult)
if err != nil {
return nil, err
}
}
}
return m.result, nil
}
func (m *merginator) appendIfNoMatch(index int) (*resource.Resource, error) {
candidate := m.incoming[index]
matchedResources := m.result.GetMatchingResourcesByOriginalId(
candidate.OrgId().Equals)
if len(matchedResources) == 0 {
m.result.Append(candidate)
return nil, nil
}
if len(matchedResources) > 1 {
return nil, fmt.Errorf("multiple resources targeted by patch")
}
return matchedResources[0], nil
}
func (m *merginator) mergeWithExisting(
index int, alreadyInResult *resource.Resource) error {
candidate := m.incoming[index]
cd, err := m.cdf.New(candidate.OrgId().Gvk)
if err != nil {
return err
}
hasConflict, err := cd.HasConflict(candidate, alreadyInResult)
if err != nil {
return err
}
if hasConflict {
return m.makeError(cd, index)
}
merged, err := cd.MergePatches(alreadyInResult, candidate)
if err != nil {
return err
}
_, err = m.result.Replace(merged)
return err
}
// Make an error message describing the conflict.
func (m *merginator) makeError(cd resource.ConflictDetector, index int) error {
conflict, err := m.findConflict(cd, index)
if err != nil {
return err
}
if conflict == nil {
return fmt.Errorf("expected conflict for %s", m.incoming[index].OrgId())
}
return fmt.Errorf(
"conflict between %#v at index %d and %#v",
m.incoming[index].Map(), index, conflict.Map())
}
// findConflict looks for a conflict in a resource slice.
// It returns the first conflict between the resource at index
// and some other resource. Two resources can only conflict if
// they have the same original ResId.
func (m *merginator) findConflict(
cd resource.ConflictDetector, index int) (*resource.Resource, error) {
targetId := m.incoming[index].OrgId()
for i, p := range m.incoming {
if i == index || !targetId.Equals(p.OrgId()) {
continue
}
conflict, err := cd.HasConflict(p, m.incoming[index])
if err != nil {
return nil, err
}
if conflict {
return p, nil
}
}
return nil, nil
}

View File

@@ -10,7 +10,6 @@ import (
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// A Transformer modifies an instance of ResMap.
@@ -236,13 +235,4 @@ type ResMap interface {
// Select returns a list of resources that
// are selected by a Selector
Select(types.Selector) ([]*resource.Resource, error)
// ToRNodeSlice converts the resources in the resmp
// to a list of RNodes
ToRNodeSlice() ([]*yaml.RNode, error)
// ApplySmPatch applies a strategic-merge patch to the
// selected set of resources.
ApplySmPatch(
selectedSet *resource.IdSet, patch *resource.Resource) error
}

View File

@@ -6,13 +6,12 @@ package resmap
import (
"bytes"
"fmt"
"strings"
"regexp"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
kyaml_yaml "sigs.k8s.io/kustomize/kyaml/yaml"
"sigs.k8s.io/yaml"
)
@@ -340,8 +339,10 @@ func (m *resWrangler) ErrorIfNotEqualLists(other ResMap) error {
}
for i, r1 := range m.rList {
r2 := m2.rList[i]
if err := r1.ErrIfNotEquals(r2); err != nil {
return err
if !r1.Equals(r2) {
return fmt.Errorf(
"Item i=%d differs:\n n1 = %s\n n2 = %s\n o1 = %s\n o2 = %s\n",
i, r1.OrgId(), r2.OrgId(), r1, r2)
}
}
return nil
@@ -509,34 +510,51 @@ func (m *resWrangler) appendReplaceOrMerge(
return nil
}
func anchorRegex(pattern string) string {
if pattern == "" {
return pattern
}
return "^" + pattern + "$"
}
// Select returns a list of resources that
// are selected by a Selector
func (m *resWrangler) Select(s types.Selector) ([]*resource.Resource, error) {
ns := regexp.MustCompile(anchorRegex(s.Namespace))
nm := regexp.MustCompile(anchorRegex(s.Name))
var result []*resource.Resource
sr, err := types.NewSelectorRegex(&s)
if err != nil {
return nil, err
}
for _, r := range m.Resources() {
curId := r.CurId()
orgId := r.OrgId()
// matches the namespace when namespace is not empty in the selector
// It first tries to match with the original namespace
// then matches with the current namespace
if !sr.MatchNamespace(orgId.EffectiveNamespace()) &&
!sr.MatchNamespace(curId.EffectiveNamespace()) {
continue
if r.GetNamespace() != "" {
matched := ns.MatchString(orgId.EffectiveNamespace())
if !matched {
matched = ns.MatchString(curId.EffectiveNamespace())
if !matched {
continue
}
}
}
// matches the name when name is not empty in the selector
// It first tries to match with the original name
// then matches with the current name
if !sr.MatchName(orgId.Name) &&
!sr.MatchName(curId.Name) {
continue
if r.GetName() != "" {
matched := nm.MatchString(orgId.Name)
if !matched {
matched = nm.MatchString(curId.Name)
if !matched {
continue
}
}
}
// matches the GVK
if !sr.MatchGvk(r.GetGvk()) {
if !r.GetGvk().IsSelected(&s.Gvk) {
continue
}
@@ -561,64 +579,3 @@ func (m *resWrangler) Select(s types.Selector) ([]*resource.Resource, error) {
}
return result, nil
}
// ToRNodeSlice converts the resources in the resmp
// to a list of RNodes
func (m *resWrangler) ToRNodeSlice() ([]*kyaml_yaml.RNode, error) {
var rnodes []*kyaml_yaml.RNode
for _, r := range m.Resources() {
s, err := r.AsYAML()
if err != nil {
return nil, err
}
rnode, err := kyaml_yaml.Parse(string(s))
if err != nil {
return nil, err
}
rnodes = append(rnodes, rnode)
}
return rnodes, nil
}
func (m *resWrangler) ApplySmPatch(
selectedSet *resource.IdSet, patch *resource.Resource) error {
newRm := New()
for _, res := range m.Resources() {
if !selectedSet.Contains(res.CurId()) {
newRm.Append(res)
continue
}
patchCopy := patch.DeepCopy()
patchCopy.SetName(res.GetName())
patchCopy.SetNamespace(res.GetNamespace())
patchCopy.SetGvk(res.GetGvk())
err := res.ApplySmPatch(patchCopy)
if err != nil {
// Check for an error string from UnmarshalJSON that's indicative
// of an object that's missing basic KRM fields, and thus may have been
// entirely deleted (an acceptable outcome). This error handling should
// be deleted along with use of ResMap and apimachinery functions like
// UnmarshalJSON.
if !strings.Contains(err.Error(), "Object 'Kind' is missing") {
// Some unknown error, let it through.
return err
}
if !res.IsEmpty() {
return errors.Wrapf(
err, "with unexpectedly non-empty object map of size %d",
len(res.Map()))
}
// Fall through to handle deleted object.
}
if !res.IsEmpty() {
// IsEmpty means all fields have been removed from the object.
// This can happen if a patch required deletion of the
// entire resource (not just a part of it). This means
// the overall resmap must shrink by one.
newRm.Append(res)
}
}
m.Clear()
m.AppendAll(newRm)
return nil
}

Some files were not shown because too many files have changed in this diff Show More