mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-14 10:30:59 +00:00
Compare commits
337 Commits
kyaml/v0.1
...
kyaml/v0.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62f0dab2ac | ||
|
|
d642b959cf | ||
|
|
d49f6e17ad | ||
|
|
0de4e0ba11 | ||
|
|
54569e4591 | ||
|
|
b2dc88447e | ||
|
|
314b8fbefa | ||
|
|
c0840b6804 | ||
|
|
1eccbc4e30 | ||
|
|
f79e16b352 | ||
|
|
b20e611413 | ||
|
|
e638e408b0 | ||
|
|
84bd402cc0 | ||
|
|
e724e25fec | ||
|
|
50e731a1d9 | ||
|
|
beb2825f82 | ||
|
|
6d9b54004e | ||
|
|
1f04fd2f23 | ||
|
|
6ffd22a1f1 | ||
|
|
3e6ede9645 | ||
|
|
14f3cea24f | ||
|
|
f0f414d53a | ||
|
|
f9d553689e | ||
|
|
69435e059a | ||
|
|
997e6fcc63 | ||
|
|
daf81df437 | ||
|
|
3e447da6ef | ||
|
|
ea21b37d67 | ||
|
|
d29febecb7 | ||
|
|
1b1e6ccab0 | ||
|
|
7ee6dd551d | ||
|
|
ccb68aa881 | ||
|
|
1252e45576 | ||
|
|
19d163ca0f | ||
|
|
bf7a0f9004 | ||
|
|
3b1a711cee | ||
|
|
cd35e95560 | ||
|
|
0a16b6cf40 | ||
|
|
7b84613ad1 | ||
|
|
d14dfb604c | ||
|
|
acba8fff62 | ||
|
|
38da7ca15c | ||
|
|
9ef7ba9c95 | ||
|
|
4e7f4bce7b | ||
|
|
f8f444d92a | ||
|
|
c2312c4018 | ||
|
|
0fbaa2d0e8 | ||
|
|
ae20497fd3 | ||
|
|
506dc4f9fe | ||
|
|
482e8930fc | ||
|
|
d37fabf876 | ||
|
|
eb1529b516 | ||
|
|
c750c0089d | ||
|
|
2b9ef61f88 | ||
|
|
344b257c1f | ||
|
|
e2196d9bd1 | ||
|
|
65aeefd281 | ||
|
|
6ce230f2b2 | ||
|
|
401cf9579c | ||
|
|
4dcc040ec1 | ||
|
|
662ccf1915 | ||
|
|
e62480d11c | ||
|
|
88cf251ef7 | ||
|
|
d6e40a3f6c | ||
|
|
eb51117adf | ||
|
|
0d68e0c7be | ||
|
|
7c2e8845ad | ||
|
|
ce18530656 | ||
|
|
ca71736140 | ||
|
|
e7d5f665b8 | ||
|
|
6c587c9542 | ||
|
|
56a47bd901 | ||
|
|
a8c0be49ae | ||
|
|
e49bf52928 | ||
|
|
a54226e0a9 | ||
|
|
f086269d6e | ||
|
|
e2e9181bed | ||
|
|
21ee7f7125 | ||
|
|
cbb61fc668 | ||
|
|
23de1499c2 | ||
|
|
cb2636335f | ||
|
|
c266537b27 | ||
|
|
f80cf9f433 | ||
|
|
032bf3338e | ||
|
|
b4d25b1b26 | ||
|
|
d917876949 | ||
|
|
14b7282ed8 | ||
|
|
8868d91670 | ||
|
|
b6fae2a959 | ||
|
|
a8388f473b | ||
|
|
08918ea352 | ||
|
|
5dcbd35e40 | ||
|
|
2e2674fa24 | ||
|
|
170eca7c52 | ||
|
|
bf17fe1d8f | ||
|
|
a8010ac469 | ||
|
|
f66936f6bf | ||
|
|
eb54c97947 | ||
|
|
b84885d5c4 | ||
|
|
298d977ee7 | ||
|
|
d5a2009d3f | ||
|
|
d0ae8fba13 | ||
|
|
f8d1e778c7 | ||
|
|
1948af8190 | ||
|
|
79a9154cf8 | ||
|
|
26fcafdb57 | ||
|
|
2ec4b971e9 | ||
|
|
1d44793d79 | ||
|
|
55a37de686 | ||
|
|
f6b72077c8 | ||
|
|
416eed97c4 | ||
|
|
5762794793 | ||
|
|
91e002a560 | ||
|
|
15545cc228 | ||
|
|
3f0c21304c | ||
|
|
bb7ebe029c | ||
|
|
64f42ea45f | ||
|
|
1b0fe2a078 | ||
|
|
56d82a8378 | ||
|
|
39dbdddb86 | ||
|
|
27a1de1a19 | ||
|
|
7229f5fbed | ||
|
|
ba9d5ee16f | ||
|
|
001b0c5fe5 | ||
|
|
bbeff6ddd6 | ||
|
|
e57b5d283f | ||
|
|
dbd719bd3f | ||
|
|
29ca6935bd | ||
|
|
f5c70b3929 | ||
|
|
b816903c93 | ||
|
|
d32fe662af | ||
|
|
4b5fbf2b80 | ||
|
|
283f8ae0a5 | ||
|
|
f6a1e4af3b | ||
|
|
e7fe132df8 | ||
|
|
631f623d9c | ||
|
|
19c467a924 | ||
|
|
afa2b52807 | ||
|
|
30843e2dac | ||
|
|
2a3b645758 | ||
|
|
b89cb92c2d | ||
|
|
9a6aad3ae4 | ||
|
|
c4b4a41913 | ||
|
|
0c37ee89af | ||
|
|
6917214251 | ||
|
|
a3a3140e4c | ||
|
|
d244c8a8bb | ||
|
|
d96e47cc38 | ||
|
|
2f2ba40876 | ||
|
|
ab09d27ec7 | ||
|
|
5e95c6ab06 | ||
|
|
0c6e827ab8 | ||
|
|
17cbd96667 | ||
|
|
0fce7d53a9 | ||
|
|
68780b4c0c | ||
|
|
04e1663b70 | ||
|
|
ba77fd5b7f | ||
|
|
77814ac12b | ||
|
|
e1b6aa393a | ||
|
|
3229c810cc | ||
|
|
344d0eec83 | ||
|
|
387c95be1f | ||
|
|
c02d0e502a | ||
|
|
5806c6f4f7 | ||
|
|
396b693e1c | ||
|
|
f95ea9e6a0 | ||
|
|
8c4d35470a | ||
|
|
6fb96b7d53 | ||
|
|
ca01b49614 | ||
|
|
4653f5d9d3 | ||
|
|
bd67fc2781 | ||
|
|
17af5d518f | ||
|
|
670cef4fd1 | ||
|
|
5c9adf248c | ||
|
|
fd847108cd | ||
|
|
d2ceab5f30 | ||
|
|
86a84ca486 | ||
|
|
876ec8fa6b | ||
|
|
2145d1984f | ||
|
|
92288a8a02 | ||
|
|
a6449aa03f | ||
|
|
9c827f5362 | ||
|
|
e201dbb31a | ||
|
|
bc981fcbc3 | ||
|
|
8a729459aa | ||
|
|
d1102fb726 | ||
|
|
edb6294741 | ||
|
|
175c99f9f6 | ||
|
|
20a93fdd12 | ||
|
|
0421c9fb50 | ||
|
|
8c8a2125b7 | ||
|
|
f39f914a98 | ||
|
|
c583f4164c | ||
|
|
6a7cecddd7 | ||
|
|
d8efc15169 | ||
|
|
86d48b2a95 | ||
|
|
7e0fd02783 | ||
|
|
1c53932166 | ||
|
|
721a905e13 | ||
|
|
3fdf88d10e | ||
|
|
4b19643b36 | ||
|
|
b0b6c962dc | ||
|
|
78191b45fb | ||
|
|
37a403fc65 | ||
|
|
fd7e170b69 | ||
|
|
afc1815f3f | ||
|
|
daa3e5e2c2 | ||
|
|
12adc1ff95 | ||
|
|
41283c4727 | ||
|
|
30740f87f1 | ||
|
|
6c8db65a90 | ||
|
|
35b5b7554f | ||
|
|
6395344bcb | ||
|
|
4a3bb926c5 | ||
|
|
ba5335cf48 | ||
|
|
03ac2e1ada | ||
|
|
2e036c24c2 | ||
|
|
1cf5b00af8 | ||
|
|
9097f7b5a6 | ||
|
|
0c8174544f | ||
|
|
a37572d193 | ||
|
|
ba7315ca76 | ||
|
|
ddf768195c | ||
|
|
b11cc3ae67 | ||
|
|
22668eae16 | ||
|
|
02eb788b78 | ||
|
|
41fb6915b3 | ||
|
|
596519d3f2 | ||
|
|
d3d92157fa | ||
|
|
c83ebd9530 | ||
|
|
c3b5d8fa19 | ||
|
|
7a773a3a48 | ||
|
|
46d4934b68 | ||
|
|
d0ef2f70a1 | ||
|
|
b8d2ff2afa | ||
|
|
7e0158e1e9 | ||
|
|
5948f6aa63 | ||
|
|
496a962a53 | ||
|
|
17b42a99f5 | ||
|
|
271f393218 | ||
|
|
c0dc68d6e7 | ||
|
|
188e35fbfd | ||
|
|
233b6adf7e | ||
|
|
41296b9814 | ||
|
|
66e4e1582b | ||
|
|
2e230b4d4b | ||
|
|
bcae65770a | ||
|
|
d49e5aa5aa | ||
|
|
94af647556 | ||
|
|
9d5491c2e2 | ||
|
|
cf89eae804 | ||
|
|
9452a031ba | ||
|
|
a464ed0c59 | ||
|
|
ec212711d4 | ||
|
|
2f2e14e953 | ||
|
|
ed72bb02d4 | ||
|
|
02e0b38bb0 | ||
|
|
01ab069bd2 | ||
|
|
cdc4a5083b | ||
|
|
5e84de2a89 | ||
|
|
e5041bae6f | ||
|
|
0d600af35a | ||
|
|
0989b26098 | ||
|
|
7888aef305 | ||
|
|
fe604fd3d1 | ||
|
|
4fc02497ae | ||
|
|
e96c38e3ab | ||
|
|
29104d6fa9 | ||
|
|
df57e196d8 | ||
|
|
f3c825f550 | ||
|
|
03c94eabb7 | ||
|
|
c071cdaedd | ||
|
|
f68a0c50d9 | ||
|
|
db34e923c5 | ||
|
|
df80b29694 | ||
|
|
ea193328e3 | ||
|
|
2d4bce5112 | ||
|
|
af06ae6b69 | ||
|
|
46875b6ac4 | ||
|
|
0fa010c7e7 | ||
|
|
3e652d6fea | ||
|
|
f54014ce3b | ||
|
|
08924dc2f5 | ||
|
|
49c0ed1326 | ||
|
|
7440f974b8 | ||
|
|
ab9b89213b | ||
|
|
9fc012cc4e | ||
|
|
877d72b10b | ||
|
|
c743f13d0d | ||
|
|
0d32543ebd | ||
|
|
28ee975948 | ||
|
|
2a9adbeb1e | ||
|
|
672c751715 | ||
|
|
d3a7b9008b | ||
|
|
b0d2e4bdcd | ||
|
|
71bf0d5d14 | ||
|
|
0a9c5cb0cf | ||
|
|
ff4136b1a2 | ||
|
|
1567b96ed3 | ||
|
|
14947e449b | ||
|
|
b368b347d1 | ||
|
|
5c359bda28 | ||
|
|
c94b5d8f25 | ||
|
|
b699204a9e | ||
|
|
cf3a452ddd | ||
|
|
faad014f96 | ||
|
|
8e46ef57be | ||
|
|
458d48430a | ||
|
|
3cecdc6214 | ||
|
|
7cac778866 | ||
|
|
0aa379c228 | ||
|
|
cd0f9b0c5b | ||
|
|
651f0c1097 | ||
|
|
6348ea9515 | ||
|
|
4b64f1e0e8 | ||
|
|
7306402cca | ||
|
|
485f7d44d9 | ||
|
|
9e57ab72fc | ||
|
|
d17ef91d94 | ||
|
|
e97cecf9dc | ||
|
|
5833f4ca80 | ||
|
|
e86c479690 | ||
|
|
d082c75b65 | ||
|
|
d2e59002ae | ||
|
|
c857ff8371 | ||
|
|
866e84059f | ||
|
|
497d2ee031 | ||
|
|
c4febc59d5 | ||
|
|
19955e73ff | ||
|
|
271bf31ce9 | ||
|
|
809182c6b6 | ||
|
|
0dd3d84104 | ||
|
|
de6b978491 | ||
|
|
8fa8e14eeb | ||
|
|
26b5e628cf | ||
|
|
80853c61b8 | ||
|
|
7ff87ef5b9 |
@@ -1,7 +1,6 @@
|
||||
.github
|
||||
docs
|
||||
examples
|
||||
functions
|
||||
hack
|
||||
site
|
||||
travis
|
||||
|
||||
6
.github/dependabot.yml
vendored
Normal file
6
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
73
.github/workflows/go.yml
vendored
73
.github/workflows/go.yml
vendored
@@ -6,6 +6,9 @@ on:
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
|
||||
lint:
|
||||
@@ -14,18 +17,21 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ^1.16
|
||||
go-version: ^1.18
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Lint
|
||||
run: ./hack/kyaml-pre-commit.sh
|
||||
env:
|
||||
KUSTOMIZE_DOCKER_E2E: false # don't need to do e2e tests for linting
|
||||
run: make lint
|
||||
|
||||
- name: Verify boilerplate
|
||||
run: make check-license
|
||||
|
||||
test-linux:
|
||||
name: Test Linux
|
||||
@@ -33,25 +39,16 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ^1.16
|
||||
go-version: ^1.18
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Test kyaml
|
||||
run: go test -cover ./...
|
||||
working-directory: ./kyaml
|
||||
|
||||
- name: Test api
|
||||
run: go test -cover ./... -ldflags "-X sigs.k8s.io/kustomize/api/provenance.version=v444.333.222"
|
||||
working-directory: ./api
|
||||
|
||||
- name: Test cmd/config
|
||||
run: go test -cover ./...
|
||||
working-directory: ./cmd/config
|
||||
- name: Test all modules
|
||||
run: make test-unit-non-plugin
|
||||
env:
|
||||
KUSTOMIZE_DOCKER_E2E: true
|
||||
|
||||
@@ -61,25 +58,16 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ^1.16
|
||||
go-version: ^1.18
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Test kyaml
|
||||
run: go test -cover ./...
|
||||
working-directory: ./kyaml
|
||||
|
||||
- name: Test api
|
||||
run: go test -cover ./... -ldflags "-X sigs.k8s.io/kustomize/api/provenance.version=v444.333.222"
|
||||
working-directory: ./api
|
||||
|
||||
- name: Test cmd/config
|
||||
run: go test -cover ./...
|
||||
working-directory: ./cmd/config
|
||||
- name: Test all modules
|
||||
run: make test-unit-non-plugin
|
||||
env:
|
||||
KUSTOMIZE_DOCKER_E2E: false # docker not installed on mac
|
||||
|
||||
@@ -89,25 +77,26 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ^1.16
|
||||
go-version: ^1.18
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Test kyaml
|
||||
run: go test -cover ./...
|
||||
working-directory: ./kyaml
|
||||
|
||||
# TODO: uncomment once Windows tests are passing.
|
||||
# - name: Test api
|
||||
# run: go test -cover ./... -ldflags "-X sigs.k8s.io/kustomize/api/provenance.version=v444.333.222"
|
||||
# working-directory: ./api
|
||||
|
||||
- name: Test cmd/config
|
||||
run: go test -cover ./...
|
||||
working-directory: ./cmd/config
|
||||
env:
|
||||
KUSTOMIZE_DOCKER_E2E: false # docker on windows not working well yet
|
||||
|
||||
# TODO (#4001): replace specific modules above with this once Windows tests are passing.
|
||||
#- name: Test all modules
|
||||
# run: make test-unit-non-plugin
|
||||
# env:
|
||||
# KUSTOMIZE_DOCKER_E2E: false # docker on windows not working well yet
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -23,7 +23,11 @@
|
||||
.bin
|
||||
|
||||
# Hugo site
|
||||
publishedSite/
|
||||
site/public/
|
||||
site/resources/
|
||||
site/.hugo_build.lock
|
||||
**/node_modules/
|
||||
|
||||
# goreleaser artifacts
|
||||
**/dist/
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
run:
|
||||
deadline: 5m
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- bodyclose
|
||||
- deadcode
|
||||
- depguard
|
||||
# - dogsled
|
||||
- dupl
|
||||
# - errcheck
|
||||
# - funlen
|
||||
# - gochecknoinits
|
||||
- goconst
|
||||
# - gocritic
|
||||
- gocyclo
|
||||
- gofmt
|
||||
- goimports
|
||||
- golint
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- interfacer
|
||||
- lll
|
||||
- misspell
|
||||
- nakedret
|
||||
# - scopelint
|
||||
- staticcheck
|
||||
- structcheck
|
||||
# stylecheck demands that acronyms not be treated as words
|
||||
# in camelCase, so JsonOp become JSONOp, etc. Yuck.
|
||||
# - stylecheck
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
- varcheck
|
||||
# - whitespace
|
||||
|
||||
linters-settings:
|
||||
dupl:
|
||||
threshold: 400
|
||||
lll:
|
||||
line-length: 170
|
||||
gocyclo:
|
||||
min-complexity: 15
|
||||
golint:
|
||||
min-confidence: 0.85
|
||||
138
.golangci.yml
Normal file
138
.golangci.yml
Normal file
@@ -0,0 +1,138 @@
|
||||
# Copyright 2019 The Kubernetes Authors.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
run:
|
||||
deadline: 5m
|
||||
|
||||
linters:
|
||||
# please, do not use `enable-all`: it's deprecated and will be removed soon.
|
||||
# inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint
|
||||
disable-all: true
|
||||
enable:
|
||||
- asciicheck
|
||||
- bidichk
|
||||
- bodyclose
|
||||
- contextcheck
|
||||
# - cyclop
|
||||
- depguard
|
||||
- dogsled
|
||||
- dupl
|
||||
- durationcheck
|
||||
- errcheck
|
||||
- errname
|
||||
- errorlint
|
||||
- exhaustive
|
||||
# - exhaustivestruct
|
||||
- exportloopref
|
||||
# - forbidigo
|
||||
- forcetypeassert
|
||||
# - funlen
|
||||
# - gci
|
||||
- gochecknoglobals
|
||||
- gochecknoinits
|
||||
# - gocognit
|
||||
- goconst
|
||||
- gocritic
|
||||
- gocyclo
|
||||
# - godot
|
||||
# - godox
|
||||
# - goerr113
|
||||
- gofmt
|
||||
# - gofumpt
|
||||
- goheader
|
||||
- goimports
|
||||
- gomnd
|
||||
- gomoddirectives
|
||||
- gomodguard
|
||||
- goprintffuncname
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
# - ifshort # too many false positives
|
||||
- importas
|
||||
- ineffassign
|
||||
# - ireturn
|
||||
- lll
|
||||
- makezero
|
||||
- misspell
|
||||
- nakedret
|
||||
- nestif
|
||||
- nilerr
|
||||
# - nilnil
|
||||
# - nlreturn
|
||||
# - noctx
|
||||
- nolintlint
|
||||
# - paralleltest
|
||||
- prealloc
|
||||
- predeclared
|
||||
- promlinter
|
||||
- revive
|
||||
- rowserrcheck
|
||||
- sqlclosecheck
|
||||
- staticcheck
|
||||
# - stylecheck
|
||||
- tagliatelle
|
||||
- tenv
|
||||
- testpackage
|
||||
- thelper
|
||||
- tparallel
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
# - varnamelen
|
||||
- wastedassign
|
||||
- whitespace
|
||||
- wrapcheck
|
||||
# - wsl
|
||||
- asasalint
|
||||
- usestdlibvars
|
||||
- interfacebloat
|
||||
- logrlint
|
||||
- reassign
|
||||
|
||||
linters-settings:
|
||||
dupl:
|
||||
threshold: 400
|
||||
lll:
|
||||
line-length: 170
|
||||
gocyclo:
|
||||
min-complexity: 30
|
||||
revive:
|
||||
rules:
|
||||
- name: var-naming
|
||||
arguments:
|
||||
- [ "ID", "API", "JSON" ] # AllowList
|
||||
- [ ] # DenyList
|
||||
gomnd:
|
||||
ignored-functions:
|
||||
- os.WriteFile
|
||||
gomoddirectives:
|
||||
replace-local: true
|
||||
gosec:
|
||||
config:
|
||||
G306: "0644"
|
||||
wrapcheck:
|
||||
ignoreSigs:
|
||||
# defaults
|
||||
- .Errorf(
|
||||
- errors.New(
|
||||
- errors.Unwrap(
|
||||
- .Wrap(
|
||||
- .Wrapf(
|
||||
- .WithMessage(
|
||||
- .WithMessagef(
|
||||
- .WithStack(
|
||||
# from kyaml's errors package
|
||||
- .WrapPrefixf(
|
||||
|
||||
issues:
|
||||
new-from-rev: c94b5d8f2 # enables us to enforce a larger set of linters for new code than pass on existing code
|
||||
max-same-issues: 0
|
||||
exclude-rules:
|
||||
- linters:
|
||||
- revive
|
||||
text: "don't use leading"
|
||||
- linters:
|
||||
- staticcheck
|
||||
text: "SA1019: kioutil.Legacy"
|
||||
349
Makefile
349
Makefile
@@ -3,6 +3,8 @@
|
||||
#
|
||||
# Makefile for kustomize CLI and API.
|
||||
|
||||
LATEST_V4_RELEASE=v4.5.6
|
||||
|
||||
SHELL := /usr/bin/env bash
|
||||
GOOS = $(shell go env GOOS)
|
||||
GOARCH = $(shell go env GOARCH)
|
||||
@@ -11,8 +13,6 @@ ifeq ($(MYGOBIN),)
|
||||
MYGOBIN = $(shell go env GOPATH)/bin
|
||||
endif
|
||||
export PATH := $(MYGOBIN):$(PATH)
|
||||
MODULES := '"cmd/config" "api/" "kustomize/" "kyaml/"'
|
||||
LATEST_V4_RELEASE=v4.5.2
|
||||
|
||||
# Provide defaults for REPO_OWNER and REPO_NAME if not present.
|
||||
# Typically these values would be provided by Prow.
|
||||
@@ -24,48 +24,35 @@ ifndef REPO_NAME
|
||||
REPO_NAME := "kustomize"
|
||||
endif
|
||||
|
||||
.PHONY: all
|
||||
all: install-tools verify-kustomize
|
||||
|
||||
.PHONY: verify-kustomize
|
||||
verify-kustomize: \
|
||||
lint-kustomize \
|
||||
test-unit-kustomize-all \
|
||||
test-examples-kustomize-against-HEAD \
|
||||
test-examples-kustomize-against-v4-release
|
||||
# --- Plugins ---
|
||||
include Makefile-plugins.mk
|
||||
|
||||
# The following target referenced by a file in
|
||||
# https://github.com/kubernetes/test-infra/tree/master/config/jobs/kubernetes-sigs/kustomize
|
||||
.PHONY: prow-presubmit-check
|
||||
prow-presubmit-check: \
|
||||
install-tools \
|
||||
lint-kustomize \
|
||||
test-unit-kustomize-all \
|
||||
test-unit-cmd-all \
|
||||
test-go-mod \
|
||||
test-examples-kustomize-against-HEAD \
|
||||
test-examples-kustomize-against-v4-release
|
||||
|
||||
.PHONY: verify-kustomize-e2e
|
||||
verify-kustomize-e2e: test-examples-e2e-kustomize
|
||||
# --- Tool management ---
|
||||
include Makefile-tools.mk
|
||||
|
||||
# Other builds in this repo might want a different linter version.
|
||||
# Without one Makefile to rule them all, the different makes
|
||||
# cannot assume that golanci-lint is at the version they want.
|
||||
# This installs what kustomize wants to use.
|
||||
$(MYGOBIN)/golangci-lint-kustomize:
|
||||
rm -f $(CURDIR)/hack/golangci-lint
|
||||
GOBIN=$(CURDIR)/hack go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.23.8
|
||||
mv $(CURDIR)/hack/golangci-lint $(MYGOBIN)/golangci-lint-kustomize
|
||||
.PHONY: install-tools
|
||||
install-tools: \
|
||||
install-local-tools \
|
||||
install-out-of-tree-tools
|
||||
|
||||
$(MYGOBIN)/mdrip:
|
||||
go install github.com/monopole/mdrip@v1.0.2
|
||||
.PHONY: uninstall-tools
|
||||
uninstall-tools: \
|
||||
uninstall-local-tools \
|
||||
uninstall-out-of-tree-tools
|
||||
|
||||
$(MYGOBIN)/stringer:
|
||||
go get golang.org/x/tools/cmd/stringer
|
||||
.PHONY: install-local-tools
|
||||
install-local-tools: \
|
||||
$(MYGOBIN)/gorepomod \
|
||||
$(MYGOBIN)/k8scopy \
|
||||
$(MYGOBIN)/pluginator
|
||||
|
||||
$(MYGOBIN)/goimports:
|
||||
go get golang.org/x/tools/cmd/goimports
|
||||
.PHONY: uninstall-local-tools
|
||||
uninstall-local-tools:
|
||||
rm -f $(MYGOBIN)/gorepomod
|
||||
rm -f $(MYGOBIN)/k8scopy
|
||||
rm -f $(MYGOBIN)/pluginator
|
||||
|
||||
# Build from local source.
|
||||
$(MYGOBIN)/gorepomod:
|
||||
@@ -82,173 +69,93 @@ $(MYGOBIN)/pluginator:
|
||||
cd cmd/pluginator; \
|
||||
go install .
|
||||
|
||||
|
||||
# --- Build targets ---
|
||||
|
||||
# Build from local source.
|
||||
$(MYGOBIN)/kustomize: build-kustomize-api
|
||||
cd kustomize; \
|
||||
go install .
|
||||
|
||||
.PHONY: install-tools
|
||||
install-tools: \
|
||||
$(MYGOBIN)/goimports \
|
||||
$(MYGOBIN)/golangci-lint-kustomize \
|
||||
$(MYGOBIN)/gorepomod \
|
||||
$(MYGOBIN)/helmV3 \
|
||||
$(MYGOBIN)/k8scopy \
|
||||
$(MYGOBIN)/mdrip \
|
||||
$(MYGOBIN)/pluginator \
|
||||
$(MYGOBIN)/stringer
|
||||
|
||||
### Begin kustomize plugin rules.
|
||||
#
|
||||
# The rules to deal with builtin plugins are a bit
|
||||
# complicated because
|
||||
#
|
||||
# - Every builtin plugin is a Go plugin -
|
||||
# meaning it gets its own module directory
|
||||
# (outside of the api module) with Go
|
||||
# code in a 'main' package per Go plugin rules.
|
||||
# - kustomize locates plugins using the
|
||||
# 'apiVersion' and 'kind' fields from the
|
||||
# plugin config file.
|
||||
# - k8s wants CamelCase in 'kind' fields.
|
||||
# - The module name (the last name in the path)
|
||||
# must be the lowercased 'kind' of the
|
||||
# plugin because Go and related tools
|
||||
# demand lowercase in import paths, but
|
||||
# allow CamelCase in file names.
|
||||
# - the generated code must live in the api
|
||||
# module (it's linked into the api).
|
||||
|
||||
# Where all generated builtin plugin code should go.
|
||||
pGen=api/internal/builtins
|
||||
# Where the builtin Go plugin modules live.
|
||||
pSrc=plugin/builtin
|
||||
|
||||
_builtinplugins = \
|
||||
AnnotationsTransformer.go \
|
||||
ConfigMapGenerator.go \
|
||||
IAMPolicyGenerator.go \
|
||||
HashTransformer.go \
|
||||
ImageTagTransformer.go \
|
||||
LabelTransformer.go \
|
||||
LegacyOrderTransformer.go \
|
||||
NamespaceTransformer.go \
|
||||
PatchJson6902Transformer.go \
|
||||
PatchStrategicMergeTransformer.go \
|
||||
PatchTransformer.go \
|
||||
PrefixTransformer.go \
|
||||
SuffixTransformer.go \
|
||||
ReplacementTransformer.go \
|
||||
ReplicaCountTransformer.go \
|
||||
SecretGenerator.go \
|
||||
ValueAddTransformer.go \
|
||||
HelmChartInflationGenerator.go
|
||||
|
||||
# Maintaining this explicit list of generated files, and
|
||||
# adding it as a dependency to a few targets, to assure
|
||||
# they get recreated if deleted. The rules below on how
|
||||
# to make them don't, by themselves, assure they will be
|
||||
# recreated if deleted.
|
||||
builtinplugins = $(patsubst %,$(pGen)/%,$(_builtinplugins))
|
||||
|
||||
# These rules are verbose, but assure that if a source file
|
||||
# is modified, the corresponding generated file, and only
|
||||
# that file, will be recreated.
|
||||
$(pGen)/AnnotationsTransformer.go: $(pSrc)/annotationstransformer/AnnotationsTransformer.go
|
||||
$(pGen)/ConfigMapGenerator.go: $(pSrc)/configmapgenerator/ConfigMapGenerator.go
|
||||
$(pGen)/GkeSaGenerator.go: $(pSrc)/gkesagenerator/GkeSaGenerator.go
|
||||
$(pGen)/HashTransformer.go: $(pSrc)/hashtransformer/HashTransformer.go
|
||||
$(pGen)/ImageTagTransformer.go: $(pSrc)/imagetagtransformer/ImageTagTransformer.go
|
||||
$(pGen)/LabelTransformer.go: $(pSrc)/labeltransformer/LabelTransformer.go
|
||||
$(pGen)/LegacyOrderTransformer.go: $(pSrc)/legacyordertransformer/LegacyOrderTransformer.go
|
||||
$(pGen)/NamespaceTransformer.go: $(pSrc)/namespacetransformer/NamespaceTransformer.go
|
||||
$(pGen)/PatchJson6902Transformer.go: $(pSrc)/patchjson6902transformer/PatchJson6902Transformer.go
|
||||
$(pGen)/PatchStrategicMergeTransformer.go: $(pSrc)/patchstrategicmergetransformer/PatchStrategicMergeTransformer.go
|
||||
$(pGen)/PatchTransformer.go: $(pSrc)/patchtransformer/PatchTransformer.go
|
||||
$(pGen)/PrefixTransformer.go: $(pSrc)/prefixtransformer/PrefixTransformer.go
|
||||
$(pGen)/SuffixTransformer.go: $(pSrc)/suffixtransformer/SuffixTransformer.go
|
||||
$(pGen)/ReplacementTransformer.go: $(pSrc)/replacementtransformer/ReplacementTransformer.go
|
||||
$(pGen)/ReplicaCountTransformer.go: $(pSrc)/replicacounttransformer/ReplicaCountTransformer.go
|
||||
$(pGen)/SecretGenerator.go: $(pSrc)/secretgenerator/SecretGenerator.go
|
||||
$(pGen)/ValueAddTransformer.go: $(pSrc)/valueaddtransformer/ValueAddTransformer.go
|
||||
$(pGen)/HelmChartInflationGenerator.go: $(pSrc)/helmchartinflationgenerator/HelmChartInflationGenerator.go
|
||||
|
||||
# The (verbose but portable) Makefile way to convert to lowercase.
|
||||
toLowerCase = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$1))))))))))))))))))))))))))
|
||||
|
||||
$(pGen)/%.go: $(MYGOBIN)/pluginator
|
||||
@echo "generating $*"
|
||||
( \
|
||||
set -e; \
|
||||
cd $(pSrc)/$(call toLowerCase,$*); \
|
||||
go generate .; \
|
||||
cd ../../../$(pGen); \
|
||||
$(MYGOBIN)/goimports -w $*.go \
|
||||
)
|
||||
|
||||
# Target is for debugging.
|
||||
.PHONY: generate-kustomize-builtin-plugins
|
||||
generate-kustomize-builtin-plugins: $(builtinplugins)
|
||||
|
||||
.PHONY: build-kustomize-external-go-plugin
|
||||
build-kustomize-external-go-plugin:
|
||||
./hack/buildExternalGoPlugins.sh ./plugin
|
||||
|
||||
.PHONY: clean-kustomize-external-go-plugin
|
||||
clean-kustomize-external-go-plugin:
|
||||
./hack/buildExternalGoPlugins.sh ./plugin clean
|
||||
|
||||
### End kustomize plugin rules.
|
||||
|
||||
.PHONY: lint-kustomize
|
||||
lint-kustomize: $(MYGOBIN)/golangci-lint-kustomize $(builtinplugins)
|
||||
cd api; $(MYGOBIN)/golangci-lint-kustomize \
|
||||
-c ../.golangci-kustomize.yml \
|
||||
run ./...
|
||||
cd kustomize; $(MYGOBIN)/golangci-lint-kustomize \
|
||||
-c ../.golangci-kustomize.yml \
|
||||
run ./...
|
||||
cd cmd/pluginator; $(MYGOBIN)/golangci-lint-kustomize \
|
||||
-c ../../.golangci-kustomize.yml \
|
||||
run ./...
|
||||
kustomize: $(MYGOBIN)/kustomize
|
||||
|
||||
# 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 ./...
|
||||
build-kustomize-api: $(MYGOBIN)/goimports $(builtinplugins)
|
||||
cd api; $(MAKE) build
|
||||
|
||||
.PHONY: generate-kustomize-api
|
||||
generate-kustomize-api: $(MYGOBIN)/k8scopy
|
||||
cd api; go generate ./...
|
||||
generate-kustomize-api:
|
||||
cd api; $(MAKE) generate
|
||||
|
||||
.PHONY: test-unit-kustomize-api
|
||||
test-unit-kustomize-api: build-kustomize-api
|
||||
cd api; go test ./... -ldflags "-X sigs.k8s.io/kustomize/api/provenance.version=v444.333.222"
|
||||
cd api/krusty; OPENAPI_TEST=true go test -run TestCustomOpenAPIFieldFromComponentWithOverlays
|
||||
|
||||
# --- Verification targets ---
|
||||
.PHONY: verify-kustomize-repo
|
||||
verify-kustomize-repo: \
|
||||
install-tools \
|
||||
lint \
|
||||
check-license \
|
||||
test-unit-all \
|
||||
build-non-plugin-all \
|
||||
test-go-mod \
|
||||
test-examples-kustomize-against-HEAD \
|
||||
test-examples-kustomize-against-v4-release
|
||||
|
||||
# The following target referenced by a file in
|
||||
# https://github.com/kubernetes/test-infra/tree/master/config/jobs/kubernetes-sigs/kustomize
|
||||
.PHONY: prow-presubmit-check
|
||||
prow-presubmit-check: \
|
||||
install-tools \
|
||||
test-unit-kustomize-plugins \
|
||||
test-go-mod \
|
||||
build-non-plugin-all \
|
||||
test-examples-kustomize-against-HEAD \
|
||||
test-examples-kustomize-against-v4-release
|
||||
|
||||
.PHONY: license
|
||||
license: $(MYGOBIN)/addlicense
|
||||
./hack/add-license.sh run
|
||||
|
||||
.PHONY: check-license
|
||||
check-license: $(MYGOBIN)/addlicense
|
||||
./hack/add-license.sh check
|
||||
|
||||
.PHONY: lint
|
||||
lint: $(MYGOBIN)/golangci-lint $(MYGOBIN)/goimports $(builtinplugins)
|
||||
./hack/for-each-module.sh "make lint"
|
||||
|
||||
.PHONY: test-unit-all
|
||||
test-unit-all: \
|
||||
test-unit-non-plugin \
|
||||
test-unit-kustomize-plugins
|
||||
|
||||
# This target is used by our Github Actions CI to run unit tests for all non-plugin modules in multiple GOOS environments.
|
||||
.PHONY: test-unit-non-plugin
|
||||
test-unit-non-plugin:
|
||||
./hack/for-each-module.sh "make test" "./plugin/*" 15
|
||||
|
||||
.PHONY: build-non-plugin-all
|
||||
build-non-plugin-all:
|
||||
./hack/for-each-module.sh "make build" "./plugin/*" 15
|
||||
|
||||
.PHONY: test-unit-kustomize-plugins
|
||||
test-unit-kustomize-plugins:
|
||||
./hack/testUnitKustomizePlugins.sh
|
||||
|
||||
.PHONY: test-unit-kustomize-cli
|
||||
test-unit-kustomize-cli:
|
||||
cd kustomize; go test ./...
|
||||
|
||||
.PHONY: test-unit-kustomize-all
|
||||
test-unit-kustomize-all: \
|
||||
test-unit-kustomize-api \
|
||||
test-unit-kustomize-cli \
|
||||
test-unit-kustomize-plugins
|
||||
|
||||
test-unit-cmd-all:
|
||||
./hack/kyaml-pre-commit.sh
|
||||
.PHONY: functions-examples-all
|
||||
functions-examples-all:
|
||||
for dir in $(abspath $(wildcard functions/examples/*/.)); do \
|
||||
echo -e "\n---Running make tasks for function $$dir---"; \
|
||||
set -e; \
|
||||
cd $$dir; $(MAKE) all; \
|
||||
done
|
||||
|
||||
test-go-mod:
|
||||
./hack/check-go-mod.sh
|
||||
./hack/for-each-module.sh "go list -m -json all > /dev/null && go mod tidy -v"
|
||||
|
||||
.PHONY:
|
||||
test-examples-e2e-kustomize: $(MYGOBIN)/mdrip $(MYGOBIN)/kind
|
||||
verify-kustomize-e2e: $(MYGOBIN)/mdrip $(MYGOBIN)/kind
|
||||
( \
|
||||
set -e; \
|
||||
/bin/rm -f $(MYGOBIN)/kustomize; \
|
||||
@@ -265,85 +172,13 @@ test-examples-kustomize-against-HEAD: $(MYGOBIN)/kustomize $(MYGOBIN)/mdrip
|
||||
test-examples-kustomize-against-v4-release: $(MYGOBIN)/mdrip
|
||||
./hack/testExamplesAgainstKustomize.sh v4@$(LATEST_V4_RELEASE)
|
||||
|
||||
# linux only.
|
||||
# This is for testing an example plugin that
|
||||
# uses kubeval for validation.
|
||||
# Don't want to add a hard dependence in go.mod file
|
||||
# to github.com/instrumenta/kubeval.
|
||||
# Instead, download the binary.
|
||||
$(MYGOBIN)/kubeval:
|
||||
( \
|
||||
set -e; \
|
||||
d=$(shell mktemp -d); cd $$d; \
|
||||
wget https://github.com/instrumenta/kubeval/releases/latest/download/kubeval-$(GOOS)-$(GOARCH).tar.gz; \
|
||||
tar xf kubeval-$(GOOS)-$(GOARCH).tar.gz; \
|
||||
mv kubeval $(MYGOBIN); \
|
||||
rm -rf $$d; \
|
||||
)
|
||||
|
||||
# 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 binaries.
|
||||
$(MYGOBIN)/helmV2:
|
||||
( \
|
||||
set -e; \
|
||||
d=$(shell mktemp -d); cd $$d; \
|
||||
tgzFile=helm-v2.13.1-$(GOOS)-$(GOARCH).tar.gz; \
|
||||
wget https://storage.googleapis.com/kubernetes-helm/$$tgzFile; \
|
||||
tar -xvzf $$tgzFile; \
|
||||
mv $(GOOS)-$(GOARCH)/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.6.3-$(GOOS)-$(GOARCH).tar.gz; \
|
||||
wget https://get.helm.sh/$$tgzFile; \
|
||||
tar -xvzf $$tgzFile; \
|
||||
mv $(GOOS)-$(GOARCH)/helm $(MYGOBIN)/helmV3; \
|
||||
rm -rf $$d \
|
||||
)
|
||||
|
||||
$(MYGOBIN)/kind:
|
||||
( \
|
||||
set -e; \
|
||||
d=$(shell mktemp -d); cd $$d; \
|
||||
wget -O ./kind https://github.com/kubernetes-sigs/kind/releases/download/v0.7.0/kind-$(GOOS)-$(GOARCH); \
|
||||
chmod +x ./kind; \
|
||||
mv ./kind $(MYGOBIN); \
|
||||
rm -rf $$d; \
|
||||
)
|
||||
|
||||
# linux only.
|
||||
$(MYGOBIN)/gh:
|
||||
( \
|
||||
set -e; \
|
||||
d=$(shell mktemp -d); cd $$d; \
|
||||
tgzFile=gh_1.0.0_$(GOOS)_$(GOARCH).tar.gz; \
|
||||
wget https://github.com/cli/cli/releases/download/v1.0.0/$$tgzFile; \
|
||||
tar -xvzf $$tgzFile; \
|
||||
mv gh_1.0.0_$(GOOS)_$(GOARCH)/bin/gh $(MYGOBIN)/gh; \
|
||||
rm -rf $$d \
|
||||
)
|
||||
|
||||
# --- Cleanup targets ---
|
||||
.PHONY: clean
|
||||
clean: clean-kustomize-external-go-plugin
|
||||
clean: clean-kustomize-external-go-plugin uninstall-tools
|
||||
go clean --cache
|
||||
rm -f $(builtinplugins)
|
||||
rm -f $(MYGOBIN)/goimports
|
||||
rm -f $(MYGOBIN)/golangci-lint-kustomize
|
||||
rm -f $(MYGOBIN)/kustomize
|
||||
rm -f $(MYGOBIN)/mdrip
|
||||
rm -f $(MYGOBIN)/stringer
|
||||
|
||||
# Handle pluginator manually.
|
||||
# rm -f $(MYGOBIN)/pluginator
|
||||
|
||||
# Nuke the site from orbit. It's the only way to be sure.
|
||||
.PHONY: nuke
|
||||
|
||||
38
Makefile-modules.mk
Normal file
38
Makefile-modules.mk
Normal file
@@ -0,0 +1,38 @@
|
||||
# Copyright 2022 The Kubernetes Authors.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
MYGOBIN = $(shell go env GOBIN)
|
||||
ifeq ($(MYGOBIN),)
|
||||
MYGOBIN = $(shell go env GOPATH)/bin
|
||||
endif
|
||||
export PATH := $(MYGOBIN):$(PATH)
|
||||
|
||||
# only set this if not already set, so importing makefiles can override it
|
||||
export KUSTOMIZE_ROOT ?= $(shell pwd | sed -E 's|(.*\/kustomize)/(.*)|\1|')
|
||||
include $(KUSTOMIZE_ROOT)/Makefile-tools.mk
|
||||
|
||||
.PHONY: lint test fix fmt tidy vet build
|
||||
|
||||
lint: $(MYGOBIN)/golangci-lint
|
||||
$(MYGOBIN)/golangci-lint \
|
||||
-c $$KUSTOMIZE_ROOT/.golangci.yml \
|
||||
--path-prefix $(shell pwd | sed -E 's|(.*\/kustomize)/(.*)|\2|') \
|
||||
run ./...
|
||||
|
||||
test:
|
||||
go test -v -timeout 45m -cover ./...
|
||||
|
||||
fix:
|
||||
go fix ./...
|
||||
|
||||
fmt:
|
||||
go fmt ./...
|
||||
|
||||
tidy:
|
||||
go mod tidy
|
||||
|
||||
vet:
|
||||
go vet ./...
|
||||
|
||||
build:
|
||||
go build -v -o $(MYGOBIN) ./...
|
||||
102
Makefile-plugins.mk
Normal file
102
Makefile-plugins.mk
Normal file
@@ -0,0 +1,102 @@
|
||||
# Copyright 2022 The Kubernetes Authors.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
### Kustomize plugin rules.
|
||||
#
|
||||
# The rules to deal with builtin plugins are a bit
|
||||
# complicated because
|
||||
#
|
||||
# - Every builtin plugin is a Go plugin -
|
||||
# meaning it gets its own module directory
|
||||
# (outside of the api module) with Go
|
||||
# code in a 'main' package per Go plugin rules.
|
||||
# - kustomize locates plugins using the
|
||||
# 'apiVersion' and 'kind' fields from the
|
||||
# plugin config file.
|
||||
# - k8s wants CamelCase in 'kind' fields.
|
||||
# - The module name (the last name in the path)
|
||||
# must be the lowercased 'kind' of the
|
||||
# plugin because Go and related tools
|
||||
# demand lowercase in import paths, but
|
||||
# allow CamelCase in file names.
|
||||
# - the generated code must live in the api
|
||||
# module (it's linked into the api).
|
||||
|
||||
# Where all generated builtin plugin code should go.
|
||||
pGen=api/internal/builtins
|
||||
# Where the builtin Go plugin modules live.
|
||||
pSrc=plugin/builtin
|
||||
|
||||
_builtinplugins = \
|
||||
AnnotationsTransformer.go \
|
||||
ConfigMapGenerator.go \
|
||||
IAMPolicyGenerator.go \
|
||||
HashTransformer.go \
|
||||
ImageTagTransformer.go \
|
||||
LabelTransformer.go \
|
||||
LegacyOrderTransformer.go \
|
||||
NamespaceTransformer.go \
|
||||
PatchJson6902Transformer.go \
|
||||
PatchStrategicMergeTransformer.go \
|
||||
PatchTransformer.go \
|
||||
PrefixTransformer.go \
|
||||
SuffixTransformer.go \
|
||||
ReplacementTransformer.go \
|
||||
ReplicaCountTransformer.go \
|
||||
SecretGenerator.go \
|
||||
ValueAddTransformer.go \
|
||||
HelmChartInflationGenerator.go
|
||||
|
||||
# Maintaining this explicit list of generated files, and
|
||||
# adding it as a dependency to a few targets, to assure
|
||||
# they get recreated if deleted. The rules below on how
|
||||
# to make them don't, by themselves, assure they will be
|
||||
# recreated if deleted.
|
||||
builtinplugins = $(patsubst %,$(pGen)/%,$(_builtinplugins))
|
||||
|
||||
# These rules are verbose, but assure that if a source file
|
||||
# is modified, the corresponding generated file, and only
|
||||
# that file, will be recreated.
|
||||
$(pGen)/AnnotationsTransformer.go: $(pSrc)/annotationstransformer/AnnotationsTransformer.go
|
||||
$(pGen)/ConfigMapGenerator.go: $(pSrc)/configmapgenerator/ConfigMapGenerator.go
|
||||
$(pGen)/GkeSaGenerator.go: $(pSrc)/gkesagenerator/GkeSaGenerator.go
|
||||
$(pGen)/HashTransformer.go: $(pSrc)/hashtransformer/HashTransformer.go
|
||||
$(pGen)/ImageTagTransformer.go: $(pSrc)/imagetagtransformer/ImageTagTransformer.go
|
||||
$(pGen)/LabelTransformer.go: $(pSrc)/labeltransformer/LabelTransformer.go
|
||||
$(pGen)/LegacyOrderTransformer.go: $(pSrc)/legacyordertransformer/LegacyOrderTransformer.go
|
||||
$(pGen)/NamespaceTransformer.go: $(pSrc)/namespacetransformer/NamespaceTransformer.go
|
||||
$(pGen)/PatchJson6902Transformer.go: $(pSrc)/patchjson6902transformer/PatchJson6902Transformer.go
|
||||
$(pGen)/PatchStrategicMergeTransformer.go: $(pSrc)/patchstrategicmergetransformer/PatchStrategicMergeTransformer.go
|
||||
$(pGen)/PatchTransformer.go: $(pSrc)/patchtransformer/PatchTransformer.go
|
||||
$(pGen)/PrefixTransformer.go: $(pSrc)/prefixtransformer/PrefixTransformer.go
|
||||
$(pGen)/SuffixTransformer.go: $(pSrc)/suffixtransformer/SuffixTransformer.go
|
||||
$(pGen)/ReplacementTransformer.go: $(pSrc)/replacementtransformer/ReplacementTransformer.go
|
||||
$(pGen)/ReplicaCountTransformer.go: $(pSrc)/replicacounttransformer/ReplicaCountTransformer.go
|
||||
$(pGen)/SecretGenerator.go: $(pSrc)/secretgenerator/SecretGenerator.go
|
||||
$(pGen)/ValueAddTransformer.go: $(pSrc)/valueaddtransformer/ValueAddTransformer.go
|
||||
$(pGen)/HelmChartInflationGenerator.go: $(pSrc)/helmchartinflationgenerator/HelmChartInflationGenerator.go
|
||||
|
||||
# The (verbose but portable) Makefile way to convert to lowercase.
|
||||
toLowerCase = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$1))))))))))))))))))))))))))
|
||||
|
||||
$(pGen)/%.go: $(MYGOBIN)/pluginator
|
||||
@echo "generating $*"
|
||||
( \
|
||||
set -e; \
|
||||
cd $(pSrc)/$(call toLowerCase,$*); \
|
||||
go generate .; \
|
||||
cd ../../../$(pGen); \
|
||||
$(MYGOBIN)/goimports -w $*.go \
|
||||
)
|
||||
|
||||
# Target is for debugging.
|
||||
.PHONY: generate-kustomize-builtin-plugins
|
||||
generate-kustomize-builtin-plugins: $(builtinplugins)
|
||||
|
||||
.PHONY: build-kustomize-external-go-plugin
|
||||
build-kustomize-external-go-plugin:
|
||||
./hack/buildExternalGoPlugins.sh ./plugin
|
||||
|
||||
.PHONY: clean-kustomize-external-go-plugin
|
||||
clean-kustomize-external-go-plugin:
|
||||
./hack/buildExternalGoPlugins.sh ./plugin clean
|
||||
105
Makefile-tools.mk
Normal file
105
Makefile-tools.mk
Normal file
@@ -0,0 +1,105 @@
|
||||
# Copyright 2022 The Kubernetes Authors.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
GOLANGCI_LINT_VERSION=v1.49.0
|
||||
|
||||
MYGOBIN = $(shell go env GOBIN)
|
||||
ifeq ($(MYGOBIN),)
|
||||
MYGOBIN = $(shell go env GOPATH)/bin
|
||||
endif
|
||||
export PATH := $(MYGOBIN):$(PATH)
|
||||
|
||||
# determines whether to run tests that only behave locally; can be overridden by override variable
|
||||
export IS_LOCAL = false
|
||||
|
||||
.PHONY: install-out-of-tree-tools
|
||||
install-out-of-tree-tools: \
|
||||
$(MYGOBIN)/goimports \
|
||||
$(MYGOBIN)/golangci-lint \
|
||||
$(MYGOBIN)/helmV3 \
|
||||
$(MYGOBIN)/mdrip \
|
||||
$(MYGOBIN)/stringer \
|
||||
$(MYGOBIN)/goimports
|
||||
|
||||
.PHONY: uninstall-out-of-tree-tools
|
||||
uninstall-out-of-tree-tools:
|
||||
rm -f $(MYGOBIN)/goimports
|
||||
rm -f $(MYGOBIN)/golangci-lint
|
||||
rm -f $(MYGOBIN)/helmV3
|
||||
rm -f $(MYGOBIN)/mdrip
|
||||
rm -f $(MYGOBIN)/stringer
|
||||
|
||||
$(MYGOBIN)/golangci-lint:
|
||||
go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION)
|
||||
|
||||
$(MYGOBIN)/mdrip:
|
||||
go install github.com/monopole/mdrip@v1.0.2
|
||||
|
||||
$(MYGOBIN)/stringer:
|
||||
go install golang.org/x/tools/cmd/stringer@latest
|
||||
|
||||
$(MYGOBIN)/goimports:
|
||||
go install golang.org/x/tools/cmd/goimports@latest
|
||||
|
||||
$(MYGOBIN)/mdtogo:
|
||||
go install sigs.k8s.io/kustomize/cmd/mdtogo@latest
|
||||
|
||||
$(MYGOBIN)/addlicense:
|
||||
go install github.com/google/addlicense@latest
|
||||
|
||||
$(MYGOBIN)/statik:
|
||||
go install github.com/rakyll/statik@latest
|
||||
|
||||
$(MYGOBIN)/goreleaser:
|
||||
go install github.com/goreleaser/goreleaser@v0.179.0 # https://github.com/kubernetes-sigs/kustomize/issues/4542
|
||||
|
||||
$(MYGOBIN)/kind:
|
||||
( \
|
||||
set -e; \
|
||||
d=$(shell mktemp -d); cd $$d; \
|
||||
wget -O ./kind https://github.com/kubernetes-sigs/kind/releases/download/v0.7.0/kind-$(GOOS)-$(GOARCH); \
|
||||
chmod +x ./kind; \
|
||||
mv ./kind $(MYGOBIN); \
|
||||
rm -rf $$d; \
|
||||
)
|
||||
|
||||
# linux only.
|
||||
$(MYGOBIN)/gh:
|
||||
( \
|
||||
set -e; \
|
||||
d=$(shell mktemp -d); cd $$d; \
|
||||
tgzFile=gh_1.0.0_$(GOOS)_$(GOARCH).tar.gz; \
|
||||
wget https://github.com/cli/cli/releases/download/v1.0.0/$$tgzFile; \
|
||||
tar -xvzf $$tgzFile; \
|
||||
mv gh_1.0.0_$(GOOS)_$(GOARCH)/bin/gh $(MYGOBIN)/gh; \
|
||||
rm -rf $$d \
|
||||
)
|
||||
|
||||
# linux only.
|
||||
# This is for testing an example plugin that
|
||||
# uses kubeval for validation.
|
||||
# Don't want to add a hard dependence in go.mod file
|
||||
# to github.com/instrumenta/kubeval.
|
||||
# Instead, download the binary.
|
||||
$(MYGOBIN)/kubeval:
|
||||
( \
|
||||
set -e; \
|
||||
d=$(shell mktemp -d); cd $$d; \
|
||||
wget https://github.com/instrumenta/kubeval/releases/latest/download/kubeval-$(GOOS)-$(GOARCH).tar.gz; \
|
||||
tar xf kubeval-$(GOOS)-$(GOARCH).tar.gz; \
|
||||
mv kubeval $(MYGOBIN); \
|
||||
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.6.3-$(GOOS)-$(GOARCH).tar.gz; \
|
||||
wget https://get.helm.sh/$$tgzFile; \
|
||||
tar -xvzf $$tgzFile; \
|
||||
mv $(GOOS)-$(GOARCH)/helm $(MYGOBIN)/helmV3; \
|
||||
rm -rf $$d \
|
||||
)
|
||||
@@ -11,6 +11,8 @@ aliases:
|
||||
- knverey
|
||||
- natasha41575
|
||||
- yuwenma
|
||||
- annasong20
|
||||
- koba1t
|
||||
|
||||
kyaml-approvers:
|
||||
- mengqiy
|
||||
|
||||
13
api/Makefile
Normal file
13
api/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
# Copyright 2022 The Kubernetes Authors.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
include ../Makefile-modules.mk
|
||||
|
||||
test:
|
||||
go test -v -timeout 45m -cover ./... -ldflags "-X sigs.k8s.io/kustomize/api/provenance.version=v444.333.222"
|
||||
|
||||
build:
|
||||
go build -ldflags "-X sigs.k8s.io/kustomize/api/provenance.version=v444.333.222" ./...
|
||||
|
||||
generate: $(MYGOBIN)/k8scopy $(MYGOBIN)/stringer
|
||||
go generate ./...
|
||||
@@ -285,7 +285,7 @@ spec:
|
||||
t.Run(tn, func(t *testing.T) {
|
||||
filter := tc.filter
|
||||
filter.WithMutationTracker(tc.setEntryCallback)
|
||||
filter.FsSlice = append(annosFs, tc.fsslice...)
|
||||
filter.FsSlice = append(annosFs, tc.fsslice...) //nolint:gocritic
|
||||
if !assert.Equal(t,
|
||||
strings.TrimSpace(tc.expectedOutput),
|
||||
strings.TrimSpace(filtertest_test.RunFilter(t, tc.input, filter))) {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package filters
|
||||
|
||||
// Package filters collects various implementations
|
||||
|
||||
@@ -8,10 +8,10 @@ import (
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filters/filtersutil"
|
||||
"sigs.k8s.io/kustomize/api/internal/utils"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/resid"
|
||||
"sigs.k8s.io/kustomize/kyaml/utils"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package filtersutil
|
||||
|
||||
import (
|
||||
@@ -9,13 +12,13 @@ type SetFn func(*yaml.RNode) error
|
||||
|
||||
// SetScalar returns a SetFn to set a scalar value
|
||||
func SetScalar(value string) SetFn {
|
||||
return func(node *yaml.RNode) error {
|
||||
return node.PipeE(yaml.FieldSetter{StringValue: value})
|
||||
}
|
||||
return SetEntry("", value, yaml.NodeTagEmpty)
|
||||
}
|
||||
|
||||
// SetEntry returns a SetFn to set an entry in a map
|
||||
func SetEntry(key, value, tag string) SetFn {
|
||||
// SetEntry returns a SetFn to set a field or a map entry to a value.
|
||||
// It can be used with an empty name to set both a value and a tag on a scalar node.
|
||||
// When setting only a value on a scalar node, use SetScalar instead.
|
||||
func SetEntry(name, value, tag string) SetFn {
|
||||
n := &yaml.Node{
|
||||
Kind: yaml.ScalarNode,
|
||||
Value: value,
|
||||
@@ -23,7 +26,7 @@ func SetEntry(key, value, tag string) SetFn {
|
||||
}
|
||||
return func(node *yaml.RNode) error {
|
||||
return node.PipeE(yaml.FieldSetter{
|
||||
Name: key,
|
||||
Name: name,
|
||||
Value: yaml.NewRNode(n),
|
||||
})
|
||||
}
|
||||
@@ -31,36 +34,72 @@ func SetEntry(key, value, tag string) SetFn {
|
||||
|
||||
type TrackableSetter struct {
|
||||
// SetValueCallback will be invoked each time a field is set
|
||||
setValueCallback func(key, value, tag string, node *yaml.RNode)
|
||||
setValueCallback func(name, value, tag string, node *yaml.RNode)
|
||||
}
|
||||
|
||||
// WithMutationTracker registers a callback which will be invoked each time a field is mutated
|
||||
func (s *TrackableSetter) WithMutationTracker(callback func(key, value, tag string, node *yaml.RNode)) {
|
||||
func (s *TrackableSetter) WithMutationTracker(callback func(key, value, tag string, node *yaml.RNode)) *TrackableSetter {
|
||||
s.setValueCallback = callback
|
||||
return s
|
||||
}
|
||||
|
||||
// SetScalar returns a SetFn to set a scalar value
|
||||
// SetScalar returns a SetFn to set a scalar value.
|
||||
// if a mutation tracker has been registered, the tracker will be invoked each
|
||||
// time a scalar is set
|
||||
func (s TrackableSetter) SetScalar(value string) SetFn {
|
||||
origSetScalar := SetScalar(value)
|
||||
return s.SetEntry("", value, yaml.NodeTagEmpty)
|
||||
}
|
||||
|
||||
// SetScalarIfEmpty returns a SetFn to set a scalar value only if it isn't already set.
|
||||
// If a mutation tracker has been registered, the tracker will be invoked each
|
||||
// time a scalar is actually set.
|
||||
func (s TrackableSetter) SetScalarIfEmpty(value string) SetFn {
|
||||
return s.SetEntryIfEmpty("", value, yaml.NodeTagEmpty)
|
||||
}
|
||||
|
||||
// SetEntry returns a SetFn to set a field or a map entry to a value.
|
||||
// It can be used with an empty name to set both a value and a tag on a scalar node.
|
||||
// When setting only a value on a scalar node, use SetScalar instead.
|
||||
// If a mutation tracker has been registered, the tracker will be invoked each
|
||||
// time an entry is set.
|
||||
func (s TrackableSetter) SetEntry(name, value, tag string) SetFn {
|
||||
origSetEntry := SetEntry(name, value, tag)
|
||||
return func(node *yaml.RNode) error {
|
||||
if s.setValueCallback != nil {
|
||||
s.setValueCallback("", value, "", node)
|
||||
s.setValueCallback(name, value, tag, node)
|
||||
}
|
||||
return origSetScalar(node)
|
||||
return origSetEntry(node)
|
||||
}
|
||||
}
|
||||
|
||||
// SetEntry returns a SetFn to set an entry in a map
|
||||
// if a mutation tracker has been registered, the tracker will be invoked each
|
||||
// time an entry is set
|
||||
func (s TrackableSetter) SetEntry(key, value, tag string) SetFn {
|
||||
// SetEntryIfEmpty returns a SetFn to set a field or a map entry to a value only if it isn't already set.
|
||||
// It can be used with an empty name to set both a value and a tag on a scalar node.
|
||||
// When setting only a value on a scalar node, use SetScalar instead.
|
||||
// If a mutation tracker has been registered, the tracker will be invoked each
|
||||
// time an entry is actually set.
|
||||
func (s TrackableSetter) SetEntryIfEmpty(key, value, tag string) SetFn {
|
||||
origSetEntry := SetEntry(key, value, tag)
|
||||
return func(node *yaml.RNode) error {
|
||||
if hasExistingValue(node, key) {
|
||||
return nil
|
||||
}
|
||||
if s.setValueCallback != nil {
|
||||
s.setValueCallback(key, value, tag, node)
|
||||
}
|
||||
return origSetEntry(node)
|
||||
}
|
||||
}
|
||||
|
||||
func hasExistingValue(node *yaml.RNode, key string) bool {
|
||||
if node.IsNilOrEmpty() {
|
||||
return false
|
||||
}
|
||||
if err := yaml.ErrorIfInvalid(node, yaml.ScalarNode); err == nil {
|
||||
return yaml.GetValue(node) != ""
|
||||
}
|
||||
entry := node.Field(key)
|
||||
if entry.IsNilOrEmpty() {
|
||||
return false
|
||||
}
|
||||
return yaml.GetValue(entry.Value) != ""
|
||||
}
|
||||
|
||||
108
api/filters/filtersutil/setters_test.go
Normal file
108
api/filters/filtersutil/setters_test.go
Normal file
@@ -0,0 +1,108 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package filtersutil_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"sigs.k8s.io/kustomize/api/filters/filtersutil"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
func TestTrackableSetter_SetScalarIfEmpty(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input *yaml.RNode
|
||||
value string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "sets null values",
|
||||
input: yaml.MakeNullNode(),
|
||||
value: "foo",
|
||||
want: "foo",
|
||||
},
|
||||
{
|
||||
name: "sets empty values",
|
||||
input: yaml.NewScalarRNode(""),
|
||||
value: "foo",
|
||||
want: "foo",
|
||||
},
|
||||
{
|
||||
name: "does not overwrite values",
|
||||
input: yaml.NewStringRNode("a"),
|
||||
value: "foo",
|
||||
want: "a",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
wasSet := false
|
||||
s := (&filtersutil.TrackableSetter{}).WithMutationTracker(func(_, _, _ string, _ *yaml.RNode) {
|
||||
wasSet = true
|
||||
})
|
||||
wantSet := tt.value == tt.want
|
||||
fn := s.SetScalarIfEmpty(tt.value)
|
||||
require.NoError(t, fn(tt.input))
|
||||
assert.Equal(t, tt.want, yaml.GetValue(tt.input))
|
||||
assert.Equal(t, wantSet, wasSet, "tracker invoked even though value was not changed")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrackableSetter_SetEntryIfEmpty(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input *yaml.RNode
|
||||
key string
|
||||
value string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "sets empty values",
|
||||
input: yaml.NewMapRNode(&map[string]string{"setMe": ""}),
|
||||
key: "setMe",
|
||||
value: "foo",
|
||||
want: "foo",
|
||||
},
|
||||
{
|
||||
name: "sets missing keys",
|
||||
input: yaml.NewMapRNode(&map[string]string{}),
|
||||
key: "setMe",
|
||||
value: "foo",
|
||||
want: "foo",
|
||||
},
|
||||
{
|
||||
name: "does not overwrite values",
|
||||
input: yaml.NewMapRNode(&map[string]string{"existing": "original"}),
|
||||
key: "existing",
|
||||
value: "foo",
|
||||
want: "original",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
wasSet := false
|
||||
s := (&filtersutil.TrackableSetter{}).WithMutationTracker(func(_, _, _ string, _ *yaml.RNode) {
|
||||
wasSet = true
|
||||
})
|
||||
wantSet := tt.value == tt.want
|
||||
fn := s.SetEntryIfEmpty(tt.key, tt.value, "")
|
||||
require.NoError(t, fn(tt.input))
|
||||
assert.Equal(t, tt.want, yaml.GetValue(tt.input.Field(tt.key).Value))
|
||||
assert.Equal(t, wantSet, wasSet, "tracker invoked even though value was not changed")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrackableSetter_SetEntryIfEmpty_BadInputNodeKind(t *testing.T) {
|
||||
fn := filtersutil.TrackableSetter{}.SetEntryIfEmpty("foo", "false", yaml.NodeTagBool)
|
||||
rn := yaml.NewListRNode("nope")
|
||||
rn.AppendToFieldPath("dummy", "path")
|
||||
assert.EqualError(t, fn(rn), `wrong node kind: expected MappingNode but got SequenceNode: node contents:
|
||||
- nope
|
||||
`)
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package gkesagenerator contains a kio.Filter that that generates a
|
||||
// iampolicy-related resources for a given cloud provider
|
||||
package iampolicygenerator
|
||||
|
||||
@@ -43,7 +43,7 @@ metadata:
|
||||
f.IAMPolicyGenerator.KubernetesService.Name)
|
||||
|
||||
if f.IAMPolicyGenerator.Namespace != "" {
|
||||
input = input + fmt.Sprintf("\n namespace: %s", f.IAMPolicyGenerator.Namespace)
|
||||
input += fmt.Sprintf("\n namespace: %s", f.IAMPolicyGenerator.Namespace)
|
||||
}
|
||||
|
||||
sa, err := yaml.Parse(input)
|
||||
|
||||
@@ -840,6 +840,45 @@ spec:
|
||||
},
|
||||
},
|
||||
},
|
||||
"updateimagesuffix": {
|
||||
input: `
|
||||
group: apps
|
||||
apiVersion: v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deploysuffix
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: redis:6.2.6
|
||||
name: redis
|
||||
`,
|
||||
expectedOutput: `
|
||||
group: apps
|
||||
apiVersion: v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deploysuffix
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: redis:6.2.6-alpine
|
||||
name: redis
|
||||
`,
|
||||
filter: Filter{
|
||||
ImageTag: types.Image{
|
||||
Name: "redis",
|
||||
TagSuffix: "-alpine",
|
||||
},
|
||||
},
|
||||
fsSlice: []types.FieldSpec{
|
||||
{
|
||||
Path: "spec/template/spec/containers[]/image",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for tn, tc := range testCases {
|
||||
|
||||
@@ -6,6 +6,7 @@ package imagetag
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/internal/utils"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
@@ -81,9 +82,7 @@ func (f findFieldsFilter) walk(node *yaml.RNode) error {
|
||||
return nil
|
||||
})
|
||||
case yaml.SequenceNode:
|
||||
return node.VisitElements(func(n *yaml.RNode) error {
|
||||
return f.walk(n)
|
||||
})
|
||||
return errors.Wrap(node.VisitElements(f.walk))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ package imagetag
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/filters/filtersutil"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/image"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
@@ -36,15 +37,19 @@ func (u imageTagUpdater) SetImageValue(rn *yaml.RNode) error {
|
||||
}
|
||||
|
||||
// overriding tag or digest will replace both original tag and digest values
|
||||
if u.ImageTag.NewTag != "" && u.ImageTag.Digest != "" {
|
||||
switch {
|
||||
case u.ImageTag.NewTag != "" && u.ImageTag.Digest != "":
|
||||
tag = u.ImageTag.NewTag
|
||||
digest = u.ImageTag.Digest
|
||||
} else if u.ImageTag.NewTag != "" {
|
||||
case u.ImageTag.NewTag != "":
|
||||
tag = u.ImageTag.NewTag
|
||||
digest = ""
|
||||
} else if u.ImageTag.Digest != "" {
|
||||
case u.ImageTag.Digest != "":
|
||||
tag = ""
|
||||
digest = u.ImageTag.Digest
|
||||
case u.ImageTag.TagSuffix != "":
|
||||
tag += u.ImageTag.TagSuffix
|
||||
digest = ""
|
||||
}
|
||||
|
||||
// build final image name
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package nameref contains a kio.Filter implementation of the kustomize
|
||||
// name reference transformer.
|
||||
package nameref
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package nameref
|
||||
|
||||
import (
|
||||
@@ -115,7 +118,9 @@ func (f Filter) setMapping(node *yaml.RNode) error {
|
||||
return err
|
||||
}
|
||||
oldName := nameNode.YNode().Value
|
||||
referral, err := f.selectReferral(oldName, candidates)
|
||||
// use allNamesAndNamespacesAreTheSame to compare referral candidates for functional identity,
|
||||
// because we source both name and namespace values from the referral in this case.
|
||||
referral, err := f.selectReferral(oldName, candidates, allNamesAndNamespacesAreTheSame)
|
||||
if err != nil || referral == nil {
|
||||
// Nil referral means nothing to do.
|
||||
return err
|
||||
@@ -164,8 +169,10 @@ func (f Filter) filterMapCandidatesByNamespace(
|
||||
}
|
||||
|
||||
func (f Filter) setScalar(node *yaml.RNode) error {
|
||||
// use allNamesAreTheSame to compare referral candidates for functional identity,
|
||||
// because we only source the name from the referral in this case.
|
||||
referral, err := f.selectReferral(
|
||||
node.YNode().Value, f.ReferralCandidates.Resources())
|
||||
node.YNode().Value, f.ReferralCandidates.Resources(), allNamesAreTheSame)
|
||||
if err != nil || referral == nil {
|
||||
// Nil referral means nothing to do.
|
||||
return err
|
||||
@@ -308,7 +315,9 @@ func (f Filter) sameCurrentNamespaceAsReferrer() sieveFunc {
|
||||
func (f Filter) selectReferral(
|
||||
// The name referral that may need to be updated.
|
||||
oldName string,
|
||||
candidates []*resource.Resource) (*resource.Resource, error) {
|
||||
candidates []*resource.Resource,
|
||||
// function that returns whether two referrals are identical for the purposes of the transformation
|
||||
candidatesIdentical func(resources []*resource.Resource) bool) (*resource.Resource, error) {
|
||||
candidates = doSieve(candidates, previousNameMatches(oldName))
|
||||
candidates = doSieve(candidates, previousIdSelectedByGvk(&f.ReferralTarget))
|
||||
candidates = doSieve(candidates, f.roleRefFilter())
|
||||
@@ -323,24 +332,21 @@ func (f Filter) selectReferral(
|
||||
if len(candidates) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if allNamesAreTheSame(candidates) {
|
||||
if candidatesIdentical(candidates) {
|
||||
// Just take the first one.
|
||||
return candidates[0], nil
|
||||
}
|
||||
ids := getIds(candidates)
|
||||
f.failureDetails(candidates)
|
||||
return nil, fmt.Errorf(" found multiple possible referrals: %s", ids)
|
||||
return nil, fmt.Errorf("found multiple possible referrals: %s\n%s", ids, f.failureDetails(candidates))
|
||||
}
|
||||
|
||||
func (f Filter) failureDetails(resources []*resource.Resource) {
|
||||
fmt.Printf(
|
||||
"\n**** Too many possible referral targets to referrer:\n%s\n",
|
||||
f.Referrer.MustYaml())
|
||||
func (f Filter) failureDetails(resources []*resource.Resource) string {
|
||||
msg := strings.Builder{}
|
||||
msg.WriteString(fmt.Sprintf("\n**** Too many possible referral targets to referrer:\n%s\n", f.Referrer.MustYaml()))
|
||||
for i, r := range resources {
|
||||
fmt.Printf(
|
||||
"--- possible referral %d:\n%s", i, r.MustYaml())
|
||||
fmt.Println("------")
|
||||
msg.WriteString(fmt.Sprintf("--- possible referral %d:\n%s\n", i, r.MustYaml()))
|
||||
}
|
||||
return msg.String()
|
||||
}
|
||||
|
||||
func allNamesAreTheSame(resources []*resource.Resource) bool {
|
||||
@@ -353,6 +359,17 @@ func allNamesAreTheSame(resources []*resource.Resource) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func allNamesAndNamespacesAreTheSame(resources []*resource.Resource) bool {
|
||||
name := resources[0].GetName()
|
||||
namespace := resources[0].GetNamespace()
|
||||
for i := 1; i < len(resources); i++ {
|
||||
if name != resources[i].GetName() || namespace != resources[i].GetNamespace() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func getIds(rs []*resource.Resource) string {
|
||||
var result []string
|
||||
for _, r := range rs {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package nameref
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package nameref
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package nameref
|
||||
|
||||
import (
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"sigs.k8s.io/kustomize/api/filters/filtersutil"
|
||||
"sigs.k8s.io/kustomize/api/filters/fsslice"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/resid"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
@@ -19,9 +20,28 @@ type Filter struct {
|
||||
// FsSlice contains the FieldSpecs to locate the namespace field
|
||||
FsSlice types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
|
||||
// UnsetOnly means only blank namespace fields will be set
|
||||
UnsetOnly bool `json:"unsetOnly" yaml:"unsetOnly"`
|
||||
|
||||
// SetRoleBindingSubjects determines which subject fields in RoleBinding and ClusterRoleBinding
|
||||
// objects will have their namespace fields set. Overrides field specs provided for these types, if any.
|
||||
// - defaultOnly (default): namespace will be set only on subjects named "default".
|
||||
// - allServiceAccounts: namespace will be set on all subjects with "kind: ServiceAccount"
|
||||
// - none: all subjects will be skipped.
|
||||
SetRoleBindingSubjects RoleBindingSubjectMode `json:"setRoleBindingSubjects" yaml:"setRoleBindingSubjects"`
|
||||
|
||||
trackableSetter filtersutil.TrackableSetter
|
||||
}
|
||||
|
||||
type RoleBindingSubjectMode string
|
||||
|
||||
const (
|
||||
DefaultSubjectsOnly RoleBindingSubjectMode = "defaultOnly"
|
||||
SubjectModeUnspecified RoleBindingSubjectMode = ""
|
||||
AllServiceAccountSubjects RoleBindingSubjectMode = "allServiceAccounts"
|
||||
NoSubjects RoleBindingSubjectMode = "none"
|
||||
)
|
||||
|
||||
var _ kio.Filter = Filter{}
|
||||
var _ kio.TrackableFilter = &Filter{}
|
||||
|
||||
@@ -36,47 +56,38 @@ func (ns Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
|
||||
// Run runs the filter on a single node rather than a slice
|
||||
func (ns Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
|
||||
// hacks for hardcoded types -- :(
|
||||
if err := ns.hacks(node); err != nil {
|
||||
// Special handling for metadata.namespace -- :(
|
||||
// never let SetEntry handle metadata.namespace--it will incorrectly include cluster-scoped resources
|
||||
ns.FsSlice = ns.removeMetaNamespaceFieldSpecs(ns.FsSlice)
|
||||
gvk := resid.GvkFromNode(node)
|
||||
if err := ns.metaNamespaceHack(node, gvk); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Remove the fieldspecs that are for hardcoded fields. The fieldspecs
|
||||
// exist for backwards compatibility with other implementations
|
||||
// of this transformation.
|
||||
// This implementation of the namespace transformation
|
||||
// Does not use the fieldspecs for implementing cases which
|
||||
// require hardcoded logic.
|
||||
ns.FsSlice = ns.removeFieldSpecsForHacks(ns.FsSlice)
|
||||
// Special handling for (cluster) role binding subjects -- :(
|
||||
if isRoleBinding(gvk.Kind) {
|
||||
ns.FsSlice = ns.removeRoleBindingSubjectFieldSpecs(ns.FsSlice)
|
||||
if err := ns.roleBindingHack(node); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// transformations based on data -- :)
|
||||
err := node.PipeE(fsslice.Filter{
|
||||
FsSlice: ns.FsSlice,
|
||||
SetValue: ns.trackableSetter.SetEntry("", ns.Namespace, yaml.NodeTagString),
|
||||
SetValue: ns.fieldSetter(),
|
||||
CreateKind: yaml.ScalarNode, // Namespace is a ScalarNode
|
||||
CreateTag: yaml.NodeTagString,
|
||||
})
|
||||
return node, err
|
||||
}
|
||||
|
||||
// hacks applies the namespace transforms that are hardcoded rather
|
||||
// than specified through FieldSpecs.
|
||||
func (ns Filter) hacks(obj *yaml.RNode) error {
|
||||
gvk := resid.GvkFromNode(obj)
|
||||
if err := ns.metaNamespaceHack(obj, gvk); err != nil {
|
||||
return err
|
||||
invalidKindErr := &yaml.InvalidNodeKindError{}
|
||||
if err != nil && errors.As(err, &invalidKindErr) && invalidKindErr.ActualNodeKind() != yaml.ScalarNode {
|
||||
return nil, errors.WrapPrefixf(err, "namespace field specs must target scalar nodes")
|
||||
}
|
||||
return ns.roleBindingHack(obj, gvk)
|
||||
return node, errors.WrapPrefixf(err, "namespace transformation failed")
|
||||
}
|
||||
|
||||
// metaNamespaceHack is a hack for implementing the namespace transform
|
||||
// for the metadata.namespace field on namespace scoped resources.
|
||||
// namespace scoped resources are determined by NOT being present
|
||||
// in a hard-coded list of cluster-scoped resource types (by apiVersion and kind).
|
||||
//
|
||||
// This hack should be updated to allow individual resources to specify
|
||||
// if they are cluster scoped through either an annotation on the resources,
|
||||
// or through inlined OpenAPI on the resource as a YAML comment.
|
||||
func (ns Filter) metaNamespaceHack(obj *yaml.RNode, gvk resid.Gvk) error {
|
||||
if gvk.IsClusterScoped() {
|
||||
return nil
|
||||
@@ -85,19 +96,23 @@ func (ns Filter) metaNamespaceHack(obj *yaml.RNode, gvk resid.Gvk) error {
|
||||
FsSlice: []types.FieldSpec{
|
||||
{Path: types.MetadataNamespacePath, CreateIfNotPresent: true},
|
||||
},
|
||||
SetValue: ns.trackableSetter.SetEntry("", ns.Namespace, yaml.NodeTagString),
|
||||
SetValue: ns.fieldSetter(),
|
||||
CreateKind: yaml.ScalarNode, // Namespace is a ScalarNode
|
||||
}
|
||||
_, err := f.Filter(obj)
|
||||
return err
|
||||
}
|
||||
|
||||
// roleBindingHack is a hack for implementing the namespace transform
|
||||
// roleBindingHack is a hack for implementing the transformer's SetRoleBindingSubjects option
|
||||
// for RoleBinding and ClusterRoleBinding resource types.
|
||||
// RoleBinding and ClusterRoleBinding have namespace set on
|
||||
//
|
||||
// In NoSubjects mode, it does nothing.
|
||||
//
|
||||
// In AllServiceAccountSubjects mode, it sets the namespace on subjects with "kind: ServiceAccount".
|
||||
//
|
||||
// In DefaultSubjectsOnly mode (default mode), RoleBinding and ClusterRoleBinding have namespace set on
|
||||
// elements of the "subjects" field if and only if the subject elements
|
||||
// "name" is "default". Otherwise the namespace is not set.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// kind: RoleBinding
|
||||
@@ -106,60 +121,64 @@ func (ns Filter) metaNamespaceHack(obj *yaml.RNode, gvk resid.Gvk) error {
|
||||
// ...
|
||||
// - name: "something-else" # this will not have the namespace set
|
||||
// ...
|
||||
func (ns Filter) roleBindingHack(obj *yaml.RNode, gvk resid.Gvk) error {
|
||||
if gvk.Kind != roleBindingKind && gvk.Kind != clusterRoleBindingKind {
|
||||
func (ns Filter) roleBindingHack(obj *yaml.RNode) error {
|
||||
var visitor filtersutil.SetFn
|
||||
switch ns.SetRoleBindingSubjects {
|
||||
case NoSubjects:
|
||||
return nil
|
||||
case DefaultSubjectsOnly, SubjectModeUnspecified:
|
||||
visitor = ns.setSubjectsNamedDefault
|
||||
case AllServiceAccountSubjects:
|
||||
visitor = ns.setServiceAccountNamespaces
|
||||
default:
|
||||
return errors.Errorf("invalid value %q for setRoleBindingSubjects: "+
|
||||
"must be one of %q, %q or %q", ns.SetRoleBindingSubjects,
|
||||
DefaultSubjectsOnly, NoSubjects, AllServiceAccountSubjects)
|
||||
}
|
||||
|
||||
// Lookup the namespace field on all elements.
|
||||
// We should change the fieldspec so this isn't necessary.
|
||||
// Lookup the subjects field on all elements.
|
||||
obj, err := obj.Pipe(yaml.Lookup(subjectsField))
|
||||
if err != nil || yaml.IsMissingOrNull(obj) {
|
||||
return err
|
||||
}
|
||||
|
||||
// add the namespace to each "subject" with name: default
|
||||
err = obj.VisitElements(func(o *yaml.RNode) error {
|
||||
// The only case we need to force the namespace
|
||||
// if for the "service account". "default" is
|
||||
// kind of hardcoded here for right now.
|
||||
name, err := o.Pipe(
|
||||
yaml.Lookup("name"), yaml.Match("default"),
|
||||
)
|
||||
if err != nil || yaml.IsMissingOrNull(name) {
|
||||
return err
|
||||
}
|
||||
|
||||
// set the namespace for the default account
|
||||
node, err := o.Pipe(
|
||||
yaml.LookupCreate(yaml.ScalarNode, "namespace"),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ns.trackableSetter.SetEntry("", ns.Namespace, yaml.NodeTagString)(node)
|
||||
|
||||
})
|
||||
|
||||
return err
|
||||
// Use the appropriate visitor to set the namespace field on the correct subset of subjects
|
||||
return errors.WrapPrefixf(obj.VisitElements(visitor), "setting namespace on (cluster)role binding subjects")
|
||||
}
|
||||
|
||||
// removeFieldSpecsForHacks removes from the list fieldspecs that
|
||||
func isRoleBinding(kind string) bool {
|
||||
return kind == roleBindingKind || kind == clusterRoleBindingKind
|
||||
}
|
||||
|
||||
func (ns Filter) setServiceAccountNamespaces(o *yaml.RNode) error {
|
||||
name, err := o.Pipe(yaml.Lookup("kind"), yaml.Match("ServiceAccount"))
|
||||
if err != nil || yaml.IsMissingOrNull(name) {
|
||||
return errors.WrapPrefixf(err, "looking up kind on (cluster)role binding subject")
|
||||
}
|
||||
return setNamespaceField(o, ns.fieldSetter())
|
||||
}
|
||||
|
||||
func (ns Filter) setSubjectsNamedDefault(o *yaml.RNode) error {
|
||||
name, err := o.Pipe(yaml.Lookup("name"), yaml.Match("default"))
|
||||
if err != nil || yaml.IsMissingOrNull(name) {
|
||||
return errors.WrapPrefixf(err, "looking up name on (cluster)role binding subject")
|
||||
}
|
||||
return setNamespaceField(o, ns.fieldSetter())
|
||||
}
|
||||
|
||||
func setNamespaceField(node *yaml.RNode, setter filtersutil.SetFn) error {
|
||||
node, err := node.Pipe(yaml.LookupCreate(yaml.ScalarNode, "namespace"))
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "setting namespace field on (cluster)role binding subject")
|
||||
}
|
||||
return setter(node)
|
||||
}
|
||||
|
||||
// removeRoleBindingSubjectFieldSpecs removes from the list fieldspecs that
|
||||
// have hardcoded implementations
|
||||
func (ns Filter) removeFieldSpecsForHacks(fs types.FsSlice) types.FsSlice {
|
||||
func (ns Filter) removeRoleBindingSubjectFieldSpecs(fs types.FsSlice) types.FsSlice {
|
||||
var val types.FsSlice
|
||||
for i := range fs {
|
||||
// implemented by metaNamespaceHack
|
||||
if fs[i].Path == types.MetadataNamespacePath {
|
||||
continue
|
||||
}
|
||||
// implemented by roleBindingHack
|
||||
if fs[i].Kind == roleBindingKind && fs[i].Path == subjectsField {
|
||||
continue
|
||||
}
|
||||
// implemented by roleBindingHack
|
||||
if fs[i].Kind == clusterRoleBindingKind && fs[i].Path == subjectsField {
|
||||
if isRoleBinding(fs[i].Kind) && fs[i].Path == subjectsNamespacePath {
|
||||
continue
|
||||
}
|
||||
val = append(val, fs[i])
|
||||
@@ -167,8 +186,27 @@ func (ns Filter) removeFieldSpecsForHacks(fs types.FsSlice) types.FsSlice {
|
||||
return val
|
||||
}
|
||||
|
||||
func (ns Filter) removeMetaNamespaceFieldSpecs(fs types.FsSlice) types.FsSlice {
|
||||
var val types.FsSlice
|
||||
for i := range fs {
|
||||
if fs[i].Path == types.MetadataNamespacePath {
|
||||
continue
|
||||
}
|
||||
val = append(val, fs[i])
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
func (ns *Filter) fieldSetter() filtersutil.SetFn {
|
||||
if ns.UnsetOnly {
|
||||
return ns.trackableSetter.SetEntryIfEmpty("", ns.Namespace, yaml.NodeTagString)
|
||||
}
|
||||
return ns.trackableSetter.SetEntry("", ns.Namespace, yaml.NodeTagString)
|
||||
}
|
||||
|
||||
const (
|
||||
subjectsField = "subjects"
|
||||
subjectsNamespacePath = "subjects/namespace"
|
||||
roleBindingKind = "RoleBinding"
|
||||
clusterRoleBindingKind = "ClusterRoleBinding"
|
||||
)
|
||||
|
||||
@@ -406,7 +406,7 @@ func TestNamespace_Filter(t *testing.T) {
|
||||
test := tests[i]
|
||||
test.filter.WithMutationTracker(test.mutationTracker)
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
test.filter.FsSlice = append(config.NameSpace, test.fsslice...)
|
||||
test.filter.FsSlice = append(config.NameSpace, test.fsslice...) //nolint:gocritic
|
||||
if !assert.Equal(t,
|
||||
strings.TrimSpace(test.expected),
|
||||
strings.TrimSpace(
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package patchstrategicmerge
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package refvar contains a kio.Filter implementation of the kustomize
|
||||
// refvar transformer (find and replace $(FOO) style variables in strings).
|
||||
package refvar
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package refvar
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package refvar_test
|
||||
|
||||
import (
|
||||
@@ -17,7 +20,6 @@ var makeMf = func(theMap map[string]interface{}) MappingFunc {
|
||||
}
|
||||
|
||||
func TestFilter(t *testing.T) {
|
||||
|
||||
testCases := map[string]struct {
|
||||
input string
|
||||
expected string
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package replacement contains a kio.Filter implementation of the kustomize
|
||||
// replacement transformer (accepts sources and looks for targets to replace
|
||||
// their values with values from the sources).
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package replacement
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/resid"
|
||||
kyaml_utils "sigs.k8s.io/kustomize/kyaml/utils"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
@@ -20,11 +22,11 @@ type Filter struct {
|
||||
|
||||
// Filter replaces values of targets with values from sources
|
||||
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
for _, r := range f.Replacements {
|
||||
for i, r := range f.Replacements {
|
||||
if r.Source == nil || r.Targets == nil {
|
||||
return nil, fmt.Errorf("replacements must specify a source and at least one target")
|
||||
}
|
||||
value, err := getReplacement(nodes, &r)
|
||||
value, err := getReplacement(nodes, &f.Replacements[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -36,22 +38,86 @@ func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
func applyReplacement(nodes []*yaml.RNode, value *yaml.RNode, targets []*types.TargetSelector) ([]*yaml.RNode, error) {
|
||||
for _, t := range targets {
|
||||
if t.Select == nil {
|
||||
return nil, fmt.Errorf("target must specify resources to select")
|
||||
func getReplacement(nodes []*yaml.RNode, r *types.Replacement) (*yaml.RNode, error) {
|
||||
source, err := selectSourceNode(nodes, r.Source)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if r.Source.FieldPath == "" {
|
||||
r.Source.FieldPath = types.DefaultReplacementFieldPath
|
||||
}
|
||||
fieldPath := kyaml_utils.SmarterPathSplitter(r.Source.FieldPath, ".")
|
||||
|
||||
rn, err := source.Pipe(yaml.Lookup(fieldPath...))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error looking up replacement source: %w", err)
|
||||
}
|
||||
if rn.IsNilOrEmpty() {
|
||||
return nil, fmt.Errorf("fieldPath `%s` is missing for replacement source %s", r.Source.FieldPath, r.Source.ResId)
|
||||
}
|
||||
|
||||
return getRefinedValue(r.Source.Options, rn)
|
||||
}
|
||||
|
||||
// selectSourceNode finds the node that matches the selector, returning
|
||||
// an error if multiple or none are found
|
||||
func selectSourceNode(nodes []*yaml.RNode, selector *types.SourceSelector) (*yaml.RNode, error) {
|
||||
var matches []*yaml.RNode
|
||||
for _, n := range nodes {
|
||||
ids, err := utils.MakeResIds(n)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting node IDs: %w", err)
|
||||
}
|
||||
if len(t.FieldPaths) == 0 {
|
||||
t.FieldPaths = []string{types.DefaultReplacementFieldPath}
|
||||
for _, id := range ids {
|
||||
if id.IsSelectedBy(selector.ResId) {
|
||||
if len(matches) > 0 {
|
||||
return nil, fmt.Errorf(
|
||||
"multiple matches for selector %s", selector)
|
||||
}
|
||||
matches = append(matches, n)
|
||||
break
|
||||
}
|
||||
}
|
||||
for _, n := range nodes {
|
||||
ids, err := utils.MakeResIds(n)
|
||||
}
|
||||
if len(matches) == 0 {
|
||||
return nil, fmt.Errorf("nothing selected by %s", selector)
|
||||
}
|
||||
return matches[0], nil
|
||||
}
|
||||
|
||||
func getRefinedValue(options *types.FieldOptions, rn *yaml.RNode) (*yaml.RNode, error) {
|
||||
if options == nil || options.Delimiter == "" {
|
||||
return rn, nil
|
||||
}
|
||||
if rn.YNode().Kind != yaml.ScalarNode {
|
||||
return nil, fmt.Errorf("delimiter option can only be used with scalar nodes")
|
||||
}
|
||||
value := strings.Split(yaml.GetValue(rn), options.Delimiter)
|
||||
if options.Index >= len(value) || options.Index < 0 {
|
||||
return nil, fmt.Errorf("options.index %d is out of bounds for value %s", options.Index, yaml.GetValue(rn))
|
||||
}
|
||||
n := rn.Copy()
|
||||
n.YNode().Value = value[options.Index]
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func applyReplacement(nodes []*yaml.RNode, value *yaml.RNode, targetSelectors []*types.TargetSelector) ([]*yaml.RNode, error) {
|
||||
for _, selector := range targetSelectors {
|
||||
if selector.Select == nil {
|
||||
return nil, errors.New("target must specify resources to select")
|
||||
}
|
||||
if len(selector.FieldPaths) == 0 {
|
||||
selector.FieldPaths = []string{types.DefaultReplacementFieldPath}
|
||||
}
|
||||
for _, possibleTarget := range nodes {
|
||||
ids, err := utils.MakeResIds(possibleTarget)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// filter targets by label and annotation selectors
|
||||
selectByAnnoAndLabel, err := selectByAnnoAndLabel(n, t)
|
||||
selectByAnnoAndLabel, err := selectByAnnoAndLabel(possibleTarget, selector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -60,9 +126,9 @@ func applyReplacement(nodes []*yaml.RNode, value *yaml.RNode, targets []*types.T
|
||||
}
|
||||
|
||||
// filter targets by matching resource IDs
|
||||
for _, id := range ids {
|
||||
if id.IsSelectedBy(t.Select.ResId) && !rejectId(t.Reject, &id) {
|
||||
err := applyToNode(n, value, t)
|
||||
for i, id := range ids {
|
||||
if id.IsSelectedBy(selector.Select.ResId) && !rejectId(selector.Reject, &ids[i]) {
|
||||
err := copyValueToTarget(possibleTarget, value, selector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -111,56 +177,50 @@ func rejectId(rejects []*types.Selector, id *resid.ResId) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func applyToNode(node *yaml.RNode, value *yaml.RNode, target *types.TargetSelector) error {
|
||||
for _, fp := range target.FieldPaths {
|
||||
fieldPath := utils.SmarterPathSplitter(fp, ".")
|
||||
var t *yaml.RNode
|
||||
var err error
|
||||
if target.Options != nil && target.Options.Create {
|
||||
t, err = node.Pipe(yaml.LookupCreate(value.YNode().Kind, fieldPath...))
|
||||
} else {
|
||||
t, err = node.Pipe(&yaml.PathMatcher{Path: fieldPath})
|
||||
}
|
||||
func copyValueToTarget(target *yaml.RNode, value *yaml.RNode, selector *types.TargetSelector) error {
|
||||
for _, fp := range selector.FieldPaths {
|
||||
fieldPath := kyaml_utils.SmarterPathSplitter(fp, ".")
|
||||
create, err := shouldCreateField(selector.Options, fieldPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if t != nil {
|
||||
if err = applyToOneNode(target.Options, t, value); err != nil {
|
||||
|
||||
var targetFields []*yaml.RNode
|
||||
if create {
|
||||
createdField, createErr := target.Pipe(yaml.LookupCreate(value.YNode().Kind, fieldPath...))
|
||||
if createErr != nil {
|
||||
return fmt.Errorf("error creating replacement node: %w", createErr)
|
||||
}
|
||||
targetFields = append(targetFields, createdField)
|
||||
} else {
|
||||
// may return multiple fields, always wrapped in a sequence node
|
||||
foundFieldSequence, lookupErr := target.Pipe(&yaml.PathMatcher{Path: fieldPath})
|
||||
if lookupErr != nil {
|
||||
return fmt.Errorf("error finding field in replacement target: %w", lookupErr)
|
||||
}
|
||||
targetFields, err = foundFieldSequence.Elements()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error fetching elements in replacement target: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, t := range targetFields {
|
||||
if err := setFieldValue(selector.Options, t, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyToOneNode(options *types.FieldOptions, t *yaml.RNode, value *yaml.RNode) error {
|
||||
if len(t.YNode().Content) == 0 {
|
||||
if err := setTargetValue(options, t, value); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, scalarNode := range t.YNode().Content {
|
||||
if options != nil && options.Create {
|
||||
return fmt.Errorf("cannot use create option in a multi-value target")
|
||||
}
|
||||
rn := yaml.NewRNode(scalarNode)
|
||||
if err := setTargetValue(options, rn, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func setTargetValue(options *types.FieldOptions, t *yaml.RNode, value *yaml.RNode) error {
|
||||
func setFieldValue(options *types.FieldOptions, targetField *yaml.RNode, value *yaml.RNode) error {
|
||||
value = value.Copy()
|
||||
if options != nil && options.Delimiter != "" {
|
||||
if t.YNode().Kind != yaml.ScalarNode {
|
||||
if targetField.YNode().Kind != yaml.ScalarNode {
|
||||
return fmt.Errorf("delimiter option can only be used with scalar nodes")
|
||||
}
|
||||
tv := strings.Split(t.YNode().Value, options.Delimiter)
|
||||
tv := strings.Split(targetField.YNode().Value, options.Delimiter)
|
||||
v := yaml.GetValue(value)
|
||||
// TODO: Add a way to remove an element
|
||||
switch {
|
||||
@@ -174,76 +234,25 @@ func setTargetValue(options *types.FieldOptions, t *yaml.RNode, value *yaml.RNod
|
||||
value.YNode().Value = strings.Join(tv, options.Delimiter)
|
||||
}
|
||||
|
||||
if t.YNode().Kind == yaml.ScalarNode {
|
||||
if targetField.YNode().Kind == yaml.ScalarNode {
|
||||
// For scalar, only copy the value (leave any type intact to auto-convert int->string or string->int)
|
||||
t.YNode().Value = value.YNode().Value
|
||||
targetField.YNode().Value = value.YNode().Value
|
||||
} else {
|
||||
t.SetYNode(value.YNode())
|
||||
targetField.SetYNode(value.YNode())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getReplacement(nodes []*yaml.RNode, r *types.Replacement) (*yaml.RNode, error) {
|
||||
source, err := selectSourceNode(nodes, r.Source)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func shouldCreateField(options *types.FieldOptions, fieldPath []string) (bool, error) {
|
||||
if options == nil || !options.Create {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if r.Source.FieldPath == "" {
|
||||
r.Source.FieldPath = types.DefaultReplacementFieldPath
|
||||
}
|
||||
fieldPath := utils.SmarterPathSplitter(r.Source.FieldPath, ".")
|
||||
|
||||
rn, err := source.Pipe(yaml.Lookup(fieldPath...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rn.IsNilOrEmpty() {
|
||||
return nil, fmt.Errorf("fieldPath `%s` is missing for replacement source %s", r.Source.FieldPath, r.Source.ResId)
|
||||
}
|
||||
|
||||
return getRefinedValue(r.Source.Options, rn)
|
||||
}
|
||||
|
||||
func getRefinedValue(options *types.FieldOptions, rn *yaml.RNode) (*yaml.RNode, error) {
|
||||
if options == nil || options.Delimiter == "" {
|
||||
return rn, nil
|
||||
}
|
||||
if rn.YNode().Kind != yaml.ScalarNode {
|
||||
return nil, fmt.Errorf("delimiter option can only be used with scalar nodes")
|
||||
}
|
||||
value := strings.Split(yaml.GetValue(rn), options.Delimiter)
|
||||
if options.Index >= len(value) || options.Index < 0 {
|
||||
return nil, fmt.Errorf("options.index %d is out of bounds for value %s", options.Index, yaml.GetValue(rn))
|
||||
}
|
||||
n := rn.Copy()
|
||||
n.YNode().Value = value[options.Index]
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// selectSourceNode finds the node that matches the selector, returning
|
||||
// an error if multiple or none are found
|
||||
func selectSourceNode(nodes []*yaml.RNode, selector *types.SourceSelector) (*yaml.RNode, error) {
|
||||
var matches []*yaml.RNode
|
||||
for _, n := range nodes {
|
||||
ids, err := utils.MakeResIds(n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, id := range ids {
|
||||
if id.IsSelectedBy(selector.ResId) {
|
||||
if len(matches) > 0 {
|
||||
return nil, fmt.Errorf(
|
||||
"multiple matches for selector %s", selector)
|
||||
}
|
||||
matches = append(matches, n)
|
||||
break
|
||||
}
|
||||
// create option is not supported in a wildcard matching
|
||||
for _, f := range fieldPath {
|
||||
if f == "*" {
|
||||
return false, fmt.Errorf("cannot support create option in a multi-value target")
|
||||
}
|
||||
}
|
||||
if len(matches) == 0 {
|
||||
return nil, fmt.Errorf("nothing selected by %s", selector)
|
||||
}
|
||||
return matches[0], nil
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -1634,6 +1634,45 @@ spec:
|
||||
- name: deployment-name
|
||||
value: sample-deploy`,
|
||||
},
|
||||
"index contains '*' character and create options": {
|
||||
input: `apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: sample-deploy
|
||||
name: sample-deploy
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: sample-deploy
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: sample-deploy
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx
|
||||
name: main
|
||||
env:
|
||||
- name: other-env
|
||||
value: YYYYY
|
||||
`,
|
||||
replacements: `replacements:
|
||||
- source:
|
||||
kind: Deployment
|
||||
name: sample-deploy
|
||||
fieldPath: metadata.name
|
||||
targets:
|
||||
- select:
|
||||
kind: Deployment
|
||||
fieldPaths:
|
||||
- spec.template.spec.containers.*.env.[name=deployment-name].value
|
||||
options:
|
||||
create: true
|
||||
`,
|
||||
expectedErr: "cannot support create option in a multi-value target",
|
||||
},
|
||||
"multiple field paths in target": {
|
||||
input: `apiVersion: v1
|
||||
kind: ConfigMap
|
||||
@@ -2315,6 +2354,66 @@ spec:
|
||||
name: myapp-container
|
||||
ports:
|
||||
- containerPort: 80
|
||||
`,
|
||||
},
|
||||
"replace an existing mapping value": {
|
||||
input: `apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: hello
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: busybox
|
||||
name: myapp-container
|
||||
restartPolicy: old
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: my-pod
|
||||
spec:
|
||||
containers:
|
||||
- image: busybox
|
||||
name: myapp-container
|
||||
restartPolicy: new
|
||||
`,
|
||||
replacements: `replacements:
|
||||
- source:
|
||||
kind: Pod
|
||||
name: my-pod
|
||||
fieldPath: spec
|
||||
targets:
|
||||
- select:
|
||||
name: hello
|
||||
kind: Job
|
||||
fieldPaths:
|
||||
- spec.template.spec
|
||||
options:
|
||||
create: true
|
||||
`,
|
||||
expected: `apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: hello
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: busybox
|
||||
name: myapp-container
|
||||
restartPolicy: new
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: my-pod
|
||||
spec:
|
||||
containers:
|
||||
- image: busybox
|
||||
name: myapp-container
|
||||
restartPolicy: new
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package replicacount
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package replicacount
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package replicacount
|
||||
|
||||
import (
|
||||
|
||||
35
api/go.mod
35
api/go.mod
@@ -1,16 +1,39 @@
|
||||
module sigs.k8s.io/kustomize/api
|
||||
|
||||
go 1.16
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/evanphx/json-patch v4.11.0+incompatible
|
||||
github.com/go-errors/errors v1.0.1
|
||||
github.com/go-errors/errors v1.4.2
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||
github.com/imdario/mergo v0.3.5
|
||||
github.com/imdario/mergo v0.3.6
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/stretchr/testify v1.8.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e
|
||||
sigs.k8s.io/kustomize/kyaml v0.13.4
|
||||
k8s.io/kube-openapi v0.0.0-20220401212409-b28bf2818661
|
||||
sigs.k8s.io/kustomize/kyaml v0.13.9
|
||||
sigs.k8s.io/yaml v1.2.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.5 // indirect
|
||||
github.com/go-openapi/swag v0.22.3 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/gnostic v0.5.7-v3refs // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/kr/pretty v0.2.1 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/xlab/treeprint v1.1.0 // indirect
|
||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
537
api/go.sum
537
api/go.sum
@@ -1,641 +1,216 @@
|
||||
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=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
|
||||
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
|
||||
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
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/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs=
|
||||
github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
|
||||
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
|
||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
||||
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
|
||||
github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM=
|
||||
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
|
||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54=
|
||||
github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
|
||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gnostic v0.5.1 h1:A8Yhf6EtqTv9RMsU6MQTyrtV1TjWlR6xU9BsZIwuTCM=
|
||||
github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q=
|
||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
|
||||
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
|
||||
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
|
||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
||||
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI=
|
||||
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk=
|
||||
github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
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 v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
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-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/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=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
|
||||
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
|
||||
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM=
|
||||
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/kustomize/kyaml v0.13.4 h1:UP4niyzHP8yBDZTJu3OyZMCbJUfT6PIj0fJZFcn8gQw=
|
||||
sigs.k8s.io/kustomize/kyaml v0.13.4/go.mod h1:/ya3Gk4diiQzlE4mBh7wykyLRFZNvqlbh+JnwQ9Vhrc=
|
||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
k8s.io/kube-openapi v0.0.0-20220401212409-b28bf2818661 h1:nqYOUleKLC/0P1zbU29F5q6aoezM6MOAVz+iyfQbZ5M=
|
||||
k8s.io/kube-openapi v0.0.0-20220401212409-b28bf2818661/go.mod h1:daOouuuwd9JXpv1L7Y34iV3yf6nxzipkKMWWlqlvK9M=
|
||||
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk=
|
||||
sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
||||
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
|
||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||
|
||||
@@ -341,6 +341,7 @@ data:
|
||||
// The return value indicates whether we should skip the rest of the test case
|
||||
// due to the error result.
|
||||
func SkipRest(t *testing.T, desc string, err error, contains string) bool {
|
||||
t.Helper()
|
||||
if err != nil {
|
||||
if len(contains) == 0 {
|
||||
t.Errorf("case %q, expect nil error but got %q", desc, err.Error())
|
||||
|
||||
@@ -28,12 +28,20 @@ type KvLoader interface {
|
||||
|
||||
// Loader interface exposes methods to read bytes.
|
||||
type Loader interface {
|
||||
|
||||
// Repo returns the repo location if this Loader was created from a url
|
||||
// or the empty string otherwise.
|
||||
Repo() string
|
||||
|
||||
// Root returns the root location for this Loader.
|
||||
Root() string
|
||||
|
||||
// New returns Loader located at newRoot.
|
||||
New(newRoot string) (Loader, error)
|
||||
|
||||
// Load returns the bytes read from the location or an error.
|
||||
Load(location string) ([]byte, error)
|
||||
|
||||
// Cleanup cleans the loader
|
||||
Cleanup() error
|
||||
}
|
||||
|
||||
@@ -113,7 +113,6 @@ func debug(fMap filterMap) {
|
||||
// 'spec/scaleTargetRef/name' field. Return a filter that can do that.
|
||||
func (t *nameReferenceTransformer) determineFilters(
|
||||
resources []*resource.Resource) (fMap filterMap) {
|
||||
|
||||
// We cache the resource OrgId values because they don't change and otherwise are very visible in a memory pprof
|
||||
resourceOrgIds := make([]resid.ResId, len(resources))
|
||||
for i, resource := range resources {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
||||
"sigs.k8s.io/kustomize/api/provider"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
@@ -524,6 +525,52 @@ func TestNameReferenceUnhappyRun(t *testing.T) {
|
||||
`considering field 'rules/resourceNames' of object ClusterRole.v1.rbac.authorization.k8s.io/cr.[noNs]: visit traversal on ` +
|
||||
`path: [resourceNames]: path config error; no 'name' field in node`,
|
||||
},
|
||||
{
|
||||
// When targeting a map reference, we need to update both name and namespace, so multiple
|
||||
// possible referral targets with different namespaces should not be considered identical.
|
||||
// This test covers a bug where the difference in namespace was ignored and one candidate was chosen at random.
|
||||
resMap: resmaptest_test.NewRmBuilderDefault(t).AddWithNsAndName(
|
||||
"", orgname,
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ServiceAccount",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": orgname,
|
||||
"namespace": ns1,
|
||||
},
|
||||
},
|
||||
).AddWithNsAndName(
|
||||
"", orgname,
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ServiceAccount",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": orgname,
|
||||
"namespace": ns2,
|
||||
},
|
||||
},
|
||||
).Add(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||
"kind": "ClusterRoleBinding",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": orgname,
|
||||
},
|
||||
"roleRef": map[string]interface{}{
|
||||
"apiGroup": "rbac.authorization.k8s.io",
|
||||
"kind": "ClusterRole",
|
||||
"name": orgname,
|
||||
},
|
||||
"subjects": []interface{}{
|
||||
map[string]interface{}{
|
||||
"kind": "ServiceAccount",
|
||||
"name": orgname,
|
||||
},
|
||||
},
|
||||
},
|
||||
).ResMap(),
|
||||
expectedErr: "found multiple possible referrals: ServiceAccount.v1.[noGrp]/uniquename.ns1, ServiceAccount.v1.[noGrp]/uniquename.ns2",
|
||||
},
|
||||
}
|
||||
|
||||
nrt := newNameReferenceTransformer(builtinconfig.MakeDefaultConfig().NameReference)
|
||||
@@ -1061,3 +1108,76 @@ func TestNameReferenceCandidateSelection(t *testing.T) {
|
||||
t.Fatalf(notEqualErrFmt, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNameReferenceCandidateDisambiguationByNamespace(t *testing.T) {
|
||||
// The ClusterRole refers to both configmaps, since it is not namespace-specific.
|
||||
// Since both names are updated consistently, the transformer should be able to
|
||||
// silently update the ClusterRole as well.
|
||||
// This test guards against a regression where allNamesAndNamespacesAreTheSame would be
|
||||
// used to detect referral candidate identity instead of allNamesAreTheSame.
|
||||
m := resmaptest_test.NewRmBuilderDefault(t).AddWithName(orgname,
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": suffixedname,
|
||||
"namespace": ns1,
|
||||
},
|
||||
},
|
||||
).AddWithName(orgname,
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": suffixedname,
|
||||
"namespace": ns2,
|
||||
},
|
||||
},
|
||||
).Add(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||
"kind": "ClusterRole",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": orgname,
|
||||
},
|
||||
"rules": []interface{}{
|
||||
map[string]interface{}{
|
||||
"resources": []interface{}{
|
||||
"configmaps",
|
||||
},
|
||||
"resourceNames": []interface{}{
|
||||
orgname,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
).ResMap()
|
||||
|
||||
expected := resmaptest_test.NewSeededRmBuilderDefault(t, m.ShallowCopy()).
|
||||
ReplaceResource(map[string]interface{}{
|
||||
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||
"kind": "ClusterRole",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": orgname,
|
||||
},
|
||||
"rules": []interface{}{
|
||||
map[string]interface{}{
|
||||
"resources": []interface{}{
|
||||
"configmaps",
|
||||
},
|
||||
"resourceNames": []interface{}{
|
||||
suffixedname,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
).ResMap()
|
||||
|
||||
nrt := newNameReferenceTransformer(builtinconfig.MakeDefaultConfig().NameReference)
|
||||
require.NoError(t, nrt.Transform(m))
|
||||
|
||||
m.RemoveBuildAnnotations()
|
||||
if err := expected.ErrorIfNotEqualLists(m); err != nil {
|
||||
t.Fatalf(notEqualErrFmt, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,6 @@ func (ra *ResAccumulator) findVarValueFromResources(v types.Var) (interface{}, e
|
||||
for _, res := range ra.resMap.Resources() {
|
||||
for _, varName := range res.GetRefVarNames() {
|
||||
if varName == v.Name {
|
||||
//nolint: staticcheck
|
||||
s, err := res.GetFieldValue(v.FieldRef.FieldPath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf(
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
)
|
||||
|
||||
func makeResAccumulator(t *testing.T) *ResAccumulator {
|
||||
t.Helper()
|
||||
ra := MakeEmptyAccumulator()
|
||||
err := ra.MergeConfig(builtinconfig.MakeDefaultConfig())
|
||||
if err != nil {
|
||||
@@ -133,6 +134,7 @@ func TestResolveVarsOneUnused(t *testing.T) {
|
||||
}
|
||||
|
||||
func expectLog(t *testing.T, log bytes.Buffer, expect string) {
|
||||
t.Helper()
|
||||
if !strings.Contains(log.String(), expect) {
|
||||
t.Fatalf("expected log containing '%s', got '%s'", expect, log.String())
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ package builtins
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -73,7 +72,7 @@ func (p *HelmChartInflationGeneratorPlugin) establishTmpDir() (err error) {
|
||||
// already done.
|
||||
return nil
|
||||
}
|
||||
p.tmpDir, err = ioutil.TempDir("", "kustomize-helm-")
|
||||
p.tmpDir, err = os.MkdirTemp("", "kustomize-helm-")
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -211,7 +210,7 @@ func (p *HelmChartInflationGeneratorPlugin) writeValuesBytes(
|
||||
return "", fmt.Errorf("cannot create tmp dir to write helm values")
|
||||
}
|
||||
path := filepath.Join(p.tmpDir, p.Name+"-kustomize-values.yaml")
|
||||
return path, ioutil.WriteFile(path, b, 0644)
|
||||
return path, errors.Wrap(os.WriteFile(path, b, 0644), "failed to write values file")
|
||||
}
|
||||
|
||||
func (p *HelmChartInflationGeneratorPlugin) cleanup() {
|
||||
@@ -283,6 +282,9 @@ func (p *HelmChartInflationGeneratorPlugin) templateCommand() []string {
|
||||
if p.IncludeCRDs {
|
||||
args = append(args, "--include-crds")
|
||||
}
|
||||
if p.SkipHooks {
|
||||
args = append(args, "--no-hooks")
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
|
||||
@@ -9,20 +9,37 @@ import (
|
||||
"sigs.k8s.io/kustomize/api/filters/namespace"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// Change or set the namespace of non-cluster level resources.
|
||||
type NamespaceTransformerPlugin struct {
|
||||
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
UnsetOnly bool `json:"unsetOnly" yaml:"unsetOnly"`
|
||||
SetRoleBindingSubjects namespace.RoleBindingSubjectMode `json:"setRoleBindingSubjects" yaml:"setRoleBindingSubjects"`
|
||||
}
|
||||
|
||||
func (p *NamespaceTransformerPlugin) Config(
|
||||
_ *resmap.PluginHelpers, c []byte) (err error) {
|
||||
p.Namespace = ""
|
||||
p.FieldSpecs = nil
|
||||
return yaml.Unmarshal(c, p)
|
||||
if err := yaml.Unmarshal(c, p); err != nil {
|
||||
return errors.WrapPrefixf(err, "unmarshalling NamespaceTransformer config")
|
||||
}
|
||||
switch p.SetRoleBindingSubjects {
|
||||
case namespace.AllServiceAccountSubjects, namespace.DefaultSubjectsOnly, namespace.NoSubjects:
|
||||
// valid
|
||||
case namespace.SubjectModeUnspecified:
|
||||
p.SetRoleBindingSubjects = namespace.DefaultSubjectsOnly
|
||||
default:
|
||||
return errors.Errorf("invalid value %q for setRoleBindingSubjects: "+
|
||||
"must be one of %q, %q or %q", p.SetRoleBindingSubjects,
|
||||
namespace.DefaultSubjectsOnly, namespace.NoSubjects, namespace.AllServiceAccountSubjects)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *NamespaceTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
@@ -36,8 +53,10 @@ func (p *NamespaceTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
}
|
||||
r.StorePreviousId()
|
||||
if err := r.ApplyFilter(namespace.Filter{
|
||||
Namespace: p.Namespace,
|
||||
FsSlice: p.FieldSpecs,
|
||||
Namespace: p.Namespace,
|
||||
FsSlice: p.FieldSpecs,
|
||||
SetRoleBindingSubjects: p.SetRoleBindingSubjects,
|
||||
UnsetOnly: p.UnsetOnly,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -22,15 +22,11 @@ func ClonerUsingGitExec(repoSpec *RepoSpec) error {
|
||||
if err = r.run("init"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = r.run(
|
||||
"remote", "add", "origin", repoSpec.CloneSpec()); err != nil {
|
||||
return err
|
||||
}
|
||||
ref := "HEAD"
|
||||
if repoSpec.Ref != "" {
|
||||
ref = repoSpec.Ref
|
||||
}
|
||||
if err = r.run("fetch", "--depth=1", "origin", ref); err != nil {
|
||||
if err = r.run("fetch", "--depth=1", repoSpec.CloneSpec(), ref); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = r.run("checkout", "FETCH_HEAD"); err != nil {
|
||||
|
||||
@@ -46,9 +46,9 @@ func (r gitRunner) run(args ...string) error {
|
||||
cmd.String(),
|
||||
r.duration,
|
||||
func() error {
|
||||
_, err := cmd.CombinedOutput()
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "git cmd = '%s'", cmd.String())
|
||||
return errors.Wrapf(err, "failed to run '%s': %s", cmd.String(), string(out))
|
||||
}
|
||||
return err
|
||||
})
|
||||
|
||||
@@ -27,7 +27,7 @@ type RepoSpec struct {
|
||||
// TODO(monopole): Drop raw, use processed fields instead.
|
||||
raw string
|
||||
|
||||
// Host, e.g. github.com
|
||||
// Host, e.g. https://github.com/
|
||||
Host string
|
||||
|
||||
// orgRepo name (organization/repoName),
|
||||
@@ -78,15 +78,15 @@ func (x *RepoSpec) Cleaner(fSys filesys.FileSystem) func() error {
|
||||
return func() error { return fSys.RemoveAll(x.Dir.String()) }
|
||||
}
|
||||
|
||||
// NewRepoSpecFromUrl parses git-like urls.
|
||||
// NewRepoSpecFromURL parses git-like urls.
|
||||
// From strings like git@github.com:someOrg/someRepo.git or
|
||||
// https://github.com/someOrg/someRepo?ref=someHash, extract
|
||||
// the parts.
|
||||
func NewRepoSpecFromUrl(n string) (*RepoSpec, error) {
|
||||
func NewRepoSpecFromURL(n string) (*RepoSpec, error) {
|
||||
if filepath.IsAbs(n) {
|
||||
return nil, fmt.Errorf("uri looks like abs path: %s", n)
|
||||
}
|
||||
host, orgRepo, path, gitRef, gitSubmodules, suffix, gitTimeout := parseGitUrl(n)
|
||||
host, orgRepo, path, gitRef, gitSubmodules, suffix, gitTimeout := parseGitURL(n)
|
||||
if orgRepo == "" {
|
||||
return nil, fmt.Errorf("url lacks orgRepo: %s", n)
|
||||
}
|
||||
@@ -108,44 +108,66 @@ const (
|
||||
// From strings like git@github.com:someOrg/someRepo.git or
|
||||
// https://github.com/someOrg/someRepo?ref=someHash, extract
|
||||
// the parts.
|
||||
func parseGitUrl(n string) (
|
||||
func parseGitURL(n string) (
|
||||
host string, orgRepo string, path string, gitRef string, gitSubmodules bool, gitSuff string, gitTimeout time.Duration) {
|
||||
// parse query first
|
||||
// safe because according to rfc3986: ? only allowed in query
|
||||
// and not recognized %-encoded
|
||||
beforeQuery, query, _ := strings.Cut(n, "?")
|
||||
n = beforeQuery
|
||||
// if no query, defaults returned
|
||||
gitRef, gitTimeout, gitSubmodules = parseQuery(query)
|
||||
|
||||
if strings.Contains(n, gitDelimiter) {
|
||||
index := strings.Index(n, gitDelimiter)
|
||||
// Adding _git/ to host
|
||||
host = normalizeGitHostSpec(n[:index+len(gitDelimiter)])
|
||||
orgRepo = strings.Split(strings.Split(n[index+len(gitDelimiter):], "/")[0], "?")[0]
|
||||
path, gitRef, gitTimeout, gitSubmodules = peelQuery(n[index+len(gitDelimiter)+len(orgRepo):])
|
||||
orgRepo = strings.Split(n[index+len(gitDelimiter):], "/")[0]
|
||||
path = parsePath(n[index+len(gitDelimiter)+len(orgRepo):])
|
||||
return
|
||||
}
|
||||
host, n = parseHostSpec(n)
|
||||
gitSuff = gitSuffix
|
||||
isLocal := strings.HasPrefix(host, "file://")
|
||||
if !isLocal {
|
||||
gitSuff = gitSuffix
|
||||
}
|
||||
if strings.Contains(n, gitSuffix) {
|
||||
gitSuff = gitSuffix
|
||||
index := strings.Index(n, gitSuffix)
|
||||
orgRepo = n[0:index]
|
||||
n = n[index+len(gitSuffix):]
|
||||
if len(n) > 0 && n[0] == '/' {
|
||||
n = n[1:]
|
||||
}
|
||||
path, gitRef, gitTimeout, gitSubmodules = peelQuery(n)
|
||||
path = parsePath(n)
|
||||
return
|
||||
}
|
||||
|
||||
if isLocal {
|
||||
if idx := strings.Index(n, "//"); idx > 0 {
|
||||
orgRepo = n[:idx]
|
||||
n = n[idx+2:]
|
||||
path = parsePath(n)
|
||||
return
|
||||
}
|
||||
orgRepo = parsePath(n)
|
||||
return
|
||||
}
|
||||
|
||||
i := strings.Index(n, "/")
|
||||
if i < 1 {
|
||||
path, gitRef, gitTimeout, gitSubmodules = peelQuery(n)
|
||||
path = parsePath(n)
|
||||
return
|
||||
}
|
||||
j := strings.Index(n[i+1:], "/")
|
||||
if j >= 0 {
|
||||
j += i + 1
|
||||
orgRepo = n[:j]
|
||||
path, gitRef, gitTimeout, gitSubmodules = peelQuery(n[j+1:])
|
||||
path = parsePath(n[j+1:])
|
||||
return
|
||||
}
|
||||
path = ""
|
||||
orgRepo, gitRef, gitTimeout, gitSubmodules = peelQuery(n)
|
||||
orgRepo = parsePath(n)
|
||||
return host, orgRepo, path, gitRef, gitSubmodules, gitSuff, gitTimeout
|
||||
}
|
||||
|
||||
@@ -155,14 +177,12 @@ const defaultSubmodules = true
|
||||
// Arbitrary, but non-infinite, timeout for running commands.
|
||||
const defaultTimeout = 27 * time.Second
|
||||
|
||||
func peelQuery(arg string) (string, string, time.Duration, bool) {
|
||||
// Parse the given arg into a URL. In the event of a parse failure, return
|
||||
// our defaults.
|
||||
parsed, err := url.Parse(arg)
|
||||
func parseQuery(query string) (string, time.Duration, bool) {
|
||||
values, err := url.ParseQuery(query)
|
||||
// in event of parse failure, return defaults
|
||||
if err != nil {
|
||||
return arg, "", defaultTimeout, defaultSubmodules
|
||||
return "", defaultTimeout, defaultSubmodules
|
||||
}
|
||||
values := parsed.Query()
|
||||
|
||||
// ref is the desired git ref to target. Can be specified by in a git URL
|
||||
// with ?ref=<string> or ?version=<string>, although ref takes precedence.
|
||||
@@ -193,7 +213,16 @@ func peelQuery(arg string) (string, string, time.Duration, bool) {
|
||||
}
|
||||
}
|
||||
|
||||
return parsed.Path, ref, duration, submodules
|
||||
return ref, duration, submodules
|
||||
}
|
||||
|
||||
func parsePath(n string) string {
|
||||
parsed, err := url.Parse(n)
|
||||
// TODO(annasong): decide how to handle error, i.e. return error, empty string, etc.
|
||||
if err != nil {
|
||||
return n
|
||||
}
|
||||
return parsed.Path
|
||||
}
|
||||
|
||||
func parseHostSpec(n string) (string, string) {
|
||||
@@ -201,7 +230,7 @@ func parseHostSpec(n string) (string, string) {
|
||||
// Start accumulating the host part.
|
||||
for _, p := range []string{
|
||||
// Order matters here.
|
||||
"git::", "gh:", "ssh://", "https://", "http://",
|
||||
"git::", "gh:", "ssh://", "https://", "http://", "file://",
|
||||
"git@", "github.com:", "github.com/"} {
|
||||
if len(p) < len(n) && strings.ToLower(n[:len(p)]) == p {
|
||||
n = n[len(p):]
|
||||
@@ -229,7 +258,7 @@ func parseHostSpec(n string) (string, string) {
|
||||
if strings.HasSuffix(host, p) {
|
||||
i := strings.Index(n, "/")
|
||||
if i > -1 {
|
||||
host = host + n[0:i+1]
|
||||
host += n[0 : i+1]
|
||||
n = n[i+1:]
|
||||
}
|
||||
break
|
||||
|
||||
@@ -6,200 +6,485 @@ package git
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var orgRepos = []string{"someOrg/someRepo", "kubernetes/website"}
|
||||
|
||||
var pathNames = []string{"README.md", "foo/krusty.txt", ""}
|
||||
|
||||
var hrefArgs = []string{"someBranch", "master", "v0.1.0", ""}
|
||||
|
||||
var hostNamesRawAndNormalized = [][]string{
|
||||
{"gh:", "gh:"},
|
||||
{"GH:", "gh:"},
|
||||
{"gitHub.com/", "https://github.com/"},
|
||||
{"github.com:", "https://github.com/"},
|
||||
{"http://github.com/", "https://github.com/"},
|
||||
{"https://github.com/", "https://github.com/"},
|
||||
{"hTTps://github.com/", "https://github.com/"},
|
||||
{"https://git-codecommit.us-east-2.amazonaws.com/", "https://git-codecommit.us-east-2.amazonaws.com/"},
|
||||
{"https://fabrikops2.visualstudio.com/", "https://fabrikops2.visualstudio.com/"},
|
||||
{"ssh://git.example.com:7999/", "ssh://git.example.com:7999/"},
|
||||
{"git::https://gitlab.com/", "https://gitlab.com/"},
|
||||
{"git::http://git.example.com/", "http://git.example.com/"},
|
||||
{"git::https://git.example.com/", "https://git.example.com/"},
|
||||
{"git@github.com:", "git@github.com:"},
|
||||
{"git@github.com/", "git@github.com:"},
|
||||
}
|
||||
|
||||
func makeUrl(hostFmt, orgRepo, path, href string) string {
|
||||
if len(path) > 0 {
|
||||
orgRepo = filepath.Join(orgRepo, path)
|
||||
func TestNewRepoSpecFromUrl_Permute(t *testing.T) {
|
||||
// Generate all many permutations of host, orgRepo, pathName, and ref.
|
||||
// Not all combinations make sense, but the parsing is very permissive and
|
||||
// we probably stil don't want to break backwards compatibility for things
|
||||
// that are unintentionally supported.
|
||||
var schemeAuthority = []struct{ raw, normalized string }{
|
||||
{"gh:", "gh:"},
|
||||
{"GH:", "gh:"},
|
||||
{"gitHub.com/", "https://github.com/"},
|
||||
{"github.com:", "https://github.com/"},
|
||||
{"http://github.com/", "https://github.com/"},
|
||||
{"https://github.com/", "https://github.com/"},
|
||||
{"hTTps://github.com/", "https://github.com/"},
|
||||
{"https://git-codecommit.us-east-2.amazonaws.com/", "https://git-codecommit.us-east-2.amazonaws.com/"},
|
||||
{"https://fabrikops2.visualstudio.com/", "https://fabrikops2.visualstudio.com/"},
|
||||
{"ssh://git.example.com:7999/", "ssh://git.example.com:7999/"},
|
||||
{"git::https://gitlab.com/", "https://gitlab.com/"},
|
||||
{"git::http://git.example.com/", "http://git.example.com/"},
|
||||
{"git::https://git.example.com/", "https://git.example.com/"},
|
||||
{"git@github.com:", "git@github.com:"},
|
||||
{"git@github.com/", "git@github.com:"},
|
||||
}
|
||||
url := hostFmt + orgRepo
|
||||
if href != "" {
|
||||
url += refQuery + href
|
||||
}
|
||||
return url
|
||||
}
|
||||
var orgRepos = []string{"someOrg/someRepo", "kubernetes/website"}
|
||||
var pathNames = []string{"README.md", "foo/krusty.txt", ""}
|
||||
var refArgs = []string{"group/version", "someBranch", "master", "v0.1.0", ""}
|
||||
|
||||
func TestNewRepoSpecFromUrl(t *testing.T) {
|
||||
var bad [][]string
|
||||
for _, tuple := range hostNamesRawAndNormalized {
|
||||
hostRaw := tuple[0]
|
||||
hostSpec := tuple[1]
|
||||
makeURL := func(hostFmt, orgRepo, path, ref string) string {
|
||||
if len(path) > 0 {
|
||||
orgRepo = filepath.Join(orgRepo, path)
|
||||
}
|
||||
url := hostFmt + orgRepo
|
||||
if ref != "" {
|
||||
url += refQuery + ref
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
var i int
|
||||
for _, v := range schemeAuthority {
|
||||
hostRaw := v.raw
|
||||
hostSpec := v.normalized
|
||||
for _, orgRepo := range orgRepos {
|
||||
for _, pathName := range pathNames {
|
||||
for _, hrefArg := range hrefArgs {
|
||||
uri := makeUrl(hostRaw, orgRepo, pathName, hrefArg)
|
||||
rs, err := NewRepoSpecFromUrl(uri)
|
||||
if err != nil {
|
||||
t.Errorf("problem %v", err)
|
||||
}
|
||||
if rs.Host != hostSpec {
|
||||
bad = append(bad, []string{"host", uri, rs.Host, hostSpec})
|
||||
}
|
||||
if rs.OrgRepo != orgRepo {
|
||||
bad = append(bad, []string{"orgRepo", uri, rs.OrgRepo, orgRepo})
|
||||
}
|
||||
if rs.Path != pathName {
|
||||
bad = append(bad, []string{"path", uri, rs.Path, pathName})
|
||||
}
|
||||
if rs.Ref != hrefArg {
|
||||
bad = append(bad, []string{"ref", uri, rs.Ref, hrefArg})
|
||||
}
|
||||
for _, hrefArg := range refArgs {
|
||||
t.Run(fmt.Sprintf("t%d", i), func(t *testing.T) {
|
||||
uri := makeURL(hostRaw, orgRepo, pathName, hrefArg)
|
||||
rs, err := NewRepoSpecFromURL(uri)
|
||||
require.NoErrorf(t, err, "unexpected error creating RepoSpec for uri %s", uri)
|
||||
assert.Equal(t, hostSpec, rs.Host, "unexpected host for uri %s", uri)
|
||||
assert.Equal(t, orgRepo, rs.OrgRepo, "unexpected orgRepo for uri %s", uri)
|
||||
assert.Equal(t, pathName, rs.Path, "unexpected path for uri %s", uri)
|
||||
assert.Equal(t, hrefArg, rs.Ref, "unexpected ref for uri %s", uri)
|
||||
})
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(bad) > 0 {
|
||||
for _, tuple := range bad {
|
||||
fmt.Printf("\n"+
|
||||
" from uri: %s\n"+
|
||||
" actual %4s: %s\n"+
|
||||
"expected %4s: %s\n",
|
||||
tuple[1], tuple[0], tuple[2], tuple[0], tuple[3])
|
||||
}
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
var badData = [][]string{
|
||||
{"/tmp", "uri looks like abs path"},
|
||||
{"iauhsdiuashduas", "url lacks orgRepo"},
|
||||
{"htxxxtp://github.com/", "url lacks host"},
|
||||
{"ssh://git.example.com", "url lacks orgRepo"},
|
||||
{"git::___", "url lacks orgRepo"},
|
||||
}
|
||||
|
||||
func TestNewRepoSpecFromUrlErrors(t *testing.T) {
|
||||
for _, tuple := range badData {
|
||||
_, err := NewRepoSpecFromUrl(tuple[0])
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), tuple[1]) {
|
||||
t.Errorf("unexpected error: %s", err)
|
||||
}
|
||||
badData := map[string]struct {
|
||||
url, error string
|
||||
}{
|
||||
"absolute_path": {
|
||||
"/tmp",
|
||||
"uri looks like abs path",
|
||||
},
|
||||
"no_slashes": {
|
||||
"iauhsdiuashduas",
|
||||
"url lacks orgRepo",
|
||||
},
|
||||
"bad_scheme": {
|
||||
"htxxxtp://github.com/",
|
||||
"url lacks host",
|
||||
},
|
||||
"no_org_repo": {
|
||||
"ssh://git.example.com",
|
||||
"url lacks orgRepo",
|
||||
},
|
||||
"hashicorp_git_only": {
|
||||
"git::___",
|
||||
"url lacks orgRepo",
|
||||
},
|
||||
"query_after_host": {
|
||||
"https://host?ref=group/version/minor_version",
|
||||
"url lacks orgRepo",
|
||||
},
|
||||
}
|
||||
|
||||
for name, testCase := range badData {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
_, err := NewRepoSpecFromURL(testCase.url)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), testCase.error)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewRepoSpecFromUrl_CloneSpecs(t *testing.T) {
|
||||
testcases := map[string]struct {
|
||||
func TestNewRepoSpecFromUrl_Smoke(t *testing.T) {
|
||||
// A set of end to end parsing tests that smoke out obvious issues
|
||||
// No tests for submodules and timeout as the expectations are hard-coded
|
||||
// to the defaults for compactness.
|
||||
testcases := []struct {
|
||||
name string
|
||||
input string
|
||||
repoSpec RepoSpec
|
||||
cloneSpec string
|
||||
absPath string
|
||||
ref string
|
||||
skip string
|
||||
}{
|
||||
"t1": {
|
||||
{
|
||||
name: "t1",
|
||||
input: "https://git-codecommit.us-east-2.amazonaws.com/someorg/somerepo/somedir",
|
||||
cloneSpec: "https://git-codecommit.us-east-2.amazonaws.com/someorg/somerepo",
|
||||
absPath: notCloned.Join("somedir"),
|
||||
ref: "",
|
||||
repoSpec: RepoSpec{
|
||||
Host: "https://git-codecommit.us-east-2.amazonaws.com/",
|
||||
OrgRepo: "someorg/somerepo",
|
||||
Path: "somedir",
|
||||
GitSuffix: ".git",
|
||||
},
|
||||
},
|
||||
"t2": {
|
||||
{
|
||||
name: "t2",
|
||||
input: "https://git-codecommit.us-east-2.amazonaws.com/someorg/somerepo/somedir?ref=testbranch",
|
||||
cloneSpec: "https://git-codecommit.us-east-2.amazonaws.com/someorg/somerepo",
|
||||
absPath: notCloned.Join("somedir"),
|
||||
ref: "testbranch",
|
||||
repoSpec: RepoSpec{
|
||||
Host: "https://git-codecommit.us-east-2.amazonaws.com/",
|
||||
OrgRepo: "someorg/somerepo",
|
||||
Path: "somedir",
|
||||
Ref: "testbranch",
|
||||
GitSuffix: ".git",
|
||||
},
|
||||
},
|
||||
"t3": {
|
||||
{
|
||||
name: "t3",
|
||||
input: "https://fabrikops2.visualstudio.com/someorg/somerepo?ref=master",
|
||||
cloneSpec: "https://fabrikops2.visualstudio.com/someorg/somerepo",
|
||||
absPath: notCloned.String(),
|
||||
ref: "master",
|
||||
repoSpec: RepoSpec{
|
||||
Host: "https://fabrikops2.visualstudio.com/",
|
||||
OrgRepo: "someorg/somerepo",
|
||||
Ref: "master",
|
||||
GitSuffix: ".git",
|
||||
},
|
||||
},
|
||||
"t4": {
|
||||
{
|
||||
name: "t4",
|
||||
input: "http://github.com/someorg/somerepo/somedir",
|
||||
cloneSpec: "https://github.com/someorg/somerepo.git",
|
||||
absPath: notCloned.Join("somedir"),
|
||||
ref: "",
|
||||
repoSpec: RepoSpec{
|
||||
Host: "https://github.com/",
|
||||
OrgRepo: "someorg/somerepo",
|
||||
Path: "somedir",
|
||||
GitSuffix: ".git",
|
||||
},
|
||||
},
|
||||
"t5": {
|
||||
{
|
||||
name: "t5",
|
||||
input: "git@github.com:someorg/somerepo/somedir",
|
||||
cloneSpec: "git@github.com:someorg/somerepo.git",
|
||||
absPath: notCloned.Join("somedir"),
|
||||
ref: "",
|
||||
repoSpec: RepoSpec{
|
||||
Host: "git@github.com:",
|
||||
OrgRepo: "someorg/somerepo",
|
||||
Path: "somedir",
|
||||
GitSuffix: ".git",
|
||||
},
|
||||
},
|
||||
"t6": {
|
||||
{
|
||||
name: "t6",
|
||||
input: "git@gitlab2.sqtools.ru:10022/infra/kubernetes/thanos-base.git?ref=v0.1.0",
|
||||
cloneSpec: "git@gitlab2.sqtools.ru:10022/infra/kubernetes/thanos-base.git",
|
||||
absPath: notCloned.String(),
|
||||
ref: "v0.1.0",
|
||||
repoSpec: RepoSpec{
|
||||
Host: "git@gitlab2.sqtools.ru:10022/",
|
||||
OrgRepo: "infra/kubernetes/thanos-base",
|
||||
Ref: "v0.1.0",
|
||||
GitSuffix: ".git",
|
||||
},
|
||||
},
|
||||
"t7": {
|
||||
{
|
||||
name: "t7",
|
||||
input: "git@bitbucket.org:company/project.git//path?ref=branch",
|
||||
cloneSpec: "git@bitbucket.org:company/project.git",
|
||||
absPath: notCloned.Join("path"),
|
||||
ref: "branch",
|
||||
repoSpec: RepoSpec{
|
||||
Host: "git@bitbucket.org:company/",
|
||||
OrgRepo: "project",
|
||||
Path: "/path",
|
||||
Ref: "branch",
|
||||
GitSuffix: ".git",
|
||||
},
|
||||
},
|
||||
"t8": {
|
||||
{
|
||||
name: "t8",
|
||||
input: "https://itfs.mycompany.com/collection/project/_git/somerepos",
|
||||
cloneSpec: "https://itfs.mycompany.com/collection/project/_git/somerepos",
|
||||
absPath: notCloned.String(),
|
||||
ref: "",
|
||||
repoSpec: RepoSpec{
|
||||
Host: "https://itfs.mycompany.com/collection/project/_git/",
|
||||
OrgRepo: "somerepos",
|
||||
},
|
||||
},
|
||||
"t9": {
|
||||
{
|
||||
name: "t9",
|
||||
input: "https://itfs.mycompany.com/collection/project/_git/somerepos?version=v1.0.0",
|
||||
cloneSpec: "https://itfs.mycompany.com/collection/project/_git/somerepos",
|
||||
absPath: notCloned.String(),
|
||||
ref: "v1.0.0",
|
||||
repoSpec: RepoSpec{
|
||||
Host: "https://itfs.mycompany.com/collection/project/_git/",
|
||||
OrgRepo: "somerepos",
|
||||
Ref: "v1.0.0",
|
||||
},
|
||||
},
|
||||
"t10": {
|
||||
{
|
||||
name: "t10",
|
||||
input: "https://itfs.mycompany.com/collection/project/_git/somerepos/somedir?version=v1.0.0",
|
||||
cloneSpec: "https://itfs.mycompany.com/collection/project/_git/somerepos",
|
||||
absPath: notCloned.Join("somedir"),
|
||||
ref: "v1.0.0",
|
||||
repoSpec: RepoSpec{
|
||||
Host: "https://itfs.mycompany.com/collection/project/_git/",
|
||||
OrgRepo: "somerepos",
|
||||
Path: "/somedir",
|
||||
Ref: "v1.0.0",
|
||||
},
|
||||
},
|
||||
"t11": {
|
||||
{
|
||||
name: "t11",
|
||||
input: "git::https://itfs.mycompany.com/collection/project/_git/somerepos",
|
||||
cloneSpec: "https://itfs.mycompany.com/collection/project/_git/somerepos",
|
||||
absPath: notCloned.String(),
|
||||
ref: "",
|
||||
repoSpec: RepoSpec{
|
||||
Host: "https://itfs.mycompany.com/collection/project/_git/",
|
||||
OrgRepo: "somerepos",
|
||||
},
|
||||
},
|
||||
"t12": {
|
||||
{
|
||||
name: "t12",
|
||||
input: "https://bitbucket.example.com/scm/project/repository.git",
|
||||
cloneSpec: "https://bitbucket.example.com/scm/project/repository.git",
|
||||
absPath: notCloned.String(),
|
||||
ref: "",
|
||||
repoSpec: RepoSpec{
|
||||
Host: "https://bitbucket.example.com/",
|
||||
OrgRepo: "scm/project/repository",
|
||||
GitSuffix: ".git",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "t13",
|
||||
input: "ssh://git-codecommit.us-east-2.amazonaws.com/someorg/somerepo/somepath",
|
||||
cloneSpec: "ssh://git-codecommit.us-east-2.amazonaws.com/someorg/somerepo",
|
||||
absPath: notCloned.Join("somepath"),
|
||||
repoSpec: RepoSpec{
|
||||
Host: "ssh://git-codecommit.us-east-2.amazonaws.com/",
|
||||
OrgRepo: "someorg/somerepo",
|
||||
Path: "somepath",
|
||||
GitSuffix: ".git",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "t14",
|
||||
input: "git@github.com/someorg/somerepo/somepath",
|
||||
cloneSpec: "git@github.com:someorg/somerepo.git",
|
||||
absPath: notCloned.Join("somepath"),
|
||||
repoSpec: RepoSpec{
|
||||
Host: "git@github.com:",
|
||||
OrgRepo: "someorg/somerepo",
|
||||
Path: "somepath",
|
||||
GitSuffix: ".git",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "t15",
|
||||
input: "https://github.com/kubernetes-sigs/kustomize//examples/multibases/dev/?ref=v1.0.6",
|
||||
cloneSpec: "https://github.com/kubernetes-sigs/kustomize.git",
|
||||
absPath: notCloned.Join("/examples/multibases/dev"),
|
||||
repoSpec: RepoSpec{
|
||||
Host: "https://github.com/",
|
||||
OrgRepo: "kubernetes-sigs/kustomize",
|
||||
Path: "/examples/multibases/dev/",
|
||||
Ref: "v1.0.6",
|
||||
GitSuffix: ".git",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "t16",
|
||||
input: "file://a/b/c/someRepo.git/somepath?ref=someBranch",
|
||||
cloneSpec: "file://a/b/c/someRepo.git",
|
||||
absPath: notCloned.Join("somepath"),
|
||||
repoSpec: RepoSpec{
|
||||
Host: "file://",
|
||||
OrgRepo: "a/b/c/someRepo",
|
||||
Path: "somepath",
|
||||
Ref: "someBranch",
|
||||
GitSuffix: ".git",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "t17",
|
||||
input: "file://a/b/c/someRepo//somepath?ref=someBranch",
|
||||
cloneSpec: "file://a/b/c/someRepo",
|
||||
absPath: notCloned.Join("somepath"),
|
||||
repoSpec: RepoSpec{
|
||||
Host: "file://",
|
||||
OrgRepo: "a/b/c/someRepo",
|
||||
Path: "somepath",
|
||||
Ref: "someBranch",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "t18",
|
||||
input: "file://a/b/c/someRepo?ref=someBranch",
|
||||
cloneSpec: "file://a/b/c/someRepo",
|
||||
absPath: notCloned.String(),
|
||||
repoSpec: RepoSpec{
|
||||
Host: "file://",
|
||||
OrgRepo: "a/b/c/someRepo",
|
||||
Ref: "someBranch",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "t19",
|
||||
input: "file:///a/b/c/someRepo?ref=someBranch",
|
||||
cloneSpec: "file:///a/b/c/someRepo",
|
||||
absPath: notCloned.String(),
|
||||
repoSpec: RepoSpec{
|
||||
Host: "file://",
|
||||
OrgRepo: "/a/b/c/someRepo",
|
||||
Ref: "someBranch",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "t20",
|
||||
input: "ssh://git@github.com/kubernetes-sigs/kustomize//examples/multibases/dev?ref=v1.0.6",
|
||||
cloneSpec: "git@github.com:kubernetes-sigs/kustomize.git",
|
||||
absPath: notCloned.Join("examples/multibases/dev"),
|
||||
repoSpec: RepoSpec{
|
||||
Host: "git@github.com:",
|
||||
OrgRepo: "kubernetes-sigs/kustomize",
|
||||
Path: "/examples/multibases/dev",
|
||||
Ref: "v1.0.6",
|
||||
GitSuffix: ".git",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "t21",
|
||||
input: "file:///a/b/c/someRepo",
|
||||
cloneSpec: "file:///a/b/c/someRepo",
|
||||
absPath: notCloned.String(),
|
||||
repoSpec: RepoSpec{
|
||||
Host: "file://",
|
||||
OrgRepo: "/a/b/c/someRepo",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "t22",
|
||||
input: "file:///",
|
||||
cloneSpec: "file:///",
|
||||
absPath: notCloned.String(),
|
||||
repoSpec: RepoSpec{
|
||||
Host: "file://",
|
||||
OrgRepo: "/",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "t23",
|
||||
skip: "the `//` repo separator does not work",
|
||||
input: "https://fake-git-hosting.org/path/to/repo//examples/multibases/dev",
|
||||
cloneSpec: "https://fake-git-hosting.org/path/to.git",
|
||||
absPath: notCloned.Join("/examples/multibases/dev"),
|
||||
repoSpec: RepoSpec{
|
||||
Host: "https://fake-git-hosting.org/",
|
||||
OrgRepo: "path/to/repo",
|
||||
Path: "/examples/multibases/dev",
|
||||
GitSuffix: ".git",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "t24",
|
||||
skip: "the `//` repo separator does not work",
|
||||
input: "ssh://alice@acme.co/path/to/repo//examples/multibases/dev",
|
||||
cloneSpec: "ssh://alice@acme.co/path/to/repo.git",
|
||||
absPath: notCloned.Join("/examples/multibases/dev"),
|
||||
repoSpec: RepoSpec{
|
||||
Host: "ssh://alice@acme.co",
|
||||
OrgRepo: "path/to/repo",
|
||||
Path: "/examples/multibases/dev",
|
||||
GitSuffix: ".git",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "query_slash",
|
||||
input: "https://authority/org/repo?ref=group/version",
|
||||
cloneSpec: "https://authority/org/repo.git",
|
||||
absPath: notCloned.String(),
|
||||
repoSpec: RepoSpec{
|
||||
Host: "https://authority/",
|
||||
OrgRepo: "org/repo",
|
||||
Ref: "group/version",
|
||||
GitSuffix: ".git",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "query_git_delimiter",
|
||||
input: "https://authority/org/repo/?ref=includes_git/for_some_reason",
|
||||
cloneSpec: "https://authority/org/repo.git",
|
||||
absPath: notCloned.String(),
|
||||
repoSpec: RepoSpec{
|
||||
Host: "https://authority/",
|
||||
OrgRepo: "org/repo",
|
||||
Ref: "includes_git/for_some_reason",
|
||||
GitSuffix: ".git",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "query_git_suffix",
|
||||
input: "https://authority/org/repo/?ref=includes.git/for_some_reason",
|
||||
cloneSpec: "https://authority/org/repo.git",
|
||||
absPath: notCloned.String(),
|
||||
repoSpec: RepoSpec{
|
||||
Host: "https://authority/",
|
||||
OrgRepo: "org/repo",
|
||||
Ref: "includes.git/for_some_reason",
|
||||
GitSuffix: ".git",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "non_parsable_path",
|
||||
input: "https://authority/org/repo/%-invalid-uri-so-not-parsable-by-net/url.Parse",
|
||||
cloneSpec: "https://authority/org/repo.git",
|
||||
absPath: notCloned.Join("%-invalid-uri-so-not-parsable-by-net/url.Parse"),
|
||||
repoSpec: RepoSpec{
|
||||
Host: "https://authority/",
|
||||
OrgRepo: "org/repo",
|
||||
Path: "%-invalid-uri-so-not-parsable-by-net/url.Parse",
|
||||
GitSuffix: ".git",
|
||||
},
|
||||
},
|
||||
}
|
||||
for tn, tc := range testcases {
|
||||
t.Run(tn, func(t *testing.T) {
|
||||
rs, err := NewRepoSpecFromUrl(tc.input)
|
||||
assert.NoError(t, err)
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if tc.skip != "" {
|
||||
t.Skip(tc.skip)
|
||||
}
|
||||
|
||||
rs, err := NewRepoSpecFromURL(tc.input)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.cloneSpec, rs.CloneSpec(), "cloneSpec mismatch")
|
||||
assert.Equal(t, tc.absPath, rs.AbsPath(), "absPath mismatch")
|
||||
assert.Equal(t, tc.ref, rs.Ref, "ref mismatch")
|
||||
// some values have defaults. Clear them here so test cases remain compact.
|
||||
// This means submodules and timeout cannot be tested here. That's fine since
|
||||
// they are tested in TestParseQuery.
|
||||
rs.raw = ""
|
||||
rs.Dir = ""
|
||||
rs.Submodules = false
|
||||
rs.Timeout = 0
|
||||
assert.Equal(t, &tc.repoSpec, rs)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewRepoSpecFromURL_DefaultQueryParams(t *testing.T) {
|
||||
repoSpec, err := NewRepoSpecFromURL("https://github.com/org/repo")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, defaultSubmodules, repoSpec.Submodules)
|
||||
require.Equal(t, defaultTimeout, repoSpec.Timeout)
|
||||
}
|
||||
|
||||
func TestIsAzureHost(t *testing.T) {
|
||||
testcases := []struct {
|
||||
input string
|
||||
@@ -230,131 +515,136 @@ func TestIsAzureHost(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPeelQuery(t *testing.T) {
|
||||
testcases := map[string]struct {
|
||||
func TestParseQuery(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input string
|
||||
path string
|
||||
ref string
|
||||
submodules bool
|
||||
timeout time.Duration
|
||||
}{
|
||||
"t1": {
|
||||
// All empty.
|
||||
input: "somerepos",
|
||||
path: "somerepos",
|
||||
{
|
||||
name: "empty",
|
||||
input: "",
|
||||
ref: "",
|
||||
submodules: defaultSubmodules,
|
||||
timeout: defaultTimeout,
|
||||
},
|
||||
"t2": {
|
||||
input: "somerepos?ref=v1.0.0",
|
||||
path: "somerepos",
|
||||
{
|
||||
name: "ref",
|
||||
input: "ref=v1.0.0",
|
||||
ref: "v1.0.0",
|
||||
submodules: defaultSubmodules,
|
||||
timeout: defaultTimeout,
|
||||
},
|
||||
"t3": {
|
||||
input: "somerepos?version=master",
|
||||
path: "somerepos",
|
||||
{
|
||||
name: "ref_slash",
|
||||
input: "ref=kustomize/v4.5.7",
|
||||
ref: "kustomize/v4.5.7",
|
||||
submodules: defaultSubmodules,
|
||||
timeout: defaultTimeout,
|
||||
},
|
||||
{
|
||||
name: "version",
|
||||
input: "version=master",
|
||||
ref: "master",
|
||||
submodules: defaultSubmodules,
|
||||
timeout: defaultTimeout,
|
||||
},
|
||||
"t4": {
|
||||
{
|
||||
name: "ref_and_version",
|
||||
// A ref value takes precedence over a version value.
|
||||
input: "somerepos?version=master&ref=v1.0.0",
|
||||
path: "somerepos",
|
||||
input: "version=master&ref=v1.0.0",
|
||||
ref: "v1.0.0",
|
||||
submodules: defaultSubmodules,
|
||||
timeout: defaultTimeout,
|
||||
},
|
||||
"t5": {
|
||||
{
|
||||
name: "empty_submodules",
|
||||
// Empty submodules value uses default.
|
||||
input: "somerepos?version=master&submodules=",
|
||||
path: "somerepos",
|
||||
input: "version=master&submodules=",
|
||||
ref: "master",
|
||||
submodules: defaultSubmodules,
|
||||
timeout: defaultTimeout,
|
||||
},
|
||||
"t6": {
|
||||
{
|
||||
name: "bad_submodules",
|
||||
// Malformed submodules value uses default.
|
||||
input: "somerepos?version=master&submodules=maybe",
|
||||
path: "somerepos",
|
||||
input: "version=master&submodules=maybe",
|
||||
ref: "master",
|
||||
submodules: defaultSubmodules,
|
||||
timeout: defaultTimeout,
|
||||
},
|
||||
"t7": {
|
||||
input: "somerepos?version=master&submodules=true",
|
||||
path: "somerepos",
|
||||
{
|
||||
name: "submodules_true",
|
||||
input: "version=master&submodules=true",
|
||||
ref: "master",
|
||||
submodules: true,
|
||||
timeout: defaultTimeout,
|
||||
},
|
||||
"t8": {
|
||||
input: "somerepos?version=master&submodules=false",
|
||||
path: "somerepos",
|
||||
{
|
||||
name: "submodules_false",
|
||||
input: "version=master&submodules=false",
|
||||
ref: "master",
|
||||
submodules: false,
|
||||
timeout: defaultTimeout,
|
||||
},
|
||||
"t9": {
|
||||
{
|
||||
name: "empty_timeout",
|
||||
// Empty timeout value uses default.
|
||||
input: "somerepos?version=master&timeout=",
|
||||
path: "somerepos",
|
||||
input: "version=master&timeout=",
|
||||
ref: "master",
|
||||
submodules: defaultSubmodules,
|
||||
timeout: defaultTimeout,
|
||||
},
|
||||
"t10": {
|
||||
{
|
||||
name: "bad_timeout",
|
||||
// Malformed timeout value uses default.
|
||||
input: "somerepos?version=master&timeout=jiffy",
|
||||
path: "somerepos",
|
||||
input: "version=master&timeout=jiffy",
|
||||
ref: "master",
|
||||
submodules: defaultSubmodules,
|
||||
timeout: defaultTimeout,
|
||||
},
|
||||
"t11": {
|
||||
{
|
||||
name: "zero_timeout",
|
||||
// Zero timeout value uses default.
|
||||
input: "somerepos?version=master&timeout=0",
|
||||
path: "somerepos",
|
||||
input: "version=master&timeout=0",
|
||||
ref: "master",
|
||||
submodules: defaultSubmodules,
|
||||
timeout: defaultTimeout,
|
||||
},
|
||||
"t12": {
|
||||
input: "somerepos?version=master&timeout=0s",
|
||||
path: "somerepos",
|
||||
{
|
||||
name: "zero_unit_timeout",
|
||||
input: "version=master&timeout=0s",
|
||||
ref: "master",
|
||||
submodules: defaultSubmodules,
|
||||
timeout: defaultTimeout,
|
||||
},
|
||||
"t13": {
|
||||
input: "somerepos?version=master&timeout=61",
|
||||
path: "somerepos",
|
||||
{
|
||||
name: "timeout",
|
||||
input: "version=master&timeout=61",
|
||||
ref: "master",
|
||||
submodules: defaultSubmodules,
|
||||
timeout: 61 * time.Second,
|
||||
},
|
||||
"t14": {
|
||||
input: "somerepos?version=master&timeout=1m1s",
|
||||
path: "somerepos",
|
||||
{
|
||||
name: "timeout_unit",
|
||||
input: "version=master&timeout=1m1s",
|
||||
ref: "master",
|
||||
submodules: defaultSubmodules,
|
||||
timeout: 61 * time.Second,
|
||||
},
|
||||
"t15": {
|
||||
input: "somerepos?version=master&submodules=false&timeout=1m1s",
|
||||
path: "somerepos",
|
||||
{
|
||||
name: "all",
|
||||
input: "version=master&submodules=false&timeout=1m1s",
|
||||
ref: "master",
|
||||
submodules: false,
|
||||
timeout: 61 * time.Second,
|
||||
},
|
||||
}
|
||||
for tn, tc := range testcases {
|
||||
t.Run(tn, func(t *testing.T) {
|
||||
path, ref, timeout, submodules := peelQuery(tc.input)
|
||||
assert.Equal(t, tc.path, path, "path mismatch")
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
ref, timeout, submodules := parseQuery(tc.input)
|
||||
assert.Equal(t, tc.ref, ref, "ref mismatch")
|
||||
assert.Equal(t, tc.timeout, timeout, "timeout mismatch")
|
||||
assert.Equal(t, tc.submodules, submodules, "submodules mismatch")
|
||||
|
||||
7
api/internal/localizer/doc.go
Normal file
7
api/internal/localizer/doc.go
Normal file
@@ -0,0 +1,7 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package localizer contains utilities for the command kustomize localize, which is
|
||||
// documented under proposals/localize-command or at
|
||||
// https://github.com/kubernetes-sigs/kustomize/blob/master/proposals/22-04-localize-command.md
|
||||
package localizer
|
||||
129
api/internal/localizer/localizer.go
Normal file
129
api/internal/localizer/localizer.go
Normal file
@@ -0,0 +1,129 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package localizer
|
||||
|
||||
import (
|
||||
"log"
|
||||
"path/filepath"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
||||
"sigs.k8s.io/kustomize/api/internal/target"
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
"sigs.k8s.io/kustomize/api/loader"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// Localizer encapsulates all state needed to localize the root at ldr.
|
||||
type Localizer struct {
|
||||
fSys filesys.FileSystem
|
||||
|
||||
// kusttarget fields
|
||||
validator ifc.Validator
|
||||
rFactory *resmap.Factory
|
||||
pLdr *pLdr.Loader
|
||||
|
||||
// underlying type is Loader
|
||||
ldr ifc.Loader
|
||||
|
||||
// destination directory in newDir that mirrors ldr's current root.
|
||||
dst filesys.ConfirmedDir
|
||||
}
|
||||
|
||||
// NewLocalizer is the factory method for Localizer
|
||||
func NewLocalizer(ldr *Loader, validator ifc.Validator, rFactory *resmap.Factory, pLdr *pLdr.Loader) (*Localizer, error) {
|
||||
toDst, err := filepath.Rel(ldr.args.Scope.String(), ldr.Root())
|
||||
if err != nil {
|
||||
log.Fatalf("cannot find path from %q to child directory %q: %s", ldr.args.Scope, ldr.Root(), err)
|
||||
}
|
||||
dst := ldr.args.NewDir.Join(toDst)
|
||||
if err = ldr.fSys.MkdirAll(dst); err != nil {
|
||||
return nil, errors.WrapPrefixf(err, "unable to create directory in localize destination")
|
||||
}
|
||||
return &Localizer{
|
||||
fSys: ldr.fSys,
|
||||
validator: validator,
|
||||
rFactory: rFactory,
|
||||
pLdr: pLdr,
|
||||
ldr: ldr,
|
||||
dst: filesys.ConfirmedDir(dst),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Localize localizes the root that lc is at
|
||||
func (lc *Localizer) Localize() error {
|
||||
kt := target.NewKustTarget(lc.ldr, lc.validator, lc.rFactory, lc.pLdr)
|
||||
err := kt.Load()
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
kust, err := lc.processKust(kt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
content, err := yaml.Marshal(kust)
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "unable to serialize localized kustomization file")
|
||||
}
|
||||
if err = lc.fSys.WriteFile(lc.dst.Join(konfig.DefaultKustomizationFileName()), content); err != nil {
|
||||
return errors.WrapPrefixf(err, "unable to write localized kustomization file")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// processKust returns a copy of the kustomization at kt with paths localized.
|
||||
func (lc *Localizer) processKust(kt *target.KustTarget) (*types.Kustomization, error) {
|
||||
kust := kt.Kustomization()
|
||||
for i := range kust.Patches {
|
||||
if kust.Patches[i].Path != "" {
|
||||
newPath, err := lc.localizeFile(kust.Patches[i].Path)
|
||||
if err != nil {
|
||||
return nil, errors.WrapPrefixf(err, "unable to localize patches path %q", kust.Patches[i].Path)
|
||||
}
|
||||
kust.Patches[i].Path = newPath
|
||||
}
|
||||
}
|
||||
// TODO(annasong): localize all other kustomization fields: resources, components, crds, configurations,
|
||||
// openapi, patchesStrategicMerge, replacements, configMapGenerators, secretGenerators
|
||||
// TODO(annasong): localize built-in plugins under generators, transformers, and validators fields
|
||||
return &kust, nil
|
||||
}
|
||||
|
||||
// localizeFile localizes file path and returns the localized path
|
||||
func (lc *Localizer) localizeFile(path string) (string, error) {
|
||||
content, err := lc.ldr.Load(path)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err)
|
||||
}
|
||||
|
||||
var locPath string
|
||||
if loader.IsRemoteFile(path) {
|
||||
// TODO(annasong): check if able to add localize directory
|
||||
locPath = locFilePath(path)
|
||||
} else {
|
||||
// ldr has checked that path must be relative; this is subject to change in beta.
|
||||
|
||||
// We must clean path to:
|
||||
// 1. avoid symlinks. A `kustomize build` run will fail if we write files to
|
||||
// symlink paths outside the current root, given that we don't want to recreate
|
||||
// the symlinks. Even worse, we could be writing files outside the localize destination.
|
||||
// 2. avoid paths that temporarily traverse outside the current root,
|
||||
// i.e. ../../../scope/target/current-root. The localized file will be surrounded by
|
||||
// different directories than its source, and so an uncleaned path may no longer be valid.
|
||||
locPath = cleanFilePath(lc.fSys, filesys.ConfirmedDir(lc.ldr.Root()), path)
|
||||
// TODO(annasong): check if hits localize directory
|
||||
}
|
||||
absPath := lc.dst.Join(locPath)
|
||||
if err = lc.fSys.MkdirAll(filepath.Dir(absPath)); err != nil {
|
||||
return "", errors.WrapPrefixf(err, "unable to create directories to localize file %q", path)
|
||||
}
|
||||
if err = lc.fSys.WriteFile(absPath, content); err != nil {
|
||||
return "", errors.WrapPrefixf(err, "unable to localize file %q", path)
|
||||
}
|
||||
return locPath, nil
|
||||
}
|
||||
301
api/internal/localizer/localizer_test.go
Normal file
301
api/internal/localizer/localizer_test.go
Normal file
@@ -0,0 +1,301 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package localizer_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"sigs.k8s.io/kustomize/api/hasher"
|
||||
. "sigs.k8s.io/kustomize/api/internal/localizer"
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
||||
"sigs.k8s.io/kustomize/api/internal/validate"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||
)
|
||||
|
||||
const podConfiguration = `apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: pod
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.14.2
|
||||
ports:
|
||||
- containerPort: 80
|
||||
`
|
||||
|
||||
func makeMemoryFs(t *testing.T) filesys.FileSystem {
|
||||
t.Helper()
|
||||
req := require.New(t)
|
||||
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
req.NoError(fSys.MkdirAll("/a/b"))
|
||||
req.NoError(fSys.WriteFile("/a/pod.yaml", []byte(podConfiguration)))
|
||||
|
||||
dirChain := "/alpha/beta/gamma/delta"
|
||||
req.NoError(fSys.MkdirAll(dirChain))
|
||||
req.NoError(fSys.WriteFile(filepath.Join(dirChain, "deployment.yaml"), []byte("deployment configuration")))
|
||||
req.NoError(fSys.Mkdir("/alpha/beta/say"))
|
||||
return fSys
|
||||
}
|
||||
|
||||
func addFiles(t *testing.T, fSys filesys.FileSystem, parentDir string, files map[string]string) {
|
||||
t.Helper()
|
||||
|
||||
// in-memory file system makes all necessary dirs when writing files
|
||||
for file, content := range files {
|
||||
require.NoError(t, fSys.WriteFile(filepath.Join(parentDir, file), []byte(content)))
|
||||
}
|
||||
}
|
||||
|
||||
func createLocalizer(t *testing.T, fSys filesys.FileSystem, target string, scope string, newDir string) *Localizer {
|
||||
t.Helper()
|
||||
|
||||
// no need to re-test Loader
|
||||
ldr, _, err := NewLoader(target, scope, newDir, fSys)
|
||||
require.NoError(t, err)
|
||||
rmFactory := resmap.NewFactory(resource.NewFactory(&hasher.Hasher{}))
|
||||
lc, err := NewLocalizer(
|
||||
ldr,
|
||||
validate.NewFieldValidator(),
|
||||
rmFactory,
|
||||
// file system can be in memory, as plugin configuration will prevent the use of file system anyway
|
||||
loader.NewLoader(types.DisabledPluginConfig(), rmFactory, fSys))
|
||||
require.NoError(t, err)
|
||||
return lc
|
||||
}
|
||||
|
||||
func checkFSys(t *testing.T, fSysExpected filesys.FileSystem, fSysActual filesys.FileSystem) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, fSysExpected, fSysActual)
|
||||
if t.Failed() {
|
||||
reportFSysDiff(t, fSysExpected, fSysActual)
|
||||
}
|
||||
}
|
||||
|
||||
func reportFSysDiff(t *testing.T, fSysExpected filesys.FileSystem, fSysActual filesys.FileSystem) {
|
||||
t.Helper()
|
||||
|
||||
visited := make(map[string]struct{})
|
||||
err := fSysActual.Walk("/", func(path string, info fs.FileInfo, err error) error {
|
||||
require.NoError(t, err)
|
||||
visited[path] = struct{}{}
|
||||
|
||||
if info.IsDir() {
|
||||
assert.Truef(t, fSysExpected.IsDir(path), "unexpected directory %q", path)
|
||||
} else {
|
||||
actualContent, readErr := fSysActual.ReadFile(path)
|
||||
require.NoError(t, readErr)
|
||||
expectedContent, findErr := fSysExpected.ReadFile(path)
|
||||
assert.NoError(t, findErr)
|
||||
if findErr == nil {
|
||||
assert.Equal(t, string(expectedContent), string(actualContent))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = fSysExpected.Walk("/", func(path string, info fs.FileInfo, err error) error {
|
||||
require.NoError(t, err)
|
||||
visited[path] = struct{}{}
|
||||
|
||||
if _, exists := visited[path]; !exists {
|
||||
t.Errorf("expected path %q not found", path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestNewLocalizerTargetIsScope(t *testing.T) {
|
||||
fSys := makeMemoryFs(t)
|
||||
kustomization := map[string]string{
|
||||
"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
namePrefix: my-
|
||||
`,
|
||||
}
|
||||
addFiles(t, fSys, "/a", kustomization)
|
||||
lclzr := createLocalizer(t, fSys, "/a", "", "/a/b/dst")
|
||||
require.NoError(t, lclzr.Localize())
|
||||
|
||||
fSysExpected := makeMemoryFs(t)
|
||||
addFiles(t, fSysExpected, "/a", kustomization)
|
||||
addFiles(t, fSysExpected, "/a/b/dst", kustomization)
|
||||
checkFSys(t, fSysExpected, fSys)
|
||||
}
|
||||
|
||||
func TestNewLocalizerTargetNestedInScope(t *testing.T) {
|
||||
fSys := makeMemoryFs(t)
|
||||
kustomization := map[string]string{
|
||||
"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
patches:
|
||||
- patch: |-
|
||||
- op: replace
|
||||
path: /some/existing/path
|
||||
value: new value
|
||||
target:
|
||||
kind: Deployment
|
||||
labelSelector: env=dev
|
||||
`,
|
||||
}
|
||||
addFiles(t, fSys, "/a/b", kustomization)
|
||||
lclzr := createLocalizer(t, fSys, "/a/b", "/", "/a/b/dst")
|
||||
require.NoError(t, lclzr.Localize())
|
||||
|
||||
fSysExpected := makeMemoryFs(t)
|
||||
addFiles(t, fSysExpected, "/a/b", kustomization)
|
||||
addFiles(t, fSysExpected, "/a/b/dst/a/b", kustomization)
|
||||
checkFSys(t, fSysExpected, fSys)
|
||||
}
|
||||
|
||||
func TestLocalizeKustomizationName(t *testing.T) {
|
||||
fSys := makeMemoryFs(t)
|
||||
kustomization := map[string]string{
|
||||
"Kustomization": `apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
commonLabels:
|
||||
label-one: value-one
|
||||
label-two: value-two
|
||||
kind: Kustomization
|
||||
`,
|
||||
}
|
||||
addFiles(t, fSys, "/a", kustomization)
|
||||
|
||||
lclzr := createLocalizer(t, fSys, "/a", "/", "/dst")
|
||||
require.NoError(t, lclzr.Localize())
|
||||
|
||||
fSysExpected := makeMemoryFs(t)
|
||||
addFiles(t, fSysExpected, "/a", kustomization)
|
||||
addFiles(t, fSysExpected, "/dst/a", map[string]string{
|
||||
"kustomization.yaml": kustomization["Kustomization"],
|
||||
})
|
||||
checkFSys(t, fSysExpected, fSys)
|
||||
}
|
||||
|
||||
func TestLocalizeFileName(t *testing.T) {
|
||||
for name, path := range map[string]string{
|
||||
"nested_directories": "a/b/c/d/patch.yaml",
|
||||
"localize_dir_name_when_absent": LocalizeDir,
|
||||
"in_localize_dir_name_when_absent": fmt.Sprintf("%s/patch.yaml", LocalizeDir),
|
||||
"no_file_extension": "patch",
|
||||
"kustomization_name": "a/kustomization.yaml",
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
fSys := makeMemoryFs(t)
|
||||
kustAndPatch := map[string]string{
|
||||
"kustomization.yaml": fmt.Sprintf(`apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
patches:
|
||||
- path: %s
|
||||
`, path),
|
||||
path: podConfiguration,
|
||||
}
|
||||
addFiles(t, fSys, "/a", kustAndPatch)
|
||||
|
||||
lclzr := createLocalizer(t, fSys, "/a", "/", "/a/dst")
|
||||
require.NoError(t, lclzr.Localize())
|
||||
|
||||
fSysExpected := makeMemoryFs(t)
|
||||
addFiles(t, fSysExpected, "/a", kustAndPatch)
|
||||
addFiles(t, fSysExpected, "/a/dst/a", kustAndPatch)
|
||||
checkFSys(t, fSysExpected, fSys)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizeFileCleaned(t *testing.T) {
|
||||
fSys := makeMemoryFs(t)
|
||||
kustAndPatch := map[string]string{
|
||||
"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
patches:
|
||||
- path: ../gamma/../../../alpha/beta/./gamma/patch.yaml
|
||||
`,
|
||||
"patch.yaml": podConfiguration,
|
||||
}
|
||||
addFiles(t, fSys, "/alpha/beta/gamma", kustAndPatch)
|
||||
|
||||
lclzr := createLocalizer(t, fSys, "/alpha/beta/gamma", "/", "")
|
||||
require.NoError(t, lclzr.Localize())
|
||||
|
||||
fSysExpected := makeMemoryFs(t)
|
||||
addFiles(t, fSysExpected, "/alpha/beta/gamma", kustAndPatch)
|
||||
addFiles(t, fSysExpected, "/localized-gamma/alpha/beta/gamma", map[string]string{
|
||||
"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
patches:
|
||||
- path: patch.yaml
|
||||
`,
|
||||
"patch.yaml": podConfiguration,
|
||||
})
|
||||
checkFSys(t, fSysExpected, fSys)
|
||||
}
|
||||
|
||||
func TestLocalizePatches(t *testing.T) {
|
||||
fSys := makeMemoryFs(t)
|
||||
kustAndPatch := map[string]string{
|
||||
"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
patches:
|
||||
- patch: |-
|
||||
apiVersion: v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/version: 1.21.0
|
||||
name: dummy-app
|
||||
target:
|
||||
labelSelector: app.kubernetes.io/name=nginx
|
||||
- options:
|
||||
allowNameChange: true
|
||||
path: patch.yaml
|
||||
`,
|
||||
"patch.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: not-used
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.21.0
|
||||
`,
|
||||
}
|
||||
addFiles(t, fSys, "/", kustAndPatch)
|
||||
|
||||
lclzr := createLocalizer(t, fSys, "/", "", "")
|
||||
require.NoError(t, lclzr.Localize())
|
||||
|
||||
fSysExpected := makeMemoryFs(t)
|
||||
addFiles(t, fSysExpected, "/", kustAndPatch)
|
||||
addFiles(t, fSysExpected, "/localized", kustAndPatch)
|
||||
checkFSys(t, fSysExpected, fSys)
|
||||
}
|
||||
|
||||
func TestLocalizeFileNoFile(t *testing.T) {
|
||||
fSys := makeMemoryFs(t)
|
||||
kustAndPatch := map[string]string{
|
||||
"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
patches:
|
||||
- path: name-DNE.yaml
|
||||
`,
|
||||
}
|
||||
addFiles(t, fSys, "/a/b", kustAndPatch)
|
||||
|
||||
lclzr := createLocalizer(t, fSys, "/a/b", "", "/dst")
|
||||
require.Error(t, lclzr.Localize())
|
||||
}
|
||||
135
api/internal/localizer/locloader.go
Normal file
135
api/internal/localizer/locloader.go
Normal file
@@ -0,0 +1,135 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package localizer
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/kustomize/api/internal/git"
|
||||
"sigs.k8s.io/kustomize/api/loader"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||
)
|
||||
|
||||
// Args holds localize arguments
|
||||
type Args struct {
|
||||
// target; local copy if remote
|
||||
Target filesys.ConfirmedDir
|
||||
|
||||
// directory that bounds target's local references
|
||||
// repo directory of local copy if target is remote
|
||||
Scope filesys.ConfirmedDir
|
||||
|
||||
// localize destination
|
||||
NewDir filesys.ConfirmedDir
|
||||
}
|
||||
|
||||
// Loader is an ifc.Loader that enforces additional constraints specific to kustomize localize.
|
||||
type Loader struct {
|
||||
fSys filesys.FileSystem
|
||||
|
||||
args *Args
|
||||
|
||||
// loader at Loader's current directory
|
||||
ifc.Loader
|
||||
|
||||
// whether Loader and all its ancestors are the result of local references
|
||||
local bool
|
||||
}
|
||||
|
||||
var _ ifc.Loader = &Loader{}
|
||||
|
||||
// NewLoader is the factory method for Loader, under localize constraints, at rawTarget. For invalid localize arguments,
|
||||
// NewLoader returns an error.
|
||||
func NewLoader(rawTarget string, rawScope string, rawNewDir string, fSys filesys.FileSystem) (*Loader, Args, error) {
|
||||
// check earlier to avoid cleanup
|
||||
repoSpec, err := git.NewRepoSpecFromURL(rawTarget)
|
||||
if err == nil && repoSpec.Ref == "" {
|
||||
return nil, Args{}, errors.Errorf("localize remote root %q missing ref query string parameter", rawTarget)
|
||||
}
|
||||
|
||||
// for security, should enforce load restrictions
|
||||
ldr, err := loader.NewLoader(loader.RestrictionRootOnly, rawTarget, fSys)
|
||||
if err != nil {
|
||||
return nil, Args{}, errors.WrapPrefixf(err, "unable to establish localize target %q", rawTarget)
|
||||
}
|
||||
|
||||
scope, err := establishScope(rawScope, rawTarget, ldr, fSys)
|
||||
if err != nil {
|
||||
_ = ldr.Cleanup()
|
||||
return nil, Args{}, errors.WrapPrefixf(err, "invalid localize scope %q", rawScope)
|
||||
}
|
||||
|
||||
newDir, err := createNewDir(rawNewDir, ldr, repoSpec, fSys)
|
||||
if err != nil {
|
||||
_ = ldr.Cleanup()
|
||||
return nil, Args{}, errors.WrapPrefixf(err, "invalid localize destination %q", rawNewDir)
|
||||
}
|
||||
|
||||
args := Args{
|
||||
Target: filesys.ConfirmedDir(ldr.Root()),
|
||||
Scope: scope,
|
||||
NewDir: newDir,
|
||||
}
|
||||
return &Loader{
|
||||
fSys: fSys,
|
||||
args: &args,
|
||||
Loader: ldr,
|
||||
local: scope != "",
|
||||
}, args, nil
|
||||
}
|
||||
|
||||
// Load returns the contents of path if path is a valid localize file.
|
||||
// Otherwise, Load returns an error.
|
||||
func (ll *Loader) Load(path string) ([]byte, error) {
|
||||
// checks in root, and thus in scope
|
||||
content, err := ll.Loader.Load(path)
|
||||
if err != nil {
|
||||
return nil, errors.WrapPrefixf(err, "invalid file reference")
|
||||
}
|
||||
if filepath.IsAbs(path) {
|
||||
return nil, errors.Errorf("absolute paths not yet supported in alpha: file path %q is absolute", path)
|
||||
}
|
||||
if ll.local {
|
||||
cleanPath := cleanFilePath(ll.fSys, filesys.ConfirmedDir(ll.Root()), path)
|
||||
cleanAbs := filepath.Join(ll.Root(), cleanPath)
|
||||
dir := filesys.ConfirmedDir(filepath.Dir(cleanAbs))
|
||||
// target cannot reference newDir, as this load would've failed prior to localize;
|
||||
// not a problem if remote because then reference could only be in newDir if repo copy,
|
||||
// which will be cleaned, is inside newDir
|
||||
if dir.HasPrefix(ll.args.NewDir) {
|
||||
return nil, errors.Errorf("file %q at %q enters localize destination %q", path, cleanAbs, ll.args.NewDir)
|
||||
}
|
||||
}
|
||||
return content, nil
|
||||
}
|
||||
|
||||
// New returns a Loader at path if path is a valid localize root.
|
||||
// Otherwise, New returns an error.
|
||||
func (ll *Loader) New(path string) (ifc.Loader, error) {
|
||||
ldr, err := ll.Loader.New(path)
|
||||
if err != nil {
|
||||
return nil, errors.WrapPrefixf(err, "invalid root reference")
|
||||
}
|
||||
|
||||
if repo := ldr.Repo(); repo == "" {
|
||||
if ll.local && !filesys.ConfirmedDir(ldr.Root()).HasPrefix(ll.args.Scope) {
|
||||
return nil, errors.Errorf("root %q outside localize scope %q", ldr.Root(), ll.args.Scope)
|
||||
}
|
||||
if ll.local && filesys.ConfirmedDir(ldr.Root()).HasPrefix(ll.args.NewDir) {
|
||||
return nil, errors.Errorf(
|
||||
"root %q references into localize destination %q", ldr.Root(), ll.args.NewDir)
|
||||
}
|
||||
} else if !hasRef(path) {
|
||||
return nil, errors.Errorf("localize remote root %q missing ref query string parameter", path)
|
||||
}
|
||||
|
||||
return &Loader{
|
||||
fSys: ll.fSys,
|
||||
args: ll.args,
|
||||
Loader: ldr,
|
||||
local: ll.local && ldr.Repo() == "",
|
||||
}, nil
|
||||
}
|
||||
293
api/internal/localizer/locloader_test.go
Normal file
293
api/internal/localizer/locloader_test.go
Normal file
@@ -0,0 +1,293 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package localizer_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
. "sigs.k8s.io/kustomize/api/internal/localizer"
|
||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||
)
|
||||
|
||||
func checkNewLoader(req *require.Assertions, ldr *Loader, args *Args, target string, scope string, newDir string, fSys filesys.FileSystem) {
|
||||
checkLoader(req, ldr, target)
|
||||
checkArgs(req, args, target, scope, newDir, fSys)
|
||||
}
|
||||
|
||||
func checkLoader(req *require.Assertions, ldr ifc.Loader, root string) {
|
||||
req.Equal(root, ldr.Root())
|
||||
req.Empty(ldr.Repo())
|
||||
}
|
||||
|
||||
func checkArgs(req *require.Assertions, args *Args, target string, scope string, newDir string, fSys filesys.FileSystem) {
|
||||
req.Equal(target, args.Target.String())
|
||||
req.Equal(scope, args.Scope.String())
|
||||
req.Equal(newDir, args.NewDir.String())
|
||||
req.True(fSys.Exists(newDir))
|
||||
}
|
||||
|
||||
func TestLocalLoadNewAndCleanup(t *testing.T) {
|
||||
req := require.New(t)
|
||||
fSys := makeMemoryFs(t)
|
||||
|
||||
var buf bytes.Buffer
|
||||
log.SetOutput(&buf)
|
||||
// typical setup
|
||||
ldr, args, err := NewLoader("a", "/", "/newDir", fSys)
|
||||
req.NoError(err)
|
||||
checkNewLoader(req, ldr, &args, "/a", "/", "/newDir", fSys)
|
||||
|
||||
fSysCopy := makeMemoryFs(t)
|
||||
req.NoError(fSysCopy.Mkdir("/newDir"))
|
||||
req.Equal(fSysCopy, fSys)
|
||||
|
||||
// easy load directly in root
|
||||
content, err := ldr.Load("pod.yaml")
|
||||
req.NoError(err)
|
||||
req.Equal([]byte(podConfiguration), content)
|
||||
|
||||
// typical sibling root reference
|
||||
sibLdr, err := ldr.New("../alpha")
|
||||
req.NoError(err)
|
||||
checkLoader(req, sibLdr, "/alpha")
|
||||
|
||||
// only need to test once, since don't need to call Cleanup() on local target
|
||||
req.NoError(sibLdr.Cleanup())
|
||||
req.NoError(ldr.Cleanup())
|
||||
|
||||
// file system and buffer checks are also one-time
|
||||
req.Equal(fSysCopy, fSys)
|
||||
req.Empty(buf.String())
|
||||
}
|
||||
|
||||
func TestNewLocLoaderDefaultForRootTarget(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
target string
|
||||
scope string
|
||||
}{
|
||||
"explicit": {
|
||||
"/",
|
||||
".",
|
||||
},
|
||||
"implicit": {
|
||||
".",
|
||||
"",
|
||||
},
|
||||
}
|
||||
for name, params := range cases {
|
||||
params := params
|
||||
t.Run(name, func(t *testing.T) {
|
||||
req := require.New(t)
|
||||
fSys := makeMemoryFs(t)
|
||||
|
||||
ldr, args, err := NewLoader(params.target, params.scope, "", fSys)
|
||||
req.NoError(err)
|
||||
checkNewLoader(req, ldr, &args, "/", "/", "/"+DstPrefix, fSys)
|
||||
|
||||
// file in root, but nested
|
||||
content, err := ldr.Load("a/pod.yaml")
|
||||
req.NoError(err)
|
||||
req.Equal([]byte(podConfiguration), content)
|
||||
|
||||
childLdr, err := ldr.New("a")
|
||||
req.NoError(err)
|
||||
checkLoader(req, childLdr, "/a")
|
||||
|
||||
// messy, uncleaned path
|
||||
content, err = childLdr.Load("./../a/pod.yaml")
|
||||
req.NoError(err)
|
||||
req.Equal([]byte(podConfiguration), content)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewMultiple(t *testing.T) {
|
||||
req := require.New(t)
|
||||
fSys := makeMemoryFs(t)
|
||||
|
||||
// default destination for non-file system root target
|
||||
// destination outside of scope
|
||||
ldr, args, err := NewLoader("/alpha/beta", "/alpha", "", fSys)
|
||||
req.NoError(err)
|
||||
checkNewLoader(req, ldr, &args, "/alpha/beta", "/alpha", "/"+DstPrefix+"-beta", fSys)
|
||||
|
||||
// nested child root that isn't cleaned
|
||||
descLdr, err := ldr.New("../beta/gamma/delta")
|
||||
req.NoError(err)
|
||||
checkLoader(req, descLdr, "/alpha/beta/gamma/delta")
|
||||
|
||||
// upwards traversal
|
||||
higherLdr, err := descLdr.New("../../say")
|
||||
req.NoError(err)
|
||||
checkLoader(req, higherLdr, "/alpha/beta/say")
|
||||
}
|
||||
|
||||
func makeWdFs(t *testing.T) map[string]filesys.FileSystem {
|
||||
t.Helper()
|
||||
req := require.New(t)
|
||||
|
||||
root := filesys.MakeEmptyDirInMemory()
|
||||
req.NoError(root.MkdirAll("a/b/c/d/e"))
|
||||
|
||||
outer, err := root.Find("a")
|
||||
req.NoError(err)
|
||||
middle, err := root.Find("a/b/c")
|
||||
req.NoError(err)
|
||||
|
||||
return map[string]filesys.FileSystem{
|
||||
"a": outer,
|
||||
"a/b/c": middle,
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewLocLoaderCwdNotRoot(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
wd string
|
||||
target string
|
||||
scope string
|
||||
newDir string
|
||||
}{
|
||||
// target not immediate child of scope
|
||||
"outer dir": {
|
||||
"a",
|
||||
"b/c/d/e",
|
||||
"b/c",
|
||||
"b/newDir",
|
||||
},
|
||||
"scope": {
|
||||
"a/b/c",
|
||||
"d/e",
|
||||
".",
|
||||
"d/e/newDir",
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range cases {
|
||||
test := test
|
||||
t.Run(name, func(t *testing.T) {
|
||||
req := require.New(t)
|
||||
fSys := makeWdFs(t)[test.wd]
|
||||
|
||||
ldr, args, err := NewLoader(test.target, test.scope, test.newDir, fSys)
|
||||
req.NoError(err)
|
||||
checkLoader(req, ldr, "a/b/c/d/e")
|
||||
|
||||
req.Equal("a/b/c/d/e", args.Target.String())
|
||||
req.Equal("a/b/c", args.Scope.String())
|
||||
req.Equal(test.wd+"/"+test.newDir, args.NewDir.String())
|
||||
// memory file system can only find paths rooted at current node
|
||||
req.True(fSys.Exists(test.newDir))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewLocLoaderFails(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
target string
|
||||
scope string
|
||||
dest string
|
||||
}{
|
||||
"non-existent target": {
|
||||
"/b",
|
||||
"/",
|
||||
"/newDir",
|
||||
},
|
||||
"file target": {
|
||||
"/a/pod.yaml",
|
||||
"/",
|
||||
"/newDir",
|
||||
},
|
||||
"inner scope": {
|
||||
"/alpha",
|
||||
"/alpha/beta",
|
||||
"/newDir",
|
||||
},
|
||||
"side scope": {
|
||||
"/alpha",
|
||||
"/a",
|
||||
"/newDir",
|
||||
},
|
||||
"existing dst": {
|
||||
"/alpha",
|
||||
"/",
|
||||
"/a",
|
||||
},
|
||||
}
|
||||
for name, params := range cases {
|
||||
params := params
|
||||
t.Run(name, func(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
log.SetOutput(&buf)
|
||||
|
||||
_, _, err := NewLoader(params.target, params.scope, params.dest, makeMemoryFs(t))
|
||||
require.Error(t, err)
|
||||
require.Empty(t, buf.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewFails(t *testing.T) {
|
||||
req := require.New(t)
|
||||
fSys := makeMemoryFs(t)
|
||||
|
||||
ldr, args, err := NewLoader("/alpha/beta/gamma", "alpha", "alpha/beta/gamma/newDir", fSys)
|
||||
req.NoError(err)
|
||||
checkNewLoader(req, ldr, &args, "/alpha/beta/gamma", "/alpha", "/alpha/beta/gamma/newDir", fSys)
|
||||
|
||||
cases := map[string]string{
|
||||
"outside scope": "../../../a",
|
||||
"at dst": "newDir",
|
||||
"ancestor": "../../beta",
|
||||
"non-existent root": "delt",
|
||||
"file": "delta/deployment.yaml",
|
||||
}
|
||||
for name, root := range cases {
|
||||
root := root
|
||||
t.Run(name, func(t *testing.T) {
|
||||
fSys := makeMemoryFs(t)
|
||||
|
||||
ldr, _, err := NewLoader("/alpha/beta/gamma", "alpha", "alpha/beta/gamma/newDir", fSys)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = ldr.New(root)
|
||||
require.Error(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadFails(t *testing.T) {
|
||||
req := require.New(t)
|
||||
fSys := makeMemoryFs(t)
|
||||
|
||||
ldr, args, err := NewLoader("./a/../a", "/a/../a", "/a/newDir", fSys)
|
||||
req.NoError(err)
|
||||
checkNewLoader(req, ldr, &args, "/a", "/a", "/a/newDir", fSys)
|
||||
|
||||
cases := map[string]string{
|
||||
"absolute path": "/a/pod.yaml",
|
||||
"directory": "b",
|
||||
"non-existent file": "kubectl.yaml",
|
||||
"file outside root": "../alpha/beta/gamma/delta/deployment.yaml",
|
||||
"inside dst": "newDir/pod.yaml",
|
||||
}
|
||||
for name, file := range cases {
|
||||
file := file
|
||||
t.Run(name, func(t *testing.T) {
|
||||
req := require.New(t)
|
||||
fSys := makeMemoryFs(t)
|
||||
|
||||
ldr, _, err := NewLoader("./a/../a", "/a/../a", "/a/newDir", fSys)
|
||||
req.NoError(err)
|
||||
|
||||
req.NoError(fSys.WriteFile("/a/newDir/pod.yaml", []byte(podConfiguration)))
|
||||
|
||||
_, err = ldr.Load(file)
|
||||
req.Error(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
127
api/internal/localizer/util.go
Normal file
127
api/internal/localizer/util.go
Normal file
@@ -0,0 +1,127 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package localizer
|
||||
|
||||
import (
|
||||
"log"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/kustomize/api/internal/git"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||
)
|
||||
|
||||
// DstPrefix prefixes the target and ref, if target is remote, in the default localize destination directory name
|
||||
const DstPrefix = "localized"
|
||||
|
||||
// LocalizeDir is the name of the localize directories used to store remote content in the localize destination
|
||||
const LocalizeDir = "localized-files"
|
||||
|
||||
// establishScope returns the effective scope given localize arguments and targetLdr at rawTarget. For remote rawTarget,
|
||||
// the effective scope is the downloaded repo.
|
||||
func establishScope(rawScope string, rawTarget string, targetLdr ifc.Loader, fSys filesys.FileSystem) (filesys.ConfirmedDir, error) {
|
||||
if repo := targetLdr.Repo(); repo != "" {
|
||||
if rawScope != "" {
|
||||
return "", errors.Errorf("scope %q specified for remote localize target %q", rawScope, rawTarget)
|
||||
}
|
||||
return filesys.ConfirmedDir(repo), nil
|
||||
}
|
||||
// default scope
|
||||
if rawScope == "" {
|
||||
return filesys.ConfirmedDir(targetLdr.Root()), nil
|
||||
}
|
||||
scope, err := filesys.ConfirmDir(fSys, rawScope)
|
||||
if err != nil {
|
||||
return "", errors.WrapPrefixf(err, "unable to establish localize scope")
|
||||
}
|
||||
if !filesys.ConfirmedDir(targetLdr.Root()).HasPrefix(scope) {
|
||||
return scope, errors.Errorf("localize scope %q does not contain target %q at %q", rawScope, rawTarget,
|
||||
targetLdr.Root())
|
||||
}
|
||||
return scope, nil
|
||||
}
|
||||
|
||||
// createNewDir returns the localize destination directory or error. Note that spec is nil if targetLdr is at local
|
||||
// target.
|
||||
func createNewDir(rawNewDir string, targetLdr ifc.Loader, spec *git.RepoSpec, fSys filesys.FileSystem) (filesys.ConfirmedDir, error) {
|
||||
if rawNewDir == "" {
|
||||
rawNewDir = defaultNewDir(targetLdr, spec)
|
||||
}
|
||||
if fSys.Exists(rawNewDir) {
|
||||
return "", errors.Errorf("localize destination %q already exists", rawNewDir)
|
||||
}
|
||||
// destination directory must sit in an existing directory
|
||||
if err := fSys.Mkdir(rawNewDir); err != nil {
|
||||
return "", errors.WrapPrefixf(err, "unable to create localize destination directory")
|
||||
}
|
||||
newDir, err := filesys.ConfirmDir(fSys, rawNewDir)
|
||||
if err != nil {
|
||||
if errCleanup := fSys.RemoveAll(newDir.String()); errCleanup != nil {
|
||||
log.Printf("%s", errors.WrapPrefixf(errCleanup, "unable to clean localize destination"))
|
||||
}
|
||||
return "", errors.WrapPrefixf(err, "unable to establish localize destination")
|
||||
}
|
||||
|
||||
return newDir, nil
|
||||
}
|
||||
|
||||
// defaultNewDir calculates the default localize destination directory name from targetLdr at the localize target
|
||||
// and spec of target, which is nil if target is local
|
||||
func defaultNewDir(targetLdr ifc.Loader, spec *git.RepoSpec) string {
|
||||
targetDir := filepath.Base(targetLdr.Root())
|
||||
if repo := targetLdr.Repo(); repo != "" {
|
||||
// kustomize doesn't download repo into repo-named folder
|
||||
// must find repo folder name from url
|
||||
if repo == targetLdr.Root() {
|
||||
targetDir = urlBase(spec.OrgRepo)
|
||||
}
|
||||
return strings.Join([]string{DstPrefix, targetDir, strings.ReplaceAll(spec.Ref, "/", "-")}, "-")
|
||||
}
|
||||
// special case for local target directory since destination directory cannot have "/" in name
|
||||
if targetDir == string(filepath.Separator) {
|
||||
return DstPrefix
|
||||
}
|
||||
return strings.Join([]string{DstPrefix, targetDir}, "-")
|
||||
}
|
||||
|
||||
// urlBase is the url equivalent of filepath.Base
|
||||
func urlBase(url string) string {
|
||||
cleaned := strings.TrimRight(url, "/")
|
||||
i := strings.LastIndex(cleaned, "/")
|
||||
if i < 0 {
|
||||
return cleaned
|
||||
}
|
||||
return cleaned[i+1:]
|
||||
}
|
||||
|
||||
// hasRef checks if repoURL has ref query string parameter
|
||||
func hasRef(repoURL string) bool {
|
||||
repoSpec, err := git.NewRepoSpecFromURL(repoURL)
|
||||
if err != nil {
|
||||
log.Fatalf("unable to parse validated root url: %s", err)
|
||||
}
|
||||
return repoSpec.Ref != ""
|
||||
}
|
||||
|
||||
// cleanFilePath returns file cleaned, where file is a relative path to root on fSys
|
||||
func cleanFilePath(fSys filesys.FileSystem, root filesys.ConfirmedDir, file string) string {
|
||||
abs := root.Join(file)
|
||||
dir, f, err := fSys.CleanedAbs(abs)
|
||||
if err != nil {
|
||||
log.Fatalf("cannot clean validated file path %q: %s", abs, err)
|
||||
}
|
||||
locPath, err := filepath.Rel(root.String(), dir.Join(f))
|
||||
if err != nil {
|
||||
log.Fatalf("cannot find path from parent %q to file %q: %s", root, dir.Join(f), err)
|
||||
}
|
||||
return locPath
|
||||
}
|
||||
|
||||
// locFilePath returns the relative localized path of validated file url fileURL
|
||||
// TODO(annasong): implement
|
||||
func locFilePath(_ string) string {
|
||||
return filepath.Join(LocalizeDir, "")
|
||||
}
|
||||
18
api/internal/localizer/util_test.go
Normal file
18
api/internal/localizer/util_test.go
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package localizer //nolint:testpackage
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestUrlBase(t *testing.T) {
|
||||
require.Equal(t, "repo", urlBase("https://github.com/org/repo"))
|
||||
}
|
||||
|
||||
func TestUrlBaseTrailingSlash(t *testing.T) {
|
||||
require.Equal(t, "repo", urlBase("github.com/org/repo//"))
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
// contains a Pod; Deployment, Job, StatefulSet, etc.
|
||||
// The ConfigMap is the ReferralTarget, the others are Referrers.
|
||||
//
|
||||
// If the the name of a ConfigMap instance changed from 'alice' to 'bob',
|
||||
// If the name of a ConfigMap instance changed from 'alice' to 'bob',
|
||||
// one must
|
||||
// - visit all objects that could refer to the ConfigMap (the Referrers)
|
||||
// - see if they mention 'alice',
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/kustomize/api/konfig/builtinpluginconsts"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
)
|
||||
|
||||
// TransformerConfig holds the data needed to perform transformations.
|
||||
@@ -18,6 +19,7 @@ type TransformerConfig struct {
|
||||
NameSuffix types.FsSlice `json:"nameSuffix,omitempty" yaml:"nameSuffix,omitempty"`
|
||||
NameSpace types.FsSlice `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
CommonLabels types.FsSlice `json:"commonLabels,omitempty" yaml:"commonLabels,omitempty"`
|
||||
TemplateLabels types.FsSlice `json:"templateLabels,omitempty" yaml:"templateLabels,omitempty"`
|
||||
CommonAnnotations types.FsSlice `json:"commonAnnotations,omitempty" yaml:"commonAnnotations,omitempty"`
|
||||
NameReference nbrSlice `json:"nameReference,omitempty" yaml:"nameReference,omitempty"`
|
||||
VarReference types.FsSlice `json:"varReference,omitempty" yaml:"varReference,omitempty"`
|
||||
@@ -60,6 +62,7 @@ func (t *TransformerConfig) sortFields() {
|
||||
sort.Sort(t.NamePrefix)
|
||||
sort.Sort(t.NameSpace)
|
||||
sort.Sort(t.CommonLabels)
|
||||
sort.Sort(t.TemplateLabels)
|
||||
sort.Sort(t.CommonAnnotations)
|
||||
sort.Sort(t.NameReference)
|
||||
sort.Sort(t.VarReference)
|
||||
@@ -108,40 +111,44 @@ func (t *TransformerConfig) Merge(input *TransformerConfig) (
|
||||
merged = &TransformerConfig{}
|
||||
merged.NamePrefix, err = t.NamePrefix.MergeAll(input.NamePrefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.WrapPrefixf(err, "failed to merge NamePrefix fieldSpec")
|
||||
}
|
||||
merged.NameSuffix, err = t.NameSuffix.MergeAll(input.NameSuffix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.WrapPrefixf(err, "failed to merge NameSuffix fieldSpec")
|
||||
}
|
||||
merged.NameSpace, err = t.NameSpace.MergeAll(input.NameSpace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.WrapPrefixf(err, "failed to merge NameSpace fieldSpec")
|
||||
}
|
||||
merged.CommonAnnotations, err = t.CommonAnnotations.MergeAll(
|
||||
input.CommonAnnotations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.WrapPrefixf(err, "failed to merge CommonAnnotations fieldSpec")
|
||||
}
|
||||
merged.CommonLabels, err = t.CommonLabels.MergeAll(input.CommonLabels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.WrapPrefixf(err, "failed to merge CommonLabels fieldSpec")
|
||||
}
|
||||
merged.TemplateLabels, err = t.TemplateLabels.MergeAll(input.TemplateLabels)
|
||||
if err != nil {
|
||||
return nil, errors.WrapPrefixf(err, "failed to merge TemplateLabels fieldSpec")
|
||||
}
|
||||
merged.VarReference, err = t.VarReference.MergeAll(input.VarReference)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.WrapPrefixf(err, "failed to merge VarReference fieldSpec")
|
||||
}
|
||||
merged.NameReference, err = t.NameReference.mergeAll(input.NameReference)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.WrapPrefixf(err, "failed to merge NameReference fieldSpec")
|
||||
}
|
||||
merged.Images, err = t.Images.MergeAll(input.Images)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.WrapPrefixf(err, "failed to merge Images fieldSpec")
|
||||
}
|
||||
merged.Replicas, err = t.Replicas.MergeAll(input.Replicas)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.WrapPrefixf(err, "failed to merge Replicas fieldSpec")
|
||||
}
|
||||
merged.sortFields()
|
||||
return merged, nil
|
||||
|
||||
@@ -36,7 +36,7 @@ const (
|
||||
|
||||
var stringToBuiltinPluginTypeMap map[string]BuiltinPluginType
|
||||
|
||||
func init() {
|
||||
func init() { //nolint:gochecknoinits
|
||||
stringToBuiltinPluginTypeMap = makeStringToBuiltinPluginTypeMap()
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ package execplugin
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
@@ -150,7 +149,7 @@ func (p *ExecPlugin) Transform(rm resmap.ResMap) error {
|
||||
// passes the full temp file path as the first arg to a process
|
||||
// running the plugin binary. Process output is returned.
|
||||
func (p *ExecPlugin) invokePlugin(input []byte) ([]byte, error) {
|
||||
f, err := ioutil.TempFile("", tmpConfigFilePrefix)
|
||||
f, err := os.CreateTemp("", tmpConfigFilePrefix)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(
|
||||
err, "creating tmp plugin config file")
|
||||
|
||||
@@ -83,7 +83,6 @@ metadata:
|
||||
`
|
||||
if expected != string(p.Cfg()) {
|
||||
t.Fatalf("expected cfg '%s', got '%s'", expected, string(p.Cfg()))
|
||||
|
||||
}
|
||||
if len(p.Args()) != 6 {
|
||||
t.Fatalf("unexpected arg len %d, %#v", len(p.Args()), p.Args())
|
||||
|
||||
@@ -51,13 +51,16 @@ func resourceToRNode(res *resource.Resource) (*yaml.RNode, error) {
|
||||
}
|
||||
|
||||
// GetFunctionSpec return function spec is there is. Otherwise return nil
|
||||
func GetFunctionSpec(res *resource.Resource) *runtimeutil.FunctionSpec {
|
||||
func GetFunctionSpec(res *resource.Resource) (*runtimeutil.FunctionSpec, error) {
|
||||
rnode, err := resourceToRNode(res)
|
||||
if err != nil {
|
||||
return nil
|
||||
return nil, fmt.Errorf("could not convert resource to RNode: %w", err)
|
||||
}
|
||||
|
||||
return runtimeutil.GetFunctionSpec(rnode)
|
||||
functionSpec, err := runtimeutil.GetFunctionSpec(rnode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get FunctionSpec: %w", err)
|
||||
}
|
||||
return functionSpec, nil
|
||||
}
|
||||
|
||||
func toStorageMounts(mounts []string) []runtimeutil.StorageMount {
|
||||
|
||||
@@ -42,27 +42,35 @@ func NewLoader(
|
||||
return &Loader{pc: pc, rf: rf, fs: fs}
|
||||
}
|
||||
|
||||
// LoaderWithWorkingDir returns loader after setting its working directory.
|
||||
// NOTE: This is not really a new loader since some of the Loader struct fields are pointers.
|
||||
func (l *Loader) LoaderWithWorkingDir(wd string) *Loader {
|
||||
lpc := &types.PluginConfig{
|
||||
PluginRestrictions: l.pc.PluginRestrictions,
|
||||
BpLoadingOptions: l.pc.BpLoadingOptions,
|
||||
FnpLoadingOptions: l.pc.FnpLoadingOptions,
|
||||
HelmConfig: l.pc.HelmConfig,
|
||||
}
|
||||
lpc.FnpLoadingOptions.WorkingDir = wd
|
||||
return &Loader{pc: lpc, rf: l.rf, fs: l.fs}
|
||||
}
|
||||
|
||||
// Config provides the global (not plugin specific) PluginConfig data.
|
||||
func (l *Loader) Config() *types.PluginConfig {
|
||||
return l.pc
|
||||
}
|
||||
|
||||
// SetWorkDir sets the working directory for this loader's plugins
|
||||
func (l *Loader) SetWorkDir(wd string) {
|
||||
l.pc.FnpLoadingOptions.WorkingDir = wd
|
||||
}
|
||||
|
||||
func (l *Loader) LoadGenerators(
|
||||
ldr ifc.Loader, v ifc.Validator, rm resmap.ResMap) (
|
||||
result []*resmap.GeneratorWithProperties, err error) {
|
||||
for _, res := range rm.Resources() {
|
||||
g, err := l.LoadGenerator(ldr, v, res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to load generator: %w", err)
|
||||
}
|
||||
generatorOrigin, err := resource.OriginFromCustomPlugin(res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to get origin from CustomPlugin: %w", err)
|
||||
}
|
||||
result = append(result, &resmap.GeneratorWithProperties{Generator: g, Origin: generatorOrigin})
|
||||
}
|
||||
@@ -130,15 +138,19 @@ func (l *Loader) AbsolutePluginPath(id resid.ResId) (string, error) {
|
||||
// absPluginHome is the home of kustomize Exec and Go plugins.
|
||||
// Kustomize plugin configuration files are k8s-style objects
|
||||
// containing the fields 'apiVersion' and 'kind', e.g.
|
||||
// apiVersion: apps/v1
|
||||
// kind: Deployment
|
||||
//
|
||||
// apiVersion: apps/v1
|
||||
// kind: Deployment
|
||||
//
|
||||
// kustomize reads plugin configuration data from a file path
|
||||
// specified in the 'generators:' or 'transformers:' field of a
|
||||
// kustomization file. For Exec and Go plugins, kustomize
|
||||
// uses this data to both locate the plugin and configure it.
|
||||
// Each Exec or Go plugin (its code, its tests, its supporting data
|
||||
// files, etc.) must be housed in its own directory at
|
||||
// ${absPluginHome}/${pluginApiVersion}/LOWERCASE(${pluginKind})
|
||||
//
|
||||
// ${absPluginHome}/${pluginApiVersion}/LOWERCASE(${pluginKind})
|
||||
//
|
||||
// where
|
||||
// - ${absPluginHome} is an absolute path, defined below.
|
||||
// - ${pluginApiVersion} is taken from the plugin config file.
|
||||
@@ -226,8 +238,22 @@ func (l *Loader) makeBuiltinPlugin(r resid.Gvk) (resmap.Configurable, error) {
|
||||
}
|
||||
|
||||
func (l *Loader) loadPlugin(res *resource.Resource) (resmap.Configurable, error) {
|
||||
spec := fnplugin.GetFunctionSpec(res)
|
||||
spec, err := fnplugin.GetFunctionSpec(res)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("loader: %w", err)
|
||||
}
|
||||
if spec != nil {
|
||||
// validation check that function mounts are under the current kustomization directory
|
||||
for _, mount := range spec.Container.StorageMounts {
|
||||
if filepath.IsAbs(mount.Src) {
|
||||
return nil, errors.New(fmt.Sprintf("plugin %s with mount path '%s' is not permitted; "+
|
||||
"mount paths must be relative to the current kustomization directory", res.OrgId(), mount.Src))
|
||||
}
|
||||
if strings.HasPrefix(filepath.Clean(mount.Src), "../") {
|
||||
return nil, errors.New(fmt.Sprintf("plugin %s with mount path '%s' is not permitted; "+
|
||||
"mount paths must be under the current kustomization directory", res.OrgId(), mount.Src))
|
||||
}
|
||||
}
|
||||
return fnplugin.NewFnPlugin(&l.pc.FnpLoadingOptions), nil
|
||||
}
|
||||
return l.loadExecOrGoPlugin(res.OrgId())
|
||||
|
||||
@@ -6,6 +6,7 @@ package loader_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
. "sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
||||
"sigs.k8s.io/kustomize/api/loader"
|
||||
"sigs.k8s.io/kustomize/api/provider"
|
||||
@@ -78,3 +79,20 @@ func TestLoader(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoaderWithWorkingDir(t *testing.T) {
|
||||
p := provider.NewDefaultDepProvider()
|
||||
rmF := resmap.NewFactory(p.GetResourceFactory())
|
||||
fsys := filesys.MakeFsInMemory()
|
||||
c := types.EnabledPluginConfig(types.BploLoadFromFileSys)
|
||||
pLdr := NewLoader(c, rmF, fsys)
|
||||
npLdr := pLdr.LoaderWithWorkingDir("/tmp/dummy")
|
||||
require.Equal(t,
|
||||
"",
|
||||
pLdr.Config().FnpLoadingOptions.WorkingDir,
|
||||
"the plugin working dir should not change")
|
||||
require.Equal(t,
|
||||
"/tmp/dummy",
|
||||
npLdr.Config().FnpLoadingOptions.WorkingDir,
|
||||
"the plugin working dir is not updated")
|
||||
}
|
||||
|
||||
@@ -105,10 +105,10 @@ func TestUpdateResourceOptionsWithInvalidHashAnnotationValues(t *testing.T) {
|
||||
"TrUe",
|
||||
"potato",
|
||||
}
|
||||
for i, c := range cases {
|
||||
for i := range cases {
|
||||
name := fmt.Sprintf("test%d", i)
|
||||
in := resmap.New()
|
||||
err := in.Append(makeConfigMap(rf, name, "", &c))
|
||||
err := in.Append(makeConfigMap(rf, name, "", &cases[i]))
|
||||
require.NoError(t, err)
|
||||
_, err = UpdateResourceOptions(in)
|
||||
require.Error(t, err)
|
||||
|
||||
@@ -6,7 +6,7 @@ package target
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@@ -45,13 +45,11 @@ func NewKustTarget(
|
||||
validator ifc.Validator,
|
||||
rFactory *resmap.Factory,
|
||||
pLdr *loader.Loader) *KustTarget {
|
||||
pLdrCopy := *pLdr
|
||||
pLdrCopy.SetWorkDir(ldr.Root())
|
||||
return &KustTarget{
|
||||
ldr: ldr,
|
||||
validator: validator,
|
||||
rFactory: rFactory,
|
||||
pLdr: &pLdrCopy,
|
||||
pLdr: pLdr.LoaderWithWorkingDir(ldr.Root()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +68,15 @@ func (kt *KustTarget) Load() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// show warning message when using deprecated fields.
|
||||
warningMessages := k.CheckDeprecatedFields()
|
||||
if warningMessages != nil {
|
||||
for _, msg := range *warningMessages {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", msg)
|
||||
}
|
||||
}
|
||||
|
||||
k.FixKustomizationPostUnmarshalling()
|
||||
errs := k.EnforceFields()
|
||||
if len(errs) > 0 {
|
||||
@@ -304,7 +311,9 @@ func (kt *KustTarget) configureExternalGenerators() (
|
||||
rm.Replace(r)
|
||||
}
|
||||
}
|
||||
ra.AppendAll(rm)
|
||||
if err = ra.AppendAll(rm); err != nil {
|
||||
return nil, errors.Wrapf(err, "configuring external generator")
|
||||
}
|
||||
}
|
||||
ra, err := kt.accumulateResources(ra, generatorPaths)
|
||||
if err != nil {
|
||||
@@ -348,7 +357,10 @@ func (kt *KustTarget) configureExternalTransformers(transformers []string) ([]*r
|
||||
rm.Replace(r)
|
||||
}
|
||||
}
|
||||
ra.AppendAll(rm)
|
||||
|
||||
if err = ra.AppendAll(rm); err != nil {
|
||||
return nil, errors.Wrapf(err, "configuring external transformer")
|
||||
}
|
||||
}
|
||||
ra, err := kt.accumulateResources(ra, transformerPaths)
|
||||
if err != nil {
|
||||
@@ -403,14 +415,14 @@ func (kt *KustTarget) accumulateResources(
|
||||
// try loading resource as file then as base (directory or git repository)
|
||||
if errF := kt.accumulateFile(ra, path); errF != nil {
|
||||
// not much we can do if the error is an HTTP error so we bail out
|
||||
if errors.Is(errF, load.ErrorHTTP) {
|
||||
return nil, errF
|
||||
}
|
||||
if kusterr.IsMalformedYAMLError(errF) { // Some error occurred while tyring to decode YAML file
|
||||
if errors.Is(errF, load.ErrHTTP) {
|
||||
return nil, errF
|
||||
}
|
||||
ldr, err := kt.ldr.New(path)
|
||||
if err != nil {
|
||||
if kusterr.IsMalformedYAMLError(errF) { // Some error occurred while tyring to decode YAML file
|
||||
return nil, errF
|
||||
}
|
||||
return nil, errors.Wrapf(
|
||||
err, "accumulation err='%s'", errF.Error())
|
||||
}
|
||||
@@ -425,6 +437,9 @@ func (kt *KustTarget) accumulateResources(
|
||||
ra, err = kt.accumulateDirectory(ra, ldr, false)
|
||||
}
|
||||
if err != nil {
|
||||
if kusterr.IsMalformedYAMLError(errF) { // Some error occurred while tyring to decode YAML file
|
||||
return nil, errF
|
||||
}
|
||||
return nil, errors.Wrapf(
|
||||
err, "accumulation err='%s'", errF.Error())
|
||||
}
|
||||
@@ -473,9 +488,8 @@ func (kt *KustTarget) accumulateDirectory(
|
||||
subKt.kustomization.BuildMetadata = kt.kustomization.BuildMetadata
|
||||
subKt.origin = kt.origin
|
||||
var bytes []byte
|
||||
path := ldr.Root()
|
||||
if openApiPath, exists := subKt.Kustomization().OpenAPI["path"]; exists {
|
||||
bytes, err = ldr.Load(filepath.Join(path, openApiPath))
|
||||
bytes, err = ldr.Load(openApiPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
@@ -285,6 +286,13 @@ var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func(
|
||||
if label.IncludeSelectors {
|
||||
fss, err = fss.MergeAll(tc.CommonLabels)
|
||||
} else {
|
||||
// merge spec/template/metadata fieldSpecs if includeTemplate flag is true
|
||||
if label.IncludeTemplates {
|
||||
fss, err = fss.MergeAll(tc.TemplateLabels)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to merge template fieldSpec")
|
||||
}
|
||||
}
|
||||
// only add to metadata by default
|
||||
fss, err = fss.MergeOne(types.FieldSpec{Path: "metadata/labels", CreateIfNotPresent: true})
|
||||
}
|
||||
|
||||
@@ -257,3 +257,71 @@ metadata:
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, string(expYaml), string(actYaml))
|
||||
}
|
||||
|
||||
func TestDuplicateExternalGeneratorsForbidden(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteK("/generator", `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
generators:
|
||||
- |-
|
||||
apiVersion: generators.example/v1
|
||||
kind: ManifestGenerator
|
||||
metadata:
|
||||
name: ManifestGenerator
|
||||
annotations:
|
||||
config.kubernetes.io/function: |
|
||||
container:
|
||||
image: ManifestGenerator:latest
|
||||
spec:
|
||||
image: 'someimage:12345'
|
||||
configPath: config.json
|
||||
- |-
|
||||
apiVersion: generators.example/v1
|
||||
kind: ManifestGenerator
|
||||
metadata:
|
||||
name: ManifestGenerator
|
||||
annotations:
|
||||
config.kubernetes.io/function: |
|
||||
container:
|
||||
image: ManifestGenerator:latest
|
||||
spec:
|
||||
image: 'someimage:12345'
|
||||
configPath: another_config.json
|
||||
`)
|
||||
_, err := makeAndLoadKustTarget(t, th.GetFSys(), "/generator").AccumulateTarget()
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "may not add resource with an already registered id: ManifestGenerator.v1.generators.example/ManifestGenerator")
|
||||
}
|
||||
|
||||
func TestDuplicateExternalTransformersForbidden(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteK("/transformer", `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
transformers:
|
||||
- |-
|
||||
apiVersion: transformers.example.co/v1
|
||||
kind: ValueAnnotator
|
||||
metadata:
|
||||
name: notImportantHere
|
||||
annotations:
|
||||
config.kubernetes.io/function: |
|
||||
container:
|
||||
image: example.docker.com/my-functions/valueannotator:1.0.0
|
||||
value: 'pass'
|
||||
- |-
|
||||
apiVersion: transformers.example.co/v1
|
||||
kind: ValueAnnotator
|
||||
metadata:
|
||||
name: notImportantHere
|
||||
annotations:
|
||||
config.kubernetes.io/function: |
|
||||
container:
|
||||
image: example.docker.com/my-functions/valueannotator:1.0.0
|
||||
value: 'fail'
|
||||
`)
|
||||
_, err := makeAndLoadKustTarget(t, th.GetFSys(), "/transformer").AccumulateTarget()
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "may not add resource with an already registered id: ValueAnnotator.v1.transformers.example.co/notImportantHere")
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ func makeAndLoadKustTarget(
|
||||
t *testing.T,
|
||||
fSys filesys.FileSystem,
|
||||
root string) *target.KustTarget {
|
||||
t.Helper()
|
||||
kt := makeKustTargetWithRf(t, fSys, root, provider.NewDefaultDepProvider())
|
||||
if err := kt.Load(); err != nil {
|
||||
t.Fatalf("Unexpected load error %v", err)
|
||||
@@ -32,6 +33,7 @@ func makeKustTargetWithRf(
|
||||
fSys filesys.FileSystem,
|
||||
root string,
|
||||
pvd *provider.DepProvider) *target.KustTarget {
|
||||
t.Helper()
|
||||
ldr, err := fLdr.NewLoader(fLdr.RestrictionRootOnly, root, fSys)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package utils
|
||||
|
||||
import "sigs.k8s.io/kustomize/api/konfig"
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
@@ -46,12 +49,9 @@ func PrevIds(n *yaml.RNode) ([]resid.ResId, error) {
|
||||
"number of previous namespaces, " +
|
||||
"number of previous kinds not equal")
|
||||
}
|
||||
apiVersion := n.GetApiVersion()
|
||||
group, version := resid.ParseGroupVersion(apiVersion)
|
||||
for i := range names {
|
||||
meta, err := n.GetMeta()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
group, version := resid.ParseGroupVersion(meta.APIVersion)
|
||||
gvk := resid.Gvk{
|
||||
Group: group,
|
||||
Version: version,
|
||||
|
||||
@@ -5,9 +5,6 @@ package builtinpluginconsts
|
||||
|
||||
const commonLabelFieldSpecs = `
|
||||
commonLabels:
|
||||
- path: metadata/labels
|
||||
create: true
|
||||
|
||||
- path: spec/selector
|
||||
create: true
|
||||
version: v1
|
||||
@@ -17,20 +14,10 @@ commonLabels:
|
||||
create: true
|
||||
version: v1
|
||||
kind: ReplicationController
|
||||
|
||||
- path: spec/template/metadata/labels
|
||||
create: true
|
||||
version: v1
|
||||
kind: ReplicationController
|
||||
|
||||
- path: spec/selector/matchLabels
|
||||
create: true
|
||||
kind: Deployment
|
||||
|
||||
- path: spec/template/metadata/labels
|
||||
create: true
|
||||
kind: Deployment
|
||||
|
||||
- path: spec/template/spec/affinity/podAffinity/preferredDuringSchedulingIgnoredDuringExecution/podAffinityTerm/labelSelector/matchLabels
|
||||
create: false
|
||||
group: apps
|
||||
@@ -60,28 +47,15 @@ commonLabels:
|
||||
create: true
|
||||
kind: ReplicaSet
|
||||
|
||||
- path: spec/template/metadata/labels
|
||||
create: true
|
||||
kind: ReplicaSet
|
||||
|
||||
- path: spec/selector/matchLabels
|
||||
create: true
|
||||
kind: DaemonSet
|
||||
|
||||
- path: spec/template/metadata/labels
|
||||
create: true
|
||||
kind: DaemonSet
|
||||
|
||||
- path: spec/selector/matchLabels
|
||||
create: true
|
||||
group: apps
|
||||
kind: StatefulSet
|
||||
|
||||
- path: spec/template/metadata/labels
|
||||
create: true
|
||||
group: apps
|
||||
kind: StatefulSet
|
||||
|
||||
- path: spec/template/spec/affinity/podAffinity/preferredDuringSchedulingIgnoredDuringExecution/podAffinityTerm/labelSelector/matchLabels
|
||||
create: false
|
||||
group: apps
|
||||
@@ -107,36 +81,16 @@ commonLabels:
|
||||
group: apps
|
||||
kind: StatefulSet
|
||||
|
||||
- path: spec/volumeClaimTemplates[]/metadata/labels
|
||||
create: true
|
||||
group: apps
|
||||
kind: StatefulSet
|
||||
|
||||
- path: spec/selector/matchLabels
|
||||
create: false
|
||||
group: batch
|
||||
kind: Job
|
||||
|
||||
- path: spec/template/metadata/labels
|
||||
create: true
|
||||
group: batch
|
||||
kind: Job
|
||||
|
||||
- path: spec/jobTemplate/spec/selector/matchLabels
|
||||
create: false
|
||||
group: batch
|
||||
kind: CronJob
|
||||
|
||||
- path: spec/jobTemplate/metadata/labels
|
||||
create: true
|
||||
group: batch
|
||||
kind: CronJob
|
||||
|
||||
- path: spec/jobTemplate/spec/template/metadata/labels
|
||||
create: true
|
||||
group: batch
|
||||
kind: CronJob
|
||||
|
||||
- path: spec/selector/matchLabels
|
||||
create: false
|
||||
group: policy
|
||||
@@ -156,4 +110,4 @@ commonLabels:
|
||||
create: false
|
||||
group: networking.k8s.io
|
||||
kind: NetworkPolicy
|
||||
`
|
||||
` + metadataLabelsFieldSpecs
|
||||
|
||||
@@ -13,6 +13,7 @@ func GetDefaultFieldSpecs() []byte {
|
||||
[]byte(namePrefixFieldSpecs),
|
||||
[]byte(nameSuffixFieldSpecs),
|
||||
[]byte(commonLabelFieldSpecs),
|
||||
[]byte(templateLabelFieldSpecs),
|
||||
[]byte(commonAnnotationFieldSpecs),
|
||||
[]byte(namespaceFieldSpecs),
|
||||
[]byte(varReferenceFieldSpecs),
|
||||
@@ -30,6 +31,7 @@ func GetDefaultFieldSpecsAsMap() map[string]string {
|
||||
result["nameprefix"] = namePrefixFieldSpecs
|
||||
result["namesuffix"] = nameSuffixFieldSpecs
|
||||
result["commonlabels"] = commonLabelFieldSpecs
|
||||
result["templatelabels"] = templateLabelFieldSpecs
|
||||
result["commonannotations"] = commonAnnotationFieldSpecs
|
||||
result["namespace"] = namespaceFieldSpecs
|
||||
result["varreference"] = varReferenceFieldSpecs
|
||||
|
||||
51
api/konfig/builtinpluginconsts/metadatalabels.go
Normal file
51
api/konfig/builtinpluginconsts/metadatalabels.go
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package builtinpluginconsts
|
||||
|
||||
const metadataLabelsFieldSpecs = `
|
||||
- path: metadata/labels
|
||||
create: true
|
||||
|
||||
- path: spec/template/metadata/labels
|
||||
create: true
|
||||
version: v1
|
||||
kind: ReplicationController
|
||||
|
||||
- path: spec/template/metadata/labels
|
||||
create: true
|
||||
kind: Deployment
|
||||
|
||||
- path: spec/template/metadata/labels
|
||||
create: true
|
||||
kind: ReplicaSet
|
||||
|
||||
- path: spec/template/metadata/labels
|
||||
create: true
|
||||
kind: DaemonSet
|
||||
|
||||
- path: spec/template/metadata/labels
|
||||
create: true
|
||||
group: apps
|
||||
kind: StatefulSet
|
||||
|
||||
- path: spec/volumeClaimTemplates[]/metadata/labels
|
||||
create: true
|
||||
group: apps
|
||||
kind: StatefulSet
|
||||
|
||||
- path: spec/template/metadata/labels
|
||||
create: true
|
||||
group: batch
|
||||
kind: Job
|
||||
|
||||
- path: spec/jobTemplate/metadata/labels
|
||||
create: true
|
||||
group: batch
|
||||
kind: CronJob
|
||||
|
||||
- path: spec/jobTemplate/spec/template/metadata/labels
|
||||
create: true
|
||||
group: batch
|
||||
kind: CronJob
|
||||
`
|
||||
@@ -50,6 +50,16 @@ nameReference:
|
||||
kind: Pod
|
||||
- path: template/spec/volumes/configMap/name
|
||||
kind: PodTemplate
|
||||
- path: template/spec/containers/env/valueFrom/configMapKeyRef/name
|
||||
kind: PodTemplate
|
||||
- path: template/spec/initContainers/env/valueFrom/configMapKeyRef/name
|
||||
kind: PodTemplate
|
||||
- path: template/spec/containers/envFrom/configMapRef/name
|
||||
kind: PodTemplate
|
||||
- path: template/spec/initContainers/envFrom/configMapRef/name
|
||||
kind: PodTemplate
|
||||
- path: template/spec/volumes/projected/sources/configMap/name
|
||||
kind: PodTemplate
|
||||
- path: spec/template/spec/volumes/configMap/name
|
||||
kind: Deployment
|
||||
- path: spec/template/spec/containers/env/valueFrom/configMapKeyRef/name
|
||||
@@ -155,6 +165,20 @@ nameReference:
|
||||
- path: spec/volumes/projected/sources/secret/name
|
||||
version: v1
|
||||
kind: Pod
|
||||
- path: template/spec/volumes/secret/secretName
|
||||
kind: PodTemplate
|
||||
- path: template/spec/containers/env/valueFrom/secretKeyRef/name
|
||||
kind: PodTemplate
|
||||
- path: template/spec/initContainers/env/valueFrom/secretKeyRef/name
|
||||
kind: PodTemplate
|
||||
- path: template/spec/containers/envFrom/secretRef/name
|
||||
kind: PodTemplate
|
||||
- path: template/spec/initContainers/envFrom/secretRef/name
|
||||
kind: PodTemplate
|
||||
- path: template/spec/imagePullSecrets/name
|
||||
kind: PodTemplate
|
||||
- path: template/spec/volumes/projected/sources/secret/name
|
||||
kind: PodTemplate
|
||||
- path: spec/template/spec/volumes/secret/secretName
|
||||
kind: Deployment
|
||||
- path: spec/template/spec/containers/env/valueFrom/secretKeyRef/name
|
||||
|
||||
@@ -6,15 +6,9 @@ package builtinpluginconsts
|
||||
const (
|
||||
namespaceFieldSpecs = `
|
||||
namespace:
|
||||
- path: metadata/namespace
|
||||
create: true
|
||||
- path: metadata/name
|
||||
kind: Namespace
|
||||
create: true
|
||||
- path: subjects
|
||||
kind: RoleBinding
|
||||
- path: subjects
|
||||
kind: ClusterRoleBinding
|
||||
- path: spec/service/namespace
|
||||
group: apiregistration.k8s.io
|
||||
kind: APIService
|
||||
|
||||
8
api/konfig/builtinpluginconsts/templatelabels.go
Normal file
8
api/konfig/builtinpluginconsts/templatelabels.go
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package builtinpluginconsts
|
||||
|
||||
const templateLabelFieldSpecs = `
|
||||
templateLabels:
|
||||
` + metadataLabelsFieldSpecs
|
||||
@@ -179,9 +179,11 @@ func TestDefaultAbsPluginHomeNoXdgJustHomeDir(t *testing.T) {
|
||||
}
|
||||
|
||||
func setenv(t *testing.T, key, value string) {
|
||||
t.Helper()
|
||||
require.NoError(t, os.Setenv(key, value))
|
||||
}
|
||||
|
||||
func unsetenv(t *testing.T, key string) {
|
||||
t.Helper()
|
||||
require.NoError(t, os.Unsetenv(key))
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ spec:
|
||||
`)
|
||||
}
|
||||
|
||||
//test for https://github.com/kubernetes-sigs/kustomize/issues/3812#issuecomment-862339267
|
||||
// test for https://github.com/kubernetes-sigs/kustomize/issues/3812#issuecomment-862339267
|
||||
func TestBasicIO3812(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteK(".", `
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty_test
|
||||
|
||||
import (
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
"sigs.k8s.io/kustomize/api/loader"
|
||||
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||
)
|
||||
|
||||
@@ -551,7 +552,7 @@ components:
|
||||
`),
|
||||
},
|
||||
runPath: "filesincomponents",
|
||||
expectedError: "'/filesincomponents/stub.yaml' must be a directory so that it can used as a build root",
|
||||
expectedError: fmt.Sprintf("%s: '%s'", loader.ErrRtNotDir.Error(), "/filesincomponents/stub.yaml"),
|
||||
},
|
||||
"invalid-component-api-version": {
|
||||
input: []FileGen{writeTestBase, writeOverlayProd,
|
||||
|
||||
@@ -460,7 +460,6 @@ metadata:
|
||||
}
|
||||
|
||||
func TestConfigMapGeneratorMergeNamePrefix(t *testing.T) {
|
||||
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteK("base", `
|
||||
configMapGenerator:
|
||||
|
||||
@@ -34,7 +34,7 @@ const container = `{ "image": "my-image", "livenessProbe": { "httpGet" : {"path"
|
||||
const patchJsonAddProbe = `[{"op": "replace", "path": "/spec/template/spec/containers/0", "value": ` +
|
||||
container + `}]`
|
||||
|
||||
const patchDnsPolicy = `
|
||||
const patchDNSPolicy = `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
@@ -44,7 +44,7 @@ spec:
|
||||
spec:
|
||||
dnsPolicy: ClusterFirst
|
||||
`
|
||||
const patchJsonDnsPolicy = `[{"op": "add", "path": "/spec/template/spec/dnsPolicy", "value": "ClusterFirst"}]`
|
||||
const patchJsonDNSPolicy = `[{"op": "add", "path": "/spec/template/spec/dnsPolicy", "value": "ClusterFirst"}]`
|
||||
|
||||
const patchRestartPolicy = `
|
||||
apiVersion: apps/v1
|
||||
@@ -96,7 +96,7 @@ resources:
|
||||
patchesStrategicMerge:
|
||||
- dep-patch.yaml
|
||||
`)
|
||||
th.WriteF("dns/dep-patch.yaml", patchDnsPolicy)
|
||||
th.WriteF("dns/dep-patch.yaml", patchDNSPolicy)
|
||||
}
|
||||
|
||||
func writeRestartOverlay(th kusttest_test.Harness) {
|
||||
@@ -209,7 +209,7 @@ patchesStrategicMerge:
|
||||
- patchRestartPolicy.yaml
|
||||
`)
|
||||
th.WriteF("composite/patchRestartPolicy.yaml", patchRestartPolicy)
|
||||
th.WriteF("composite/patchDnsPolicy.yaml", patchDnsPolicy)
|
||||
th.WriteF("composite/patchDnsPolicy.yaml", patchDNSPolicy)
|
||||
th.WriteF("composite/patchAddProbe.yaml", patchAddProbe)
|
||||
|
||||
m := th.Run("composite", th.MakeDefaultOptions())
|
||||
@@ -220,7 +220,7 @@ func definePatchDirStructure(th kusttest_test.Harness) {
|
||||
writeDeploymentBase(th)
|
||||
|
||||
th.WriteF("patches/patchRestartPolicy.yaml", patchRestartPolicy)
|
||||
th.WriteF("patches/patchDnsPolicy.yaml", patchDnsPolicy)
|
||||
th.WriteF("patches/patchDnsPolicy.yaml", patchDNSPolicy)
|
||||
th.WriteF("patches/patchAddProbe.yaml", patchAddProbe)
|
||||
}
|
||||
|
||||
@@ -368,7 +368,7 @@ func TestIssue1251_Plugins_Local(t *testing.T) {
|
||||
writeDeploymentBase(th.Harness)
|
||||
|
||||
writeJsonTransformerPluginConfig(
|
||||
th, "composite", "addDnsPolicy", patchJsonDnsPolicy)
|
||||
th, "composite", "addDnsPolicy", patchJsonDNSPolicy)
|
||||
writeJsonTransformerPluginConfig(
|
||||
th, "composite", "addRestartPolicy", patchJsonRestartPolicy)
|
||||
writeJsonTransformerPluginConfig(
|
||||
@@ -417,7 +417,7 @@ resources:
|
||||
- addProbeConfig.yaml
|
||||
`)
|
||||
writeJsonTransformerPluginConfig(
|
||||
th, "patches", "addDnsPolicy", patchJsonDnsPolicy)
|
||||
th, "patches", "addDnsPolicy", patchJsonDNSPolicy)
|
||||
writeJsonTransformerPluginConfig(
|
||||
th, "patches", "addRestartPolicy", patchJsonRestartPolicy)
|
||||
writeJsonTransformerPluginConfig(
|
||||
@@ -441,7 +441,7 @@ resources:
|
||||
- addDnsPolicyConfig.yaml
|
||||
`)
|
||||
writeJsonTransformerPluginConfig(
|
||||
th, "patches/addDnsPolicy", "addDnsPolicy", patchJsonDnsPolicy)
|
||||
th, "patches/addDnsPolicy", "addDnsPolicy", patchJsonDNSPolicy)
|
||||
|
||||
th.WriteK("patches/addRestartPolicy", `
|
||||
resources:
|
||||
|
||||
@@ -82,21 +82,19 @@ metadata:
|
||||
secret := findSecret(m, "")
|
||||
if secret == nil {
|
||||
t.Errorf("Expected to find a Secret")
|
||||
}
|
||||
if secret.GetName() != "foo-secret-bar-82c2g5f8f6" {
|
||||
} else if secret.GetName() != "foo-secret-bar-82c2g5f8f6" {
|
||||
t.Errorf("unexpected secret resource name: %s", secret.GetName())
|
||||
}
|
||||
|
||||
th.WriteK("/whatever",
|
||||
strings.Replace(kustomizationContent,
|
||||
strings.ReplaceAll(kustomizationContent,
|
||||
"disableNameSuffixHash: false",
|
||||
"disableNameSuffixHash: true", -1))
|
||||
"disableNameSuffixHash: true"))
|
||||
m = th.Run("/whatever", th.MakeDefaultOptions())
|
||||
secret = findSecret(m, "")
|
||||
if secret == nil {
|
||||
t.Errorf("Expected to find a Secret")
|
||||
}
|
||||
if secret.GetName() != "foo-secret-bar" { // No hash at end.
|
||||
} else if secret.GetName() != "foo-secret-bar" { // No hash at end.
|
||||
t.Errorf("unexpected secret resource name: %s", secret.GetName())
|
||||
}
|
||||
}
|
||||
@@ -131,16 +129,14 @@ secretGenerator:
|
||||
secret := findSecret(m, "nohash")
|
||||
if secret == nil {
|
||||
t.Errorf("Expected to find a Secret")
|
||||
}
|
||||
if secret.GetName() != "nohash" {
|
||||
} else 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-82c2g5f8f6" {
|
||||
} else if secret.GetName() != "yeshash-82c2g5f8f6" {
|
||||
t.Errorf("unexpected secret resource name: %s", secret.GetName())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty_test
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty_test
|
||||
|
||||
import (
|
||||
@@ -7,6 +10,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
. "sigs.k8s.io/kustomize/api/krusty"
|
||||
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||
)
|
||||
@@ -37,7 +41,19 @@ spec:
|
||||
EOF
|
||||
`
|
||||
|
||||
func TestFnExecGenerator(t *testing.T) {
|
||||
const krmTransformerDotSh = `#!/bin/bash
|
||||
cat << EOF
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: dummyTransformed
|
||||
stringData:
|
||||
foo: bar
|
||||
type: Opaque
|
||||
EOF
|
||||
`
|
||||
|
||||
func TestFnExecGeneratorInBase(t *testing.T) {
|
||||
fSys := filesys.MakeFsOnDisk()
|
||||
|
||||
th := kusttest_test.MakeHarnessWithFs(t, fSys)
|
||||
@@ -83,7 +99,6 @@ spec:
|
||||
`)
|
||||
|
||||
m := th.Run(tmpDir.String(), o)
|
||||
assert.NoError(t, err)
|
||||
yml, err := m.AsYaml()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, `apiVersion: v1
|
||||
@@ -122,7 +137,7 @@ spec:
|
||||
assert.NoError(t, fSys.RemoveAll(tmpDir.String()))
|
||||
}
|
||||
|
||||
func TestFnExecGeneratorWithOverlay(t *testing.T) {
|
||||
func TestFnExecGeneratorInBaseWithOverlay(t *testing.T) {
|
||||
fSys := filesys.MakeFsOnDisk()
|
||||
|
||||
th := kusttest_test.MakeHarnessWithFs(t, fSys)
|
||||
@@ -213,7 +228,276 @@ spec:
|
||||
assert.NoError(t, fSys.RemoveAll(tmpDir.String()))
|
||||
}
|
||||
|
||||
func TestFnExecGeneratorInOverlay(t *testing.T) {
|
||||
fSys := filesys.MakeFsOnDisk()
|
||||
|
||||
th := kusttest_test.MakeHarnessWithFs(t, fSys)
|
||||
o := th.MakeOptionsPluginsEnabled()
|
||||
o.PluginConfig.FnpLoadingOptions.EnableExec = true
|
||||
|
||||
tmpDir, err := filesys.NewTmpConfirmedDir()
|
||||
assert.NoError(t, err)
|
||||
base := filepath.Join(tmpDir.String(), "base")
|
||||
prod := filepath.Join(tmpDir.String(), "prod")
|
||||
assert.NoError(t, fSys.Mkdir(base))
|
||||
assert.NoError(t, fSys.Mkdir(prod))
|
||||
th.WriteK(base, `
|
||||
resources:
|
||||
- short_secret.yaml
|
||||
`)
|
||||
th.WriteK(prod, `
|
||||
resources:
|
||||
- ../base
|
||||
generators:
|
||||
- gener.yaml
|
||||
`)
|
||||
th.WriteF(filepath.Join(base, "short_secret.yaml"),
|
||||
`
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
labels:
|
||||
airshipit.org/ephemeral-user-data: "true"
|
||||
name: node1-bmc-secret
|
||||
type: Opaque
|
||||
stringData:
|
||||
userData: |
|
||||
bootcmd:
|
||||
- mkdir /mnt/vda
|
||||
`)
|
||||
th.WriteF(filepath.Join(prod, "generateDeployment.sh"), generateDeploymentDotSh)
|
||||
|
||||
assert.NoError(t, os.Chmod(filepath.Join(prod, "generateDeployment.sh"), 0777))
|
||||
th.WriteF(filepath.Join(prod, "gener.yaml"), `
|
||||
kind: executable
|
||||
metadata:
|
||||
name: demo
|
||||
annotations:
|
||||
config.kubernetes.io/function: |
|
||||
exec:
|
||||
path: ./generateDeployment.sh
|
||||
spec:
|
||||
`)
|
||||
|
||||
m := th.Run(prod, o)
|
||||
assert.NoError(t, err)
|
||||
yml, err := m.AsYaml()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, `apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
labels:
|
||||
airshipit.org/ephemeral-user-data: "true"
|
||||
name: node1-bmc-secret
|
||||
stringData:
|
||||
userData: |
|
||||
bootcmd:
|
||||
- mkdir /mnt/vda
|
||||
type: Opaque
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
annotations:
|
||||
tshirt-size: small
|
||||
labels:
|
||||
app: nginx
|
||||
name: nginx
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx
|
||||
name: nginx
|
||||
`, string(yml))
|
||||
assert.NoError(t, fSys.RemoveAll(tmpDir.String()))
|
||||
}
|
||||
|
||||
func TestFnExecTransformerInBase(t *testing.T) {
|
||||
fSys := filesys.MakeFsOnDisk()
|
||||
|
||||
th := kusttest_test.MakeHarnessWithFs(t, fSys)
|
||||
o := th.MakeOptionsPluginsEnabled()
|
||||
o.PluginConfig.FnpLoadingOptions.EnableExec = true
|
||||
|
||||
tmpDir, err := filesys.NewTmpConfirmedDir()
|
||||
assert.NoError(t, err)
|
||||
base := filepath.Join(tmpDir.String(), "base")
|
||||
assert.NoError(t, fSys.Mkdir(base))
|
||||
th.WriteK(base, `
|
||||
resources:
|
||||
- secret.yaml
|
||||
transformers:
|
||||
- krm-transformer.yaml
|
||||
`)
|
||||
th.WriteF(filepath.Join(base, "secret.yaml"),
|
||||
`
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: dummy
|
||||
type: Opaque
|
||||
stringData:
|
||||
foo: bar
|
||||
`)
|
||||
th.WriteF(filepath.Join(base, "krmTransformer.sh"), krmTransformerDotSh)
|
||||
|
||||
assert.NoError(t, os.Chmod(filepath.Join(base, "krmTransformer.sh"), 0777))
|
||||
th.WriteF(filepath.Join(base, "krm-transformer.yaml"), `
|
||||
apiVersion: examples.config.kubernetes.io/v1beta1
|
||||
kind: MyPlugin
|
||||
metadata:
|
||||
name: notImportantHere
|
||||
annotations:
|
||||
config.kubernetes.io/function: |
|
||||
exec:
|
||||
path: ./krmTransformer.sh
|
||||
`)
|
||||
|
||||
m := th.Run(base, o)
|
||||
yml, err := m.AsYaml()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, `apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: dummyTransformed
|
||||
stringData:
|
||||
foo: bar
|
||||
type: Opaque
|
||||
`, string(yml))
|
||||
assert.NoError(t, fSys.RemoveAll(tmpDir.String()))
|
||||
}
|
||||
|
||||
func TestFnExecTransformerInBaseWithOverlay(t *testing.T) {
|
||||
fSys := filesys.MakeFsOnDisk()
|
||||
|
||||
th := kusttest_test.MakeHarnessWithFs(t, fSys)
|
||||
o := th.MakeOptionsPluginsEnabled()
|
||||
o.PluginConfig.FnpLoadingOptions.EnableExec = true
|
||||
|
||||
tmpDir, err := filesys.NewTmpConfirmedDir()
|
||||
assert.NoError(t, err)
|
||||
base := filepath.Join(tmpDir.String(), "base")
|
||||
prod := filepath.Join(tmpDir.String(), "prod")
|
||||
assert.NoError(t, fSys.Mkdir(base))
|
||||
assert.NoError(t, fSys.Mkdir(prod))
|
||||
th.WriteK(base, `
|
||||
resources:
|
||||
- secret.yaml
|
||||
transformers:
|
||||
- krm-transformer.yaml
|
||||
`)
|
||||
th.WriteK(prod, `
|
||||
resources:
|
||||
- ../base
|
||||
`)
|
||||
th.WriteF(filepath.Join(base, "secret.yaml"),
|
||||
`
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: dummy
|
||||
type: Opaque
|
||||
stringData:
|
||||
foo: bar
|
||||
`)
|
||||
th.WriteF(filepath.Join(base, "krmTransformer.sh"), krmTransformerDotSh)
|
||||
|
||||
assert.NoError(t, os.Chmod(filepath.Join(base, "krmTransformer.sh"), 0777))
|
||||
th.WriteF(filepath.Join(base, "krm-transformer.yaml"), `
|
||||
apiVersion: examples.config.kubernetes.io/v1beta1
|
||||
kind: MyPlugin
|
||||
metadata:
|
||||
name: notImportantHere
|
||||
annotations:
|
||||
config.kubernetes.io/function: |
|
||||
exec:
|
||||
path: ./krmTransformer.sh
|
||||
`)
|
||||
|
||||
m := th.Run(prod, o)
|
||||
yml, err := m.AsYaml()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, `apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: dummyTransformed
|
||||
stringData:
|
||||
foo: bar
|
||||
type: Opaque
|
||||
`, string(yml))
|
||||
assert.NoError(t, fSys.RemoveAll(tmpDir.String()))
|
||||
}
|
||||
|
||||
func TestFnExecTransformerInOverlay(t *testing.T) {
|
||||
fSys := filesys.MakeFsOnDisk()
|
||||
|
||||
th := kusttest_test.MakeHarnessWithFs(t, fSys)
|
||||
o := th.MakeOptionsPluginsEnabled()
|
||||
o.PluginConfig.FnpLoadingOptions.EnableExec = true
|
||||
|
||||
tmpDir, err := filesys.NewTmpConfirmedDir()
|
||||
assert.NoError(t, err)
|
||||
base := filepath.Join(tmpDir.String(), "base")
|
||||
prod := filepath.Join(tmpDir.String(), "prod")
|
||||
assert.NoError(t, fSys.Mkdir(base))
|
||||
assert.NoError(t, fSys.Mkdir(prod))
|
||||
th.WriteK(base, `
|
||||
resources:
|
||||
- secret.yaml
|
||||
`)
|
||||
th.WriteK(prod, `
|
||||
resources:
|
||||
- ../base
|
||||
transformers:
|
||||
- krm-transformer.yaml
|
||||
`)
|
||||
th.WriteF(filepath.Join(base, "secret.yaml"),
|
||||
`
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: dummy
|
||||
type: Opaque
|
||||
stringData:
|
||||
foo: bar
|
||||
`)
|
||||
th.WriteF(filepath.Join(prod, "krmTransformer.sh"), krmTransformerDotSh)
|
||||
|
||||
assert.NoError(t, os.Chmod(filepath.Join(prod, "krmTransformer.sh"), 0777))
|
||||
th.WriteF(filepath.Join(prod, "krm-transformer.yaml"), `
|
||||
apiVersion: examples.config.kubernetes.io/v1beta1
|
||||
kind: MyPlugin
|
||||
metadata:
|
||||
name: notImportantHere
|
||||
annotations:
|
||||
config.kubernetes.io/function: |
|
||||
exec:
|
||||
path: ./krmTransformer.sh
|
||||
`)
|
||||
|
||||
m := th.Run(prod, o)
|
||||
yml, err := m.AsYaml()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, `apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: dummyTransformed
|
||||
stringData:
|
||||
foo: bar
|
||||
type: Opaque
|
||||
`, string(yml))
|
||||
assert.NoError(t, fSys.RemoveAll(tmpDir.String()))
|
||||
}
|
||||
|
||||
func skipIfNoDocker(t *testing.T) {
|
||||
t.Helper()
|
||||
if _, err := exec.LookPath("docker"); err != nil {
|
||||
t.Skip("skipping because docker binary wasn't found in PATH")
|
||||
}
|
||||
@@ -531,30 +815,33 @@ spec:
|
||||
|
||||
func TestFnContainerTransformerWithConfig(t *testing.T) {
|
||||
skipIfNoDocker(t)
|
||||
|
||||
// Function plugins should not need the env setup done by MakeEnhancedHarness
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
|
||||
th.WriteK(".", `
|
||||
o := th.MakeOptionsPluginsEnabled()
|
||||
fSys := filesys.MakeFsOnDisk()
|
||||
b := MakeKustomizer(&o)
|
||||
tmpDir, err := filesys.NewTmpConfirmedDir()
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "kustomization.yaml"), []byte(`
|
||||
resources:
|
||||
- data1.yaml
|
||||
- data2.yaml
|
||||
transformers:
|
||||
- label_namespace.yaml
|
||||
`)
|
||||
|
||||
th.WriteF("data1.yaml", `apiVersion: v1
|
||||
`)))
|
||||
assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "data1.yaml"), []byte(`
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: my-namespace
|
||||
`)
|
||||
th.WriteF("data2.yaml", `apiVersion: v1
|
||||
`)))
|
||||
assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "data2.yaml"), []byte(`
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: another-namespace
|
||||
`)
|
||||
|
||||
th.WriteF("label_namespace.yaml", `apiVersion: v1
|
||||
`)))
|
||||
assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "label_namespace.yaml"), []byte(`
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: label_namespace
|
||||
@@ -565,11 +852,14 @@ metadata:
|
||||
data:
|
||||
label_name: my-ns-name
|
||||
label_value: function-test
|
||||
`)
|
||||
|
||||
m := th.Run(".", th.MakeOptionsPluginsEnabled())
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: v1
|
||||
`)))
|
||||
m, err := b.Run(
|
||||
fSys,
|
||||
tmpDir.String())
|
||||
assert.NoError(t, err)
|
||||
actual, err := m.AsYaml()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, `apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
labels:
|
||||
@@ -582,24 +872,22 @@ metadata:
|
||||
labels:
|
||||
my-ns-name: function-test
|
||||
name: another-namespace
|
||||
`)
|
||||
`, string(actual))
|
||||
}
|
||||
|
||||
func TestFnContainerEnvVars(t *testing.T) {
|
||||
skipIfNoDocker(t)
|
||||
|
||||
// Function plugins should not need the env setup done by MakeEnhancedHarness
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
|
||||
th.WriteK(".", `
|
||||
o := th.MakeOptionsPluginsEnabled()
|
||||
fSys := filesys.MakeFsOnDisk()
|
||||
b := MakeKustomizer(&o)
|
||||
tmpDir, err := filesys.NewTmpConfirmedDir()
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "kustomization.yaml"), []byte(`
|
||||
generators:
|
||||
- gener.yaml
|
||||
`)
|
||||
|
||||
// TODO: cheange image to gcr.io/kpt-functions/templater:stable
|
||||
// when https://github.com/GoogleContainerTools/kpt-functions-catalog/pull/103
|
||||
// is merged
|
||||
th.WriteF("gener.yaml", `
|
||||
`)))
|
||||
assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "gener.yaml"), []byte(`
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
@@ -618,14 +906,176 @@ data:
|
||||
name: env
|
||||
data:
|
||||
value: '{{ env "TESTTEMPLATE" }}'
|
||||
`)
|
||||
m := th.Run(".", th.MakeOptionsPluginsEnabled())
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: v1
|
||||
`)))
|
||||
m, err := b.Run(
|
||||
fSys,
|
||||
tmpDir.String())
|
||||
assert.NoError(t, err)
|
||||
actual, err := m.AsYaml()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, `apiVersion: v1
|
||||
data:
|
||||
value: value
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: env
|
||||
`)
|
||||
`, string(actual))
|
||||
}
|
||||
|
||||
func TestFnContainerFnMounts(t *testing.T) {
|
||||
skipIfNoDocker(t)
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
o := th.MakeOptionsPluginsEnabled()
|
||||
fSys := filesys.MakeFsOnDisk()
|
||||
b := MakeKustomizer(&o)
|
||||
tmpDir, err := filesys.NewTmpConfirmedDir()
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "kustomization.yaml"), []byte(`
|
||||
generators:
|
||||
- gener.yaml
|
||||
`)))
|
||||
assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "gener.yaml"), []byte(`
|
||||
apiVersion: v1alpha1
|
||||
kind: RenderHelmChart
|
||||
metadata:
|
||||
name: demo
|
||||
annotations:
|
||||
config.kubernetes.io/function: |
|
||||
container:
|
||||
image: gcr.io/kpt-fn/render-helm-chart:v0.1.0
|
||||
mounts:
|
||||
- type: "bind"
|
||||
src: "./charts"
|
||||
dst: "/tmp/charts"
|
||||
helmCharts:
|
||||
- name: helloworld-chart
|
||||
releaseName: test
|
||||
valuesFile: /tmp/charts/helloworld-values/values.yaml
|
||||
`)))
|
||||
assert.NoError(t, fSys.MkdirAll(filepath.Join(tmpDir.String(), "charts", "helloworld-chart", "templates")))
|
||||
assert.NoError(t, fSys.MkdirAll(filepath.Join(tmpDir.String(), "charts", "helloworld-values")))
|
||||
assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "charts", "helloworld-chart", "Chart.yaml"), []byte(`
|
||||
apiVersion: v2
|
||||
name: helloworld-chart
|
||||
description: A Helm chart for Kubernetes
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: 1.16.0
|
||||
`)))
|
||||
assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "charts", "helloworld-chart", "templates", "deployment.yaml"), []byte(`
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: name
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
`)))
|
||||
assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "charts", "helloworld-values", "values.yaml"), []byte(`
|
||||
replicaCount: 5
|
||||
`)))
|
||||
m, err := b.Run(
|
||||
fSys,
|
||||
tmpDir.String())
|
||||
assert.NoError(t, err)
|
||||
actual, err := m.AsYaml()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, `apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: name
|
||||
spec:
|
||||
replicas: 5
|
||||
`, string(actual))
|
||||
}
|
||||
|
||||
func TestFnContainerMountsLoadRestrictions_absolute(t *testing.T) {
|
||||
skipIfNoDocker(t)
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
o := th.MakeOptionsPluginsEnabled()
|
||||
fSys := filesys.MakeFsOnDisk()
|
||||
b := MakeKustomizer(&o)
|
||||
tmpDir, err := filesys.NewTmpConfirmedDir()
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "kustomization.yaml"), []byte(`
|
||||
generators:
|
||||
- |-
|
||||
apiVersion: v1alpha1
|
||||
kind: RenderHelmChart
|
||||
metadata:
|
||||
name: demo
|
||||
annotations:
|
||||
config.kubernetes.io/function: |
|
||||
container:
|
||||
image: gcr.io/kpt-fn/render-helm-chart:v0.1.0
|
||||
mounts:
|
||||
- type: "bind"
|
||||
src: "/tmp/dir"
|
||||
dst: "/tmp/charts"
|
||||
`)))
|
||||
_, err = b.Run(
|
||||
fSys,
|
||||
tmpDir.String())
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "loading generator plugins: failed to load generator: plugin RenderHelmChart."+
|
||||
"v1alpha1.[noGrp]/demo.[noNs] with mount path '/tmp/dir' is not permitted; mount paths must"+
|
||||
" be relative to the current kustomization directory")
|
||||
}
|
||||
|
||||
func TestFnContainerMountsLoadRestrictions_outsideCurrentDir(t *testing.T) {
|
||||
skipIfNoDocker(t)
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
o := th.MakeOptionsPluginsEnabled()
|
||||
fSys := filesys.MakeFsOnDisk()
|
||||
b := MakeKustomizer(&o)
|
||||
tmpDir, err := filesys.NewTmpConfirmedDir()
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "kustomization.yaml"), []byte(`
|
||||
generators:
|
||||
- |-
|
||||
apiVersion: v1alpha1
|
||||
kind: RenderHelmChart
|
||||
metadata:
|
||||
name: demo
|
||||
annotations:
|
||||
config.kubernetes.io/function: |
|
||||
container:
|
||||
image: gcr.io/kpt-fn/render-helm-chart:v0.1.0
|
||||
mounts:
|
||||
- type: "bind"
|
||||
src: "./tmp/../../dir"
|
||||
dst: "/tmp/charts"
|
||||
`)))
|
||||
_, err = b.Run(
|
||||
fSys,
|
||||
tmpDir.String())
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "loading generator plugins: failed to load generator: plugin RenderHelmChart."+
|
||||
"v1alpha1.[noGrp]/demo.[noNs] with mount path './tmp/../../dir' is not permitted; mount paths must "+
|
||||
"be under the current kustomization directory")
|
||||
}
|
||||
|
||||
func TestFnContainerMountsLoadRestrictions_root(t *testing.T) {
|
||||
skipIfNoDocker(t)
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
|
||||
th.WriteK(".", `
|
||||
generators:
|
||||
- gener.yaml
|
||||
`)
|
||||
// Create generator config
|
||||
th.WriteF("gener.yaml", `
|
||||
apiVersion: examples.config.kubernetes.io/v1beta1
|
||||
kind: CockroachDB
|
||||
metadata:
|
||||
name: demo
|
||||
annotations:
|
||||
config.kubernetes.io/function: |
|
||||
container:
|
||||
image: gcr.io/kustomize-functions/example-cockroachdb:v0.1.0
|
||||
spec:
|
||||
replicas: 3
|
||||
`)
|
||||
err := th.RunWithErr(".", th.MakeOptionsPluginsEnabled())
|
||||
assert.Error(t, err)
|
||||
assert.EqualError(t, err, "couldn't execute function: root working directory '/' not allowed")
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty_test
|
||||
|
||||
import (
|
||||
|
||||
@@ -91,3 +91,437 @@ spec:
|
||||
c: d
|
||||
`)
|
||||
}
|
||||
|
||||
func TestKustomizationLabelsInDeploymentTemplate(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteF("app/deployment.yaml", `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/component: a
|
||||
app.kubernetes.io/instance: b
|
||||
app.kubernetes.io/name: c
|
||||
app.kubernetes.io/part-of: d
|
||||
name: deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/component: a
|
||||
app.kubernetes.io/instance: b
|
||||
app.kubernetes.io/name: c
|
||||
app.kubernetes.io/part-of: d
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/component: a
|
||||
app.kubernetes.io/instance: b
|
||||
app.kubernetes.io/name: c
|
||||
app.kubernetes.io/part-of: d
|
||||
`)
|
||||
th.WriteK("/app", `
|
||||
resources:
|
||||
- deployment.yaml
|
||||
|
||||
labels:
|
||||
- pairs:
|
||||
foo: bar
|
||||
includeSelectors: false
|
||||
includeTemplates: true
|
||||
`)
|
||||
m := th.Run("/app", th.MakeDefaultOptions())
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/component: a
|
||||
app.kubernetes.io/instance: b
|
||||
app.kubernetes.io/name: c
|
||||
app.kubernetes.io/part-of: d
|
||||
foo: bar
|
||||
name: deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/component: a
|
||||
app.kubernetes.io/instance: b
|
||||
app.kubernetes.io/name: c
|
||||
app.kubernetes.io/part-of: d
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/component: a
|
||||
app.kubernetes.io/instance: b
|
||||
app.kubernetes.io/name: c
|
||||
app.kubernetes.io/part-of: d
|
||||
foo: bar
|
||||
`)
|
||||
}
|
||||
|
||||
func TestKustomizationLabelsInTemplateWhenLabelsIsNil(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteF("app/deployment.yaml", `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: test-server
|
||||
image: test-server
|
||||
`)
|
||||
th.WriteK("/app", `
|
||||
resources:
|
||||
- deployment.yaml
|
||||
|
||||
commonLabels:
|
||||
app: test-server
|
||||
|
||||
labels:
|
||||
- pairs:
|
||||
app.kubernetes.io/component: a
|
||||
app.kubernetes.io/instance: b
|
||||
app.kubernetes.io/name: c
|
||||
app.kubernetes.io/part-of: d
|
||||
includeSelectors: false
|
||||
includeTemplates: true
|
||||
`)
|
||||
m := th.Run("/app", th.MakeDefaultOptions())
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: test-server
|
||||
app.kubernetes.io/component: a
|
||||
app.kubernetes.io/instance: b
|
||||
app.kubernetes.io/name: c
|
||||
app.kubernetes.io/part-of: d
|
||||
name: deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: test-server
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: test-server
|
||||
app.kubernetes.io/component: a
|
||||
app.kubernetes.io/instance: b
|
||||
app.kubernetes.io/name: c
|
||||
app.kubernetes.io/part-of: d
|
||||
spec:
|
||||
containers:
|
||||
- image: test-server
|
||||
name: test-server
|
||||
`)
|
||||
}
|
||||
|
||||
func TestKustomizationLabelsDoesNotCreateInvalidTemplatePaths(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteF("app/deployment.yaml", `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: test-server
|
||||
image: test-server
|
||||
`)
|
||||
th.WriteF("app/service.yaml", `
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: service
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
protocol: TCP
|
||||
targetPort: 9376
|
||||
`)
|
||||
th.WriteK("/app", `
|
||||
resources:
|
||||
- deployment.yaml
|
||||
- service.yaml
|
||||
|
||||
commonLabels:
|
||||
app: test-server
|
||||
|
||||
labels:
|
||||
- pairs:
|
||||
app.kubernetes.io/component: a
|
||||
app.kubernetes.io/instance: b
|
||||
app.kubernetes.io/name: c
|
||||
app.kubernetes.io/part-of: d
|
||||
includeSelectors: false
|
||||
includeTemplates: true
|
||||
`)
|
||||
m := th.Run("/app", th.MakeDefaultOptions())
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: test-server
|
||||
app.kubernetes.io/component: a
|
||||
app.kubernetes.io/instance: b
|
||||
app.kubernetes.io/name: c
|
||||
app.kubernetes.io/part-of: d
|
||||
name: deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: test-server
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: test-server
|
||||
app.kubernetes.io/component: a
|
||||
app.kubernetes.io/instance: b
|
||||
app.kubernetes.io/name: c
|
||||
app.kubernetes.io/part-of: d
|
||||
spec:
|
||||
containers:
|
||||
- image: test-server
|
||||
name: test-server
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: test-server
|
||||
app.kubernetes.io/component: a
|
||||
app.kubernetes.io/instance: b
|
||||
app.kubernetes.io/name: c
|
||||
app.kubernetes.io/part-of: d
|
||||
name: service
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
protocol: TCP
|
||||
targetPort: 9376
|
||||
selector:
|
||||
app: test-server
|
||||
`)
|
||||
}
|
||||
|
||||
func TestKustomizationLabelsInDaemonSetTemplate(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteF("app/ds.yaml", `
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: daemon
|
||||
name: daemon
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: daemon
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: daemon
|
||||
`)
|
||||
th.WriteK("/app", `
|
||||
resources:
|
||||
- ds.yaml
|
||||
|
||||
labels:
|
||||
- pairs:
|
||||
foo: bar
|
||||
includeSelectors: false
|
||||
includeTemplates: true
|
||||
`)
|
||||
m := th.Run("/app", th.MakeDefaultOptions())
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: daemon
|
||||
foo: bar
|
||||
name: daemon
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: daemon
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: daemon
|
||||
foo: bar
|
||||
`)
|
||||
}
|
||||
|
||||
func TestKustomizationLabelsInStatefulSetTemplate(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteF("app/sts.yaml", `
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: set
|
||||
name: set
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: set
|
||||
serviceName: set
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: set
|
||||
`)
|
||||
th.WriteK("/app", `
|
||||
resources:
|
||||
- sts.yaml
|
||||
|
||||
labels:
|
||||
- pairs:
|
||||
foo: bar
|
||||
includeSelectors: false
|
||||
includeTemplates: true
|
||||
`)
|
||||
m := th.Run("/app", th.MakeDefaultOptions())
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: set
|
||||
foo: bar
|
||||
name: set
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: set
|
||||
serviceName: set
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: set
|
||||
foo: bar
|
||||
`)
|
||||
}
|
||||
|
||||
func TestKustomizationLabelsInCronJobTemplate(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteF("app/cjob.yaml", `
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: job
|
||||
name: job
|
||||
spec:
|
||||
jobTemplate:
|
||||
spec:
|
||||
backoffLimit: 4
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: job
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
schedule: '* * * * *'
|
||||
`)
|
||||
th.WriteK("/app", `
|
||||
resources:
|
||||
- cjob.yaml
|
||||
|
||||
labels:
|
||||
- pairs:
|
||||
foo: bar
|
||||
includeSelectors: false
|
||||
includeTemplates: true
|
||||
`)
|
||||
m := th.Run("/app", th.MakeDefaultOptions())
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: job
|
||||
foo: bar
|
||||
name: job
|
||||
spec:
|
||||
jobTemplate:
|
||||
metadata:
|
||||
labels:
|
||||
foo: bar
|
||||
spec:
|
||||
backoffLimit: 4
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: job
|
||||
foo: bar
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
schedule: '* * * * *'
|
||||
`)
|
||||
}
|
||||
|
||||
func TestKustomizationLabelsInJobTemplate(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteF("app/job.yaml", `
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: job
|
||||
name: job
|
||||
spec:
|
||||
backoffLimit: 4
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: job
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
`)
|
||||
th.WriteK("/app", `
|
||||
resources:
|
||||
- job.yaml
|
||||
|
||||
labels:
|
||||
- pairs:
|
||||
foo: bar
|
||||
includeSelectors: false
|
||||
includeTemplates: true
|
||||
`)
|
||||
m := th.Run("/app", th.MakeDefaultOptions())
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: job
|
||||
foo: bar
|
||||
name: job
|
||||
spec:
|
||||
backoffLimit: 4
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: job
|
||||
foo: bar
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
`)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty_test
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty_test
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty_test
|
||||
|
||||
import (
|
||||
|
||||
@@ -5,7 +5,6 @@ package krusty
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/internal/builtins"
|
||||
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
||||
@@ -17,6 +16,7 @@ import (
|
||||
"sigs.k8s.io/kustomize/api/provider"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||
"sigs.k8s.io/kustomize/kyaml/openapi"
|
||||
)
|
||||
@@ -76,7 +76,7 @@ func (b *Kustomizer) Run(
|
||||
}
|
||||
var bytes []byte
|
||||
if openApiPath, exists := kt.Kustomization().OpenAPI["path"]; exists {
|
||||
bytes, err = ldr.Load(filepath.Join(ldr.Root(), openApiPath))
|
||||
bytes, err = ldr.Load(openApiPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -113,10 +113,16 @@ func (b *Kustomizer) Run(
|
||||
}
|
||||
m.RemoveBuildAnnotations()
|
||||
if !utils.StringSliceContains(kt.Kustomization().BuildMetadata, types.OriginAnnotations) {
|
||||
m.RemoveOriginAnnotations()
|
||||
err = m.RemoveOriginAnnotations()
|
||||
if err != nil {
|
||||
return nil, errors.WrapPrefixf(err, "failed to clean up origin tracking annotations")
|
||||
}
|
||||
}
|
||||
if !utils.StringSliceContains(kt.Kustomization().BuildMetadata, types.TransformerAnnotations) {
|
||||
m.RemoveTransformerAnnotations()
|
||||
err = m.RemoveTransformerAnnotations()
|
||||
if err != nil {
|
||||
return nil, errors.WrapPrefixf(err, "failed to clean up transformer annotations")
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty_test
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty_test
|
||||
|
||||
import (
|
||||
|
||||
74
api/krusty/namedspacedserviceaccounts_test.go
Normal file
74
api/krusty/namedspacedserviceaccounts_test.go
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright 2022 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||
)
|
||||
|
||||
func TestNamedspacedServiceAccountsWithOverlap(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
|
||||
th.WriteF("a/a.yaml", `
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: sa
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: crb-a
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: cr-a
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: sa
|
||||
`)
|
||||
|
||||
th.WriteK("a/", `
|
||||
namespace: a
|
||||
resources:
|
||||
- a.yaml
|
||||
`)
|
||||
|
||||
th.WriteF("b/b.yaml", `
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: sa
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: crb-b
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: cr-b
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: sa
|
||||
`)
|
||||
|
||||
th.WriteK("b/", `
|
||||
namespace: b
|
||||
resources:
|
||||
- b.yaml
|
||||
`)
|
||||
|
||||
th.WriteK(".", `
|
||||
resources:
|
||||
- a
|
||||
- b
|
||||
`)
|
||||
|
||||
err := th.RunWithErr(".", th.MakeDefaultOptions())
|
||||
assert.Contains(t, err.Error(), "found multiple possible referrals: ServiceAccount.v1.[noGrp]/sa.a, ServiceAccount.v1.[noGrp]/sa.b")
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user