Compare commits

...

70 Commits

Author SHA1 Message Date
Kubernetes Prow Robot
b736b81167 Merge pull request #3151 from Shell32-Natsu/master
Pin to cmd/config 0.8.4
2020-10-29 15:24:06 -07:00
Donny Xia
0a04b1bb78 Pin to cmd/config 0.8.4 2020-10-29 15:11:09 -07:00
Kubernetes Prow Robot
f7ebaae39e Merge pull request #3150 from Shell32-Natsu/master
Pin to kyaml v0.9.3
2020-10-29 15:04:06 -07:00
Donny Xia
08099f0cea Pin to kyaml v0.9.3 2020-10-29 14:47:52 -07:00
Kubernetes Prow Robot
6fd04dd253 Merge pull request #3146 from ilyakaznacheev/fix-configmap-doc
Add better configMap cleanup description.
2020-10-28 17:38:59 -07:00
Ilya Kaznacheev
9ac97ef91f Add better configMap cleanup descripion 2020-10-29 01:50:45 +03:00
Jeff Regan
cfbf426174 Merge pull request #3129 from Shell32-Natsu/patches-command
Update edit patch command
2020-10-28 12:47:13 -07:00
Donny Xia
9aafc61c5b disable edit add patch command tests temporarily 2020-10-28 12:24:51 -07:00
Donny Xia
cd2ebd3046 code review 2020-10-27 15:10:29 -07:00
Jeff Regan
b20e5d7f84 Merge pull request #3135 from Shell32-Natsu/cleanup-namespace-transformer
cleanup namespace transformer
2020-10-27 09:54:28 -07:00
Jeff Regan
13c9a2873e Update comments in multi-transformer 2020-10-27 07:17:14 -07:00
Kubernetes Prow Robot
fc06283905 Merge pull request #3140 from teruyam/patch-1
Fix broken link to release page
2020-10-26 12:37:02 -07:00
Jeff Regan
119d7cadf5 Merge pull request #3136 from natasha41575/NamespaceabilityFromOpenAPI
removed hardcoded list of namespaceable resources
2020-10-26 12:22:36 -07:00
Masashi Teruya
cdc6d1fc28 Fix broken link to release page 2020-10-24 11:18:33 +09:00
Natasha Sarkar
49dced2e01 removed hardcoded list of namespaceable resources 2020-10-23 11:47:29 -07:00
Donny Xia
76a8f034cb Merge pull request #3133 from robinbraemer/patch-2
Add Ingress tls secretName to Secret builtin nameref
2020-10-23 11:20:11 -07:00
Donny Xia
52060ac480 Merge pull request #3132 from robinbraemer/patch-1
Add Ingress v1 support to builtin name references
2020-10-23 11:19:51 -07:00
Donny Xia
719532e4df Merge pull request #3123 from AlphaWong/patch-1
doc: add varReference example
2020-10-22 14:42:05 -07:00
Donny Xia
70dcc79bf4 cleanup namespace transformer 2020-10-22 13:18:20 -07:00
Kubernetes Prow Robot
55b4448862 Merge pull request #3134 from phanimarupaka/OptionallySuppressIsSet
Make isSet a parameter
2020-10-22 11:43:37 -07:00
Phani Teja Marupaka
bcaac6f8c1 Make isSet a parameter 2020-10-22 11:31:30 -07:00
Jeff Regan
ba4b44db6b Merge pull request #3126 from monopole/mechanical
Generated go.sum/mod and docs.go changes.
2020-10-22 10:30:52 -07:00
Robin Brämer
fd280d0c0b Add Ingress tls secretName to Secret builtin nameref 2020-10-22 17:00:10 +02:00
Robin Brämer
1dbf490146 Add IngressClass kind
Adds IngressClass kind and Ingress fieldSpecs path spec/ingressClassName
2020-10-22 16:11:44 +02:00
Robin Brämer
62e4df72d3 Add Service name references for Ingress v1
Since Kubernetes v1.19, Ingress networking.k8s.io/v1 has two more Server name references.
- https://kubernetes.io/docs/concepts/services-networking/ingress/#the-ingress-resource
- https://kubernetes.io/docs/setup/release/notes/
2020-10-22 15:59:22 +02:00
Donny Xia
bb77a7c86d refactor edit remove patch 2020-10-21 18:48:53 -07:00
Donny Xia
41abeb85be refactor edit add patch command 2020-10-21 14:56:20 -07:00
Jeff Regan
3c86d37148 Merge pull request #3122 from Shell32-Natsu/ref-target
check Gvk in roleRef when update name reference
2020-10-21 11:19:20 -07:00
Kubernetes Prow Robot
287b38cc87 Merge pull request #3106 from Shell32-Natsu/array-index
support array index in PathGetter
2020-10-21 11:16:20 -07:00
jregan
d8d727b1ca Generated go.sum/mod and docs.go changes. 2020-10-20 17:22:48 -07:00
Jeff Regan
a81a3d40ce Merge pull request #3087 from etefera/add-isSet-to-list-setters
Add isSet to ListSetters cmd.
2020-10-20 16:52:13 -07:00
Eyob Tefera
52e682489c Merge branch 'add-isSet-to-list-setters' of https://github.com/etefera/kustomize into add-isSet-to-list-setters 2020-10-20 23:24:11 +00:00
Eyob Tefera
8714ca5a58 Move "Is Set" column to after "Required" 2020-10-20 23:17:54 +00:00
Eyob Tefera
0490ca163f Fix list_setters test. 2020-10-20 23:17:54 +00:00
Eyob Tefera
b4947fe8a0 Add isSet to ListSetters cmd. 2020-10-20 23:17:54 +00:00
Donny Xia
9c7b4fddf9 code review 2020-10-20 12:39:50 -07:00
Alpha
5d5b1c2c38 doc: simplify the language for understanding 2020-10-20 13:13:13 +08:00
Alpha
cf1aafb121 doc: add description for new user about vars 2020-10-20 13:06:31 +08:00
Alpha
2d4e406a86 doc: add varReference example 2020-10-20 12:56:43 +08:00
Jeff Regan
2a8edd2859 Merge pull request #3110 from aude/completion
Use Cobra for shell completion
2020-10-19 18:03:06 -07:00
Kubernetes Prow Robot
a3bc13847c Merge pull request #3119 from phanimarupaka/MakeRecurseLogicPublic
Make recurse logic public
2020-10-19 17:28:07 -07:00
Kubernetes Prow Robot
944b19ff7c Merge pull request #3114 from monopole/hideOpenapi
Hide openapi top-level command
2020-10-19 17:14:07 -07:00
Jeff Regan
f75274bae7 Merge pull request #3085 from mikeyrcamp/feat/add-edit-transformer
Add kustomize edit add/remove transformer command #3053
2020-10-19 15:04:12 -07:00
Donny Xia
62a8a8c57d check Gvk in roleRef when update name reference 2020-10-19 14:01:13 -07:00
Kubernetes Prow Robot
9514f9cd3a Merge pull request #3121 from natasha41575/regenerateSwagger
regenerated swagger.go files and updated asset name
2020-10-19 13:39:18 -07:00
Natasha Sarkar
c1c2725360 regenerated swagger.go files and updated asset name 2020-10-19 13:04:56 -07:00
Phani Teja Marupaka
e9ff26bb1b Make recurse logic public 2020-10-19 12:26:15 -07:00
Kubernetes Prow Robot
14dc3dfb81 Merge pull request #3112 from KnVerey/pipeline_continue
[kyaml] Option to continue pipeline processing when filter returns empty result
2020-10-19 10:46:14 -07:00
Katrina Verey
44619d5ca2 Option to continue pipeline processing when filter returns empty result 2020-10-19 10:34:28 -07:00
Kubernetes Prow Robot
a458ed84f9 Merge pull request #3113 from etefera/add-isSet-to-setter-struct
Add IsSet to SetterDefinition for kyaml release.
2020-10-18 11:26:13 -07:00
Kubernetes Prow Robot
108f44377d Merge pull request #3115 from monopole/refactorOpenapiMakefile
Refactor making of openapi generated files.
2020-10-16 19:24:12 -07:00
jregan
dc8439fbfa Refactor making of openapi generated files. 2020-10-16 19:03:33 -07:00
Jeff Regan
f5353fafa1 Update info.go 2020-10-16 18:00:18 -07:00
jregan
3d1376bbbc oopsHideProperCommand 2020-10-16 17:57:25 -07:00
Eyob Tefera
b1ea25e86a Add IsSet to SetterDefinition for kyaml release. 2020-10-17 00:46:30 +00:00
Jeff Regan
495f6df973 Merge pull request #3107 from natasha41575/reportOpenAPIinfo
Created a "kustomize openapi info" command
2020-10-16 14:33:21 -07:00
Natasha Sarkar
a4f1f0841e added a hidden openapi info command 2020-10-16 13:55:37 -07:00
Asbjørn Apeland
9d0fba81f0 Use Cobra for shell completion 2020-10-16 18:55:54 +02:00
Donny Xia
92826c6a1e support array index in PathGetter 2020-10-15 16:28:09 -07:00
Kubernetes Prow Robot
7e04be9ec6 Merge pull request #3105 from Shell32-Natsu/unpinKyaml
Unpin kyaml
2020-10-15 14:23:25 -07:00
Donny Xia
d954c39ef7 Unpin kyaml 2020-10-15 14:05:31 -07:00
Jeff Regan
176ac5b4fa Merge pull request #3104 from Shell32-Natsu/pinToKyaml0.9.2
Pin to kyaml v0.9.2
2020-10-15 14:02:47 -07:00
Donny Xia
dd696b5cb4 Pin to kyaml v0.9.2 2020-10-15 13:55:30 -07:00
Jeff Regan
501404e403 Merge pull request #3103 from monopole/prchecker
Move multi-module-span.go to cmd/prchecker
2020-10-15 13:39:48 -07:00
Jeff Regan
232da9e12b Update Makefile 2020-10-15 11:58:50 -07:00
jregan
8b9ce8eacb Move multi-module-span.go to cmd/prchecker 2020-10-15 11:46:27 -07:00
Mike Camp
a6a061215f Add kustomize edit add/remove transformer command #3053
Similar to edit add/remove patch these commands
add the ability to add or remove a transformer file path
from the kustomization.yaml.

Refactored the "remove resource" and new "remove transformer"
tests into a common testRemoveCommand function to prevent
code duplication.
2020-10-14 22:24:08 -04:00
Eyob Tefera
ccca424234 Move "Is Set" column to after "Required" 2020-10-14 19:38:47 +00:00
Eyob Tefera
58092bf66d Fix list_setters test. 2020-10-12 20:23:53 +00:00
Eyob Tefera
747323efce Add isSet to ListSetters cmd. 2020-10-12 20:14:25 +00:00
146 changed files with 2318 additions and 1208 deletions

View File

@@ -72,6 +72,11 @@ $(MYGOBIN)/pluginator:
cd cmd/pluginator; \ cd cmd/pluginator; \
go install . go install .
# Build from local source.
$(MYGOBIN)/prchecker:
cd cmd/prchecker; \
go install .
# Build from local source. # Build from local source.
$(MYGOBIN)/kustomize: $(MYGOBIN)/kustomize:
cd kustomize; \ cd kustomize; \
@@ -85,6 +90,7 @@ install-tools: \
$(MYGOBIN)/gorepomod \ $(MYGOBIN)/gorepomod \
$(MYGOBIN)/mdrip \ $(MYGOBIN)/mdrip \
$(MYGOBIN)/pluginator \ $(MYGOBIN)/pluginator \
$(MYGOBIN)/prchecker \
$(MYGOBIN)/stringer $(MYGOBIN)/stringer
### Begin kustomize plugin rules. ### Begin kustomize plugin rules.

View File

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

View File

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

View File

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

View File

@@ -17,8 +17,6 @@ require (
k8s.io/apimachinery v0.17.0 k8s.io/apimachinery v0.17.0
k8s.io/client-go v0.17.0 k8s.io/client-go v0.17.0
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a
sigs.k8s.io/kustomize/kyaml v0.9.1 sigs.k8s.io/kustomize/kyaml v0.9.3
sigs.k8s.io/yaml v1.2.0 sigs.k8s.io/yaml v1.2.0
) )
replace sigs.k8s.io/kustomize/kyaml v0.9.1 => ../kyaml

View File

@@ -588,6 +588,8 @@ mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphD
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f h1:Cq7MalBHYACRd6EesksG1Q8EoIAKOsiZviGKbOLIej4= mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f h1:Cq7MalBHYACRd6EesksG1Q8EoIAKOsiZviGKbOLIej4=
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw= mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw=
sigs.k8s.io/kustomize/kyaml v0.9.3 h1:kZ5HnNmmnbndSXFivrAVM6u3Ik1dwu4kbpaV8KNwy8I=
sigs.k8s.io/kustomize/kyaml v0.9.3/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=

View File

@@ -789,9 +789,9 @@ func TestNameReferenceClusterWide(t *testing.T) {
"name": modifiedname, "name": modifiedname,
}, },
"roleRef": map[string]interface{}{ "roleRef": map[string]interface{}{
"apiVersion": "rbac.authorization.k8s.io/v1", "apiGroup": "rbac.authorization.k8s.io",
"kind": "ClusterRole", "kind": "ClusterRole",
"name": orgname, "name": orgname,
}, },
"subjects": []interface{}{ "subjects": []interface{}{
map[string]interface{}{ map[string]interface{}{
@@ -845,9 +845,9 @@ func TestNameReferenceClusterWide(t *testing.T) {
"name": modifiedname, "name": modifiedname,
}, },
"roleRef": map[string]interface{}{ "roleRef": map[string]interface{}{
"apiVersion": "rbac.authorization.k8s.io/v1", "apiGroup": "rbac.authorization.k8s.io",
"kind": "ClusterRole", "kind": "ClusterRole",
"name": modifiedname, "name": modifiedname,
}, },
// The following tests required a change in // The following tests required a change in
// getNameFunc implementation in order to leverage // getNameFunc implementation in order to leverage
@@ -937,9 +937,9 @@ func TestNameReferenceNamespaceTransformation(t *testing.T) {
"name": modifiedname, "name": modifiedname,
}, },
"roleRef": map[string]interface{}{ "roleRef": map[string]interface{}{
"apiVersion": "rbac.authorization.k8s.io/v1", "apiGroup": "rbac.authorization.k8s.io",
"kind": "ClusterRole", "kind": "ClusterRole",
"name": orgname, "name": orgname,
}, },
"subjects": []interface{}{ "subjects": []interface{}{
map[string]interface{}{ map[string]interface{}{
@@ -973,9 +973,9 @@ func TestNameReferenceNamespaceTransformation(t *testing.T) {
"name": modifiedname, "name": modifiedname,
}, },
"roleRef": map[string]interface{}{ "roleRef": map[string]interface{}{
"apiVersion": "rbac.authorization.k8s.io/v1", "apiGroup": "rbac.authorization.k8s.io",
"kind": "ClusterRole", "kind": "ClusterRole",
"name": modifiedname, "name": modifiedname,
}, },
// The following tests required a change in // The following tests required a change in
// getNameFunc implementation in order to leverage // getNameFunc implementation in order to leverage

View File

@@ -527,8 +527,8 @@ k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw= mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw=
sigs.k8s.io/kustomize/kyaml v0.9.1 h1:T7aNUraSioQp0NHJZtYjIhL/q8mqRzCiHcAKdvo09go= sigs.k8s.io/kustomize/kyaml v0.9.3 h1:kZ5HnNmmnbndSXFivrAVM6u3Ik1dwu4kbpaV8KNwy8I=
sigs.k8s.io/kustomize/kyaml v0.9.1/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw= sigs.k8s.io/kustomize/kyaml v0.9.3/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,6 +6,7 @@ package resid
import ( import (
"strings" "strings"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/yaml" "sigs.k8s.io/kustomize/kyaml/yaml"
) )
@@ -207,5 +208,6 @@ func (x Gvk) toKyamlTypeMeta() yaml.TypeMeta {
// IsNamespaceableKind returns true if x is a namespaceable Gvk // IsNamespaceableKind returns true if x is a namespaceable Gvk
// Implements https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/#not-all-objects-are-in-a-namespace // Implements https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/#not-all-objects-are-in-a-namespace
func (x Gvk) IsNamespaceableKind() bool { func (x Gvk) IsNamespaceableKind() bool {
return x.toKyamlTypeMeta().IsNamespaceable() isNamespaceScoped, found := openapi.IsNamespaceScoped(x.toKyamlTypeMeta())
return !found || isNamespaceScoped
} }

View File

@@ -18,6 +18,8 @@ package resid
import ( import (
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
var equalsTests = []struct { var equalsTests = []struct {
@@ -255,3 +257,40 @@ func TestSelectByGVK(t *testing.T) {
} }
} }
} }
func TestIsNamespaceableKind(t *testing.T) {
testCases := []struct {
name string
gvk Gvk
expected bool
}{
{
"namespaceable resource",
Gvk{Group: "apps", Version: "v1", Kind: "Deployment"},
true,
},
{
"clusterscoped resource",
Gvk{Group: "", Version: "v1", Kind: "Namespace"},
false,
},
{
"unknown resource (should default to namespaceable)",
Gvk{Group: "example1.com", Version: "v1", Kind: "Bar"},
true,
},
{
"unknown resource (should default to namespaceable)",
Gvk{Group: "apps", Version: "v1", Kind: "ClusterRoleBinding"},
true,
},
}
for i := range testCases {
test := testCases[i]
t.Run(test.name, func(t *testing.T) {
isNamespaceable := test.gvk.IsNamespaceableKind()
assert.Equal(t, test.expected, isNamespaceable)
})
}
}

View File

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

View File

@@ -355,7 +355,7 @@ func TestSubsetThatCouldBeReferencedByResource(t *testing.T) {
}) })
r4 := rf.FromMap( r4 := rf.FromMap(
map[string]interface{}{ map[string]interface{}{
"apiVersion": "v1", "apiVersion": "apps/v1",
"kind": "Deployment", "kind": "Deployment",
"metadata": map[string]interface{}{ "metadata": map[string]interface{}{
"name": "charlie", "name": "charlie",
@@ -374,7 +374,7 @@ func TestSubsetThatCouldBeReferencedByResource(t *testing.T) {
r5.AddNamePrefix("little-") r5.AddNamePrefix("little-")
r6 := rf.FromMap( r6 := rf.FromMap(
map[string]interface{}{ map[string]interface{}{
"apiVersion": "v1", "apiVersion": "apps/v1",
"kind": "Deployment", "kind": "Deployment",
"metadata": map[string]interface{}{ "metadata": map[string]interface{}{
"name": "domino", "name": "domino",
@@ -384,7 +384,7 @@ func TestSubsetThatCouldBeReferencedByResource(t *testing.T) {
r6.AddNamePrefix("little-") r6.AddNamePrefix("little-")
r7 := rf.FromMap( r7 := rf.FromMap(
map[string]interface{}{ map[string]interface{}{
"apiVersion": "v1", "apiVersion": "rbac.authorization.k8s.io/v1",
"kind": "ClusterRoleBinding", "kind": "ClusterRoleBinding",
"metadata": map[string]interface{}{ "metadata": map[string]interface{}{
"name": "meh", "name": "meh",

View File

@@ -17,3 +17,12 @@ type Patch struct {
// Target points to the resources that the patch is applied to // Target points to the resources that the patch is applied to
Target *Selector `json:"target,omitempty" yaml:"target,omitempty"` Target *Selector `json:"target,omitempty" yaml:"target,omitempty"`
} }
// Equals return true if p equals o.
func (p *Patch) Equals(o Patch) bool {
targetEqual := (p.Target == o.Target) ||
(p.Target != nil && o.Target != nil && *p.Target == *o.Target)
return p.Path == o.Path &&
p.Patch == o.Patch &&
targetEqual
}

125
api/types/patch_test.go Normal file
View File

@@ -0,0 +1,125 @@
package types_test
import (
"testing"
"sigs.k8s.io/kustomize/api/resid"
. "sigs.k8s.io/kustomize/api/types"
)
func TestPatchEquals(t *testing.T) {
selector := Selector{
Gvk: resid.Gvk{
Group: "group",
Version: "version",
Kind: "kind",
},
Name: "name",
Namespace: "namespace",
LabelSelector: "selector",
AnnotationSelector: "selector",
}
type testcase struct {
patch1 Patch
patch2 Patch
expect bool
name string
}
testcases := []testcase{
{
name: "empty patches",
patch1: Patch{},
patch2: Patch{},
expect: true,
},
{
name: "full patches",
patch1: Patch{
Path: "foo",
Patch: "bar",
Target: &Selector{
Gvk: resid.Gvk{
Group: "group",
Version: "version",
Kind: "kind",
},
Name: "name",
Namespace: "namespace",
LabelSelector: "selector",
AnnotationSelector: "selector",
},
},
patch2: Patch{
Path: "foo",
Patch: "bar",
Target: &Selector{
Gvk: resid.Gvk{
Group: "group",
Version: "version",
Kind: "kind",
},
Name: "name",
Namespace: "namespace",
LabelSelector: "selector",
AnnotationSelector: "selector",
},
},
expect: true,
},
{
name: "same target",
patch1: Patch{
Path: "foo",
Patch: "bar",
Target: &selector,
},
patch2: Patch{
Path: "foo",
Patch: "bar",
Target: &selector,
},
expect: true,
},
{
name: "omit target",
patch1: Patch{
Path: "foo",
Patch: "bar",
},
patch2: Patch{
Path: "foo",
Patch: "bar",
},
expect: true,
},
{
name: "one nil target",
patch1: Patch{
Path: "foo",
Patch: "bar",
Target: &selector,
},
patch2: Patch{
Path: "foo",
Patch: "bar",
},
expect: false,
},
{
name: "different path",
patch1: Patch{
Path: "foo",
},
patch2: Patch{
Path: "bar",
},
expect: false,
},
}
for _, tc := range testcases {
if tc.expect != tc.patch1.Equals(tc.patch2) {
t.Fatalf("%s: unexpected result %v", tc.name, !tc.expect)
}
}
}

View File

@@ -1,72 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package complete
import (
"os"
"strings"
"github.com/posener/complete/v2"
"github.com/posener/complete/v2/predict"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/kyaml/errors"
)
// NewCommand returns a new install-completion command
func NewCommand() *cobra.Command {
return &cobra.Command{
Use: "install-completion",
Short: commands.CompletionShort,
Long: commands.CompletionLong,
PreRunE: preRunE,
Run: run,
}
}
func preRunE(cmd *cobra.Command, args []string) error {
// install by default
if os.Getenv("COMP_INSTALL") == "" {
if err := errors.Wrap(os.Setenv("COMP_INSTALL", "1")); err != nil {
return err
}
}
return nil
}
func run(cmd *cobra.Command, args []string) {
// find the root command
for cmd.Parent() != nil {
cmd = cmd.Parent()
}
// do completion
Complete(cmd).Complete("kustomize")
}
// Complete returns a completion command for a cobra command
func Complete(cmd *cobra.Command) *complete.Command {
cc := &complete.Command{
Flags: map[string]complete.Predictor{},
Sub: map[string]*complete.Command{},
}
if strings.Contains(cmd.Use, "DIR") {
// if usage contains directory, then use a file predictor
cc.Args = predict.Dirs("*")
}
// add completion for each subcommand
for i := range cmd.Commands() {
c := cmd.Commands()[i]
name := strings.Split(c.Use, " ")[0]
cc.Sub[name] = Complete(c)
}
// add completion for each flag
cmd.Flags().VisitAll(func(flag *pflag.Flag) {
cc.Flags[flag.Name] = predict.Nothing
})
return cc
}

View File

@@ -0,0 +1,33 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package completion
import (
"os"
"github.com/spf13/cobra"
)
func NewCommand() *cobra.Command {
return &cobra.Command{
Use: "completion [bash|zsh|fish|powershell]",
Short: "Generate shell completion script",
Long: "Generate shell completion.",
DisableFlagsInUseLine: true,
ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
Args: cobra.ExactValidArgs(1),
Run: func(cmd *cobra.Command, args []string) {
switch args[0] {
case "bash":
cmd.Root().GenBashCompletion(os.Stdout)
case "zsh":
cmd.Root().GenZshCompletion(os.Stdout)
case "fish":
cmd.Root().GenFishCompletion(os.Stdout, true)
case "powershell":
cmd.Root().GenPowerShellCompletion(os.Stdout)
}
},
}
}

View File

@@ -10,6 +10,7 @@ import (
"sigs.k8s.io/kustomize/cmd/config/internal/commands" "sigs.k8s.io/kustomize/cmd/config/internal/commands"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/api" "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/api"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/tutorials" "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/tutorials"
"sigs.k8s.io/kustomize/cmd/config/runner"
) )
// Export commands publicly for composition // Export commands publicly for composition
@@ -35,13 +36,13 @@ var (
Wrap = commands.WrapCommand Wrap = commands.WrapCommand
XArgs = commands.XArgsCommand XArgs = commands.XArgsCommand
StackOnError = &commands.StackOnError StackOnError = &runner.StackOnError
ExitOnError = &commands.ExitOnError ExitOnError = &runner.ExitOnError
) )
// AddCommands adds the cfg and fn commands to kustomize. // AddCommands adds the cfg and fn commands to kustomize.
func AddCommands(root *cobra.Command, name string) *cobra.Command { func AddCommands(root *cobra.Command, name string) *cobra.Command {
commands.ExitOnError = true runner.ExitOnError = true
root.PersistentFlags().BoolVar(StackOnError, "stack-trace", false, root.PersistentFlags().BoolVar(StackOnError, "stack-trace", false,
"print a stack-trace on error") "print a stack-trace on error")

View File

@@ -1,20 +1,25 @@
## install-completion ## completion
Install shell completion. Generate shell completion.
### Synopsis ### Synopsis
Install shell completion for kustomize commands and flags -- supports bash, fish and zsh. Generate shell completion for `kustomize` -- supports bash, zsh, fish and powershell.
kustomize install-completion ### Examples
Registers the completion command with known shells (e.g. .bashrc, .bash_profile, etc): # load completion for Bash
source <(kustomize completion bash)
complete -C /Users/USER/go/bin/kustomize kustomize # install for Bash in Linux
kustomize completion bash > /etc/bash_completion.d/kustomize
Because the completion command is embedded in kustomize directly, there is no need to update # install for Bash in MacOS
it separately from the kustomize binary. kustomize completion bash > /usr/local/etc/bash_completion.d/kustomize
To uninstall shell completion run: # package for Bash
kustomize completion bash > /usr/share/bash-completion/completions/kustomize
# package for zsh
kustomize completion zsh > /usr/share/zsh/site-functions/_kustomize
COMP_UNINSTALL=1 kustomize install-completion

View File

@@ -9,15 +9,11 @@ require (
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/olekukonko/tablewriter v0.0.4 github.com/olekukonko/tablewriter v0.0.4
github.com/posener/complete/v2 v2.0.1-alpha.12
github.com/spf13/cobra v1.0.0 github.com/spf13/cobra v1.0.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.6.1 github.com/stretchr/testify v1.6.1
golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
k8s.io/apimachinery v0.17.3 k8s.io/apimachinery v0.17.3
sigs.k8s.io/kustomize/kyaml v0.9.1 sigs.k8s.io/kustomize/kyaml v0.9.3
) )
replace sigs.k8s.io/kustomize/kyaml v0.9.1 => ../../kyaml

View File

@@ -152,10 +152,6 @@ github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoA
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
@@ -226,14 +222,9 @@ github.com/paulmach/orb v0.1.3/go.mod h1:VFlX/8C+IQ1p6FTRRKzKoOPJnvEtA5G0Veuqwbu
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete/v2 v2.0.1-alpha.12 h1:0wvkuDfHb5vSZlNBYgpEH4XQHpF46MjLPHav8XC77Nc=
github.com/posener/complete/v2 v2.0.1-alpha.12/go.mod h1://JlL91cS2JV7rOl6LVHrRqBXoBUecJu3ILQPgbJiMQ=
github.com/posener/script v1.0.4 h1:nSuXW5ZdmFnQIueLB2s0qvs4oNsUloM1Zydzh75v42w=
github.com/posener/script v1.0.4/go.mod h1:Rg3ijooqulo05aGLyGsHoLmIOUzHUVK19WVgrYBPU/E=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
@@ -400,6 +391,8 @@ k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU=
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
sigs.k8s.io/kustomize/kyaml v0.9.3 h1:kZ5HnNmmnbndSXFivrAVM6u3Ik1dwu4kbpaV8KNwy8I=
sigs.k8s.io/kustomize/kyaml v0.9.3/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=

View File

@@ -11,6 +11,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext" "sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/cmd/config/runner"
"sigs.k8s.io/kustomize/kyaml/errors" "sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml" "sigs.k8s.io/kustomize/kyaml/yaml"
@@ -27,7 +28,7 @@ func NewAnnotateRunner(parent string) *AnnotateRunner {
Example: commands.AnnotateExamples, Example: commands.AnnotateExamples,
RunE: r.runE, RunE: r.runE,
} }
fixDocs(parent, c) runner.FixDocs(parent, c)
r.Command = c r.Command = c
c.Flags().StringVar(&r.Kind, "kind", "", "Resource kind to annotate") c.Flags().StringVar(&r.Kind, "kind", "", "Resource kind to annotate")
c.Flags().StringVar(&r.ApiVersion, "apiVersion", "", "Resource apiVersion to annotate") c.Flags().StringVar(&r.ApiVersion, "apiVersion", "", "Resource apiVersion to annotate")
@@ -62,29 +63,29 @@ func (r *AnnotateRunner) runE(c *cobra.Command, args []string) error {
input = []kio.Reader{rw} input = []kio.Reader{rw}
output = []kio.Writer{rw} output = []kio.Writer{rw}
return handleError(c, kio.Pipeline{ return runner.HandleError(c, kio.Pipeline{
Inputs: input, Inputs: input,
Filters: []kio.Filter{r}, Filters: []kio.Filter{r},
Outputs: output, Outputs: output,
}.Execute()) }.Execute())
} }
e := executeCmdOnPkgs{ e := runner.ExecuteCmdOnPkgs{
writer: c.OutOrStdout(), Writer: c.OutOrStdout(),
needOpenAPI: false, NeedOpenAPI: false,
recurseSubPackages: r.RecurseSubPackages, RecurseSubPackages: r.RecurseSubPackages,
cmdRunner: r, CmdRunner: r,
rootPkgPath: args[0], RootPkgPath: args[0],
} }
err := e.execute() err := e.Execute()
if err != nil { if err != nil {
return err return err
} }
return nil return nil
} }
func (r *AnnotateRunner) executeCmd(w io.Writer, pkgPath string) error { func (r *AnnotateRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
rw := &kio.LocalPackageReadWriter{ rw := &kio.LocalPackageReadWriter{
PackagePath: pkgPath, PackagePath: pkgPath,
NoDeleteFiles: true, NoDeleteFiles: true,

View File

@@ -13,6 +13,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext" "sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/cmd/config/runner"
"sigs.k8s.io/kustomize/kyaml/errors" "sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/kio/filters" "sigs.k8s.io/kustomize/kyaml/kio/filters"
@@ -30,7 +31,7 @@ func GetCatRunner(name string) *CatRunner {
RunE: r.runE, RunE: r.runE,
Args: cobra.MaximumNArgs(1), Args: cobra.MaximumNArgs(1),
} }
fixDocs(name, c) runner.FixDocs(name, c)
c.Flags().BoolVar(&r.Format, "format", true, c.Flags().BoolVar(&r.Format, "format", true,
"format resource config yaml before printing.") "format resource config yaml before printing.")
c.Flags().BoolVar(&r.KeepAnnotations, "annotate", false, c.Flags().BoolVar(&r.KeepAnnotations, "annotate", false,
@@ -95,21 +96,21 @@ func (r *CatRunner) runE(c *cobra.Command, args []string) error {
if err != nil { if err != nil {
return err return err
} }
return handleError(c, kio.Pipeline{Inputs: []kio.Reader{input}, Filters: r.catFilters(), Outputs: outputs}.Execute()) return runner.HandleError(c, kio.Pipeline{Inputs: []kio.Reader{input}, Filters: r.catFilters(), Outputs: outputs}.Execute())
} }
out := &bytes.Buffer{} out := &bytes.Buffer{}
e := executeCmdOnPkgs{ e := runner.ExecuteCmdOnPkgs{
writer: out, Writer: out,
needOpenAPI: false, NeedOpenAPI: false,
recurseSubPackages: r.RecurseSubPackages, RecurseSubPackages: r.RecurseSubPackages,
cmdRunner: r, CmdRunner: r,
rootPkgPath: args[0], RootPkgPath: args[0],
skipPkgPathPrint: true, SkipPkgPathPrint: true,
} }
err := e.execute() err := e.Execute()
if err != nil { if err != nil {
return err return err
} }
@@ -120,7 +121,7 @@ func (r *CatRunner) runE(c *cobra.Command, args []string) error {
return nil return nil
} }
func (r *CatRunner) executeCmd(w io.Writer, pkgPath string) error { func (r *CatRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
input := kio.LocalPackageReader{PackagePath: pkgPath, PackageFileName: ext.KRMFileName()} input := kio.LocalPackageReader{PackagePath: pkgPath, PackageFileName: ext.KRMFileName()}
out := &bytes.Buffer{} out := &bytes.Buffer{}
outputs, err := r.out(out) outputs, err := r.out(out)

View File

@@ -15,6 +15,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext" "sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/cmd/config/runner"
"sigs.k8s.io/kustomize/kyaml/errors" "sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/setters" "sigs.k8s.io/kustomize/kyaml/setters"
@@ -63,7 +64,7 @@ func NewCreateSetterRunner(parent string) *CreateSetterRunner {
set.Flags().BoolVarP(&r.CreateSetter.RecurseSubPackages, "recurse-subpackages", "R", false, set.Flags().BoolVarP(&r.CreateSetter.RecurseSubPackages, "recurse-subpackages", "R", false,
"creates setter recursively in all the nested subpackages") "creates setter recursively in all the nested subpackages")
set.Flags().MarkHidden("version") set.Flags().MarkHidden("version")
fixDocs(parent, set) runner.FixDocs(parent, set)
r.Command = set r.Command = set
return r return r
} }
@@ -81,7 +82,7 @@ type CreateSetterRunner struct {
} }
func (r *CreateSetterRunner) runE(c *cobra.Command, args []string) error { func (r *CreateSetterRunner) runE(c *cobra.Command, args []string) error {
return handleError(c, r.createSetter(c, args)) return runner.HandleError(c, r.createSetter(c, args))
} }
func (r *CreateSetterRunner) preRunE(c *cobra.Command, args []string) error { func (r *CreateSetterRunner) preRunE(c *cobra.Command, args []string) error {
@@ -179,16 +180,16 @@ func (r *CreateSetterRunner) processSchema() error {
func (r *CreateSetterRunner) createSetter(c *cobra.Command, args []string) error { func (r *CreateSetterRunner) createSetter(c *cobra.Command, args []string) error {
if setterVersion == "v2" { if setterVersion == "v2" {
e := executeCmdOnPkgs{ e := runner.ExecuteCmdOnPkgs{
needOpenAPI: true, NeedOpenAPI: true,
writer: c.OutOrStdout(), Writer: c.OutOrStdout(),
rootPkgPath: args[0], RootPkgPath: args[0],
recurseSubPackages: r.CreateSetter.RecurseSubPackages, RecurseSubPackages: r.CreateSetter.RecurseSubPackages,
cmdRunner: r, CmdRunner: r,
} }
err := e.execute() err := e.Execute()
if err != nil { if err != nil {
return handleError(c, err) return runner.HandleError(c, err)
} }
return nil return nil
} }
@@ -204,7 +205,7 @@ func (r *CreateSetterRunner) createSetter(c *cobra.Command, args []string) error
return nil return nil
} }
func (r *CreateSetterRunner) executeCmd(w io.Writer, pkgPath string) error { func (r *CreateSetterRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
r.CreateSetter = settersutil.SetterCreator{ r.CreateSetter = settersutil.SetterCreator{
Name: r.CreateSetter.Name, Name: r.CreateSetter.Name,
SetBy: r.CreateSetter.SetBy, SetBy: r.CreateSetter.SetBy,

View File

@@ -10,6 +10,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext" "sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/runner"
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil" "sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
) )
@@ -32,7 +33,7 @@ func NewCreateSubstitutionRunner(parent string) *CreateSubstitutionRunner {
"creates substitution recursively in all the nested subpackages") "creates substitution recursively in all the nested subpackages")
_ = cs.MarkFlagRequired("pattern") _ = cs.MarkFlagRequired("pattern")
_ = cs.MarkFlagRequired("field-value") _ = cs.MarkFlagRequired("field-value")
fixDocs(parent, cs) runner.FixDocs(parent, cs)
r.Command = cs r.Command = cs
return r return r
} }
@@ -49,22 +50,22 @@ type CreateSubstitutionRunner struct {
} }
func (r *CreateSubstitutionRunner) runE(c *cobra.Command, args []string) error { func (r *CreateSubstitutionRunner) runE(c *cobra.Command, args []string) error {
e := executeCmdOnPkgs{ e := runner.ExecuteCmdOnPkgs{
needOpenAPI: true, NeedOpenAPI: true,
writer: c.OutOrStdout(), Writer: c.OutOrStdout(),
rootPkgPath: args[0], RootPkgPath: args[0],
recurseSubPackages: r.CreateSubstitution.RecurseSubPackages, RecurseSubPackages: r.CreateSubstitution.RecurseSubPackages,
cmdRunner: r, CmdRunner: r,
} }
err := e.execute() err := e.Execute()
if err != nil { if err != nil {
return handleError(c, err) return runner.HandleError(c, err)
} }
return nil return nil
} }
func (r *CreateSubstitutionRunner) executeCmd(w io.Writer, pkgPath string) error { func (r *CreateSubstitutionRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
r.CreateSubstitution = settersutil.SubstitutionCreator{ r.CreateSubstitution = settersutil.SubstitutionCreator{
Name: r.CreateSubstitution.Name, Name: r.CreateSubstitution.Name,
FieldName: r.CreateSubstitution.FieldName, FieldName: r.CreateSubstitution.FieldName,

View File

@@ -11,6 +11,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext" "sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/cmd/config/runner"
"sigs.k8s.io/kustomize/kyaml/fieldmeta" "sigs.k8s.io/kustomize/kyaml/fieldmeta"
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil" "sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
) )
@@ -29,7 +30,7 @@ func NewDeleteSetterRunner(parent string) *DeleteSetterRunner {
} }
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", false, c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", false,
"deletes setter recursively in all the nested subpackages") "deletes setter recursively in all the nested subpackages")
fixDocs(parent, c) runner.FixDocs(parent, c)
r.Command = c r.Command = c
return r return r
@@ -56,22 +57,21 @@ func (r *DeleteSetterRunner) preRunE(c *cobra.Command, args []string) error {
} }
func (r *DeleteSetterRunner) runE(c *cobra.Command, args []string) error { func (r *DeleteSetterRunner) runE(c *cobra.Command, args []string) error {
e := executeCmdOnPkgs{ e := runner.ExecuteCmdOnPkgs{
needOpenAPI: true, NeedOpenAPI: true,
writer: c.OutOrStdout(), Writer: c.OutOrStdout(),
rootPkgPath: args[0], RootPkgPath: args[0],
recurseSubPackages: r.RecurseSubPackages, RecurseSubPackages: r.RecurseSubPackages,
cmdRunner: r, CmdRunner: r,
} }
err := e.execute() err := e.Execute()
if err != nil { if err != nil {
return handleError(c, err) return runner.HandleError(c, err)
} }
return nil return nil
} }
func (r *DeleteSetterRunner) executeCmd(w io.Writer, pkgPath string) error { func (r *DeleteSetterRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
r.DeleteSetter = settersutil.DeleterCreator{ r.DeleteSetter = settersutil.DeleterCreator{
Name: r.DeleteSetter.Name, Name: r.DeleteSetter.Name,
DefinitionPrefix: fieldmeta.SetterDefinitionPrefix, DefinitionPrefix: fieldmeta.SetterDefinitionPrefix,

View File

@@ -10,6 +10,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext" "sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/runner"
"sigs.k8s.io/kustomize/kyaml/fieldmeta" "sigs.k8s.io/kustomize/kyaml/fieldmeta"
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil" "sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
) )
@@ -25,7 +26,7 @@ func NewDeleteSubstitutionRunner(parent string) *DeleteSubstitutionRunner {
} }
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", false, c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", false,
"deletes substitution recursively in all the nested subpackages") "deletes substitution recursively in all the nested subpackages")
fixDocs(parent, c) runner.FixDocs(parent, c)
r.Command = c r.Command = c
return r return r
@@ -52,21 +53,21 @@ func (r *DeleteSubstitutionRunner) preRunE(c *cobra.Command, args []string) erro
} }
func (r *DeleteSubstitutionRunner) runE(c *cobra.Command, args []string) error { func (r *DeleteSubstitutionRunner) runE(c *cobra.Command, args []string) error {
e := executeCmdOnPkgs{ e := runner.ExecuteCmdOnPkgs{
needOpenAPI: true, NeedOpenAPI: true,
writer: c.OutOrStdout(), Writer: c.OutOrStdout(),
rootPkgPath: args[0], RootPkgPath: args[0],
recurseSubPackages: r.RecurseSubPackages, RecurseSubPackages: r.RecurseSubPackages,
cmdRunner: r, CmdRunner: r,
} }
err := e.execute() err := e.Execute()
if err != nil { if err != nil {
return handleError(c, err) return runner.HandleError(c, err)
} }
return nil return nil
} }
func (r *DeleteSubstitutionRunner) executeCmd(w io.Writer, pkgPath string) error { func (r *DeleteSubstitutionRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
r.DeleteSubstitution = settersutil.DeleterCreator{ r.DeleteSubstitution = settersutil.DeleterCreator{
Name: r.DeleteSubstitution.Name, Name: r.DeleteSubstitution.Name,
DefinitionPrefix: fieldmeta.SubstitutionDefinitionPrefix, DefinitionPrefix: fieldmeta.SubstitutionDefinitionPrefix,

View File

@@ -11,6 +11,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/cmd/config/runner"
"sigs.k8s.io/kustomize/kyaml/errors" "sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/krmfile" "sigs.k8s.io/kustomize/kyaml/krmfile"
) )
@@ -26,7 +27,7 @@ func GetInitRunner(name string) *InitRunner {
Example: commands.InitExamples, Example: commands.InitExamples,
RunE: r.runE, RunE: r.runE,
} }
fixDocs(name, c) runner.FixDocs(name, c)
r.Command = c r.Command = c
return r return r
} }

View File

@@ -14,6 +14,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext" "sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/cmd/config/runner"
"sigs.k8s.io/kustomize/kyaml/fieldmeta" "sigs.k8s.io/kustomize/kyaml/fieldmeta"
"sigs.k8s.io/kustomize/kyaml/setters" "sigs.k8s.io/kustomize/kyaml/setters"
"sigs.k8s.io/kustomize/kyaml/setters2" "sigs.k8s.io/kustomize/kyaml/setters2"
@@ -37,7 +38,7 @@ func NewListSettersRunner(parent string) *ListSettersRunner {
"include substitutions in the output") "include substitutions in the output")
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", true, c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", true,
"list setters recursively in all the nested subpackages") "list setters recursively in all the nested subpackages")
fixDocs(parent, c) runner.FixDocs(parent, c)
r.Command = c r.Command = c
return r return r
} }
@@ -67,24 +68,24 @@ func (r *ListSettersRunner) preRunE(c *cobra.Command, args []string) error {
func (r *ListSettersRunner) runE(c *cobra.Command, args []string) error { func (r *ListSettersRunner) runE(c *cobra.Command, args []string) error {
if setterVersion == "v2" { if setterVersion == "v2" {
e := executeCmdOnPkgs{ e := runner.ExecuteCmdOnPkgs{
needOpenAPI: true, NeedOpenAPI: true,
writer: c.OutOrStdout(), Writer: c.OutOrStdout(),
rootPkgPath: args[0], RootPkgPath: args[0],
recurseSubPackages: r.RecurseSubPackages, RecurseSubPackages: r.RecurseSubPackages,
cmdRunner: r, CmdRunner: r,
} }
err := e.execute() err := e.Execute()
if err != nil { if err != nil {
return handleError(c, err) return runner.HandleError(c, err)
} }
return nil return nil
} }
return handleError(c, lookup(r.Lookup, c, args)) return runner.HandleError(c, lookup(r.Lookup, c, args))
} }
func (r *ListSettersRunner) executeCmd(w io.Writer, pkgPath string) error { func (r *ListSettersRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
r.List = setters2.List{ r.List = setters2.List{
Name: r.List.Name, Name: r.List.Name,
OpenAPIFileName: ext.KRMFileName(), OpenAPIFileName: ext.KRMFileName(),
@@ -107,7 +108,7 @@ func (r *ListSettersRunner) ListSetters(w io.Writer, openAPIPath, resourcePath s
return err return err
} }
table := newTable(w, r.Markdown) table := newTable(w, r.Markdown)
table.SetHeader([]string{"NAME", "VALUE", "SET BY", "DESCRIPTION", "COUNT", "REQUIRED"}) table.SetHeader([]string{"NAME", "VALUE", "SET BY", "DESCRIPTION", "COUNT", "REQUIRED", "IS SET"})
for i := range r.List.Setters { for i := range r.List.Setters {
s := r.List.Setters[i] s := r.List.Setters[i]
v := s.Value v := s.Value
@@ -117,20 +118,23 @@ func (r *ListSettersRunner) ListSetters(w io.Writer, openAPIPath, resourcePath s
v = strings.Join(s.ListValues, ",") v = strings.Join(s.ListValues, ",")
v = fmt.Sprintf("[%s]", v) v = fmt.Sprintf("[%s]", v)
} }
var required string required := "No"
if s.Required { if s.Required {
required = "Yes" required = "Yes"
} else {
required = "No"
} }
isSet := "No"
if s.IsSet {
isSet = "Yes"
}
table.Append([]string{ table.Append([]string{
s.Name, v, s.SetBy, s.Description, fmt.Sprintf("%d", s.Count), required}) s.Name, v, s.SetBy, s.Description, fmt.Sprintf("%d", s.Count), required, isSet})
} }
table.Render() table.Render()
if len(r.List.Setters) == 0 { if len(r.List.Setters) == 0 {
// exit non-0 if no matching setters are found // exit non-0 if no matching setters are found
if ExitOnError { if runner.ExitOnError {
os.Exit(1) os.Exit(1)
} }
} }

View File

@@ -46,8 +46,8 @@ metadata:
spec: spec:
replicas: 3 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas"} replicas: 3 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas"}
`, `,
expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
replicas 3 me hello world 1 Yes replicas 3 me hello world 1 Yes No
`, `,
}, },
@@ -72,8 +72,8 @@ metadata:
spec: spec:
replicas: 3 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas"} replicas: 3 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas"}
`, `,
expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
replicas 4 me hello world 1 No replicas 4 me hello world 1 No No
`, `,
}, },
{ {
@@ -131,10 +131,10 @@ spec:
- name: nginx2 - name: nginx2
image: nginx # {"$ref": "#/definitions/io.k8s.cli.setters.image"} image: nginx # {"$ref": "#/definitions/io.k8s.cli.setters.image"}
`, `,
expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
image nginx me2 hello world 2 2 No image nginx me2 hello world 2 2 No No
replicas 3 me1 hello world 1 1 No replicas 3 me1 hello world 1 1 No No
tag 1.7.9 me3 hello world 3 1 Yes tag 1.7.9 me3 hello world 3 1 Yes No
--------------- ----------- -------------- --------------- ----------- --------------
SUBSTITUTION PATTERN REFERENCES SUBSTITUTION PATTERN REFERENCES
image IMAGE:TAG [image,tag] image IMAGE:TAG [image,tag]
@@ -207,10 +207,10 @@ spec:
- name: nginx2 - name: nginx2
image: nginx image: nginx
`, `,
expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
image nginx me2 hello world 2 3 No image nginx me2 hello world 2 3 No No
replicas 3 me1 hello world 1 2 No replicas 3 me1 hello world 1 2 No No
tag 1.7.9 me3 hello world 3 2 No tag 1.7.9 me3 hello world 3 2 No No
--------------- ----------- -------------- --------------- ----------- --------------
SUBSTITUTION PATTERN REFERENCES SUBSTITUTION PATTERN REFERENCES
image IMAGE:TAG [image,tag] image IMAGE:TAG [image,tag]
@@ -284,8 +284,8 @@ spec:
- name: nginx2 - name: nginx2
image: nginx image: nginx
`, `,
expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
image nginx me2 hello world 2 3 Yes image nginx me2 hello world 2 3 Yes No
`, `,
}, },
@@ -324,8 +324,8 @@ spec:
- "b" - "b"
- "c" - "c"
`, `,
expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
list [a,b,c] me hello world 1 Yes list [a,b,c] me hello world 1 Yes No
`, `,
}, },
@@ -390,10 +390,10 @@ openAPI:
name: my-other-setter name: my-other-setter
value: nginxotherthing value: nginxotherthing
`, `,
expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
my-image-setter nginx 2 No my-image-setter nginx 2 No No
my-other-setter nginxotherthing 1 No my-other-setter nginxotherthing 1 No No
my-tag-setter 1.7.9 2 Yes my-tag-setter 1.7.9 2 Yes Yes
------------------ ------------------------------------------------ ----------------------------------- ------------------ ------------------------------------------------ -----------------------------------
SUBSTITUTION PATTERN REFERENCES SUBSTITUTION PATTERN REFERENCES
my-image-subst ${my-image-setter}::${my-tag-setter} [my-image-setter,my-tag-setter] my-image-subst ${my-image-setter}::${my-tag-setter} [my-image-setter,my-tag-setter]
@@ -476,20 +476,20 @@ func TestListSettersSubPackages(t *testing.T) {
expected: ` expected: `
test/testdata/dataset-with-setters/mysql/ test/testdata/dataset-with-setters/mysql/
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
image mysql 1 No image mysql 1 No No
namespace myspace 1 No namespace myspace 1 No No
tag 1.7.9 1 No tag 1.7.9 1 No No
--------------- ----------------- -------------- --------------- ----------------- --------------
SUBSTITUTION PATTERN REFERENCES SUBSTITUTION PATTERN REFERENCES
image-tag ${image}:${tag} [image,tag] image-tag ${image}:${tag} [image,tag]
test/testdata/dataset-with-setters/mysql/nosetters/ test/testdata/dataset-with-setters/mysql/nosetters/
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
test/testdata/dataset-with-setters/mysql/storage/ test/testdata/dataset-with-setters/mysql/storage/
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
namespace myspace 1 No namespace myspace 1 No No
`, `,
}, },
{ {
@@ -499,10 +499,10 @@ test/testdata/dataset-with-setters/mysql/storage/
expected: ` expected: `
test/testdata/dataset-with-setters/mysql/ test/testdata/dataset-with-setters/mysql/
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
image mysql 1 No image mysql 1 No No
namespace myspace 1 No namespace myspace 1 No No
tag 1.7.9 1 No tag 1.7.9 1 No No
`, `,
}, },
} }

View File

@@ -13,6 +13,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext" "sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/cmd/config/runner"
"sigs.k8s.io/kustomize/kyaml/errors" "sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/setters" "sigs.k8s.io/kustomize/kyaml/setters"
@@ -31,7 +32,7 @@ func NewSetRunner(parent string) *SetRunner {
PreRunE: r.preRunE, PreRunE: r.preRunE,
RunE: r.runE, RunE: r.runE,
} }
fixDocs(parent, c) runner.FixDocs(parent, c)
r.Command = c r.Command = c
c.Flags().StringArrayVar(&r.Values, "values", []string{}, c.Flags().StringArrayVar(&r.Values, "values", []string{},
"optional flag, the values of the setter to be set to") "optional flag, the values of the setter to be set to")
@@ -131,26 +132,26 @@ func (r *SetRunner) preRunE(c *cobra.Command, args []string) error {
func (r *SetRunner) runE(c *cobra.Command, args []string) error { func (r *SetRunner) runE(c *cobra.Command, args []string) error {
if setterVersion == "v2" { if setterVersion == "v2" {
e := executeCmdOnPkgs{ e := runner.ExecuteCmdOnPkgs{
needOpenAPI: true, NeedOpenAPI: true,
writer: c.OutOrStdout(), Writer: c.OutOrStdout(),
rootPkgPath: args[0], RootPkgPath: args[0],
recurseSubPackages: r.Set.RecurseSubPackages, RecurseSubPackages: r.Set.RecurseSubPackages,
cmdRunner: r, CmdRunner: r,
} }
err := e.execute() err := e.Execute()
if err != nil { if err != nil {
return handleError(c, err) return runner.HandleError(c, err)
} }
return nil return nil
} }
if len(args) > 2 || c.Flag("values").Changed { if len(args) > 2 || c.Flag("values").Changed {
return handleError(c, r.perform(c, args)) return runner.HandleError(c, r.perform(c, args))
} }
return handleError(c, lookup(r.Lookup, c, args)) return runner.HandleError(c, lookup(r.Lookup, c, args))
} }
func (r *SetRunner) executeCmd(w io.Writer, pkgPath string) error { func (r *SetRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
r.Set = settersutil.FieldSetter{ r.Set = settersutil.FieldSetter{
Name: r.Set.Name, Name: r.Set.Name,
Value: r.Set.Value, Value: r.Set.Value,
@@ -162,6 +163,7 @@ func (r *SetRunner) executeCmd(w io.Writer, pkgPath string) error {
OpenAPIFileName: ext.KRMFileName(), OpenAPIFileName: ext.KRMFileName(),
ResourcesPath: pkgPath, ResourcesPath: pkgPath,
RecurseSubPackages: r.Set.RecurseSubPackages, RecurseSubPackages: r.Set.RecurseSubPackages,
IsSet: true,
} }
count, err := r.Set.Set() count, err := r.Set.Set()
if err != nil { if err != nil {

View File

@@ -10,6 +10,7 @@ import (
"path/filepath" "path/filepath"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/runner"
"sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/kio/filters" "sigs.k8s.io/kustomize/kyaml/kio/filters"
) )
@@ -135,5 +136,5 @@ func (r *WrapRunner) runE(c *cobra.Command, args []string) error {
Writer: c.OutOrStdout(), Writer: c.OutOrStdout(),
WrappingKind: kio.ResourceListKind, WrappingKind: kio.ResourceListKind,
WrappingAPIVersion: kio.ResourceListAPIVersion}}}.Execute() WrappingAPIVersion: kio.ResourceListAPIVersion}}}.Execute()
return handleError(c, err) return runner.HandleError(c, err)
} }

View File

@@ -11,6 +11,7 @@ import (
"unicode" "unicode"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/runner"
"sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml" "sigs.k8s.io/kustomize/kyaml/yaml"
) )
@@ -211,7 +212,7 @@ func (r *XArgsRunner) runE(c *cobra.Command, _ []string) error {
return err return err
} }
return handleError(c, run.Run()) return runner.HandleError(c, run.Run())
} }
func parseYNode(node *yaml.Node) string { func parseYNode(node *yaml.Node) string {

View File

@@ -11,6 +11,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext" "sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/cmd/config/runner"
"sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/sets" "sigs.k8s.io/kustomize/kyaml/sets"
"sigs.k8s.io/kustomize/kyaml/yaml" "sigs.k8s.io/kustomize/kyaml/yaml"
@@ -26,7 +27,7 @@ func GetCountRunner(name string) *CountRunner {
Example: commands.CountExamples, Example: commands.CountExamples,
RunE: r.runE, RunE: r.runE,
} }
fixDocs(name, c) runner.FixDocs(name, c)
c.Flags().BoolVar(&r.Kind, "kind", true, c.Flags().BoolVar(&r.Kind, "kind", true,
"count resources by kind.") "count resources by kind.")
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", true, c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", true,
@@ -51,24 +52,24 @@ func (r *CountRunner) runE(c *cobra.Command, args []string) error {
if len(args) == 0 { if len(args) == 0 {
input := &kio.ByteReader{Reader: c.InOrStdin()} input := &kio.ByteReader{Reader: c.InOrStdin()}
return handleError(c, kio.Pipeline{ return runner.HandleError(c, kio.Pipeline{
Inputs: []kio.Reader{input}, Inputs: []kio.Reader{input},
Outputs: r.out(c.OutOrStdout()), Outputs: r.out(c.OutOrStdout()),
}.Execute()) }.Execute())
} }
e := executeCmdOnPkgs{ e := runner.ExecuteCmdOnPkgs{
writer: c.OutOrStdout(), Writer: c.OutOrStdout(),
needOpenAPI: false, NeedOpenAPI: false,
recurseSubPackages: r.RecurseSubPackages, RecurseSubPackages: r.RecurseSubPackages,
cmdRunner: r, CmdRunner: r,
rootPkgPath: args[0], RootPkgPath: args[0],
} }
return e.execute() return e.Execute()
} }
func (r *CountRunner) executeCmd(w io.Writer, pkgPath string) error { func (r *CountRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
input := kio.LocalPackageReader{PackagePath: pkgPath, PackageFileName: ext.KRMFileName()} input := kio.LocalPackageReader{PackagePath: pkgPath, PackageFileName: ext.KRMFileName()}
err := kio.Pipeline{ err := kio.Pipeline{

View File

@@ -35,8 +35,8 @@ openAPI:
}, },
expectedStdOut: ` expectedStdOut: `
./ ./
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED NAME VALUE SET BY DESCRIPTION COUNT REQUIRED IS SET
replicas 3 1 No replicas 3 1 No No
`, `,
}, },
} }

View File

@@ -10,6 +10,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext" "sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/cmd/config/runner"
"sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/kio/filters" "sigs.k8s.io/kustomize/kyaml/kio/filters"
) )
@@ -25,7 +26,7 @@ func GetFmtRunner(name string) *FmtRunner {
RunE: r.runE, RunE: r.runE,
PreRunE: r.preRunE, PreRunE: r.preRunE,
} }
fixDocs(name, c) runner.FixDocs(name, c)
c.Flags().StringVar(&r.FilenamePattern, "pattern", filters.DefaultFilenamePattern, c.Flags().StringVar(&r.FilenamePattern, "pattern", filters.DefaultFilenamePattern,
`pattern to use for generating filenames for resources -- may contain the following `pattern to use for generating filenames for resources -- may contain the following
formatting substitution verbs {'%n': 'metadata.name', '%s': 'metadata.namespace', '%k': 'kind'}`) formatting substitution verbs {'%n': 'metadata.name', '%s': 'metadata.namespace', '%k': 'kind'}`)
@@ -74,20 +75,20 @@ func (r *FmtRunner) runE(c *cobra.Command, args []string) error {
Writer: c.OutOrStdout(), Writer: c.OutOrStdout(),
KeepReaderAnnotations: r.KeepAnnotations, KeepReaderAnnotations: r.KeepAnnotations,
} }
return handleError(c, kio.Pipeline{ return runner.HandleError(c, kio.Pipeline{
Inputs: []kio.Reader{rw}, Filters: r.fmtFilters(), Outputs: []kio.Writer{rw}}.Execute()) Inputs: []kio.Reader{rw}, Filters: r.fmtFilters(), Outputs: []kio.Writer{rw}}.Execute())
} }
for _, rootPkgPath := range args { for _, rootPkgPath := range args {
e := executeCmdOnPkgs{ e := runner.ExecuteCmdOnPkgs{
writer: c.OutOrStdout(), Writer: c.OutOrStdout(),
needOpenAPI: false, NeedOpenAPI: false,
recurseSubPackages: r.RecurseSubPackages, RecurseSubPackages: r.RecurseSubPackages,
cmdRunner: r, CmdRunner: r,
rootPkgPath: rootPkgPath, RootPkgPath: rootPkgPath,
} }
err := e.execute() err := e.Execute()
if err != nil { if err != nil {
return err return err
} }
@@ -95,7 +96,7 @@ func (r *FmtRunner) runE(c *cobra.Command, args []string) error {
return nil return nil
} }
func (r *FmtRunner) executeCmd(w io.Writer, pkgPath string) error { func (r *FmtRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
rw := &kio.LocalPackageReadWriter{ rw := &kio.LocalPackageReadWriter{
NoDeleteFiles: true, NoDeleteFiles: true,
PackagePath: pkgPath, PackagePath: pkgPath,

View File

@@ -13,6 +13,7 @@ import (
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
"sigs.k8s.io/kustomize/cmd/config/ext" "sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/cmd/config/runner"
"sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/kio/filters" "sigs.k8s.io/kustomize/kyaml/kio/filters"
) )
@@ -29,7 +30,7 @@ func GetGrepRunner(name string) *GrepRunner {
RunE: r.runE, RunE: r.runE,
Args: cobra.MaximumNArgs(2), Args: cobra.MaximumNArgs(2),
} }
fixDocs(name, c) runner.FixDocs(name, c)
c.Flags().BoolVar(&r.KeepAnnotations, "annotate", true, c.Flags().BoolVar(&r.KeepAnnotations, "annotate", true,
"annotate resources with their file origins.") "annotate resources with their file origins.")
c.Flags().BoolVarP(&r.InvertMatch, "invert-match", "", false, c.Flags().BoolVarP(&r.InvertMatch, "invert-match", "", false,
@@ -66,7 +67,7 @@ func (r *GrepRunner) preRunE(c *cobra.Command, args []string) error {
return qa.Cmp(qb), err return qa.Cmp(qb), err
} }
parts, err := parseFieldPath(args[0]) parts, err := runner.ParseFieldPath(args[0])
if err != nil { if err != nil {
return err return err
} }
@@ -105,7 +106,7 @@ func (r *GrepRunner) preRunE(c *cobra.Command, args []string) error {
func (r *GrepRunner) runE(c *cobra.Command, args []string) error { func (r *GrepRunner) runE(c *cobra.Command, args []string) error {
if len(args) == 1 { if len(args) == 1 {
input := &kio.ByteReader{Reader: c.InOrStdin()} input := &kio.ByteReader{Reader: c.InOrStdin()}
return handleError(c, kio.Pipeline{ return runner.HandleError(c, kio.Pipeline{
Inputs: []kio.Reader{input}, Inputs: []kio.Reader{input},
Filters: []kio.Filter{r.GrepFilter}, Filters: []kio.Filter{r.GrepFilter},
Outputs: []kio.Writer{kio.ByteWriter{ Outputs: []kio.Writer{kio.ByteWriter{
@@ -117,16 +118,16 @@ func (r *GrepRunner) runE(c *cobra.Command, args []string) error {
out := bytes.Buffer{} out := bytes.Buffer{}
e := executeCmdOnPkgs{ e := runner.ExecuteCmdOnPkgs{
writer: &out, Writer: &out,
needOpenAPI: false, NeedOpenAPI: false,
recurseSubPackages: r.RecurseSubPackages, RecurseSubPackages: r.RecurseSubPackages,
cmdRunner: r, CmdRunner: r,
rootPkgPath: args[1], RootPkgPath: args[1],
skipPkgPathPrint: true, SkipPkgPathPrint: true,
} }
err := e.execute() err := e.Execute()
if err != nil { if err != nil {
return err return err
} }
@@ -138,7 +139,7 @@ func (r *GrepRunner) runE(c *cobra.Command, args []string) error {
} }
func (r *GrepRunner) executeCmd(w io.Writer, pkgPath string) error { func (r *GrepRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
input := kio.LocalPackageReader{PackagePath: pkgPath, PackageFileName: ext.KRMFileName()} input := kio.LocalPackageReader{PackagePath: pkgPath, PackageFileName: ext.KRMFileName()}
out := &bytes.Buffer{} out := &bytes.Buffer{}
err := kio.Pipeline{ err := kio.Pipeline{

View File

@@ -6,6 +6,7 @@ package commands
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/cmd/config/runner"
"sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/kio/filters" "sigs.k8s.io/kustomize/kyaml/kio/filters"
) )
@@ -19,7 +20,7 @@ func GetMergeRunner(name string) *MergeRunner {
Example: commands.MergeExamples, Example: commands.MergeExamples,
RunE: r.runE, RunE: r.runE,
} }
fixDocs(name, c) runner.FixDocs(name, c)
r.Command = c r.Command = c
r.Command.Flags().BoolVar(&r.InvertOrder, "invert-order", false, r.Command.Flags().BoolVar(&r.InvertOrder, "invert-order", false,
"if true, merge Resources in the reverse order") "if true, merge Resources in the reverse order")
@@ -64,5 +65,5 @@ func (r *MergeRunner) runE(c *cobra.Command, args []string) error {
} }
filters := []kio.Filter{filters.MergeFilter{}, filters.FormatFilter{}} filters := []kio.Filter{filters.MergeFilter{}, filters.FormatFilter{}}
return handleError(c, kio.Pipeline{Inputs: inputs, Filters: filters, Outputs: outputs}.Execute()) return runner.HandleError(c, kio.Pipeline{Inputs: inputs, Filters: filters, Outputs: outputs}.Execute())
} }

View File

@@ -6,6 +6,7 @@ package commands
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/cmd/config/runner"
"sigs.k8s.io/kustomize/kyaml/kio/filters" "sigs.k8s.io/kustomize/kyaml/kio/filters"
) )
@@ -18,7 +19,7 @@ func GetMerge3Runner(name string) *Merge3Runner {
Example: commands.Merge3Examples, Example: commands.Merge3Examples,
RunE: r.runE, RunE: r.runE,
} }
fixDocs(name, c) runner.FixDocs(name, c)
c.Flags().StringVar(&r.ancestor, "ancestor", "", c.Flags().StringVar(&r.ancestor, "ancestor", "",
"Path to original package") "Path to original package")
c.Flags().StringVar(&r.fromDir, "from", "", c.Flags().StringVar(&r.fromDir, "from", "",

View File

@@ -9,6 +9,7 @@ import (
"strings" "strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/runner"
"sigs.k8s.io/kustomize/kyaml/errors" "sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil" "sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil"
@@ -29,7 +30,7 @@ func GetRunFnRunner(name string) *RunFnRunner {
RunE: r.runE, RunE: r.runE,
PreRunE: r.preRunE, PreRunE: r.preRunE,
} }
fixDocs(name, c) runner.FixDocs(name, c)
c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true, c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
"also print resources from subpackages.") "also print resources from subpackages.")
r.Command = c r.Command = c
@@ -103,7 +104,7 @@ type RunFnRunner struct {
} }
func (r *RunFnRunner) runE(c *cobra.Command, args []string) error { func (r *RunFnRunner) runE(c *cobra.Command, args []string) error {
return handleError(c, r.RunFns.Execute()) return runner.HandleError(c, r.RunFns.Execute())
} }
// getContainerFunctions parses the commandline flags and arguments into explicit // getContainerFunctions parses the commandline flags and arguments into explicit

View File

@@ -6,6 +6,7 @@ package commands
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/cmd/config/runner"
"sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/kio/kioutil" "sigs.k8s.io/kustomize/kyaml/kio/kioutil"
) )
@@ -21,7 +22,7 @@ func GetSinkRunner(name string) *SinkRunner {
RunE: r.runE, RunE: r.runE,
Args: cobra.MaximumNArgs(1), Args: cobra.MaximumNArgs(1),
} }
fixDocs(name, c) runner.FixDocs(name, c)
r.Command = c r.Command = c
return r return r
} }
@@ -49,5 +50,5 @@ func (r *SinkRunner) runE(c *cobra.Command, args []string) error {
err := kio.Pipeline{ err := kio.Pipeline{
Inputs: []kio.Reader{&kio.ByteReader{Reader: c.InOrStdin()}}, Inputs: []kio.Reader{&kio.ByteReader{Reader: c.InOrStdin()}},
Outputs: outputs}.Execute() Outputs: outputs}.Execute()
return handleError(c, err) return runner.HandleError(c, err)
} }

View File

@@ -8,6 +8,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/cmd/config/runner"
"sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml" "sigs.k8s.io/kustomize/kyaml/yaml"
) )
@@ -22,7 +23,7 @@ func GetSourceRunner(name string) *SourceRunner {
Example: commands.SourceExamples, Example: commands.SourceExamples,
RunE: r.runE, RunE: r.runE,
} }
fixDocs(name, c) runner.FixDocs(name, c)
c.Flags().StringVar(&r.WrapKind, "wrap-kind", kio.ResourceListKind, c.Flags().StringVar(&r.WrapKind, "wrap-kind", kio.ResourceListKind,
"output using this format.") "output using this format.")
c.Flags().StringVar(&r.WrapApiVersion, "wrap-version", kio.ResourceListAPIVersion, c.Flags().StringVar(&r.WrapApiVersion, "wrap-version", kio.ResourceListAPIVersion,
@@ -78,5 +79,5 @@ func (r *SourceRunner) runE(c *cobra.Command, args []string) error {
} }
err := kio.Pipeline{Inputs: inputs, Outputs: outputs}.Execute() err := kio.Pipeline{Inputs: inputs, Outputs: outputs}.Execute()
return handleError(c, err) return runner.HandleError(c, err)
} }

View File

@@ -9,6 +9,7 @@ import (
"sigs.k8s.io/kustomize/cmd/config/ext" "sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/cmd/config/runner"
"sigs.k8s.io/kustomize/kyaml/kio/filters" "sigs.k8s.io/kustomize/kyaml/kio/filters"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@@ -26,7 +27,7 @@ func GetTreeRunner(name string) *TreeRunner {
RunE: r.runE, RunE: r.runE,
Args: cobra.MaximumNArgs(1), Args: cobra.MaximumNArgs(1),
} }
fixDocs(name, c) runner.FixDocs(name, c)
// TODO(pwittrock): Figure out if these are the right things to expose, and consider making it // TODO(pwittrock): Figure out if these are the right things to expose, and consider making it
// a list of options instead of individual flags // a list of options instead of individual flags
@@ -91,7 +92,7 @@ func (r *TreeRunner) runE(c *cobra.Command, args []string) error {
var fields []kio.TreeWriterField var fields []kio.TreeWriterField
for _, field := range r.fields { for _, field := range r.fields {
path, err := parseFieldPath(field) path, err := runner.ParseFieldPath(field)
if err != nil { if err != nil {
return err return err
} }
@@ -155,7 +156,7 @@ func (r *TreeRunner) runE(c *cobra.Command, args []string) error {
ExcludeNonLocalConfig: r.excludeNonLocal, ExcludeNonLocalConfig: r.excludeNonLocal,
}} }}
return handleError(c, kio.Pipeline{ return runner.HandleError(c, kio.Pipeline{
Inputs: []kio.Reader{input}, Inputs: []kio.Reader{input},
Filters: fltrs, Filters: fltrs,
Outputs: []kio.Writer{kio.TreeWriter{ Outputs: []kio.Writer{kio.TreeWriter{

View File

@@ -35,22 +35,26 @@ var CatExamples = `
# unwrap Resource config from a directory in an ResourceList # unwrap Resource config from a directory in an ResourceList
... | kustomize cfg cat` ... | kustomize cfg cat`
var CompletionShort = `Install shell completion.` var CompletionShort = `Generate shell completion.`
var CompletionLong = ` var CompletionLong = `
Install shell completion for kustomize commands and flags -- supports bash, fish and zsh. Generate shell completion for ` + "`" + `kustomize` + "`" + ` -- supports bash, zsh, fish and powershell.
`
var CompletionExamples = `
# load completion for Bash
source <(kustomize completion bash)
kustomize install-completion # install for Bash in Linux
kustomize completion bash > /etc/bash_completion.d/kustomize
Registers the completion command with known shells (e.g. .bashrc, .bash_profile, etc): # install for Bash in MacOS
kustomize completion bash > /usr/local/etc/bash_completion.d/kustomize
complete -C /Users/USER/go/bin/kustomize kustomize # package for Bash
kustomize completion bash > /usr/share/bash-completion/completions/kustomize
Because the completion command is embedded in kustomize directly, there is no need to update # package for zsh
it separately from the kustomize binary. kustomize completion zsh > /usr/share/zsh/site-functions/_kustomize
`
To uninstall shell completion run:
COMP_UNINSTALL=1 kustomize install-completion`
var CountShort = `[Alpha] Count Resources Config from a local directory.` var CountShort = `[Alpha] Count Resources Config from a local directory.`
var CountLong = ` var CountLong = `

View File

@@ -1,7 +1,7 @@
// Copyright 2019 The Kubernetes Authors. // Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
package commands package runner
import ( import (
"fmt" "fmt"
@@ -17,72 +17,72 @@ import (
"sigs.k8s.io/kustomize/kyaml/pathutil" "sigs.k8s.io/kustomize/kyaml/pathutil"
) )
// cmdRunner interface holds executeCmd definition which executes respective command's // CmdRunner interface holds ExecuteCmd definition which executes respective command's
// implementation on single package // implementation on single package
type cmdRunner interface { type CmdRunner interface {
executeCmd(w io.Writer, pkgPath string) error ExecuteCmd(w io.Writer, pkgPath string) error
} }
// executeCmdOnPkgs struct holds the parameters necessary to // ExecuteCmdOnPkgs struct holds the parameters necessary to
// execute the filter command on packages in rootPkgPath // execute the filter command on packages in rootPkgPath
type executeCmdOnPkgs struct { type ExecuteCmdOnPkgs struct {
rootPkgPath string RootPkgPath string
recurseSubPackages bool RecurseSubPackages bool
needOpenAPI bool NeedOpenAPI bool
cmdRunner cmdRunner CmdRunner CmdRunner
writer io.Writer Writer io.Writer
skipPkgPathPrint bool SkipPkgPathPrint bool
} }
// executeCmdOnPkgs takes the function definition for a command to be executed on single package, applies that definition // ExecuteCmdOnPkgs takes the function definition for a command to be executed on single package, applies that definition
// recursively on all the subpackages present in rootPkgPath if recurseSubPackages is true, else applies the command on rootPkgPath only // recursively on all the subpackages present in rootPkgPath if recurseSubPackages is true, else applies the command on rootPkgPath only
func (e executeCmdOnPkgs) execute() error { func (e ExecuteCmdOnPkgs) Execute() error {
pkgsPaths, err := pathutil.DirsWithFile(e.rootPkgPath, ext.KRMFileName(), e.recurseSubPackages) pkgsPaths, err := pathutil.DirsWithFile(e.RootPkgPath, ext.KRMFileName(), e.RecurseSubPackages)
if err != nil { if err != nil {
return err return err
} }
if len(pkgsPaths) == 0 { if len(pkgsPaths) == 0 {
// at this point, there are no openAPI files in the rootPkgPath // at this point, there are no openAPI files in the rootPkgPath
if e.needOpenAPI { if e.NeedOpenAPI {
// few executions need openAPI file to be present(ex: setters commands), if true throw an error // few executions need openAPI file to be present(ex: setters commands), if true throw an error
return errors.Errorf("unable to find %q in package %q", ext.KRMFileName(), e.rootPkgPath) return errors.Errorf("unable to find %q in package %q", ext.KRMFileName(), e.RootPkgPath)
} }
// add root path for commands which doesn't need openAPI(ex: annotate, fmt) // add root path for commands which doesn't need openAPI(ex: annotate, fmt)
pkgsPaths = []string{e.rootPkgPath} pkgsPaths = []string{e.RootPkgPath}
} }
// for commands which doesn't need openAPI file, make sure that the root package is // for commands which doesn't need openAPI file, make sure that the root package is
// included all the times // included all the times
if !e.needOpenAPI && !containsString(pkgsPaths, e.rootPkgPath) { if !e.NeedOpenAPI && !containsString(pkgsPaths, e.RootPkgPath) {
pkgsPaths = append([]string{e.rootPkgPath}, pkgsPaths...) pkgsPaths = append([]string{e.RootPkgPath}, pkgsPaths...)
} }
for i := range pkgsPaths { for i := range pkgsPaths {
pkgPath := pkgsPaths[i] pkgPath := pkgsPaths[i]
// Add schema present in openAPI file for current package // Add schema present in openAPI file for current package
if e.needOpenAPI { if e.NeedOpenAPI {
if err := openapi.AddSchemaFromFile(filepath.Join(pkgPath, ext.KRMFileName())); err != nil { if err := openapi.AddSchemaFromFile(filepath.Join(pkgPath, ext.KRMFileName())); err != nil {
return err return err
} }
} }
if !e.skipPkgPathPrint { if !e.SkipPkgPathPrint {
fmt.Fprintf(e.writer, "%s/\n", pkgPath) fmt.Fprintf(e.Writer, "%s/\n", pkgPath)
} }
err := e.cmdRunner.executeCmd(e.writer, pkgPath) err := e.CmdRunner.ExecuteCmd(e.Writer, pkgPath)
if err != nil { if err != nil {
return err return err
} }
if i != len(pkgsPaths)-1 { if i != len(pkgsPaths)-1 {
fmt.Fprint(e.writer, "\n") fmt.Fprint(e.Writer, "\n")
} }
// Delete schema present in openAPI file for current package // Delete schema present in openAPI file for current package
if e.needOpenAPI { if e.NeedOpenAPI {
if err := openapi.DeleteSchemaInFile(filepath.Join(pkgPath, ext.KRMFileName())); err != nil { if err := openapi.DeleteSchemaInFile(filepath.Join(pkgPath, ext.KRMFileName())); err != nil {
return err return err
} }
@@ -91,8 +91,8 @@ func (e executeCmdOnPkgs) execute() error {
return nil return nil
} }
// parseFieldPath parse a flag value into a field path // ParseFieldPath parse a flag value into a field path
func parseFieldPath(path string) ([]string, error) { func ParseFieldPath(path string) ([]string, error) {
// fixup '\.' so we don't split on it // fixup '\.' so we don't split on it
match := strings.ReplaceAll(path, "\\.", "$$$$") match := strings.ReplaceAll(path, "\\.", "$$$$")
parts := strings.Split(match, ".") parts := strings.Split(match, ".")
@@ -118,7 +118,7 @@ func parseFieldPath(path string) ([]string, error) {
return newParts, nil return newParts, nil
} }
func handleError(c *cobra.Command, err error) error { func HandleError(c *cobra.Command, err error) error {
if err == nil { if err == nil {
return nil return nil
} }
@@ -145,7 +145,7 @@ var StackOnError bool
const cmdName = "kustomize config" const cmdName = "kustomize config"
// FixDocs replaces instances of old with new in the docs for c // FixDocs replaces instances of old with new in the docs for c
func fixDocs(new string, c *cobra.Command) { func FixDocs(new string, c *cobra.Command) {
c.Use = strings.ReplaceAll(c.Use, cmdName, new) c.Use = strings.ReplaceAll(c.Use, cmdName, new)
c.Short = strings.ReplaceAll(c.Short, cmdName, new) c.Short = strings.ReplaceAll(c.Short, cmdName, new)
c.Long = strings.ReplaceAll(c.Long, cmdName, new) c.Long = strings.ReplaceAll(c.Long, cmdName, new)

View File

@@ -1,7 +1,7 @@
// Copyright 2019 The Kubernetes Authors. // Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package commands package runner
import ( import (
"bytes" "bytes"
@@ -76,14 +76,14 @@ ${baseDir}/subpkg2/subpkg3/
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
actual := &bytes.Buffer{} actual := &bytes.Buffer{}
r := &TestRunner{} r := &TestRunner{}
e := executeCmdOnPkgs{ e := ExecuteCmdOnPkgs{
needOpenAPI: test.needOpenAPI, NeedOpenAPI: test.needOpenAPI,
writer: actual, Writer: actual,
rootPkgPath: filepath.Join(dir, test.pkgPath), RootPkgPath: filepath.Join(dir, test.pkgPath),
recurseSubPackages: test.recurse, RecurseSubPackages: test.recurse,
cmdRunner: r, CmdRunner: r,
} }
err := e.execute() err := e.Execute()
if test.errMsg == "" { if test.errMsg == "" {
if !assert.NoError(t, err) { if !assert.NoError(t, err) {
t.FailNow() t.FailNow()
@@ -170,7 +170,7 @@ func createTestDirStructure(dir string) error {
type TestRunner struct{} type TestRunner struct{}
func (r *TestRunner) executeCmd(w io.Writer, pkgPath string) error { func (r *TestRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
children, err := ioutil.ReadDir(pkgPath) children, err := ioutil.ReadDir(pkgPath)
if err != nil { if err != nil {
return err return err

View File

@@ -482,8 +482,8 @@ k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw= mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw=
sigs.k8s.io/kustomize/kyaml v0.9.1 h1:T7aNUraSioQp0NHJZtYjIhL/q8mqRzCiHcAKdvo09go= sigs.k8s.io/kustomize/kyaml v0.9.3 h1:kZ5HnNmmnbndSXFivrAVM6u3Ik1dwu4kbpaV8KNwy8I=
sigs.k8s.io/kustomize/kyaml v0.9.1/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw= sigs.k8s.io/kustomize/kyaml v0.9.3/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=

8
cmd/prchecker/go.mod Normal file
View File

@@ -0,0 +1,8 @@
module sigs.k8s.io/kustomize/cmd/prchecker
go 1.15
require (
github.com/google/go-github v17.0.0+incompatible
github.com/google/go-querystring v1.0.0 // indirect
)

4
cmd/prchecker/go.sum Normal file
View File

@@ -0,0 +1,4 @@
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=

View File

@@ -1,12 +1,16 @@
// multi-module-span script: // prchecker examines pull requests
// A script which can detect when a pull request would make changes which
// span a series of restricted directories (ex: multiple go modules or projects)
// //
// When a pull request includes files which span two modules the script will // - When a PR includes files from multiple modules that we'd rather not
// exit with a non-zero exit code. // modify at the same time (in an effort to have more self-contained
// release notes), the script will exit with a non-zero exit code.
// //
// Running: // Usage:
// go run multi-module-span.go -owner=kubernetes-sigs -repo=kustomize -pr=2997 cmd/config api/ kustomize/ kyaml/ //
// go run . \
// -owner=kubernetes-sigs \
// -repo=kustomize \
// -pr=2997 \
// cmd/config api kustomize kyaml
package main package main

View File

@@ -251,8 +251,15 @@ specification of the cluster's desired state to
point deployments to _new_ configMaps with _new_ names. point deployments to _new_ configMaps with _new_ names.
`kustomize` makes this easy with its `kustomize` makes this easy with its
`configMapGenerator` directive and associated naming `configMapGenerator` directive and associated naming
controls. A GC process in the k8s master eventually controls.
deletes unused configMaps.
To remove outdated configMaps add a label
to your resource, for example, kustomize-cleanup="true",
and then you can use `kustomize` to prune old resources^
> ```
> kustomize build | kubectl apply --prune -f- -l kustomize-cleanup="true"
> ```
### Create and use the overlay for _production_ ### Create and use the overlay for _production_

View File

@@ -4,13 +4,13 @@
## ConfigMap generation and rolling updates ## ConfigMap generation and rolling updates
Kustomize provides two ways of adding ConfigMap in one `kustomization`, either by declaring ConfigMap as a [resource] or declaring ConfigMap from a ConfigMapGenerator. The formats inside `kustomization.yaml` are Kustomize provides two ways of adding ConfigMap in one `kustomization`, either by declaring ConfigMap as a [resource] or declaring ConfigMap from a ConfigMapGenerator. The formats inside `kustomization.yaml` are
> ``` > ```
> # declare ConfigMap as a resource > # declare ConfigMap as a resource
> resources: > resources:
> - configmap.yaml > - configmap.yaml
> >
> # declare ConfigMap from a ConfigMapGenerator > # declare ConfigMap from a ConfigMapGenerator
> configMapGenerator: > configMapGenerator:
> - name: a-configmap > - name: a-configmap
@@ -28,7 +28,9 @@ In this demo, the same [hello_world](helloWorld/README.md) is used while the Con
### Establish base and staging ### Establish base and staging
Establish the base with a configMapGenerator Establish the base with a configMapGenerator
<!-- @establishBase @testAgainstLatestRelease --> <!-- @establishBase @testAgainstLatestRelease -->
``` ```
DEMO_HOME=$(mktemp -d) DEMO_HOME=$(mktemp -d)
@@ -46,16 +48,18 @@ commonLabels:
resources: resources:
- deployment.yaml - deployment.yaml
- service.yaml - service.yaml
configMapGenerator: configMapGenerator:
- name: the-map - name: the-map
literals: literals:
- altGreeting=Good Morning! - altGreeting=Good Morning!
- enableRisky="false" - enableRisky="false"
EOF EOF
``` ```
Establish the staging with a patch applied to the ConfigMap Establish the staging with a patch applied to the ConfigMap
<!-- @establishStaging @testAgainstLatestRelease --> <!-- @establishStaging @testAgainstLatestRelease -->
``` ```
OVERLAYS=$DEMO_HOME/overlays OVERLAYS=$DEMO_HOME/overlays
mkdir -p $OVERLAYS/staging mkdir -p $OVERLAYS/staging
@@ -92,8 +96,8 @@ configured with data from a configMap.
The deployment refers to this map by name: The deployment refers to this map by name:
<!-- @showDeployment @testAgainstLatestRelease --> <!-- @showDeployment @testAgainstLatestRelease -->
``` ```
grep -C 2 configMapKeyRef $BASE/deployment.yaml grep -C 2 configMapKeyRef $BASE/deployment.yaml
``` ```
@@ -106,12 +110,12 @@ changed, so such updates have no effect.
The recommended way to change a deployment's The recommended way to change a deployment's
configuration is to configuration is to
1. create a new configMap with a new name, 1. create a new configMap with a new name,
1. patch the _deployment_, modifying the name value of 1. patch the _deployment_, modifying the name value of
the appropriate `configMapKeyRef` field. the appropriate `configMapKeyRef` field.
This latter change initiates rolling update to the pods This latter change initiates rolling update to the pods
in the deployment. The older configMap, when no longer in the deployment. The older configMap, when no longer
referenced by any other resource, is eventually [garbage referenced by any other resource, is eventually [garbage
collected](/../../issues/242). collected](/../../issues/242).
@@ -120,6 +124,7 @@ collected](/../../issues/242).
The _staging_ [variant] here has a configMap [patch]: The _staging_ [variant] here has a configMap [patch]:
<!-- @showMapPatch @testAgainstLatestRelease --> <!-- @showMapPatch @testAgainstLatestRelease -->
``` ```
cat $OVERLAYS/staging/map.yaml cat $OVERLAYS/staging/map.yaml
``` ```
@@ -131,6 +136,7 @@ resource spec.
The ConfigMap it modifies is declared from a configMapGenerator. The ConfigMap it modifies is declared from a configMapGenerator.
<!-- @showMapBase @testAgainstLatestRelease --> <!-- @showMapBase @testAgainstLatestRelease -->
``` ```
grep -C 4 configMapGenerator $BASE/kustomization.yaml grep -C 4 configMapGenerator $BASE/kustomization.yaml
``` ```
@@ -139,11 +145,12 @@ For a patch to work, the names in the `metadata/name`
fields must match. fields must match.
However, the name values specified in the file are However, the name values specified in the file are
_not_ what gets used in the cluster. By design, _not_ what gets used in the cluster. By design,
kustomize modifies names of ConfigMaps declared from ConfigMapGenerator. To see the names kustomize modifies names of ConfigMaps declared from ConfigMapGenerator. To see the names
ultimately used in the cluster, just run kustomize: ultimately used in the cluster, just run kustomize:
<!-- @grepStagingName @testAgainstLatestRelease --> <!-- @grepStagingName @testAgainstLatestRelease -->
``` ```
kustomize build $OVERLAYS/staging |\ kustomize build $OVERLAYS/staging |\
grep -B 8 -A 1 staging-the-map grep -B 8 -A 1 staging-the-map
@@ -161,7 +168,8 @@ The suffix to the configMap name is generated from a
hash of the maps content - in this case the name suffix hash of the maps content - in this case the name suffix
is _5276h4th55_: is _5276h4th55_:
<!-- @grepStagingHash --> <!-- @grepStagingHash @testAgainstLatestRelease -->
``` ```
kustomize build $OVERLAYS/staging | grep 5276h4th55 kustomize build $OVERLAYS/staging | grep 5276h4th55
``` ```
@@ -170,6 +178,7 @@ Now modify the map patch, to change the greeting
the server will use: the server will use:
<!-- @changeMap @testAgainstLatestRelease --> <!-- @changeMap @testAgainstLatestRelease -->
``` ```
sed -i.bak 's/pineapple/kiwi/' $OVERLAYS/staging/map.yaml sed -i.bak 's/pineapple/kiwi/' $OVERLAYS/staging/map.yaml
``` ```
@@ -184,6 +193,7 @@ kustomize build $OVERLAYS/staging |\
Run kustomize again to see the new configMap names: Run kustomize again to see the new configMap names:
<!-- @grepStagingName @testAgainstLatestRelease --> <!-- @grepStagingName @testAgainstLatestRelease -->
``` ```
kustomize build $OVERLAYS/staging |\ kustomize build $OVERLAYS/staging |\
grep -B 8 -A 1 staging-the-map grep -B 8 -A 1 staging-the-map
@@ -194,7 +204,8 @@ in three new names ending in _c2g8fcbf88_ - one in the
configMap name itself, and two in the deployment that configMap name itself, and two in the deployment that
uses the map: uses the map:
<!-- @countHashes --> <!-- @countHashes @testAgainstLatestRelease -->
``` ```
test 3 == \ test 3 == \
$(kustomize build $OVERLAYS/staging | grep c2g8fcbf88 | wc -l); \ $(kustomize build $OVERLAYS/staging | grep c2g8fcbf88 | wc -l); \
@@ -204,7 +215,7 @@ test 3 == \
Applying these resources to the cluster will result in Applying these resources to the cluster will result in
a rolling update of the deployments pods, retargetting a rolling update of the deployments pods, retargetting
them from the _5276h4th55_ maps to the _c2g8fcbf88_ them from the _5276h4th55_ maps to the _c2g8fcbf88_
maps. The system will later garbage collect the maps. The system will later garbage collect the
unused maps. unused maps.
## Rollback ## Rollback

View File

@@ -102,7 +102,7 @@ For Spring Boot application, we can set an active profile through the environmen
the application will pick up an extra `application-<profile>.properties` file. With this, we can customize the configMap in two the application will pick up an extra `application-<profile>.properties` file. With this, we can customize the configMap in two
steps. Add an environment variable through the patch and add a file to the configMap. steps. Add an environment variable through the patch and add a file to the configMap.
<!-- @customizeConfigMap @testAgainstLatestRelease --> <!-- @customizeConfigMap -->
``` ```
cat <<EOF >$DEMO_HOME/patch.yaml cat <<EOF >$DEMO_HOME/patch.yaml
apiVersion: apps/v1 apiVersion: apps/v1
@@ -119,7 +119,7 @@ spec:
value: prod value: prod
EOF EOF
kustomize edit add patch patch.yaml kustomize edit add patch --path patch.yaml --name sbdemo --kind Deployment --group apps --version v1
cat <<EOF >$DEMO_HOME/application-prod.properties cat <<EOF >$DEMO_HOME/application-prod.properties
spring.jpa.hibernate.ddl-auto=update spring.jpa.hibernate.ddl-auto=update
@@ -281,20 +281,35 @@ The output contains
Add these patches to the kustomization: Add these patches to the kustomization:
<!-- @addPatch @testAgainstLatestRelease --> <!-- @addPatch -->
``` ```
cd $DEMO_HOME cd $DEMO_HOME
kustomize edit add patch memorylimit_patch.yaml kustomize edit add patch --path memorylimit_patch.yaml --name sbdemo --kind Deployment --group apps --version v1
kustomize edit add patch healthcheck_patch.yaml kustomize edit add patch --path healthcheck_patch.yaml --name sbdemo --kind Deployment --group apps --version v1
``` ```
`kustomization.yaml` should have patches field: `kustomization.yaml` should have patches field:
> ``` > ```
> patchesStrategicMerge: > patches:
> - patch.yaml > - path: patch.yaml
> - memorylimit_patch.yaml > target:
> - healthcheck_patch.yaml > group: apps
> version: v1
> kind: Deployment
> name: sbdemo
> - path: memorylimit_patch.yaml
> target:
> group: apps
> version: v1
> kind: Deployment
> name: sbdemo
> - path: healthcheck_patch.yaml
> target:
> group: apps
> version: v1
> kind: Deployment
> name: sbdemo
> ``` > ```
The output of the following command can now be applied The output of the following command can now be applied

View File

@@ -5,6 +5,7 @@
## ConfigMap 的生成和滚动更新 ## ConfigMap 的生成和滚动更新
kustomize 提供了两种添加 ConfigMap 的方法: kustomize 提供了两种添加 ConfigMap 的方法:
- 将 ConfigMap 声明为 [resource] - 将 ConfigMap 声明为 [resource]
- 通过 ConfigMapGenerator 声明 ConfigMap - 通过 ConfigMapGenerator 声明 ConfigMap
@@ -14,7 +15,7 @@ kustomize 提供了两种添加 ConfigMap 的方法:
> # 将 ConfigMap 声明为 resource > # 将 ConfigMap 声明为 resource
> resources: > resources:
> - configmap.yaml > - configmap.yaml
> >
> # 在 ConfigMapGenerator 中声明 ConfigMap > # 在 ConfigMapGenerator 中声明 ConfigMap
> configMapGenerator: > configMapGenerator:
> - name: a-configmap > - name: a-configmap
@@ -30,7 +31,9 @@ kustomize 提供了两种添加 ConfigMap 的方法:
### 建立 base 和 staging ### 建立 base 和 staging
使用 configMapGenerator 建立 base 使用 configMapGenerator 建立 base
<!-- @establishBase @testAgainstLatestRelease --> <!-- @establishBase @testAgainstLatestRelease -->
``` ```
DEMO_HOME=$(mktemp -d) DEMO_HOME=$(mktemp -d)
@@ -48,16 +51,18 @@ commonLabels:
resources: resources:
- deployment.yaml - deployment.yaml
- service.yaml - service.yaml
configMapGenerator: configMapGenerator:
- name: the-map - name: the-map
literals: literals:
- altGreeting=Good Morning! - altGreeting=Good Morning!
- enableRisky="false" - enableRisky="false"
EOF EOF
``` ```
通过应用 ConfigMap patch 的方式建立 staging 通过应用 ConfigMap patch 的方式建立 staging
<!-- @establishStaging @testAgainstLatestRelease --> <!-- @establishStaging @testAgainstLatestRelease -->
``` ```
OVERLAYS=$DEMO_HOME/overlays OVERLAYS=$DEMO_HOME/overlays
mkdir -p $OVERLAYS/staging mkdir -p $OVERLAYS/staging
@@ -94,6 +99,7 @@ EOF
deployment 按照名称引用此 ConfigMap deployment 按照名称引用此 ConfigMap
<!-- @showDeployment @testAgainstLatestRelease --> <!-- @showDeployment @testAgainstLatestRelease -->
``` ```
grep -C 2 configMapKeyRef $BASE/deployment.yaml grep -C 2 configMapKeyRef $BASE/deployment.yaml
``` ```
@@ -102,16 +108,17 @@ grep -C 2 configMapKeyRef $BASE/deployment.yaml
更改 Deployment 配置的推荐方法是: 更改 Deployment 配置的推荐方法是:
1. 使用新名称创建一个新的 configMap 1. 使用新名称创建一个新的 configMap
2. 为_deployment_ 添加 patch修改相应 `configMapKeyRef` 字段的名称值。 2. 为*deployment* 添加 patch修改相应 `configMapKeyRef` 字段的名称值。
后一种更改会启动对 deployment 中的 pod 的滚动更新。旧的 configMap 在不再被任何其他资源引用时最终会被[垃圾回收](/../../issues/242)。 后一种更改会启动对 deployment 中的 pod 的滚动更新。旧的 configMap 在不再被任何其他资源引用时最终会被[垃圾回收](/../../issues/242)。
### 如何使用 kustomize ### 如何使用 kustomize
_staging_ 的 [variant] 包含一个 configMap 的 [patch] _staging_ 的 [variant] 包含一个 configMap 的 [patch]
<!-- @showMapPatch @testAgainstLatestRelease --> <!-- @showMapPatch @testAgainstLatestRelease -->
``` ```
cat $OVERLAYS/staging/map.yaml cat $OVERLAYS/staging/map.yaml
``` ```
@@ -121,6 +128,7 @@ cat $OVERLAYS/staging/map.yaml
在 ConfigMapGenerator 中声明 ConfigMap 的修改。 在 ConfigMapGenerator 中声明 ConfigMap 的修改。
<!-- @showMapBase @testAgainstLatestRelease --> <!-- @showMapBase @testAgainstLatestRelease -->
``` ```
grep -C 4 configMapGenerator $BASE/kustomization.yaml grep -C 4 configMapGenerator $BASE/kustomization.yaml
``` ```
@@ -130,6 +138,7 @@ grep -C 4 configMapGenerator $BASE/kustomization.yaml
但是文件中指定的名称值不是群集中使用的名称值。根据设计kustomize 修改从 ConfigMapGenerator 声明的 ConfigMaps 的名称。要查看最终在群集中使用的名称,只需运行 kustomize 但是文件中指定的名称值不是群集中使用的名称值。根据设计kustomize 修改从 ConfigMapGenerator 声明的 ConfigMaps 的名称。要查看最终在群集中使用的名称,只需运行 kustomize
<!-- @grepStagingName @testAgainstLatestRelease --> <!-- @grepStagingName @testAgainstLatestRelease -->
``` ```
kustomize build $OVERLAYS/staging |\ kustomize build $OVERLAYS/staging |\
grep -B 8 -A 1 staging-the-map grep -B 8 -A 1 staging-the-map
@@ -141,7 +150,8 @@ kustomize build $OVERLAYS/staging |\
configMap 名称的后缀是由 map 内容的哈希生成的 - 在这种情况下,名称后缀是 _5276h4th55_ configMap 名称的后缀是由 map 内容的哈希生成的 - 在这种情况下,名称后缀是 _5276h4th55_
<!-- @grepStagingHash --> <!-- @grepStagingHash @testAgainstLatestRelease -->
``` ```
kustomize build $OVERLAYS/staging | grep 5276h4th55 kustomize build $OVERLAYS/staging | grep 5276h4th55
``` ```
@@ -149,6 +159,7 @@ kustomize build $OVERLAYS/staging | grep 5276h4th55
现在修改 map patch ,更改该服务将使用的问候消息: 现在修改 map patch ,更改该服务将使用的问候消息:
<!-- @changeMap @testAgainstLatestRelease --> <!-- @changeMap @testAgainstLatestRelease -->
``` ```
sed -i.bak 's/pineapple/kiwi/' $OVERLAYS/staging/map.yaml sed -i.bak 's/pineapple/kiwi/' $OVERLAYS/staging/map.yaml
``` ```
@@ -163,6 +174,7 @@ kustomize build $OVERLAYS/staging |\
再次运行 kustomize 查看新的 configMap 名称: 再次运行 kustomize 查看新的 configMap 名称:
<!-- @grepStagingName @testAgainstLatestRelease --> <!-- @grepStagingName @testAgainstLatestRelease -->
``` ```
kustomize build $OVERLAYS/staging |\ kustomize build $OVERLAYS/staging |\
grep -B 8 -A 1 staging-the-map grep -B 8 -A 1 staging-the-map
@@ -170,7 +182,8 @@ kustomize build $OVERLAYS/staging |\
确认 configMap 内容的更改将会生成以 _c2g8fcbf88_ 结尾的三个新名称 - 一个在 configMap 的名称中,另两个在使用 ConfigMap 的 deployment 中: 确认 configMap 内容的更改将会生成以 _c2g8fcbf88_ 结尾的三个新名称 - 一个在 configMap 的名称中,另两个在使用 ConfigMap 的 deployment 中:
<!-- @countHashes --> <!-- @countHashes @testAgainstLatestRelease -->
``` ```
test 3 == \ test 3 == \
$(kustomize build $OVERLAYS/staging | grep c2g8fcbf88 | wc -l); \ $(kustomize build $OVERLAYS/staging | grep c2g8fcbf88 | wc -l); \

View File

@@ -89,7 +89,7 @@ cat kustomization.yaml
1. 通过 patch 添加一个环境变量 1. 通过 patch 添加一个环境变量
2. 将文件添加到 ConfigMap 中 2. 将文件添加到 ConfigMap 中
<!-- @customizeConfigMap @testAgainstLatestRelease --> <!-- @customizeConfigMap -->
``` ```
cat <<EOF >$DEMO_HOME/patch.yaml cat <<EOF >$DEMO_HOME/patch.yaml
apiVersion: apps/v1 apiVersion: apps/v1
@@ -106,7 +106,7 @@ spec:
value: prod value: prod
EOF EOF
kustomize edit add patch patch.yaml kustomize edit add patch --path patch.yaml --name sbdemo --kind Deployment --group apps --version v1
cat <<EOF >$DEMO_HOME/application-prod.properties cat <<EOF >$DEMO_HOME/application-prod.properties
spring.jpa.hibernate.ddl-auto=update spring.jpa.hibernate.ddl-auto=update
@@ -257,23 +257,38 @@ cat $DEMO_HOME/healthcheck_patch.yaml
将这些 patch 添加到 `kustomization.yaml` 中: 将这些 patch 添加到 `kustomization.yaml` 中:
<!-- @addPatch @testAgainstLatestRelease --> <!-- @addPatch -->
``` ```
cd $DEMO_HOME cd $DEMO_HOME
kustomize edit add patch memorylimit_patch.yaml kustomize edit add patch --path memorylimit_patch.yaml --name sbdemo --kind Deployment --group apps --version v1
kustomize edit add patch healthcheck_patch.yaml kustomize edit add patch --path healthcheck_patch.yaml --name sbdemo --kind Deployment --group apps --version v1
``` ```
执行上面的命令后,`kustomization.yaml` 的 patchesStrategicMerge 字段如下: 执行上面的命令后,`kustomization.yaml` 的 patches 字段如下:
> ``` > ```
> patchesStrategicMerge: > patches:
> - patch.yaml > - path: patch.yaml
> - memorylimit_patch.yaml > target:
> - healthcheck_patch.yaml > group: apps
> version: v1
> kind: Deployment
> name: sbdemo
> - path: memorylimit_patch.yaml
> target:
> group: apps
> version: v1
> kind: Deployment
> name: sbdemo
> - path: healthcheck_patch.yaml
> target:
> group: apps
> version: v1
> kind: Deployment
> name: sbdemo
> ``` > ```
现在就可以将完整的配置输出并在集群中部署(将结果通过管道输出给 `kubectl apply`在生产环境创建Spring Boot 应用。 现在就可以将完整的配置输出并在集群中部署(将结果通过管道输出给 `kubectl apply`),在生产环境创建 Spring Boot 应用。
<!-- @finalBuild @testAgainstLatestRelease --> <!-- @finalBuild @testAgainstLatestRelease -->
``` ```

View File

@@ -9,7 +9,8 @@ require (
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
k8s.io/client-go v0.17.3 k8s.io/client-go v0.17.3
sigs.k8s.io/kustomize/api v0.6.3 sigs.k8s.io/kustomize/api v0.6.3
sigs.k8s.io/kustomize/cmd/config v0.8.2 sigs.k8s.io/kustomize/cmd/config v0.8.4
sigs.k8s.io/kustomize/kyaml v0.9.3
sigs.k8s.io/yaml v1.2.0 sigs.k8s.io/yaml v1.2.0
) )
@@ -20,5 +21,3 @@ exclude (
) )
replace sigs.k8s.io/kustomize/api v0.6.3 => ../api replace sigs.k8s.io/kustomize/api v0.6.3 => ../api
replace sigs.k8s.io/kustomize/cmd/config v0.8.2 => ../cmd/config

View File

@@ -229,12 +229,8 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig= github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0= github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0=
@@ -339,10 +335,6 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete/v2 v2.0.1-alpha.12 h1:0wvkuDfHb5vSZlNBYgpEH4XQHpF46MjLPHav8XC77Nc=
github.com/posener/complete/v2 v2.0.1-alpha.12/go.mod h1://JlL91cS2JV7rOl6LVHrRqBXoBUecJu3ILQPgbJiMQ=
github.com/posener/script v1.0.4 h1:nSuXW5ZdmFnQIueLB2s0qvs4oNsUloM1Zydzh75v42w=
github.com/posener/script v1.0.4/go.mod h1:Rg3ijooqulo05aGLyGsHoLmIOUzHUVK19WVgrYBPU/E=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
@@ -606,8 +598,10 @@ k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw= mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw=
sigs.k8s.io/kustomize/kyaml v0.9.1 h1:T7aNUraSioQp0NHJZtYjIhL/q8mqRzCiHcAKdvo09go= sigs.k8s.io/kustomize/cmd/config v0.8.4 h1:Lo26VjENBVfAOJu0v6w6C1cv5Zp9K8XRs39/0cb87+k=
sigs.k8s.io/kustomize/kyaml v0.9.1/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw= sigs.k8s.io/kustomize/cmd/config v0.8.4/go.mod h1:1+URiyIJrjdxCdCNDuh2SLyf+I36txRgubFI3PIg2Gc=
sigs.k8s.io/kustomize/kyaml v0.9.3 h1:kZ5HnNmmnbndSXFivrAVM6u3Ik1dwu4kbpaV8KNwy8I=
sigs.k8s.io/kustomize/kyaml v0.9.3/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=

View File

@@ -15,10 +15,11 @@ import (
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct" "sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/api/k8sdeps/validator" "sigs.k8s.io/kustomize/api/k8sdeps/validator"
"sigs.k8s.io/kustomize/api/konfig" "sigs.k8s.io/kustomize/api/konfig"
shell_complete "sigs.k8s.io/kustomize/cmd/config/complete" "sigs.k8s.io/kustomize/cmd/config/completion"
"sigs.k8s.io/kustomize/kustomize/v3/internal/commands/build" "sigs.k8s.io/kustomize/kustomize/v3/internal/commands/build"
"sigs.k8s.io/kustomize/kustomize/v3/internal/commands/create" "sigs.k8s.io/kustomize/kustomize/v3/internal/commands/create"
"sigs.k8s.io/kustomize/kustomize/v3/internal/commands/edit" "sigs.k8s.io/kustomize/kustomize/v3/internal/commands/edit"
"sigs.k8s.io/kustomize/kustomize/v3/internal/commands/openapi"
"sigs.k8s.io/kustomize/kustomize/v3/internal/commands/version" "sigs.k8s.io/kustomize/kustomize/v3/internal/commands/version"
) )
@@ -38,11 +39,12 @@ See https://sigs.k8s.io/kustomize
uf := kunstruct.NewKunstructuredFactoryImpl() uf := kunstruct.NewKunstructuredFactoryImpl()
v := validator.NewKustValidator() v := validator.NewKustValidator()
c.AddCommand( c.AddCommand(
shell_complete.NewCommand(), completion.NewCommand(),
build.NewCmdBuild(stdOut), build.NewCmdBuild(stdOut),
edit.NewCmdEdit(fSys, v, uf), edit.NewCmdEdit(fSys, v, uf),
create.NewCmdCreate(fSys, uf), create.NewCmdCreate(fSys, uf),
version.NewCmdVersion(stdOut), version.NewCmdVersion(stdOut),
openapi.NewCmdOpenAPI(stdOut),
) )
configcobra.AddCommands(c, "kustomize") configcobra.AddCommands(c, "kustomize")

View File

@@ -9,54 +9,67 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/api/filesys" "sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/kustomize/v3/internal/commands/edit/patch" "sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kustomize/v3/internal/commands/kustfile" "sigs.k8s.io/kustomize/kustomize/v3/internal/commands/kustfile"
"sigs.k8s.io/kustomize/kustomize/v3/internal/commands/util"
) )
type addPatchOptions struct { type addPatchOptions struct {
patchFilePaths []string Patch types.Patch
} }
// newCmdAddPatch adds the name of a file containing a patch to the kustomization file. // newCmdAddPatch adds the name of a file containing a patch to the kustomization file.
func newCmdAddPatch(fSys filesys.FileSystem) *cobra.Command { func newCmdAddPatch(fSys filesys.FileSystem) *cobra.Command {
var o addPatchOptions var o addPatchOptions
o.Patch.Target = &types.Selector{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "patch", Use: "patch",
Short: "Add the name of a file containing a patch to the kustomization file.", Short: "Add an item to patches field.",
Long: `This command will add an item to patches field in the kustomization file.
Each item may:
- be either a strategic merge patch, or a JSON patch
- be either a file, or an inline string
- target a single resource or multiple resources
For more information please see https://kubernetes-sigs.github.io/kustomize/api-reference/kustomization/patches/
`,
Example: ` Example: `
add patch {filepath}`, add patch --path {filepath} --group {target group name} --version {target version}`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
err := o.Validate(args) err := o.Validate()
if err != nil { if err != nil {
return err return err
} }
return o.RunAddPatch(fSys) return o.RunAddPatch(fSys)
}, },
} }
cmd.Flags().StringVar(&o.Patch.Path, "path", "", "Path to the patch file. Cannot be used with --patch at the same time.")
cmd.Flags().StringVar(&o.Patch.Patch, "patch", "", "Literal string of patch content. Cannot be used with --path at the same time.")
cmd.Flags().StringVar(&o.Patch.Target.Group, "group", "", "API group in patch target")
cmd.Flags().StringVar(&o.Patch.Target.Version, "version", "", "API version in patch target")
cmd.Flags().StringVar(&o.Patch.Target.Kind, "kind", "", "Resource kind in patch target")
cmd.Flags().StringVar(&o.Patch.Target.Name, "name", "", "Resource name in patch target")
cmd.Flags().StringVar(&o.Patch.Target.Namespace, "namespace", "", "Resource namespace in patch target")
cmd.Flags().StringVar(&o.Patch.Target.AnnotationSelector, "annotation-selector", "", "annotationSelector in patch target")
cmd.Flags().StringVar(&o.Patch.Target.LabelSelector, "label-selector", "", "labelSelector in patch target")
return cmd return cmd
} }
// Validate validates addPatch command. // Validate validates addPatch command.
func (o *addPatchOptions) Validate(args []string) error { func (o *addPatchOptions) Validate() error {
if len(args) == 0 { if o.Patch.Patch != "" && o.Patch.Path != "" {
return errors.New("must specify a patch file") return errors.New("patch and path can't be set at the same time")
}
if o.Patch.Patch == "" && o.Patch.Path == "" {
return errors.New("must provide either patch or path")
} }
o.patchFilePaths = args
return nil return nil
} }
// RunAddPatch runs addPatch command (do real work). // RunAddPatch runs addPatch command (do real work).
func (o *addPatchOptions) RunAddPatch(fSys filesys.FileSystem) error { func (o *addPatchOptions) RunAddPatch(fSys filesys.FileSystem) error {
patches, err := util.GlobPatterns(fSys, o.patchFilePaths)
if err != nil {
return err
}
if len(patches) == 0 {
return nil
}
mf, err := kustfile.NewKustomizationFile(fSys) mf, err := kustfile.NewKustomizationFile(fSys)
if err != nil { if err != nil {
return err return err
@@ -67,13 +80,18 @@ func (o *addPatchOptions) RunAddPatch(fSys filesys.FileSystem) error {
return err return err
} }
for _, p := range patches { // Omit target if it's empty
if patch.Exist(m.PatchesStrategicMerge, p) { emptyTarget := types.Selector{}
log.Printf("patch %s already in kustomization file", p) if o.Patch.Target != nil && *o.Patch.Target == emptyTarget {
continue o.Patch.Target = nil
}
m.PatchesStrategicMerge = patch.Append(m.PatchesStrategicMerge, p)
} }
for _, p := range m.Patches {
if p.Equals(o.Patch) {
log.Printf("patch %#v already in kustomization file", p)
return nil
}
}
m.Patches = append(m.Patches, o.Patch)
return mf.Write(m) return mf.Write(m)
} }

View File

@@ -15,19 +15,34 @@ const (
patchFileName = "myWonderfulPatch.yaml" patchFileName = "myWonderfulPatch.yaml"
patchFileContent = ` patchFileContent = `
Lorem ipsum dolor sit amet, consectetur adipiscing elit, Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
` `
kind = "myKind"
group = "myGroup"
version = "myVersion"
name = "myName"
namespace = "myNamespace"
annotationSelector = "myAnnotationSelector"
labelSelector = "myLabelSelector"
) )
func TestAddPatchHappyPath(t *testing.T) { func TestAddPatchWithFilePath(t *testing.T) {
fSys := filesys.MakeEmptyDirInMemory() fSys := filesys.MakeEmptyDirInMemory()
fSys.WriteFile(patchFileName, []byte(patchFileContent)) fSys.WriteFile(patchFileName, []byte(patchFileContent))
fSys.WriteFile(patchFileName+"another", []byte(patchFileContent))
testutils_test.WriteTestKustomization(fSys) testutils_test.WriteTestKustomization(fSys)
cmd := newCmdAddPatch(fSys) cmd := newCmdAddPatch(fSys)
args := []string{patchFileName + "*"} args := []string{
err := cmd.RunE(cmd, args) "--path", patchFileName,
"--kind", kind,
"--group", group,
"--version", version,
"--name", name,
"--namespace", namespace,
"--annotation-selector", annotationSelector,
"--label-selector", labelSelector,
}
cmd.SetArgs(args)
err := cmd.Execute()
if err != nil { if err != nil {
t.Errorf("unexpected cmd error: %v", err) t.Errorf("unexpected cmd error: %v", err)
} }
@@ -35,11 +50,42 @@ func TestAddPatchHappyPath(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("unexpected read error: %v", err) t.Errorf("unexpected read error: %v", err)
} }
if !strings.Contains(string(content), patchFileName) { for i := 1; i < len(args); i += 2 {
t.Errorf("expected patch name in kustomization") if !strings.Contains(string(content), args[i]) {
t.Errorf("expected flag value of %s in kustomization but got\n%s", args[i-1], content)
}
} }
if !strings.Contains(string(content), patchFileName+"another") { }
t.Errorf("expected patch name in kustomization")
func TestAddPatchWithPatchContent(t *testing.T) {
fSys := filesys.MakeEmptyDirInMemory()
fSys.WriteFile(patchFileName, []byte(patchFileContent))
testutils_test.WriteTestKustomization(fSys)
cmd := newCmdAddPatch(fSys)
args := []string{
"--patch", patchFileContent,
"--kind", kind,
"--group", group,
"--version", version,
"--name", name,
"--namespace", namespace,
"--annotation-selector", annotationSelector,
"--label-selector", labelSelector,
}
cmd.SetArgs(args)
err := cmd.Execute()
if err != nil {
t.Errorf("unexpected cmd error: %v", err)
}
content, err := testutils_test.ReadTestKustomization(fSys)
if err != nil {
t.Errorf("unexpected read error: %v", err)
}
for i := 1; i < len(args); i += 2 {
if !strings.Contains(string(content), strings.Trim(args[i], " \n")) {
t.Errorf("expected flag value of %s in kustomization but got\n%s", args[i-1], content)
}
} }
} }
@@ -49,14 +95,24 @@ func TestAddPatchAlreadyThere(t *testing.T) {
testutils_test.WriteTestKustomization(fSys) testutils_test.WriteTestKustomization(fSys)
cmd := newCmdAddPatch(fSys) cmd := newCmdAddPatch(fSys)
args := []string{patchFileName} args := []string{
err := cmd.RunE(cmd, args) "--path", patchFileName,
"--kind", kind,
"--group", group,
"--version", version,
"--name", name,
"--namespace", namespace,
"--annotation-selector", annotationSelector,
"--label-selector", labelSelector,
}
cmd.SetArgs(args)
err := cmd.Execute()
if err != nil { if err != nil {
t.Fatalf("unexpected cmd error: %v", err) t.Fatalf("unexpected cmd error: %v", err)
} }
// adding an existing patch shouldn't return an error // adding an existing patch shouldn't return an error
err = cmd.RunE(cmd, args) err = cmd.Execute()
if err != nil { if err != nil {
t.Errorf("unexpected cmd error: %v", err) t.Errorf("unexpected cmd error: %v", err)
} }
@@ -70,7 +126,7 @@ func TestAddPatchNoArgs(t *testing.T) {
if err == nil { if err == nil {
t.Errorf("expected error: %v", err) t.Errorf("expected error: %v", err)
} }
if err.Error() != "must specify a patch file" { if err.Error() != "must provide either patch or path" {
t.Errorf("incorrect error: %v", err.Error()) t.Errorf("incorrect error: %v", err.Error())
} }
} }

View File

@@ -0,0 +1,79 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package add
import (
"errors"
"log"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/kustomize/v3/internal/commands/kustfile"
"sigs.k8s.io/kustomize/kustomize/v3/internal/commands/util"
)
type addTransformerOptions struct {
transformerFilePaths []string
}
// newCmdAddTransformer adds the name of a file containing a transformer
// configuration to the kustomization file.
func newCmdAddTransformer(fSys filesys.FileSystem) *cobra.Command {
var o addTransformerOptions
cmd := &cobra.Command{
Use: "transformer",
Short: "Add the name of a file containing a transformer configuration to the kustomization file.",
Example: `
add transformer {filepath}`,
RunE: func(cmd *cobra.Command, args []string) error {
err := o.Validate(args)
if err != nil {
return err
}
return o.RunAddTransformer(fSys)
},
}
return cmd
}
// Validate validates add transformer command.
func (o *addTransformerOptions) Validate(args []string) error {
if len(args) == 0 {
return errors.New("must specify a transformer file")
}
o.transformerFilePaths = args
return nil
}
// RunAddTransformer runs add transformer command (do real work).
func (o *addTransformerOptions) RunAddTransformer(fSys filesys.FileSystem) error {
transformers, err := util.GlobPatterns(fSys, o.transformerFilePaths)
if err != nil {
return err
}
if len(transformers) == 0 {
return nil
}
mf, err := kustfile.NewKustomizationFile(fSys)
if err != nil {
return err
}
m, err := mf.Read()
if err != nil {
return err
}
for _, t := range transformers {
if kustfile.StringInSlice(t, m.Transformers) {
log.Printf("transformer %s already in kustomization file", t)
continue
}
m.Transformers = append(m.Transformers, t)
}
return mf.Write(m)
}

View File

@@ -0,0 +1,109 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package add
import (
"fmt"
"strings"
"testing"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/kustomize/v3/internal/commands/kustfile"
testutils_test "sigs.k8s.io/kustomize/kustomize/v3/internal/commands/testutils"
)
const (
transformerFileName = "myWonderfulTransformer.yaml"
transformerFileContent = `
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
`
)
func TestAddTransformerHappyPath(t *testing.T) {
fSys := filesys.MakeEmptyDirInMemory()
fSys.WriteFile(transformerFileName, []byte(transformerFileContent))
fSys.WriteFile(transformerFileName+"another", []byte(transformerFileContent))
testutils_test.WriteTestKustomization(fSys)
cmd := newCmdAddTransformer(fSys)
args := []string{transformerFileName + "*"}
err := cmd.RunE(cmd, args)
if err != nil {
t.Errorf("unexpected cmd error: %v", err)
}
content, err := testutils_test.ReadTestKustomization(fSys)
if err != nil {
t.Errorf("unexpected read error: %v", err)
}
if !strings.Contains(string(content), transformerFileName) {
t.Errorf("expected transformer name in kustomization")
}
if !strings.Contains(string(content), transformerFileName+"another") {
t.Errorf("expected transformer name in kustomization")
}
}
func TestAddTransformerAlreadyThere(t *testing.T) {
fSys := filesys.MakeEmptyDirInMemory()
fSys.WriteFile(transformerFileName, []byte(transformerFileName))
testutils_test.WriteTestKustomization(fSys)
cmd := newCmdAddTransformer(fSys)
args := []string{transformerFileName}
err := cmd.RunE(cmd, args)
if err != nil {
t.Fatalf("unexpected cmd error: %v", err)
}
// adding an existing transformer shouldn't return an error
err = cmd.RunE(cmd, args)
if err != nil {
t.Errorf("unexpected cmd error: %v", err)
}
// There can be only one. May it be the...
mf, err := kustfile.NewKustomizationFile(fSys)
if err != nil {
t.Fatalf("error retrieving kustomization file: %v", err)
}
m, err := mf.Read()
if err != nil {
t.Fatalf("error reading kustomization file: %v", err)
}
if len(m.Transformers) != 1 || m.Transformers[0] != transformerFileName {
t.Errorf("expected transformers [%s]; got transformers [%s]", transformerFileName, strings.Join(m.Transformers, ","))
}
}
func TestAddTransformerNoArgs(t *testing.T) {
fSys := filesys.MakeFsInMemory()
cmd := newCmdAddTransformer(fSys)
err := cmd.Execute()
if err == nil {
t.Errorf("expected error: %v", err)
}
if err.Error() != "must specify a transformer file" {
t.Errorf("incorrect error: %v", err.Error())
}
}
func TestAddTransformerMissingKustomizationYAML(t *testing.T) {
fSys := filesys.MakeEmptyDirInMemory()
fSys.WriteFile(transformerFileName, []byte(transformerFileContent))
fSys.WriteFile(transformerFileName+"another", []byte(transformerFileContent))
cmd := newCmdAddTransformer(fSys)
args := []string{transformerFileName + "*"}
err := cmd.RunE(cmd, args)
if err == nil {
t.Errorf("expected error: %v", err)
}
fmt.Println(err.Error())
if err.Error() != "Missing kustomization file 'kustomization.yaml'.\n" {
t.Errorf("incorrect error: %v", err.Error())
}
}

View File

@@ -29,7 +29,7 @@ func NewCmdAdd(
kustomize edit add resource <filepath> kustomize edit add resource <filepath>
# Adds a patch to the kustomization # Adds a patch to the kustomization
kustomize edit add patch <filepath> kustomize edit add patch --path {filepath} --group {target group name} --version {target version}
# Adds a component to the kustomization # Adds a component to the kustomization
kustomize edit add component <filepath> kustomize edit add component <filepath>
@@ -43,6 +43,9 @@ func NewCmdAdd(
# Adds one or more commonAnnotations to the kustomization # Adds one or more commonAnnotations to the kustomization
kustomize edit add annotation {annotationKey1:annotationValue1},{annotationKey2:annotationValue2} kustomize edit add annotation {annotationKey1:annotationValue1},{annotationKey2:annotationValue2}
# Adds a transformer configuration to the kustomization
kustomize edit add transformer <filepath>
`, `,
Args: cobra.MinimumNArgs(1), Args: cobra.MinimumNArgs(1),
} }
@@ -55,6 +58,7 @@ func NewCmdAdd(
newCmdAddBase(fSys), newCmdAddBase(fSys),
newCmdAddLabel(fSys, ldr.Validator().MakeLabelValidator()), newCmdAddLabel(fSys, ldr.Validator().MakeLabelValidator()),
newCmdAddAnnotation(fSys, ldr.Validator().MakeAnnotationValidator()), newCmdAddAnnotation(fSys, ldr.Validator().MakeAnnotationValidator()),
newCmdAddTransformer(fSys),
) )
return c return c
} }

View File

@@ -1,41 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package patch
import "sigs.k8s.io/kustomize/api/types"
// Append appends a slice of patch paths to a PatchStrategicMerge slice
func Append(patches []types.PatchStrategicMerge, paths ...string) []types.PatchStrategicMerge {
for _, p := range paths {
patches = append(patches, types.PatchStrategicMerge(p))
}
return patches
}
// Exist determines if a patch path exists in a slice of PatchStrategicMerge
func Exist(patches []types.PatchStrategicMerge, path string) bool {
for _, p := range patches {
if p == types.PatchStrategicMerge(path) {
return true
}
}
return false
}
// Delete deletes patches from a PatchStrategicMerge slice
func Delete(patches []types.PatchStrategicMerge, paths ...string) []types.PatchStrategicMerge {
// Convert paths into PatchStrategicMerge slice
convertedPath := make([]types.PatchStrategicMerge, len(paths))
for i, p := range paths {
convertedPath[i] = types.PatchStrategicMerge(p)
}
filteredPatches := make([]types.PatchStrategicMerge, 0, len(patches))
for _, containedPatch := range patches {
if !Exist(convertedPath, string(containedPatch)) {
filteredPatches = append(filteredPatches, containedPatch)
}
}
return filteredPatches
}

View File

@@ -1,83 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.
package patch
import (
"testing"
"sigs.k8s.io/kustomize/api/types"
)
func buildPatchStrategicMergeSlice(patchStrings []string) []types.PatchStrategicMerge {
var patches []types.PatchStrategicMerge
for _, patchString := range patchStrings {
patches = append(patches, types.PatchStrategicMerge(patchString))
}
return patches
}
func TestAppend(t *testing.T) {
patchStrings := []string{"patch1.yaml", "patch2.yaml"}
patches := buildPatchStrategicMergeSlice(patchStrings)
patches = Append(patches, "patch3.yaml")
for i, k := range []string{"patch1.yaml", "patch2.yaml", "patch3.yaml"} {
if patches[i] != types.PatchStrategicMerge(k) {
t.Fatalf("patches[%d] must be %s, got %s", i, k, patches[i])
}
}
}
func TestExistTrue(t *testing.T) {
patchStrings := []string{"patch1.yaml", "patch2.yaml"}
patches := buildPatchStrategicMergeSlice(patchStrings)
for _, patchString := range patchStrings {
if !Exist(patches, patchString) {
t.Fatalf("%s must exist", patchString)
}
}
}
func TestExistFalse(t *testing.T) {
patchStrings := []string{"patch1.yaml", "patch2.yaml"}
patches := buildPatchStrategicMergeSlice(patchStrings)
for _, patchString := range []string{"invalid1.yaml", "invalid2.yaml"} {
if Exist(patches, patchString) {
t.Fatalf("%s must not exist", patchString)
}
}
}
func TestDelete(t *testing.T) {
patchStrings := []string{"patch1.yaml", "patch2.yaml"}
patches := buildPatchStrategicMergeSlice(patchStrings)
patches = Delete(patches, "patch1.yaml")
if Exist(patches, "patch1.yaml") {
t.Fatalf("patch1.yaml should be deleted")
}
if !Exist(patches, "patch2.yaml") {
t.Fatalf("patch2.yaml should exist")
}
if len(patches) != 1 {
t.Fatalf("Length of slice must be 1: actual %d", len(patches))
}
}
func TestDeleteMultiple(t *testing.T) {
patchStrings := []string{"patch1.yaml", "patch2.yaml"}
patches := buildPatchStrategicMergeSlice(patchStrings)
patches = Delete(patches, "patch2.yaml", "patch4.yaml", "patch1.yaml", "patch3.yaml")
for _, k := range patchStrings {
if Exist(patches, k) {
t.Fatalf("%s should be deleted", k)
}
}
}

View File

@@ -23,13 +23,16 @@ func NewCmdRemove(
kustomize edit remove resource {pattern} kustomize edit remove resource {pattern}
# Removes one or more patches from the kustomization file # Removes one or more patches from the kustomization file
kustomize edit remove patch <filepath> kustomize edit remove patch --path {filepath} --group {target group name} --version {target version}
# Removes one or more commonLabels from the kustomization file # Removes one or more commonLabels from the kustomization file
kustomize edit remove label {labelKey1},{labelKey2} kustomize edit remove label {labelKey1},{labelKey2}
# Removes one or more commonAnnotations from the kustomization file # Removes one or more commonAnnotations from the kustomization file
kustomize edit remove annotation {annotationKey1},{annotationKey2} kustomize edit remove annotation {annotationKey1},{annotationKey2}
# Removes one or more transformers from the kustomization file
kustomize edit remove transformer <filepath>
`, `,
Args: cobra.MinimumNArgs(1), Args: cobra.MinimumNArgs(1),
} }
@@ -38,6 +41,7 @@ func NewCmdRemove(
newCmdRemoveLabel(fSys, v.MakeLabelNameValidator()), newCmdRemoveLabel(fSys, v.MakeLabelNameValidator()),
newCmdRemoveAnnotation(fSys, v.MakeAnnotationNameValidator()), newCmdRemoveAnnotation(fSys, v.MakeAnnotationNameValidator()),
newCmdRemovePatch(fSys), newCmdRemovePatch(fSys),
newCmdRemoveTransformer(fSys),
) )
return c return c
} }

View File

@@ -10,55 +10,58 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/api/filesys" "sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/konfig" "sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/kustomize/v3/internal/commands/edit/patch" "sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kustomize/v3/internal/commands/kustfile" "sigs.k8s.io/kustomize/kustomize/v3/internal/commands/kustfile"
"sigs.k8s.io/kustomize/kustomize/v3/internal/commands/util"
) )
type removePatchOptions struct { type removePatchOptions struct {
patchFilePaths []string Patch types.Patch
} }
// newCmdRemovePatch removes the name of a file containing a patch from the kustomization file. // newCmdRemovePatch removes the name of a file containing a patch from the kustomization file.
func newCmdRemovePatch(fSys filesys.FileSystem) *cobra.Command { func newCmdRemovePatch(fSys filesys.FileSystem) *cobra.Command {
var o removePatchOptions var o removePatchOptions
o.Patch.Target = &types.Selector{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "patch", Use: "patch",
Short: "Removes one or more patches from " + Short: "Removes a patch from " +
konfig.DefaultKustomizationFileName(), konfig.DefaultKustomizationFileName(),
Long: `Removes a patch from patches field. The fields specified by flags must
exactly match the patch item to successfully remote the item.`,
Example: ` Example: `
remove patch {filepath}`, remove patch --path {filepath} --group {target group name} --version {target version}`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
err := o.Validate(args) err := o.Validate()
if err != nil { if err != nil {
return err return err
} }
return o.RunRemovePatch(fSys) return o.RunRemovePatch(fSys)
}, },
} }
cmd.Flags().StringVar(&o.Patch.Path, "path", "", "Path to the patch file. Cannot be used with --patch at the same time.")
cmd.Flags().StringVar(&o.Patch.Patch, "patch", "", "Literal string of patch content. Cannot be used with --path at the same time.")
cmd.Flags().StringVar(&o.Patch.Target.Group, "group", "", "API group in patch target")
cmd.Flags().StringVar(&o.Patch.Target.Version, "version", "", "API version in patch target")
cmd.Flags().StringVar(&o.Patch.Target.Kind, "kind", "", "Resource kind in patch target")
cmd.Flags().StringVar(&o.Patch.Target.Name, "name", "", "Resource name in patch target")
cmd.Flags().StringVar(&o.Patch.Target.Namespace, "namespace", "", "Resource namespace in patch target")
cmd.Flags().StringVar(&o.Patch.Target.AnnotationSelector, "annotation-selector", "", "annotationSelector in patch target")
cmd.Flags().StringVar(&o.Patch.Target.LabelSelector, "label-selector", "", "labelSelector in patch target")
return cmd return cmd
} }
// Validate validates removePatch command. // Validate validates removePatch command.
func (o *removePatchOptions) Validate(args []string) error { func (o *removePatchOptions) Validate() error {
if len(args) == 0 { if o.Patch.Patch != "" && o.Patch.Path != "" {
return errors.New("must specify a patch file") return errors.New("patch and path can't be set at the same time")
} }
o.patchFilePaths = args
return nil return nil
} }
// RunRemovePatch runs removePatch command (do real work). // RunRemovePatch runs removePatch command (do real work).
func (o *removePatchOptions) RunRemovePatch(fSys filesys.FileSystem) error { func (o *removePatchOptions) RunRemovePatch(fSys filesys.FileSystem) error {
patches, err := util.GlobPatterns(fSys, o.patchFilePaths)
if err != nil {
return err
}
if len(patches) == 0 {
return nil
}
mf, err := kustfile.NewKustomizationFile(fSys) mf, err := kustfile.NewKustomizationFile(fSys)
if err != nil { if err != nil {
return err return err
@@ -69,15 +72,23 @@ func (o *removePatchOptions) RunRemovePatch(fSys filesys.FileSystem) error {
return err return err
} }
var removePatches []string // Omit target if it's empty
for _, p := range patches { emptyTarget := types.Selector{}
if !patch.Exist(m.PatchesStrategicMerge, p) { if o.Patch.Target != nil && *o.Patch.Target == emptyTarget {
log.Printf("patch %s doesn't exist in kustomization file", p) o.Patch.Target = nil
continue
}
removePatches = append(removePatches, p)
} }
m.PatchesStrategicMerge = patch.Delete(m.PatchesStrategicMerge, removePatches...)
var patches []types.Patch
for _, p := range m.Patches {
if !p.Equals(o.Patch) {
patches = append(patches, p)
}
}
if len(patches) == len(m.Patches) {
log.Printf("patch %s doesn't exist in kustomization file", o.Patch)
return nil
}
m.Patches = patches
return mf.Write(m) return mf.Write(m)
} }

View File

@@ -4,29 +4,53 @@
package remove package remove
import ( import (
"fmt"
"strings"
"testing" "testing"
"sigs.k8s.io/kustomize/api/filesys" "sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/kustomize/v3/internal/commands/edit/patch"
testutils_test "sigs.k8s.io/kustomize/kustomize/v3/internal/commands/testutils" testutils_test "sigs.k8s.io/kustomize/kustomize/v3/internal/commands/testutils"
) )
const ( const (
patchFileContent = ` patchFileContent = `- op: replace
Lorem ipsum dolor sit amet, consectetur adipiscing elit, path: /some/existing/path
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. value: new value`
` kind = "myKind"
group = "myGroup"
version = "myVersion"
name = "myName"
namespace = "myNamespace"
annotationSelector = "myAnnotationSelector"
labelSelector = "myLabelSelector"
) )
func makeKustomizationPatchFS() filesys.FileSystem { func makeKustomizationPatchFS() filesys.FileSystem {
fSys := filesys.MakeEmptyDirInMemory() fSys := filesys.MakeEmptyDirInMemory()
patches := []string{"patch1.yaml", "patch2.yaml"} patches := []string{"patch1.yaml", "patch2.yaml"}
testutils_test.WriteTestKustomizationWith(fSys, []byte( testutils_test.WriteTestKustomizationWith(fSys, []byte(`
fmt.Sprintf("patchesStrategicMerge:\n - %s", patches:
strings.Join(patches, "\n - ")))) - path: patch1.yaml
target:
group: myGroup
version: myVersion
kind: myKind
name: myName
namespace: myNamespace
labelSelector: myLabelSelector
annotationSelector: myAnnotationSelector
- path: patch2.yaml
target:
group: myGroup
version: myVersion
kind: myKind
- patch: |-
- op: replace
path: /some/existing/path
value: new value
target:
kind: myKind
labelSelector: myLabelSelector
`))
for _, p := range patches { for _, p := range patches {
fSys.WriteFile(p, []byte(patchFileContent)) fSys.WriteFile(p, []byte(patchFileContent))
@@ -38,69 +62,86 @@ func makeKustomizationPatchFS() filesys.FileSystem {
func TestRemovePatch(t *testing.T) { func TestRemovePatch(t *testing.T) {
fSys := makeKustomizationPatchFS() fSys := makeKustomizationPatchFS()
cmd := newCmdRemovePatch(fSys) cmd := newCmdRemovePatch(fSys)
args := []string{"patch1.yaml"} patchPath := "patch1.yaml"
err := cmd.RunE(cmd, args) args := []string{
"--path", patchPath,
"--kind", kind,
"--group", group,
"--version", version,
"--name", name,
"--namespace", namespace,
"--annotation-selector", annotationSelector,
"--label-selector", labelSelector,
}
cmd.SetArgs(args)
err := cmd.Execute()
if err != nil { if err != nil {
t.Errorf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
} }
m := readKustomizationFS(t, fSys) m := readKustomizationFS(t, fSys)
for _, k := range args { for _, p := range m.Patches {
if patch.Exist(m.PatchesStrategicMerge, k) { if p.Path == patchPath {
t.Errorf("%s must be deleted", k) t.Fatalf("%s must be deleted", patchPath)
} }
} }
} }
func TestRemovePatchMultipleArgs(t *testing.T) { func TestRemovePatch2(t *testing.T) {
fSys := makeKustomizationPatchFS() fSys := makeKustomizationPatchFS()
cmd := newCmdRemovePatch(fSys) cmd := newCmdRemovePatch(fSys)
args := []string{"patch1.yaml", "patch2.yaml"} args := []string{
err := cmd.RunE(cmd, args) "--patch", patchFileContent,
"--kind", kind,
"--label-selector", labelSelector,
}
cmd.SetArgs(args)
err := cmd.Execute()
if err != nil { if err != nil {
t.Errorf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
} }
m := readKustomizationFS(t, fSys) m := readKustomizationFS(t, fSys)
for _, k := range args { for _, p := range m.Patches {
if patch.Exist(m.PatchesStrategicMerge, k) { if p.Patch == patchFileContent {
t.Errorf("%s must be deleted", k) t.Fatalf("%s must be deleted", patchFileContent)
} }
} }
} }
func TestRemovePatchGlob(t *testing.T) {
fSys := makeKustomizationPatchFS()
cmd := newCmdRemovePatch(fSys)
args := []string{"patch*.yaml"}
err := cmd.RunE(cmd, args)
if err != nil {
t.Errorf("unexpected error %v", err)
}
m := readKustomizationFS(t, fSys)
if len(m.PatchesStrategicMerge) != 0 {
t.Errorf("all patch must be deleted")
}
}
func TestRemovePatchNotDefinedInKustomization(t *testing.T) { func TestRemovePatchNotDefinedInKustomization(t *testing.T) {
fSys := makeKustomizationPatchFS() fSys := makeKustomizationPatchFS()
cmd := newCmdRemovePatch(fSys) cmd := newCmdRemovePatch(fSys)
args := []string{"patch3.yaml"} args := []string{
err := cmd.RunE(cmd, args) "--path", "patch3.yaml",
"--kind", kind,
"--group", group,
"--version", version,
"--name", name,
"--namespace", namespace,
"--annotation-selector", annotationSelector,
"--label-selector", labelSelector,
}
cmd.SetArgs(args)
err := cmd.Execute()
if err != nil { if err != nil {
t.Errorf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
} }
m := readKustomizationFS(t, fSys) m := readKustomizationFS(t, fSys)
for _, k := range []string{"patch1.yaml", "patch2.yaml"} { for _, k := range []string{"patch1.yaml", "patch2.yaml"} {
if !patch.Exist(m.PatchesStrategicMerge, k) { found := false
t.Errorf("%s must exist", k) for _, p := range m.Patches {
if p.Path == k {
found = true
break
}
}
if !found {
t.Fatalf("%s must exist", k)
} }
} }
} }
@@ -108,30 +149,45 @@ func TestRemovePatchNotDefinedInKustomization(t *testing.T) {
func TestRemovePatchNotExist(t *testing.T) { func TestRemovePatchNotExist(t *testing.T) {
fSys := makeKustomizationPatchFS() fSys := makeKustomizationPatchFS()
cmd := newCmdRemovePatch(fSys) cmd := newCmdRemovePatch(fSys)
args := []string{"patch4.yaml"} args := []string{
err := cmd.RunE(cmd, args) "--path", "patch4.yaml",
"--kind", kind,
"--group", group,
"--version", version,
"--name", name,
"--namespace", namespace,
"--annotation-selector", annotationSelector,
"--label-selector", labelSelector,
}
cmd.SetArgs(args)
err := cmd.Execute()
if err != nil { if err != nil {
t.Errorf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
} }
m := readKustomizationFS(t, fSys) m := readKustomizationFS(t, fSys)
for _, k := range []string{"patch1.yaml", "patch2.yaml"} { for _, k := range []string{"patch1.yaml", "patch2.yaml"} {
if !patch.Exist(m.PatchesStrategicMerge, k) { found := false
t.Errorf("%s must exist", k) for _, p := range m.Patches {
if p.Path == k {
found = true
break
}
}
if !found {
t.Fatalf("%s must exist", k)
} }
} }
} }
func TestRemovePatchNoArgs(t *testing.T) { func TestRemovePatchNoArgs(t *testing.T) {
// if no flags specified, we should do nothing
fSys := makeKustomizationPatchFS() fSys := makeKustomizationPatchFS()
cmd := newCmdRemovePatch(fSys) cmd := newCmdRemovePatch(fSys)
err := cmd.RunE(cmd, nil) err := cmd.Execute()
if err == nil { if err != nil {
t.Errorf("expected an error") t.Fatalf("unexpected error %v", err)
}
if err.Error() != "must specify a patch file" {
t.Errorf("incorrect error: %v", err.Error())
} }
} }

View File

@@ -5,65 +5,49 @@ package remove
import ( import (
"errors" "errors"
"fmt"
"strings"
"testing" "testing"
"sigs.k8s.io/kustomize/api/filesys" "sigs.k8s.io/kustomize/kustomize/v3/internal/commands/edit/remove_test"
testutils_test "sigs.k8s.io/kustomize/kustomize/v3/internal/commands/testutils"
) )
func TestRemoveResources(t *testing.T) { func TestRemoveResources(t *testing.T) {
type given struct { testCases := []remove_test.Case{
resources []string
removeArgs []string
}
type expected struct {
resources []string
deleted []string
err error
}
testCases := []struct {
description string
given given
expected expected
}{
{ {
description: "remove resource", Description: "remove resources",
given: given{ Given: remove_test.Given{
resources: []string{ Items: []string{
"resource1.yaml", "resource1.yaml",
"resource2.yaml", "resource2.yaml",
"resource3.yaml", "resource3.yaml",
}, },
removeArgs: []string{"resource1.yaml"}, RemoveArgs: []string{"resource1.yaml"},
}, },
expected: expected{ Expected: remove_test.Expected{
resources: []string{ Items: []string{
"resource2.yaml", "resource2.yaml",
"resource3.yaml", "resource3.yaml",
}, },
deleted: []string{ Deleted: []string{
"resource1.yaml", "resource1.yaml",
}, },
}, },
}, },
{ {
description: "remove resources with pattern", Description: "remove resource with pattern",
given: given{ Given: remove_test.Given{
resources: []string{ Items: []string{
"foo/resource1.yaml", "foo/resource1.yaml",
"foo/resource2.yaml", "foo/resource2.yaml",
"foo/resource3.yaml", "foo/resource3.yaml",
"do/not/deleteme/please.yaml", "do/not/deleteme/please.yaml",
}, },
removeArgs: []string{"foo/resource*.yaml"}, RemoveArgs: []string{"foo/resource*.yaml"},
}, },
expected: expected{ Expected: remove_test.Expected{
resources: []string{ Items: []string{
"do/not/deleteme/please.yaml", "do/not/deleteme/please.yaml",
}, },
deleted: []string{ Deleted: []string{
"foo/resource1.yaml", "foo/resource1.yaml",
"foo/resource2.yaml", "foo/resource2.yaml",
"foo/resource3.yaml", "foo/resource3.yaml",
@@ -71,17 +55,17 @@ func TestRemoveResources(t *testing.T) {
}, },
}, },
{ {
description: "nothing found to remove", Description: "nothing found to remove",
given: given{ Given: remove_test.Given{
resources: []string{ Items: []string{
"resource1.yaml", "resource1.yaml",
"resource2.yaml", "resource2.yaml",
"resource3.yaml", "resource3.yaml",
}, },
removeArgs: []string{"foo"}, RemoveArgs: []string{"foo"},
}, },
expected: expected{ Expected: remove_test.Expected{
resources: []string{ Items: []string{
"resource2.yaml", "resource2.yaml",
"resource3.yaml", "resource3.yaml",
"resource1.yaml", "resource1.yaml",
@@ -89,32 +73,32 @@ func TestRemoveResources(t *testing.T) {
}, },
}, },
{ {
description: "no arguments", Description: "no arguments",
given: given{}, Given: remove_test.Given{},
expected: expected{ Expected: remove_test.Expected{
err: errors.New("must specify a resource file"), Err: errors.New("must specify a resource file"),
}, },
}, },
{ {
description: "remove with multiple pattern arguments", Description: "remove with multiple pattern arguments",
given: given{ Given: remove_test.Given{
resources: []string{ Items: []string{
"foo/foo.yaml", "foo/foo.yaml",
"bar/bar.yaml", "bar/bar.yaml",
"resource3.yaml", "resource3.yaml",
"do/not/deleteme/please.yaml", "do/not/deleteme/please.yaml",
}, },
removeArgs: []string{ RemoveArgs: []string{
"foo/*.*", "foo/*.*",
"bar/*.*", "bar/*.*",
"res*.yaml", "res*.yaml",
}, },
}, },
expected: expected{ Expected: remove_test.Expected{
resources: []string{ Items: []string{
"do/not/deleteme/please.yaml", "do/not/deleteme/please.yaml",
}, },
deleted: []string{ Deleted: []string{
"foo/foo.yaml", "foo/foo.yaml",
"bar/bar.yaml", "bar/bar.yaml",
"resource3.yaml", "resource3.yaml",
@@ -123,40 +107,5 @@ func TestRemoveResources(t *testing.T) {
}, },
} }
for _, tc := range testCases { remove_test.ExecuteTestCases(t, testCases, "resources", newCmdRemoveResource)
t.Run(tc.description, func(t *testing.T) {
fSys := filesys.MakeFsInMemory()
testutils_test.WriteTestKustomizationWith(
fSys,
[]byte(fmt.Sprintf(
"resources:\n - %s", strings.Join(tc.given.resources, "\n - "))))
cmd := newCmdRemoveResource(fSys)
err := cmd.RunE(cmd, tc.given.removeArgs)
if err != nil && tc.expected.err == nil {
t.Errorf("unexpected cmd error: %v", err)
} else if tc.expected.err != nil {
if err.Error() != tc.expected.err.Error() {
t.Errorf("expected error did not occurred. Expected: %v. Actual: %v", tc.expected.err, err)
}
return
}
content, err := testutils_test.ReadTestKustomization(fSys)
if err != nil {
t.Errorf("unexpected read error: %v", err)
}
for _, resourceFileName := range tc.expected.resources {
if !strings.Contains(string(content), resourceFileName) {
t.Errorf("expected resource not found in kustomization file.\nResource: %s\nKustomization file:\n%s", resourceFileName, content)
}
}
for _, resourceFileName := range tc.expected.deleted {
if strings.Contains(string(content), resourceFileName) {
t.Errorf("expected deleted resource found in kustomization file. Resource: %s\nKustomization file:\n%s", resourceFileName, content)
}
}
})
}
} }

View File

@@ -0,0 +1,83 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package remove
import (
"errors"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/kustomize/v3/internal/commands/kustfile"
)
type removeTransformerOptions struct {
transformerFilePaths []string
}
// newCmdRemoveTransformer remove the name of a file containing a transformer to the kustomization file.
func newCmdRemoveTransformer(fSys filesys.FileSystem) *cobra.Command {
var o removeTransformerOptions
cmd := &cobra.Command{
Use: "transformer",
Short: "Removes one or more transformers from " +
konfig.DefaultKustomizationFileName(),
Example: `
remove transformer my-transformer.yml
remove transformer transformer1.yml transformer2.yml transformer3.yml
remove transformer transformers/*.yml
`,
RunE: func(cmd *cobra.Command, args []string) error {
err := o.Validate(args)
if err != nil {
return err
}
return o.RunRemoveTransformer(fSys)
},
}
return cmd
}
// Validate validates removeTransformer command.
func (o *removeTransformerOptions) Validate(args []string) error {
if len(args) == 0 {
return errors.New("must specify a transformer file")
}
o.transformerFilePaths = args
return nil
}
// RunRemoveTransformer runs Transformer command (do real work).
func (o *removeTransformerOptions) RunRemoveTransformer(fSys filesys.FileSystem) error {
mf, err := kustfile.NewKustomizationFile(fSys)
if err != nil {
return err
}
m, err := mf.Read()
if err != nil {
return err
}
transformers, err := globPatterns(m.Transformers, o.transformerFilePaths)
if err != nil {
return err
}
if len(transformers) == 0 {
return nil
}
newTransformers := make([]string, 0, len(m.Transformers))
for _, transformer := range m.Transformers {
if kustfile.StringInSlice(transformer, transformers) {
continue
}
newTransformers = append(newTransformers, transformer)
}
m.Transformers = newTransformers
return mf.Write(m)
}

View File

@@ -0,0 +1,108 @@
package remove
import (
"testing"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/kustomize/v3/internal/commands/edit/remove_test"
)
func TestRemoveTransformer(t *testing.T) {
testCases := []remove_test.Case{
{
Description: "remove transformers",
Given: remove_test.Given{
Items: []string{
"transformer1.yaml",
"transformer2.yaml",
"transformer3.yaml",
},
RemoveArgs: []string{"transformer1.yaml"},
},
Expected: remove_test.Expected{
Items: []string{
"transformer2.yaml",
"transformer3.yaml",
},
Deleted: []string{
"transformer1.yaml",
},
},
},
{
Description: "remove transformer with pattern",
Given: remove_test.Given{
Items: []string{
"foo/transformer1.yaml",
"foo/transformer2.yaml",
"foo/transformer3.yaml",
"do/not/deleteme/please.yaml",
},
RemoveArgs: []string{"foo/transformer*.yaml"},
},
Expected: remove_test.Expected{
Items: []string{
"do/not/deleteme/please.yaml",
},
Deleted: []string{
"foo/transformer1.yaml",
"foo/transformer2.yaml",
"foo/transformer3.yaml",
},
},
},
{
Description: "nothing found to remove",
Given: remove_test.Given{
Items: []string{
"transformer1.yaml",
"transformer2.yaml",
"transformer3.yaml",
},
RemoveArgs: []string{"foo"},
},
Expected: remove_test.Expected{
Items: []string{
"transformer2.yaml",
"transformer3.yaml",
"transformer1.yaml",
},
},
},
{
Description: "no arguments",
Given: remove_test.Given{},
Expected: remove_test.Expected{
Err: errors.New("must specify a transformer file"),
},
},
{
Description: "remove with multiple pattern arguments",
Given: remove_test.Given{
Items: []string{
"foo/foo.yaml",
"bar/bar.yaml",
"transformer3.yaml",
"do/not/deleteme/please.yaml",
},
RemoveArgs: []string{
"foo/*.*",
"bar/*.*",
"tra*.yaml",
},
},
Expected: remove_test.Expected{
Items: []string{
"do/not/deleteme/please.yaml",
},
Deleted: []string{
"foo/foo.yaml",
"bar/bar.yaml",
"transformer3.yaml",
},
},
},
}
remove_test.ExecuteTestCases(t, testCases, "transformers", newCmdRemoveTransformer)
}

View File

@@ -0,0 +1,85 @@
package remove_test
import (
"fmt"
"strings"
"testing"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/api/filesys"
testutils_test "sigs.k8s.io/kustomize/kustomize/v3/internal/commands/testutils"
)
// Given represents the provided inputs for the test case.
type Given struct {
// Items is the given input items.
Items []string
// RemoveArgs are the arguments to pass to the remove command.
RemoveArgs []string
}
// Expected represents the expected outputs of the test case.
type Expected struct {
// Expected is the collection of expected output items.
Items []string
// Deleted is the collection of expected Deleted items (if any).
Deleted []string
// Err represents the error that is expected in the output (if any).
Err error
}
// Case represents a test case to execute.
type Case struct {
// Description is the description of the test case.
Description string
// Given is the provided inputs for the test case.
Given Given
// Expected is the expected outputs for the test case.
Expected Expected
}
// ExecuteTestCases executes the provided test cases against the specified command
// for a particular collection (e.g. ) tests a command defined by the provided
// collection Name (e.g. transformers or resources) and newRemoveCmdToTest function.
func ExecuteTestCases(t *testing.T, testCases []Case, collectionName string,
newRemoveCmdToTest func(filesys.FileSystem) *cobra.Command) {
for _, tc := range testCases {
t.Run(tc.Description, func(t *testing.T) {
fSys := filesys.MakeFsInMemory()
testutils_test.WriteTestKustomizationWith(
fSys,
[]byte(fmt.Sprintf("%s:\n - %s",
collectionName,
strings.Join(tc.Given.Items, "\n - "))))
cmd := newRemoveCmdToTest(fSys)
err := cmd.RunE(cmd, tc.Given.RemoveArgs)
if err != nil && tc.Expected.Err == nil {
t.Errorf("unexpected cmd error: %v", err)
} else if tc.Expected.Err != nil {
if err.Error() != tc.Expected.Err.Error() {
t.Errorf("expected error did not occurred. Expected: %v. Actual: %v",
tc.Expected.Err,
err)
}
return
}
content, err := testutils_test.ReadTestKustomization(fSys)
if err != nil {
t.Errorf("unexpected read error: %v", err)
}
for _, itemFileName := range tc.Expected.Items {
if !strings.Contains(string(content), itemFileName) {
t.Errorf("expected item not found in kustomization file.\nItem: %s\nKustomization file:\n%s",
itemFileName, content)
}
}
for _, itemFileName := range tc.Expected.Deleted {
if strings.Contains(string(content), itemFileName) {
t.Errorf("expected deleted item found in kustomization file. Item: %s\nKustomization file:\n%s",
itemFileName, content)
}
}
})
}
}

View File

@@ -0,0 +1,28 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package info
import (
"fmt"
"io"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi"
)
// NewCmdInfo makes a new info command.
func NewCmdInfo(w io.Writer) *cobra.Command {
infoCmd := cobra.Command{
Use: "info",
Short: "Prints the `info` field from the kubernetes OpenAPI data",
Example: `kustomize openapi info`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Fprintln(w, kubernetesapi.Info)
},
Hidden: true,
}
return &infoCmd
}

View File

@@ -0,0 +1,28 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package openapi
import (
"io"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/configcobra"
"sigs.k8s.io/kustomize/kustomize/v3/internal/commands/openapi/info"
)
// NewCmdOpenAPI makes a new openapi command.
func NewCmdOpenAPI(w io.Writer) *cobra.Command {
openApiCmd := &cobra.Command{
Use: "openapi",
Short: "Commands for interacting with the OpenAPI data",
Example: `kustomize openapi info`,
Hidden: true,
}
openApiCmd.AddCommand(info.NewCmdInfo(w))
configcobra.AddCommands(openApiCmd, "openapi")
return openApiCmd
}

View File

@@ -7,7 +7,6 @@ package main
import ( import (
"os" "os"
"sigs.k8s.io/kustomize/cmd/config/complete"
"sigs.k8s.io/kustomize/kustomize/v3/internal/commands" "sigs.k8s.io/kustomize/kustomize/v3/internal/commands"
// initialize auth // initialize auth
@@ -17,10 +16,7 @@ import (
) )
func main() { func main() {
cmd := commands.NewDefaultCommand() if err := commands.NewDefaultCommand().Execute(); err != nil {
complete.Complete(cmd).Complete("kustomize")
if err := cmd.Execute(); err != nil {
os.Exit(1) os.Exit(1)
} }
os.Exit(0) os.Exit(0)

View File

@@ -2,10 +2,9 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
MYGOBIN := $(shell go env GOPATH)/bin MYGOBIN := $(shell go env GOPATH)/bin
GOPATH := $(shell go env GOPATH)
export PATH := $(MYGOBIN):$(PATH) export PATH := $(MYGOBIN):$(PATH)
.PHONY: generate license fix vet fmt test lint tidy openapi schema .PHONY: generate license fix vet fmt test lint tidy
all: generate license fix vet fmt test lint tidy all: generate license fix vet fmt test lint tidy
fix: fix:
@@ -15,51 +14,22 @@ fmt:
go fmt ./... go fmt ./...
generate: generate:
(which $(GOPATH)/bin/stringer || go get golang.org/x/tools/cmd/stringer) (which $(MYGOBIN)/stringer || go get golang.org/x/tools/cmd/stringer)
go generate ./... go generate ./...
license: license:
(which $(GOPATH)/bin/addlicense || go get github.com/google/addlicense) (which $(MYGOBIN)/addlicense || go get github.com/google/addlicense)
$(GOPATH)/bin/addlicense -y 2019 -c "The Kubernetes Authors." -f LICENSE_TEMPLATE . $(MYGOBIN)/addlicense -y 2019 -c "The Kubernetes Authors." -f LICENSE_TEMPLATE .
tidy: tidy:
go mod tidy go mod tidy
lint: lint:
(which $(GOPATH)/bin/golangci-lint || go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.19.1) (which $(MYGOBIN)/golangci-lint || go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.19.1)
$(GOPATH)/bin/golangci-lint run ./... $(MYGOBIN)/golangci-lint run ./...
test: test:
go test -cover ./... go test -cover ./...
vet: vet:
go vet ./... go vet ./...
openapi:
(which $(GOPATH)/bin/go-bindata || go get -u github.com/go-bindata/go-bindata/...)
$(GOPATH)/bin/go-bindata --pkg kubernetesapi -o openapi/kubernetesapi/swagger.go openapi/kubernetesapi/swagger.json
$(GOPATH)/bin/go-bindata --pkg kustomizationapi -o openapi/kustomizationapi/swagger.go openapi/kustomizationapi/swagger.json
$(MYGOBIN)/kind:
( \
set -e; \
d=$(shell mktemp -d); cd $$d; \
wget -O ./kind https://github.com/kubernetes-sigs/kind/releases/download/v0.7.0/kind-$(shell uname)-amd64; \
chmod +x ./kind; \
mv ./kind $(MYGOBIN); \
rm -rf $$d; \
)
$(MYGOBIN)/kpt:
../hack/install_kpt.sh 0.34.0 $(MYGOBIN)
API_VERSION="v1.19.1"
schema: $(MYGOBIN)/kind $(MYGOBIN)/kpt
cp $(HOME)/.kube/config /tmp/kubeconfig.txt | true
$(MYGOBIN)/kind create cluster --image kindest/node:$(API_VERSION) --name=getopenapidata
$(MYGOBIN)/kpt live fetch-k8s-schema --pretty-print > /tmp/new_swagger.json
$(MYGOBIN)/kind delete cluster --name=getopenapidata
cp /tmp/kubeconfig.txt $(HOME)/.kube/config | true
cp /tmp/new_swagger.json openapi/kubernetesapi/swagger.json

View File

@@ -8,7 +8,7 @@ import (
) )
// EnabkeAlphaCommmandsEnvName is the environment variable used to enable Alpha kustomize commands. // EnabkeAlphaCommmandsEnvName is the environment variable used to enable Alpha kustomize commands.
//If set to "true" alpha commands will be enabled. // If set to "true" alpha commands will be enabled.
const EnableAlphaCommmandsEnvName = "KUSTOMIZE_ENABLE_ALPHA_COMMANDS" const EnableAlphaCommmandsEnvName = "KUSTOMIZE_ENABLE_ALPHA_COMMANDS"
// GetAlphaEnabled returns true if alpha commands should be enabled. // GetAlphaEnabled returns true if alpha commands should be enabled.

View File

@@ -64,7 +64,7 @@ run(ctx.resource_list["items"])
Filters: []kio.Filter{fltr}, Filters: []kio.Filter{fltr},
Outputs: []kio.Writer{&kio.ByteWriter{Writer: output}}}.Execute() Outputs: []kio.Writer{&kio.ByteWriter{Writer: output}}}.Execute()
if err != nil { if err != nil {
log.Fatal(err) log.Println(err)
} }
fmt.Println(output.String()) fmt.Println(output.String())
@@ -131,7 +131,7 @@ spec:
value: "hello world" value: "hello world"
`) `)
if err != nil { if err != nil {
log.Fatal(err) log.Println(err)
} }
// fltr transforms the input using a starlark program // fltr transforms the input using a starlark program
@@ -156,7 +156,7 @@ run(ctx.resource_list["items"], ctx.resource_list["functionConfig"]["spec"]["val
Filters: []kio.Filter{fltr}, Filters: []kio.Filter{fltr},
Outputs: []kio.Writer{&kio.ByteWriter{Writer: output}}}.Execute() Outputs: []kio.Writer{&kio.ByteWriter{Writer: output}}}.Execute()
if err != nil { if err != nil {
log.Fatal(err) log.Println(err)
} }
fmt.Println(output.String()) fmt.Println(output.String())
@@ -197,7 +197,7 @@ func ExampleFilter_Filter_file() {
// setup the configuration // setup the configuration
d, err := ioutil.TempDir("", "") d, err := ioutil.TempDir("", "")
if err != nil { if err != nil {
log.Fatal(err) log.Println(err)
} }
defer os.RemoveAll(d) defer os.RemoveAll(d)
@@ -214,7 +214,7 @@ spec:
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image-1"} image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image-1"}
`), 0600) `), 0600)
if err != nil { if err != nil {
log.Fatal(err) log.Println(err)
} }
err = ioutil.WriteFile(filepath.Join(d, "deploy2.yaml"), []byte(` err = ioutil.WriteFile(filepath.Join(d, "deploy2.yaml"), []byte(`
@@ -230,7 +230,7 @@ spec:
image: nginx:1.7.9 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image-2"} image: nginx:1.7.9 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image-2"}
`), 0600) `), 0600)
if err != nil { if err != nil {
log.Fatal(err) log.Println(err)
} }
err = ioutil.WriteFile(filepath.Join(d, "annotate.star"), []byte(` err = ioutil.WriteFile(filepath.Join(d, "annotate.star"), []byte(`
@@ -241,7 +241,7 @@ def run(items):
run(ctx.resource_list["items"]) run(ctx.resource_list["items"])
`), 0600) `), 0600)
if err != nil { if err != nil {
log.Fatal(err) log.Println(err)
} }
fltr := &starlark.Filter{ fltr := &starlark.Filter{
@@ -261,7 +261,7 @@ run(ctx.resource_list["items"])
ClearAnnotations: []string{"config.kubernetes.io/path"}, ClearAnnotations: []string{"config.kubernetes.io/path"},
}}}.Execute() }}}.Execute()
if err != nil { if err != nil {
log.Fatal(err) log.Println(err)
} }
fmt.Println(output.String()) fmt.Println(output.String())

View File

@@ -117,7 +117,7 @@ func (r *ByteReader) Read() ([]*yaml.RNode, error) {
} }
// replace the ending \r\n (line ending used in windows) with \n and then separate by \n---\n // replace the ending \r\n (line ending used in windows) with \n and then separate by \n---\n
values := strings.Split(strings.Replace(input.String(), "\r\n", "\n", -1), "\n---\n") values := strings.Split(strings.ReplaceAll(input.String(), "\r\n", "\n"), "\n---\n")
index := 0 index := 0
for i := range values { for i := range values {

View File

@@ -170,9 +170,9 @@ func (f *FileSetter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
return nil, err return nil, err
} }
file := f.FilenamePattern file := f.FilenamePattern
file = strings.Replace(file, string(KindFmt), strings.ToLower(m.Kind), -1) file = strings.ReplaceAll(file, string(KindFmt), strings.ToLower(m.Kind))
file = strings.Replace(file, string(NameFmt), strings.ToLower(m.Name), -1) file = strings.ReplaceAll(file, string(NameFmt), strings.ToLower(m.Name))
file = strings.Replace(file, string(NamespaceFmt), strings.ToLower(m.Namespace), -1) file = strings.ReplaceAll(file, string(NamespaceFmt), strings.ToLower(m.Namespace))
if _, found := m.Annotations[kioutil.PathAnnotation]; !found || f.Override { if _, found := m.Annotations[kioutil.PathAnnotation]; !found || f.Override {
if _, err := input[i].Pipe(yaml.SetAnnotation(kioutil.PathAnnotation, file)); err != nil { if _, err := input[i].Pipe(yaml.SetAnnotation(kioutil.PathAnnotation, file)); err != nil {

View File

@@ -68,7 +68,7 @@ func (f GrepFilter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
if err != nil { if err != nil {
return err return err
} }
str = strings.TrimSpace(strings.Replace(str, `"`, "", -1)) str = strings.TrimSpace(strings.ReplaceAll(str, `"`, ""))
} else { } else {
// if not regexp, then it needs to parse into a quantity and comments will // if not regexp, then it needs to parse into a quantity and comments will
// break that // break that

View File

@@ -75,6 +75,16 @@ type Pipeline struct {
// Outputs are where the transformed Resource Configuration is written. // Outputs are where the transformed Resource Configuration is written.
Outputs []Writer `yaml:"outputs,omitempty"` Outputs []Writer `yaml:"outputs,omitempty"`
// ContinueOnEmptyResult configures what happens when a filter in the pipeline
// returns an empty result.
// If it is false (default), subsequent filters will be skipped and the result
// will be returned immediately. This is useful as an optimization when you
// know that subsequent filters will not alter the empty result.
// If it is true, the empty result will be provided as input to the next
// filter in the list. This is useful when subsequent functions in the
// pipeline may generate new resources.
ContinueOnEmptyResult bool `yaml:"continueOnEmptyResult,omitempty"`
} }
// Execute executes each step in the sequence, returning immediately after encountering // Execute executes each step in the sequence, returning immediately after encountering
@@ -111,7 +121,7 @@ func (p Pipeline) ExecuteWithCallback(callback PipelineExecuteCallbackFunc) erro
// TODO (issue 2872): This len(result) == 0 should be removed and empty result list should be // TODO (issue 2872): This len(result) == 0 should be removed and empty result list should be
// handled by outputs. However currently some writer like LocalPackageReadWriter // handled by outputs. However currently some writer like LocalPackageReadWriter
// will clear the output directory and which will cause unpredictable results // will clear the output directory and which will cause unpredictable results
if len(result) == 0 || err != nil { if len(result) == 0 && !p.ContinueOnEmptyResult || err != nil {
return errors.Wrap(err) return errors.Wrap(err)
} }
} }

View File

@@ -149,3 +149,41 @@ items:
t.FailNow() t.FailNow()
} }
} }
func TestContinueOnEmptyBehavior(t *testing.T) {
cases := map[string]struct {
continueOnEmptyResult bool
expected string
}{
"quit on empty": {continueOnEmptyResult: false, expected: ""},
"continue on empty": {continueOnEmptyResult: true, expected: "foo: bar"},
}
for _, tc := range cases {
actual := &bytes.Buffer{}
output := ByteWriter{Writer: actual}
generatorFunc := FilterFunc(func(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
nodes = append(nodes, yaml.NewMapRNode(&map[string]string{
"foo": "bar",
}))
return nodes, nil
})
emptyFunc := FilterFunc(func(nodes []*yaml.RNode) ([]*yaml.RNode, error) { return nodes, nil })
p := Pipeline{
Outputs: []Writer{output},
Filters: []Filter{emptyFunc, generatorFunc},
ContinueOnEmptyResult: tc.continueOnEmptyResult,
}
err := p.Execute()
if err != nil {
t.Fatal(err)
}
if !assert.Equal(t,
tc.expected, strings.TrimSpace(actual.String())) {
t.Fail()
}
}
}

View File

@@ -5,7 +5,6 @@ package kio_test
import ( import (
"bytes" "bytes"
"fmt"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -69,7 +68,7 @@ spec:
t.FailNow() t.FailNow()
} }
if !assert.Equal(t, fmt.Sprintf(` if !assert.Equal(t, `
├── bar-package ├── bar-package
│   └── [f2.yaml] Deployment bar │   └── [f2.yaml] Deployment bar
└── foo-package └── foo-package
@@ -77,7 +76,7 @@ spec:
├── [f1.yaml] Service default/foo ├── [f1.yaml] Service default/foo
└── 3 └── 3
└── [f3.yaml] Deployment default/foo └── [f3.yaml] Deployment default/foo
`), out.String()) { `, out.String()) {
t.FailNow() t.FailNow()
} }
} }

62
kyaml/openapi/Makefile Normal file
View File

@@ -0,0 +1,62 @@
# Copyright 2020 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
MYGOBIN := $(shell go env GOPATH)/bin
.PHONY: all
all: \
kustomizationapi/swagger.go \
kubernetesapi/swagger.go \
kubernetesapi/openapiinfo.go
.PHONY: clean
clean:
rm kustomizationapi/swagger.go
rm kubernetesapi/swagger.go
rm kubernetesapi/openapiinfo.go
# To get swagger.json, we need a cluster at the correct version,
# so think twice before deleting.
.PHONY: nuke
nuke: clean
rm kubernetesapi/swagger.json
$(MYGOBIN)/go-bindata:
go install github.com/go-bindata/go-bindata/v3/go-bindata
$(MYGOBIN)/kind:
( \
set -e; \
d=$(shell mktemp -d); cd $$d; \
wget -O ./kind https://github.com/kubernetes-sigs/kind/releases/download/v0.7.0/kind-$(shell uname)-amd64; \
chmod +x ./kind; \
mv ./kind $(MYGOBIN); \
rm -rf $$d; \
)
$(MYGOBIN)/kpt:
../../hack/install_kpt.sh 0.34.0 $(MYGOBIN)
kubernetesapi/swagger.go: $(MYGOBIN)/go-bindata kubernetesapi/swagger.json
$(MYGOBIN)/go-bindata \
--pkg kubernetesapi \
-o kubernetesapi/swagger.go \
kubernetesapi/swagger.json
kustomizationapi/swagger.go: $(MYGOBIN)/go-bindata kustomizationapi/swagger.json
$(MYGOBIN)/go-bindata \
--pkg kustomizationapi \
-o kustomizationapi/swagger.go \
kustomizationapi/swagger.json
kubernetesapi/openapiinfo.go: kubernetesapi/swagger.json
./makeOpenApiInfoDotGo.sh kubernetesapi/swagger.json
API_VERSION="v1.19.1"
kubernetesapi/swagger.json: $(MYGOBIN)/kind $(MYGOBIN)/kpt
cp $(HOME)/.kube/config /tmp/kubeconfig.txt | true
$(MYGOBIN)/kind create cluster --image kindest/node:$(API_VERSION) --name=getopenapidata
$(MYGOBIN)/kpt live fetch-k8s-schema --pretty-print > /tmp/new_swagger.json
$(MYGOBIN)/kind delete cluster --name=getopenapidata
cp /tmp/kubeconfig.txt $(HOME)/.kube/config | true
cp /tmp/new_swagger.json kubernetesapi/swagger.json

View File

@@ -1,36 +1,42 @@
# Sampling New OpenAPI Data # Sampling New OpenAPI Data
[kyaml]: ../
[OpenAPI schema]: ./kubernetesapi/swagger.json [OpenAPI schema]: ./kubernetesapi/swagger.json
[home]: ../../
This document describes how to fetch OpenAPI data from This document describes how to fetch OpenAPI data from
a particular kubernetes version number. a particular kubernetes version number.
### Fetching the Schema
In this directory, fetch the openapi schema for the kubernetes api:
### Fetching the Schema
In the [kyaml] directory, fetch the schema
``` ```
make schema make nuke
make kubernetesapi/swagger.json
``` ```
You can specify a specific version with the "API_VERSION" You can specify a specific version with the "API_VERSION"
parameter. The default version is v1.19.1. Here is an parameter. The default version is v1.19.1. Here is an
example for fetching the data for v1.14.1. example for fetching the data for v1.14.1.
``` ```
make schema API_VERSION=v1.14.1 make kubernetesapi/swagger.json API_VERSION=v1.14.1
``` ```
This will update the [OpenAPI schema]. This will update the [OpenAPI schema].
### Generating Swagger.go ### Generating Swagger.go
In the [kyaml] directory, generate the swagger.go files.
In this directory, generate the swagger.go files.
``` ```
make openapi make
``` ```
### Run all tests ### Run all tests
In the [home] directory, run the tests.
At the top of the repository, run the tests.
``` ```
make prow-presubmit-check >& /tmp/k.txt; echo $? make prow-presubmit-check >& /tmp/k.txt; echo $?
# The exit code should be zero; if not examine /tmp/k.txt # The exit code should be zero; if not examine /tmp/k.txt
``` ```

View File

@@ -0,0 +1,8 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Code generated by ./makeOpenApiInfoDotGo.sh; DO NOT EDIT.
package kubernetesapi
const Info = "{title:Kubernetes,version:v1.17.0}"

File diff suppressed because one or more lines are too long

View File

@@ -3,7 +3,7 @@
// Code generated for package kustomizationapi by go-bindata DO NOT EDIT. (@generated) // Code generated for package kustomizationapi by go-bindata DO NOT EDIT. (@generated)
// sources: // sources:
// openapi/kustomizationapi/swagger.json // kustomizationapi/swagger.json
package kustomizationapi package kustomizationapi
import ( import (
@@ -80,22 +80,22 @@ func (fi bindataFileInfo) Sys() interface{} {
return nil return nil
} }
var _openapiKustomizationapiSwaggerJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xdc\x54\xb1\x6e\xdb\x30\x10\xdd\xfd\x15\x04\xdb\xd1\x52\xe0\xad\xf0\x56\x74\xe8\x10\x04\x08\x90\x6e\x45\x86\xb3\x7c\x52\xae\x92\x49\xf6\x78\x12\xea\x16\xfe\xf7\x42\xac\xa5\x88\xb6\xd4\xb4\x46\x1c\x24\x1e\x0c\x18\xd4\xdd\x7b\xbc\x7b\x8f\xef\xd7\x4c\x29\xbd\xc6\x9c\x0c\x09\x59\xe3\xf5\x52\xb5\x47\x4a\x69\xb2\x69\xf9\xc1\xa7\xe0\x28\x05\xe7\x7c\xda\x2c\xd2\x4f\xd6\xe4\x54\xdc\x80\xfb\xc8\xc5\x63\xa5\x52\xda\xb1\x75\xc8\x42\x38\x3c\x55\x4a\x7f\x46\x83\x0c\x62\xf9\xa0\x21\x7c\x7c\xcf\x98\xeb\xa5\xd2\xef\xae\x06\xfc\x57\x23\xb4\x31\x4a\x0f\xb1\xdb\xff\xdb\xcd\xbb\x6b\xc0\x7a\x1d\x50\xa0\xba\x1d\x5e\x28\x87\xca\x63\x5f\x24\x5b\x87\x2d\xad\x5d\x7d\xc3\x4c\x74\x7f\xfe\x23\x29\xeb\x15\xb2\x41\x41\x9f\x14\x6c\x6b\x97\x34\xc8\x9e\xac\x49\x4a\x32\x6b\xbd\x54\x5f\x7b\xea\x68\x8e\x50\xdb\x22\x96\xb5\x17\xbb\xa1\x9f\x98\x66\x61\x51\x61\x10\xb2\x3d\x45\xa8\xde\x63\xe9\x78\x97\x51\xc9\x9e\xb6\xad\x6a\x16\x2b\x14\x58\x1c\x0f\x7d\x3f\x1b\x8c\x3e\xa6\xd5\x1d\x66\x8c\xf2\x3a\x84\x7a\x9c\xae\xdb\x7e\x84\xdf\x29\xe2\x85\xc9\x14\x97\x22\xf0\x40\x80\xe7\x57\x77\x4a\xaf\x49\x81\x0d\x6c\xd0\x3b\xc8\xfe\x7d\xf9\xf3\xb8\xf9\x94\xbe\x15\x3e\x40\x43\x96\x4f\xe9\xbd\x6e\x6e\x81\xf8\xce\xd6\x9c\xe1\xe9\x8e\x8c\x51\x2e\xc4\x59\xb1\xf8\xcf\x6f\xae\xeb\xfd\x65\x40\xfe\x40\xf5\xe6\x62\xfc\x5e\x13\x63\x3c\x90\xfe\xb2\x75\x78\x83\x02\x1d\xd3\xfd\xfc\x29\x33\x66\x5d\xf6\xf5\x93\x1c\x0a\x4c\x82\x9b\x43\xd5\xff\x47\xf7\x38\x5d\x07\x20\xbb\xf9\x98\x11\x81\x19\xb6\xf1\x26\x23\x4d\x1d\x48\xf6\x90\x6c\x90\x0b\x4c\x4a\xdc\xb6\x2d\xe1\x4d\x3c\xd5\xe1\x85\x41\xb0\x08\x0d\xa1\x7b\xdc\xeb\x3e\x44\xc5\xd9\x96\x31\x48\xa2\x57\xb9\x89\x37\xfd\x18\xe3\xc7\x72\x86\xc7\x38\x91\x83\x93\x8f\xab\x22\x41\x86\xea\x28\x33\x27\x5c\x34\x95\xc5\x7f\x37\xc8\xa8\x8d\x73\xaa\x8e\xa3\xfa\xfc\xb4\x68\x9a\x97\x62\x7d\xdb\x4e\x8d\x9c\x74\xaa\x53\x67\xed\x6f\xf7\x3b\x00\x00\xff\xff\xfe\x97\xce\xec\x37\x0c\x00\x00") var _kustomizationapiSwaggerJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xdc\x54\xb1\x6e\xdb\x30\x10\xdd\xfd\x15\x04\xdb\xd1\x52\xe0\xad\xf0\x56\x74\xe8\x10\x04\x08\x90\x6e\x45\x86\xb3\x7c\x52\xae\x92\x49\xf6\x78\x12\xea\x16\xfe\xf7\x42\xac\xa5\x88\xb6\xd4\xb4\x46\x1c\x24\x1e\x0c\x18\xd4\xdd\x7b\xbc\x7b\x8f\xef\xd7\x4c\x29\xbd\xc6\x9c\x0c\x09\x59\xe3\xf5\x52\xb5\x47\x4a\x69\xb2\x69\xf9\xc1\xa7\xe0\x28\x05\xe7\x7c\xda\x2c\xd2\x4f\xd6\xe4\x54\xdc\x80\xfb\xc8\xc5\x63\xa5\x52\xda\xb1\x75\xc8\x42\x38\x3c\x55\x4a\x7f\x46\x83\x0c\x62\xf9\xa0\x21\x7c\x7c\xcf\x98\xeb\xa5\xd2\xef\xae\x06\xfc\x57\x23\xb4\x31\x4a\x0f\xb1\xdb\xff\xdb\xcd\xbb\x6b\xc0\x7a\x1d\x50\xa0\xba\x1d\x5e\x28\x87\xca\x63\x5f\x24\x5b\x87\x2d\xad\x5d\x7d\xc3\x4c\x74\x7f\xfe\x23\x29\xeb\x15\xb2\x41\x41\x9f\x14\x6c\x6b\x97\x34\xc8\x9e\xac\x49\x4a\x32\x6b\xbd\x54\x5f\x7b\xea\x68\x8e\x50\xdb\x22\x96\xb5\x17\xbb\xa1\x9f\x98\x66\x61\x51\x61\x10\xb2\x3d\x45\xa8\xde\x63\xe9\x78\x97\x51\xc9\x9e\xb6\xad\x6a\x16\x2b\x14\x58\x1c\x0f\x7d\x3f\x1b\x8c\x3e\xa6\xd5\x1d\x66\x8c\xf2\x3a\x84\x7a\x9c\xae\xdb\x7e\x84\xdf\x29\xe2\x85\xc9\x14\x97\x22\xf0\x40\x80\xe7\x57\x77\x4a\xaf\x49\x81\x0d\x6c\xd0\x3b\xc8\xfe\x7d\xf9\xf3\xb8\xf9\x94\xbe\x15\x3e\x40\x43\x96\x4f\xe9\xbd\x6e\x6e\x81\xf8\xce\xd6\x9c\xe1\xe9\x8e\x8c\x51\x2e\xc4\x59\xb1\xf8\xcf\x6f\xae\xeb\xfd\x65\x40\xfe\x40\xf5\xe6\x62\xfc\x5e\x13\x63\x3c\x90\xfe\xb2\x75\x78\x83\x02\x1d\xd3\xfd\xfc\x29\x33\x66\x5d\xf6\xf5\x93\x1c\x0a\x4c\x82\x9b\x43\xd5\xff\x47\xf7\x38\x5d\x07\x20\xbb\xf9\x98\x11\x81\x19\xb6\xf1\x26\x23\x4d\x1d\x48\xf6\x90\x6c\x90\x0b\x4c\x4a\xdc\xb6\x2d\xe1\x4d\x3c\xd5\xe1\x85\x41\xb0\x08\x0d\xa1\x7b\xdc\xeb\x3e\x44\xc5\xd9\x96\x31\x48\xa2\x57\xb9\x89\x37\xfd\x18\xe3\xc7\x72\x86\xc7\x38\x91\x83\x93\x8f\xab\x22\x41\x86\xea\x28\x33\x27\x5c\x34\x95\xc5\x7f\x37\xc8\xa8\x8d\x73\xaa\x8e\xa3\xfa\xfc\xb4\x68\x9a\x97\x62\x7d\xdb\x4e\x8d\x9c\x74\xaa\x53\x67\xed\x6f\xf7\x3b\x00\x00\xff\xff\xfe\x97\xce\xec\x37\x0c\x00\x00")
func openapiKustomizationapiSwaggerJsonBytes() ([]byte, error) { func kustomizationapiSwaggerJsonBytes() ([]byte, error) {
return bindataRead( return bindataRead(
_openapiKustomizationapiSwaggerJson, _kustomizationapiSwaggerJson,
"openapi/kustomizationapi/swagger.json", "kustomizationapi/swagger.json",
) )
} }
func openapiKustomizationapiSwaggerJson() (*asset, error) { func kustomizationapiSwaggerJson() (*asset, error) {
bytes, err := openapiKustomizationapiSwaggerJsonBytes() bytes, err := kustomizationapiSwaggerJsonBytes()
if err != nil { if err != nil {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "openapi/kustomizationapi/swagger.json", size: 3127, mode: os.FileMode(420), modTime: time.Unix(1602011464, 0)} info := bindataFileInfo{name: "kustomizationapi/swagger.json", size: 3127, mode: os.FileMode(420), modTime: time.Unix(1602011464, 0)}
a := &asset{bytes: bytes, info: info} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }
@@ -152,7 +152,7 @@ func AssetNames() []string {
// _bindata is a table, holding each asset generator, mapped to its name. // _bindata is a table, holding each asset generator, mapped to its name.
var _bindata = map[string]func() (*asset, error){ var _bindata = map[string]func() (*asset, error){
"openapi/kustomizationapi/swagger.json": openapiKustomizationapiSwaggerJson, "kustomizationapi/swagger.json": kustomizationapiSwaggerJson,
} }
// AssetDir returns the file names below a certain // AssetDir returns the file names below a certain
@@ -196,10 +196,8 @@ type bintree struct {
} }
var _bintree = &bintree{nil, map[string]*bintree{ var _bintree = &bintree{nil, map[string]*bintree{
"openapi": &bintree{nil, map[string]*bintree{ "kustomizationapi": &bintree{nil, map[string]*bintree{
"kustomizationapi": &bintree{nil, map[string]*bintree{ "swagger.json": &bintree{kustomizationapiSwaggerJson, map[string]*bintree{}},
"swagger.json": &bintree{openapiKustomizationapiSwaggerJson, map[string]*bintree{}},
}},
}}, }},
}} }}

View File

@@ -0,0 +1,27 @@
#!/bin/bash
# Copyright 2020 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
set -e
if ! command -v jq &> /dev/null ; then
echo Please install jq
echo on ubuntu: sudo apt-get install jq
exit 1
fi
OPEN_API_INFO=$(\
jq -r '.info' $1 | \
sed 's/[\" *]//g' | \
tr -d '\n' )
cat <<EOF >kubernetesapi/openapiinfo.go
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Code generated by $0; DO NOT EDIT.
package kubernetesapi
const Info = "$OPEN_API_INFO"
EOF

View File

@@ -363,11 +363,11 @@ func (rs *ResourceSchema) PatchStrategyAndKey() (string, string) {
const ( const (
// kubernetesAPIAssetName is the name of the asset containing the statically compiled in // kubernetesAPIAssetName is the name of the asset containing the statically compiled in
// OpenAPI definitions for Kubernetes built-in types // OpenAPI definitions for Kubernetes built-in types
kubernetesAPIAssetName = "openapi/kubernetesapi/swagger.json" kubernetesAPIAssetName = "kubernetesapi/swagger.json"
// kustomizationAPIAssetName is the name of the asset containing the statically compiled in // kustomizationAPIAssetName is the name of the asset containing the statically compiled in
// OpenAPI definitions for Kustomization built-in types // OpenAPI definitions for Kustomization built-in types
kustomizationAPIAssetName = "openapi/kustomizationapi/swagger.json" kustomizationAPIAssetName = "kustomizationapi/swagger.json"
// kubernetesGVKExtensionKey is the key to lookup the kubernetes group version kind extension // kubernetesGVKExtensionKey is the key to lookup the kubernetes group version kind extension
// -- the extension is an array of objects containing a gvk // -- the extension is an array of objects containing a gvk

View File

@@ -114,7 +114,7 @@ func (fs *fieldSetter) set(
} }
// be sure to set the tag to the matching type so the yaml doesn't incorrectly quote // be sure to set the tag to the matching type so the yaml doesn't incorrectly quote
//integers or booleans as strings // integers or booleans as strings
fType := fieldmeta.FieldValueType(f.Schema.Type[0]) fType := fieldmeta.FieldValueType(f.Schema.Type[0])
if err := fType.Validate(field.YNode().Value); err != nil { if err := fType.Validate(field.YNode().Value); err != nil {
return err return err

View File

@@ -172,6 +172,9 @@ type SetterDefinition struct {
// live apply/preview. This field is added to the setter definition to record // live apply/preview. This field is added to the setter definition to record
// the package publisher's intent to make the setter required to be set. // the package publisher's intent to make the setter required to be set.
Required bool `yaml:"required,omitempty"` Required bool `yaml:"required,omitempty"`
// IsSet indicates the specified field has been explicitly assigned.
IsSet bool `yaml:"isSet,omitempty"`
} }
func (sd SetterDefinition) AddToFile(path string) error { func (sd SetterDefinition) AddToFile(path string) error {

View File

@@ -281,13 +281,13 @@ packageMetadata:
func TestAdd_Filter2(t *testing.T) { func TestAdd_Filter2(t *testing.T) {
path := filepath.Join(os.TempDir(), "resourcefile") path := filepath.Join(os.TempDir(), "resourcefile")
//write initial resourcefile to temp path // write initial resourcefile to temp path
err := ioutil.WriteFile(path, []byte(resourcefile), 0666) err := ioutil.WriteFile(path, []byte(resourcefile), 0666)
if !assert.NoError(t, err) { if !assert.NoError(t, err) {
t.FailNow() t.FailNow()
} }
//add a setter definition // add a setter definition
sd := SetterDefinition{ sd := SetterDefinition{
Name: "image", Name: "image",
Value: "1", Value: "1",

View File

@@ -353,6 +353,8 @@ type SetOpenAPI struct {
Description string `yaml:"description"` Description string `yaml:"description"`
SetBy string `yaml:"setBy"` SetBy string `yaml:"setBy"`
IsSet bool `yaml:"isSet"`
} }
// UpdateFile updates the OpenAPI definitions in a file with the given setter value. // UpdateFile updates the OpenAPI definitions in a file with the given setter value.
@@ -458,8 +460,10 @@ func (s SetOpenAPI) Filter(object *yaml.RNode) (*yaml.RNode, error) {
return nil, err return nil, err
} }
if err := def.PipeE(&yaml.FieldSetter{Name: "isSet", StringValue: "true"}); err != nil { if s.IsSet {
return nil, err if err := def.PipeE(&yaml.FieldSetter{Name: "isSet", StringValue: "true"}); err != nil {
return nil, err
}
} }
if s.Description != "" { if s.Description != "" {

View File

@@ -971,11 +971,13 @@ func TestSetOpenAPI_Filter(t *testing.T) {
description string description string
setBy string setBy string
err string err string
isSet bool
}{ }{
{ {
name: "set-replicas", name: "set-replicas",
setter: "replicas", setter: "replicas",
value: "3", value: "3",
isSet: true,
input: ` input: `
openAPI: openAPI:
definitions: definitions:
@@ -1023,6 +1025,7 @@ openAPI:
name: "set-annotation-quoted", name: "set-annotation-quoted",
setter: "replicas", setter: "replicas",
value: "3", value: "3",
isSet: true,
input: ` input: `
openAPI: openAPI:
definitions: definitions:
@@ -1048,6 +1051,7 @@ openAPI:
setter: "replicas", setter: "replicas",
value: "3", value: "3",
description: "hello world", description: "hello world",
isSet: true,
input: ` input: `
openAPI: openAPI:
definitions: definitions:
@@ -1094,6 +1098,7 @@ openAPI:
setter: "replicas", setter: "replicas",
value: "3", value: "3",
setBy: "carl", setBy: "carl",
isSet: true,
input: ` input: `
openAPI: openAPI:
definitions: definitions:
@@ -1139,6 +1144,7 @@ openAPI:
name: "set-replicas-set-by-empty", name: "set-replicas-set-by-empty",
setter: "replicas", setter: "replicas",
value: "3", value: "3",
isSet: true,
input: ` input: `
openAPI: openAPI:
definitions: definitions:
@@ -1229,7 +1235,6 @@ openAPI:
enumValues: enumValues:
foo: bar foo: bar
baz: biz baz: biz
isSet: true
io.k8s.cli.setters.no-match-2': io.k8s.cli.setters.no-match-2':
x-k8s-cli: x-k8s-cli:
setter: setter:
@@ -1242,6 +1247,7 @@ openAPI:
name: "set-replicas-fail", name: "set-replicas-fail",
setter: "replicas", setter: "replicas",
value: "hello", value: "hello",
isSet: true,
input: ` input: `
openAPI: openAPI:
definitions: definitions:
@@ -1272,6 +1278,7 @@ openAPI:
name: "error", name: "error",
setter: "replicas", setter: "replicas",
err: `setter "replicas" is not found`, err: `setter "replicas" is not found`,
isSet: true,
input: ` input: `
openAPI: openAPI:
definitions: definitions:
@@ -1328,7 +1335,6 @@ openAPI:
name: args name: args
listValues: ["2", "3", "4"] listValues: ["2", "3", "4"]
required: true required: true
isSet: true
`, `,
}, },
} }
@@ -1343,7 +1349,7 @@ openAPI:
// invoke the setter // invoke the setter
instance := &SetOpenAPI{ instance := &SetOpenAPI{
Name: test.setter, Value: test.value, ListValues: test.values, Name: test.setter, Value: test.value, ListValues: test.values,
SetBy: test.setBy, Description: test.description} SetBy: test.setBy, Description: test.description, IsSet: test.isSet}
result, err := instance.Filter(in) result, err := instance.Filter(in)
if test.err != "" { if test.err != "" {
if !assert.EqualError(t, err, test.err) { if !assert.EqualError(t, err, test.err) {

View File

@@ -38,6 +38,8 @@ type FieldSetter struct {
ResourcesPath string ResourcesPath string
RecurseSubPackages bool RecurseSubPackages bool
IsSet bool
} }
func (fs *FieldSetter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) { func (fs *FieldSetter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
@@ -54,6 +56,7 @@ func (fs FieldSetter) Set() (int, error) {
ListValues: fs.ListValues, ListValues: fs.ListValues,
Description: fs.Description, Description: fs.Description,
SetBy: fs.SetBy, SetBy: fs.SetBy,
IsSet: fs.IsSet,
} }
// the input field value is updated in the openAPI file and then parsed // the input field value is updated in the openAPI file and then parsed
@@ -156,6 +159,7 @@ func syncOpenAPIValuesWithSchema(openAPIPath string) error {
Name: cliExt.Setter.Name, Name: cliExt.Setter.Name,
Value: cliExt.Setter.Value, Value: cliExt.Setter.Value,
ListValues: cliExt.Setter.ListValues, ListValues: cliExt.Setter.ListValues,
IsSet: true,
} }
if err := soa.UpdateFile(openAPIPath); err != nil { if err := soa.UpdateFile(openAPIPath); err != nil {
return err return err

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