Compare commits

..

116 Commits

Author SHA1 Message Date
Kubernetes Prow Robot
243394002f Merge pull request #2391 from pwittrock/validation-spec
Allow declaratively running starlark functions
2020-04-22 09:27:53 -07:00
Jeff Regan
b9053655db Merge pull request #2395 from monopole/checkForProwNotTravis
Check for prow, not travis, in CI test.
2020-04-21 21:19:45 -07:00
jregan
1f35b37712 Check for prow, not travis, in CI test. 2020-04-21 21:09:09 -07:00
Kubernetes Prow Robot
d7484aacad Merge pull request #2394 from monopole/installHelm3
Start adding helm3 to ChartInflator and its coverage.
2020-04-21 21:03:51 -07:00
jregan
98414e8bf6 Start adding helm3 to ChartInflator and its coverage. 2020-04-21 20:45:19 -07:00
Phillip Wittrock
c1f2dd3688 Allow declaratively running starlark functions 2020-04-21 14:51:15 -07:00
Jeff Regan
982b9e77d4 Merge pull request #2372 from phanimarupaka/GitDiffForUpdate
Print file difference like git diff
2020-04-21 11:16:36 -07:00
Kubernetes Prow Robot
c75a47322b Merge pull request #2388 from monopole/removeStaticCling
Remove static cling in plugin development flow.
2020-04-20 12:13:40 -07:00
Jeff Regan
bb05d19a5a Merge pull request #2383 from novalagung/master
Issue #2381 - bug fix for unmodified `found` variable
2020-04-20 10:41:20 -07:00
jregan
2c615d78a2 Remove static cling in plugin development flow. 2020-04-20 08:29:01 -07:00
Jeff Regan
45a9805656 Merge pull request #2387 from monopole/splitOutCompilerUtils
Add compiler utils test.
2020-04-19 17:56:38 -07:00
jregan
504029281a Add compiler utils test. 2020-04-19 17:44:01 -07:00
Jeff Regan
2d699f93fc Merge pull request #2385 from monopole/pluginLoader
Plugin flow doc improvements and a new option for the plugin loader
2020-04-18 19:45:16 -07:00
jregan
1653a70693 Plugin loader improvements. 2020-04-18 18:29:10 -07:00
Kubernetes Prow Robot
4667372114 Merge pull request #2384 from pwittrock/validation-spec
Enable functions to defer failures
2020-04-17 21:43:35 -07:00
Phillip Wittrock
6d9702561a Enable functions to defer failures
so multiple validators can be run sequentially without shortcircuiting the pipeline
2020-04-17 20:27:58 -07:00
novalagung
4533e43009 Issue #2381 - bug fix for unmodified found variable 2020-04-18 04:06:54 +07:00
Kubernetes Prow Robot
c7b00733c1 Merge pull request #2382 from pwittrock/release
release cmd/config and kyaml
2020-04-17 11:03:07 -07:00
Phillip Wittrock
b023570fae release cmd/config and kyaml 2020-04-17 09:51:59 -07:00
Kubernetes Prow Robot
8c315ab874 Merge pull request #2362 from pwittrock/validation-spec
Support for serializing ResourceList.results field from functions
2020-04-17 09:23:06 -07:00
Phani Teja Marupaka
014db05f9c Print file difference like git diff 2020-04-16 12:31:00 -07:00
Kubernetes Prow Robot
d8f601248b Merge pull request #2377 from monopole/patchReadability
PatchTransformer readability mods and another test.
2020-04-16 10:46:46 -07:00
Jeffrey Regan
9c75afca58 PatchTransfomer readability mods. 2020-04-15 18:48:59 -07:00
Jeff Regan
8f2f2c201f Merge pull request #2376 from monopole/updateDeps
Update deps (autogenerated)
2020-04-15 17:49:55 -07:00
Jeffrey Regan
e66235f380 Update deps. 2020-04-15 17:12:25 -07:00
Jeff Regan
636167ac7f Merge pull request #2359 from mortent/PatchTransformerFilter
Update PatchTransformer to use kyaml filters
2020-04-15 17:11:29 -07:00
Kubernetes Prow Robot
4eac2b10d6 Merge pull request #2373 from monopole/addGeneratorTest
Add coverage to the disable name hash option in generators.
2020-04-15 16:18:45 -07:00
Jeffrey Regan
d15a573544 Add Generator Test 2020-04-15 16:00:06 -07:00
Phillip Wittrock
8d22cbdcca Support writing results from container filter 2020-04-15 08:01:49 -07:00
Phillip Wittrock
b72db9e783 ByteReader/Writer support for serializing ResourceList.results field 2020-04-14 12:59:46 -07:00
Kubernetes Prow Robot
a446a4f4fe Merge pull request #2354 from phanimarupaka/KustomizeOpenApi
Kustomization openapi ConfigMapGenerator and SecretGenerator
2020-04-14 10:48:13 -07:00
Phani Teja Marupaka
f81d766584 Kustomization openapi 2020-04-13 23:21:17 -07:00
Morten Torkildsen
ef592606a0 Update PatchTransformer to use kyaml filters 2020-04-13 21:25:02 -07:00
Kubernetes Prow Robot
4e322fb501 Merge pull request #2363 from monopole/moarPatchTransformerCoverage
Add more patch transformer coverage.
2020-04-10 19:35:47 -07:00
jregan
b1e48a46c7 Add more patch transformer coverage. 2020-04-10 18:21:12 -07:00
Jeff Regan
83700461fc Merge pull request #2361 from mortent/PatchTransformerFilterTest
Update tests for PatchTransformer
2020-04-10 18:04:33 -07:00
Kubernetes Prow Robot
853181e36f Merge pull request #2360 from monopole/updateDocs
More documentation for  field.
2020-04-10 17:49:47 -07:00
Morten Torkildsen
e7e7648c55 Update tests for PatchTransformer 2020-04-10 16:12:53 -07:00
jregan
20643c933e More documentation for field. 2020-04-10 13:54:25 -07:00
Kubernetes Prow Robot
0227582684 Merge pull request #2357 from monopole/refactorGeneratorArgs
Define hash suffix behavior in the presence of multiple GeneratorOptions.
2020-04-10 11:15:47 -07:00
jregan
c4db0f9a60 checkpoint 2020-04-10 11:01:31 -07:00
Jeff Regan
5479d32aa3 Merge pull request #2353 from kubernetes-sigs/prowBadge
Show prow build instead of deprecated travis
2020-04-09 19:49:33 -07:00
Jeff Regan
6aabe72fce Merge pull request #2352 from monopole/unpinPlugins
Unpin the plugins (i.e. point them to head).
2020-04-08 19:55:38 -07:00
Jeff Regan
ee110a8e02 Show prow build instead of deprecated travis 2020-04-08 18:29:57 -07:00
jregan
65b6e1c2bb Unpin the plugins (i.e. point them to head). 2020-04-08 18:01:10 -07:00
Jeff Regan
826da4b19e Merge pull request #2344 from mortent/patchJson6902
Add json6902 patch filter based on kyaml libraries
2020-04-08 13:10:11 -07:00
Kubernetes Prow Robot
630ac1b318 Merge pull request #2350 from pwittrock/comments
fix copy comments to include document comments
2020-04-08 10:53:44 -07:00
Phillip Wittrock
23589cc2af fix copy comments to include document comments 2020-04-08 09:16:43 -07:00
Kubernetes Prow Robot
b349351e6e Merge pull request #2343 from phanimarupaka/DetectMergeConflicts
Copy file from source to destination
2020-04-07 12:47:44 -07:00
Phani Teja Marupaka
7bddd14419 Copyfile 2020-04-07 12:17:07 -07:00
Kubernetes Prow Robot
894e21acbf Merge pull request #2341 from pwittrock/master
Fix program path in runfn
2020-04-07 10:03:44 -07:00
Morten Torkildsen
524d672307 Update go mudules dependencies 2020-04-07 09:57:45 -07:00
Morten Torkildsen
d051588789 Add json6902 patch filter based on kyaml libraries 2020-04-06 18:59:10 -07:00
Kubernetes Prow Robot
ea807fcdcc Merge pull request #2342 from monopole/fieldNameChange
Remove use of patchjson6902 field.
2020-04-06 17:37:19 -07:00
Jeffrey Regan
a7f0af939b Remove use of patchjson6902 field. 2020-04-06 17:23:55 -07:00
Phillip Wittrock
4f926df7cf Fix path in runfn
- Calculate path relative to the functionConfig file
- Do not allow absolute paths or traversal to parent directories
2020-04-06 16:53:20 -07:00
Jeff Regan
1dad3f0975 Update patchMultipleObjects.md 2020-04-06 16:34:20 -07:00
Jeff Regan
885a9db52e Update jsonpatch.md 2020-04-06 16:33:53 -07:00
Jeff Regan
8d40ead9b7 Merge pull request #2338 from monopole/multiPatchDemo
Better multi-patch demo.
2020-04-06 16:30:47 -07:00
Jeffrey Regan
86bcb47b7d Better multi-patch demo. 2020-04-06 16:16:44 -07:00
Kubernetes Prow Robot
f08594cc22 Merge pull request #2337 from mortent/releaseKyaml
release kyaml 0.1.5
2020-04-06 15:43:48 -07:00
Morten Torkildsen
56b6fa90b3 release kyaml 0.1.5 2020-04-06 15:25:51 -07:00
Jeff Regan
292d950465 Merge pull request #2336 from mortent/AddMortentAsMaintainer
Add mortent to the maintainers list
2020-04-06 10:17:21 -07:00
Morten Torkildsen
ee431f755c Add mortent to the maintainers list 2020-04-06 10:12:26 -07:00
Kubernetes Prow Robot
e00d0b98de Merge pull request #2229 from boylee1111/boyil/priorityclass_ref
Add namereference for PriorityClass
2020-04-06 08:51:47 -07:00
Kubernetes Prow Robot
a8b9741866 Merge pull request #2331 from monopole/moreExamplesInJsonPatch
Improve json6902 patch example.
2020-04-05 16:36:09 -07:00
Kubernetes Prow Robot
7855031ecc Merge pull request #2330 from phanimarupaka/RemoveFormatFilterForUpdate
Remove format filter for merge
2020-04-05 16:36:01 -07:00
Kubernetes Prow Robot
e12d57e6f2 Merge pull request #2327 from mortent/StrategicMergeTransformer
Add strategic merge patch filter based on kyaml libraries
2020-04-05 16:35:54 -07:00
Kubernetes Prow Robot
0d2ae19c80 Merge pull request #2306 from mortent/imageTagFilter
Add imagetag filter based on kayml libraries
2020-04-05 16:35:46 -07:00
Kubernetes Prow Robot
804cf6d71c Merge pull request #2326 from ian-howell/export-noFieldError
Export noFieldError
2020-04-05 16:19:46 -07:00
Kubernetes Prow Robot
e342b68f0a Merge pull request #2334 from mortent/FixKyamlJson
Fix issue with kyaml json unmarshalling
2020-04-05 15:51:46 -07:00
Morten Torkildsen
022805b56b Fix issue with kyaml json unmarshalling 2020-04-04 20:39:29 -07:00
Jeffrey Regan
eb57d4b510 Improve json patch example. 2020-04-03 18:34:02 -07:00
Phani Teja Marupaka
a5a51ba76a Remove format filter for update 2020-04-03 15:24:10 -07:00
Morten Torkildsen
32efef71f4 Add imagetag filter based on kayml libraries 2020-04-03 15:00:09 -07:00
Morten Torkildsen
98c08b2b66 Add strategic merge patch filter based on kyaml libraries 2020-04-03 13:56:20 -07:00
Ian Howell
5ea34b2efb Export noFieldError
This would allow user's of the kustomize API to determine whether the
error received while trying to access a value at a specific field-path
occurred because that field doesn't exist, or if it was something else
that went wrong.
2020-04-03 14:22:14 -05:00
Jeff Regan
0f3d5c80e4 Merge pull request #2324 from mortent/BetterTransformerTesting
Better support for testing tranformers with kyaml support
2020-04-03 08:28:29 -07:00
Morten Torkildsen
cabaccb9fd Better support for testing tranformers with kyaml support 2020-04-02 17:00:34 -07:00
Kubernetes Prow Robot
4d1fe6678f Merge pull request #2319 from pwittrock/master
Implement json marshal / unmarshal for RNode
2020-04-02 16:33:46 -07:00
Kubernetes Prow Robot
04af0e6648 Merge pull request #2320 from pwittrock/starlark
Import environment and openAPI into starlark fn runtime
2020-04-02 14:29:05 -07:00
Kubernetes Prow Robot
7a696ef616 Merge pull request #2312 from prachirp/volume
Support mounting volumes to containers
2020-04-02 14:13:04 -07:00
Phillip Wittrock
691c11d520 Import environment and openAPI into starlark fn runtime 2020-04-02 12:35:47 -07:00
Prachi Pendse
109ffdaec5 Update parsing of StringToStorageMount to use SplitN 2020-04-02 12:12:27 -07:00
Kubernetes Prow Robot
aac1b7dc24 Merge pull request #2323 from pwittrock/release
release kyaml 0.1.4
2020-04-02 11:42:25 -07:00
Phillip Wittrock
96782d9584 release kyaml 0.1.4 2020-04-02 11:32:25 -07:00
Prachi Pendse
b17ea88bf7 Update mount flag to match docker docs
- Also modify TODO in validator-kubeval example
2020-04-02 11:20:32 -07:00
Kubernetes Prow Robot
091964c2c4 Merge pull request #2317 from trodge/markdown
added markdown format flag for create-setters
2020-04-02 08:10:25 -07:00
Prachi Pendse
38973a80c3 Use mount flag to pass storage mounts to functions 2020-04-01 15:03:57 -07:00
Phillip Wittrock
4a7b22cf23 Implement json marshal / unmarshal so it can be used by PatchJson6902Transformer 2020-04-01 14:35:05 -07:00
Kubernetes Prow Robot
21a544f188 Merge pull request #2316 from mortent/ReplicaCountTransformer
Add replicacount filter based on kyaml libraries
2020-04-01 14:04:24 -07:00
Kubernetes Prow Robot
43f44b88ce Merge pull request #2315 from mortent/CleanupAnnotationsTransformer
Improve tests for AnnotationsTransformer
2020-04-01 13:48:23 -07:00
Kubernetes Prow Robot
0086470fe1 Merge pull request #2318 from pwittrock/master
Refactor and optimize function to set all setters
2020-04-01 12:46:23 -07:00
Phillip Wittrock
6a3eaf8ba0 Refactor and optimize function to set all setters 2020-04-01 11:27:59 -07:00
Thomas Rodgers
26e801d2f2 added markdown format flag 2020-04-01 10:35:53 -07:00
Kubernetes Prow Robot
d5d908610d Merge pull request #2314 from phanimarupaka/SetAllSetterDefinitions
Set all setter definitions from source package
2020-04-01 09:35:28 -07:00
Morten Torkildsen
8a22efb213 Add replicacount filter based on kyaml libraries 2020-03-31 22:25:02 -07:00
Morten Torkildsen
8bd989abb1 Improve tests for AnnotationsTransformer 2020-03-31 20:29:50 -07:00
Phani Teja Marupaka
a3f59f2f4f Set all setter definitions from source package 2020-03-31 20:25:52 -07:00
Prachi Pendse
a4ee1c2e72 Remove TODO for network and volume issues 2020-03-31 10:19:17 -07:00
Prachi Pendse
39fe903498 Support mounting volumes to containers 2020-03-31 01:08:54 -07:00
Kubernetes Prow Robot
78abd4193a Merge pull request #2311 from pwittrock/master
kyaml implementation of the PrefixSuffixTransformer
2020-03-30 16:34:40 -07:00
Phillip Wittrock
96926fecce kyaml implementation of the PrefixSuffixTransformer 2020-03-30 13:07:11 -07:00
Kubernetes Prow Robot
7d852c7bab Merge pull request #2305 from pwittrock/filtersutil
NamespaceTransformer tests
2020-03-30 11:56:41 -07:00
Kubernetes Prow Robot
d36a5a9c2f Merge pull request #2304 from bndn/patch-1
Fix argument name to provide digest to an image
2020-03-30 11:44:17 -07:00
Kubernetes Prow Robot
f81cc75925 Merge pull request #2307 from phanimarupaka/RearrangeComments
Rearrange comments for yaml/V3 bug fix
2020-03-30 11:22:16 -07:00
Kubernetes Prow Robot
ab39586960 Merge pull request #2309 from bzub/2308-list-setters_docs
config: update docs to use list-setters.
2020-03-30 10:54:17 -07:00
Phani Teja Marupaka
17503ae9d8 Rearrange comments for yaml/V3 bug fix 2020-03-30 10:51:47 -07:00
bzub
24988df444 config: update docs to use list-setters. 2020-03-30 12:42:37 -05:00
Phillip Wittrock
11ce0128ad NamespaceTransformer tests
Follow up items to #2288
2020-03-30 10:32:51 -07:00
Benjamin Danon
4c0ab89c87 Fix argument name to provide digest to an image 2020-03-29 11:36:47 +02:00
Kubernetes Prow Robot
50cc1968e4 Merge pull request #2303 from pwittrock/filtersutil
Move filltersutil serialization to kyaml
2020-03-28 16:37:53 -07:00
Phillip Wittrock
51ba40d39b Move filltersutil serialization to kyaml 2020-03-28 10:02:15 -07:00
Kubernetes Prow Robot
20184e9835 Merge pull request #2302 from pwittrock/filtersutil
Update kyaml version
2020-03-28 08:55:53 -07:00
Phillip Wittrock
8e3b7b195e Update kyaml version 2020-03-28 08:44:32 -07:00
Boyil (Elliot) Li
1503b4c834 add namereference for PriorityClass 2020-02-26 14:18:49 -08:00
200 changed files with 8372 additions and 2310 deletions

View File

@@ -188,8 +188,14 @@ lint-kustomize: install-tools $(builtinplugins)
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.
.PHONY: build-kustomize-api
build-kustomize-api: $(builtinplugins)
cd api; go build ./...
.PHONY: test-unit-kustomize-api
test-unit-kustomize-api: $(builtinplugins)
test-unit-kustomize-api: build-kustomize-api
cd api; go test ./...
.PHONY: test-unit-kustomize-plugins
@@ -255,18 +261,31 @@ $(MYGOBIN)/kubeval:
)
# linux only.
# This is for testing an example plugin that
# uses helm to inflate a chart for subsequent kustomization.
# Don't want to add a hard dependence in go.mod file
# to helm.
# Instead, download the binary.
$(MYGOBIN)/helm:
# This is for testing an example plugin that uses helm to inflate a chart
# for subsequent kustomization.
# Don't want to add a hard dependence in go.mod file to helm.
# Instead, download the binaries.
$(MYGOBIN)/helmV2:
( \
set -e; \
d=$(shell mktemp -d); cd $$d; \
wget https://storage.googleapis.com/kubernetes-helm/helm-v2.13.1-linux-amd64.tar.gz; \
tar -xvzf helm-v2.13.1-linux-amd64.tar.gz; \
mv linux-amd64/helm $(MYGOBIN); \
tgzFile=helm-v2.13.1-linux-amd64.tar.gz; \
wget https://storage.googleapis.com/kubernetes-helm/$$tgzFile; \
tar -xvzf $$tgzFile; \
mv linux-amd64/helm $(MYGOBIN)/helmV2; \
rm -rf $$d \
)
# Helm V3 differs from helm V2; downloading it to provide coverage for the
# chart inflator plugin under helm v3.
$(MYGOBIN)/helmV3:
( \
set -e; \
d=$(shell mktemp -d); cd $$d; \
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 \
)
@@ -288,6 +307,7 @@ clean: kustomize-external-go-plugin-clean
rm -f $(MYGOBIN)/kustomize
rm -f $(MYGOBIN)/golangci-lint-kustomize
# Nuke the site from orbit. It's the only way to be sure.
.PHONY: nuke
nuke: clean
sudo rm -rf $(shell go env GOPATH)/pkg/mod/sigs.k8s.io
go clean --modcache

View File

@@ -9,3 +9,4 @@ aliases:
- mengqiy
- monopole
- pwittrock
- mortent

View File

@@ -12,8 +12,7 @@ and it's like [`sed`], in that it emits edited text.
This tool is sponsored by [sig-cli] ([KEP]), and
inspired by [DAM].
[![Build Status](https://travis-ci.org/kubernetes-sigs/kustomize.svg?branch=master)](https://travis-ci.org/kubernetes-sigs/kustomize)
[![Build Status](https://prow.k8s.io/badge.svg?jobs=kustomize-presubmit-master)](https://prow.k8s.io/job-history/kubernetes-jenkins/pr-logs/directory/kustomize-presubmit-master)
[![Go Report Card](https://goreportcard.com/badge/github.com/kubernetes-sigs/kustomize)](https://goreportcard.com/report/github.com/kubernetes-sigs/kustomize)
Download a binary from the [release page], or see

View File

@@ -5,10 +5,10 @@ package builtins
import (
"sigs.k8s.io/kustomize/api/filters/annotations"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/transform"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/filtersutil"
"sigs.k8s.io/yaml"
)
@@ -19,7 +19,7 @@ type AnnotationsTransformerPlugin struct {
// YAMLSupport can be set to true to use the kyaml filter instead of the
// kunstruct transformer
YAMLSupport bool
YAMLSupport bool `json:"yamlSupport,omitempty" yaml:"yamlSupport,omitempty"`
}
func (p *AnnotationsTransformerPlugin) Config(

View File

@@ -13,13 +13,10 @@ import (
type ConfigMapGeneratorPlugin struct {
h *resmap.PluginHelpers
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
types.GeneratorOptions
types.ConfigMapArgs
}
func (p *ConfigMapGeneratorPlugin) Config(
h *resmap.PluginHelpers, config []byte) (err error) {
p.GeneratorOptions = types.GeneratorOptions{}
func (p *ConfigMapGeneratorPlugin) Config(h *resmap.PluginHelpers, config []byte) (err error) {
p.ConfigMapArgs = types.ConfigMapArgs{}
err = yaml.Unmarshal(config, p)
if p.ConfigMapArgs.Name == "" {
@@ -34,8 +31,7 @@ func (p *ConfigMapGeneratorPlugin) Config(
func (p *ConfigMapGeneratorPlugin) Generate() (resmap.ResMap, error) {
return p.h.ResmapFactory().FromConfigMapArgs(
kv.NewLoader(p.h.Loader(), p.h.Validator()),
&p.GeneratorOptions, p.ConfigMapArgs)
kv.NewLoader(p.h.Loader(), p.h.Validator()), p.ConfigMapArgs)
}
func NewConfigMapGeneratorPlugin() resmap.GeneratorPlugin {

View File

@@ -55,26 +55,23 @@ func (p *InventoryTransformerPlugin) Config(
// (e.g. some App object) become more desirable
// for this purpose.
func (p *InventoryTransformerPlugin) Transform(m resmap.ResMap) error {
inv, h, err := makeInventory(m)
if err != nil {
return err
}
args := types.ConfigMapArgs{}
args.Name = p.Name
args.Namespace = p.Namespace
opts := &types.GeneratorOptions{
Annotations: make(map[string]string),
args.Options = &types.GeneratorOptions{
Annotations: map[string]string{inventory.HashAnnotation: h},
}
opts.Annotations[inventory.HashAnnotation] = h
err = inv.UpdateAnnotations(opts.Annotations)
err = inv.UpdateAnnotations(args.Options.Annotations)
if err != nil {
return err
}
cm, err := p.h.ResmapFactory().RF().MakeConfigMap(
kv.NewLoader(p.h.Loader(), p.h.Validator()), opts, &args)
kv.NewLoader(p.h.Loader(), p.h.Validator()), &args)
if err != nil {
return err
}

View File

@@ -6,14 +6,13 @@ package builtins
import (
"fmt"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/filters/namespace"
"sigs.k8s.io/kustomize/api/transform"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/transform"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/filtersutil"
"sigs.k8s.io/yaml"
)
@@ -23,8 +22,9 @@ type NamespaceTransformerPlugin struct {
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
// YAMLSupport can be set to true to use the kyaml filter instead of the
// kunstruct transformer
YAMLSupport bool
// kunstruct transformer.
// TODO: change the default to use kyaml when it is stable
YAMLSupport bool `json:"yamlSupport,omitempty" yaml:"yamlSupport,omitempty"`
}
func (p *NamespaceTransformerPlugin) Config(

View File

@@ -8,10 +8,12 @@ import (
jsonpatch "github.com/evanphx/json-patch"
"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"
"sigs.k8s.io/yaml"
)
@@ -21,6 +23,8 @@ type PatchJson6902TransformerPlugin struct {
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"`
YAMLSupport bool `json:"yamlSupport,omitempty" yaml:"yamlSupport,omitempty"`
}
func (p *PatchJson6902TransformerPlugin) Config(
@@ -83,16 +87,22 @@ func (p *PatchJson6902TransformerPlugin) Transform(m resmap.ResMap) error {
if err != nil {
return err
}
rawObj, err := obj.MarshalJSON()
if err != nil {
return err
if !p.YAMLSupport {
rawObj, err := obj.MarshalJSON()
if err != nil {
return err
}
modifiedObj, err := p.decodedPatch.Apply(rawObj)
if err != nil {
return errors.Wrapf(
err, "failed to apply json patch '%s'", p.JsonOp)
}
return obj.UnmarshalJSON(modifiedObj)
} else {
return filtersutil.ApplyToJSON(patchjson6902.Filter{
Patch: p.JsonOp,
}, obj.Kunstructured)
}
modifiedObj, err := p.decodedPatch.Apply(rawObj)
if err != nil {
return errors.Wrapf(
err, "failed to apply json patch '%s'", p.JsonOp)
}
return obj.UnmarshalJSON(modifiedObj)
}
func NewPatchJson6902TransformerPlugin() resmap.TransformerPlugin {

View File

@@ -4,11 +4,16 @@
package builtins
import (
"encoding/json"
"fmt"
kyaml "sigs.k8s.io/kustomize/kyaml/yaml"
"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"
)
@@ -17,6 +22,8 @@ type PatchStrategicMergeTransformerPlugin struct {
loadedPatches []*resource.Resource
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
Patches string `json:"patches,omitempty" yaml:"patches,omitempty"`
YAMLSupport bool `json:"yamlSupport,omitempty" yaml:"yamlSupport,omitempty"`
}
func (p *PatchStrategicMergeTransformerPlugin) Config(
@@ -69,22 +76,42 @@ func (p *PatchStrategicMergeTransformerPlugin) Transform(m resmap.ResMap) error
if err != nil {
return err
}
err = target.Patch(patch.Kunstructured)
if err != nil {
return err
}
// remove the resource from resmap
// when the patch is to $patch: delete that target
if len(target.Map()) == 0 {
err = m.Remove(target.CurId())
if !p.YAMLSupport {
err = target.Patch(patch.Kunstructured)
if err != nil {
return err
}
// remove the resource from resmap
// when the patch is to $patch: delete that target
if len(target.Map()) == 0 {
err = m.Remove(target.CurId())
if err != nil {
return err
}
}
} else {
node, err := getRNode(patch)
if err != nil {
return err
}
err = filtersutil.ApplyToJSON(patchstrategicmerge.Filter{
Patch: node,
}, target.Kunstructured)
}
}
return nil
}
//TODO: Remove this once the next version of kyaml is released which
// exposes GetRNode from the filutersutil package.
func getRNode(k json.Marshaler) (*kyaml.RNode, error) {
j, err := k.MarshalJSON()
if err != nil {
return nil, err
}
return kyaml.Parse(string(j))
}
func NewPatchStrategicMergeTransformerPlugin() resmap.TransformerPlugin {
return &PatchStrategicMergeTransformerPlugin{}
}

View File

@@ -5,12 +5,16 @@ package builtins
import (
"fmt"
"strings"
jsonpatch "github.com/evanphx/json-patch"
"github.com/pkg/errors"
"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"
"sigs.k8s.io/kustomize/kyaml/filtersutil"
"sigs.k8s.io/yaml"
)
@@ -20,69 +24,112 @@ type PatchTransformerPlugin struct {
Path string `json:"path,omitempty" yaml:"path,omitempty"`
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"`
YAMLSupport bool `json:"yamlSupport,omitempty" yaml:"yamlSupport,omitempty"`
}
func (p *PatchTransformerPlugin) Config(
h *resmap.PluginHelpers, c []byte) (err error) {
err = yaml.Unmarshal(c, p)
h *resmap.PluginHelpers, c []byte) error {
err := yaml.Unmarshal(c, p)
if err != nil {
return err
}
p.Patch = strings.TrimSpace(p.Patch)
if p.Patch == "" && p.Path == "" {
err = fmt.Errorf(
return fmt.Errorf(
"must specify one of patch and path in\n%s", string(c))
return
}
if p.Patch != "" && p.Path != "" {
err = fmt.Errorf(
return fmt.Errorf(
"patch and path can't be set at the same time\n%s", string(c))
return
}
var in []byte
if p.Path != "" {
in, err = h.Loader().Load(p.Path)
if err != nil {
return
}
}
if p.Patch != "" {
in = []byte(p.Patch)
}
patchSM, errSM := h.ResmapFactory().RF().FromBytes(in)
patchJson, errJson := jsonPatchFromBytes(in)
if p.Path != "" {
loaded, loadErr := h.Loader().Load(p.Path)
if loadErr != nil {
return loadErr
}
p.Patch = string(loaded)
}
patchSM, errSM := h.ResmapFactory().RF().FromBytes([]byte(p.Patch))
patchJson, errJson := jsonPatchFromBytes([]byte(p.Patch))
if (errSM == nil && errJson == nil) ||
(patchSM != nil && patchJson != nil) {
return fmt.Errorf(
"illegally qualifies as both an SM and JSON patch: [%v]",
p.Patch)
}
if errSM != nil && errJson != nil {
err = fmt.Errorf(
"unable to get either a Strategic Merge Patch or JSON patch 6902 from %s", p.Patch)
return
return fmt.Errorf(
"unable to parse SM or JSON patch from [%v]", p.Patch)
}
if errSM == nil && errJson != nil {
if errSM == nil {
p.loadedPatch = patchSM
}
if errJson == nil && errSM != nil {
} else {
p.decodedPatch = patchJson
}
if patchSM != nil && patchJson != nil {
err = fmt.Errorf(
"a patch can't be both a Strategic Merge Patch and JSON patch 6902 %s", p.Patch)
}
return nil
}
func (p *PatchTransformerPlugin) Transform(m resmap.ResMap) error {
if p.loadedPatch != nil && p.Target == nil {
target, err := m.GetById(p.loadedPatch.OrgId())
if p.loadedPatch != nil {
// The patch was a strategic merge patch
return p.transformStrategicMerge(m, p.loadedPatch)
} else {
return p.transformJson6902(m, p.decodedPatch)
}
}
// transformStrategicMerge applies the provided strategic merge patch
// to all the resources in the ResMap that match either the Target or
// the identifier of the patch.
func (p *PatchTransformerPlugin) transformStrategicMerge(m resmap.ResMap, patch *resource.Resource) error {
if p.Target == nil {
target, err := m.GetById(patch.OrgId())
if err != nil {
return err
}
err = target.Patch(p.loadedPatch.Kunstructured)
if err != nil {
return err
}
return nil
return p.applySMPatch(target, patch)
}
resources, err := m.Select(*p.Target)
if err != nil {
return err
}
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. Depending on the value of YAMLSupport, it will either
// use the legacy implementation or the kyaml-based solution.
func (p *PatchTransformerPlugin) applySMPatch(resource, patch *resource.Resource) error {
if !p.YAMLSupport {
return resource.Patch(patch.Kunstructured)
} else {
node, err := filtersutil.GetRNode(patch)
if err != nil {
return err
}
return filtersutil.ApplyToJSON(patchstrategicmerge.Filter{
Patch: node,
}, resource.Kunstructured)
}
}
// transformJson6902 applies the provided json6902 patch
// to all the resources in the ResMap that match the Target.
func (p *PatchTransformerPlugin) transformJson6902(m resmap.ResMap, patch jsonpatch.Patch) error {
if p.Target == nil {
return fmt.Errorf("must specify a target for patch %s", p.Patch)
}
@@ -92,35 +139,36 @@ func (p *PatchTransformerPlugin) Transform(m resmap.ResMap) error {
return err
}
for _, res := range resources {
if p.decodedPatch != nil {
rawObj, err := res.MarshalJSON()
if err != nil {
return err
}
modifiedObj, err := p.decodedPatch.Apply(rawObj)
if err != nil {
return errors.Wrapf(
err, "failed to apply json patch '%s'", p.Patch)
}
err = res.UnmarshalJSON(modifiedObj)
if err != nil {
return err
}
}
if p.loadedPatch != nil {
patchCopy := p.loadedPatch.DeepCopy()
patchCopy.SetName(res.GetName())
patchCopy.SetNamespace(res.GetNamespace())
patchCopy.SetGvk(res.GetGvk())
err = res.Patch(patchCopy.Kunstructured)
if err != nil {
return err
}
err = p.applyJson6902Patch(res, patch)
if err != nil {
return err
}
}
return nil
}
// applyJson6902Patch applies the provided patch to the given resource.
// Depending on the value of YAMLSupport, it will either
// use the legacy implementation or the kyaml-based solution.
func (p *PatchTransformerPlugin) applyJson6902Patch(resource *resource.Resource, patch jsonpatch.Patch) error {
if !p.YAMLSupport {
rawObj, err := resource.MarshalJSON()
if err != nil {
return err
}
modifiedObj, err := patch.Apply(rawObj)
if err != nil {
return errors.Wrapf(
err, "failed to apply json patch '%s'", p.Patch)
}
return resource.UnmarshalJSON(modifiedObj)
} else {
return filtersutil.ApplyToJSON(patchjson6902.Filter{
Patch: p.Patch,
}, resource.Kunstructured)
}
}
// jsonPatchFromBytes loads a Json 6902 patch from
// a bytes input
func jsonPatchFromBytes(

View File

@@ -13,12 +13,10 @@ import (
type SecretGeneratorPlugin struct {
h *resmap.PluginHelpers
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
types.GeneratorOptions
types.SecretArgs
}
func (p *SecretGeneratorPlugin) Config(h *resmap.PluginHelpers, config []byte) (err error) {
p.GeneratorOptions = types.GeneratorOptions{}
p.SecretArgs = types.SecretArgs{}
err = yaml.Unmarshal(config, p)
if p.SecretArgs.Name == "" {
@@ -33,8 +31,7 @@ func (p *SecretGeneratorPlugin) Config(h *resmap.PluginHelpers, config []byte) (
func (p *SecretGeneratorPlugin) Generate() (resmap.ResMap, error) {
return p.h.ResmapFactory().FromSecretArgs(
kv.NewLoader(p.h.Loader(), p.h.Validator()),
&p.GeneratorOptions, p.SecretArgs)
kv.NewLoader(p.h.Loader(), p.h.Validator()), p.SecretArgs)
}
func NewSecretGeneratorPlugin() resmap.GeneratorPlugin {

View File

@@ -4,11 +4,7 @@
package filtersutil
import (
"encoding/json"
"sort"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// SortedMapKeys returns a sorted slice of keys to the given map.
@@ -23,69 +19,3 @@ func SortedMapKeys(m map[string]string) []string {
sort.Strings(keys)
return keys
}
// ApplyToJSON applies the filter to the json objects.
func ApplyToJSON(filter kio.Filter, objs ...marshalerUnmarshaler) error {
var nodes []*yaml.RNode
for i := range objs {
node, err := getRNode(objs[i])
if err != nil {
return err
}
nodes = append(nodes, node)
l, err := filter.Filter([]*yaml.RNode{node})
if err != nil {
return err
}
err = setRNode(objs[i], l[0])
if err != nil {
return err
}
}
_, err := filter.Filter(nodes)
if err != nil {
return err
}
for i := range nodes {
err = setRNode(objs[i], nodes[i])
if err != nil {
return err
}
}
return nil
}
type marshalerUnmarshaler interface {
json.Unmarshaler
json.Marshaler
}
// getRNode converts k into an RNode
func getRNode(k json.Marshaler) (*yaml.RNode, error) {
j, err := k.MarshalJSON()
if err != nil {
return nil, err
}
return yaml.Parse(string(j))
}
// setRNode marshals node into k
func setRNode(k json.Unmarshaler, node *yaml.RNode) error {
s, err := node.String()
if err != nil {
return err
}
m := map[string]interface{}{}
if err := yaml.Unmarshal([]byte(s), &m); err != nil {
return err
}
b, err := json.Marshal(m)
if err != nil {
return err
}
return k.UnmarshalJSON(b)
}

View File

@@ -1,14 +1,10 @@
package filtersutil_test
import (
"bytes"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
func TestSortedKeys(t *testing.T) {
@@ -36,51 +32,3 @@ func TestSortedKeys(t *testing.T) {
})
}
}
func TestApplyToJSON(t *testing.T) {
instance1 := bytes.NewBufferString(`{"kind": "Foo"}`)
instance2 := bytes.NewBufferString(`{"kind": "Bar"}`)
err := filtersutil.ApplyToJSON(
kio.FilterFunc(func(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
for i := range nodes {
set := yaml.SetField(
"foo", yaml.NewScalarRNode("bar"))
node := nodes[i]
err := node.PipeE(set)
if !assert.NoError(t, err) {
t.FailNow()
}
}
return nodes, nil
}), buffer{Buffer: instance1}, buffer{Buffer: instance2},
)
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.Equal(t,
strings.TrimSpace(`{"foo":"bar","kind":"Foo"}`),
strings.TrimSpace(instance1.String())) {
t.FailNow()
}
if !assert.Equal(t,
strings.TrimSpace(`{"foo":"bar","kind":"Bar"}`),
strings.TrimSpace(instance2.String())) {
t.FailNow()
}
}
type buffer struct {
*bytes.Buffer
}
func (buff buffer) UnmarshalJSON(b []byte) error {
buff.Reset()
buff.Write(b)
return nil
}
func (buff buffer) MarshalJSON() ([]byte, error) {
return buff.Bytes(), nil
}

View File

@@ -0,0 +1,12 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package imagetag contains two kio.Filter implementations to cover the
// functionality of the kustomize imagetag transformer.
//
// Filter updates fields based on a FieldSpec and an ImageTag.
//
// LegacyFilter doesn't use a FieldSpec, and instead only updates image
// references if the field is name image and it is underneath a field called
// either containers or initContainers.
package imagetag

View File

@@ -0,0 +1,126 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package imagetag
import (
"bytes"
"log"
"os"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio"
)
func ExampleFilter() {
err := kio.Pipeline{
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
spec:
containers:
- name: FooBar
image: nginx
---
apiVersion: example.com/v1
kind: Bar
metadata:
name: instance
spec:
containers:
- name: BarFoo
image: nginx:1.2.1
`)}},
Filters: []kio.Filter{Filter{
ImageTag: types.Image{
Name: "nginx",
NewName: "apache",
Digest: "12345",
},
FsSlice: []types.FieldSpec{
{
Path: "spec/containers[]/image",
},
},
}},
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
}.Execute()
if err != nil {
log.Fatal(err)
}
// Output:
// apiVersion: example.com/v1
// kind: Foo
// metadata:
// name: instance
// spec:
// containers:
// - name: FooBar
// image: apache@12345
// ---
// apiVersion: example.com/v1
// kind: Bar
// metadata:
// name: instance
// spec:
// containers:
// - name: BarFoo
// image: apache@12345
}
func ExampleLegacyFilter() {
err := kio.Pipeline{
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
spec:
containers:
- name: FooBar
image: nginx
---
apiVersion: example.com/v1
kind: Bar
metadata:
name: instance
spec:
containers:
- name: BarFoo
image: nginx:1.2.1
`)}},
Filters: []kio.Filter{LegacyFilter{
ImageTag: types.Image{
Name: "nginx",
NewName: "apache",
Digest: "12345",
},
}},
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
}.Execute()
if err != nil {
log.Fatal(err)
}
// Output:
// apiVersion: example.com/v1
// kind: Foo
// metadata:
// name: instance
// spec:
// containers:
// - name: FooBar
// image: apache@12345
// ---
// apiVersion: example.com/v1
// kind: Bar
// metadata:
// name: instance
// spec:
// containers:
// - name: BarFoo
// image: apache@12345
}

View File

@@ -0,0 +1,44 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package imagetag
import (
"sigs.k8s.io/kustomize/api/filters/fsslice"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
type Filter struct {
// imageTag is the tag we want to apply to the inputs
ImageTag types.Image `json:"imageTag,omitempty" yaml:"imageTag,omitempty"`
// FsSlice contains the FieldSpecs to locate the namespace field
FsSlice types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
var _ kio.Filter = Filter{}
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
_, err := kio.FilterAll(yaml.FilterFunc(f.filter)).Filter(nodes)
return nodes, err
}
func (f Filter) filter(node *yaml.RNode) (*yaml.RNode, error) {
if err := node.PipeE(fsslice.Filter{
FsSlice: f.FsSlice,
SetValue: updateImageTagFn(f.ImageTag),
}); err != nil {
return nil, err
}
return node, nil
}
func updateImageTagFn(imageTag types.Image) fsslice.SetFn {
return func(node *yaml.RNode) error {
return node.PipeE(imageTagUpdater{
ImageTag: imageTag,
})
}
}

View File

@@ -0,0 +1,101 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package imagetag
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
filtertest "sigs.k8s.io/kustomize/api/testutils/filtertest"
"sigs.k8s.io/kustomize/api/types"
)
func TestImageTagUpdater_Filter(t *testing.T) {
testCases := map[string]struct {
input string
expectedOutput string
filter Filter
fsSlice types.FsSlice
}{
"update with digest": {
input: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
spec:
image: nginx:1.2.1
`,
expectedOutput: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
spec:
image: apache@12345
`,
filter: Filter{
ImageTag: types.Image{
Name: "nginx",
NewName: "apache",
Digest: "12345",
},
},
fsSlice: []types.FieldSpec{
{
Path: "spec/image",
},
},
},
"multiple matches in sequence": {
input: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
spec:
containers:
- image: nginx:1.2.1
- image: not_nginx@54321
- image: nginx:1.2.1
`,
expectedOutput: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
spec:
containers:
- image: apache:3.2.1
- image: not_nginx@54321
- image: apache:3.2.1
`,
filter: Filter{
ImageTag: types.Image{
Name: "nginx",
NewName: "apache",
NewTag: "3.2.1",
},
},
fsSlice: []types.FieldSpec{
{
Path: "spec/containers/image",
},
},
},
}
for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
filter := tc.filter
filter.FsSlice = tc.fsSlice
if !assert.Equal(t,
strings.TrimSpace(tc.expectedOutput),
strings.TrimSpace(filtertest.RunFilter(t, tc.input, filter))) {
t.FailNow()
}
})
}
}

View File

@@ -0,0 +1,113 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package imagetag
import (
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// LegacyFilter is an implementation of the kio.Filter interface
// that scans through the provided kyaml data structure and updates
// any values of any image fields that is inside a sequence under
// a field called either containers or initContainers. The field is only
// update if it has a value that matches and image reference and the name
// of the image is a match with the provided ImageTag.
type LegacyFilter struct {
ImageTag types.Image `json:"imageTag,omitempty" yaml:"imageTag,omitempty"`
}
var _ kio.Filter = LegacyFilter{}
func (lf LegacyFilter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
return kio.FilterAll(yaml.FilterFunc(lf.filter)).Filter(nodes)
}
func (lf LegacyFilter) filter(node *yaml.RNode) (*yaml.RNode, error) {
meta, err := node.GetMeta()
if err != nil {
return nil, err
}
// We do not make any changes if the type of the resource
// is CustomResourceDefinition.
if meta.Kind == `CustomResourceDefinition` {
return node, nil
}
fff := findFieldsFilter{
fields: []string{"containers", "initContainers"},
fieldCallback: checkImageTagsFn(lf.ImageTag),
}
if err := node.PipeE(fff); err != nil {
return nil, err
}
return node, nil
}
type fieldCallback func(node *yaml.RNode) error
// findFieldsFilter is an implementation of the kio.Filter
// interface. It will walk the data structure and look for fields
// that matches the provided list of field names. For each match,
// the value of the field will be passed in as a parameter to the
// provided fieldCallback.
// TODO: move this to kyaml/filterutils
type findFieldsFilter struct {
fields []string
fieldCallback fieldCallback
}
func (f findFieldsFilter) Filter(obj *yaml.RNode) (*yaml.RNode, error) {
return obj, f.walk(obj)
}
func (f findFieldsFilter) walk(node *yaml.RNode) error {
switch node.YNode().Kind {
case yaml.MappingNode:
return node.VisitFields(func(n *yaml.MapNode) error {
err := f.walk(n.Value)
if err != nil {
return err
}
key := n.Key.YNode().Value
if contains(f.fields, key) {
return f.fieldCallback(n.Value)
}
return nil
})
case yaml.SequenceNode:
return node.VisitElements(func(n *yaml.RNode) error {
return f.walk(n)
})
}
return nil
}
func contains(slice []string, str string) bool {
for _, s := range slice {
if s == str {
return true
}
}
return false
}
func checkImageTagsFn(imageTag types.Image) fieldCallback {
return func(node *yaml.RNode) error {
if node.YNode().Kind != yaml.SequenceNode {
return nil
}
return node.VisitElements(func(n *yaml.RNode) error {
// Look up any fields on the provided node that is named
// image.
return n.PipeE(yaml.Get("image"), imageTagUpdater{
ImageTag: imageTag,
})
})
}
}

View File

@@ -0,0 +1,136 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package imagetag
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
filtertest "sigs.k8s.io/kustomize/api/testutils/filtertest"
"sigs.k8s.io/kustomize/api/types"
)
func TestLegacyImageTag_Filter(t *testing.T) {
testCases := map[string]struct {
input string
expectedOutput string
filter LegacyFilter
}{
"updates multiple images inside containers": {
input: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
spec:
containers:
- image: nginx:1.2.1
- image: nginx:2.1.2
`,
expectedOutput: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
spec:
containers:
- image: apache@12345
- image: apache@12345
`,
filter: LegacyFilter{
ImageTag: types.Image{
Name: "nginx",
NewName: "apache",
Digest: "12345",
},
},
},
"updates inside both containers and initContainers": {
input: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
spec:
containers:
- image: nginx:1.2.1
- image: tomcat:1.2.3
initContainers:
- image: nginx:1.2.1
- image: apache:1.2.3
`,
expectedOutput: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
spec:
containers:
- image: apache:3.2.1
- image: tomcat:1.2.3
initContainers:
- image: apache:3.2.1
- image: apache:1.2.3
`,
filter: LegacyFilter{
ImageTag: types.Image{
Name: "nginx",
NewName: "apache",
NewTag: "3.2.1",
},
},
},
"updates on multiple depths": {
input: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
spec:
containers:
- image: nginx:1.2.1
- image: tomcat:1.2.3
template:
spec:
initContainers:
- image: nginx:1.2.1
- image: apache:1.2.3
`,
expectedOutput: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
spec:
containers:
- image: apache:3.2.1
- image: tomcat:1.2.3
template:
spec:
initContainers:
- image: apache:3.2.1
- image: apache:1.2.3
`,
filter: LegacyFilter{
ImageTag: types.Image{
Name: "nginx",
NewName: "apache",
NewTag: "3.2.1",
},
},
},
}
for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
filter := tc.filter
if !assert.Equal(t,
strings.TrimSpace(tc.expectedOutput),
strings.TrimSpace(filtertest.RunFilter(t, tc.input, filter))) {
t.FailNow()
}
})
}
}

View File

@@ -0,0 +1,43 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package imagetag
import (
"sigs.k8s.io/kustomize/api/image"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// imageTagUpdater is an implementation of the kio.Filter interface
// that will update the value of the yaml node based on the provided
// ImageTag if the current value matches the format of an image reference.
type imageTagUpdater struct {
Kind string `yaml:"kind,omitempty"`
ImageTag types.Image `yaml:"imageTag,omitempty"`
}
func (u imageTagUpdater) Filter(rn *yaml.RNode) (*yaml.RNode, error) {
if err := yaml.ErrorIfInvalid(rn, yaml.ScalarNode); err != nil {
return nil, err
}
value := rn.YNode().Value
if !image.IsImageMatched(value, u.ImageTag.Name) {
return rn, nil
}
name, tag := image.Split(value)
if u.ImageTag.NewName != "" {
name = u.ImageTag.NewName
}
if u.ImageTag.NewTag != "" {
tag = ":" + u.ImageTag.NewTag
}
if u.ImageTag.Digest != "" {
tag = "@" + u.ImageTag.Digest
}
return rn.Pipe(yaml.FieldSetter{StringValue: name + tag})
}

View File

@@ -15,7 +15,7 @@ type Filter struct {
Namespace string `yaml:"namespace,omitempty"`
// FsSlice contains the FieldSpecs to locate the namespace field
FsSlice types.FsSlice
FsSlice types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
var _ kio.Filter = Filter{}

View File

@@ -0,0 +1,6 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package namespace contains a kio.Filter implementation of the kustomize
// patchjson6902 transformer
package patchjson6902

View File

@@ -0,0 +1,55 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package patchjson6902
import (
"bytes"
"log"
"os"
"sigs.k8s.io/kustomize/kyaml/kio"
)
func ExampleFilter() {
err := kio.Pipeline{
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
---
apiVersion: example.com/v1
kind: Bar
metadata:
name: instance
namespace: bar
`)}},
Filters: []kio.Filter{
Filter{
Patch: `
- op: replace
path: /metadata/namespace
value: "ns"
`,
},
},
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
}.Execute()
if err != nil {
log.Fatal(err)
}
// Output:
// apiVersion: example.com/v1
// kind: Foo
// metadata:
// name: instance
// namespace: ns
// ---
// apiVersion: example.com/v1
// kind: Bar
// metadata:
// name: instance
// namespace: ns
}

View File

@@ -0,0 +1,65 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package patchjson6902
import (
"strings"
jsonpatch "github.com/evanphx/json-patch"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
k8syaml "sigs.k8s.io/yaml"
)
type Filter struct {
Patch string
decodedPatch jsonpatch.Patch
}
var _ kio.Filter = Filter{}
func (pf Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
decodedPatch, err := pf.decodePatch()
if err != nil {
return nil, err
}
pf.decodedPatch = decodedPatch
return kio.FilterAll(yaml.FilterFunc(pf.run)).Filter(nodes)
}
func (pf Filter) decodePatch() (jsonpatch.Patch, error) {
patch := pf.Patch
// If the patch doesn't look like a JSON6902 patch, we
// try to parse it to json.
if !strings.HasPrefix(pf.Patch, "[") {
p, err := k8syaml.YAMLToJSON([]byte(patch))
if err != nil {
return nil, err
}
patch = string(p)
}
decodedPatch, err := jsonpatch.DecodePatch([]byte(patch))
if err != nil {
return nil, err
}
return decodedPatch, nil
}
func (pf Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
// We don't actually use the kyaml library for manipulating the
// yaml here. We just marshal it to json and rely on the
// jsonpatch library to take care of applying the patch.
// This means ordering might not be preserved with this filter.
b, err := node.MarshalJSON()
if err != nil {
return nil, err
}
res, err := pf.decodedPatch.Apply(b)
if err != nil {
return nil, err
}
err = node.UnmarshalJSON(res)
return node, err
}

View File

@@ -0,0 +1,173 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package patchjson6902
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
filtertest "sigs.k8s.io/kustomize/api/testutils/filtertest"
)
const input = `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
replica: 2
template:
metadata:
labels:
old-label: old-value
spec:
containers:
- image: nginx
name: nginx
`
func TestSomething(t *testing.T) {
testCases := []struct {
testName string
input string
filter Filter
expectedOutput string
}{
{
testName: "single operation, json",
input: input,
filter: Filter{
Patch: `[
{"op": "replace", "path": "/spec/replica", "value": 5}
]`,
},
expectedOutput: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
replica: 5
template:
metadata:
labels:
old-label: old-value
spec:
containers:
- image: nginx
name: nginx
`,
},
{
testName: "multiple operations, json",
input: input,
filter: Filter{
Patch: `[
{"op": "replace", "path": "/spec/template/spec/containers/0/name", "value": "my-nginx"},
{"op": "add", "path": "/spec/replica", "value": 999},
{"op": "add", "path": "/spec/template/spec/containers/0/command", "value": ["arg1", "arg2", "arg3"]}
]`,
},
expectedOutput: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
replica: 999
template:
metadata:
labels:
old-label: old-value
spec:
containers:
- command:
- arg1
- arg2
- arg3
image: nginx
name: my-nginx
`,
},
{
testName: "single operation, yaml",
input: input,
filter: Filter{
Patch: `
- op: replace
path: /spec/replica
value: 5
`,
},
expectedOutput: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
replica: 5
template:
metadata:
labels:
old-label: old-value
spec:
containers:
- image: nginx
name: nginx
`,
},
{
testName: "multiple operations, yaml",
input: input,
filter: Filter{
Patch: `
- op: replace
path: /spec/template/spec/containers/0/name
value: my-nginx
- op: add
path: /spec/replica
value: 999
- op: add
path: /spec/template/spec/containers/0/command
value:
- arg1
- arg2
- arg3
`,
},
expectedOutput: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
replica: 999
template:
metadata:
labels:
old-label: old-value
spec:
containers:
- command:
- arg1
- arg2
- arg3
image: nginx
name: my-nginx
`,
},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
if !assert.Equal(t,
strings.TrimSpace(tc.expectedOutput),
strings.TrimSpace(
filtertest.RunFilter(t, tc.input, tc.filter))) {
t.FailNow()
}
})
}
}

View File

@@ -0,0 +1,6 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package patchstrategicmerge contains a kio.Filter implementation of the
// kustomize strategic merge patch transformer.
package patchstrategicmerge

View File

@@ -0,0 +1,49 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package patchstrategicmerge
import (
"bytes"
"log"
"os"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
func ExampleFilter() {
err := kio.Pipeline{
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
spec:
replicas: 3
`)}},
Filters: []kio.Filter{Filter{
Patch: yaml.MustParse(`
spec:
template:
containers:
- image: nginx
`),
}},
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
}.Execute()
if err != nil {
log.Fatal(err)
}
// Output:
// apiVersion: example.com/v1
// kind: Foo
// metadata:
// name: instance
// spec:
// replicas: 3
// template:
// containers:
// - image: nginx
}

View File

@@ -0,0 +1,21 @@
package patchstrategicmerge
import (
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
"sigs.k8s.io/kustomize/kyaml/yaml/merge2"
)
type Filter struct {
Patch *yaml.RNode
}
var _ kio.Filter = Filter{}
func (pf Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
return kio.FilterAll(yaml.FilterFunc(pf.run)).Filter(nodes)
}
func (pf Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
return merge2.Merge(pf.Patch, node)
}

View File

@@ -0,0 +1,82 @@
package patchstrategicmerge
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
filtertest "sigs.k8s.io/kustomize/api/testutils/filtertest"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
func TestFilter(t *testing.T) {
testCases := map[string]struct {
input string
patch *yaml.RNode
expected string
}{
"simple patch": {
input: `
apiVersion: apps/v1
metadata:
name: myDeploy
kind: Deployment
`,
patch: yaml.MustParse(`
metadata:
name: yourDeploy
`),
expected: `
apiVersion: apps/v1
metadata:
name: yourDeploy
kind: Deployment
`,
},
"nested patch": {
input: `
apiVersion: apps/v1
metadata:
name: myDeploy
kind: Deployment
spec:
containers:
- name: nginx
args:
- abc
`,
patch: yaml.MustParse(`
spec:
containers:
- name: nginx
args:
- def
`),
expected: `
apiVersion: apps/v1
metadata:
name: myDeploy
kind: Deployment
spec:
containers:
- name: nginx
args:
- def
`,
},
}
for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
f := Filter{
Patch: tc.patch,
}
if !assert.Equal(t,
strings.TrimSpace(tc.expected),
strings.TrimSpace(
filtertest.RunFilter(t, tc.input, f))) {
t.FailNow()
}
})
}
}

View File

@@ -0,0 +1,6 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package prefixsuffix contains a kio.Filter implementation of the kustomize
// PrefixSuffixTransformer.
package prefixsuffix

View File

@@ -0,0 +1,47 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package prefixsuffix_test
import (
"bytes"
"log"
"os"
"sigs.k8s.io/kustomize/api/filters/prefixsuffix"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
"sigs.k8s.io/kustomize/kyaml/kio"
)
func ExampleFilter() {
fss := builtinconfig.MakeDefaultConfig().NamePrefix
err := kio.Pipeline{
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
---
apiVersion: example.com/v1
kind: Bar
metadata:
name: instance
`)}},
Filters: []kio.Filter{prefixsuffix.Filter{Prefix: "baz-", FsSlice: fss}},
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
}.Execute()
if err != nil {
log.Fatal(err)
}
// Output:
// apiVersion: example.com/v1
// kind: Foo
// metadata:
// name: baz-instance
// ---
// apiVersion: example.com/v1
// kind: Bar
// metadata:
// name: baz-instance
}

View File

@@ -0,0 +1,43 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package prefixsuffix
import (
"fmt"
"sigs.k8s.io/kustomize/api/filters/fsslice"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// Filter applies resource name prefix's and suffix's using the fieldSpecs
type Filter struct {
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"`
Suffix string `json:"suffix,omitempty" yaml:"suffix,omitempty"`
FsSlice types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
var _ kio.Filter = Filter{}
func (ns Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
return kio.FilterAll(yaml.FilterFunc(ns.run)).Filter(nodes)
}
// Run runs the filter on a single node rather than a slice
func (ns Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
// transformations based on data -- :)
err := node.PipeE(fsslice.Filter{
FsSlice: ns.FsSlice,
SetValue: ns.set,
CreateKind: yaml.ScalarNode, // Name is a ScalarNode
})
return node, err
}
func (ns Filter) set(node *yaml.RNode) error {
return fsslice.SetScalar(fmt.Sprintf(
"%s%s%s", ns.Prefix, node.YNode().Value, ns.Suffix))(node)
}

View File

@@ -0,0 +1,167 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package prefixsuffix_test
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/api/filters/prefixsuffix"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
"sigs.k8s.io/kustomize/api/types"
)
var tests = []TestCase{
{
name: "prefix",
input: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
---
apiVersion: example.com/v1
kind: Bar
metadata:
name: instance
`,
expected: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: foo-instance
---
apiVersion: example.com/v1
kind: Bar
metadata:
name: foo-instance
`,
filter: prefixsuffix.Filter{Prefix: "foo-"},
},
{
name: "suffix",
input: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
---
apiVersion: example.com/v1
kind: Bar
metadata:
name: instance
`,
expected: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance-foo
---
apiVersion: example.com/v1
kind: Bar
metadata:
name: instance-foo
`,
filter: prefixsuffix.Filter{Suffix: "-foo"},
},
{
name: "prefix-suffix",
input: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
---
apiVersion: example.com/v1
kind: Bar
metadata:
name: instance
`,
expected: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: bar-instance-foo
---
apiVersion: example.com/v1
kind: Bar
metadata:
name: bar-instance-foo
`,
filter: prefixsuffix.Filter{Prefix: "bar-", Suffix: "-foo"},
},
{
name: "data-fieldspecs",
input: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
a:
b:
c: d
---
apiVersion: example.com/v1
kind: Bar
metadata:
name: instance
a:
b:
c: d
`,
expected: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: foo-instance
a:
b:
c: foo-d
---
apiVersion: example.com/v1
kind: Bar
metadata:
name: foo-instance
a:
b:
c: foo-d
`,
filter: prefixsuffix.Filter{Prefix: "foo-"},
fsslice: []types.FieldSpec{
{
Path: "a/b/c",
},
},
},
}
type TestCase struct {
name string
input string
expected string
filter prefixsuffix.Filter
fsslice types.FsSlice
}
var config = builtinconfig.MakeDefaultConfig()
func TestFilter(t *testing.T) {
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
test.filter.FsSlice = append(config.NamePrefix, test.fsslice...)
if !assert.Equal(t,
strings.TrimSpace(test.expected),
strings.TrimSpace(
filtertest_test.RunFilter(t, test.input, test.filter))) {
t.FailNow()
}
})
}
}

View File

@@ -0,0 +1,6 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package replicacount contains a kio.Filter implementation of the kustomize
// ReplicaCountTransformer.
package replicacount

View File

@@ -0,0 +1,64 @@
package replicacount
import (
"bytes"
"log"
"os"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio"
)
func ExampleFilter() {
err := kio.Pipeline{
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
spec:
template:
replicas: 5
---
apiVersion: example.com/v1
kind: Bar
metadata:
name: instance
spec:
template:
replicas: 5
`)}},
Filters: []kio.Filter{Filter{
Replica: types.Replica{
Count: 42,
Name: "instance",
},
FsSlice: types.FsSlice{
{
Path: "spec/template/replicas",
},
},
}},
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
}.Execute()
if err != nil {
log.Fatal(err)
}
// Output:
// apiVersion: example.com/v1
// kind: Foo
// metadata:
// name: instance
// spec:
// template:
// replicas: 42
// ---
// apiVersion: example.com/v1
// kind: Bar
// metadata:
// name: instance
// spec:
// template:
// replicas: 42
}

View File

@@ -0,0 +1,48 @@
package replicacount
import (
"strconv"
"sigs.k8s.io/kustomize/api/filters/fsslice"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// Filter updates/sets replicas fields using the fieldSpecs
type Filter struct {
Replica types.Replica `json:"replica,omitempty" yaml:"replica,omitempty"`
// FsSlice contains the FieldSpecs to locate the namespace field
FsSlice types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
var _ kio.Filter = Filter{}
func (rc Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
return kio.FilterAll(yaml.FilterFunc(rc.run)).Filter(nodes)
}
// run processes each node individually.
func (rc Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
meta, err := node.GetMeta()
if err != nil {
return nil, err
}
// only update resources where the name matches the Replica name.
if meta.Name != rc.Replica.Name {
return node, nil
}
err = node.PipeE(fsslice.Filter{
FsSlice: rc.FsSlice,
SetValue: rc.set,
CreateKind: yaml.ScalarNode, // replicas is a ScalarNode
})
return node, err
}
func (rc Filter) set(node *yaml.RNode) error {
return fsslice.SetScalar(strconv.FormatInt(rc.Replica.Count, 10))(node)
}

View File

@@ -0,0 +1,164 @@
package replicacount
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
"sigs.k8s.io/kustomize/api/types"
)
func TestFilter(t *testing.T) {
var config = builtinconfig.MakeDefaultConfig()
testCases := map[string]struct {
input string
expected string
filter Filter
fsslice types.FsSlice
}{
"update field": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
spec:
replicas: 5
`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
spec:
replicas: 42
`,
filter: Filter{
Replica: types.Replica{
Name: "dep",
Count: 42,
},
},
fsslice: types.FsSlice{
{
Path: "spec/replicas",
},
},
},
"add field": {
input: `
apiVersion: custom/v1
kind: Custom
metadata:
name: cus
spec:
template:
other: something
`,
expected: `
apiVersion: custom/v1
kind: Custom
metadata:
name: cus
spec:
template:
other: something
replicas: 42
`,
filter: Filter{
Replica: types.Replica{
Name: "cus",
Count: 42,
},
},
fsslice: types.FsSlice{
{
Path: "spec/template/replicas",
CreateIfNotPresent: true,
},
},
},
"no update if CreateIfNotPresent is false": {
input: `
apiVersion: custom/v1
kind: Custom
metadata:
name: cus
spec:
template:
other: something
`,
expected: `
apiVersion: custom/v1
kind: Custom
metadata:
name: cus
spec:
template:
other: something
`,
filter: Filter{
Replica: types.Replica{
Name: "cus",
Count: 42,
},
},
fsslice: types.FsSlice{
{
Path: "spec/template/replicas",
},
},
},
"update multiple fields": {
input: `
apiVersion: custom/v1
kind: Custom
metadata:
name: cus
spec:
replicas: 5
template:
replicas: 5
`,
expected: `
apiVersion: custom/v1
kind: Custom
metadata:
name: cus
spec:
replicas: 42
template:
replicas: 42
`,
filter: Filter{
Replica: types.Replica{
Name: "cus",
Count: 42,
},
},
fsslice: types.FsSlice{
{
Path: "spec/template/replicas",
},
{
Path: "spec/replicas",
},
},
},
}
for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
tc.filter.FsSlice = append(config.Replicas, tc.fsslice...)
if !assert.Equal(t,
strings.TrimSpace(tc.expected),
strings.TrimSpace(
filtertest_test.RunFilter(t, tc.input, tc.filter))) {
t.FailNow()
}
})
}
}

View File

@@ -16,6 +16,6 @@ require (
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.1.1
sigs.k8s.io/kustomize/kyaml v0.1.5
sigs.k8s.io/yaml v1.1.0
)

View File

@@ -1,6 +1,7 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
github.com/360EntSecGroup-Skylar/excelize v1.4.1/go.mod h1:vnax29X2usfl7HHkBrX5EvSCJcmH3dT9luvxzu8iGAE=
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
@@ -14,6 +15,7 @@ github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb0
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/OpenPeeDeeP/depguard v1.0.1 h1:VlW4R6jmBIv3/u1JNlawEvJMM4J+dPORPaZasQee8Us=
github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM=
github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
@@ -23,6 +25,7 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdko
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -31,6 +34,9 @@ github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ
github.com/bombsimon/wsl v1.2.5 h1:9gTOkIwVtoDZywvX802SDHokeX4kW1cKnV8ZTVAPkRs=
github.com/bombsimon/wsl v1.2.5/go.mod h1:43lEF/i0kpXbLCeDXL9LMT8c92HyBywXb0AsgMHYngM=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
@@ -47,6 +53,7 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/dustmop/soup v1.1.2-0.20190516214245-38228baa104e/go.mod h1:CgNC6SGbT+Xb8wGGvzilttZL1mc5sQ/5KkcxsZttMIk=
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
@@ -249,6 +256,7 @@ github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lN
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
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/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=
@@ -263,6 +271,7 @@ github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/paulmach/orb v0.1.3/go.mod h1:VFlX/8C+IQ1p6FTRRKzKoOPJnvEtA5G0Veuqwbu//Vk=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
@@ -281,6 +290,7 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/qri-io/starlib v0.4.2-0.20200213133954-ff2e8cd5ef8d/go.mod h1:7DPO4domFU579Ga6E61sB9VFNaniPVwJP5C4bBCu3wA=
github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
@@ -323,6 +333,7 @@ github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.3-0.20181224173747-660f15d67dbb/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -351,6 +362,8 @@ github.com/yujunz/go-getter v1.4.1-lite h1:FhvNc94AXMZkfqUwfMKhnQEC9phkphSGdPTL7
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.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.starlark.net v0.0.0-20190528202925-30ae18b8564f/go.mod h1:c1/X6cHgvdXj6pUlmWKMkuqRnW4K8x2vwt6JAaaircg=
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
@@ -368,6 +381,7 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -408,6 +422,7 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69 h1:rOhMmluY6kLMhdnrivzec6lLgaVbMHMn2ISQXJeJ5EM=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -496,6 +511,10 @@ sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbL
sigs.k8s.io/kustomize/kyaml v0.1.1 h1:nGUNYINljZNmlAS8uoobUv/wx/s3Pg8dNxYo+W7uYh0=
sigs.k8s.io/kustomize/kyaml v0.1.1/go.mod h1:/NdPPfrperSCGjm55cwEro1loBVtbtVIXSb7FguK6uk=
sigs.k8s.io/kustomize/kyaml v0.1.2 h1:l12+QGl+ETUHhP8/bZAi6TknU7H194fXL/9b2gUxZFY=
sigs.k8s.io/kustomize/kyaml v0.1.3 h1:zbeHVTMCQPtWgjIH/YYJZC45mm7coTdw2TblyJ79BrY=
sigs.k8s.io/kustomize/kyaml v0.1.3/go.mod h1:461i94nj0h0ylJ6w83jLkR4SqqVhn1iY6fjD0JSTQeE=
sigs.k8s.io/kustomize/kyaml v0.1.5 h1:NicBWYTwkuOfVyZDbNkfSBSCwSgin4uirkedtyZltIc=
sigs.k8s.io/kustomize/kyaml v0.1.5/go.mod h1:461i94nj0h0ylJ6w83jLkR4SqqVhn1iY6fjD0JSTQeE=
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

@@ -75,14 +75,8 @@ type KunstructuredFactory interface {
SliceFromBytes([]byte) ([]Kunstructured, error)
FromMap(m map[string]interface{}) Kunstructured
Hasher() KunstructuredHasher
MakeConfigMap(
kvLdr KvLoader,
options *types.GeneratorOptions,
args *types.ConfigMapArgs) (Kunstructured, error)
MakeSecret(
kvLdr KvLoader,
options *types.GeneratorOptions,
args *types.SecretArgs) (Kunstructured, error)
MakeConfigMap(kvLdr KvLoader, args *types.ConfigMapArgs) (Kunstructured, error)
MakeSecret(kvLdr KvLoader, args *types.SecretArgs) (Kunstructured, error)
}
// KunstructuredHasher returns a hash of the argument

50
api/image/image.go Normal file
View File

@@ -0,0 +1,50 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package image
import (
"regexp"
"strings"
)
// IsImageMatched returns true if the value of t is identical to the
// image name in the full image name and tag as given by s.
func IsImageMatched(s, t string) bool {
// Tag values are limited to [a-zA-Z0-9_.{}-].
// Some tools like Bazel rules_k8s allow tag patterns with {} characters.
// More info: https://github.com/bazelbuild/rules_k8s/pull/423
pattern, _ := regexp.Compile("^" + t + "(@sha256)?(:[a-zA-Z0-9_.{}-]*)?$")
return pattern.MatchString(s)
}
// Split separates and returns the name and tag parts
// from the image string using either colon `:` or at `@` separators.
// Note that the returned tag keeps its separator.
func Split(imageName string) (name string, tag string) {
// check if image name contains a domain
// if domain is present, ignore domain and check for `:`
ic := -1
if slashIndex := strings.Index(imageName, "/"); slashIndex < 0 {
ic = strings.LastIndex(imageName, ":")
} else {
lastIc := strings.LastIndex(imageName[slashIndex:], ":")
// set ic only if `:` is present
if lastIc > 0 {
ic = slashIndex + lastIc
}
}
ia := strings.LastIndex(imageName, "@")
if ic < 0 && ia < 0 {
return imageName, ""
}
i := ic
if ia > 0 {
i = ia
}
name = imageName[:i]
tag = imageName[i:]
return
}

80
api/image/image_test.go Normal file
View File

@@ -0,0 +1,80 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package image
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestIsImageMatched(t *testing.T) {
testCases := []struct {
testName string
value string
name string
isMatched bool
}{
{
testName: "identical",
value: "nginx",
name: "nginx",
isMatched: true,
},
{
testName: "name is match",
value: "nginx:12345",
name: "nginx",
isMatched: true,
},
{
testName: "name is not a match",
value: "apache:12345",
name: "nginx",
isMatched: false,
},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
assert.Equal(t, tc.isMatched, IsImageMatched(tc.value, tc.name))
})
}
}
func TestSplit(t *testing.T) {
testCases := []struct {
testName string
value string
name string
tag string
}{
{
testName: "no tag",
value: "nginx",
name: "nginx",
tag: "",
},
{
testName: "with tag",
value: "nginx:1.2.3",
name: "nginx",
tag: ":1.2.3",
},
{
testName: "with digest",
value: "nginx@12345",
name: "nginx",
tag: "@12345",
},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
name, tag := Split(tc.value)
assert.Equal(t, tc.name, name)
assert.Equal(t, tc.tag, tag)
})
}
}

View File

@@ -25,8 +25,7 @@ func makeFreshConfigMap(
}
// MakeConfigMap returns a new ConfigMap, or nil and an error.
func (f *Factory) MakeConfigMap(
args *types.ConfigMapArgs) (*corev1.ConfigMap, error) {
func (f *Factory) MakeConfigMap(args *types.ConfigMapArgs) (*corev1.ConfigMap, error) {
all, err := f.kvLdr.Load(args.KvPairSources)
if err != nil {
return nil, errors.Wrap(err, "loading KV pairs")
@@ -38,7 +37,7 @@ func (f *Factory) MakeConfigMap(
return nil, errors.Wrap(err, "trouble mapping")
}
}
f.setLabelsAndAnnnotations(cm, args.GeneratorOptions)
f.copyLabelsAndAnnotations(cm, args.Options)
return cm, nil
}

View File

@@ -82,7 +82,6 @@ func TestConstructConfigMap(t *testing.T) {
type testCase struct {
description string
input types.ConfigMapArgs
options *types.GeneratorOptions
expected *corev1.ConfigMap
}
@@ -99,7 +98,6 @@ func TestConstructConfigMap(t *testing.T) {
},
},
},
options: nil,
expected: makeEnvConfigMap("envConfigMap"),
},
{
@@ -115,7 +113,6 @@ func TestConstructConfigMap(t *testing.T) {
},
},
},
options: nil,
expected: makeFileConfigMap("fileConfigMap"),
},
{
@@ -126,11 +123,11 @@ func TestConstructConfigMap(t *testing.T) {
KvPairSources: types.KvPairSources{
LiteralSources: []string{"a=x", "b=y", "c=\"Hello World\"", "d='true'"},
},
},
},
options: &types.GeneratorOptions{
Labels: map[string]string{
"foo": "bar",
Options: &types.GeneratorOptions{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
expected: makeLiteralConfigMap("literalConfigMap", map[string]string{
@@ -145,7 +142,7 @@ func TestConstructConfigMap(t *testing.T) {
KvPairSources: types.KvPairSources{
LiteralSources: []string{"a=x", "b=y", "c=\"Hello World\"", "d='true'"},
},
GeneratorOptions: &types.GeneratorOptions{
Options: &types.GeneratorOptions{
Labels: map[string]string{
"foo": "changed",
"cat": "dog",
@@ -157,18 +154,6 @@ func TestConstructConfigMap(t *testing.T) {
},
},
},
options: &types.GeneratorOptions{
Labels: map[string]string{
"foo": "bar",
},
Annotations: map[string]string{
"foo": "bar",
},
},
// GeneratorOptions from the ConfigMapArgs take precedence over the
// factory level GeneratorOptions and should overwrite
// labels/annotations set in the factory level if there are common
// labels/annotations
expected: makeLiteralConfigMap("literalConfigMap", map[string]string{
"foo": "changed",
"cat": "dog",
@@ -193,8 +178,7 @@ func TestConstructConfigMap(t *testing.T) {
loader.NewFileLoaderAtRoot(fSys),
valtest_test.MakeFakeValidator())
for _, tc := range testCases {
f := NewFactory(kvLdr, tc.options)
cm, err := f.MakeConfigMap(&tc.input)
cm, err := NewFactory(kvLdr).MakeConfigMap(&tc.input)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}

View File

@@ -11,44 +11,26 @@ import (
// Factory makes ConfigMaps and Secrets.
type Factory struct {
kvLdr ifc.KvLoader
options *types.GeneratorOptions
kvLdr ifc.KvLoader
}
// NewFactory returns a new factory that makes ConfigMaps and Secrets.
func NewFactory(
kvLdr ifc.KvLoader, o *types.GeneratorOptions) *Factory {
return &Factory{kvLdr: kvLdr, options: o}
func NewFactory(kvLdr ifc.KvLoader) *Factory {
return &Factory{kvLdr: kvLdr}
}
// setLabelsAndAnnnotations will take the labels and annotations from
// global GeneratorOptions and resource level GeneratorOptions and merge them
// with the resource level taking precedence, and then set them on the provided
// obj.
func (f *Factory) setLabelsAndAnnnotations(obj metav1.Object, opts *types.GeneratorOptions) {
labels := make(map[string]string)
annotations := make(map[string]string)
if f.options != nil {
for k, v := range f.options.Labels {
labels[k] = v
}
for k, v := range f.options.Annotations {
annotations[k] = v
}
// copyLabelsAndAnnotations copies labels and annotations from
// GeneratorOptions into the given object.
func (f *Factory) copyLabelsAndAnnotations(
obj metav1.Object, opts *types.GeneratorOptions) {
if opts == nil {
return
}
if opts != nil {
for k, v := range opts.Labels {
labels[k] = v
}
for k, v := range opts.Annotations {
annotations[k] = v
}
if opts.Labels != nil {
obj.SetLabels(types.CopyMap(opts.Labels))
}
if len(labels) != 0 {
obj.SetLabels(labels)
}
if len(annotations) != 0 {
obj.SetAnnotations(annotations)
if opts.Annotations != nil {
obj.SetAnnotations(types.CopyMap(opts.Annotations))
}
}

View File

@@ -26,8 +26,7 @@ func makeFreshSecret(
}
// MakeSecret returns a new secret.
func (f *Factory) MakeSecret(
args *types.SecretArgs) (*corev1.Secret, error) {
func (f *Factory) MakeSecret(args *types.SecretArgs) (*corev1.Secret, error) {
all, err := f.kvLdr.Load(args.KvPairSources)
if err != nil {
return nil, err
@@ -39,7 +38,7 @@ func (f *Factory) MakeSecret(
return nil, err
}
}
f.setLabelsAndAnnnotations(s, args.GeneratorOptions)
f.copyLabelsAndAnnotations(s, args.Options)
return s, nil
}

View File

@@ -79,7 +79,6 @@ func TestConstructSecret(t *testing.T) {
type testCase struct {
description string
input types.SecretArgs
options *types.GeneratorOptions
expected *corev1.Secret
}
@@ -94,7 +93,6 @@ func TestConstructSecret(t *testing.T) {
},
},
},
options: nil,
expected: makeEnvSecret("envSecret"),
},
{
@@ -107,7 +105,6 @@ func TestConstructSecret(t *testing.T) {
},
},
},
options: nil,
expected: makeFileSecret("fileSecret"),
},
{
@@ -118,55 +115,22 @@ func TestConstructSecret(t *testing.T) {
KvPairSources: types.KvPairSources{
LiteralSources: []string{"a=x", "b=y"},
},
},
},
options: &types.GeneratorOptions{
Labels: map[string]string{
"foo": "bar",
Options: &types.GeneratorOptions{
Labels: map[string]string{
"foo": "bar",
},
Annotations: map[string]string{
"fruit": "banana",
"pet": "dog",
},
},
},
},
expected: makeLiteralSecret("literalSecret", map[string]string{
"foo": "bar",
}, nil),
},
{
description: "construct secret from literal with GeneratorOptions in SecretArgs",
input: types.SecretArgs{
GeneratorArgs: types.GeneratorArgs{
Name: "literalSecret",
KvPairSources: types.KvPairSources{
LiteralSources: []string{"a=x", "b=y"},
},
GeneratorOptions: &types.GeneratorOptions{
Labels: map[string]string{
"foo": "changed",
"cat": "dog",
},
Annotations: map[string]string{
"foo": "changed",
"cat": "dog",
},
},
},
},
options: &types.GeneratorOptions{
Labels: map[string]string{
"foo": "bar",
},
Annotations: map[string]string{
"foo": "bar",
},
},
// GeneratorOptions from the SecretArgs take precedence over the
// factory level GeneratorOptions and should overwrite
// labels/annotations set in the factory level if there are common
// labels/annotations
expected: makeLiteralSecret("literalSecret", map[string]string{
"foo": "changed",
"cat": "dog",
}, map[string]string{
"foo": "changed",
"cat": "dog",
"fruit": "banana",
"pet": "dog",
}),
},
}
@@ -178,7 +142,7 @@ func TestConstructSecret(t *testing.T) {
loader.NewFileLoaderAtRoot(fSys),
valtest_test.MakeFakeValidator())
for _, tc := range testCases {
f := NewFactory(kvLdr, tc.options)
f := NewFactory(kvLdr)
cm, err := f.MakeSecret(&tc.input)
if err != nil {
t.Fatalf("unexpected error: %v", err)

View File

@@ -6,143 +6,85 @@ package compiler
import (
"bytes"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/konfig"
)
// Compiler creates Go plugin object files.
//
// Source code is read from
// ${srcRoot}/${g}/${v}/${k}.go
//
// Object code is written to
// ${objRoot}/${g}/${v}/${k}.so
type Compiler struct {
srcRoot string
objRoot string
}
// DeterminePluginSrcRoot guesses where the user
// has her ${g}/${v}/$lower(${k})/${k}.go files.
func DeterminePluginSrcRoot(fSys filesys.FileSystem) (string, error) {
return konfig.FirstDirThatExistsElseError(
"source directory", fSys, []konfig.NotedFunc{
{
Note: "relative to unit test",
F: func() string {
return filepath.Clean(
filepath.Join(
os.Getenv("PWD"),
"..", "..",
konfig.RelPluginHome))
},
},
{
Note: "relative to unit test (internal pkg)",
F: func() string {
return filepath.Clean(
filepath.Join(
os.Getenv("PWD"),
"..", "..", "..", "..",
konfig.RelPluginHome))
},
},
{
Note: "relative to api package",
F: func() string {
return filepath.Clean(
filepath.Join(
os.Getenv("PWD"),
"..", "..", "..",
konfig.RelPluginHome))
},
},
{
Note: "old style $GOPATH",
F: func() string {
return filepath.Join(
os.Getenv("GOPATH"),
"src", konfig.DomainName,
konfig.ProgramName, konfig.RelPluginHome)
},
},
{
Note: "HOME with literal 'gopath'",
F: func() string {
return filepath.Join(
konfig.HomeDir(), "gopath",
"src", konfig.DomainName,
konfig.ProgramName, konfig.RelPluginHome)
},
},
{
Note: "home directory",
F: func() string {
return filepath.Join(
konfig.HomeDir(), konfig.DomainName,
konfig.ProgramName, konfig.RelPluginHome)
},
},
})
// pluginRoot is where the user
// has her ${g}/${v}/$lower(${k})/${k}.go files.
pluginRoot string
// Where compilation happens.
workDir string
// Used as the root file name for src and object.
rawKind string
// Capture compiler output.
stderr bytes.Buffer
// Capture compiler output.
stdout bytes.Buffer
}
// NewCompiler returns a new compiler instance.
func NewCompiler(srcRoot, objRoot string) *Compiler {
return &Compiler{srcRoot: srcRoot, objRoot: objRoot}
func NewCompiler(root string) *Compiler {
return &Compiler{pluginRoot: root}
}
// ObjRoot is root of compilation target tree.
func (b *Compiler) ObjRoot() string {
return b.objRoot
// Set GVK converts g,v,k tuples to file path components.
func (b *Compiler) SetGVK(g, v, k string) {
b.rawKind = k
b.workDir = filepath.Join(b.pluginRoot, g, v, strings.ToLower(k))
}
// SrcRoot is where to find src.
func (b *Compiler) SrcRoot() string {
return b.srcRoot
func (b *Compiler) srcPath() string {
return filepath.Join(b.workDir, b.rawKind+".go")
}
func goBin() string {
return filepath.Join(runtime.GOROOT(), "bin", "go")
func (b *Compiler) objFile() string {
return b.rawKind + ".so"
}
// Compile reads ${srcRoot}/${g}/${v}/${k}.go
// and writes ${objRoot}/${g}/${v}/${k}.so
func (b *Compiler) Compile(g, v, k string) error {
lowK := strings.ToLower(k)
objDir := filepath.Join(b.objRoot, g, v, lowK)
objFile := filepath.Join(objDir, k) + ".so"
if RecentFileExists(objFile) {
// Skip rebuilding it.
// Absolute path to the compiler output (the .so file).
func (b *Compiler) ObjPath() string {
return filepath.Join(b.workDir, b.objFile())
}
// Cleanup provides a hook to delete the .so file.
// Ignore errors.
func (b *Compiler) Cleanup() {
_ = os.Remove(b.ObjPath())
}
// Compile changes its working directory to
// ${pluginRoot}/${g}/${v}/$lower(${k} and places
// object code next to source code.
func (b *Compiler) Compile() error {
if FileYoungerThan(b.ObjPath(), 8*time.Second) {
// Skip rebuilding it, to save time in a plugin test file
// that has many distinct calls to make a harness and compile
// the plugin (only the first compile will happen).
// Make it a short time to avoid tricking someone who's actively
// developing a plugin.
return nil
}
err := os.MkdirAll(objDir, os.ModePerm)
if err != nil {
return err
}
srcFile := filepath.Join(b.srcRoot, g, v, lowK, k) + ".go"
if !FileExists(srcFile) {
// Handy for tests of lone plugins.
s := k + ".go"
if !FileExists(s) {
return fmt.Errorf(
"cannot find source at '%s' or '%s'", srcFile, s)
}
srcFile = s
if !FileExists(b.srcPath()) {
return fmt.Errorf("cannot find source at '%s'", b.srcPath())
}
// If you use an IDE, make sure it's go build and test flags
// match those used below. Same goes for Makefile targets.
commands := []string{
"build",
// "-trimpath", This flag used to make it better, now it makes it worse,
// see https://github.com/golang/go/issues/31354
"-buildmode",
"plugin",
"-o", objFile, srcFile,
"-o", b.objFile(),
}
goBin := goBin()
if !FileExists(goBin) {
@@ -150,34 +92,26 @@ func (b *Compiler) Compile(g, v, k string) error {
"cannot find go compiler %s", goBin)
}
cmd := exec.Command(goBin, commands...)
var stderr bytes.Buffer
cmd.Stderr = &stderr
b.stderr.Reset()
cmd.Stderr = &b.stderr
b.stdout.Reset()
cmd.Stdout = &b.stdout
cmd.Env = os.Environ()
cmd.Dir = b.workDir
if err := cmd.Run(); err != nil {
b.report()
return errors.Wrapf(
err, "cannot compile %s:\nSTDERR\n%s\n", srcFile, stderr.String())
err, "cannot compile %s:\nSTDERR\n%s\n",
b.srcPath(), b.stderr.String())
}
return nil
}
// True if file less than 3 minutes old, i.e. not
// accidentally left over from some earlier build.
func RecentFileExists(path string) bool {
fi, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
return false
}
}
age := time.Since(fi.ModTime())
return age.Minutes() < 3
}
func FileExists(name string) bool {
if _, err := os.Stat(name); err != nil {
if os.IsNotExist(err) {
return false
}
}
return true
func (b *Compiler) report() {
log.Println("stdout: -------")
log.Println(b.stdout.String())
log.Println("----------------")
log.Println("stderr: -------")
log.Println(b.stderr.String())
log.Println("----------------")
}

View File

@@ -4,10 +4,9 @@
package compiler_test
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"time"
"sigs.k8s.io/kustomize/api/filesys"
. "sigs.k8s.io/kustomize/api/internal/plugins/compiler"
@@ -15,53 +14,46 @@ import (
// Regression coverage over compiler behavior.
func TestCompiler(t *testing.T) {
configRoot, err := ioutil.TempDir("", "kustomize-compiler-test")
if err != nil {
t.Errorf("failed to make temp dir: %v", err)
}
srcRoot, err := DeterminePluginSrcRoot(filesys.MakeFsOnDisk())
if err != nil {
t.Error(err)
}
c := NewCompiler(srcRoot, configRoot)
if configRoot != c.ObjRoot() {
t.Errorf("unexpected objRoot %s", c.ObjRoot())
}
c := NewCompiler(srcRoot)
c.SetGVK("someteam.example.com", "v1", "DatePrefixer")
expectObj := filepath.Join(
c.ObjRoot(),
"someteam.example.com", "v1", "dateprefixer", "DatePrefixer.so")
if FileExists(expectObj) {
t.Errorf("obj file should not exist yet: %s", expectObj)
srcRoot, "someteam.example.com", "v1", "dateprefixer", "DatePrefixer.so")
if expectObj != c.ObjPath() {
t.Errorf("Expected '%s', got '%s'", expectObj, c.ObjPath())
}
err = c.Compile("someteam.example.com", "v1", "DatePrefixer")
err = c.Compile()
if err != nil {
t.Error(err)
}
if !RecentFileExists(expectObj) {
if !FileYoungerThan(expectObj, time.Second) {
t.Errorf("didn't find expected obj file %s", expectObj)
}
c.Cleanup()
if FileExists(expectObj) {
t.Errorf("obj file '%s' should be gone", expectObj)
}
c.SetGVK("builtin", "", "SecretGenerator")
expectObj = filepath.Join(
c.ObjRoot(),
srcRoot,
"builtin", "", "secretgenerator", "SecretGenerator.so")
if FileExists(expectObj) {
t.Errorf("obj file should not exist yet: %s", expectObj)
if expectObj != c.ObjPath() {
t.Errorf("Expected '%s', got '%s'", expectObj, c.ObjPath())
}
err = c.Compile("builtin", "", "SecretGenerator")
err = c.Compile()
if err != nil {
t.Error(err)
}
if !RecentFileExists(expectObj) {
if !FileYoungerThan(expectObj, time.Second) {
t.Errorf("didn't find expected obj file %s", expectObj)
}
err = os.RemoveAll(c.ObjRoot())
if err != nil {
t.Errorf(
"removing temp dir: %s %v", c.ObjRoot(), err)
}
c.Cleanup()
if FileExists(expectObj) {
t.Errorf("cleanup failed; still see: %s", expectObj)
t.Errorf("obj file '%s' should be gone", expectObj)
}
}

View File

@@ -0,0 +1,102 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package compiler
import (
"os"
"path/filepath"
"runtime"
"time"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/konfig"
)
func goBin() string {
return filepath.Join(runtime.GOROOT(), "bin", "go")
}
// DeterminePluginSrcRoot guesses where the user
// has her ${g}/${v}/$lower(${k})/${k}.go files.
func DeterminePluginSrcRoot(fSys filesys.FileSystem) (string, error) {
return konfig.FirstDirThatExistsElseError(
"source directory", fSys, []konfig.NotedFunc{
{
Note: "relative to unit test",
F: func() string {
return filepath.Clean(
filepath.Join(
os.Getenv("PWD"),
"..", "..",
konfig.RelPluginHome))
},
},
{
Note: "relative to unit test (internal pkg)",
F: func() string {
return filepath.Clean(
filepath.Join(
os.Getenv("PWD"),
"..", "..", "..", "..",
konfig.RelPluginHome))
},
},
{
Note: "relative to api package",
F: func() string {
return filepath.Clean(
filepath.Join(
os.Getenv("PWD"),
"..", "..", "..",
konfig.RelPluginHome))
},
},
{
Note: "old style $GOPATH",
F: func() string {
return filepath.Join(
os.Getenv("GOPATH"),
"src", konfig.DomainName,
konfig.ProgramName, konfig.RelPluginHome)
},
},
{
Note: "HOME with literal 'gopath'",
F: func() string {
return filepath.Join(
konfig.HomeDir(), "gopath",
"src", konfig.DomainName,
konfig.ProgramName, konfig.RelPluginHome)
},
},
{
Note: "home directory",
F: func() string {
return filepath.Join(
konfig.HomeDir(), konfig.DomainName,
konfig.ProgramName, konfig.RelPluginHome)
},
},
})
}
// FileYoungerThan returns true if the file age is <= the Duration argument.
func FileYoungerThan(path string, d time.Duration) bool {
fi, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
return false
}
}
return time.Since(fi.ModTime()) <= d
}
func FileExists(name string) bool {
if _, err := os.Stat(name); err != nil {
if os.IsNotExist(err) {
return false
}
}
return true
}

View File

@@ -0,0 +1,26 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package compiler
import (
"path/filepath"
"strings"
"testing"
"sigs.k8s.io/kustomize/api/filesys"
)
func TestDeterminePluginSrcRoot(t *testing.T) {
actual, err := DeterminePluginSrcRoot(filesys.MakeFsOnDisk())
if err != nil {
t.Error(err)
}
if !filepath.IsAbs(actual) {
t.Errorf("expected absolute path, but got '%s'", actual)
}
expectedSuffix := filepath.Join("sigs.k8s.io", "kustomize", "plugin")
if !strings.HasSuffix(actual, expectedSuffix) {
t.Errorf("expected suffix '%s' in '%s'", expectedSuffix, actual)
}
}

View File

@@ -266,8 +266,9 @@ func (p *ExecPlugin) UpdateResourceOptions(rm resmap.ResMap) (resmap.ResMap, err
}
r.SetAnnotations(annotations)
r.SetOptions(types.NewGenArgs(
&types.GeneratorArgs{Behavior: behavior},
&types.GeneratorOptions{DisableNameSuffixHash: !needsHash}))
&types.GeneratorArgs{
Behavior: behavior,
Options: &types.GeneratorOptions{DisableNameSuffixHash: !needsHash}}))
}
return rm, nil
}

View File

@@ -116,7 +116,9 @@ func makeConfigMapOptions(rf *resource.Factory, name, behavior string, disableHa
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{"name": name},
}, &types.GeneratorArgs{Behavior: behavior}, &types.GeneratorOptions{DisableNameSuffixHash: disableHash})
}, &types.GeneratorArgs{
Behavior: behavior,
Options: &types.GeneratorOptions{DisableNameSuffixHash: disableHash}})
}
func strptr(s string) *string {

View File

@@ -22,6 +22,7 @@ import (
"sigs.k8s.io/kustomize/api/types"
)
// Loader loads plugins using a file loader (a different loader).
type Loader struct {
pc *types.PluginConfig
rf *resmap.Factory
@@ -107,17 +108,35 @@ func isBuiltinPlugin(res *resource.Resource) bool {
}
func (l *Loader) loadAndConfigurePlugin(
ldr ifc.Loader, v ifc.Validator, res *resource.Resource) (c resmap.Configurable, err error) {
ldr ifc.Loader,
v ifc.Validator,
res *resource.Resource) (c resmap.Configurable, err error) {
if isBuiltinPlugin(res) {
// Instead of looking for and loading a .so file, just
// instantiate the plugin from a generated factory
// function (see "pluginator"). Being able to do this
// is what makes a plugin "builtin".
c, err = l.makeBuiltinPlugin(res.GetGvk())
} else if l.pc.PluginRestrictions == types.PluginRestrictionsNone {
c, err = l.loadPlugin(res.OrgId())
switch l.pc.BpLoadingOptions {
case types.BploLoadFromFileSys:
c, err = l.loadPlugin(res.OrgId())
case types.BploUseStaticallyLinked:
// Instead of looking for and loading a .so file,
// instantiate the plugin from a generated factory
// function (see "pluginator"). Being able to do this
// is what makes a plugin "builtin".
c, err = l.makeBuiltinPlugin(res.GetGvk())
default:
err = fmt.Errorf(
"unknown plugin loader behavior specified: %v",
l.pc.BpLoadingOptions)
}
} else {
err = types.NewErrOnlyBuiltinPluginsAllowed(res.OrgId().Kind)
switch l.pc.PluginRestrictions {
case types.PluginRestrictionsNone:
c, err = l.loadPlugin(res.OrgId())
case types.PluginRestrictionsBuiltinsOnly:
err = types.NewErrOnlyBuiltinPluginsAllowed(res.OrgId().Kind)
default:
err = fmt.Errorf(
"unknown plugin restriction specified: %v",
l.pc.PluginRestrictions)
}
}
if err != nil {
return nil, err

View File

@@ -15,6 +15,7 @@ import (
"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"
)
const (
@@ -58,22 +59,26 @@ func TestLoader(t *testing.T) {
if err != nil {
t.Fatal(err)
}
c, err := konfig.EnabledPluginConfig()
if err != nil {
t.Fatal(err)
}
pLdr := NewLoader(c, rmF)
if pLdr == nil {
t.Fatal("expect non-nil loader")
}
m, err := rmF.NewResMapFromBytes([]byte(
generatorConfigs, err := rmF.NewResMapFromBytes([]byte(
someServiceGenerator + "---\n" + secretGenerator))
if err != nil {
t.Fatal(err)
}
_, err = pLdr.LoadGenerators(
fLdr, valtest_test.MakeFakeValidator(), m)
if err != nil {
t.Fatal(err)
for _, behavior := range []types.BuiltinPluginLoadingOptions{
types.BploUseStaticallyLinked,
types.BploLoadFromFileSys} {
c, err := konfig.EnabledPluginConfig(behavior)
if err != nil {
t.Fatal(err)
}
pLdr := NewLoader(c, rmF)
if pLdr == nil {
t.Fatal("expect non-nil loader")
}
_, err = pLdr.LoadGenerators(
fLdr, valtest_test.MakeFakeValidator(), generatorConfigs)
if err != nil {
t.Fatal(err)
}
}
}

View File

@@ -74,14 +74,12 @@ var generatorConfigurators = map[builtinhelpers.BuiltinPluginType]func(
builtinhelpers.SecretGenerator: func(kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f gFactory) (
result []resmap.Generator, err error) {
var c struct {
types.GeneratorOptions
types.SecretArgs
}
if kt.kustomization.GeneratorOptions != nil {
c.GeneratorOptions = *kt.kustomization.GeneratorOptions
}
for _, args := range kt.kustomization.SecretGenerator {
c.SecretArgs = args
c.SecretArgs.Options = types.MergeGlobalOptionsIntoLocal(
c.SecretArgs.Options, kt.kustomization.GeneratorOptions)
p := f()
err := kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
@@ -95,14 +93,12 @@ var generatorConfigurators = map[builtinhelpers.BuiltinPluginType]func(
builtinhelpers.ConfigMapGenerator: func(kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f gFactory) (
result []resmap.Generator, err error) {
var c struct {
types.GeneratorOptions
types.ConfigMapArgs
}
if kt.kustomization.GeneratorOptions != nil {
c.GeneratorOptions = *kt.kustomization.GeneratorOptions
}
for _, args := range kt.kustomization.ConfigMapGenerator {
c.ConfigMapArgs = args
c.ConfigMapArgs.Options = types.MergeGlobalOptionsIntoLocal(
c.ConfigMapArgs.Options, kt.kustomization.GeneratorOptions)
p := f()
err := kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {

View File

@@ -7,7 +7,6 @@ import (
"encoding/base64"
"testing"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/api/resmap"
@@ -19,8 +18,7 @@ import (
// high level tests.
func TestMakeCustomizedResMap(t *testing.T) {
fSys := filesys.MakeFsInMemory()
th := kusttest_test.MakeHarnessWithFs(t, fSys)
th := kusttest_test.MakeHarness(t)
th.WriteK("/whatever", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
@@ -168,7 +166,7 @@ metadata:
}
actual, err := makeKustTargetWithRf(
t, fSys, "/whatever", resFactory).MakeCustomizedResMap()
t, th.GetFSys(), "/whatever", resFactory).MakeCustomizedResMap()
if err != nil {
t.Fatalf("unexpected Resources error %v", err)
}

View File

@@ -75,11 +75,8 @@ func (kf *KunstructuredFactoryImpl) FromMap(
// MakeConfigMap returns an instance of Kunstructured for ConfigMap
func (kf *KunstructuredFactoryImpl) MakeConfigMap(
kvLdr ifc.KvLoader,
options *types.GeneratorOptions,
args *types.ConfigMapArgs) (ifc.Kunstructured, error) {
o, err := configmapandsecret.NewFactory(
kvLdr, options).MakeConfigMap(args)
kvLdr ifc.KvLoader, args *types.ConfigMapArgs) (ifc.Kunstructured, error) {
o, err := configmapandsecret.NewFactory(kvLdr).MakeConfigMap(args)
if err != nil {
return nil, err
}
@@ -88,11 +85,8 @@ func (kf *KunstructuredFactoryImpl) MakeConfigMap(
// MakeSecret returns an instance of Kunstructured for Secret
func (kf *KunstructuredFactoryImpl) MakeSecret(
kvLdr ifc.KvLoader,
options *types.GeneratorOptions,
args *types.SecretArgs) (ifc.Kunstructured, error) {
o, err := configmapandsecret.NewFactory(
kvLdr, options).MakeSecret(args)
kvLdr ifc.KvLoader, args *types.SecretArgs) (ifc.Kunstructured, error) {
o, err := configmapandsecret.NewFactory(kvLdr).MakeSecret(args)
if err != nil {
return nil, err
}

View File

@@ -133,7 +133,7 @@ func (fs *UnstructAdapter) selectSubtree(path string) (map[string]interface{}, [
func (fs *UnstructAdapter) GetFieldValue(path string) (interface{}, error) {
content, fields, found, err := fs.selectSubtree(path)
if !found || err != nil {
return nil, noFieldError{Field: path}
return nil, NoFieldError{Field: path}
}
s, found, err := unstructured.NestedFieldNoCopy(
@@ -141,14 +141,14 @@ func (fs *UnstructAdapter) GetFieldValue(path string) (interface{}, error) {
if found || err != nil {
return s, err
}
return nil, noFieldError{Field: path}
return nil, NoFieldError{Field: path}
}
// GetString returns value at the given fieldpath.
func (fs *UnstructAdapter) GetString(path string) (string, error) {
content, fields, found, err := fs.selectSubtree(path)
if !found || err != nil {
return "", noFieldError{Field: path}
return "", NoFieldError{Field: path}
}
s, found, err := unstructured.NestedString(
@@ -156,14 +156,14 @@ func (fs *UnstructAdapter) GetString(path string) (string, error) {
if found || err != nil {
return s, err
}
return "", noFieldError{Field: path}
return "", NoFieldError{Field: path}
}
// GetStringSlice returns value at the given fieldpath.
func (fs *UnstructAdapter) GetStringSlice(path string) ([]string, error) {
content, fields, found, err := fs.selectSubtree(path)
if !found || err != nil {
return []string{}, noFieldError{Field: path}
return []string{}, NoFieldError{Field: path}
}
s, found, err := unstructured.NestedStringSlice(
@@ -171,14 +171,14 @@ func (fs *UnstructAdapter) GetStringSlice(path string) ([]string, error) {
if found || err != nil {
return s, err
}
return []string{}, noFieldError{Field: path}
return []string{}, NoFieldError{Field: path}
}
// GetBool returns value at the given fieldpath.
func (fs *UnstructAdapter) GetBool(path string) (bool, error) {
content, fields, found, err := fs.selectSubtree(path)
if !found || err != nil {
return false, noFieldError{Field: path}
return false, NoFieldError{Field: path}
}
s, found, err := unstructured.NestedBool(
@@ -186,7 +186,7 @@ func (fs *UnstructAdapter) GetBool(path string) (bool, error) {
if found || err != nil {
return s, err
}
return false, noFieldError{Field: path}
return false, NoFieldError{Field: path}
}
// GetFloat64 returns value at the given fieldpath.
@@ -201,14 +201,14 @@ func (fs *UnstructAdapter) GetFloat64(path string) (float64, error) {
if found || err != nil {
return s, err
}
return 0, noFieldError{Field: path}
return 0, NoFieldError{Field: path}
}
// GetInt64 returns value at the given fieldpath.
func (fs *UnstructAdapter) GetInt64(path string) (int64, error) {
content, fields, found, err := fs.selectSubtree(path)
if !found || err != nil {
return 0, noFieldError{Field: path}
return 0, NoFieldError{Field: path}
}
s, found, err := unstructured.NestedInt64(
@@ -216,14 +216,14 @@ func (fs *UnstructAdapter) GetInt64(path string) (int64, error) {
if found || err != nil {
return s, err
}
return 0, noFieldError{Field: path}
return 0, NoFieldError{Field: path}
}
// GetSlice returns value at the given fieldpath.
func (fs *UnstructAdapter) GetSlice(path string) ([]interface{}, error) {
content, fields, found, err := fs.selectSubtree(path)
if !found || err != nil {
return nil, noFieldError{Field: path}
return nil, NoFieldError{Field: path}
}
s, found, err := unstructured.NestedSlice(
@@ -231,14 +231,14 @@ func (fs *UnstructAdapter) GetSlice(path string) ([]interface{}, error) {
if found || err != nil {
return s, err
}
return nil, noFieldError{Field: path}
return nil, NoFieldError{Field: path}
}
// GetStringMap returns value at the given fieldpath.
func (fs *UnstructAdapter) GetStringMap(path string) (map[string]string, error) {
content, fields, found, err := fs.selectSubtree(path)
if !found || err != nil {
return nil, noFieldError{Field: path}
return nil, NoFieldError{Field: path}
}
s, found, err := unstructured.NestedStringMap(
@@ -246,14 +246,14 @@ func (fs *UnstructAdapter) GetStringMap(path string) (map[string]string, error)
if found || err != nil {
return s, err
}
return nil, noFieldError{Field: path}
return nil, NoFieldError{Field: path}
}
// GetMap returns value at the given fieldpath.
func (fs *UnstructAdapter) GetMap(path string) (map[string]interface{}, error) {
content, fields, found, err := fs.selectSubtree(path)
if !found || err != nil {
return nil, noFieldError{Field: path}
return nil, NoFieldError{Field: path}
}
s, found, err := unstructured.NestedMap(
@@ -261,7 +261,7 @@ func (fs *UnstructAdapter) GetMap(path string) (map[string]interface{}, error) {
if found || err != nil {
return s, err
}
return nil, noFieldError{Field: path}
return nil, NoFieldError{Field: path}
}
func (fs *UnstructAdapter) MatchesLabelSelector(selector string) (bool, error) {
@@ -340,11 +340,11 @@ func toSchemaGvk(x resid.Gvk) schema.GroupVersionKind {
}
}
// noFieldError is returned when a field is expected, but missing.
type noFieldError struct {
// NoFieldError is returned when a field is expected, but missing.
type NoFieldError struct {
Field string
}
func (e noFieldError) Error() string {
func (e NoFieldError) Error() string {
return fmt.Sprintf("no field named '%s'", e.Field)
}

View File

@@ -345,5 +345,24 @@ nameReference:
kind: PersistentVolumeClaim
- path: spec/volumeClaimTemplates/spec/storageClassName
kind: StatefulSet
- kind: PriorityClass
version: v1
group: scheduling.k8s.io
fieldSpecs:
- path: spec/priorityClassName
kind: Pod
- path: spec/template/spec/priorityClassName
kind: StatefulSet
- path: spec/template/spec/priorityClassName
kind: Deployment
- path: spec/template/spec/priorityClassName
kind: ReplicationController
- path: spec/jobTemplate/spec/template/spec/priorityClassName
kind: CronJob
- path: spec/template/spec/priorityClassName
kind: Job
- path: spec/template/spec/priorityClassName
kind: DaemonSet
`
)

View File

@@ -35,37 +35,46 @@ const (
// Domain from which kustomize code is imported, for locating
// plugin source code under $GOPATH when GOPATH is defined.
DomainName = "sigs.k8s.io"
// Injected into plugin paths when plugins are disabled.
// Provides a clue in flows that shouldn't happen.
NoPluginHomeSentinal = "/No/non-builtin/plugins!"
)
func EnabledPluginConfig() (*types.PluginConfig, error) {
func EnabledPluginConfig(b types.BuiltinPluginLoadingOptions) (*types.PluginConfig, error) {
dir, err := DefaultAbsPluginHome(filesys.MakeFsOnDisk())
if err != nil {
return nil, err
}
return MakePluginConfig(types.PluginRestrictionsNone, dir), nil
return MakePluginConfig(types.PluginRestrictionsNone, b, dir), nil
}
func DisabledPluginConfig() *types.PluginConfig {
return MakePluginConfig(
types.PluginRestrictionsBuiltinsOnly, NoPluginHomeSentinal)
types.PluginRestrictionsBuiltinsOnly,
types.BploUseStaticallyLinked,
NoPluginHomeSentinal)
}
func MakePluginConfig(
pr types.PluginRestrictions, home string) *types.PluginConfig {
pr types.PluginRestrictions,
b types.BuiltinPluginLoadingOptions,
home string) *types.PluginConfig {
return &types.PluginConfig{
PluginRestrictions: pr,
AbsPluginHome: home,
BpLoadingOptions: b,
}
}
// Use an obviously erroneous path, in case it's accidentally used.
const NoPluginHomeSentinal = "/no/non-builtin/plugins!"
type NotedFunc struct {
Note string
F func() string
}
// DefaultAbsPluginHome returns the absolute path in the given file
// system to first directory that looks like a good candidate for
// the home of kustomize plugins.
func DefaultAbsPluginHome(fSys filesys.FileSystem) (string, error) {
return FirstDirThatExistsElseError(
"plugin home directory", fSys, []NotedFunc{

View File

@@ -143,7 +143,8 @@ apiVersion: builtin
kind: ConfigMapGenerator
metadata:
name: my-config
disableNameSuffixHash: true
options:
disableNameSuffixHash: true
literals:
- MY_ENV=foo
`)

View File

@@ -12,10 +12,12 @@ import (
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func findSecret(m resmap.ResMap) *resource.Resource {
func findSecret(m resmap.ResMap, prefix string) *resource.Resource {
for _, r := range m.Resources() {
if r.OrgId().Kind == "Secret" {
return r
if prefix == "" || strings.HasPrefix(r.GetName(), prefix) {
return r
}
}
}
return nil
@@ -77,7 +79,7 @@ metadata:
m := th.Run("/whatever", th.MakeDefaultOptions())
secret := findSecret(m)
secret := findSecret(m, "")
if secret == nil {
t.Errorf("Expected to find a Secret")
}
@@ -90,7 +92,7 @@ metadata:
"disableNameSuffixHash: false",
"disableNameSuffixHash: true", -1))
m = th.Run("/whatever", th.MakeDefaultOptions())
secret = findSecret(m)
secret = findSecret(m, "")
if secret == nil {
t.Errorf("Expected to find a Secret")
}
@@ -98,3 +100,47 @@ metadata:
t.Errorf("unexpected secret resource name: %s", secret.GetName())
}
}
func TestDisableNameSuffixHashPerObject(t *testing.T) {
th := kusttest_test.MakeHarness(t)
const kustomizationContent = `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
generatorOptions:
disableNameSuffixHash: false
secretGenerator:
- name: nohash
options:
disableNameSuffixHash: true
literals:
- DB_USERNAME=admin
- DB_PASSWORD=somepw
type: Opaque
- name: yeshash
options:
disableNameSuffixHash: false
literals:
- DB_USERNAME=admin
- DB_PASSWORD=somepw
type: Opaque
`
th.WriteK("/whatever", kustomizationContent)
m := th.Run("/whatever", th.MakeDefaultOptions())
secret := findSecret(m, "nohash")
if secret == nil {
t.Errorf("Expected to find a Secret")
}
if secret.GetName() != "nohash" {
t.Errorf("unexpected secret resource name: %s", secret.GetName())
}
secret = findSecret(m, "yeshash")
if secret == nil {
t.Errorf("Expected to find a Secret")
}
if secret.GetName() != "yeshash-mcgcmdcm69" {
t.Errorf("unexpected secret resource name: %s", secret.GetName())
}
}

View File

@@ -66,12 +66,10 @@ func (rmF *Factory) NewResMapFromBytes(b []byte) (ResMap, error) {
// NewResMapFromConfigMapArgs returns a Resource slice given
// a configmap metadata slice from kustomization file.
func (rmF *Factory) NewResMapFromConfigMapArgs(
kvLdr ifc.KvLoader,
options *types.GeneratorOptions,
argList []types.ConfigMapArgs) (ResMap, error) {
kvLdr ifc.KvLoader, argList []types.ConfigMapArgs) (ResMap, error) {
var resources []*resource.Resource
for _, args := range argList {
res, err := rmF.resF.MakeConfigMap(kvLdr, options, &args)
res, err := rmF.resF.MakeConfigMap(kvLdr, &args)
if err != nil {
return nil, errors.Wrap(err, "NewResMapFromConfigMapArgs")
}
@@ -81,10 +79,8 @@ func (rmF *Factory) NewResMapFromConfigMapArgs(
}
func (rmF *Factory) FromConfigMapArgs(
kvLdr ifc.KvLoader,
options *types.GeneratorOptions,
args types.ConfigMapArgs) (ResMap, error) {
res, err := rmF.resF.MakeConfigMap(kvLdr, options, &args)
kvLdr ifc.KvLoader, args types.ConfigMapArgs) (ResMap, error) {
res, err := rmF.resF.MakeConfigMap(kvLdr, &args)
if err != nil {
return nil, err
}
@@ -94,12 +90,10 @@ func (rmF *Factory) FromConfigMapArgs(
// NewResMapFromSecretArgs takes a SecretArgs slice, generates
// secrets from each entry, and accumulates them in a ResMap.
func (rmF *Factory) NewResMapFromSecretArgs(
kvLdr ifc.KvLoader,
options *types.GeneratorOptions,
argsList []types.SecretArgs) (ResMap, error) {
kvLdr ifc.KvLoader, argsList []types.SecretArgs) (ResMap, error) {
var resources []*resource.Resource
for _, args := range argsList {
res, err := rmF.resF.MakeSecret(kvLdr, options, &args)
res, err := rmF.resF.MakeSecret(kvLdr, &args)
if err != nil {
return nil, errors.Wrap(err, "NewResMapFromSecretArgs")
}
@@ -109,10 +103,8 @@ func (rmF *Factory) NewResMapFromSecretArgs(
}
func (rmF *Factory) FromSecretArgs(
kvLdr ifc.KvLoader,
options *types.GeneratorOptions,
args types.SecretArgs) (ResMap, error) {
res, err := rmF.resF.MakeSecret(kvLdr, options, &args)
kvLdr ifc.KvLoader, args types.SecretArgs) (ResMap, error) {
res, err := rmF.resF.MakeSecret(kvLdr, &args)
if err != nil {
return nil, err
}

View File

@@ -227,7 +227,7 @@ BAR=baz
t.Fatalf("error adding file '%s': %v\n", tc.filepath, fErr)
}
}
r, err := rmF.NewResMapFromConfigMapArgs(kvLdr, nil, tc.input)
r, err := rmF.NewResMapFromConfigMapArgs(kvLdr, tc.input)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
@@ -258,7 +258,7 @@ func TestNewResMapFromSecretArgs(t *testing.T) {
actual, err := rmF.NewResMapFromSecretArgs(
kv.NewLoader(
loader.NewFileLoaderAtRoot(fSys),
valtest_test.MakeFakeValidator()), nil, secrets)
valtest_test.MakeFakeValidator()), secrets)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}

View File

@@ -826,7 +826,7 @@ func makeMap1() ResMap {
},
}, &types.GeneratorArgs{
Behavior: "create",
}, nil))
}))
}
func makeMap2(b types.GenerationBehavior) ResMap {
@@ -844,7 +844,7 @@ func makeMap2(b types.GenerationBehavior) ResMap {
},
}, &types.GeneratorArgs{
Behavior: b.String(),
}, nil))
}))
}
func TestAbsorbAll(t *testing.T) {
@@ -864,7 +864,7 @@ func TestAbsorbAll(t *testing.T) {
},
}, &types.GeneratorArgs{
Behavior: "create",
}, nil))
}))
w := makeMap1()
if err := w.AbsorbAll(makeMap2(types.BehaviorMerge)); err != nil {
t.Fatalf("unexpected error: %v", err)

View File

@@ -50,8 +50,8 @@ func (rf *Factory) FromMapWithNamespaceAndName(ns string, n string, m map[string
// FromMapAndOption returns a new instance of Resource with given options.
func (rf *Factory) FromMapAndOption(
m map[string]interface{}, args *types.GeneratorArgs, option *types.GeneratorOptions) *Resource {
return rf.makeOne(rf.kf.FromMap(m), types.NewGenArgs(args, option))
m map[string]interface{}, args *types.GeneratorArgs) *Resource {
return rf.makeOne(rf.kf.FromMap(m), types.NewGenArgs(args))
}
// FromKunstructured returns a new instance of Resource.
@@ -66,7 +66,7 @@ func (rf *Factory) makeOne(
log.Fatal("unstruct ifc must not be null")
}
if o == nil {
o = types.NewGenArgs(nil, nil)
o = types.NewGenArgs(nil)
}
r := &Resource{
Kunstructured: u,
@@ -147,33 +147,19 @@ func (rf *Factory) SliceFromBytes(in []byte) ([]*Resource, error) {
}
// MakeConfigMap makes an instance of Resource for ConfigMap
func (rf *Factory) MakeConfigMap(
kvLdr ifc.KvLoader,
options *types.GeneratorOptions,
args *types.ConfigMapArgs) (*Resource, error) {
u, err := rf.kf.MakeConfigMap(kvLdr, options, args)
func (rf *Factory) MakeConfigMap(kvLdr ifc.KvLoader, args *types.ConfigMapArgs) (*Resource, error) {
u, err := rf.kf.MakeConfigMap(kvLdr, args)
if err != nil {
return nil, err
}
return rf.makeOne(
u,
types.NewGenArgs(
&types.GeneratorArgs{Behavior: args.Behavior},
options)), nil
return rf.makeOne(u, types.NewGenArgs(&args.GeneratorArgs)), nil
}
// MakeSecret makes an instance of Resource for Secret
func (rf *Factory) MakeSecret(
kvLdr ifc.KvLoader,
options *types.GeneratorOptions,
args *types.SecretArgs) (*Resource, error) {
u, err := rf.kf.MakeSecret(kvLdr, options, args)
func (rf *Factory) MakeSecret(kvLdr ifc.KvLoader, args *types.SecretArgs) (*Resource, error) {
u, err := rf.kf.MakeSecret(kvLdr, args)
if err != nil {
return nil, err
}
return rf.makeOne(
u,
types.NewGenArgs(
&types.GeneratorArgs{Behavior: args.Behavior},
options)), nil
return rf.makeOne(u, types.NewGenArgs(&args.GeneratorArgs)), nil
}

View File

@@ -70,7 +70,7 @@ func (th Harness) MakeOptionsPluginsDisabled() krusty.Options {
// Enables use of non-builtin plugins.
func (th Harness) MakeOptionsPluginsEnabled() krusty.Options {
c, err := konfig.EnabledPluginConfig()
c, err := konfig.EnabledPluginConfig(types.BploLoadFromFileSys)
if err != nil {
if strings.Contains(err.Error(), "unable to find plugin root") {
th.t.Log(

View File

@@ -4,6 +4,9 @@
package kusttest_test
import (
"bytes"
"fmt"
"strconv"
"testing"
"sigs.k8s.io/kustomize/api/filesys"
@@ -16,36 +19,50 @@ import (
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// HarnessEnhanced manages a full plugin environment for tests.
type HarnessEnhanced struct {
// An instance of *testing.T, and a filesystem (likely in-memory)
// for loading test data - plugin config, resources to transform, etc.
Harness
// plugintestEnv holds the plugin compiler and data needed to
// create compilation sub-processes.
pte *pluginTestEnv
rf *resmap.Factory
// rf creates Resources from byte streams.
rf *resmap.Factory
// A file loader using the Harness.fSys to read test data.
ldr ifc.Loader
pl *pLdr.Loader
// A plugin loader that loads plugins from a (real) file system.
pl *pLdr.Loader
}
func MakeEnhancedHarness(t *testing.T) *HarnessEnhanced {
pte := newPluginTestEnv(t).set()
pc, err := konfig.EnabledPluginConfig()
pc, err := konfig.EnabledPluginConfig(types.BploLoadFromFileSys)
if err != nil {
t.Fatal(err)
}
fSys := filesys.MakeFsInMemory()
rf := resmap.NewFactory(
resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl()),
transformer.NewFactoryImpl())
result := &HarnessEnhanced{
Harness: Harness{t: t, fSys: fSys},
Harness: MakeHarness(t),
pte: pte,
rf: rf,
pl: pLdr.NewLoader(pc, rf)}
// Point the file loader to the root ('/') of the in-memory file system.
result.ResetLoaderRoot(filesys.Separator)
return result
@@ -55,21 +72,23 @@ func (th *HarnessEnhanced) Reset() {
th.pte.reset()
}
func (th *HarnessEnhanced) PrepBuiltin(k string) *HarnessEnhanced {
return th.BuildGoPlugin(konfig.BuiltinPluginPackage, "", k)
}
func (th *HarnessEnhanced) BuildGoPlugin(g, v, k string) *HarnessEnhanced {
th.pte.buildGoPlugin(g, v, k)
th.pte.prepareGoPlugin(g, v, k)
return th
}
func (th *HarnessEnhanced) PrepExecPlugin(g, v, k string) *HarnessEnhanced {
th.pte.prepExecPlugin(g, v, k)
return th
}
func (th *HarnessEnhanced) PrepBuiltin(k string) *HarnessEnhanced {
th.pte.buildGoPlugin(konfig.BuiltinPluginPackage, "", k)
th.pte.prepareExecPlugin(g, v, k)
return th
}
// ResetLoaderRoot interprets its argument as an absolute directory path.
// It creates the directory, and creates the harness's file loader
// rooted in that directory.
func (th *HarnessEnhanced) ResetLoaderRoot(root string) {
if err := th.fSys.Mkdir(root); err != nil {
th.t.Fatal(err)
@@ -109,12 +128,68 @@ func (th *HarnessEnhanced) LoadAndRunTransformer(
return resMap
}
func (th *HarnessEnhanced) RunTransformerAndCheckResult(
config, input, expected string) {
for _, b := range []bool{true, false} {
th.t.Run(fmt.Sprintf("yaml-%v", b), func(t *testing.T) {
c, err := toggleYamlSupportField(config, b)
if err != nil {
th.t.Fatalf("Err: %v", err)
}
resMap, err := th.RunTransformer(c, input)
if err != nil {
th.t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(resMap, expected)
})
}
}
func toggleYamlSupportField(config string, yamlSupport bool) (string, error) {
var out bytes.Buffer
rw := kio.ByteReadWriter{
Reader: bytes.NewBufferString(config),
Writer: &out,
}
err := kio.Pipeline{
Inputs: []kio.Reader{&rw},
Filters: []kio.Filter{
kio.FilterAll(yaml.FilterFunc(
func(node *yaml.RNode) (*yaml.RNode, error) {
return node.Pipe(yaml.FieldSetter{
Name: "yamlSupport",
StringValue: strconv.FormatBool(yamlSupport),
})
}),
),
},
Outputs: []kio.Writer{&rw},
}.Execute()
return out.String(), err
}
func (th *HarnessEnhanced) ErrorFromLoadAndRunTransformer(
config, input string) error {
_, err := th.RunTransformer(config, input)
return err
}
type AssertFunc func(t *testing.T, err error)
func (th *HarnessEnhanced) RunTransformerAndCheckError(
config, input string, assertFn AssertFunc) {
for _, b := range []bool{true, false} {
th.t.Run(fmt.Sprintf("yaml-%v", b), func(t *testing.T) {
c, err := toggleYamlSupportField(config, b)
if err != nil {
th.t.Fatalf("Err: %v", err)
}
_, err = th.RunTransformer(c, input)
assertFn(t, err)
})
}
}
func (th *HarnessEnhanced) RunTransformer(
config, input string) (resmap.ResMap, error) {
resMap, err := th.rf.NewResMapFromBytes([]byte(input))

View File

@@ -4,11 +4,7 @@
package kusttest_test
import (
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"sigs.k8s.io/kustomize/api/filesys"
@@ -16,17 +12,14 @@ import (
"sigs.k8s.io/kustomize/api/konfig"
)
// pluginTestEnv manages plugins for tests.
// It manages a Go plugin compiler,
// makes and removes a temporary working directory,
// and sets/resets shell env vars as needed.
// pluginTestEnv manages compiling plugins for tests.
// It manages a Go plugin compiler, and sets/resets shell env vars as needed.
type pluginTestEnv struct {
t *testing.T
compiler *compiler.Compiler
srcRoot string
workDir string
oldXdg string
wasSet bool
t *testing.T
compiler *compiler.Compiler
pluginRoot string
oldXdg string
wasSet bool
}
// newPluginTestEnv returns a new instance of pluginTestEnv.
@@ -39,76 +32,44 @@ func newPluginTestEnv(t *testing.T) *pluginTestEnv {
// plugin code - this FileSystem has nothing to do with
// the FileSystem used for loading config yaml in the tests.
func (x *pluginTestEnv) set() *pluginTestEnv {
x.createWorkDir()
var err error
x.srcRoot, err = compiler.DeterminePluginSrcRoot(filesys.MakeFsOnDisk())
x.pluginRoot, err = compiler.DeterminePluginSrcRoot(filesys.MakeFsOnDisk())
if err != nil {
x.t.Error(err)
}
x.compiler = compiler.NewCompiler(x.srcRoot, x.workDir)
x.compiler = compiler.NewCompiler(x.pluginRoot)
x.setEnv()
return x
}
// reset restores the environment to pre-test state.
func (x *pluginTestEnv) reset() {
// Calling Cleanup forces recompilation in a test file with multiple
// calls to MakeEnhancedHarness - so leaving it out. Your .gitignore
// should ignore .so files anyway.
// x.compiler.Cleanup()
x.resetEnv()
x.removeWorkDir()
}
// buildGoPlugin compiles a Go plugin, leaving the newly
// created object code in the right place - a temporary
// working directory pointed to by KustomizePluginHomeEnv.
// This avoids overwriting anything the user/developer has
// otherwise created.
func (x *pluginTestEnv) buildGoPlugin(g, v, k string) {
err := x.compiler.Compile(g, v, k)
// prepareGoPlugin compiles a Go plugin, leaving the newly
// created object code alongside the src code.
func (x *pluginTestEnv) prepareGoPlugin(g, v, k string) {
x.compiler.SetGVK(g, v, k)
err := x.compiler.Compile()
if err != nil {
x.t.Errorf("compile failed: %v", err)
}
}
// prepExecPlugin copies an exec plugin from it's
// home in the discovered srcRoot to the same temp
// directory where Go plugin object code is placed.
// Kustomize (and its tests) expect to find plugins
// (Go or Exec) in the same spot, and since the test
// framework is compiling Go plugins to a temp dir,
// it must likewise copy Exec plugins to that same
// temp dir.
func (x *pluginTestEnv) prepExecPlugin(g, v, k string) {
lowK := strings.ToLower(k)
src := filepath.Join(x.srcRoot, g, v, lowK, k)
tmp := filepath.Join(x.workDir, g, v, lowK, k)
if err := os.MkdirAll(filepath.Dir(tmp), 0755); err != nil {
x.t.Errorf("error making directory: %s", filepath.Dir(tmp))
}
cmd := exec.Command("cp", src, tmp)
cmd.Env = os.Environ()
if err := cmd.Run(); err != nil {
x.t.Errorf("error copying %s to %s: %v", src, tmp, err)
}
}
func (x *pluginTestEnv) createWorkDir() {
var err error
x.workDir, err = ioutil.TempDir("", "kustomize-plugin-tests")
if err != nil {
x.t.Errorf("failed to make work dir: %v", err)
}
}
func (x *pluginTestEnv) removeWorkDir() {
err := os.RemoveAll(x.workDir)
if err != nil {
x.t.Errorf(
"removing work dir: %s %v", x.workDir, err)
}
func (x *pluginTestEnv) prepareExecPlugin(_, _, _ string) {
// Do nothing. At one point this method
// copied the exec plugin directory to a temp dir
// and ran it from there. Left as a hook.
}
func (x *pluginTestEnv) setEnv() {
x.oldXdg, x.wasSet = os.LookupEnv(konfig.KustomizePluginHomeEnv)
os.Setenv(konfig.KustomizePluginHomeEnv, x.workDir)
os.Setenv(konfig.KustomizePluginHomeEnv, x.pluginRoot)
}
func (x *pluginTestEnv) resetEnv() {

View File

@@ -8,18 +8,14 @@ import (
"strings"
)
// GenArgs contains both GeneratorArgs and GeneratorOptions.
// GenArgs is a facade over GeneratorArgs, exposing a few readonly properties.
type GenArgs struct {
args *GeneratorArgs
opts *GeneratorOptions
}
// NewGenArgs returns a new object of GenArgs
func NewGenArgs(args *GeneratorArgs, opts *GeneratorOptions) *GenArgs {
return &GenArgs{
args: args,
opts: opts,
}
// NewGenArgs returns a new instance of GenArgs.
func NewGenArgs(args *GeneratorArgs) *GenArgs {
return &GenArgs{args: args}
}
func (g *GenArgs) String() string {
@@ -38,7 +34,7 @@ func (g *GenArgs) String() string {
// content hash should be appended to the name of the resource.
func (g *GenArgs) ShouldAddHashSuffixToName() bool {
return g.args != nil &&
(g.opts == nil || !g.opts.DisableNameSuffixHash)
(g.args.Options == nil || !g.args.Options.DisableNameSuffixHash)
}
// Behavior returns Behavior field of GeneratorArgs

View File

@@ -24,8 +24,10 @@ func TestGenArgs_String(t *testing.T) {
},
{
ga: NewGenArgs(
&GeneratorArgs{Behavior: "merge"},
&GeneratorOptions{DisableNameSuffixHash: false}),
&GeneratorArgs{
Behavior: "merge",
Options: &GeneratorOptions{DisableNameSuffixHash: false},
}),
expected: "{nsfx:true,beh:merge}",
},
}

View File

@@ -22,6 +22,6 @@ type GeneratorArgs struct {
// KvPairSources for the generator.
KvPairSources `json:",inline,omitempty" yaml:",inline,omitempty"`
// GeneratorOptions modify this generator
GeneratorOptions *GeneratorOptions `json:"generatorOptions,omitempty" yaml:"generatorOptions,omitempty"`
// Local overrides to global generatorOptions field.
Options *GeneratorOptions `json:"options,omitempty" yaml:"options,omitempty"`
}

View File

@@ -16,3 +16,55 @@ type GeneratorOptions struct {
// resource contents.
DisableNameSuffixHash bool `json:"disableNameSuffixHash,omitempty" yaml:"disableNameSuffixHash,omitempty"`
}
// MergeGlobalOptionsIntoLocal merges two instances of GeneratorOptions.
// Values in the first 'local' argument cannot be overridden by the second
// 'global' argument, except in the case of booleans.
//
// With booleans, there's no way to distinguish an 'intentional'
// false from 'default' false. So the rule is, if the global value
// of the value of a boolean is true, i.e. disable, it trumps the
// local value. If the global value is false, then the local value is
// respected. Bottom line: a local false cannot override a global true.
//
// boolean fields are always a bad idea; should always use enums instead.
func MergeGlobalOptionsIntoLocal(
localOpts *GeneratorOptions,
globalOpts *GeneratorOptions) *GeneratorOptions {
if globalOpts == nil {
return localOpts
}
if localOpts == nil {
localOpts = &GeneratorOptions{}
}
overrideMap(&localOpts.Labels, globalOpts.Labels)
overrideMap(&localOpts.Annotations, globalOpts.Annotations)
if globalOpts.DisableNameSuffixHash {
localOpts.DisableNameSuffixHash = true
}
return localOpts
}
func overrideMap(localMap *map[string]string, globalMap map[string]string) {
if *localMap == nil {
if globalMap != nil {
*localMap = CopyMap(globalMap)
}
return
}
for k, v := range globalMap {
_, ok := (*localMap)[k]
if !ok {
(*localMap)[k] = v
}
}
}
// CopyMap copies a map.
func CopyMap(in map[string]string) map[string]string {
out := make(map[string]string)
for k, v := range in {
out[k] = v
}
return out
}

View File

@@ -0,0 +1,125 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types_test
import (
"reflect"
"testing"
. "sigs.k8s.io/kustomize/api/types"
)
func TestMergeGlobalOptionsIntoLocal(t *testing.T) {
tests := []struct {
name string
local *GeneratorOptions
global *GeneratorOptions
expected *GeneratorOptions
}{
{
name: "everything nil",
local: nil,
global: nil,
expected: nil,
},
{
name: "nil global",
local: &GeneratorOptions{
Labels: map[string]string{"pet": "dog"},
Annotations: map[string]string{"fruit": "apple"},
},
global: nil,
expected: &GeneratorOptions{
Labels: map[string]string{"pet": "dog"},
Annotations: map[string]string{"fruit": "apple"},
DisableNameSuffixHash: false,
},
},
{
name: "nil local",
local: nil,
global: &GeneratorOptions{
Labels: map[string]string{"pet": "dog"},
Annotations: map[string]string{"fruit": "apple"},
},
expected: &GeneratorOptions{
Labels: map[string]string{"pet": "dog"},
Annotations: map[string]string{"fruit": "apple"},
DisableNameSuffixHash: false,
},
},
{
name: "global doesn't damage local",
local: &GeneratorOptions{
Labels: map[string]string{"pet": "dog"},
Annotations: map[string]string{
"fruit": "apple"},
},
global: &GeneratorOptions{
Labels: map[string]string{
"pet": "cat",
"simpson": "homer",
},
Annotations: map[string]string{
"fruit": "peach",
"tesla": "Y",
},
},
expected: &GeneratorOptions{
Labels: map[string]string{
"pet": "dog",
"simpson": "homer",
},
Annotations: map[string]string{
"fruit": "apple",
"tesla": "Y",
},
DisableNameSuffixHash: false,
},
},
{
name: "global disable trumps local",
local: &GeneratorOptions{
DisableNameSuffixHash: false,
},
global: &GeneratorOptions{
DisableNameSuffixHash: true,
},
expected: &GeneratorOptions{
DisableNameSuffixHash: true,
},
},
{
name: "local disable works",
local: &GeneratorOptions{
DisableNameSuffixHash: true,
},
global: &GeneratorOptions{
DisableNameSuffixHash: false,
},
expected: &GeneratorOptions{
DisableNameSuffixHash: true,
},
},
{
name: "everyone wants disable",
local: &GeneratorOptions{
DisableNameSuffixHash: true,
},
global: &GeneratorOptions{
DisableNameSuffixHash: true,
},
expected: &GeneratorOptions{
DisableNameSuffixHash: true,
},
},
}
for _, tc := range tests {
actual := MergeGlobalOptionsIntoLocal(tc.local, tc.global)
if !reflect.DeepEqual(tc.expected, actual) {
t.Fatalf("%s annotations: Expected '%v', got '%v'",
tc.name, tc.expected, *actual)
}
}
}

View File

@@ -10,22 +10,23 @@ type PluginConfig struct {
// containing the fields 'apiVersion' and 'kind', e.g.
// apiVersion: apps/v1
// kind: Deployment
// When kustomize reads a plugin configuration file (as as result
// of seeing the file name in the 'generators:' or 'transformers:'
// field in a kustomization file), it must then locate the plugin
// code (Go plugin or exec plugin).
// Every kustomize plugin (its code, its tests, supporting data
// kustomize reads plugin configuration data from a file path
// specified in the 'generators:' or 'transformers:' field of a
// kustomization file. kustomize must then use this data to both
// locate the plugin and configure it.
// Every kustomize plugin (its code, its tests, its supporting data
// files, etc.) must be housed in its own directory at
// ${AbsPluginHome}/${pluginApiVersion}/LOWERCASE(${pluginKind})
// where
// - ${AbsPluginHome} is an absolute path, defined below.
// - ${pluginApiVersion} is taken from the plugin config file.
// - ${pluginKind} is taken from the plugin config file.
// The value of AbsPluginHome can be any absolute path, but might
// default to $XDG_CONFIG_HOME/kustomize/plugin.
// The value of AbsPluginHome can be any absolute path.
AbsPluginHome string
// PluginRestrictions defines the plugin restriction state.
// See type for more information.
// PluginRestrictions distinguishes plugin restrictions.
PluginRestrictions PluginRestrictions
// BpLoadingOptions distinguishes builtin plugin behaviors.
BpLoadingOptions BuiltinPluginLoadingOptions
}

View File

@@ -26,3 +26,18 @@ const (
// No restrictions, do whatever you want.
PluginRestrictionsNone
)
// BuiltinPluginLoadingOptions distinguish ways in which builtin plugins are used.
//go:generate stringer -type=BuiltinPluginLoadingOptions
type BuiltinPluginLoadingOptions int
const (
BploUndefined BuiltinPluginLoadingOptions = iota
// Desired in production use for performance.
BploUseStaticallyLinked
// Desired in testing and development cycles where it's undesirable
// to generate static code.
BploLoadFromFileSys
)

View File

@@ -18,6 +18,6 @@ List setters for Resources.
Show setters:
$ config set DIR/
$ config list-setters DIR/
NAME DESCRIPTION VALUE TYPE COUNT SETBY
name-prefix '' PREFIX string 2

View File

@@ -28,8 +28,8 @@ the configuration as comments.
Optional. The value to set on the field.
To print the possible setters for the Resources in a directory, run `set` on
a directory -- e.g. `kustomize config set DIR/`.
To print the possible setters for the Resources in a directory, run
`list-setters` on a directory -- e.g. `kustomize config list-setters DIR/`.
#### Tips
@@ -58,7 +58,7 @@ To create a custom setter for a field see: `kustomize help config create-setter`
List setters: Show the possible setters
$ config set DIR/
$ config list-setters DIR/
NAME DESCRIPTION VALUE TYPE COUNT SETBY
name-prefix '' PREFIX string 2
@@ -69,7 +69,7 @@ To create a custom setter for a field see: `kustomize help config create-setter`
List setters: Show the new values
$ config set DIR/
$ config list-setters DIR/
NAME DESCRIPTION VALUE TYPE COUNT SETBY
name-prefix 'test environment' test string 2 dev

View File

@@ -29,6 +29,8 @@ func NewListSettersRunner(parent string) *ListSettersRunner {
PreRunE: r.preRunE,
RunE: r.runE,
}
c.Flags().BoolVar(&r.Markdown, "markdown", false,
"output as github markdown")
fixDocs(parent, c)
r.Command = c
return r
@@ -39,9 +41,10 @@ func ListSettersCommand(parent string) *cobra.Command {
}
type ListSettersRunner struct {
Command *cobra.Command
Lookup setters.LookupSetters
List setters2.List
Command *cobra.Command
Lookup setters.LookupSetters
List setters2.List
Markdown bool
}
func (r *ListSettersRunner) preRunE(c *cobra.Command, args []string) error {
@@ -64,7 +67,7 @@ func (r *ListSettersRunner) runE(c *cobra.Command, args []string) error {
if err := r.List.List(path, args[0]); err != nil {
return err
}
table := newTable(c.OutOrStdout())
table := newTable(c.OutOrStdout(), r.Markdown)
table.SetHeader([]string{"NAME", "VALUE", "SET BY", "DESCRIPTION", "COUNT"})
for i := range r.List.Setters {
s := r.List.Setters[i]
@@ -92,13 +95,19 @@ func (r *ListSettersRunner) runE(c *cobra.Command, args []string) error {
return handleError(c, lookup(r.Lookup, c, args))
}
func newTable(o io.Writer) *tablewriter.Table {
func newTable(o io.Writer, m bool) *tablewriter.Table {
table := tablewriter.NewWriter(o)
table.SetRowLine(false)
table.SetBorder(false)
table.SetHeaderLine(false)
table.SetColumnSeparator(" ")
table.SetCenterSeparator(" ")
if m {
// markdown format
table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
table.SetCenterSeparator("|")
} else {
table.SetBorder(false)
table.SetHeaderLine(false)
table.SetColumnSeparator(" ")
table.SetCenterSeparator(" ")
}
table.SetAlignment(tablewriter.ALIGN_LEFT)
return table
}

View File

@@ -11,6 +11,7 @@ import (
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/kio/filters"
"sigs.k8s.io/kustomize/kyaml/runfn"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
@@ -50,10 +51,16 @@ func GetRunFnRunner(name string) *RunFnRunner {
&r.StarName, "star-name", "", "name of starlark program.")
r.Command.Flags().MarkHidden("star-name")
r.Command.Flags().StringVar(
&r.ResultsDir, "results-dir", "", "write function results to this dir")
r.Command.Flags().BoolVar(
&r.Network, "network", false, "enable network access for functions that declare it")
r.Command.Flags().StringVar(
&r.NetworkName, "network-name", "bridge", "the docker network to run the container in")
r.Command.Flags().StringArrayVar(
&r.Mounts, "mount", []string{},
"a list of storage options read from the filesystem")
return r
}
@@ -73,8 +80,10 @@ type RunFnRunner struct {
StarPath string
StarName string
RunFns runfn.RunFns
ResultsDir string
Network bool
NetworkName string
Mounts []string
}
func (r *RunFnRunner) runE(c *cobra.Command, args []string) error {
@@ -199,9 +208,17 @@ data: {}
return []*yaml.RNode{rc}, nil
}
func toStorageMounts(mounts []string) []filters.StorageMount {
var sms []filters.StorageMount
for _, mount := range mounts {
sms = append(sms, filters.StringToStorageMount(mount))
}
return sms
}
func (r *RunFnRunner) preRunE(c *cobra.Command, args []string) error {
if r.EnableStar != (r.StarPath != "") {
return errors.Errorf("must specify --star-path with --enable-star")
if !r.EnableStar && r.StarPath != "" {
return errors.Errorf("must specify --enable-star with --star-path")
}
if c.ArgsLenAtDash() >= 0 && r.Image == "" &&
@@ -240,6 +257,9 @@ func (r *RunFnRunner) preRunE(c *cobra.Command, args []string) error {
path = args[0]
}
// parse mounts to set storageMounts
storageMounts := toStorageMounts(r.Mounts)
r.RunFns = runfn.RunFns{
FunctionPaths: r.FnPaths,
GlobalScope: r.GlobalScope,
@@ -250,6 +270,8 @@ func (r *RunFnRunner) preRunE(c *cobra.Command, args []string) error {
Network: r.Network,
NetworkName: r.NetworkName,
EnableStarlark: r.EnableStar,
StorageMounts: storageMounts,
ResultsDir: r.ResultsDir,
}
// don't consider args for the function

View File

@@ -11,22 +11,25 @@ import (
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/kyaml/runfn"
)
// TestRunFnCommand_preRunE verifies that preRunE correctly parses the commandline
// flags and arguments into the RunFns structure to be executed.
func TestRunFnCommand_preRunE(t *testing.T) {
tests := []struct {
name string
args []string
expected string
err string
path string
input io.Reader
output io.Writer
functionPaths []string
network bool
networkName string
name string
args []string
expected string
expectedStruct *runfn.RunFns
err string
path string
input io.Reader
output io.Writer
functionPaths []string
network bool
networkName string
mount []string
}{
{
name: "config map",
@@ -180,7 +183,7 @@ apiVersion: v1
"--star-name", "foo",
"--", "Foo", "g=h"},
path: "dir",
err: "must specify --star-path with --enable-star",
err: "must specify --enable-star with --star-path",
},
{
name: "image-star-not-enabled",
@@ -190,7 +193,17 @@ apiVersion: v1
"--star-name", "foo",
"--", "Foo", "g=h"},
path: "dir",
err: "must specify --star-path with --enable-star",
err: "must specify --enable-star with --star-path",
},
{
name: "star-enabled",
args: []string{"run", "dir", "--enable-star"},
path: "dir",
expectedStruct: &runfn.RunFns{
Path: "dir",
NetworkName: "bridge",
EnableStarlark: true,
},
},
{
name: "function paths",
@@ -213,6 +226,46 @@ metadata:
data: {g: h, i: j=k}
kind: Foo
apiVersion: v1
`,
},
{
name: "custom kind with storage mounts",
args: []string{
"run", "dir", "--mount", "type=bind,src=/mount/path,dst=/local/",
"--mount", "type=volume,src=myvol,dst=/local/",
"--mount", "type=tmpfs,dst=/local/",
"--image", "foo:bar", "--", "Foo", "g=h", "i=j=k"},
path: "dir",
mount: []string{"type=bind,src=/mount/path,dst=/local/", "type=volume,src=myvol,dst=/local/", "type=tmpfs,dst=/local/"},
expected: `
metadata:
name: function-input
annotations:
config.kubernetes.io/function: |
container: {image: 'foo:bar'}
data: {g: h, i: j=k}
kind: Foo
apiVersion: v1
`,
},
{
name: "results_dir",
args: []string{"run", "dir", "--results-dir", "foo/", "--image", "foo:bar", "--", "a=b", "c=d", "e=f"},
path: "dir",
expectedStruct: &runfn.RunFns{
Path: "dir",
NetworkName: "bridge",
ResultsDir: "foo/",
},
expected: `
metadata:
name: function-input
annotations:
config.kubernetes.io/function: |
container: {image: 'foo:bar'}
data: {a: b, c: d, e: f}
kind: ConfigMap
apiVersion: v1
`,
},
{
@@ -303,6 +356,14 @@ apiVersion: v1
t.FailNow()
}
if !assert.Equal(t, r.RunFns, r.RunFns) {
t.FailNow()
}
if !assert.Equal(t, toStorageMounts(tt.mount), r.RunFns.StorageMounts) {
t.FailNow()
}
// check if Functions were set
if tt.expected != "" {
if !assert.Len(t, r.RunFns.Functions, 1) {
@@ -314,6 +375,14 @@ apiVersion: v1
}
}
if tt.expectedStruct != nil {
r.RunFns.Functions = nil
tt.expectedStruct.FunctionPaths = tt.functionPaths
if !assert.Equal(t, *tt.expectedStruct, r.RunFns) {
t.FailNow()
}
}
})
}

View File

@@ -171,7 +171,7 @@ List setters for Resources.
var ListSettersExamples = `
Show setters:
$ config set DIR/
$ config list-setters DIR/
NAME DESCRIPTION VALUE TYPE COUNT SETBY
name-prefix '' PREFIX string 2`
@@ -289,8 +289,8 @@ the configuration as comments.
Optional. The value to set on the field.
To print the possible setters for the Resources in a directory, run ` + "`" + `set` + "`" + ` on
a directory -- e.g. ` + "`" + `kustomize config set DIR/` + "`" + `.
To print the possible setters for the Resources in a directory, run
` + "`" + `list-setters` + "`" + ` on a directory -- e.g. ` + "`" + `kustomize config list-setters DIR/` + "`" + `.
#### Tips
@@ -318,7 +318,7 @@ var SetExamples = `
List setters: Show the possible setters
$ config set DIR/
$ config list-setters DIR/
NAME DESCRIPTION VALUE TYPE COUNT SETBY
name-prefix '' PREFIX string 2
@@ -329,7 +329,7 @@ var SetExamples = `
List setters: Show the new values
$ config set DIR/
$ config list-setters DIR/
NAME DESCRIPTION VALUE TYPE COUNT SETBY
name-prefix 'test environment' test string 2 dev

View File

@@ -12,8 +12,8 @@
# Builtin Plugins
A list of kustomize's builtin plugins (both
generators and transformers).
A list of kustomize's builtin plugins - both
generators and transformers.
For each plugin, an example is given for
@@ -92,16 +92,35 @@ one ConfigMap resource (it's a generator of n maps).
The example below creates three ConfigMaps. One with the names and contents of
the given files, one with key/value as data, and a third which sets an
annotation and label via generatorOptions for that single ConfigMap.
annotation and label via `options` for that single ConfigMap.
Each configMapGenerator item accepts a parameter of
`behavior: [create|replace|merge]`.
This allows an overlay to modify or
replace an existing configMap from the parent.
Also, each entry has an `options` field, that has the
same subfields as the kustomization file's `generatorOptions` field.
This `options` field allows one to add labels and/or
annotations to the generated instance, or to individually
disable the name suffix hash for that instance.
Labels and annotations added here will not be overwritten
by the global options associated with the kustomization
file `generatorOptions` field. However, due to how
booleans behave, if the global `generatorOptions` field
specifies `disableNameSuffixHash: true`, this will
trump any attempt to locally override it.
```
# These labels are added to all configmaps and secrets.
generatorOptions:
labels:
fruit: apple
configMapGenerator:
- name: my-java-server-props
behavior: merge
files:
- application.properties
- more.properties
@@ -109,10 +128,14 @@ configMapGenerator:
literals:
- JAVA_HOME=/opt/java/jdk
- JAVA_TOOL_OPTIONS=-agentlib:hprof
options:
disableNameSuffixHash: true
labels:
pet: dog
- name: dashboards
files:
- mydashboard.json
generatorOptions:
options:
annotations:
dashboard: "1"
labels:
@@ -138,8 +161,6 @@ configMapGenerator:
### Usage via plugin
#### Arguments
> [types.GeneratorOptions]
>
> [types.ConfigMapArgs]
#### Example
@@ -640,6 +661,9 @@ results in the creation of
one Secret resource
(it's a generator of n secrets).
This works like the `configMapGenerator` field
described above.
```
secretGenerator:
- name: app-tls
@@ -663,7 +687,7 @@ secretGenerator:
files:
- app-config.yaml
type: Opaque
generatorOptions:
options:
annotations:
app_config: "true"
labels:
@@ -676,8 +700,6 @@ secretGenerator:
> [types.ObjectMeta]
>
> [types.GeneratorOptions]
>
> [types.SecretArgs]
#### Example

View File

@@ -1,20 +1,22 @@
# Demo: applying a json patch
# JSON Patching
A kustomization file supports customizing resources via [JSON patches](https://tools.ietf.org/html/rfc6902).
[JSON patches]: https://tools.ietf.org/html/rfc6902
[JSON patch]: https://tools.ietf.org/html/rfc6902
The example below modifies an `Ingress` object with such a patch.
A kustomization file supports customizing
resources via [JSON patches].
Make a `kustomization` containing an ingress resource.
Make a place to work:
<!-- @createIngress @testAgainstLatestRelease -->
<!-- @placeToWork @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
cat <<EOF >$DEMO_HOME/kustomization.yaml
resources:
- ingress.yaml
EOF
We'll be editting an `Ingress` object:
<!-- @ingress @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/ingress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
@@ -25,94 +27,175 @@ spec:
- host: foo.bar.com
http:
paths:
- backend:
- path: /
backend:
serviceName: homepage
servicePort: 8888
- path: /api
backend:
serviceName: my-api
servicePort: 80
servicePort: 7701
- path: /test
backend:
serviceName: hello
servicePort: 7702
EOF
```
Declare a JSON patch file to update two fields of the Ingress object:
The edits we want to make are:
- change host from `foo.bar.com` to `foo.bar.io`
- change servicePort from `80` to `8080`
- change the value of `host` to _foo.bar.io_
- change the port for `'/'` from _8888_ to _80_
- insert an entirely new serving path `/healthz`
at a particular point in the `paths` list,
rather than at the end or the beginning.
Here's the patch file to do that:
<!-- @addJsonPatch @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/ingress_patch.json
[
{"op": "replace", "path": "/spec/rules/0/host", "value": "foo.bar.io"},
{"op": "replace", "path": "/spec/rules/0/http/paths/0/backend/servicePort", "value": 8080}
{"op": "replace",
"path": "/spec/rules/0/host",
"value": "foo.bar.io"},
{"op": "replace",
"path": "/spec/rules/0/http/paths/0/backend/servicePort",
"value": 80},
{"op": "add",
"path": "/spec/rules/0/http/paths/1",
"value": { "path": "/healthz", "backend": {"servicePort":7700} }}
]
EOF
```
You can also write the patch in YAML format. This example also shows the "add" operation:
We'll of course need a `kustomization` file
referring to the `Ingress`:
<!-- @addYamlPatch @testAgainstLatestRelease -->
<!-- @kustomization @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/ingress_patch.yaml
- op: replace
path: /spec/rules/0/host
value: foo.bar.io
- op: add
path: /spec/rules/0/http/paths/-
value:
path: '/test'
backend:
serviceName: my-test
servicePort: 8081
cat <<EOF >$DEMO_HOME/kustomization.yaml
resources:
- ingress.yaml
EOF
```
Apply the patch by adding _patchesJson6902_ field in kustomization.yaml
To this same `kustomization` file, add a
`patches` field refering to
the patch file we just made and
target it to the `Ingress` object:
<!-- @applyJsonPatch @testAgainstLatestRelease -->
```
cat <<EOF >>$DEMO_HOME/kustomization.yaml
patchesJson6902:
- target:
patches:
- path: ingress_patch.json
target:
group: networking.k8s.io
version: v1beta1
kind: Ingress
name: my-ingress
path: ingress_patch.json
EOF
```
Running `kustomize build $DEMO_HOME`, in the output confirm that host has been updated correctly.
<!-- @confirmHost @testAgainstLatestRelease -->
Define the expected output:
<!-- @expected @testAgainstLatestRelease -->
```
test 1 == \
$(kustomize build $DEMO_HOME | grep "host: foo.bar.io" | wc -l); \
echo $?
```
Running `kustomize build $DEMO_HOME`, in the output confirm that the servicePort has been updated correctly.
<!-- @confirmServicePort @testAgainstLatestRelease -->
```
test 1 == \
$(kustomize build $DEMO_HOME | grep "servicePort: 8080" | wc -l); \
echo $?
cat <<EOF >$DEMO_HOME/out_expected.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: my-ingress
spec:
rules:
- host: foo.bar.io
http:
paths:
- backend:
serviceName: homepage
servicePort: 80
path: /
- backend:
servicePort: 7700
path: /healthz
- backend:
serviceName: my-api
servicePort: 7701
path: /api
- backend:
serviceName: hello
servicePort: 7702
path: /test
EOF
```
If the patch is YAML-formatted, it will be parsed correctly:
Run the build:
<!-- @runIt @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME >$DEMO_HOME/out_actual.yaml
```
<!-- @applyYamlPatch @testAgainstLatestRelease -->
Confirm they match:
<!-- @diffShouldExitZero @testAgainstLatestRelease -->
```
diff $DEMO_HOME/out_actual.yaml $DEMO_HOME/out_expected.yaml
```
If you prefer YAML to JSON, the patch can be expressed
in YAML format (neverthless following [JSON patch] rules):
<!-- @writeYamlPatch @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/ingress_patch.yaml
- op: add
path: /spec/rules/0/http/paths/-
value:
path: '/canada'
backend:
serviceName: hoser
servicePort: 7703
EOF
```
Now add this to the list of patches in the `kustomization` file:
<!-- @addYamlPatch @testAgainstLatestRelease -->
```
cat <<EOF >>$DEMO_HOME/kustomization.yaml
patchesJson6902:
- target:
- path: ingress_patch.yaml
target:
group: networking.k8s.io
version: v1beta1
kind: Ingress
name: my-ingress
path: ingress_patch.yaml
EOF
```
<!-- @confirmYamlPatch @testAgainstLatestRelease -->
We expect the following at the end of the output:
<!-- @expected @testAgainstLatestRelease -->
```
test 1 == \
$(kustomize build $DEMO_HOME | grep "path: /test" | wc -l); \
echo $?
cat <<EOF >$DEMO_HOME/out_expected.yaml
- backend:
serviceName: hello
servicePort: 7702
path: /test
- backend:
serviceName: hoser
servicePort: 7703
path: /canada
EOF
```
Try it:
<!-- @runIt @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME | tail -n 8 |\
diff $DEMO_HOME/out_expected.yaml -
```
To see how to apply one JSON patch to many resources,
see the [multi-patch](patchMultipleObjects.md) demo.

View File

@@ -1,43 +1,78 @@
[Strategic Merge Patch]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-api-machinery/strategic-merge-patch.md
[JSON patches]: https://tools.ietf.org/html/rfc6902
[label selector]: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors
# Patching multiple resources at once.
kustomize supports patching via either a
[strategic merge patch] (wherein you
partially re-specify the thing you want to
modify, with in-place changes) or a
[JSON patch] (wherein you specify specific
operation/target/value tuples in a particular
syntax).
A kustomize file lets one specify many
patches. Each patch must be associated with
a _target selector_:
[strategic merge patch]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-api-machinery/strategic-merge-patch.md
[JSON patch]: jsonpatch.md
> ```yaml
> patches:
> - path: <relative path to file containing patch>
> target:
> group: <optional group>
> version: <optional version>
> kind: <optional kind>
> name: <optional name>
> namespace: <optional namespace>
> labelSelector: <optional label selector>
> annotationSelector: <optional annotation selector>
> ```
E.g. select resources with _name_ matching `foo*`:
> ```yaml
> target:
> name: foo*
> ```
Select all resources of _kind_ `Deployment`:
> ```yaml
> target:
> kind: Deployment
> ```
[label/annotation selector rules]: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors
Using multiple fields just makes the target
more specific. The following selects only
Deployments that also have the _label_ `app=hello`
(full [label/annotation selector rules]):
> ```yaml
> target:
> kind: Deployment
> labelSelector: app=hello
> ```
### Demo
The example below shows how to inject a
sidecar container for multiple Deployment
resources.
# Demo: applying a patch to multiple resources
Make a place to work:
A kustomization file supports customizing resources via both
[Strategic Merge Patch] and [JSON patches]. Now one patch can be
applied to multiple resources.
This can be done by specifying a patch and a target selector as follows:
```
patches:
- path: <PatchFile>
target:
group: <Group>
version: <Version>
kind: <Kind>
name: <Name>
namespace: <Namespace>
labelSelector: <LabelSelector>
annotationSelector: <AnnotationSelector>
```
Both `labelSelector` and `annotationSelector` should follow the convention in [label selector].
Kustomize selects the targets which match all the fields in `target` to apply the patch.
The example below shows how to inject a sidecar container for all deployment resources.
Make a `kustomization` containing a Deployment resource.
<!-- @createDeployment @testAgainstLatestRelease -->
<!-- @demoHome @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
cat <<EOF >$DEMO_HOME/kustomization.yaml
resources:
- deployments.yaml
EOF
Make a file describing two Deployments:
<!-- @createDeployments @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/deployments.yaml
apiVersion: apps/v1
kind: Deployment
@@ -72,9 +107,10 @@ spec:
EOF
```
Declare a Strategic Merge Patch file to inject a sidecar container:
Declare a [strategic merge patch] file
to inject a sidecar container:
<!-- @addPatch @testAgainstLatestRelease -->
<!-- @definePatch @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/patch.yaml
apiVersion: apps/v1
@@ -93,11 +129,16 @@ spec:
EOF
```
Apply the patch by adding _patches_ field in kustomization.yaml
Finally, define a kustomization file
that specifies both a `patches` and `resources`
entry:
<!-- @applyPatch @testAgainstLatestRelease -->
<!-- @createKustomization @testAgainstLatestRelease -->
```
cat <<EOF >>$DEMO_HOME/kustomization.yaml
cat <<EOF >$DEMO_HOME/kustomization.yaml
resources:
- deployments.yaml
patches:
- path: patch.yaml
target:
@@ -105,18 +146,11 @@ patches:
EOF
```
Running `kustomize build $DEMO_HOME`, in the output confirm that both Deployment resources are patched correctly.
The expected result is:
<!-- @confirmPatch @testAgainstLatestRelease -->
<!-- @definedExpectedOutput @testAgainstLatestRelease -->
```
test 2 == \
$(kustomize build $DEMO_HOME | grep "image: docker.io/istio/proxyv2" | wc -l); \
echo $?
```
The output is as follows:
```yaml
cat <<EOF >$DEMO_HOME/out_expected.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
@@ -157,32 +191,21 @@ spec:
name: istio-proxy
- image: busybox
name: busybox
EOF
```
## Target selector
- Select resources with name matching `name*`
```yaml
target:
name: name*
```
- Select all Deployment resources
```yaml
target:
kind: Deployment
```
- Select resources matching label `app=hello`
```yaml
target:
labelSelector: app=hello
```
- Select resources matching annotation `app=hello`
```yaml
target:
annotationSelector: app=hello
```
- Select all Deployment resources matching label `app=hello`
```yaml
target:
kind: Deployment
labelSelector: app=hello
```
Run the build:
<!-- @runIt @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME >$DEMO_HOME/out_actual.yaml
```
Confirm expectations:
<!-- @diffShouldExitZero @testAgainstLatestRelease -->
```
diff $DEMO_HOME/out_actual.yaml $DEMO_HOME/out_expected.yaml
```
To see how to do this with JSON patches,
try the [JSON patch] demo.

View File

@@ -109,6 +109,7 @@ func getGroupKinds(in []*yaml.RNode) ([]metav1.GroupKind, error) {
found := false
for _, gk := range groupKinds {
if gk.Group == gvk.Group && gk.Kind == gvk.Kind {
found = true
break
}
}

View File

@@ -12,8 +12,7 @@ spec:
strict: true
ignoreMissingSchemas: true
# TODO: Remove these once function container network/volumes features are
# stabilized.
# TODO: Update this to use network/volumes features.
# Relevant issues:
# - https://github.com/kubernetes-sigs/kustomize/issues/1901
# - https://github.com/kubernetes-sigs/kustomize/issues/1902

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env sh
#!/bin/bash
set -e
# Builds or removes Go plugin object code.
@@ -40,8 +40,8 @@ function removePlugin {
}
goPlugins=$(
find $root -name "*.go" |
grep -v builtin/ |
find $root -name "*.go" |
grep -v builtin/ |
xargs grep -l "var KustomizePlugin")
for p in $goPlugins; do

View File

@@ -15,7 +15,13 @@ set -o pipefail
rcAccumulator=0
function onLinuxAndNotOnTravis {
[[ ("linux" == "$(go env GOOS)") && (-z ${TRAVIS+x}) ]] && return
# TODO: Make the code ignorant of the CI environment "brand name".
# We used to run CI tests on travis, and disabled certain tests
# when running there. Now we run on Prow, so look for that.
# https://github.com/kubernetes/test-infra/blob/master/prow/jobs.md
# Should eschew using the brand name of the CI environment
# (replace "travis" with "CI_env" or something - not just switch to "prow").
[[ ("linux" == "$(go env GOOS)") && (-z ${$PROW_JOB_ID+x}) ]] && return
false
}
@@ -24,7 +30,7 @@ function runTest {
local code=0
if grep -q "// +build notravis" "$file"; then
if onLinuxAndNotOnTravis; then
go test -v -tags=notravis $file
go test -v -tags=notravis $file
code=$?
else
# TODO: make work for non-linux
@@ -51,7 +57,8 @@ function scanDir {
if onLinuxAndNotOnTravis; then
# Some of these tests have special deps.
make $(go env GOPATH)/bin/helm
make $(go env GOPATH)/bin/helmV2
make $(go env GOPATH)/bin/helmV3
make $(go env GOPATH)/bin/kubeval
fi
@@ -60,7 +67,7 @@ for goMod in $(find ./plugin -name 'go.mod'); do
if [[ "$d" == "./plugin/someteam.example.com/v1/gogetter" ]]; then
echo "Skipping broken $d"
else
scanDir $d
scanDir $d
fi
done

View File

@@ -16,7 +16,7 @@ require (
sigs.k8s.io/kustomize/cmd/config v0.0.5
sigs.k8s.io/kustomize/cmd/kubectl v0.0.3
sigs.k8s.io/kustomize/kstatus v0.0.1
sigs.k8s.io/kustomize/kyaml v0.1.1
sigs.k8s.io/kustomize/kyaml v0.1.5
sigs.k8s.io/yaml v1.1.0
)

View File

@@ -2,6 +2,7 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
github.com/360EntSecGroup-Skylar/excelize v1.4.1/go.mod h1:vnax29X2usfl7HHkBrX5EvSCJcmH3dT9luvxzu8iGAE=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-autorest/autorest v0.9.0 h1:MRvx8gncNaXJqOoLmhNjUAKh33JJF8LyxPhomEtOsjs=
@@ -26,6 +27,7 @@ github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb0
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/OpenPeeDeeP/depguard v1.0.1 h1:VlW4R6jmBIv3/u1JNlawEvJMM4J+dPORPaZasQee8Us=
github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM=
github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
@@ -38,6 +40,7 @@ github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpH
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
@@ -52,6 +55,9 @@ github.com/bombsimon/wsl v1.2.5/go.mod h1:43lEF/i0kpXbLCeDXL9LMT8c92HyBywXb0AsgM
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 h1:7aWHqerlJ41y6FOsEUvknqgXnGmJyJSbjhAWq5pO4F8=
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
@@ -82,6 +88,7 @@ github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dustmop/soup v1.1.2-0.20190516214245-38228baa104e/go.mod h1:CgNC6SGbT+Xb8wGGvzilttZL1mc5sQ/5KkcxsZttMIk=
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e h1:p1yVGRW3nmb85p1Sh1ZJSDm4A4iKLS5QNbvUHMgGu/M=
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
@@ -146,8 +153,6 @@ github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsd
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo=
github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/spec v0.19.5 h1:Xm0Ao53uqnk9QE/LlYV5DEU09UAgpliA85QoT9LzqPw=
github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk=
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
@@ -370,6 +375,7 @@ github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lN
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
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/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=
@@ -391,6 +397,7 @@ github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/paulmach/orb v0.1.3/go.mod h1:VFlX/8C+IQ1p6FTRRKzKoOPJnvEtA5G0Veuqwbu//Vk=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
@@ -426,6 +433,8 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z
github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/qri-io/starlib v0.4.2-0.20200213133954-ff2e8cd5ef8d h1:K6eOUihrFLdZjZnA4XlRp864fmWXv9YTIk7VPLhRacA=
github.com/qri-io/starlib v0.4.2-0.20200213133954-ff2e8cd5ef8d/go.mod h1:7DPO4domFU579Ga6E61sB9VFNaniPVwJP5C4bBCu3wA=
github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
@@ -472,6 +481,7 @@ github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.3-0.20181224173747-660f15d67dbb/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -503,6 +513,9 @@ github.com/yujunz/go-getter v1.4.1-lite h1:FhvNc94AXMZkfqUwfMKhnQEC9phkphSGdPTL7
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.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.starlark.net v0.0.0-20190528202925-30ae18b8564f/go.mod h1:c1/X6cHgvdXj6pUlmWKMkuqRnW4K8x2vwt6JAaaircg=
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc=
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
@@ -537,6 +550,7 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180112015858-5ccada7d0a7b/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -588,6 +602,8 @@ golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190911201528-7ad0cfa0b7b5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69 h1:rOhMmluY6kLMhdnrivzec6lLgaVbMHMn2ISQXJeJ5EM=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c h1:Vco5b+cuG5NNfORVxZy6bYZQ7rsigisU1WQFkvQ0L5E=
golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20171227012246-e19ae1496984/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -739,10 +755,8 @@ sigs.k8s.io/kustomize/cmd/config v0.0.5 h1:mFJowsk9IGvwm5dUpVB+ZM63on2JjgaCy+YcV
sigs.k8s.io/kustomize/cmd/config v0.0.5/go.mod h1:L47nDnZDfGFQG3gnPJLG2UABn0nVb9v+ndceyMH0jjU=
sigs.k8s.io/kustomize/kyaml v0.0.2/go.mod h1:rywm/rcR5LmCBghz9956tE45OdUPChFoXVVs+WmhMTI=
sigs.k8s.io/kustomize/kyaml v0.0.5/go.mod h1:waxTrzQRK9i6/5fR5HNo8xa4YwvWn8t85vMnOGFEZik=
sigs.k8s.io/kustomize/kyaml v0.0.6 h1:KhQr7JwpCseFTSWCwqp4CJ4mY6Kx+i34tF4e0eNkcXw=
sigs.k8s.io/kustomize/kyaml v0.0.6/go.mod h1:tDOfJjL6slQVBLHJ76XfXAFgAOEdfm04AW2HehYOp8k=
sigs.k8s.io/kustomize/kyaml v0.1.1 h1:nGUNYINljZNmlAS8uoobUv/wx/s3Pg8dNxYo+W7uYh0=
sigs.k8s.io/kustomize/kyaml v0.1.1/go.mod h1:/NdPPfrperSCGjm55cwEro1loBVtbtVIXSb7FguK6uk=
sigs.k8s.io/kustomize/kyaml v0.1.5 h1:NicBWYTwkuOfVyZDbNkfSBSCwSgin4uirkedtyZltIc=
sigs.k8s.io/kustomize/kyaml v0.1.5/go.mod h1:461i94nj0h0ylJ6w83jLkR4SqqVhn1iY6fjD0JSTQeE=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA=
sigs.k8s.io/testing_frameworks v0.1.2 h1:vK0+tvjF0BZ/RYFeZ1E6BYBwHJJXhjuZ3TdsEKH+UQM=

View File

@@ -16,6 +16,7 @@ import (
"sigs.k8s.io/kustomize/api/krusty"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/yaml"
)
@@ -107,7 +108,7 @@ func (o *Options) makeOptions() *krusty.Options {
DoPrune: false,
}
if isFlagEnablePluginsSet() {
c, err := konfig.EnabledPluginConfig()
c, err := konfig.EnabledPluginConfig(types.BploUseStaticallyLinked)
if err != nil {
log.Fatal(err)
}

View File

@@ -95,11 +95,10 @@ func addConfigMap(
args := findOrMakeConfigMapArgs(k, flags.Name)
mergeFlagsIntoCmArgs(args, flags)
// Validate by trying to create corev1.configmap.
_, err := kf.MakeConfigMap(ldr, k.GeneratorOptions, args)
if err != nil {
return err
}
return nil
args.Options = types.MergeGlobalOptionsIntoLocal(
args.Options, k.GeneratorOptions)
_, err := kf.MakeConfigMap(ldr, args)
return err
}
func findOrMakeConfigMapArgs(m *types.Kustomization, name string) *types.ConfigMapArgs {

View File

@@ -105,11 +105,10 @@ func addSecret(
args := findOrMakeSecretArgs(k, flags.Name, flags.Namespace, flags.Type)
mergeFlagsIntoGeneratorArgs(&args.GeneratorArgs, flags)
// Validate by trying to create corev1.secret.
_, err := kf.MakeSecret(ldr, k.GeneratorOptions, args)
if err != nil {
return err
}
return nil
args.Options = types.MergeGlobalOptionsIntoLocal(
args.Options, k.GeneratorOptions)
_, err := kf.MakeSecret(ldr, args)
return err
}
func findOrMakeSecretArgs(m *types.Kustomization, name, namespace, secretType string) *types.SecretArgs {

View File

@@ -28,7 +28,7 @@ var (
errImageNoArgs = errors.New("no image specified")
errImageInvalidArgs = errors.New(`invalid format of image, use one of the following options:
- <image>=<newimage>:<newtag>
- <image>=<newimage>@<newtag>
- <image>=<newimage>@<digest>
- <image>=<newimage>
- <image>:<newtag>
- <image>@<digest>`)

View File

@@ -35,4 +35,5 @@ vet:
openapi:
(which $(GOPATH)/bin/go-bindata || go get -v github.com/go-bindata/go-bindata)
go-bindata --pkg openapi -o openapi/swagger.go openapi/swagger.json
$(GOPATH)/bin/go-bindata --pkg kubernetesapi -o openapi/kubernetesapi/swagger.go openapi/kubernetesapi/swagger.json
$(GOPATH)/bin/go-bindata --pkg kustomizationapi -o openapi/kustomizationapi/swagger.go openapi/kustomizationapi/swagger.json

View File

@@ -11,6 +11,7 @@ import (
// CopyComments recursively copies the comments on fields in from to fields in to
func CopyComments(from, to *yaml.RNode) error {
copy(from, to)
// walk the fields copying comments
_, err := walk.Walker{
Sources: []*yaml.RNode{from, to},
@@ -44,13 +45,13 @@ func copy(from, to *yaml.RNode) {
if from == nil || to == nil {
return
}
if from.YNode().LineComment != "" {
to.YNode().LineComment = from.YNode().LineComment
if from.Document().LineComment != "" {
to.Document().LineComment = from.Document().LineComment
}
if from.YNode().HeadComment != "" {
to.YNode().HeadComment = from.YNode().HeadComment
if from.Document().HeadComment != "" {
to.Document().HeadComment = from.Document().HeadComment
}
if from.YNode().FootComment != "" {
to.YNode().FootComment = from.YNode().FootComment
if from.Document().FootComment != "" {
to.Document().FootComment = from.Document().FootComment
}
}

View File

@@ -0,0 +1,65 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package comments
import (
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
func TestCopyComments(t *testing.T) {
from, err := yaml.Parse(`# A
#
# B
# C
apiVersion: apps/v1
kind: Deployment
spec: # comment 1
# comment 2
replicas: 3 # comment 3
# comment 4
`)
if !assert.NoError(t, err) {
t.FailNow()
}
to, err := yaml.Parse(`apiVersion: apps/v1
kind: Deployment
spec:
replicas: 4
`)
if !assert.NoError(t, err) {
t.FailNow()
}
err = CopyComments(from, to)
if !assert.NoError(t, err) {
t.FailNow()
}
actual, err := to.String()
if !assert.NoError(t, err) {
t.FailNow()
}
expected := `# A
#
# B
# C
apiVersion: apps/v1
kind: Deployment
spec: # comment 1
# comment 2
replicas: 4 # comment 3
# comment 4
`
if !assert.Equal(t, expected, actual) {
t.FailNow()
}
}

View File

@@ -121,13 +121,65 @@ func Diff(sourceDir, destDir string) (sets.String, error) {
return diff, err
}
if !bytes.Equal(b1, b2) {
dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(string(b1), string(b2), false)
fmt.Println(dmp.DiffPrettyText(diffs))
fmt.Println(PrettyFileDiff(string(b1), string(b2)))
diff.Insert(f)
}
}
// return the differing files
return diff, nil
}
// PrettyFileDiff takes the content of two files and returns the pretty diff
func PrettyFileDiff(s1, s2 string) string {
dmp := diffmatchpatch.New()
wSrc, wDst, warray := dmp.DiffLinesToRunes(s1, s2)
diffs := dmp.DiffMainRunes(wSrc, wDst, false)
diffs = dmp.DiffCharsToLines(diffs, warray)
return dmp.DiffPrettyText(diffs)
}
// SyncFile copies file from src file path to a dst file path by replacement
// deletes dst file if src file doesn't exist
func SyncFile(src, dst string) error {
srcFileInfo, err := os.Stat(src)
if err != nil {
// delete dst if source doesn't exist
if err = deleteFile(dst); err != nil {
return err
}
return nil
}
input, err := ioutil.ReadFile(src)
if err != nil {
return err
}
var filePerm os.FileMode
// get the destination file perm if file exists
dstFileInfo, err := os.Stat(dst)
if err != nil {
// get source file perm if destination file doesn't exist
filePerm = srcFileInfo.Mode().Perm()
} else {
filePerm = dstFileInfo.Mode().Perm()
}
err = ioutil.WriteFile(dst, input, filePerm)
if err != nil {
return err
}
return nil
}
// deleteFile deletes file from path, returns no error if file doesn't exist
func deleteFile(path string) error {
_, err := os.Stat(path)
if err != nil {
// return nil if file doesn't exist
return nil
}
return os.Remove(path)
}

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