Compare commits

...

58 Commits

Author SHA1 Message Date
Jingfang Liu
6f82073d4b Merge pull request #133 from Liujingfang1/loader
Add glob support
2018-06-27 15:20:01 -07:00
Jingfang Liu
2a3f09a2f0 Add integration test for glob support 2018-06-27 14:48:50 -07:00
Jingfang Liu
6392e6629f Add glob support 2018-06-27 10:54:12 -07:00
Jingfang Liu
c25ed7f7bc Merge pull request #137 from babiel/add-cronjob-to-refvars
Add CronJob to refvars transformer
2018-06-26 10:02:38 -07:00
Jingfang Liu
918247d2cc Merge pull request #138 from guineveresaenger/secret-docs
Adds example for secret download using curl
2018-06-26 10:02:01 -07:00
Maximilian Gaß
2a06a174e8 Add CronJob to refvars transformer 2018-06-26 12:20:52 +02:00
guineveresaenger
54e8a014bc Adds example for secret download using curl
It is possible to download secrets from web locations, as the command subfield can execute any terminal command specified.
This is a useful feature that should be highlighted.
2018-06-25 16:39:29 -07:00
Jingfang Liu
5b67b580f2 Merge pull request #129 from fanzhangio/issue114
Enhancement for format error message
2018-06-25 10:33:36 -07:00
fanzhangio
6a67183ed7 Enhancement for format error message
- add yaml format error handler
- silent usage when build command fails
2018-06-25 07:35:43 -07:00
Jingfang Liu
a38befdaa1 Merge pull request #132 from Liujingfang1/order
correct ordering of the k8s objects
2018-06-22 10:33:31 -07:00
Jingfang Liu
0312cdf677 Merge pull request #130 from sethpollack/image-pull-secret
add imagePullSecrets namerefs
2018-06-22 10:22:33 -07:00
Jingfang Liu
991ffbbdfc populate the map from a slice 2018-06-22 10:19:41 -07:00
Seth Pollack
bbd29d9dc1 add test 2018-06-21 23:17:03 -04:00
Jingfang Liu
28953e03a0 Merge pull request #120 from guineveresaenger/edit-add-base
New command: kustomize edit add base
2018-06-21 16:54:15 -07:00
guineveresaenger
37489ec2e9 Adds ability to add multiple base directories to kustomization 2018-06-21 16:39:46 -07:00
Jingfang Liu
636ab874eb update failed test 2018-06-21 16:36:27 -07:00
Jingfang Liu
90d16c2377 correct ordering of the k8s objects:
NameSpace, CRD, ServiceAccount, Role, ClusterRole, RoleBinding,
ClusterRoleBinding
2018-06-21 16:21:31 -07:00
Seth Pollack
5d24dda28a add imagePullSecrets namerefs 2018-06-20 23:23:31 -04:00
Jingfang Liu
dec5109e31 Merge pull request #127 from Liujingfang1/master
remove extra package comment on crds
2018-06-20 13:23:41 -07:00
Jingfang Liu
cc8690381c remove extra package comment on crds 2018-06-20 13:22:17 -07:00
Jingfang Liu
f5f95e3692 Merge pull request #125 from Liujingfang1/order
put namespace objects first in the output
2018-06-19 16:10:48 -07:00
Jingfang Liu
809d5b1fe2 put namespace objects first in the output 2018-06-19 15:44:33 -07:00
Jingfang Liu
38b4365ab3 Merge pull request #121 from traherom/master
Jobs do not create a selector if not already present
2018-06-19 14:22:15 -07:00
Jingfang Liu
d865300fdb Merge pull request #105 from Liujingfang1/crdsupport
Add support for CRDs
2018-06-19 12:04:35 -07:00
Jingfang Liu
e2677cdc8a Merge pull request #123 from Liujingfang1/master
Add variable reference to pod command,args,env
2018-06-19 12:04:06 -07:00
Jingfang Liu
ea00134776 Update pathconfigs library
implement CRD support and add unit tests

Add integration test for crd support

address comments
2018-06-19 11:45:53 -07:00
Jingfang Liu
ad3cd47c25 Add variable reference to pod command,args,env 2018-06-19 11:25:58 -07:00
guineveresaenger
a1dcf3386b Adds kustomize edit add base command
This pull request adds support for editing the kustomization.yaml in the current directory with a base.
2018-06-19 10:09:13 -07:00
Jingfang Liu
e7ecceb0c2 Update vendor 2018-06-19 09:36:30 -07:00
Ryan Morehart
50c40eb80c CronJob transformation fixed
- no longer add labels in an invalid location (#116)
- only have selector added it already present
2018-06-19 06:14:05 -06:00
Ryan Morehart
398ceb0a92 Jobs do not create a selector if not already present 2018-06-18 17:09:23 -06:00
Jingfang Liu
b7be630924 Merge pull request #113 from uthark/unparam
Enable unparam linter and fix found issues
2018-06-18 11:55:57 -07:00
Oleg Atamanenko
f557841e54 Enable unparam linter and fix issues 2018-06-18 14:49:57 -04:00
Jingfang Liu
9fc24634a2 Merge pull request #115 from woop/patch-1
Update example to show correct environment
2018-06-15 12:35:12 -07:00
Jingfang Liu
0617a283a0 Merge pull request #111 from Liujingfang1/master
Add variable reference to container env
2018-06-15 11:20:25 -07:00
Willem Pienaar
f616e30a38 Update example to show correct environment 2018-06-15 23:27:16 +08:00
Jingfang Liu
50b197f329 Merge pull request #110 from uthark/gometalinter
Add gometalinter to pre-commit hook
2018-06-14 18:52:59 -07:00
Oleg Atamanenko
6fd0330b80 Add gometalinter to pre-commit hook
Enable varcheck and fix found issues

Add ineffassign to list of checks and fix found issues

Added nakedret and fixed found issues

Add interfacer check and fix found issue

Add lll and fix found issues

Add deadcode linter, remove unused code
2018-06-14 20:55:20 -04:00
Jingfang Liu
8127b09d12 Merge pull request #73 from guineveresaenger/example-docfix
Clarifies hello-world example documentation
2018-06-14 15:24:25 -07:00
Jingfang Liu
09ab2bb5c0 Add variable reference to container env 2018-06-14 13:38:58 -07:00
Sunil Arora
54ac4e73e7 Merge pull request #108 from Liujingfang1/args
Add variable reference support for args
2018-06-13 14:51:46 -07:00
Jeff Regan
d4ad7f80e0 Merge pull request #104 from monopole/renameExamplesToTestData
Rename examples dir to examplelayout.
2018-06-12 15:07:14 -07:00
Jeffrey Regan
623e21d1c0 Rename examples dir to examplelayout. 2018-06-12 15:03:45 -07:00
Jeff Regan
0c88c43c67 Merge pull request #102 from monopole/upgradeCrypto
Replace deprecated crypto/md5 with crypto/sha256
2018-06-12 13:51:10 -07:00
Jeffrey Regan
c6d8bcb01b Replace deprecated crypto/md5 with crypto/sha256 2018-06-12 13:47:22 -07:00
Jeff Regan
5285e6101f Merge pull request #101 from monopole/moveVersion
Move version.go to commands dir.
2018-06-12 13:10:00 -07:00
Jeffrey Regan
2fb69db685 Move version.go to commands dir. 2018-06-12 13:08:23 -07:00
guineveresaenger
730597b77e grepping for kiwi 2018-06-12 10:33:37 -07:00
guineveresaenger
d488d9804d grepping for configMap name 2018-06-12 10:29:25 -07:00
Jeff Regan
f98bc42cbb Merge pull request #99 from monopole/tempCaptureExec
Absorb exec package from k8s.io/utils.
2018-06-12 09:46:14 -07:00
Jeffrey Regan
d7b9f64c5a Absorb exec package from utils. 2018-06-12 09:22:07 -07:00
Jeff Regan
785291af62 Merge pull request #95 from Liujingfang1/crdsupport
Add skeleton for CRD support
2018-06-12 09:21:10 -07:00
Jingfang Liu
4f05482e00 Add support for CRDs 2018-06-11 21:52:13 -07:00
Jeff Regan
3c3f85e623 Merge pull request #96 from monopole/secContacts
Fixes #33; add SECURITY_CONTACTS
2018-06-11 19:32:10 -07:00
jregan
40bb81142b Fixes #33; add SECURITY_CONTACTS 2018-06-11 19:30:13 -07:00
Jingfang Liu
46e8fd7065 Add variable reference support for args 2018-06-11 13:57:34 -07:00
guineveresaenger
4e7610a44d Addresses review comments 2018-06-11 12:35:33 -07:00
guineveresaenger
5a3c6553fc Clarifies hello-world example documentation
The example documentation had a few minor discrepancies between commands suggested and expected outcomes. This pull request addresses those, making it easier for folks to use the hello-world demo.
2018-06-08 13:27:20 -07:00
399 changed files with 61034 additions and 1599 deletions

View File

@@ -13,6 +13,7 @@ before_install:
- go get -u github.com/onsi/ginkgo/ginkgo
- go get -u github.com/monopole/mdrip
- go get -u github.com/fzipp/gocyclo
- go get -u gopkg.in/alecthomas/gometalinter.v2 && gometalinter.v2 --install
# Install must be set to prevent default `go get` to run.
# The dependencies have already been vendored by `dep` so

71
Gopkg.lock generated
View File

@@ -1,12 +1,33 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/PuerkitoBio/purell"
packages = ["."]
revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4"
version = "v1.1.0"
[[projects]]
branch = "master"
name = "github.com/PuerkitoBio/urlesc"
packages = ["."]
revision = "de5bf2ad457846296e2031421a34e2568e304e35"
[[projects]]
name = "github.com/davecgh/go-spew"
packages = ["spew"]
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0"
[[projects]]
name = "github.com/emicklei/go-restful"
packages = [
".",
"log"
]
revision = "3658237ded108b4134956c1b3050349d93e7b895"
version = "v2.7.1"
[[projects]]
name = "github.com/evanphx/json-patch"
packages = ["."]
@@ -19,6 +40,30 @@
revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "github.com/go-openapi/jsonpointer"
packages = ["."]
revision = "3a0015ad55fa9873f41605d3e8f28cd279c32ab2"
[[projects]]
branch = "master"
name = "github.com/go-openapi/jsonreference"
packages = ["."]
revision = "3fb327e6747da3043567ee86abd02bb6376b6be2"
[[projects]]
branch = "master"
name = "github.com/go-openapi/spec"
packages = ["."]
revision = "bcff419492eeeb01f76e77d2ebc714dc97b607f5"
[[projects]]
branch = "master"
name = "github.com/go-openapi/swag"
packages = ["."]
revision = "811b1089cde9dad18d4d0c2d09fbdbf28dbd27a5"
[[projects]]
name = "github.com/gogo/protobuf"
packages = [
@@ -74,6 +119,16 @@
revision = "ca39e5af3ece67bbcda3d0f4f56a8e24d9f2dad4"
version = "1.1.3"
[[projects]]
branch = "master"
name = "github.com/mailru/easyjson"
packages = [
"buffer",
"jlexer",
"jwriter"
]
revision = "3fdea8d05856a0c8df22ed4bc71b3219245e4485"
[[projects]]
name = "github.com/modern-go/concurrent"
packages = ["."]
@@ -131,7 +186,8 @@
"unicode/bidi",
"unicode/cldr",
"unicode/norm",
"unicode/rangetable"
"unicode/rangetable",
"width"
]
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0"
@@ -231,18 +287,15 @@
[[projects]]
branch = "master"
name = "k8s.io/kube-openapi"
packages = ["pkg/util/proto"]
packages = [
"pkg/common",
"pkg/util/proto"
]
revision = "b3f03f55328800731ce03a164b80973014ecd455"
[[projects]]
branch = "master"
name = "k8s.io/utils"
packages = ["exec"]
revision = "258e2a2fa64568210fbd6267cf1d8fd87c3cb86e"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "e966d7880a29cf5669060d6564407f0f4c164e93eb844c22efec383383af2d3e"
inputs-digest = "586d4cb9094e9b5c0731f16e931b953e9c0f709b7125a7537ae3625ada179eee"
solver-name = "gps-cdcl"
solver-version = 1

View File

@@ -52,3 +52,7 @@
[[constraint]]
branch = "master"
name = "k8s.io/utils"
[[constraint]]
branch = "master"
name = "github.com/go-openapi/spec"

15
SECURITY_CONTACTS Normal file
View File

@@ -0,0 +1,15 @@
# Defined below are the security contacts for this repo.
#
# They are the contact point for the Product Security Team to reach out
# to for triaging and handling of incoming issues.
#
# The below names agree to abide by the
# [Embargo Policy](https://github.com/kubernetes/sig-release/blob/master/security-release-process-documentation/security-release-process.md#embargo-policy)
# and will be removed and replaced if they violate that agreement.
#
# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE
# INSTRUCTIONS AT https://kubernetes.io/security/
monopole
Liujingfang1
pwittrock

View File

@@ -1,4 +1,5 @@
#!/bin/bash
set -e
# Make sure, we run in the root of the repo and
# therefore run the tests on all packages
@@ -36,14 +37,28 @@ function testGoCyclo {
diff <(echo -n) <(go_dirs | xargs -0 gocyclo -over 15)
}
function testGoImports {
diff -u <(echo -n) <(go_dirs | xargs -0 goimports -l)
}
function testGoLint {
diff -u <(echo -n) <(go_dirs | xargs -0 golint --min_confidence 0.85 )
}
function testGoMetalinter {
diff -u <(echo -n) <(go_dirs | xargs -0 gometalinter.v2 --disable-all --deadline 5m \
--enable=misspell \
--enable=structcheck \
--enable=deadcode \
--enable=goimports \
--enable=varcheck \
--enable=goconst \
--enable=unparam \
--enable=ineffassign \
--enable=nakedret \
--enable=interfacer \
--enable=misspell \
--line-length=170 --enable=lll \
--dupl-threshold=400 --enable=dupl)
}
function testGoVet {
go vet -all ./...
}
@@ -57,7 +72,7 @@ function testExamples {
}
runTest testGoFmt
runTest testGoImports
runTest testGoMetalinter
runTest testGoLint
runTest testGoVet
runTest testGoCyclo

View File

@@ -82,6 +82,11 @@ secretGenerator:
tls.crt: "cat secret/tls.cert"
tls.key: "cat secret/tls.key"
type: "kubernetes.io/tls"
- name: downloaded_secret
commands:
username: "curl -s https://path/to/secrets/username.yaml"
password: "curl -s https://path/to/secrets/password.yaml"
type: Opaque
# Each entry in this list should resolve to a directory
# containing a kustomization file, else the
@@ -115,3 +120,19 @@ patches:
- service_port_8888.yaml
- deployment_increase_replicas.yaml
- deployment_increase_memory.yaml
# Each entry in this list should be a relative path to
# a file for custom resource definition(CRD).
#
# The presence of this field is to allow kustomize be
# aware of CRDs and apply proper
# transformation for any objects in those types.
#
# Typical use case: A CRD object refers to a ConfigMap object.
# In kustomization, the ConfigMap object name may change by adding namePrefix or hashing
# The name reference for this ConfigMap object in CRD object need to be
# updated with namePrefix or hashing in the same way.
crds:
- crds/typeA.yaml
- crds/typeB.yaml

View File

@@ -112,6 +112,12 @@ sed -i 's/app: hello/app: my-hello/' \
$BASE/kustomization.yaml
```
On a Mac, use:
```
sed -i '' $pattern $file
```
to get in-place editing.
See the effect:
<!-- @checkLabel @test -->
```
@@ -397,7 +403,14 @@ the server will use:
sed -i 's/pineapple/kiwi/' $OVERLAYS/staging/map.yaml
```
Run kustomize again to see the new names:
See the new greeting:
```
kustomize build $OVERLAYS/staging |\
grep -B 2 -A 3 kiwi
```
Run kustomize again to see the new configMap names:
<!-- @grepStagingName @test -->
```
@@ -413,7 +426,8 @@ uses the map:
<!-- @countHashes @test -->
```
test 3 == \
$(kustomize build $OVERLAYS/staging | grep khk45ktkd9 | wc -l)
$(kustomize build $OVERLAYS/staging | grep khk45ktkd9 | wc -l); \
echo $?
```
Applying these resources to the cluster will result in

View File

@@ -4,7 +4,7 @@ metadata:
name: demo-configmap
data:
application.properties: |
app.name=Staging Kinflate Demo
app.name=Production Kinflate Demo
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://<production_db_ip>:3306/db_example
spring.datasource.username=root

View File

@@ -89,7 +89,7 @@ The patch has following content
> - name: wordpress
> env:
> - name: WORDPRESS_DB_HOST
> value: mysql
> value: $(MYSQL_SERVICE)
> - name: WORDPRESS_DB_PASSWORD
> valueFrom:
> secretKeyRef:

View File

@@ -15,7 +15,7 @@ spec:
- name: wordpress
env:
- name: WORDPRESS_DB_HOST
value: mysql
value: $(MYSQL_SERVICE)
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:

View File

@@ -27,6 +27,7 @@ import (
"github.com/golang/glog"
"github.com/kubernetes-sigs/kustomize/pkg/constants"
"github.com/kubernetes-sigs/kustomize/pkg/crds"
interror "github.com/kubernetes-sigs/kustomize/pkg/internal/error"
"github.com/kubernetes-sigs/kustomize/pkg/loader"
"github.com/kubernetes-sigs/kustomize/pkg/resmap"
@@ -127,7 +128,11 @@ func (a *Application) loadCustomizedResMap() (resmap.ResMap, error) {
errs := &interror.KustomizationErrors{}
result, err := a.loadResMapFromBasesAndResources()
if err != nil {
errs.Append(errors.Wrap(err, "rawResources"))
errs.Append(errors.Wrap(err, "loadResMapFromBasesAndResources"))
}
err = crds.RegisterCRDs(a.loader, a.kustomization.CRDs)
if err != nil {
errs.Append(errors.Wrap(err, "RegisterCRDs"))
}
cms, err := resmap.NewResMapFromConfigMapArgs(a.loader, a.kustomization.ConfigMapGenerator)

99
pkg/commands/addbase.go Normal file
View File

@@ -0,0 +1,99 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package commands
import (
"errors"
"fmt"
"strings"
"github.com/spf13/cobra"
"github.com/kubernetes-sigs/kustomize/pkg/constants"
"github.com/kubernetes-sigs/kustomize/pkg/fs"
)
type addBaseOptions struct {
baseDirectoryPaths string
}
// newCmdAddBase adds the file path of the kustomize base to the kustomization file.
func newCmdAddBase(fsys fs.FileSystem) *cobra.Command {
var o addBaseOptions
cmd := &cobra.Command{
Use: "base",
Short: "Adds one or more bases to the kustomization.yaml in current directory",
Example: `
add base {filepath1},{filepath2}`,
RunE: func(cmd *cobra.Command, args []string) error {
err := o.Validate(args)
if err != nil {
return err
}
err = o.Complete(cmd, args)
if err != nil {
return err
}
return o.RunAddBase(fsys)
},
}
return cmd
}
// Validate validates addBase command.
func (o *addBaseOptions) Validate(args []string) error {
if len(args) != 1 {
return errors.New("must specify a base directory")
}
o.baseDirectoryPaths = args[0]
return nil
}
// Complete completes addBase command.
func (o *addBaseOptions) Complete(cmd *cobra.Command, args []string) error {
return nil
}
// RunAddBase runs addBase command (do real work).
func (o *addBaseOptions) RunAddBase(fsys fs.FileSystem) error {
mf, err := newKustomizationFile(constants.KustomizationFileName, fsys)
if err != nil {
return err
}
m, err := mf.read()
if err != nil {
return err
}
// split directory paths
paths := strings.Split(o.baseDirectoryPaths, ",")
for _, path := range paths {
_, err := fsys.Stat(path)
if err != nil {
return err
}
if stringInSlice(path, m.Bases) {
return fmt.Errorf("base %s already in kustomization file", path)
}
m.Bases = append(m.Bases, path)
}
return mf.write(m)
}

View File

@@ -0,0 +1,100 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package commands
import (
"testing"
"strings"
"github.com/kubernetes-sigs/kustomize/pkg/constants"
"github.com/kubernetes-sigs/kustomize/pkg/fs"
)
const (
baseDirectoryPaths = "my/path/to/wonderful/base,other/path/to/even/more/wonderful/base"
)
func TestAddBaseHappyPath(t *testing.T) {
fakeFS := fs.MakeFakeFS()
bases := strings.Split(baseDirectoryPaths, ",")
for _, base := range bases {
fakeFS.Mkdir(base, 0777)
}
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
cmd := newCmdAddBase(fakeFS)
args := []string{baseDirectoryPaths}
err := cmd.RunE(cmd, args)
if err != nil {
t.Errorf("unexpected cmd error: %v", err)
}
content, err := fakeFS.ReadFile(constants.KustomizationFileName)
if err != nil {
t.Errorf("unexpected read error: %v", err)
}
for _, base := range bases {
if !strings.Contains(string(content), base) {
t.Errorf("expected base name in kustomization")
}
}
}
func TestAddBaseAlreadyThere(t *testing.T) {
fakeFS := fs.MakeFakeFS()
// Create fake directories
bases := strings.Split(baseDirectoryPaths, ",")
for _, base := range bases {
fakeFS.Mkdir(base, 0777)
}
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
cmd := newCmdAddBase(fakeFS)
args := []string{baseDirectoryPaths}
err := cmd.RunE(cmd, args)
if err != nil {
t.Fatalf("unexpected cmd error: %v", err)
}
// adding an existing base should return an error
err = cmd.RunE(cmd, args)
if err == nil {
t.Errorf("expected already there problem")
}
var expectedErrors []string
for _, base := range bases {
error := "base " + base + " already in kustomization file"
expectedErrors = append(expectedErrors, error)
if !stringInSlice(error, expectedErrors) {
t.Errorf("unexpected error %v", err)
}
}
}
func TestAddBaseNoArgs(t *testing.T) {
fakeFS := fs.MakeFakeFS()
cmd := newCmdAddBase(fakeFS)
err := cmd.Execute()
if err == nil {
t.Errorf("expected error: %v", err)
}
if err.Error() != "must specify a base directory" {
t.Errorf("incorrect error: %v", err.Error())
}
}

View File

@@ -19,7 +19,6 @@ package commands
import (
"errors"
"fmt"
"io"
"github.com/spf13/cobra"
@@ -32,7 +31,7 @@ type addPatchOptions struct {
}
// newCmdAddPatch adds the name of a file containing a patch to the kustomization file.
func newCmdAddPatch(out, errOut io.Writer, fsys fs.FileSystem) *cobra.Command {
func newCmdAddPatch(fsys fs.FileSystem) *cobra.Command {
var o addPatchOptions
cmd := &cobra.Command{
@@ -49,7 +48,7 @@ func newCmdAddPatch(out, errOut io.Writer, fsys fs.FileSystem) *cobra.Command {
if err != nil {
return err
}
return o.RunAddPatch(out, errOut, fsys)
return o.RunAddPatch(fsys)
},
}
return cmd
@@ -70,7 +69,7 @@ func (o *addPatchOptions) Complete(cmd *cobra.Command, args []string) error {
}
// RunAddPatch runs addPatch command (do real work).
func (o *addPatchOptions) RunAddPatch(out, errOut io.Writer, fsys fs.FileSystem) error {
func (o *addPatchOptions) RunAddPatch(fsys fs.FileSystem) error {
_, err := fsys.Stat(o.patchFilePath)
if err != nil {
return err

View File

@@ -17,8 +17,6 @@ limitations under the License.
package commands
import (
"bytes"
"os"
"testing"
"strings"
@@ -36,12 +34,11 @@ sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
)
func TestAddPatchHappyPath(t *testing.T) {
buf := bytes.NewBuffer([]byte{})
fakeFS := fs.MakeFakeFS()
fakeFS.WriteFile(patchFileName, []byte(patchFileContent))
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
cmd := newCmdAddPatch(buf, os.Stderr, fakeFS)
cmd := newCmdAddPatch(fakeFS)
args := []string{patchFileName}
err := cmd.RunE(cmd, args)
if err != nil {
@@ -57,12 +54,11 @@ func TestAddPatchHappyPath(t *testing.T) {
}
func TestAddPatchAlreadyThere(t *testing.T) {
buf := bytes.NewBuffer([]byte{})
fakeFS := fs.MakeFakeFS()
fakeFS.WriteFile(patchFileName, []byte(patchFileContent))
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
cmd := newCmdAddPatch(buf, os.Stderr, fakeFS)
cmd := newCmdAddPatch(fakeFS)
args := []string{patchFileName}
err := cmd.RunE(cmd, args)
if err != nil {
@@ -80,10 +76,9 @@ func TestAddPatchAlreadyThere(t *testing.T) {
}
func TestAddPatchNoArgs(t *testing.T) {
buf := bytes.NewBuffer([]byte{})
fakeFS := fs.MakeFakeFS()
cmd := newCmdAddPatch(buf, os.Stderr, fakeFS)
cmd := newCmdAddPatch(fakeFS)
err := cmd.Execute()
if err == nil {
t.Errorf("expected error: %v", err)

View File

@@ -19,7 +19,6 @@ package commands
import (
"errors"
"fmt"
"io"
"github.com/spf13/cobra"
@@ -32,7 +31,7 @@ type addResourceOptions struct {
}
// newCmdAddResource adds the name of a file containing a resource to the kustomization file.
func newCmdAddResource(out, errOut io.Writer, fsys fs.FileSystem) *cobra.Command {
func newCmdAddResource(fsys fs.FileSystem) *cobra.Command {
var o addResourceOptions
cmd := &cobra.Command{
@@ -49,7 +48,7 @@ func newCmdAddResource(out, errOut io.Writer, fsys fs.FileSystem) *cobra.Command
if err != nil {
return err
}
return o.RunAddResource(out, errOut, fsys)
return o.RunAddResource(fsys)
},
}
return cmd
@@ -70,7 +69,7 @@ func (o *addResourceOptions) Complete(cmd *cobra.Command, args []string) error {
}
// RunAddResource runs addResource command (do real work).
func (o *addResourceOptions) RunAddResource(out, errOut io.Writer, fsys fs.FileSystem) error {
func (o *addResourceOptions) RunAddResource(fsys fs.FileSystem) error {
_, err := fsys.Stat(o.resourceFilePath)
if err != nil {
return err

View File

@@ -17,8 +17,6 @@ limitations under the License.
package commands
import (
"bytes"
"os"
"testing"
"strings"
@@ -52,12 +50,11 @@ secretGenerator: []
)
func TestAddResourceHappyPath(t *testing.T) {
buf := bytes.NewBuffer([]byte{})
fakeFS := fs.MakeFakeFS()
fakeFS.WriteFile(resourceFileName, []byte(resourceFileContent))
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
cmd := newCmdAddResource(buf, os.Stderr, fakeFS)
cmd := newCmdAddResource(fakeFS)
args := []string{resourceFileName}
err := cmd.RunE(cmd, args)
if err != nil {
@@ -73,12 +70,11 @@ func TestAddResourceHappyPath(t *testing.T) {
}
func TestAddResourceAlreadyThere(t *testing.T) {
buf := bytes.NewBuffer([]byte{})
fakeFS := fs.MakeFakeFS()
fakeFS.WriteFile(resourceFileName, []byte(resourceFileContent))
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
cmd := newCmdAddResource(buf, os.Stderr, fakeFS)
cmd := newCmdAddResource(fakeFS)
args := []string{resourceFileName}
err := cmd.RunE(cmd, args)
if err != nil {
@@ -96,10 +92,9 @@ func TestAddResourceAlreadyThere(t *testing.T) {
}
func TestAddResourceNoArgs(t *testing.T) {
buf := bytes.NewBuffer([]byte{})
fakeFS := fs.MakeFakeFS()
cmd := newCmdAddResource(buf, os.Stderr, fakeFS)
cmd := newCmdAddResource(fakeFS)
err := cmd.Execute()
if err == nil {
t.Errorf("expected error: %v", err)

View File

@@ -35,7 +35,7 @@ type buildOptions struct {
}
// newCmdBuild creates a new build command.
func newCmdBuild(out, errOut io.Writer, fs fs.FileSystem) *cobra.Command {
func newCmdBuild(out io.Writer, fs fs.FileSystem) *cobra.Command {
var o buildOptions
cmd := &cobra.Command{
@@ -43,12 +43,13 @@ func newCmdBuild(out, errOut io.Writer, fs fs.FileSystem) *cobra.Command {
Short: "Print current configuration per contents of " + constants.KustomizationFileName,
Example: "Use the file somedir/" + constants.KustomizationFileName +
" to generate a set of api resources:\nbuild somedir/",
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
err := o.Validate(args)
if err != nil {
return err
}
return o.RunBuild(out, errOut, fs)
return o.RunBuild(out, fs)
},
}
return cmd
@@ -68,7 +69,7 @@ func (o *buildOptions) Validate(args []string) error {
}
// RunBuild runs build command.
func (o *buildOptions) RunBuild(out, errOut io.Writer, fs fs.FileSystem) error {
func (o *buildOptions) RunBuild(out io.Writer, fs fs.FileSystem) error {
l := loader.Init([]loader.SchemeLoader{loader.NewFileLoader(fs)})
absPath, err := filepath.Abs(o.kustomizationPath)

View File

@@ -125,7 +125,7 @@ func runBuildTestCase(t *testing.T, testcaseName string, updateKustomizeExpected
kustomizationPath: testcase.Filename,
}
buf := bytes.NewBuffer([]byte{})
err = ops.RunBuild(buf, os.Stderr, fs)
err = ops.RunBuild(buf, fs)
switch {
case err != nil && len(testcase.ExpectedError) == 0:
t.Errorf("unexpected error: %v", err)

View File

@@ -19,11 +19,9 @@ package commands
import (
"flag"
"io"
"os"
"github.com/kubernetes-sigs/kustomize/pkg/fs"
"github.com/kubernetes-sigs/kustomize/version"
"github.com/spf13/cobra"
)
@@ -43,10 +41,11 @@ See https://github.com/kubernetes-sigs/kustomize
}
c.AddCommand(
newCmdBuild(stdOut, stdErr, fsys),
// TODO: Make consistent API for newCmd* functions.
newCmdBuild(stdOut, fsys),
newCmdDiff(stdOut, stdErr, fsys),
newCmdEdit(stdOut, stdErr, fsys),
version.NewCmdVersion(stdOut),
newCmdEdit(fsys),
newCmdVersion(stdOut),
)
c.PersistentFlags().AddGoFlagSet(flag.CommandLine)
@@ -57,7 +56,7 @@ See https://github.com/kubernetes-sigs/kustomize
}
// newCmdEdit returns an instance of 'edit' subcommand.
func newCmdEdit(stdOut, stdErr io.Writer, fsys fs.FileSystem) *cobra.Command {
func newCmdEdit(fsys fs.FileSystem) *cobra.Command {
c := &cobra.Command{
Use: "edit",
Short: "Edits a kustomization file",
@@ -72,17 +71,17 @@ func newCmdEdit(stdOut, stdErr io.Writer, fsys fs.FileSystem) *cobra.Command {
Args: cobra.MinimumNArgs(1),
}
c.AddCommand(
newCmdAdd(stdOut, stdErr, fsys),
newCmdSet(stdOut, stdErr, fsys),
newCmdAdd(fsys),
newCmdSet(fsys),
)
return c
}
// newAddCommand returns an instance of 'add' subcommand.
func newCmdAdd(stdOut, stdErr io.Writer, fsys fs.FileSystem) *cobra.Command {
func newCmdAdd(fsys fs.FileSystem) *cobra.Command {
c := &cobra.Command{
Use: "add",
Short: "Adds configmap/resource/patch to the kustomization file.",
Short: "Adds configmap/resource/patch/base to the kustomization file.",
Long: "",
Example: `
# Adds a configmap to the kustomization file
@@ -93,19 +92,24 @@ func newCmdAdd(stdOut, stdErr io.Writer, fsys fs.FileSystem) *cobra.Command {
# Adds a patch to the kustomization
kustomize edit add patch <filepath>
# Adds one or more base directories to the kustomization
kustomize edit add base <filepath>
kustomize edit add base <filepath1>,<filepath2>,<filepath3>
`,
Args: cobra.MinimumNArgs(1),
}
c.AddCommand(
newCmdAddResource(stdOut, stdErr, fsys),
newCmdAddPatch(stdOut, stdErr, fsys),
newCmdAddConfigMap(stdErr, fsys),
newCmdAddResource(fsys),
newCmdAddPatch(fsys),
newCmdAddConfigMap(fsys),
newCmdAddBase(fsys),
)
return c
}
// newSetCommand returns an instance of 'set' subcommand.
func newCmdSet(stdOut, stdErr io.Writer, fsys fs.FileSystem) *cobra.Command {
func newCmdSet(fsys fs.FileSystem) *cobra.Command {
c := &cobra.Command{
Use: "set",
Short: "Sets the value of different fields in kustomization file.",
@@ -118,7 +122,7 @@ func newCmdSet(stdOut, stdErr io.Writer, fsys fs.FileSystem) *cobra.Command {
}
c.AddCommand(
newCmdSetNamePrefix(stdOut, stdErr, fsys),
newCmdSetNamePrefix(fsys),
)
return c
}

View File

@@ -18,7 +18,6 @@ package commands
import (
"fmt"
"io"
"github.com/spf13/cobra"
@@ -28,7 +27,7 @@ import (
"github.com/kubernetes-sigs/kustomize/pkg/types"
)
func newCmdAddConfigMap(errOut io.Writer, fsys fs.FileSystem) *cobra.Command {
func newCmdAddConfigMap(fsys fs.FileSystem) *cobra.Command {
var config dataConfig
cmd := &cobra.Command{
Use: "configmap NAME [--from-file=[key=]source] [--from-literal=key1=value1]",
@@ -76,7 +75,9 @@ func newCmdAddConfigMap(errOut io.Writer, fsys fs.FileSystem) *cobra.Command {
&config.FileSources,
"from-file",
[]string{},
"Key file can be specified using its file path, in which case file basename will be used as configmap key, or optionally with a key and file path, in which case the given key will be used. Specifying a directory will iterate each named file in the directory whose basename is a valid configmap key.")
"Key file can be specified using its file path, in which case file basename will be used as configmap "+
"key, or optionally with a key and file path, in which case the given key will be used. Specifying a "+
"directory will iterate each named file in the directory whose basename is a valid configmap key.")
cmd.Flags().StringArrayVar(
&config.LiteralSources,
"from-literal",

View File

@@ -24,7 +24,7 @@ import (
)
func TestNewAddConfigMapIsNotNil(t *testing.T) {
if newCmdAddConfigMap(nil, fs.MakeFakeFS()) == nil {
if newCmdAddConfigMap(fs.MakeFakeFS()) == nil {
t.Fatal("newCmdAddConfigMap shouldn't be nil")
}
}

View File

@@ -42,7 +42,7 @@ func newCmdDiff(out, errOut io.Writer, fs fs.FileSystem) *cobra.Command {
Use: "diff [path]",
Short: "diff between customized resources and uncustomized resources",
RunE: func(cmd *cobra.Command, args []string) error {
err := o.Validate(cmd, args)
err := o.Validate(args)
if err != nil {
return err
}
@@ -53,7 +53,7 @@ func newCmdDiff(out, errOut io.Writer, fs fs.FileSystem) *cobra.Command {
}
// Validate validates diff command.
func (o *diffOptions) Validate(cmd *cobra.Command, args []string) error {
func (o *diffOptions) Validate(args []string) error {
if len(args) > 1 {
return errors.New("specify one path to " + constants.KustomizationFileName)
}

View File

@@ -1,96 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package commands
import (
"fmt"
"io"
"errors"
"github.com/kubernetes-sigs/kustomize/pkg/constants"
"github.com/kubernetes-sigs/kustomize/pkg/fs"
"github.com/spf13/cobra"
)
const kustomizationTemplate = `
namePrefix: some-prefix
# Labels to add to all objects and selectors.
# These labels would also be used to form the selector for apply --prune
# Named differently than “labels” to avoid confusion with metadata for this object
commonLabels:
app: helloworld
commonAnnotations:
note: This is an example annotation
resources: []
#- service.yaml
#- ../some-dir/
# There could also be configmaps in Base, which would make these overlays
configMapGenerator: []
# There could be secrets in Base, if just using a fork/rebase workflow
secretGenerator: []
`
type initOptions struct {
}
// NewCmdInit makes the init command.
func newCmdInit(out, errOut io.Writer, fs fs.FileSystem) *cobra.Command {
var o initOptions
cmd := &cobra.Command{
Use: "init",
Short: "Creates a file called \"" + constants.KustomizationFileName + "\" in the current directory",
Long: "Creates a file called \"" +
constants.KustomizationFileName + "\" in the current directory with example values.",
Example: `init`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
err := o.Validate(cmd, args)
if err != nil {
return err
}
err = o.Complete(cmd, args)
if err != nil {
return err
}
return o.RunInit(out, errOut, fs)
},
}
return cmd
}
// Validate validates init command.
func (o *initOptions) Validate(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
return errors.New("The init command takes no arguments.")
}
return nil
}
// Complete completes init command.
func (o *initOptions) Complete(cmd *cobra.Command, args []string) error {
return nil
}
// RunInit writes a kustomization file.
func (o *initOptions) RunInit(out, errOut io.Writer, fs fs.FileSystem) error {
if _, err := fs.Stat(constants.KustomizationFileName); err == nil {
return fmt.Errorf("%q already exists", constants.KustomizationFileName)
}
return fs.WriteFile(constants.KustomizationFileName, []byte(kustomizationTemplate))
}

View File

@@ -35,7 +35,7 @@ type kustomizationFile struct {
fsys fs.FileSystem
}
func newKustomizationFile(mPath string, fsys fs.FileSystem) (*kustomizationFile, error) {
func newKustomizationFile(mPath string, fsys fs.FileSystem) (*kustomizationFile, error) { // nolint
mf := &kustomizationFile{path: mPath, fsys: fsys}
err := mf.validate()
if err != nil {

View File

@@ -18,7 +18,6 @@ package commands
import (
"errors"
"io"
"github.com/spf13/cobra"
@@ -31,7 +30,7 @@ type setNamePrefixOptions struct {
}
// newCmdSetNamePrefix sets the value of the namePrefix field in the kustomization.
func newCmdSetNamePrefix(out, errOut io.Writer, fsys fs.FileSystem) *cobra.Command {
func newCmdSetNamePrefix(fsys fs.FileSystem) *cobra.Command {
var o setNamePrefixOptions
cmd := &cobra.Command{
@@ -52,7 +51,7 @@ and overwrite the value with "acme-" if the field does exist.
if err != nil {
return err
}
return o.RunSetNamePrefix(out, errOut, fsys)
return o.RunSetNamePrefix(fsys)
},
}
return cmd
@@ -74,7 +73,7 @@ func (o *setNamePrefixOptions) Complete(cmd *cobra.Command, args []string) error
}
// RunSetNamePrefix runs setNamePrefix command (does real work).
func (o *setNamePrefixOptions) RunSetNamePrefix(out, errOut io.Writer, fsys fs.FileSystem) error {
func (o *setNamePrefixOptions) RunSetNamePrefix(fsys fs.FileSystem) error {
mf, err := newKustomizationFile(constants.KustomizationFileName, fsys)
if err != nil {
return err

View File

@@ -17,8 +17,6 @@ limitations under the License.
package commands
import (
"bytes"
"os"
"testing"
"strings"
@@ -32,11 +30,10 @@ const (
)
func TestSetNamePrefixHappyPath(t *testing.T) {
buf := bytes.NewBuffer([]byte{})
fakeFS := fs.MakeFakeFS()
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
cmd := newCmdSetNamePrefix(buf, os.Stderr, fakeFS)
cmd := newCmdSetNamePrefix(fakeFS)
args := []string{goodPrefixValue}
err := cmd.RunE(cmd, args)
if err != nil {
@@ -52,10 +49,9 @@ func TestSetNamePrefixHappyPath(t *testing.T) {
}
func TestSetNamePrefixNoArgs(t *testing.T) {
buf := bytes.NewBuffer([]byte{})
fakeFS := fs.MakeFakeFS()
cmd := newCmdSetNamePrefix(buf, os.Stderr, fakeFS)
cmd := newCmdSetNamePrefix(fakeFS)
err := cmd.Execute()
if err == nil {
t.Errorf("expected error: %v", err)

View File

@@ -6,5 +6,4 @@ commonLabels:
commonAnnotations:
note: This is a test annotation
resources:
- deployment.yaml
- service.yaml
- resources/*.yaml

View File

@@ -0,0 +1,6 @@
apiVersion: v1beta1
kind: Bee
metadata:
name: bee
spec:
action: fly

View File

@@ -0,0 +1,9 @@
crds:
- mycrd.json
resources:
- secret.yaml
- mykind.yaml
- bee.yaml
namePrefix: test-

View File

@@ -0,0 +1,170 @@
{
"github.com/example/pkg/apis/jingfang/v1beta1.Bee": {
"Schema": {
"description": "Bee",
"properties": {
"apiVersion": {
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources",
"type": "string"
},
"kind": {
"description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds",
"type": "string"
},
"metadata": {
"$ref": "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"
},
"spec": {
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.BeeSpec"
},
"status": {
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.BeeStatus"
}
}
},
"Dependencies": [
"github.com/example/pkg/apis/jingfang/v1beta1.BeeSpec",
"github.com/example/pkg/apis/jingfang/v1beta1.BeeStatus",
"k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"
]
},
"github.com/example/pkg/apis/jingfang/v1beta1.BeeList": {
"Schema": {
"required": [
"items"
],
"properties": {
"apiVersion": {
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources",
"type": "string"
},
"items": {
"type": "array",
"items": {
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.Bee"
}
},
"kind": {
"description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds",
"type": "string"
},
"metadata": {
"$ref": "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"
}
}
},
"Dependencies": [
"github.com/example/pkg/apis/jingfang/v1beta1.Bee",
"k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"
]
},
"github.com/example/pkg/apis/jingfang/v1beta1.BeeObjectReference": {
"Schema": {
"properties": {
"name": {
"type": "string"
}
}
},
"Dependencies": []
},
"github.com/example/pkg/apis/jingfang/v1beta1.BeeSpec": {
"Schema": {
"description": "BeeSpec defines the desired state of Bee"
},
"Dependencies": []
},
"github.com/example/pkg/apis/jingfang/v1beta1.BeeStatus": {
"Schema": {
"description": "BeeStatus defines the observed state of Bee"
},
"Dependencies": []
},
"github.com/example/pkg/apis/jingfang/v1beta1.MyKind": {
"Schema": {
"description": "MyKind",
"properties": {
"apiVersion": {
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources",
"type": "string"
},
"kind": {
"description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds",
"type": "string"
},
"metadata": {
"$ref": "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"
},
"spec": {
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.MyKindSpec"
},
"status": {
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.MyKindStatus"
}
}
},
"Dependencies": [
"github.com/example/pkg/apis/jingfang/v1beta1.MyKindSpec",
"github.com/example/pkg/apis/jingfang/v1beta1.MyKindStatus",
"k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"
]
},
"github.com/example/pkg/apis/jingfang/v1beta1.MyKindList": {
"Schema": {
"required": [
"items"
],
"properties": {
"apiVersion": {
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources",
"type": "string"
},
"items": {
"type": "array",
"items": {
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.MyKind"
}
},
"kind": {
"description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds",
"type": "string"
},
"metadata": {
"$ref": "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"
}
}
},
"Dependencies": [
"github.com/example/pkg/apis/jingfang/v1beta1.MyKind",
"k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"
]
},
"github.com/example/pkg/apis/jingfang/v1beta1.MyKindSpec": {
"Schema": {
"description": "MyKindSpec defines the desired state of MyKind",
"properties": {
"beeRef": {
"x-kubernetes-object-ref-api-version": "v1beta1",
"x-kubernetes-object-ref-kind": "Bee",
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.BeeObjectReference"
},
"secretRef": {
"description": "If defined, we use this secret for configuring the MYSQL_ROOT_PASSWORD If it is not set we generate a secret dynamically",
"x-kubernetes-object-ref-api-version": "v1",
"x-kubernetes-object-ref-kind": "Secret",
"$ref": "k8s.io/api/core/v1.LocalObjectReference"
}
}
},
"Dependencies": [
"github.com/example/pkg/apis/jingfang/v1beta1.BeeObjectReference",
"k8s.io/api/core/v1.LocalObjectReference"
]
},
"github.com/example/pkg/apis/jingfang/v1beta1.MyKindStatus": {
"Schema": {
"description": "MyKindStatus defines the observed state of MyKind"
},
"Dependencies": []
}
}

View File

@@ -0,0 +1,9 @@
apiVersion: jingfang.example.com/v1beta1
kind: MyKind
metadata:
name: mykind
spec:
secretRef:
name: crdsecret
beeRef:
name: bee

View File

@@ -0,0 +1,6 @@
apiVersion: v1
kind: Secret
metadata:
name: crdsecret
data:
PATH: YmJiYmJiYmIK

View File

@@ -0,0 +1,36 @@
diff -u -N /tmp/noop/jingfang.example.com_v1beta1_MyKind_mykind.yaml /tmp/transformed/jingfang.example.com_v1beta1_MyKind_mykind.yaml
--- /tmp/noop/jingfang.example.com_v1beta1_MyKind_mykind.yaml YYYY-MM-DD HH:MM:SS
+++ /tmp/transformed/jingfang.example.com_v1beta1_MyKind_mykind.yaml YYYY-MM-DD HH:MM:SS
@@ -1,9 +1,9 @@
apiVersion: jingfang.example.com/v1beta1
kind: MyKind
metadata:
- name: mykind
+ name: test-mykind
spec:
beeRef:
- name: bee
+ name: test-bee
secretRef:
- name: crdsecret-m5ht5thcb4
+ name: test-crdsecret-m48btmkck5
diff -u -N /tmp/noop/v1beta1_Bee_bee.yaml /tmp/transformed/v1beta1_Bee_bee.yaml
--- /tmp/noop/v1beta1_Bee_bee.yaml YYYY-MM-DD HH:MM:SS
+++ /tmp/transformed/v1beta1_Bee_bee.yaml YYYY-MM-DD HH:MM:SS
@@ -1,6 +1,6 @@
apiVersion: v1beta1
kind: Bee
metadata:
- name: bee
+ name: test-bee
spec:
action: fly
diff -u -N /tmp/noop/v1_Secret_crdsecret.yaml /tmp/transformed/v1_Secret_crdsecret.yaml
--- /tmp/noop/v1_Secret_crdsecret.yaml YYYY-MM-DD HH:MM:SS
+++ /tmp/transformed/v1_Secret_crdsecret.yaml YYYY-MM-DD HH:MM:SS
@@ -3,4 +3,4 @@
PATH: YmJiYmJiYmIK
kind: Secret
metadata:
- name: crdsecret-m5ht5thcb4
+ name: test-crdsecret-m48btmkck5

View File

@@ -0,0 +1,23 @@
apiVersion: v1
data:
PATH: YmJiYmJiYmIK
kind: Secret
metadata:
name: test-crdsecret-m48btmkck5
---
apiVersion: v1beta1
kind: Bee
metadata:
name: test-bee
spec:
action: fly
---
apiVersion: jingfang.example.com/v1beta1
kind: MyKind
metadata:
name: test-mykind
spec:
beeRef:
name: test-bee
secretRef:
name: test-crdsecret-m48btmkck5

View File

@@ -0,0 +1,5 @@
description: name reference in CRDs
args: []
filename: testdata/testcase-crds/crd
expectedStdout: testdata/testcase-crds/expected.yaml
expectedDiff: testdata/testcase-crds/expected.diff

View File

@@ -2,8 +2,7 @@ namePrefix: staging-
commonLabels:
env: staging
patches:
- deployment-patch1.yaml
- deployment-patch2.yaml
- patches/deployment-patch*.yaml
bases:
- ../package/
configMapGenerator:

View File

@@ -1,5 +1,5 @@
description: simple
args: []
filename: ../examples/simple/instances/exampleinstance/
filename: ../examplelayout/simple/instances/exampleinstance/
expectedStdout: testdata/testcase-simple/expected.yaml
expectedDiff: testdata/testcase-simple/expected.diff

View File

@@ -41,6 +41,31 @@ diff -u -N /tmp/noop/apps_v1beta1_StatefulSet_cockroachdb.yaml /tmp/transformed/
terminationGracePeriodSeconds: 60
volumes:
- name: datadir
diff -u -N /tmp/noop/batch_v1beta1_CronJob_cronjob-example.yaml /tmp/transformed/batch_v1beta1_CronJob_cronjob-example.yaml
--- /tmp/noop/batch_v1beta1_CronJob_cronjob-example.yaml YYYY-MM-DD HH:MM:SS
+++ /tmp/transformed/batch_v1beta1_CronJob_cronjob-example.yaml YYYY-MM-DD HH:MM:SS
@@ -1,7 +1,7 @@
apiVersion: batch/v1beta1
kind: CronJob
metadata:
- name: base-cronjob-example
+ name: dev-base-cronjob-example
spec:
concurrencyPolicy: Forbid
jobTemplate:
@@ -11,10 +11,10 @@
containers:
- command:
- echo
- - base-cockroachdb
+ - dev-base-cockroachdb
env:
- name: CDB_PUBLIC_SVC
- value: base-cockroachdb-public
+ value: dev-base-cockroachdb-public
image: cockroachdb/cockroach:v1.1.5
name: cronjob-example
schedule: '*/1 * * * *'
diff -u -N /tmp/noop/policy_v1beta1_PodDisruptionBudget_cockroachdb-budget.yaml /tmp/transformed/policy_v1beta1_PodDisruptionBudget_cockroachdb-budget.yaml
--- /tmp/noop/policy_v1beta1_PodDisruptionBudget_cockroachdb-budget.yaml YYYY-MM-DD HH:MM:SS
+++ /tmp/transformed/policy_v1beta1_PodDisruptionBudget_cockroachdb-budget.yaml YYYY-MM-DD HH:MM:SS

View File

@@ -1,4 +1,72 @@
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app: cockroachdb
name: dev-base-cockroachdb
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
labels:
app: cockroachdb
name: dev-base-cockroachdb
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- create
- get
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
labels:
app: cockroachdb
name: dev-base-cockroachdb
rules:
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests
verbs:
- create
- get
- watch
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
labels:
app: cockroachdb
name: dev-base-cockroachdb
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: dev-base-cockroachdb
subjects:
- kind: ServiceAccount
name: dev-base-cockroachdb
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
labels:
app: cockroachdb
name: dev-base-cockroachdb
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: dev-base-cockroachdb
subjects:
- kind: ServiceAccount
name: dev-base-cockroachdb
namespace: default
---
apiVersion: v1
kind: Service
metadata:
annotations:
@@ -38,13 +106,6 @@ spec:
selector:
app: cockroachdb
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app: cockroachdb
name: dev-base-cockroachdb
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
@@ -131,6 +192,27 @@ spec:
requests:
storage: 1Gi
---
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: dev-base-cronjob-example
spec:
concurrencyPolicy: Forbid
jobTemplate:
spec:
template:
spec:
containers:
- command:
- echo
- dev-base-cockroachdb
env:
- name: CDB_PUBLIC_SVC
value: dev-base-cockroachdb-public
image: cockroachdb/cockroach:v1.1.5
name: cronjob-example
schedule: '*/1 * * * *'
---
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
@@ -142,64 +224,3 @@ spec:
selector:
matchLabels:
app: cockroachdb
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
labels:
app: cockroachdb
name: dev-base-cockroachdb
rules:
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests
verbs:
- create
- get
- watch
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
labels:
app: cockroachdb
name: dev-base-cockroachdb
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: dev-base-cockroachdb
subjects:
- kind: ServiceAccount
name: dev-base-cockroachdb
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
labels:
app: cockroachdb
name: dev-base-cockroachdb
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- create
- get
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
labels:
app: cockroachdb
name: dev-base-cockroachdb
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: dev-base-cockroachdb
subjects:
- kind: ServiceAccount
name: dev-base-cockroachdb
namespace: default

View File

@@ -0,0 +1,20 @@
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: cronjob-example
spec:
schedule: "*/1 * * * *"
concurrencyPolicy: Forbid
jobTemplate:
spec:
template:
spec:
containers:
- name: cronjob-example
image: cockroachdb/cockroach:v1.1.5
command:
- echo
- "$(CDB_STATEFULSET_NAME)"
env:
- name: CDB_PUBLIC_SVC
value: "$(CDB_PUBLIC_SVC)"

View File

@@ -1,6 +1,7 @@
namePrefix: base-
resources:
- cockroachdb-statefulset-secure.yaml
- cronjob.yaml
vars:
- name: CDB_PUBLIC_SVC
objref:

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package version
package commands
import (
"fmt"
@@ -32,8 +32,8 @@ var (
buildDate = "1970-01-01T00:00:00Z" // build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ')
)
// Version represens kustomize version.
type Version struct {
// version returns the version of kustomize.
type version struct {
// KustomizeVersion is a kustomize binary version.
KustomizeVersion string `json:"kustomizeVersion"`
// GitCommit is a git commit
@@ -46,9 +46,9 @@ type Version struct {
GoArch string `json:"goArch"`
}
// GetVersion returns version.
func GetVersion() Version {
return Version{
// getVersion returns version.
func getVersion() version {
return version{
kustomizeVersion,
gitCommit,
buildDate,
@@ -58,18 +58,18 @@ func GetVersion() Version {
}
// Print prints version.
func (v Version) Print(w io.Writer) {
func (v version) Print(w io.Writer) {
fmt.Fprintf(w, "Version: %+v\n", v)
}
// NewCmdVersion makes version command.
func NewCmdVersion(w io.Writer) *cobra.Command {
func newCmdVersion(w io.Writer) *cobra.Command {
return &cobra.Command{
Use: "version",
Short: "Prints the kustomize version",
Example: `kustomize version`,
Run: func(cmd *cobra.Command, args []string) {
GetVersion().Print(w)
getVersion().Print(w)
},
}
}

View File

@@ -141,7 +141,7 @@ func TestConstructConfigMap(t *testing.T) {
input: types.ConfigMapArgs{
Name: "envConfigMap",
DataSources: types.DataSources{
EnvSource: "../examples/simple/instances/exampleinstance/configmap/app.env",
EnvSource: "../examplelayout/simple/instances/exampleinstance/configmap/app.env",
},
},
expected: makeEnvConfigMap("envConfigMap"),
@@ -151,7 +151,7 @@ func TestConstructConfigMap(t *testing.T) {
input: types.ConfigMapArgs{
Name: "fileConfigMap",
DataSources: types.DataSources{
FileSources: []string{"../examples/simple/instances/exampleinstance/configmap/app-init.ini"},
FileSources: []string{"../examplelayout/simple/instances/exampleinstance/configmap/app-init.ini"},
},
},
expected: makeFileConfigMap("fileConfigMap"),
@@ -234,10 +234,10 @@ func TestObjectConvertToUnstructured(t *testing.T) {
for _, tc := range testCases {
actual, err := objectToUnstructured(tc.input)
if err != nil {
t.Fatalf("unexpected error: %v", err)
t.Fatalf("%s: unexpected error: %v", tc.description, err)
}
if !reflect.DeepEqual(actual, tc.expected) {
t.Fatalf("%#v\ndoesn't match expected\n%#v\n", actual, tc.expected)
t.Fatalf("%s: %#v\ndoesn't match expected\n%#v\n", tc.description, actual, tc.expected)
}
}
}

View File

@@ -66,7 +66,7 @@ func processEnvFileLine(line []byte, filePath string,
// from the environment.
value = os.Getenv(key)
}
return
return key, value, err
}
// addFromEnvFile processes an env file allows a generic addTo to handle the

View File

@@ -18,7 +18,7 @@ limitations under the License.
package util
import (
"crypto/md5"
"crypto/sha256"
"errors"
"fmt"
"path"
@@ -30,7 +30,7 @@ import (
)
// ParseRFC3339 parses an RFC3339 date in either RFC3339Nano or RFC3339 format.
func ParseRFC3339(s string, nowFn func() metav1.Time) (metav1.Time, error) {
func ParseRFC3339(s string) (metav1.Time, error) {
if t, timeErr := time.Parse(time.RFC3339Nano, s); timeErr == nil {
return metav1.Time{Time: t}, nil
}
@@ -42,12 +42,12 @@ func ParseRFC3339(s string, nowFn func() metav1.Time) (metav1.Time, error) {
}
// HashObject encodes object using given codec and returns MD5 sum of the result.
func HashObject(obj runtime.Object, codec runtime.Codec) (string, error) {
func HashObject(obj runtime.Object, codec runtime.Encoder) (string, error) {
data, err := runtime.Encode(codec, obj)
if err != nil {
return "", err
}
return fmt.Sprintf("%x", md5.Sum(data)), nil
return fmt.Sprintf("%x", sha256.Sum256(data)), nil
}
// ParseFileSource parses the source given.

42
pkg/crds/constants.go Normal file
View File

@@ -0,0 +1,42 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package crds
// Annotation is to mark a field as annotations.
// "x-kubernetes-annotation": ""
const Annotation = "x-kubernetes-annotation"
// LabelSelector is to mark a field as LabelSelector
// "x-kubernetes-label-selector": ""
const LabelSelector = "x-kubernetes-label-selector"
// Identity is to mark a field as Identity
// "x-kubernetes-identity": ""
const Identity = "x-kubernetes-identity"
// Version marks the type version of an object ref field
// "x-kubernetes-object-ref-api-version": <apiVersion name>
const Version = "x-kubernetes-object-ref-api-version"
// Kind marks the type name of an object ref field
// "x-kubernetes-object-ref-kind": <kind name>
const Kind = "x-kubernetes-object-ref-kind"
// NameKey marks the field key that refers to an object of an object ref field
// "x-kubernetes-object-ref-name-key": "name"
// default is "name"
const NameKey = "x-kubernetes-object-ref-name-key"

209
pkg/crds/crds.go Normal file
View File

@@ -0,0 +1,209 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package crds read in files for CRD schemas and parse annotations from it
package crds
import (
"encoding/json"
"reflect"
"strings"
"github.com/ghodss/yaml"
"github.com/kubernetes-sigs/kustomize/pkg/loader"
"github.com/kubernetes-sigs/kustomize/pkg/transformers"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kube-openapi/pkg/common"
)
type pathConfigs struct {
labelPathConfig transformers.PathConfig
annotationPathConfig transformers.PathConfig
prefixPathConfig transformers.PathConfig
namereferencePathConfigs []transformers.ReferencePathConfig
}
func (p *pathConfigs) addLabelPathConfig(config transformers.PathConfig) {
if *(p.labelPathConfig.GroupVersionKind) == *config.GroupVersionKind {
p.labelPathConfig.Path = append(p.labelPathConfig.Path, config.Path...)
} else {
p.labelPathConfig = config
}
}
func (p *pathConfigs) addAnnotationPathConfig(config transformers.PathConfig) {
if *(p.annotationPathConfig.GroupVersionKind) == *config.GroupVersionKind {
p.annotationPathConfig.Path = append(p.labelPathConfig.Path, config.Path...)
} else {
p.annotationPathConfig = config
}
}
func (p *pathConfigs) addNamereferencePathConfig(config transformers.ReferencePathConfig) {
p.namereferencePathConfigs = transformers.MergeNameReferencePathConfigs(p.namereferencePathConfigs, config)
}
func (p *pathConfigs) addPrefixPathConfig(config transformers.PathConfig) {
if *(p.prefixPathConfig.GroupVersionKind) == *config.GroupVersionKind {
p.prefixPathConfig.Path = append(p.prefixPathConfig.Path, config.Path...)
} else {
p.prefixPathConfig = config
}
}
// RegisterCRDs parse CRD schemas from paths and update various pathConfigs
func RegisterCRDs(loader loader.Loader, paths []string) error {
pathConfigs := []pathConfigs{}
for _, path := range paths {
pathConfig, err := registerCRD(loader, path)
if err != nil {
return err
}
pathConfigs = append(pathConfigs, pathConfig...)
}
addPathConfigs(pathConfigs)
return nil
}
// register CRD from one path
func registerCRD(loader loader.Loader, path string) ([]pathConfigs, error) {
result := []pathConfigs{}
content, err := loader.Load(path)
if err != nil {
return result, err
}
var types map[string]common.OpenAPIDefinition
if content[0] == '{' {
err = json.Unmarshal(content, &types)
if err != nil {
return nil, err
}
} else {
err = yaml.Unmarshal(content, &types)
if err != nil {
return nil, err
}
}
crds := getCRDs(types)
for crd, gvk := range crds {
crdPathConfigs := pathConfigs{}
err = getCRDPathConfig(types, crd, crd, gvk, []string{}, &crdPathConfigs)
if err != nil {
return result, err
}
if !reflect.DeepEqual(crdPathConfigs, pathConfigs{}) {
result = append(result, crdPathConfigs)
}
}
return result, nil
}
// getCRDs get all CRD types
func getCRDs(types map[string]common.OpenAPIDefinition) map[string]schema.GroupVersionKind {
crds := map[string]schema.GroupVersionKind{}
for typename, t := range types {
properties := t.Schema.SchemaProps.Properties
_, foundKind := properties["kind"]
_, foundAPIVersion := properties["apiVersion"]
_, foundMetadata := properties["metadata"]
if foundKind && foundAPIVersion && foundMetadata {
// TODO: Get Group and Version for CRD from the openAPI definition once
// "x-kubernetes-group-version-kind" is available in CRD
kind := strings.Split(typename, ".")[len(strings.Split(typename, "."))-1]
crds[typename] = schema.GroupVersionKind{Kind: kind}
}
}
return crds
}
// getCRDPathConfig gets pathConfigs for one CRD recursively
func getCRDPathConfig(types map[string]common.OpenAPIDefinition, atype string, crd string, gvk schema.GroupVersionKind,
path []string, configs *pathConfigs) error {
if _, ok := types[crd]; !ok {
return nil
}
for propname, property := range types[atype].Schema.SchemaProps.Properties {
_, annotate := property.Extensions.GetString(Annotation)
if annotate {
configs.addAnnotationPathConfig(
transformers.PathConfig{
CreateIfNotPresent: false,
GroupVersionKind: &gvk,
Path: append(path, propname),
},
)
}
_, label := property.Extensions.GetString(LabelSelector)
if label {
configs.addLabelPathConfig(
transformers.PathConfig{
CreateIfNotPresent: false,
GroupVersionKind: &gvk,
Path: append(path, propname),
},
)
}
_, identity := property.Extensions.GetString(Identity)
if identity {
configs.addPrefixPathConfig(
transformers.PathConfig{
CreateIfNotPresent: false,
GroupVersionKind: &gvk,
Path: append(path, propname),
},
)
}
version, ok := property.Extensions.GetString(Version)
if ok {
kind, ok := property.Extensions.GetString(Kind)
if ok {
nameKey, ok := property.Extensions.GetString(NameKey)
if !ok {
nameKey = "name"
}
configs.addNamereferencePathConfig(transformers.NewReferencePathConfig(
schema.GroupVersionKind{Kind: kind, Version: version},
[]transformers.PathConfig{
{CreateIfNotPresent: false,
GroupVersionKind: &gvk,
Path: append(path, propname, nameKey),
}}))
}
}
if property.Ref.GetURL() != nil {
getCRDPathConfig(types, property.Ref.String(), crd, gvk, append(path, propname), configs)
}
}
return nil
}
// addPathConfigs add extra path configs to the default ones
func addPathConfigs(p []pathConfigs) {
for _, pc := range p {
transformers.AddLabelsPathConfigs(pc.labelPathConfig)
transformers.AddAnnotationsPathConfigs(pc.annotationPathConfig)
transformers.AddNameReferencePathConfigs(pc.namereferencePathConfigs)
transformers.AddPrefixPathConfigs(pc.prefixPathConfig)
}
}

198
pkg/crds/crds_test.go Normal file
View File

@@ -0,0 +1,198 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package crds
import (
"reflect"
"sort"
"testing"
"github.com/kubernetes-sigs/kustomize/pkg/internal/loadertest"
"github.com/kubernetes-sigs/kustomize/pkg/loader"
"github.com/kubernetes-sigs/kustomize/pkg/transformers"
"k8s.io/apimachinery/pkg/runtime/schema"
)
const (
crdContent = `
{
"github.com/example/pkg/apis/jingfang/v1beta1.Bee": {
"Schema": {
"description": "Bee",
"properties": {
"apiVersion": {
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert
recognized schemas to the latest internal value, and may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources",
"type": "string"
},
"kind": {
"description": "Kind is a string value representing the REST resource this object represents. Servers may infer
this from the endpoint the client submits requests to. Cannot be updated. In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds",
"type": "string"
},
"metadata": {
"$ref": "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"
},
"spec": {
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.BeeSpec"
},
"status": {
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.BeeStatus"
}
}
},
"Dependencies": [
"github.com/example/pkg/apis/jingfang/v1beta1.BeeSpec",
"github.com/example/pkg/apis/jingfang/v1beta1.BeeStatus",
"k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"
]
},
"github.com/example/pkg/apis/jingfang/v1beta1.BeeSpec": {
"Schema": {
"description": "BeeSpec defines the desired state of Bee"
},
"Dependencies": []
},
"github.com/example/pkg/apis/jingfang/v1beta1.BeeStatus": {
"Schema": {
"description": "BeeStatus defines the observed state of Bee"
},
"Dependencies": []
},
"github.com/example/pkg/apis/jingfang/v1beta1.MyKind": {
"Schema": {
"description": "MyKind",
"properties": {
"apiVersion": {
"description": "APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources",
"type": "string"
},
"kind": {
"description": "Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to. Cannot be updated.
In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds",
"type": "string"
},
"metadata": {
"$ref": "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"
},
"spec": {
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.MyKindSpec"
},
"status": {
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.MyKindStatus"
}
}
},
"Dependencies": [
"github.com/example/pkg/apis/jingfang/v1beta1.MyKindSpec",
"github.com/example/pkg/apis/jingfang/v1beta1.MyKindStatus",
"k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"
]
},
"github.com/example/pkg/apis/jingfang/v1beta1.MyKindSpec": {
"Schema": {
"description": "MyKindSpec defines the desired state of MyKind",
"properties": {
"beeRef": {
"x-kubernetes-object-ref-api-version": "v1beta1",
"x-kubernetes-object-ref-kind": "Bee",
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.Bee"
},
"secretRef": {
"description": "If defined, we use this secret for configuring the MYSQL_ROOT_PASSWORD
If it is not set we generate a secret dynamically",
"x-kubernetes-object-ref-api-version": "v1",
"x-kubernetes-object-ref-kind": "Secret",
"$ref": "k8s.io/api/core/v1.LocalObjectReference"
}
}
},
"Dependencies": [
"github.com/example/pkg/apis/jingfang/v1beta1.Bee",
"k8s.io/api/core/v1.LocalObjectReference"
]
},
"github.com/example/pkg/apis/jingfang/v1beta1.MyKindStatus": {
"Schema": {
"description": "MyKindStatus defines the observed state of MyKind"
},
"Dependencies": []
}
}
`
)
func makeLoader(t *testing.T) loader.Loader {
loader := loadertest.NewFakeLoader("/testpath")
err := loader.AddFile("/testpath/crd.json", []byte(crdContent))
if err != nil {
t.Fatalf("Failed to setup fake loader.")
}
return loader
}
func TestRegisterCRD(t *testing.T) {
refpathconfigs := []transformers.ReferencePathConfig{
transformers.NewReferencePathConfig(
schema.GroupVersionKind{Kind: "Bee", Version: "v1beta1"},
[]transformers.PathConfig{
{
CreateIfNotPresent: false,
GroupVersionKind: &schema.GroupVersionKind{Kind: "MyKind"},
Path: []string{"spec", "beeRef", "name"},
},
},
),
transformers.NewReferencePathConfig(
schema.GroupVersionKind{Kind: "Secret", Version: "v1"},
[]transformers.PathConfig{
{
CreateIfNotPresent: false,
GroupVersionKind: &schema.GroupVersionKind{Kind: "MyKind"},
Path: []string{"spec", "secretRef", "name"},
},
},
),
}
sort.Slice(refpathconfigs, func(i, j int) bool {
return refpathconfigs[i].GVK() < refpathconfigs[j].GVK()
})
expected := []pathConfigs{
{
namereferencePathConfigs: refpathconfigs,
},
}
loader := makeLoader(t)
pathconfig, _ := registerCRD(loader, "/testpath/crd.json")
sort.Slice(pathconfig[0].namereferencePathConfigs, func(i, j int) bool {
return pathconfig[0].namereferencePathConfigs[i].GVK() < pathconfig[0].namereferencePathConfigs[j].GVK()
})
if !reflect.DeepEqual(pathconfig, expected) {
t.Fatalf("expected\n %v\n but got\n %v\n", expected, pathconfig)
}
}

View File

@@ -20,7 +20,7 @@ import (
"io"
"os"
"k8s.io/utils/exec"
"github.com/kubernetes-sigs/kustomize/pkg/exec"
)
// program wraps the system diff program.
@@ -39,11 +39,10 @@ func newProgram(out, errOut io.Writer) *program {
}
func (d *program) makeCommand(args ...string) exec.Cmd {
diff := ""
diff := "diff"
if envDiff := os.Getenv("KUBERNETES_EXTERNAL_DIFF"); envDiff != "" {
diff = envDiff
} else {
diff = "diff"
args = append([]string{"-u", "-N"}, args...)
}
cmd := exec.New().Command(diff, args...)

View File

@@ -26,18 +26,22 @@ import (
)
// RunDiff runs system diff program to compare two Maps.
func RunDiff(raw, transformed resmap.ResMap, out, errOut io.Writer) error {
func RunDiff(raw, transformed resmap.ResMap, out, errOut io.Writer) (err error) {
transformedDir, err := writeYamlToNewDir(transformed, "transformed")
if err != nil {
return err
}
defer transformedDir.delete()
defer func() {
err = transformedDir.delete()
}()
noopDir, err := writeYamlToNewDir(raw, "noop")
if err != nil {
return err
}
defer noopDir.delete()
defer func() {
err = noopDir.delete()
}()
return newProgram(out, errOut).run(noopDir.name(), transformedDir.name())
}

View File

@@ -15,4 +15,7 @@ limitations under the License.
*/
// Package exec provides an injectable interface and implementations for running commands.
package exec // import "k8s.io/utils/exec"
// TODO: delete this package, use k8s.io/utils/exec instead.
// That package was copied here as a temporary workaround to make progress on b/80488884
// (avoid the need to import exec first).
package exec

View File

@@ -206,10 +206,12 @@ func (e CodeExitError) String() string {
return e.Err.Error()
}
// Exited returns true.
func (e CodeExitError) Exited() bool {
return true
}
// ExitStatus delegates to Code.
func (e CodeExitError) ExitStatus() int {
return e.Code
}

View File

@@ -54,7 +54,7 @@ func TestExecutorNoArgs(t *testing.T) {
}
cmd = ex.Command("/does/not/exist")
out, err = cmd.CombinedOutput()
_, err = cmd.CombinedOutput()
if err == nil {
t.Errorf("expected failure, got nil error")
}

View File

@@ -20,7 +20,7 @@ import (
"bytes"
"fmt"
"k8s.io/utils/exec"
"github.com/kubernetes-sigs/kustomize/pkg/exec"
)
func ExampleNew() {

View File

@@ -31,11 +31,6 @@ type FakeFile struct {
open bool
}
// makeFile makes a fake file.
func makeFile() *FakeFile {
return &FakeFile{}
}
// makeDir makes a fake directory.
func makeDir(name string) *FakeFile {
return &FakeFile{name: name, dir: true}

View File

@@ -71,6 +71,18 @@ func (fs *FakeFS) ReadFile(name string) ([]byte, error) {
return nil, fmt.Errorf("cannot read file %q", name)
}
// ReadFiles looks through all files in the fake filesystem
// and find the matching files and then read content from all of them
func (fs *FakeFS) ReadFiles(name string) (map[string][]byte, error) {
result := map[string][]byte{}
for p, f := range fs.m {
if fs.pathMatch(p, name) {
result[p] = f.content
}
}
return result, nil
}
// WriteFile always succeeds and does nothing.
func (fs *FakeFS) WriteFile(name string, c []byte) error {
ff := &FakeFile{}
@@ -78,3 +90,10 @@ func (fs *FakeFS) WriteFile(name string, c []byte) error {
fs.m[name] = ff
return nil
}
func (fs *FakeFS) pathMatch(path, pattern string) bool {
if path == pattern {
return true
}
return false
}

View File

@@ -29,6 +29,7 @@ type FileSystem interface {
Open(name string) (File, error)
Stat(name string) (os.FileInfo, error)
ReadFile(name string) ([]byte, error)
ReadFiles(name string) (map[string][]byte, error)
WriteFile(name string, data []byte) error
}

View File

@@ -19,6 +19,7 @@ package fs
import (
"io/ioutil"
"os"
"path/filepath"
)
var _ FileSystem = realFS{}
@@ -46,6 +47,26 @@ func (realFS) Stat(name string) (os.FileInfo, error) { return os.Stat(name) }
// ReadFile delegates to ioutil.ReadFile.
func (realFS) ReadFile(name string) ([]byte, error) { return ioutil.ReadFile(name) }
// ReadFiles use glob to find the matching files and then read content from all of them
func (realFS) ReadFiles(name string) (map[string][]byte, error) {
files, err := filepath.Glob(name)
if err != nil || len(files) == 0 {
return nil, err
}
output := map[string][]byte{}
for _, file := range files {
bytes, err := ioutil.ReadFile(file)
if err != nil {
return nil, err
}
if bytes != nil {
output[file] = bytes
}
}
return output, nil
}
// WriteFile delegates to ioutil.WriteFile with read/write permissions.
func (realFS) WriteFile(name string, c []byte) error {
return ioutil.WriteFile(name, c, 0666)

58
pkg/fs/realfs_test.go Normal file
View File

@@ -0,0 +1,58 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fs
import (
"os"
"path"
"reflect"
"testing"
)
func TestReadFilesRealFS(t *testing.T) {
x := MakeRealFS()
testDir := "kustomize_testing_dir"
err := x.Mkdir(testDir, 0777)
defer os.RemoveAll(testDir)
if err != nil {
t.Fatalf("unexpected error %s", err)
}
err = x.WriteFile(path.Join(testDir, "foo"), []byte(`foo`))
if err != nil {
t.Fatalf("unexpected error %s", err)
}
err = x.WriteFile(path.Join(testDir, "bar"), []byte(`bar`))
if err != nil {
t.Fatalf("unexpected error %s", err)
}
expected := map[string][]byte{
path.Join(testDir, "foo"): []byte(`foo`),
path.Join(testDir, "bar"): []byte(`bar`),
}
content, err := x.ReadFiles("kustomize_testing_dir/*")
if !reflect.DeepEqual(content, expected) {
t.Fatalf("actual: %+v doesn't match expected: %+v", content, expected)
}
if err != nil {
t.Fatalf("unexpected error %s", err)
}
}

View File

@@ -96,15 +96,19 @@ func TestEncodeConfigMap(t *testing.T) {
// one key
{"one key", &v1.ConfigMap{Data: map[string]string{"one": ""}}, `{"data":{"one":""},"kind":"ConfigMap","name":""}`, ""},
// three keys (tests sorting order)
{"three keys", &v1.ConfigMap{Data: map[string]string{"two": "2", "one": "", "three": "3"}}, `{"data":{"one":"","three":"3","two":"2"},"kind":"ConfigMap","name":""}`, ""},
{"three keys", &v1.ConfigMap{Data: map[string]string{"two": "2", "one": "", "three": "3"}},
`{"data":{"one":"","three":"3","two":"2"},"kind":"ConfigMap","name":""}`, ""},
// empty binary map
{"empty data", &v1.ConfigMap{BinaryData: map[string][]byte{}}, `{"data":null,"kind":"ConfigMap","name":""}`, ""},
// one key with binary data
{"one key", &v1.ConfigMap{BinaryData: map[string][]byte{"one": []byte("")}}, `{"binaryData":{"one":""},"data":null,"kind":"ConfigMap","name":""}`, ""},
{"one key", &v1.ConfigMap{BinaryData: map[string][]byte{"one": []byte("")}},
`{"binaryData":{"one":""},"data":null,"kind":"ConfigMap","name":""}`, ""},
// three keys with binary data (tests sorting order)
{"three keys", &v1.ConfigMap{BinaryData: map[string][]byte{"two": []byte("2"), "one": []byte(""), "three": []byte("3")}}, `{"binaryData":{"one":"","three":"Mw==","two":"Mg=="},"data":null,"kind":"ConfigMap","name":""}`, ""},
{"three keys", &v1.ConfigMap{BinaryData: map[string][]byte{"two": []byte("2"), "one": []byte(""), "three": []byte("3")}},
`{"binaryData":{"one":"","three":"Mw==","two":"Mg=="},"data":null,"kind":"ConfigMap","name":""}`, ""},
// two keys, one string and one binary values
{"two keys with one each", &v1.ConfigMap{Data: map[string]string{"one": ""}, BinaryData: map[string][]byte{"two": []byte("")}}, `{"binaryData":{"two":""},"data":{"one":""},"kind":"ConfigMap","name":""}`, ""},
{"two keys with one each", &v1.ConfigMap{Data: map[string]string{"one": ""}, BinaryData: map[string][]byte{"two": []byte("")}},
`{"binaryData":{"two":""},"data":{"one":""},"kind":"ConfigMap","name":""}`, ""},
}
for _, c := range cases {
s, err := encodeConfigMap(c.cm)
@@ -129,7 +133,11 @@ func TestEncodeSecret(t *testing.T) {
// one key
{"one key", &v1.Secret{Type: "my-type", Data: map[string][]byte{"one": []byte("")}}, `{"data":{"one":""},"kind":"Secret","name":"","type":"my-type"}`, ""},
// three keys (tests sorting order) - note json.Marshal base64 encodes the values because they come in as []byte
{"three keys", &v1.Secret{Type: "my-type", Data: map[string][]byte{"two": []byte("2"), "one": []byte(""), "three": []byte("3")}}, `{"data":{"one":"","three":"Mw==","two":"Mg=="},"kind":"Secret","name":"","type":"my-type"}`, ""},
{"three keys", &v1.Secret{
Type: "my-type",
Data: map[string][]byte{"two": []byte("2"), "one": []byte(""), "three": []byte("3")},
},
`{"data":{"one":"","three":"Mw==","two":"Mg=="},"kind":"Secret","name":"","type":"my-type"}`, ""},
}
for _, c := range cases {
s, err := encodeSecret(c.secret)

View File

@@ -0,0 +1,45 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package error has contextual error types.
package error
import (
"fmt"
yaml "k8s.io/apimachinery/pkg/util/yaml"
)
// YamlFormatError represents error with yaml file name where json/yaml format error happens.
type YamlFormatError struct {
Path string
ErrorMsg string
}
func (e YamlFormatError) Error() string {
return fmt.Sprintf("YAML file [%s] encounters a format error.\n%s\n", e.Path, e.ErrorMsg)
}
// ErrorHandler handles YamlFormatError
func ErrorHandler(e error, path string) error {
if err, ok := e.(yaml.YAMLSyntaxError); ok {
return YamlFormatError{
Path: path,
ErrorMsg: err.Error(),
}
}
return e
}

View File

@@ -0,0 +1,67 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package error
import (
"bytes"
"fmt"
"testing"
"github.com/kubernetes-sigs/kustomize/pkg/constants"
yaml "k8s.io/apimachinery/pkg/util/yaml"
)
var (
filepath = "/path/to/" + constants.KustomizationFileName
expected = "YAML file [/path/to/kustomization.yaml] encounters a format error.\n" +
"error converting YAML to JSON: yaml: line 2: found character that cannot start any token\n"
doc = `
foo:
- fiz
- fu
`
)
func TestYamlFormatError_Error(t *testing.T) {
testErr := YamlFormatError{
Path: filepath,
ErrorMsg: "error converting YAML to JSON: yaml: line 2: found character that cannot start any token",
}
if testErr.Error() != expected {
t.Errorf("Expected : %s\n, but found : %s\n", expected, testErr.Error())
}
}
func TestErrorHandler(t *testing.T) {
f := foo{}
err := yaml.NewYAMLToJSONDecoder(bytes.NewReader([]byte(doc))).Decode(&f)
testErr := ErrorHandler(err, filepath)
expectedErr := fmt.Errorf("Format error message")
fmtErr := ErrorHandler(expectedErr, filepath)
if fmtErr.Error() != expectedErr.Error() {
t.Errorf("Expected returning fmt.Error, but found %T", fmtErr)
}
if _, ok := testErr.(YamlFormatError); !ok {
t.Errorf("Expected returning YamlFormatError, but found %T", testErr)
}
if testErr == nil || testErr.Error() != expected {
t.Errorf("Expected : %s\n, but found : %s\n", expected, testErr.Error())
}
}
//type foo struct
type foo struct{}

View File

@@ -67,3 +67,8 @@ func (f FakeLoader) New(newRoot string) (loader.Loader, error) {
func (f FakeLoader) Load(location string) ([]byte, error) {
return f.delegate.Load(location)
}
// GlobLoad performs load from a given location.
func (f FakeLoader) GlobLoad(location string) (map[string][]byte, error) {
return f.delegate.GlobLoad(location)
}

View File

@@ -79,3 +79,13 @@ func (l *fileLoader) Load(fullFilePath string) ([]byte, error) {
}
return l.fs.ReadFile(fullFilePath)
}
// GlobLoad returns the map from path to bytes from reading a glob path.
// Implements the Loader interface.
func (l *fileLoader) GlobLoad(fullFilePath string) (map[string][]byte, error) {
// Validate path to load from is a full file path.
if !filepath.IsAbs(fullFilePath) {
return nil, fmt.Errorf("Attempting to load file without full file path: %s\n", fullFilePath)
}
return l.fs.ReadFiles(fullFilePath)
}

View File

@@ -28,6 +28,8 @@ type Loader interface {
New(newRoot string) (Loader, error)
// Load returns the bytes read from the location or an error.
Load(location string) ([]byte, error)
// GlobLoad returns the bytes read from a glob path or an error.
GlobLoad(location string) (map[string][]byte, error)
}
// Private implmentation of Loader interface.
@@ -44,6 +46,8 @@ type SchemeLoader interface {
FullLocation(root string, path string) (string, error)
// Load bytes at scheme-specific location or an error.
Load(location string) ([]byte, error)
// GlobLoad returns the bytes read from a glob path or an error.
GlobLoad(location string) (map[string][]byte, error)
}
const emptyRoot = ""
@@ -91,6 +95,21 @@ func (l *loaderImpl) Load(location string) ([]byte, error) {
return scheme.Load(fullLocation)
}
// GlobLoad returns a map from path to bytes read from scheme-specific location or an error.
// "location" can be an absolute path, or if relative, full location is
// calculated from the Root().
func (l *loaderImpl) GlobLoad(location string) (map[string][]byte, error) {
scheme, err := l.getSchemeLoader(location)
if err != nil {
return nil, err
}
fullLocation, err := scheme.FullLocation(l.root, location)
if err != nil {
return nil, err
}
return scheme.GlobLoad(fullLocation)
}
// Helper function to parse scheme from location parameter.
func (l *loaderImpl) getSchemeLoader(location string) (SchemeLoader, error) {
for _, scheme := range l.schemes {

View File

@@ -20,6 +20,7 @@ import (
"sort"
"github.com/kubernetes-sigs/kustomize/pkg/resource"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// IdSlice implements the sort interface.
@@ -31,7 +32,32 @@ func (a IdSlice) Len() int { return len(a) }
func (a IdSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a IdSlice) Less(i, j int) bool {
if a[i].Gvk().String() != a[j].Gvk().String() {
return a[i].Gvk().String() < a[j].Gvk().String()
return gvkLess(a[i].Gvk(), a[j].Gvk())
}
return a[i].Name() < a[j].Name()
}
var order = []string{"Namespace", "CustomResourceDefinition", "ServiceAccount",
"Role", "ClusterRole", "RoleBinding", "ClusterRoleBinding"}
var typeOrders = func() map[string]int {
m := map[string]int{}
for i, n := range order {
m[n] = i
}
return m
}()
func gvkLess(i, j schema.GroupVersionKind) bool {
indexi, foundi := typeOrders[i.Kind]
indexj, foundj := typeOrders[j.Kind]
if foundi && foundj {
return indexi < indexj
}
if foundi && !foundj {
return true
}
if !foundi && foundj {
return false
}
return i.String() < j.String()
}

View File

@@ -0,0 +1,53 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package resmap
import (
"reflect"
"sort"
"testing"
"github.com/kubernetes-sigs/kustomize/pkg/resource"
"k8s.io/apimachinery/pkg/runtime/schema"
)
func TestLess(t *testing.T) {
ids := IdSlice{
resource.NewResId(schema.GroupVersionKind{Kind: "ConfigMap"}, "cm"),
resource.NewResId(schema.GroupVersionKind{Kind: "Pod"}, "pod"),
resource.NewResId(schema.GroupVersionKind{Kind: "Namespace"}, "ns1"),
resource.NewResId(schema.GroupVersionKind{Kind: "Namespace"}, "ns2"),
resource.NewResId(schema.GroupVersionKind{Kind: "Role"}, "ro"),
resource.NewResId(schema.GroupVersionKind{Kind: "RoleBinding"}, "rb"),
resource.NewResId(schema.GroupVersionKind{Kind: "CustomResourceDefinition"}, "crd"),
resource.NewResId(schema.GroupVersionKind{Kind: "ServiceAccount"}, "sa"),
}
expected := IdSlice{
resource.NewResId(schema.GroupVersionKind{Kind: "Namespace"}, "ns1"),
resource.NewResId(schema.GroupVersionKind{Kind: "Namespace"}, "ns2"),
resource.NewResId(schema.GroupVersionKind{Kind: "CustomResourceDefinition"}, "crd"),
resource.NewResId(schema.GroupVersionKind{Kind: "ServiceAccount"}, "sa"),
resource.NewResId(schema.GroupVersionKind{Kind: "Role"}, "ro"),
resource.NewResId(schema.GroupVersionKind{Kind: "RoleBinding"}, "rb"),
resource.NewResId(schema.GroupVersionKind{Kind: "ConfigMap"}, "cm"),
resource.NewResId(schema.GroupVersionKind{Kind: "Pod"}, "pod"),
}
sort.Sort(ids)
if !reflect.DeepEqual(ids, expected) {
t.Fatalf("expected %+v but got %+v", expected, ids)
}
}

View File

@@ -26,6 +26,7 @@ import (
"github.com/ghodss/yaml"
"github.com/golang/glog"
internal "github.com/kubernetes-sigs/kustomize/pkg/internal/error"
"github.com/kubernetes-sigs/kustomize/pkg/loader"
"github.com/kubernetes-sigs/kustomize/pkg/resource"
"github.com/pkg/errors"
@@ -112,16 +113,18 @@ func NewResourceSliceFromPatches(
loader loader.Loader, paths []string) ([]*resource.Resource, error) {
result := []*resource.Resource{}
for _, path := range paths {
content, err := loader.Load(path)
contents, err := loader.GlobLoad(path)
if err != nil {
return nil, err
}
for p, content := range contents {
res, err := newResourceSliceFromBytes(content)
if err != nil {
return nil, internal.ErrorHandler(err, p)
}
result = append(result, res...)
res, err := newResourceSliceFromBytes(content)
if err != nil {
return nil, err
}
result = append(result, res...)
}
return result, nil
}
@@ -130,15 +133,17 @@ func NewResourceSliceFromPatches(
func NewResMapFromFiles(loader loader.Loader, paths []string) (ResMap, error) {
result := []ResMap{}
for _, path := range paths {
content, err := loader.Load(path)
contents, err := loader.GlobLoad(path)
if err != nil {
return nil, errors.Wrap(err, "Load from path "+path+" failed")
}
res, err := newResMapFromBytes(content)
if err != nil {
return nil, err
for p, content := range contents {
res, err := newResMapFromBytes(content)
if err != nil {
return nil, internal.ErrorHandler(err, p)
}
result = append(result, res)
}
result = append(result, res)
}
return MergeWithoutOverride(result...)
}

View File

@@ -30,9 +30,10 @@ var secret = schema.GroupVersionKind{Version: "v1", Kind: "Secret"}
var cmap = schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}
var ns = schema.GroupVersionKind{Version: "v1", Kind: "Namespace"}
var deploy = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}
var statefulset = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "StatefulSet"}
var foo = schema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "Foo"}
var crd = schema.GroupVersionKind{Group: "apiwctensions.k8s.io", Version: "v1beta1", Kind: "CustomResourceDefinition"}
var job = schema.GroupVersionKind{Group: "batch", Version: "v1", Kind: "Job"}
var cronjob = schema.GroupVersionKind{Group: "batch", Version: "v1beta1", Kind: "CronJob"}
func TestLabelsRun(t *testing.T) {
m := resmap.ResMap{
@@ -86,6 +87,106 @@ func TestLabelsRun(t *testing.T) {
},
},
}),
resource.NewResId(job, "job1"): resource.NewResourceFromMap(
map[string]interface{}{
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": map[string]interface{}{
"name": "job1",
},
"spec": map[string]interface{}{
"template": map[string]interface{}{
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"name": "nginx",
"image": "nginx:1.7.9",
},
},
},
},
},
}),
resource.NewResId(job, "job2"): resource.NewResourceFromMap(
map[string]interface{}{
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": map[string]interface{}{
"name": "job2",
},
"spec": map[string]interface{}{
"selector": map[string]interface{}{
"matchLabels": map[string]interface{}{
"old-label": "old-value",
},
},
"template": map[string]interface{}{
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"name": "nginx",
"image": "nginx:1.7.9",
},
},
},
},
},
}),
resource.NewResId(cronjob, "cronjob1"): resource.NewResourceFromMap(
map[string]interface{}{
"apiVersion": "batch/v1beta1",
"kind": "CronJob",
"metadata": map[string]interface{}{
"name": "cronjob1",
},
"spec": map[string]interface{}{
"schedule": "* 23 * * *",
"jobTemplate": map[string]interface{}{
"spec": map[string]interface{}{
"template": map[string]interface{}{
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"name": "nginx",
"image": "nginx:1.7.9",
},
},
},
},
},
},
},
}),
resource.NewResId(cronjob, "cronjob2"): resource.NewResourceFromMap(
map[string]interface{}{
"apiVersion": "batch/v1beta1",
"kind": "CronJob",
"metadata": map[string]interface{}{
"name": "cronjob2",
},
"spec": map[string]interface{}{
"schedule": "* 23 * * *",
"jobTemplate": map[string]interface{}{
"spec": map[string]interface{}{
"selector": map[string]interface{}{
"matchLabels": map[string]interface{}{
"old-label": "old-value",
},
},
"template": map[string]interface{}{
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"name": "nginx",
"image": "nginx:1.7.9",
},
},
},
},
},
},
},
}),
}
expected := resmap.ResMap{
resource.NewResId(cmap, "cm1"): resource.NewResourceFromMap(
@@ -162,6 +263,150 @@ func TestLabelsRun(t *testing.T) {
},
},
}),
resource.NewResId(job, "job1"): resource.NewResourceFromMap(
map[string]interface{}{
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": map[string]interface{}{
"name": "job1",
"labels": map[string]interface{}{
"label-key1": "label-value1",
"label-key2": "label-value2",
},
},
"spec": map[string]interface{}{
"template": map[string]interface{}{
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"label-key1": "label-value1",
"label-key2": "label-value2",
},
},
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"name": "nginx",
"image": "nginx:1.7.9",
},
},
},
},
},
}),
resource.NewResId(job, "job2"): resource.NewResourceFromMap(
map[string]interface{}{
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": map[string]interface{}{
"name": "job2",
"labels": map[string]interface{}{
"label-key1": "label-value1",
"label-key2": "label-value2",
},
},
"spec": map[string]interface{}{
"selector": map[string]interface{}{
"matchLabels": map[string]interface{}{
"label-key1": "label-value1",
"label-key2": "label-value2",
"old-label": "old-value",
},
},
"template": map[string]interface{}{
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"label-key1": "label-value1",
"label-key2": "label-value2",
},
},
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"name": "nginx",
"image": "nginx:1.7.9",
},
},
},
},
},
}),
resource.NewResId(cronjob, "cronjob1"): resource.NewResourceFromMap(
map[string]interface{}{
"apiVersion": "batch/v1beta1",
"kind": "CronJob",
"metadata": map[string]interface{}{
"name": "cronjob1",
"labels": map[string]interface{}{
"label-key1": "label-value1",
"label-key2": "label-value2",
},
},
"spec": map[string]interface{}{
"schedule": "* 23 * * *",
"jobTemplate": map[string]interface{}{
"spec": map[string]interface{}{
"template": map[string]interface{}{
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"label-key1": "label-value1",
"label-key2": "label-value2",
},
},
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"name": "nginx",
"image": "nginx:1.7.9",
},
},
},
},
},
},
},
}),
resource.NewResId(cronjob, "cronjob2"): resource.NewResourceFromMap(
map[string]interface{}{
"apiVersion": "batch/v1beta1",
"kind": "CronJob",
"metadata": map[string]interface{}{
"name": "cronjob2",
"labels": map[string]interface{}{
"label-key1": "label-value1",
"label-key2": "label-value2",
},
},
"spec": map[string]interface{}{
"schedule": "* 23 * * *",
"jobTemplate": map[string]interface{}{
"spec": map[string]interface{}{
"selector": map[string]interface{}{
"matchLabels": map[string]interface{}{
"old-label": "old-value",
"label-key1": "label-value1",
"label-key2": "label-value2",
},
},
"template": map[string]interface{}{
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"label-key1": "label-value1",
"label-key2": "label-value2",
},
},
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"name": "nginx",
"image": "nginx:1.7.9",
},
},
},
},
},
},
},
}),
}
lt, err := NewDefaultingLabelsMapTransformer(map[string]string{"label-key1": "label-value1", "label-key2": "label-value2"})
@@ -312,3 +557,23 @@ func TestAnnotationsRun(t *testing.T) {
t.Fatalf("actual doesn't match expected: %v", err)
}
}
func TestAddPathConfigs(t *testing.T) {
aexpected := len(defaultAnnotationsPathConfigs) + 1
lexpected := len(defaultLabelsPathConfigs) + 1
pathConfigs := []PathConfig{
{
GroupVersionKind: &schema.GroupVersionKind{Group: "GroupA", Kind: "KindB"},
Path: []string{"path", "to", "a", "field"},
CreateIfNotPresent: true,
},
}
AddLabelsPathConfigs(pathConfigs...)
AddAnnotationsPathConfigs(pathConfigs[0])
if len(defaultAnnotationsPathConfigs) != aexpected {
t.Fatalf("actual %v doesn't match expected: %v", len(defaultAnnotationsPathConfigs), aexpected)
}
if len(defaultLabelsPathConfigs) != lexpected {
t.Fatalf("actual %v doesn't match expected: %v", len(defaultLabelsPathConfigs), lexpected)
}
}

View File

@@ -85,7 +85,7 @@ var defaultLabelsPathConfigs = []PathConfig{
{
GroupVersionKind: &schema.GroupVersionKind{Group: "batch", Kind: "Job"},
Path: []string{"spec", "selector", "matchLabels"},
CreateIfNotPresent: true,
CreateIfNotPresent: false,
},
{
GroupVersionKind: &schema.GroupVersionKind{Group: "batch", Kind: "Job"},
@@ -95,12 +95,7 @@ var defaultLabelsPathConfigs = []PathConfig{
{
GroupVersionKind: &schema.GroupVersionKind{Group: "batch", Kind: "CronJob"},
Path: []string{"spec", "jobTemplate", "spec", "selector", "matchLabels"},
CreateIfNotPresent: true,
},
{
GroupVersionKind: &schema.GroupVersionKind{Group: "batch", Kind: "CronJob"},
Path: []string{"spec", "jobTemplate", "spec", "metadata", "labels"},
CreateIfNotPresent: true,
CreateIfNotPresent: false,
},
{
GroupVersionKind: &schema.GroupVersionKind{Group: "batch", Kind: "CronJob"},
@@ -162,3 +157,13 @@ var defaultAnnotationsPathConfigs = []PathConfig{
CreateIfNotPresent: true,
},
}
// AddLabelsPathConfigs adds extra path configs to the default one
func AddLabelsPathConfigs(pathConfigs ...PathConfig) {
defaultLabelsPathConfigs = append(defaultLabelsPathConfigs, pathConfigs...)
}
// AddAnnotationsPathConfigs adds extra path configs to the default one
func AddAnnotationsPathConfigs(pathConfigs ...PathConfig) {
defaultAnnotationsPathConfigs = append(defaultAnnotationsPathConfigs, pathConfigs...)
}

View File

@@ -43,10 +43,16 @@ func (o *nameHashTransformer) Transform(m resmap.ResMap) error {
for id, res := range m {
switch {
case selectByGVK(id.Gvk(), &schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}):
appendHashForConfigMap(res)
err := appendHashForConfigMap(res)
if err != nil {
return err
}
case selectByGVK(id.Gvk(), &schema.GroupVersionKind{Version: "v1", Kind: "Secret"}):
appendHashForSecret(res)
err := appendHashForSecret(res)
if err != nil {
return err
}
}
}
return nil

View File

@@ -26,7 +26,7 @@ import (
// nameReferenceTransformer contains the referencing info between 2 GroupVersionKinds
type nameReferenceTransformer struct {
pathConfigs []referencePathConfig
pathConfigs []ReferencePathConfig
}
var _ Transformer = &nameReferenceTransformer{}
@@ -38,7 +38,7 @@ func NewDefaultingNameReferenceTransformer() (Transformer, error) {
}
// NewNameReferenceTransformer construct a nameReferenceTransformer.
func NewNameReferenceTransformer(pc []referencePathConfig) (Transformer, error) {
func NewNameReferenceTransformer(pc []ReferencePathConfig) (Transformer, error) {
if pc == nil {
return nil, errors.New("pathConfigs is not expected to be nil")
}

View File

@@ -22,6 +22,7 @@ import (
"github.com/kubernetes-sigs/kustomize/pkg/resmap"
"github.com/kubernetes-sigs/kustomize/pkg/resource"
"k8s.io/apimachinery/pkg/runtime/schema"
)
func TestNameReferenceRun(t *testing.T) {
@@ -93,6 +94,11 @@ func TestNameReferenceRun(t *testing.T) {
},
},
},
"imagePullSecrets": []interface{}{
map[string]interface{}{
"name": "secret1",
},
},
"volumes": map[string]interface{}{
"configMap": map[string]interface{}{
"name": "cm1",
@@ -175,6 +181,11 @@ func TestNameReferenceRun(t *testing.T) {
},
},
},
"imagePullSecrets": []interface{}{
map[string]interface{}{
"name": "someprefix-secret1-somehash",
},
},
"volumes": map[string]interface{}{
"configMap": map[string]interface{}{
"name": "someprefix-cm1-somehash",
@@ -190,6 +201,9 @@ func TestNameReferenceRun(t *testing.T) {
}
nrt, err := NewDefaultingNameReferenceTransformer()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
err = nrt.Transform(m)
if err != nil {
t.Fatalf("unexpected error: %v", err)
@@ -199,3 +213,29 @@ func TestNameReferenceRun(t *testing.T) {
t.Fatalf("actual doesn't match expected: %v", err)
}
}
func TestAddNameReferencePathConfigs(t *testing.T) {
expected := len(defaultNameReferencePathConfigs) + 1
pathConfigs := []ReferencePathConfig{
{
referencedGVK: schema.GroupVersionKind{
Kind: "KindA",
},
pathConfigs: []PathConfig{
{
GroupVersionKind: &schema.GroupVersionKind{
Kind: "KindB",
},
Path: []string{"path", "to", "a", "field"},
CreateIfNotPresent: false,
},
},
},
}
AddNameReferencePathConfigs(pathConfigs)
if len(defaultNameReferencePathConfigs) != expected {
t.Fatalf("actual %v doesn't match expected: %v", len(defaultAnnotationsPathConfigs), expected)
}
}

View File

@@ -22,7 +22,7 @@ import (
// defaultNameReferencePathConfigs is the default configuration for updating
// the fields reference the name of other resources.
var defaultNameReferencePathConfigs = []referencePathConfig{
var defaultNameReferencePathConfigs = []ReferencePathConfig{
{
referencedGVK: schema.GroupVersionKind{
Kind: "Deployment",
@@ -369,6 +369,14 @@ var defaultNameReferencePathConfigs = []referencePathConfig{
Path: []string{"spec", "initContainers", "envFrom", "secretRef", "name"},
CreateIfNotPresent: false,
},
{
GroupVersionKind: &schema.GroupVersionKind{
Version: "v1",
Kind: "Pod",
},
Path: []string{"spec", "imagePullSecrets", "name"},
CreateIfNotPresent: false,
},
{
GroupVersionKind: &schema.GroupVersionKind{
Kind: "Deployment",
@@ -404,6 +412,13 @@ var defaultNameReferencePathConfigs = []referencePathConfig{
Path: []string{"spec", "template", "spec", "initContainers", "envFrom", "secretRef", "name"},
CreateIfNotPresent: false,
},
{
GroupVersionKind: &schema.GroupVersionKind{
Kind: "Deployment",
},
Path: []string{"spec", "template", "spec", "imagePullSecrets", "name"},
CreateIfNotPresent: false,
},
{
GroupVersionKind: &schema.GroupVersionKind{
Kind: "ReplicaSet",
@@ -439,6 +454,13 @@ var defaultNameReferencePathConfigs = []referencePathConfig{
Path: []string{"spec", "template", "spec", "initContainers", "envFrom", "secretRef", "name"},
CreateIfNotPresent: false,
},
{
GroupVersionKind: &schema.GroupVersionKind{
Kind: "ReplicaSet",
},
Path: []string{"spec", "template", "spec", "imagePullSecrets", "name"},
CreateIfNotPresent: false,
},
{
GroupVersionKind: &schema.GroupVersionKind{
Kind: "DaemonSet",
@@ -474,6 +496,13 @@ var defaultNameReferencePathConfigs = []referencePathConfig{
Path: []string{"spec", "template", "spec", "initContainers", "envFrom", "secretRef", "name"},
CreateIfNotPresent: false,
},
{
GroupVersionKind: &schema.GroupVersionKind{
Kind: "DaemonSet",
},
Path: []string{"spec", "template", "spec", "imagePullSecrets", "name"},
CreateIfNotPresent: false,
},
{
GroupVersionKind: &schema.GroupVersionKind{
Kind: "StatefulSet",
@@ -509,6 +538,13 @@ var defaultNameReferencePathConfigs = []referencePathConfig{
Path: []string{"spec", "template", "spec", "initContainers", "envFrom", "secretRef", "name"},
CreateIfNotPresent: false,
},
{
GroupVersionKind: &schema.GroupVersionKind{
Kind: "StatefulSet",
},
Path: []string{"spec", "template", "spec", "imagePullSecrets", "name"},
CreateIfNotPresent: false,
},
{
GroupVersionKind: &schema.GroupVersionKind{
Kind: "Job",
@@ -544,6 +580,13 @@ var defaultNameReferencePathConfigs = []referencePathConfig{
Path: []string{"spec", "template", "spec", "initContainers", "envFrom", "secretRef", "name"},
CreateIfNotPresent: false,
},
{
GroupVersionKind: &schema.GroupVersionKind{
Kind: "Job",
},
Path: []string{"spec", "template", "spec", "imagePullSecrets", "name"},
CreateIfNotPresent: false,
},
{
GroupVersionKind: &schema.GroupVersionKind{
Kind: "CronJob",
@@ -579,6 +622,13 @@ var defaultNameReferencePathConfigs = []referencePathConfig{
Path: []string{"spec", "jobTemplate", "spec", "template", "spec", "initContainers", "envFrom", "secretRef", "name"},
CreateIfNotPresent: false,
},
{
GroupVersionKind: &schema.GroupVersionKind{
Kind: "CronJob",
},
Path: []string{"spec", "jobTemplate", "spec", "template", "spec", "imagePullSecrets", "name"},
CreateIfNotPresent: false,
},
{
GroupVersionKind: &schema.GroupVersionKind{
Kind: "Ingress",
@@ -586,6 +636,13 @@ var defaultNameReferencePathConfigs = []referencePathConfig{
Path: []string{"spec", "tls", "secretName"},
CreateIfNotPresent: false,
},
{
GroupVersionKind: &schema.GroupVersionKind{
Kind: "ServiceAccount",
},
Path: []string{"imagePullSecrets", "name"},
CreateIfNotPresent: false,
},
},
},
{
@@ -733,3 +790,29 @@ var defaultNameReferencePathConfigs = []referencePathConfig{
},
},
}
// AddNameReferencePathConfigs adds extra reference path configs to the default one
func AddNameReferencePathConfigs(r []ReferencePathConfig) {
for _, p := range r {
defaultNameReferencePathConfigs = MergeNameReferencePathConfigs(defaultNameReferencePathConfigs, p)
}
}
// MergeNameReferencePathConfigs merges one ReferencePathConfig into a slice of ReferencePathConfig
func MergeNameReferencePathConfigs(configs []ReferencePathConfig, config ReferencePathConfig) []ReferencePathConfig {
result := []ReferencePathConfig{}
found := false
for _, c := range configs {
if c.referencedGVK == config.referencedGVK {
c.pathConfigs = append(c.pathConfigs, config.pathConfigs...)
found = true
}
result = append(result, c)
}
if !found {
result = append(result, config)
}
return result
}

View File

@@ -33,12 +33,12 @@ type PathConfig struct {
Path []string
}
// referencePathConfig contains the configuration of a field that references
// ReferencePathConfig contains the configuration of a field that references
// the name of another resource whose GroupVersionKind is specified in referencedGVK.
// e.g. pod.spec.template.volumes.configMap.name references the name of a configmap
// Its corresponding referencePathConfig will look like:
//
// referencePathConfig{
// ReferencePathConfig{
// referencedGVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
// pathConfigs: []PathConfig{
// {
@@ -46,10 +46,23 @@ type PathConfig struct {
// Path: []string{"spec", "volumes", "configMap", "name"},
// },
// }
type referencePathConfig struct {
type ReferencePathConfig struct {
// referencedGVK is the GroupVersionKind that is referenced by
// the PathConfig's gvk in the path of PathConfig.Path.
referencedGVK schema.GroupVersionKind
// PathConfig is the gvk that is referencing the referencedGVK object's name.
pathConfigs []PathConfig
}
// NewReferencePathConfig creates a new ReferencePathConfig object
func NewReferencePathConfig(gvk schema.GroupVersionKind, pathconfigs []PathConfig) ReferencePathConfig {
return ReferencePathConfig{
referencedGVK: gvk,
pathConfigs: pathconfigs,
}
}
// GVK returns the Group version kind of a Reference PathConfig
func (r ReferencePathConfig) GVK() string {
return r.referencedGVK.String()
}

View File

@@ -100,3 +100,8 @@ func (o *namePrefixTransformer) addPrefix(in interface{}) (interface{}, error) {
}
return o.prefix + s, nil
}
// AddPrefixPathConfigs adds extra path configs to the default one
func AddPrefixPathConfigs(pathConfigs ...PathConfig) {
defaultNamePrefixPathConfigs = append(defaultNamePrefixPathConfigs, pathConfigs...)
}

View File

@@ -22,6 +22,7 @@ import (
"github.com/kubernetes-sigs/kustomize/pkg/resmap"
"github.com/kubernetes-sigs/kustomize/pkg/resource"
"k8s.io/apimachinery/pkg/runtime/schema"
)
func TestPrefixNameRun(t *testing.T) {
@@ -91,3 +92,19 @@ func TestPrefixNameRun(t *testing.T) {
t.Fatalf("actual doesn't match expected: %v", err)
}
}
func TestAddPrefixPathConfigs(t *testing.T) {
expected := len(defaultNamePrefixPathConfigs) + 1
pathConfigs := []PathConfig{
{
GroupVersionKind: &schema.GroupVersionKind{Group: "GroupA", Kind: "KindB"},
Path: []string{"path", "to", "a", "field"},
CreateIfNotPresent: true,
},
}
AddPrefixPathConfigs(pathConfigs...)
if len(defaultNamePrefixPathConfigs) != expected {
t.Fatalf("actual %v doesn't match expected: %v", len(defaultNamePrefixPathConfigs), expected)
}
}

View File

@@ -38,6 +38,70 @@ func NewRefVarTransformer(vars map[string]string) (Transformer, error) {
GroupVersionKind: &schema.GroupVersionKind{Kind: "Job"},
Path: []string{"spec", "template", "spec", "containers", "command"},
},
{
GroupVersionKind: &schema.GroupVersionKind{Kind: "CronJob"},
Path: []string{"spec", "jobTemplate", "spec", "template", "spec", "containers", "command"},
},
{
GroupVersionKind: &schema.GroupVersionKind{Kind: "StatefulSet"},
Path: []string{"spec", "template", "spec", "initContainers", "args"},
},
{
GroupVersionKind: &schema.GroupVersionKind{Kind: "StatefulSet"},
Path: []string{"spec", "template", "spec", "containers", "args"},
},
{
GroupVersionKind: &schema.GroupVersionKind{Kind: "Deployment"},
Path: []string{"spec", "template", "spec", "initContainers", "args"},
},
{
GroupVersionKind: &schema.GroupVersionKind{Kind: "Deployment"},
Path: []string{"spec", "template", "spec", "containers", "args"},
},
{
GroupVersionKind: &schema.GroupVersionKind{Kind: "Job"},
Path: []string{"spec", "template", "spec", "containers", "args"},
},
{
GroupVersionKind: &schema.GroupVersionKind{Kind: "CronJob"},
Path: []string{"spec", "jobTemplate", "spec", "template", "spec", "containers", "args"},
},
{
GroupVersionKind: &schema.GroupVersionKind{Kind: "StatefulSet"},
Path: []string{"spec", "template", "spec", "initContainers", "env", "value"},
},
{
GroupVersionKind: &schema.GroupVersionKind{Kind: "StatefulSet"},
Path: []string{"spec", "template", "spec", "containers", "env", "value"},
},
{
GroupVersionKind: &schema.GroupVersionKind{Kind: "Deployment"},
Path: []string{"spec", "template", "spec", "initContainers", "env", "value"},
},
{
GroupVersionKind: &schema.GroupVersionKind{Kind: "Deployment"},
Path: []string{"spec", "template", "spec", "containers", "env", "value"},
},
{
GroupVersionKind: &schema.GroupVersionKind{Kind: "Job"},
Path: []string{"spec", "template", "spec", "containers", "env", "value"},
},
{
GroupVersionKind: &schema.GroupVersionKind{Kind: "CronJob"},
Path: []string{"spec", "jobTemplate", "spec", "template", "spec", "containers", "env", "value"},
},
{
GroupVersionKind: &schema.GroupVersionKind{Kind: "Pod"},
Path: []string{"spec", "containers", "command"},
},
{
GroupVersionKind: &schema.GroupVersionKind{Kind: "Pod"},
Path: []string{"spec", "containers", "args"},
},
{
GroupVersionKind: &schema.GroupVersionKind{Kind: "Pod"},
Path: []string{"spec", "containers", "env", "value"},
},
},
}, nil
}

View File

@@ -44,6 +44,9 @@ type Kustomization struct {
// URLs and globs.
Resources []string `json:"resources,omitempty" yaml:"resources,omitempty"`
// CRDs specifies relative paths to custom resource definition files.
CRDs []string `json:"crds,omitempty" yaml:"crds,omitempty"`
// An Patch entry is very similar to an Resource entry.
// It specifies the relative paths within the package, and could be any
// format that kubectl -f allows.

5
vendor/github.com/PuerkitoBio/purell/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,5 @@
*.sublime-*
.DS_Store
*.swp
*.swo
tags

7
vendor/github.com/PuerkitoBio/purell/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,7 @@
language: go
go:
- 1.4
- 1.5
- 1.6
- tip

12
vendor/github.com/PuerkitoBio/purell/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,12 @@
Copyright (c) 2012, Martin Angers
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

187
vendor/github.com/PuerkitoBio/purell/README.md generated vendored Normal file
View File

@@ -0,0 +1,187 @@
# Purell
Purell is a tiny Go library to normalize URLs. It returns a pure URL. Pure-ell. Sanitizer and all. Yeah, I know...
Based on the [wikipedia paper][wiki] and the [RFC 3986 document][rfc].
[![build status](https://secure.travis-ci.org/PuerkitoBio/purell.png)](http://travis-ci.org/PuerkitoBio/purell)
## Install
`go get github.com/PuerkitoBio/purell`
## Changelog
* **2016-11-14 (v1.1.0)** : IDN: Conform to RFC 5895: Fold character width (thanks to @beeker1121).
* **2016-07-27 (v1.0.0)** : Normalize IDN to ASCII (thanks to @zenovich).
* **2015-02-08** : Add fix for relative paths issue ([PR #5][pr5]) and add fix for unnecessary encoding of reserved characters ([see issue #7][iss7]).
* **v0.2.0** : Add benchmarks, Attempt IDN support.
* **v0.1.0** : Initial release.
## Examples
From `example_test.go` (note that in your code, you would import "github.com/PuerkitoBio/purell", and would prefix references to its methods and constants with "purell."):
```go
package purell
import (
"fmt"
"net/url"
)
func ExampleNormalizeURLString() {
if normalized, err := NormalizeURLString("hTTp://someWEBsite.com:80/Amazing%3f/url/",
FlagLowercaseScheme|FlagLowercaseHost|FlagUppercaseEscapes); err != nil {
panic(err)
} else {
fmt.Print(normalized)
}
// Output: http://somewebsite.com:80/Amazing%3F/url/
}
func ExampleMustNormalizeURLString() {
normalized := MustNormalizeURLString("hTTpS://someWEBsite.com:443/Amazing%fa/url/",
FlagsUnsafeGreedy)
fmt.Print(normalized)
// Output: http://somewebsite.com/Amazing%FA/url
}
func ExampleNormalizeURL() {
if u, err := url.Parse("Http://SomeUrl.com:8080/a/b/.././c///g?c=3&a=1&b=9&c=0#target"); err != nil {
panic(err)
} else {
normalized := NormalizeURL(u, FlagsUsuallySafeGreedy|FlagRemoveDuplicateSlashes|FlagRemoveFragment)
fmt.Print(normalized)
}
// Output: http://someurl.com:8080/a/c/g?c=3&a=1&b=9&c=0
}
```
## API
As seen in the examples above, purell offers three methods, `NormalizeURLString(string, NormalizationFlags) (string, error)`, `MustNormalizeURLString(string, NormalizationFlags) (string)` and `NormalizeURL(*url.URL, NormalizationFlags) (string)`. They all normalize the provided URL based on the specified flags. Here are the available flags:
```go
const (
// Safe normalizations
FlagLowercaseScheme NormalizationFlags = 1 << iota // HTTP://host -> http://host, applied by default in Go1.1
FlagLowercaseHost // http://HOST -> http://host
FlagUppercaseEscapes // http://host/t%ef -> http://host/t%EF
FlagDecodeUnnecessaryEscapes // http://host/t%41 -> http://host/tA
FlagEncodeNecessaryEscapes // http://host/!"#$ -> http://host/%21%22#$
FlagRemoveDefaultPort // http://host:80 -> http://host
FlagRemoveEmptyQuerySeparator // http://host/path? -> http://host/path
// Usually safe normalizations
FlagRemoveTrailingSlash // http://host/path/ -> http://host/path
FlagAddTrailingSlash // http://host/path -> http://host/path/ (should choose only one of these add/remove trailing slash flags)
FlagRemoveDotSegments // http://host/path/./a/b/../c -> http://host/path/a/c
// Unsafe normalizations
FlagRemoveDirectoryIndex // http://host/path/index.html -> http://host/path/
FlagRemoveFragment // http://host/path#fragment -> http://host/path
FlagForceHTTP // https://host -> http://host
FlagRemoveDuplicateSlashes // http://host/path//a///b -> http://host/path/a/b
FlagRemoveWWW // http://www.host/ -> http://host/
FlagAddWWW // http://host/ -> http://www.host/ (should choose only one of these add/remove WWW flags)
FlagSortQuery // http://host/path?c=3&b=2&a=1&b=1 -> http://host/path?a=1&b=1&b=2&c=3
// Normalizations not in the wikipedia article, required to cover tests cases
// submitted by jehiah
FlagDecodeDWORDHost // http://1113982867 -> http://66.102.7.147
FlagDecodeOctalHost // http://0102.0146.07.0223 -> http://66.102.7.147
FlagDecodeHexHost // http://0x42660793 -> http://66.102.7.147
FlagRemoveUnnecessaryHostDots // http://.host../path -> http://host/path
FlagRemoveEmptyPortSeparator // http://host:/path -> http://host/path
// Convenience set of safe normalizations
FlagsSafe NormalizationFlags = FlagLowercaseHost | FlagLowercaseScheme | FlagUppercaseEscapes | FlagDecodeUnnecessaryEscapes | FlagEncodeNecessaryEscapes | FlagRemoveDefaultPort | FlagRemoveEmptyQuerySeparator
// For convenience sets, "greedy" uses the "remove trailing slash" and "remove www. prefix" flags,
// while "non-greedy" uses the "add (or keep) the trailing slash" and "add www. prefix".
// Convenience set of usually safe normalizations (includes FlagsSafe)
FlagsUsuallySafeGreedy NormalizationFlags = FlagsSafe | FlagRemoveTrailingSlash | FlagRemoveDotSegments
FlagsUsuallySafeNonGreedy NormalizationFlags = FlagsSafe | FlagAddTrailingSlash | FlagRemoveDotSegments
// Convenience set of unsafe normalizations (includes FlagsUsuallySafe)
FlagsUnsafeGreedy NormalizationFlags = FlagsUsuallySafeGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagRemoveWWW | FlagSortQuery
FlagsUnsafeNonGreedy NormalizationFlags = FlagsUsuallySafeNonGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagAddWWW | FlagSortQuery
// Convenience set of all available flags
FlagsAllGreedy = FlagsUnsafeGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
FlagsAllNonGreedy = FlagsUnsafeNonGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
)
```
For convenience, the set of flags `FlagsSafe`, `FlagsUsuallySafe[Greedy|NonGreedy]`, `FlagsUnsafe[Greedy|NonGreedy]` and `FlagsAll[Greedy|NonGreedy]` are provided for the similarly grouped normalizations on [wikipedia's URL normalization page][wiki]. You can add (using the bitwise OR `|` operator) or remove (using the bitwise AND NOT `&^` operator) individual flags from the sets if required, to build your own custom set.
The [full godoc reference is available on gopkgdoc][godoc].
Some things to note:
* `FlagDecodeUnnecessaryEscapes`, `FlagEncodeNecessaryEscapes`, `FlagUppercaseEscapes` and `FlagRemoveEmptyQuerySeparator` are always implicitly set, because internally, the URL string is parsed as an URL object, which automatically decodes unnecessary escapes, uppercases and encodes necessary ones, and removes empty query separators (an unnecessary `?` at the end of the url). So this operation cannot **not** be done. For this reason, `FlagRemoveEmptyQuerySeparator` (as well as the other three) has been included in the `FlagsSafe` convenience set, instead of `FlagsUnsafe`, where Wikipedia puts it.
* The `FlagDecodeUnnecessaryEscapes` decodes the following escapes (*from -> to*):
- %24 -> $
- %26 -> &
- %2B-%3B -> +,-./0123456789:;
- %3D -> =
- %40-%5A -> @ABCDEFGHIJKLMNOPQRSTUVWXYZ
- %5F -> _
- %61-%7A -> abcdefghijklmnopqrstuvwxyz
- %7E -> ~
* When the `NormalizeURL` function is used (passing an URL object), this source URL object is modified (that is, after the call, the URL object will be modified to reflect the normalization).
* The *replace IP with domain name* normalization (`http://208.77.188.166/ → http://www.example.com/`) is obviously not possible for a library without making some network requests. This is not implemented in purell.
* The *remove unused query string parameters* and *remove default query parameters* are also not implemented, since this is a very case-specific normalization, and it is quite trivial to do with an URL object.
### Safe vs Usually Safe vs Unsafe
Purell allows you to control the level of risk you take while normalizing an URL. You can aggressively normalize, play it totally safe, or anything in between.
Consider the following URL:
`HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid`
Normalizing with the `FlagsSafe` gives:
`https://www.root.com/toto/tE%1F///a/./b/../c/?z=3&w=2&a=4&w=1#invalid`
With the `FlagsUsuallySafeGreedy`:
`https://www.root.com/toto/tE%1F///a/c?z=3&w=2&a=4&w=1#invalid`
And with `FlagsUnsafeGreedy`:
`http://root.com/toto/tE%1F/a/c?a=4&w=1&w=2&z=3`
## TODOs
* Add a class/default instance to allow specifying custom directory index names? At the moment, removing directory index removes `(^|/)((?:default|index)\.\w{1,4})$`.
## Thanks / Contributions
@rogpeppe
@jehiah
@opennota
@pchristopher1275
@zenovich
@beeker1121
## License
The [BSD 3-Clause license][bsd].
[bsd]: http://opensource.org/licenses/BSD-3-Clause
[wiki]: http://en.wikipedia.org/wiki/URL_normalization
[rfc]: http://tools.ietf.org/html/rfc3986#section-6
[godoc]: http://go.pkgdoc.org/github.com/PuerkitoBio/purell
[pr5]: https://github.com/PuerkitoBio/purell/pull/5
[iss7]: https://github.com/PuerkitoBio/purell/issues/7

57
vendor/github.com/PuerkitoBio/purell/bench_test.go generated vendored Normal file
View File

@@ -0,0 +1,57 @@
package purell
import (
"testing"
)
var (
safeUrl = "HttPS://..iaMHost..Test:443/paTh^A%ef//./%41PaTH/..//?"
usuallySafeUrl = "HttPS://..iaMHost..Test:443/paTh^A%ef//./%41PaTH/../final/"
unsafeUrl = "HttPS://..www.iaMHost..Test:443/paTh^A%ef//./%41PaTH/../final/index.html?t=val1&a=val4&z=val5&a=val1#fragment"
allDWORDUrl = "HttPS://1113982867:/paTh^A%ef//./%41PaTH/../final/index.html?t=val1&a=val4&z=val5&a=val1#fragment"
allOctalUrl = "HttPS://0102.0146.07.0223:/paTh^A%ef//./%41PaTH/../final/index.html?t=val1&a=val4&z=val5&a=val1#fragment"
allHexUrl = "HttPS://0x42660793:/paTh^A%ef//./%41PaTH/../final/index.html?t=val1&a=val4&z=val5&a=val1#fragment"
allCombinedUrl = "HttPS://..0x42660793.:/paTh^A%ef//./%41PaTH/../final/index.html?t=val1&a=val4&z=val5&a=val1#fragment"
)
func BenchmarkSafe(b *testing.B) {
for i := 0; i < b.N; i++ {
NormalizeURLString(safeUrl, FlagsSafe)
}
}
func BenchmarkUsuallySafe(b *testing.B) {
for i := 0; i < b.N; i++ {
NormalizeURLString(usuallySafeUrl, FlagsUsuallySafeGreedy)
}
}
func BenchmarkUnsafe(b *testing.B) {
for i := 0; i < b.N; i++ {
NormalizeURLString(unsafeUrl, FlagsUnsafeGreedy)
}
}
func BenchmarkAllDWORD(b *testing.B) {
for i := 0; i < b.N; i++ {
NormalizeURLString(allDWORDUrl, FlagsAllGreedy)
}
}
func BenchmarkAllOctal(b *testing.B) {
for i := 0; i < b.N; i++ {
NormalizeURLString(allOctalUrl, FlagsAllGreedy)
}
}
func BenchmarkAllHex(b *testing.B) {
for i := 0; i < b.N; i++ {
NormalizeURLString(allHexUrl, FlagsAllGreedy)
}
}
func BenchmarkAllCombined(b *testing.B) {
for i := 0; i < b.N; i++ {
NormalizeURLString(allCombinedUrl, FlagsAllGreedy)
}
}

View File

@@ -0,0 +1,9 @@
PASS
BenchmarkSafe 500000 6131 ns/op
BenchmarkUsuallySafe 200000 7864 ns/op
BenchmarkUnsafe 100000 28560 ns/op
BenchmarkAllDWORD 50000 38722 ns/op
BenchmarkAllOctal 50000 40941 ns/op
BenchmarkAllHex 50000 44063 ns/op
BenchmarkAllCombined 50000 33613 ns/op
ok github.com/PuerkitoBio/purell 17.404s

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