mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-14 18:40:55 +00:00
Compare commits
1 Commits
api/v0.2.0
...
version
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9b3a0c971a |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -5,9 +5,6 @@
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
.idea
|
||||
*.iml
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
|
||||
15
.travis.yml
15
.travis.yml
@@ -1,10 +1,7 @@
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
# TODO: Speed up the slowness of the osx travis runs
|
||||
# Maybe cache brew installs?
|
||||
#
|
||||
# TODO: Uncomment when some gets the tests running on Windows.
|
||||
# TODO: Uncomment when tests running on Windows.
|
||||
# - windows
|
||||
|
||||
addons:
|
||||
@@ -23,20 +20,24 @@ git:
|
||||
language: go
|
||||
|
||||
go:
|
||||
- "1.13"
|
||||
- "1.12"
|
||||
|
||||
go_import_path: sigs.k8s.io/kustomize
|
||||
|
||||
before_install:
|
||||
- source ./travis/consider-early-travis-exit.sh
|
||||
- curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s -- -b $(go env GOPATH)/bin v1.17.1
|
||||
- go get -u github.com/monopole/mdrip
|
||||
# The following would install Helm if needed for some reason.
|
||||
# - wget https://storage.googleapis.com/kubernetes-helm/helm-v2.13.1-linux-amd64.tar.gz
|
||||
# - tar -xvzf helm-v2.13.1-linux-amd64.tar.gz
|
||||
# - sudo mv linux-amd64/helm /usr/local/bin/helm
|
||||
|
||||
# Skip the install process; let pre-commit.sh do it.
|
||||
install: true
|
||||
|
||||
script:
|
||||
- ./travis/verify-deps.sh
|
||||
- ./travis/pre-commit.sh
|
||||
- ./travis/kyaml-pre-commit.sh
|
||||
|
||||
# TBD. Suppressing for now.
|
||||
notifications:
|
||||
|
||||
@@ -6,10 +6,6 @@ _As contributors and maintainers of this project, and in the interest of fosteri
|
||||
|
||||
## Getting Started
|
||||
|
||||
Dev guides:
|
||||
|
||||
- [Mac](docs/macDevGuide.md)
|
||||
|
||||
We have full documentation on how to get started contributing here:
|
||||
|
||||
- [Contributor License Agreement](https://git.k8s.io/community/CLA.md) Kubernetes projects require that you sign a Contributor License Agreement (CLA) before we can accept your pull requests
|
||||
|
||||
145
Makefile
145
Makefile
@@ -1,145 +0,0 @@
|
||||
# This Makefile is (and must be) used by
|
||||
# travis/pre-commit.sh to qualify pull requests.
|
||||
#
|
||||
# That script generates all the code that needs
|
||||
# to be generated, and runs all the tests.
|
||||
#
|
||||
# Functionality in that script is gradually moving here.
|
||||
|
||||
MYGOBIN := $(shell go env GOPATH)/bin
|
||||
PATH := $(PATH):$(MYGOBIN)
|
||||
SHELL := env PATH=$(PATH) /bin/bash
|
||||
|
||||
.PHONY: all
|
||||
all: pre-commit
|
||||
|
||||
# The pre-commit.sh script generates, lints and tests.
|
||||
# It uses this makefile. For more clarity, would like
|
||||
# to stop that - any scripts invoked by targets here
|
||||
# shouldn't "call back" to the makefile.
|
||||
.PHONY: pre-commit
|
||||
pre-commit:
|
||||
./travis/pre-commit.sh
|
||||
|
||||
# Version pinned by api/go.mod
|
||||
$(MYGOBIN)/golangci-lint:
|
||||
cd api; \
|
||||
go install github.com/golangci/golangci-lint/cmd/golangci-lint
|
||||
|
||||
# Version pinned by api/go.mod
|
||||
$(MYGOBIN)/mdrip:
|
||||
cd api; \
|
||||
go install github.com/monopole/mdrip
|
||||
|
||||
# Version pinned by api/go.mod
|
||||
$(MYGOBIN)/stringer:
|
||||
cd api; \
|
||||
go install golang.org/x/tools/cmd/stringer
|
||||
|
||||
# Version pinned by api/go.mod
|
||||
$(MYGOBIN)/goimports:
|
||||
cd api; \
|
||||
go install golang.org/x/tools/cmd/goimports
|
||||
|
||||
# TODO: need a new release of the API, followed by a new pluginator.
|
||||
# pluginator v1.1.0 is too old for the code currently needed in the API.
|
||||
# Can release a new one at any time, just haven't done so.
|
||||
# When one has been released,
|
||||
# - uncomment the pluginator line in './api/internal/tools/tools.go'
|
||||
# - pin the version tag in './api/go.mod' to match the new release
|
||||
# - change the following to 'cd api; go install sigs.k8s.io/kustomize/pluginator'
|
||||
$(MYGOBIN)/pluginator:
|
||||
cd pluginator; \
|
||||
go install .
|
||||
|
||||
.PHONY: install-tools
|
||||
install-tools: \
|
||||
$(MYGOBIN)/goimports \
|
||||
$(MYGOBIN)/golangci-lint \
|
||||
$(MYGOBIN)/mdrip \
|
||||
$(MYGOBIN)/pluginator \
|
||||
$(MYGOBIN)/stringer
|
||||
|
||||
# Builtin plugins are generated code.
|
||||
# Add new items here to create new builtins.
|
||||
builtinplugins = \
|
||||
api/builtins/annotationstransformer.go \
|
||||
api/builtins/configmapgenerator.go \
|
||||
api/builtins/hashtransformer.go \
|
||||
api/builtins/imagetagtransformer.go \
|
||||
api/builtins/inventorytransformer.go \
|
||||
api/builtins/labeltransformer.go \
|
||||
api/builtins/legacyordertransformer.go \
|
||||
api/builtins/namespacetransformer.go \
|
||||
api/builtins/patchjson6902transformer.go \
|
||||
api/builtins/patchstrategicmergetransformer.go \
|
||||
api/builtins/patchtransformer.go \
|
||||
api/builtins/prefixsuffixtransformer.go \
|
||||
api/builtins/replicacounttransformer.go \
|
||||
api/builtins/secretgenerator.go
|
||||
|
||||
.PHONY: lint
|
||||
lint: install-tools $(builtinplugins)
|
||||
cd api; $(MYGOBIN)/golangci-lint run ./...
|
||||
cd kustomize; $(MYGOBIN)/golangci-lint run ./...
|
||||
cd pluginator; $(MYGOBIN)/golangci-lint run ./...
|
||||
|
||||
api/builtins/%.go: $(MYGOBIN)/pluginator
|
||||
@echo "generating $*"; \
|
||||
cd plugin/builtin/$*; \
|
||||
go generate .; \
|
||||
cd ../../../api/builtins; \
|
||||
$(MYGOBIN)/goimports -w $*.go
|
||||
|
||||
.PHONY: generate
|
||||
generate: $(builtinplugins)
|
||||
|
||||
.PHONY: unit-test-api
|
||||
unit-test-api: $(builtinplugins)
|
||||
cd api; go test ./...
|
||||
|
||||
.PHONY: unit-test-plugins
|
||||
unit-test-plugins:
|
||||
./hack/runPluginUnitTests.sh
|
||||
|
||||
.PHONY: unit-test-kustomize
|
||||
unit-test-kustomize:
|
||||
cd kustomize; go test ./...
|
||||
|
||||
.PHONY: unit-test-all
|
||||
unit-test-all: unit-test-api unit-test-kustomize unit-test-plugins
|
||||
|
||||
# linux only.
|
||||
# This is for testing an example plugin that
|
||||
# uses kubeval for validation.
|
||||
# Don't want to add a hard dependence in go.mod file
|
||||
# to github.com/instrumenta/kubeval.
|
||||
# Instead, download the binary.
|
||||
$(MYGOBIN)/kubeval:
|
||||
d=$(shell mktemp -d); cd $$d; \
|
||||
wget https://github.com/instrumenta/kubeval/releases/latest/download/kubeval-linux-amd64.tar.gz; \
|
||||
tar xf kubeval-linux-amd64.tar.gz; \
|
||||
mv kubeval $(MYGOBIN); \
|
||||
rm -rf $$d
|
||||
|
||||
# linux only.
|
||||
# This is for testing an example plugin that
|
||||
# uses helm to inflate a chart for subsequent kustomization.
|
||||
# Don't want to add a hard dependence in go.mod file
|
||||
# to helm.
|
||||
# Instead, download the binary.
|
||||
$(MYGOBIN)/helm:
|
||||
d=$(shell mktemp -d); cd $$d; \
|
||||
wget https://storage.googleapis.com/kubernetes-helm/helm-v2.13.1-linux-amd64.tar.gz; \
|
||||
tar -xvzf helm-v2.13.1-linux-amd64.tar.gz; \
|
||||
mv linux-amd64/helm $(MYGOBIN); \
|
||||
rm -rf $$d
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f $(builtinplugins)
|
||||
rm -f $(MYGOBIN)/pluginator
|
||||
|
||||
.PHONY: nuke
|
||||
nuke: clean
|
||||
sudo rm -rf $(shell go env GOPATH)/pkg/mod/sigs.k8s.io
|
||||
15
README.md
15
README.md
@@ -22,17 +22,8 @@ these [instructions](docs/INSTALL.md).
|
||||
Browse the [docs](docs) or jump right into the
|
||||
tested [examples](examples).
|
||||
|
||||
## kubectl integration
|
||||
kustomize [v2.0.3] is available in [kubectl v1.15][kubectl].
|
||||
|
||||
Since [v1.14][kubectl announcement] the kustomize build system has been included in kubectl.
|
||||
|
||||
| kubectl version | kustomize version |
|
||||
|---------|--------|
|
||||
| v1.16.0 | [v2.0.3](https://github.com/kubernetes-sigs/kustomize/tree/v2.0.3) |
|
||||
| v1.15.x | [v2.0.3](https://github.com/kubernetes-sigs/kustomize/tree/v2.0.3) |
|
||||
| v1.14.x | [v2.0.3](https://github.com/kubernetes-sigs/kustomize/tree/v2.0.3) |
|
||||
|
||||
For examples and guides for using the kubectl integration please see the [kubectl book] or the [kubernetes documentation].
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -168,9 +159,7 @@ is governed by the [Kubernetes Code of Conduct].
|
||||
[imageBase]: docs/images/base.jpg
|
||||
[imageOverlay]: docs/images/overlay.jpg
|
||||
[kind/feature]: https://github.com/kubernetes-sigs/kustomize/labels/kind%2Ffeature
|
||||
[kubectl announcement]: https://kubernetes.io/blog/2019/03/25/kubernetes-1-14-release-announcement
|
||||
[kubectl book]: https://kubectl.docs.kubernetes.io/pages/app_customization/introduction.html
|
||||
[kubernetes documentation]: https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/
|
||||
[kubectl]: https://kubernetes.io/blog/2019/03/25/kubernetes-1-14-release-announcement
|
||||
[kubernetes style]: docs/glossary.md#kubernetes-style-object
|
||||
[kustomization]: docs/glossary.md#kustomization
|
||||
[overlay]: docs/glossary.md#overlay
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
// Code generated by pluginator on AnnotationsTransformer; DO NOT EDIT.
|
||||
// pluginator {unknown 1970-01-01T00:00:00Z }
|
||||
|
||||
package builtins
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/transform"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// Add the given annotations to the given field specifications.
|
||||
type AnnotationsTransformerPlugin struct {
|
||||
Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
|
||||
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
|
||||
func (p *AnnotationsTransformerPlugin) Config(
|
||||
h *resmap.PluginHelpers, c []byte) (err error) {
|
||||
p.Annotations = nil
|
||||
p.FieldSpecs = nil
|
||||
return yaml.Unmarshal(c, p)
|
||||
}
|
||||
|
||||
func (p *AnnotationsTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
t, err := transform.NewMapTransformer(
|
||||
p.FieldSpecs,
|
||||
p.Annotations,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return t.Transform(m)
|
||||
}
|
||||
|
||||
func NewAnnotationsTransformerPlugin() resmap.TransformerPlugin {
|
||||
return &AnnotationsTransformerPlugin{}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package builtins holds code generated from the builtin plugins.
|
||||
// The "builtin" plugins are written as normal plugins and can
|
||||
// be used as such, but they are also used to generate the code
|
||||
// in this package so they can be statically linked to client code.
|
||||
package builtins
|
||||
@@ -1,39 +0,0 @@
|
||||
// Code generated by pluginator on LabelTransformer; DO NOT EDIT.
|
||||
// pluginator {unknown 1970-01-01T00:00:00Z }
|
||||
|
||||
package builtins
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/transform"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// Add the given labels to the given field specifications.
|
||||
type LabelTransformerPlugin struct {
|
||||
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
|
||||
func (p *LabelTransformerPlugin) Config(
|
||||
h *resmap.PluginHelpers, c []byte) (err error) {
|
||||
p.Labels = nil
|
||||
p.FieldSpecs = nil
|
||||
return yaml.Unmarshal(c, p)
|
||||
}
|
||||
|
||||
func (p *LabelTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
t, err := transform.NewMapTransformer(
|
||||
p.FieldSpecs,
|
||||
p.Labels,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return t.Transform(m)
|
||||
}
|
||||
|
||||
func NewLabelTransformerPlugin() resmap.TransformerPlugin {
|
||||
return &LabelTransformerPlugin{}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
// Code generated by pluginator on NamespaceTransformer; DO NOT EDIT.
|
||||
// pluginator {unknown 1970-01-01T00:00:00Z }
|
||||
|
||||
package builtins
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/transform"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// Change or set the namespace of non-cluster level resources.
|
||||
type NamespaceTransformerPlugin struct {
|
||||
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
|
||||
func (p *NamespaceTransformerPlugin) Config(
|
||||
h *resmap.PluginHelpers, c []byte) (err error) {
|
||||
p.Namespace = ""
|
||||
p.FieldSpecs = nil
|
||||
return yaml.Unmarshal(c, p)
|
||||
}
|
||||
|
||||
func (p *NamespaceTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
if len(p.Namespace) == 0 {
|
||||
return nil
|
||||
}
|
||||
for _, r := range m.Resources() {
|
||||
if len(r.Map()) == 0 {
|
||||
// Don't mutate empty objects?
|
||||
continue
|
||||
}
|
||||
|
||||
id := r.OrgId()
|
||||
applicableFs := p.applicableFieldSpecs(id)
|
||||
|
||||
for _, fs := range applicableFs {
|
||||
err := transform.MutateField(
|
||||
r.Map(), fs.PathSlice(), fs.CreateIfNotPresent,
|
||||
p.changeNamespace(r))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
matches := m.GetMatchingResourcesByCurrentId(r.CurId().Equals)
|
||||
if len(matches) != 1 {
|
||||
return fmt.Errorf("namespace tranformation produces ID conflict: %#v", matches)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
const metaNamespace = "metadata/namespace"
|
||||
|
||||
// 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 != metaNamespace || (fs.Path == metaNamespace && id.IsNamespaceableKind())) {
|
||||
res = append(res, fs)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (p *NamespaceTransformerPlugin) changeNamespace(
|
||||
referrer *resource.Resource) func(in interface{}) (interface{}, error) {
|
||||
return func(in interface{}) (interface{}, error) {
|
||||
switch in.(type) {
|
||||
case string:
|
||||
// will happen when the metadata/namespace
|
||||
// value is replaced
|
||||
return p.Namespace, nil
|
||||
case []interface{}:
|
||||
l, _ := in.([]interface{})
|
||||
for idx, item := range l {
|
||||
switch item.(type) {
|
||||
case map[string]interface{}:
|
||||
// Will happen when mutating the subjects
|
||||
// field of ClusterRoleBinding and RoleBinding
|
||||
inMap, _ := item.(map[string]interface{})
|
||||
if _, ok := inMap["name"]; !ok {
|
||||
continue
|
||||
}
|
||||
name, ok := inMap["name"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
// The only case we need to force the namespace
|
||||
// if for the "service account". "default" is
|
||||
// kind of hardcoded here for right now.
|
||||
if name != "default" {
|
||||
continue
|
||||
}
|
||||
inMap["namespace"] = p.Namespace
|
||||
l[idx] = inMap
|
||||
default:
|
||||
// nothing to do for right now
|
||||
}
|
||||
}
|
||||
return in, nil
|
||||
case map[string]interface{}:
|
||||
// Will happen if the createField=true
|
||||
// when the namespace is added to the
|
||||
// object
|
||||
inMap := in.(map[string]interface{})
|
||||
if len(inMap) == 0 {
|
||||
return p.Namespace, nil
|
||||
} else {
|
||||
return in, nil
|
||||
}
|
||||
default:
|
||||
return in, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewNamespaceTransformerPlugin() resmap.TransformerPlugin {
|
||||
return &NamespaceTransformerPlugin{}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
// Code generated by pluginator on PatchStrategicMergeTransformer; DO NOT EDIT.
|
||||
// pluginator {unknown 1970-01-01T00:00:00Z }
|
||||
|
||||
package builtins
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
type PatchStrategicMergeTransformerPlugin struct {
|
||||
h *resmap.PluginHelpers
|
||||
loadedPatches []*resource.Resource
|
||||
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
|
||||
Patches string `json:"patches,omitempty" yaml:"patches,omitempty"`
|
||||
}
|
||||
|
||||
func (p *PatchStrategicMergeTransformerPlugin) Config(
|
||||
h *resmap.PluginHelpers, c []byte) (err error) {
|
||||
p.h = h
|
||||
err = yaml.Unmarshal(c, p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(p.Paths) == 0 && p.Patches == "" {
|
||||
return fmt.Errorf("empty file path and empty patch content")
|
||||
}
|
||||
if len(p.Paths) != 0 {
|
||||
for _, onePath := range p.Paths {
|
||||
res, err := p.h.ResmapFactory().RF().SliceFromBytes([]byte(onePath))
|
||||
if err == nil {
|
||||
p.loadedPatches = append(p.loadedPatches, res...)
|
||||
continue
|
||||
}
|
||||
res, err = p.h.ResmapFactory().RF().SliceFromPatches(
|
||||
p.h.Loader(), []types.PatchStrategicMerge{onePath})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.loadedPatches = append(p.loadedPatches, res...)
|
||||
}
|
||||
}
|
||||
if p.Patches != "" {
|
||||
res, err := p.h.ResmapFactory().RF().SliceFromBytes([]byte(p.Patches))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.loadedPatches = append(p.loadedPatches, res...)
|
||||
}
|
||||
|
||||
if len(p.loadedPatches) == 0 {
|
||||
return fmt.Errorf(
|
||||
"patch appears to be empty; files=%v, Patch=%s", p.Paths, p.Patches)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PatchStrategicMergeTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
patches, err := p.h.ResmapFactory().MergePatches(p.loadedPatches)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, patch := range patches.Resources() {
|
||||
target, err := m.GetById(patch.OrgId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = target.Patch(patch.Kunstructured)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// remove the resource from resmap
|
||||
// when the patch is to $patch: delete that target
|
||||
if len(target.Map()) == 0 {
|
||||
err = m.Remove(target.CurId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewPatchStrategicMergeTransformerPlugin() resmap.TransformerPlugin {
|
||||
return &PatchStrategicMergeTransformerPlugin{}
|
||||
}
|
||||
@@ -1,145 +0,0 @@
|
||||
// Code generated by pluginator on PatchTransformer; DO NOT EDIT.
|
||||
// pluginator {unknown 1970-01-01T00:00:00Z }
|
||||
|
||||
package builtins
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
type PatchTransformerPlugin struct {
|
||||
loadedPatch *resource.Resource
|
||||
decodedPatch jsonpatch.Patch
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
||||
Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"`
|
||||
}
|
||||
|
||||
func (p *PatchTransformerPlugin) Config(
|
||||
h *resmap.PluginHelpers, c []byte) (err error) {
|
||||
err = yaml.Unmarshal(c, p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if p.Patch == "" && p.Path == "" {
|
||||
err = fmt.Errorf(
|
||||
"must specify one of patch and path in\n%s", string(c))
|
||||
return
|
||||
}
|
||||
if p.Patch != "" && p.Path != "" {
|
||||
err = fmt.Errorf(
|
||||
"patch and path can't be set at the same time\n%s", string(c))
|
||||
return
|
||||
}
|
||||
var in []byte
|
||||
if p.Path != "" {
|
||||
in, err = h.Loader().Load(p.Path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
if p.Patch != "" {
|
||||
in = []byte(p.Patch)
|
||||
}
|
||||
|
||||
patchSM, errSM := h.ResmapFactory().RF().FromBytes(in)
|
||||
patchJson, errJson := jsonPatchFromBytes(in)
|
||||
if errSM != nil && errJson != nil {
|
||||
err = fmt.Errorf(
|
||||
"unable to get either a Strategic Merge Patch or JSON patch 6902 from %s", p.Patch)
|
||||
return
|
||||
}
|
||||
if errSM == nil && errJson != nil {
|
||||
p.loadedPatch = patchSM
|
||||
}
|
||||
if errJson == nil && errSM != nil {
|
||||
p.decodedPatch = patchJson
|
||||
}
|
||||
if patchSM != nil && patchJson != nil {
|
||||
err = fmt.Errorf(
|
||||
"a patch can't be both a Strategic Merge Patch and JSON patch 6902 %s", p.Patch)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PatchTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
if p.loadedPatch != nil && p.Target == nil {
|
||||
target, err := m.GetById(p.loadedPatch.OrgId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = target.Patch(p.loadedPatch.Kunstructured)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if p.Target == nil {
|
||||
return fmt.Errorf("must specify a target for patch %s", p.Patch)
|
||||
}
|
||||
|
||||
resources, err := m.Select(*p.Target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, res := range resources {
|
||||
if p.decodedPatch != nil {
|
||||
rawObj, err := res.MarshalJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
modifiedObj, err := p.decodedPatch.Apply(rawObj)
|
||||
if err != nil {
|
||||
return errors.Wrapf(
|
||||
err, "failed to apply json patch '%s'", p.Patch)
|
||||
}
|
||||
err = res.UnmarshalJSON(modifiedObj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if p.loadedPatch != nil {
|
||||
patchCopy := p.loadedPatch.DeepCopy()
|
||||
patchCopy.SetName(res.GetName())
|
||||
patchCopy.SetNamespace(res.GetNamespace())
|
||||
patchCopy.SetGvk(res.GetGvk())
|
||||
err = res.Patch(patchCopy.Kunstructured)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// jsonPatchFromBytes loads a Json 6902 patch from
|
||||
// a bytes input
|
||||
func jsonPatchFromBytes(
|
||||
in []byte) (jsonpatch.Patch, error) {
|
||||
ops := string(in)
|
||||
if ops == "" {
|
||||
return nil, fmt.Errorf("empty json patch operations")
|
||||
}
|
||||
|
||||
if ops[0] != '[' {
|
||||
jsonOps, err := yaml.YAMLToJSON(in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ops = string(jsonOps)
|
||||
}
|
||||
return jsonpatch.DecodePatch([]byte(ops))
|
||||
}
|
||||
|
||||
func NewPatchTransformerPlugin() resmap.TransformerPlugin {
|
||||
return &PatchTransformerPlugin{}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package filesys
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
var _ os.FileInfo = &fileInfo{}
|
||||
|
||||
// fileInfo implements os.FileInfo for a fileInMemory instance.
|
||||
type fileInfo struct {
|
||||
*fileInMemory
|
||||
}
|
||||
|
||||
// Name returns the name of the file
|
||||
func (fi *fileInfo) Name() string { return fi.name }
|
||||
|
||||
// Size returns the size of the file
|
||||
func (fi *fileInfo) Size() int64 { return int64(len(fi.content)) }
|
||||
|
||||
// Mode returns the file mode
|
||||
func (fi *fileInfo) Mode() os.FileMode { return 0777 }
|
||||
|
||||
// ModTime returns the modification time
|
||||
func (fi *fileInfo) ModTime() time.Time { return time.Time{} }
|
||||
|
||||
// IsDir returns if it is a directory
|
||||
func (fi *fileInfo) IsDir() bool { return fi.dir }
|
||||
|
||||
// Sys should return underlying data source, but it now returns nil
|
||||
func (fi *fileInfo) Sys() interface{} { return nil }
|
||||
|
||||
// File groups the basic os.File methods.
|
||||
type File interface {
|
||||
io.ReadWriteCloser
|
||||
Stat() (os.FileInfo, error)
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package filesys
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
)
|
||||
|
||||
var _ File = &fileInMemory{}
|
||||
|
||||
// fileInMemory implements File in-memory for tests.
|
||||
type fileInMemory struct {
|
||||
name string
|
||||
content []byte
|
||||
dir bool
|
||||
open bool
|
||||
}
|
||||
|
||||
// makeDir makes a fake directory.
|
||||
func makeDir(name string) *fileInMemory {
|
||||
return &fileInMemory{name: name, dir: true}
|
||||
}
|
||||
|
||||
// Close marks the fake file closed.
|
||||
func (f *fileInMemory) Close() error {
|
||||
f.open = false
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read never fails, and doesn't mutate p.
|
||||
func (f *fileInMemory) Read(p []byte) (n int, err error) {
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// Write saves the contents of the argument to memory.
|
||||
func (f *fileInMemory) Write(p []byte) (n int, err error) {
|
||||
f.content = p
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// ContentMatches returns true if v matches fake file's content.
|
||||
func (f *fileInMemory) ContentMatches(v []byte) bool {
|
||||
return bytes.Equal(v, f.content)
|
||||
}
|
||||
|
||||
// GetContent the content of a fake file.
|
||||
func (f *fileInMemory) GetContent() []byte {
|
||||
return f.content
|
||||
}
|
||||
|
||||
// Stat returns nil.
|
||||
func (f *fileInMemory) Stat() (os.FileInfo, error) {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package filesys
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
var _ File = &fileOnDisk{}
|
||||
|
||||
// fileOnDisk implements File using the local filesystem.
|
||||
type fileOnDisk struct {
|
||||
file *os.File
|
||||
}
|
||||
|
||||
// Close closes a file.
|
||||
func (f *fileOnDisk) Close() error { return f.file.Close() }
|
||||
|
||||
// Read reads a file's content.
|
||||
func (f *fileOnDisk) Read(p []byte) (n int, err error) { return f.file.Read(p) }
|
||||
|
||||
// Write writes bytes to a file
|
||||
func (f *fileOnDisk) Write(p []byte) (n int, err error) { return f.file.Write(p) }
|
||||
|
||||
// Stat returns an interface which has all the information regarding the file.
|
||||
func (f *fileOnDisk) Stat() (os.FileInfo, error) { return f.file.Stat() }
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package filesys provides a file system abstraction layer.
|
||||
package filesys
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// FileSystem groups basic os filesystem methods.
|
||||
type FileSystem interface {
|
||||
// Create a file.
|
||||
Create(name string) (File, error)
|
||||
// MkDir makes a directory.
|
||||
Mkdir(path string) error
|
||||
// MkDir makes a directory path, creating intervening directories.
|
||||
MkdirAll(path string) error
|
||||
// RemoveAll removes path and any children it contains.
|
||||
RemoveAll(path string) error
|
||||
// Open opens the named file for reading.
|
||||
Open(path string) (File, error)
|
||||
// IsDir returns true if the path is a directory.
|
||||
IsDir(path string) bool
|
||||
// CleanedAbs converts the given path into a
|
||||
// directory and a file name, where the directory
|
||||
// is represented as a ConfirmedDir and all that implies.
|
||||
// If the entire path is a directory, the file component
|
||||
// is an empty string.
|
||||
CleanedAbs(path string) (ConfirmedDir, string, error)
|
||||
// Exists is true if the path exists in the file system.
|
||||
Exists(path string) bool
|
||||
// Glob returns the list of matching files
|
||||
Glob(pattern string) ([]string, error)
|
||||
// ReadFile returns the contents of the file at the given path.
|
||||
ReadFile(path string) ([]byte, error)
|
||||
// WriteFile writes the data to a file at the given path.
|
||||
WriteFile(path string, data []byte) error
|
||||
// Walk walks the file system with the given WalkFunc.
|
||||
Walk(path string, walkFn filepath.WalkFunc) error
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package filesys
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var _ FileSystem = &fsInMemory{}
|
||||
|
||||
// fsInMemory implements FileSystem using a in-memory filesystem
|
||||
// primarily for use in tests.
|
||||
type fsInMemory struct {
|
||||
m map[string]*fileInMemory
|
||||
}
|
||||
|
||||
// MakeFsInMemory returns an instance of fsInMemory with no files in it.
|
||||
func MakeFsInMemory() FileSystem {
|
||||
result := &fsInMemory{m: map[string]*fileInMemory{}}
|
||||
result.Mkdir(separator)
|
||||
return result
|
||||
}
|
||||
|
||||
const (
|
||||
separator = string(filepath.Separator)
|
||||
doubleSep = separator + separator
|
||||
)
|
||||
|
||||
// Create assures a fake file appears in the in-memory file system.
|
||||
func (fs *fsInMemory) Create(name string) (File, error) {
|
||||
f := &fileInMemory{}
|
||||
f.open = true
|
||||
fs.m[name] = f
|
||||
return fs.m[name], nil
|
||||
}
|
||||
|
||||
// Mkdir assures a fake directory appears in the in-memory file system.
|
||||
func (fs *fsInMemory) Mkdir(name string) error {
|
||||
fs.m[name] = makeDir(name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// MkdirAll delegates to Mkdir
|
||||
func (fs *fsInMemory) MkdirAll(name string) error {
|
||||
return fs.Mkdir(name)
|
||||
}
|
||||
|
||||
// RemoveAll presumably does rm -r on a path.
|
||||
// There's no error.
|
||||
func (fs *fsInMemory) RemoveAll(name string) error {
|
||||
var toRemove []string
|
||||
for k := range fs.m {
|
||||
if strings.HasPrefix(k, name) {
|
||||
toRemove = append(toRemove, k)
|
||||
}
|
||||
}
|
||||
for _, k := range toRemove {
|
||||
delete(fs.m, k)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Open returns a fake file in the open state.
|
||||
func (fs *fsInMemory) Open(name string) (File, error) {
|
||||
if _, found := fs.m[name]; !found {
|
||||
return nil, fmt.Errorf("file %q cannot be opened", name)
|
||||
}
|
||||
return fs.m[name], nil
|
||||
}
|
||||
|
||||
// CleanedAbs cannot fail.
|
||||
func (fs *fsInMemory) CleanedAbs(path string) (ConfirmedDir, string, error) {
|
||||
if fs.IsDir(path) {
|
||||
return ConfirmedDir(path), "", nil
|
||||
}
|
||||
d := filepath.Dir(path)
|
||||
if d == path {
|
||||
return ConfirmedDir(d), "", nil
|
||||
}
|
||||
return ConfirmedDir(d), filepath.Base(path), nil
|
||||
}
|
||||
|
||||
// Exists returns true if file is known.
|
||||
func (fs *fsInMemory) Exists(name string) bool {
|
||||
_, found := fs.m[name]
|
||||
return found
|
||||
}
|
||||
|
||||
// Glob returns the list of matching files
|
||||
func (fs *fsInMemory) Glob(pattern string) ([]string, error) {
|
||||
var result []string
|
||||
for p := range fs.m {
|
||||
if fs.pathMatch(p, pattern) {
|
||||
result = append(result, p)
|
||||
}
|
||||
}
|
||||
sort.Strings(result)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// IsDir returns true if the file exists and is a directory.
|
||||
func (fs *fsInMemory) IsDir(name string) bool {
|
||||
f, found := fs.m[name]
|
||||
if found && f.dir {
|
||||
return true
|
||||
}
|
||||
if !strings.HasSuffix(name, separator) {
|
||||
name = name + separator
|
||||
}
|
||||
for k := range fs.m {
|
||||
if strings.HasPrefix(k, name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ReadFile always returns an empty bytes and error depending on content of m.
|
||||
func (fs *fsInMemory) ReadFile(name string) ([]byte, error) {
|
||||
if ff, found := fs.m[name]; found {
|
||||
return ff.content, nil
|
||||
}
|
||||
return nil, fmt.Errorf("cannot read file %q", name)
|
||||
}
|
||||
|
||||
// WriteFile always succeeds and does nothing.
|
||||
func (fs *fsInMemory) WriteFile(name string, c []byte) error {
|
||||
ff := &fileInMemory{}
|
||||
ff.Write(c)
|
||||
fs.m[name] = ff
|
||||
return nil
|
||||
}
|
||||
|
||||
// Walk implements filepath.Walk using the fake filesystem.
|
||||
func (fs *fsInMemory) Walk(path string, walkFn filepath.WalkFunc) error {
|
||||
info, err := fs.lstat(path)
|
||||
if err != nil {
|
||||
err = walkFn(path, info, err)
|
||||
} else {
|
||||
err = fs.walk(path, info, walkFn)
|
||||
}
|
||||
if err == filepath.SkipDir {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (fs *fsInMemory) pathMatch(path, pattern string) bool {
|
||||
match, _ := filepath.Match(pattern, path)
|
||||
return match
|
||||
}
|
||||
|
||||
func (fs *fsInMemory) lstat(path string) (*fileInfo, error) {
|
||||
f, found := fs.m[path]
|
||||
if !found {
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
return &fileInfo{f}, nil
|
||||
}
|
||||
|
||||
func (fs *fsInMemory) join(elem ...string) string {
|
||||
for i, e := range elem {
|
||||
if e != "" {
|
||||
return strings.Replace(
|
||||
strings.Join(elem[i:], separator), doubleSep, separator, -1)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (fs *fsInMemory) readDirNames(path string) []string {
|
||||
var names []string
|
||||
if !strings.HasSuffix(path, separator) {
|
||||
path += separator
|
||||
}
|
||||
pathSegments := strings.Count(path, separator)
|
||||
for name := range fs.m {
|
||||
if name == path {
|
||||
continue
|
||||
}
|
||||
if strings.Count(name, separator) > pathSegments {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(name, path) {
|
||||
names = append(names, filepath.Base(name))
|
||||
}
|
||||
}
|
||||
sort.Strings(names)
|
||||
return names
|
||||
}
|
||||
|
||||
func (fs *fsInMemory) walk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error {
|
||||
if !info.IsDir() {
|
||||
return walkFn(path, info, nil)
|
||||
}
|
||||
|
||||
names := fs.readDirNames(path)
|
||||
if err := walkFn(path, info, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, name := range names {
|
||||
filename := fs.join(path, name)
|
||||
fileInfo, err := fs.lstat(filename)
|
||||
if err != nil {
|
||||
if err := walkFn(filename, fileInfo, os.ErrNotExist); err != nil && err != filepath.SkipDir {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err = fs.walk(filename, fileInfo, walkFn)
|
||||
if err != nil {
|
||||
if !fileInfo.IsDir() || err != filepath.SkipDir {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package filesys_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
. "sigs.k8s.io/kustomize/api/filesys"
|
||||
)
|
||||
|
||||
func TestExists(t *testing.T) {
|
||||
fSys := MakeFsInMemory()
|
||||
if fSys.Exists("foo") {
|
||||
t.Fatalf("expected no foo")
|
||||
}
|
||||
fSys.Mkdir("/")
|
||||
if !fSys.IsDir("/") {
|
||||
t.Fatalf("expected dir at /")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsDir(t *testing.T) {
|
||||
fSys := MakeFsInMemory()
|
||||
expectedName := "my-dir"
|
||||
err := fSys.Mkdir(expectedName)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
shouldExist(t, fSys, expectedName)
|
||||
if !fSys.IsDir(expectedName) {
|
||||
t.Fatalf(expectedName + " should be a dir")
|
||||
}
|
||||
}
|
||||
|
||||
func shouldExist(t *testing.T, fSys FileSystem, name string) {
|
||||
if !fSys.Exists(name) {
|
||||
t.Fatalf(name + " should exist")
|
||||
}
|
||||
}
|
||||
|
||||
func shouldNotExist(t *testing.T, fSys FileSystem, name string) {
|
||||
if fSys.Exists(name) {
|
||||
t.Fatalf(name + " should not exist")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveAll(t *testing.T) {
|
||||
fSys := MakeFsInMemory()
|
||||
fSys.WriteFile("/foo/project/file.yaml", []byte("Unused"))
|
||||
fSys.WriteFile("/foo/project/subdir/file.yaml", []byte("Unused"))
|
||||
fSys.WriteFile("/foo/apple/subdir/file.yaml", []byte("Unused"))
|
||||
shouldExist(t, fSys, "/foo/project/file.yaml")
|
||||
shouldExist(t, fSys, "/foo/project/subdir/file.yaml")
|
||||
shouldExist(t, fSys, "/foo/apple/subdir/file.yaml")
|
||||
err := fSys.RemoveAll("/foo/project")
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
shouldNotExist(t, fSys, "/foo/project/file.yaml")
|
||||
shouldNotExist(t, fSys, "/foo/project/subdir/file.yaml")
|
||||
shouldExist(t, fSys, "/foo/apple/subdir/file.yaml")
|
||||
}
|
||||
|
||||
func TestIsDirDeeper(t *testing.T) {
|
||||
fSys := MakeFsInMemory()
|
||||
fSys.WriteFile("/foo/project/file.yaml", []byte("Unused"))
|
||||
fSys.WriteFile("/foo/project/subdir/file.yaml", []byte("Unused"))
|
||||
if !fSys.IsDir("/") {
|
||||
t.Fatalf("/ should be a dir")
|
||||
}
|
||||
if !fSys.IsDir("/foo") {
|
||||
t.Fatalf("/foo should be a dir")
|
||||
}
|
||||
if !fSys.IsDir("/foo/project") {
|
||||
t.Fatalf("/foo/project should be a dir")
|
||||
}
|
||||
if fSys.IsDir("/fo") {
|
||||
t.Fatalf("/fo should not be a dir")
|
||||
}
|
||||
if fSys.IsDir("/x") {
|
||||
t.Fatalf("/x should not be a dir")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
fSys := MakeFsInMemory()
|
||||
f, err := fSys.Create("foo")
|
||||
if f == nil {
|
||||
t.Fatalf("expected file")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error")
|
||||
}
|
||||
shouldExist(t, fSys, "foo")
|
||||
}
|
||||
|
||||
func TestReadFile(t *testing.T) {
|
||||
fSys := MakeFsInMemory()
|
||||
f, err := fSys.Create("foo")
|
||||
if f == nil {
|
||||
t.Fatalf("expected file")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error")
|
||||
}
|
||||
content, err := fSys.ReadFile("foo")
|
||||
if len(content) != 0 {
|
||||
t.Fatalf("expected no content")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteFile(t *testing.T) {
|
||||
fSys := MakeFsInMemory()
|
||||
c := []byte("heybuddy")
|
||||
err := fSys.WriteFile("foo", c)
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error")
|
||||
}
|
||||
content, err := fSys.ReadFile("foo")
|
||||
if err != nil {
|
||||
t.Fatalf("expected read to work: %v", err)
|
||||
}
|
||||
if bytes.Compare(c, content) != 0 {
|
||||
t.Fatalf("incorrect content: %v", content)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGlob(t *testing.T) {
|
||||
fSys := MakeFsInMemory()
|
||||
fSys.Create("dir/foo")
|
||||
fSys.Create("dir/bar")
|
||||
files, err := fSys.Glob("dir/*")
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error")
|
||||
}
|
||||
expected := []string{
|
||||
"dir/bar",
|
||||
"dir/foo",
|
||||
}
|
||||
if !reflect.DeepEqual(files, expected) {
|
||||
t.Fatalf("incorrect files found by glob: %v", files)
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package filesys
|
||||
|
||||
import "path/filepath"
|
||||
|
||||
// RootedPath returns a rooted path, e.g. "/foo/bar" as
|
||||
// opposed to "foo/bar".
|
||||
func RootedPath(elem ...string) string {
|
||||
return separator + filepath.Join(elem...)
|
||||
}
|
||||
18
api/go.mod
18
api/go.mod
@@ -1,18 +0,0 @@
|
||||
module sigs.k8s.io/kustomize/api
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/emicklei/go-restful v2.9.6+incompatible // indirect
|
||||
github.com/evanphx/json-patch v4.5.0+incompatible
|
||||
github.com/go-openapi/spec v0.19.4
|
||||
github.com/golangci/golangci-lint v1.19.1
|
||||
github.com/googleapis/gnostic v0.3.0 // indirect
|
||||
github.com/monopole/mdrip v1.0.0
|
||||
github.com/pkg/errors v0.8.1
|
||||
golang.org/x/tools v0.0.0-20190912215617-3720d1ec3678
|
||||
gopkg.in/yaml.v2 v2.2.4
|
||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a
|
||||
sigs.k8s.io/kustomize/pseudo/k8s v0.1.0
|
||||
sigs.k8s.io/yaml v1.1.0
|
||||
)
|
||||
463
api/go.sum
463
api/go.sum
@@ -1,463 +0,0 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
|
||||
github.com/Azure/go-autorest/autorest v0.9.2/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
|
||||
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
|
||||
github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
|
||||
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
|
||||
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/OpenPeeDeeP/depguard v1.0.1 h1:VlW4R6jmBIv3/u1JNlawEvJMM4J+dPORPaZasQee8Us=
|
||||
github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM=
|
||||
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||
github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emicklei/go-restful v2.9.6+incompatible h1:tfrHha8zJ01ywiOEC1miGY8st1/igzWB8OmvPgoYX7w=
|
||||
github.com/emicklei/go-restful v2.9.6+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=
|
||||
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-critic/go-critic v0.3.5-0.20190904082202-d79a9f0c64db h1:GYXWx7Vr3+zv833u+8IoXbNnQY0AdXsxAgI0kX7xcwA=
|
||||
github.com/go-critic/go-critic v0.3.5-0.20190904082202-d79a9f0c64db/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-lintpack/lintpack v0.5.2 h1:DI5mA3+eKdWeJ40nU4d6Wc26qmdG8RCi/btYq0TuRN0=
|
||||
github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
|
||||
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
|
||||
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
|
||||
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
|
||||
github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w=
|
||||
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
|
||||
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
|
||||
github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo=
|
||||
github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
||||
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
|
||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-toolsmith/astcast v1.0.0 h1:JojxlmI6STnFVG9yOImLeGREv8W2ocNUM+iOhR6jE7g=
|
||||
github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4=
|
||||
github.com/go-toolsmith/astcopy v1.0.0 h1:OMgl1b1MEpjFQ1m5ztEO06rz5CUd3oBv9RF7+DyvdG8=
|
||||
github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ=
|
||||
github.com/go-toolsmith/astequal v0.0.0-20180903214952-dcb477bfacd6/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
|
||||
github.com/go-toolsmith/astequal v1.0.0 h1:4zxD8j3JRFNyLN46lodQuqz3xdKSrur7U/sr0SDS/gQ=
|
||||
github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
|
||||
github.com/go-toolsmith/astfmt v0.0.0-20180903215011-8f8ee99c3086/go.mod h1:mP93XdblcopXwlyN4X4uodxXQhldPGZbcEJIimQHrkg=
|
||||
github.com/go-toolsmith/astfmt v1.0.0 h1:A0vDDXt+vsvLEdbMFJAUBI/uTbRw1ffOPnxsILnFL6k=
|
||||
github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw=
|
||||
github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21/go.mod h1:dDStQCHtmZpYOmjRP/8gHHnCCch3Zz3oEgCdZVdtweU=
|
||||
github.com/go-toolsmith/astp v0.0.0-20180903215135-0af7e3c24f30/go.mod h1:SV2ur98SGypH1UjcPpCatrV5hPazG6+IfNHbkDXBRrk=
|
||||
github.com/go-toolsmith/astp v1.0.0 h1:alXE75TXgcmupDsMK1fRAy0YUzLzqPVvBKoyWV+KPXg=
|
||||
github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI=
|
||||
github.com/go-toolsmith/pkgload v0.0.0-20181119091011-e9e65178eee8/go.mod h1:WoMrjiy4zvdS+Bg6z9jZH82QXwkcgCBX6nOfnmdaHks=
|
||||
github.com/go-toolsmith/pkgload v1.0.0 h1:4DFWWMXVfbcN5So1sBNW9+yeiMqLFGl1wFLTL5R0Tgg=
|
||||
github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc=
|
||||
github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUDxe2Jb4=
|
||||
github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
|
||||
github.com/go-toolsmith/typep v1.0.0 h1:zKymWyA1TRYvqYrYDrfEMZULyrhcnGY3x7LDKU2XQaA=
|
||||
github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 h1:23T5iq8rbUYlhpt5DB4XJkc6BU31uODLD1o1gKvZmD0=
|
||||
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4=
|
||||
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM=
|
||||
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk=
|
||||
github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6 h1:YYWNAGTKWhKpcLLt7aSj/odlKrSrelQwlovBpDuf19w=
|
||||
github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0=
|
||||
github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613 h1:9kfjN3AdxcbsZBf8NjltjWihK2QfBBBZuv91cMFfDHw=
|
||||
github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8=
|
||||
github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3 h1:pe9JHs3cHHDQgOFXJJdYkK6fLz2PWyYtP4hthoCMvs8=
|
||||
github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o=
|
||||
github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee h1:J2XAy40+7yz70uaOiMbNnluTg7gyQhtGqLQncQh+4J8=
|
||||
github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU=
|
||||
github.com/golangci/gofmt v0.0.0-20181222123516-0b8337e80d98 h1:0OkFarm1Zy2CjCiDKfK9XHgmc2wbDlRMD2hD8anAJHU=
|
||||
github.com/golangci/gofmt v0.0.0-20181222123516-0b8337e80d98/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU=
|
||||
github.com/golangci/golangci-lint v1.19.1 h1:g9xL8KW7UZDCkVlgHYJMA6F4Sj/sRVa0FoCeXI+Z3iM=
|
||||
github.com/golangci/golangci-lint v1.19.1/go.mod h1:2CEc4Fxx3vxDv7g8DyXkHCBF73AOzAymcJAprs2vCps=
|
||||
github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc h1:gLLhTLMk2/SutryVJ6D4VZCU3CUqr8YloG7FPIBWFpI=
|
||||
github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU=
|
||||
github.com/golangci/lint-1 v0.0.0-20190420132249-ee948d087217 h1:En/tZdwhAn0JNwLuXzP3k2RVtMqMmOEK7Yu/g3tmtJE=
|
||||
github.com/golangci/lint-1 v0.0.0-20190420132249-ee948d087217/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg=
|
||||
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA=
|
||||
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o=
|
||||
github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770 h1:EL/O5HGrF7Jaq0yNhBLucz9hTuRzj2LdwGBOaENgxIk=
|
||||
github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA=
|
||||
github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21 h1:leSNB7iYzLYSSx3J/s5sVf4Drkc68W2wm4Ixh/mr0us=
|
||||
github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21/go.mod h1:tf5+bzsHdTM0bsB7+8mt0GUMvjCgwLpTapNZHU8AajI=
|
||||
github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0 h1:HVfrLniijszjS1aiNg8JbBMO2+E1WIQ+j/gL4SQqGPg=
|
||||
github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4=
|
||||
github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 h1:zwtduBRr5SSWhqsYNgcuWO2kFlpdOZbP0+yRjmvPGys=
|
||||
github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/googleapis/gnostic v0.3.0 h1:CcQijm0XKekKjP/YCz28LXVSpgguuB+nCxaSjCe09y0=
|
||||
github.com/googleapis/gnostic v0.3.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/gophercloud/gophercloud v0.6.0/go.mod h1:GICNByuaEBibcjmjvI7QvYJSZEbGkcYwAR7EZK2WMqM=
|
||||
github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f h1:9oNbS1z4rVpbnkHBdPZU4jo9bSmrLpII768arSyMFgk=
|
||||
github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.0 h1:UykbtMB/w5No2LmE16gINgLj+r/vbziTgaoERQv6U+0=
|
||||
github.com/gorilla/mux v1.6.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/securecookie v0.0.0-20160422134519-667fe4e3466a h1:YH0IojQwndMQdeRWdw1aPT8bkbiWaYR3WD+Zf5e09DU=
|
||||
github.com/gorilla/securecookie v0.0.0-20160422134519-667fe4e3466a/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v0.0.0-20160922145804-ca9ada445741 h1:OuuPl66BpF1q3OEkaPpp+VfzxrBBY62ATGdWqql/XX8=
|
||||
github.com/gorilla/sessions v0.0.0-20160922145804-ca9ada445741/go.mod h1:+WVp8kdw6VhyKExm03PAMRn2ZxnPtm58pV0dBVPdhHE=
|
||||
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3 h1:JVnpOZS+qxli+rgVl98ILOXVNbW+kb5wcxeGx8ShUIw=
|
||||
github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok=
|
||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/matoous/godox v0.0.0-20190910121045-032ad8106c86 h1:q6SrfsK4FojRnJ1j8+8OJzyq3g9Y1oSVyL6nYGJXXBk=
|
||||
github.com/matoous/godox v0.0.0-20190910121045-032ad8106c86/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
|
||||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/monopole/mdrip v1.0.0 h1:RFDBa+tab6mW+gX4Ww2SZDc4kS6p01FwnLtgz64Il+I=
|
||||
github.com/monopole/mdrip v1.0.0/go.mod h1:N1/ppRG9CaPeUKAUHZ3dUlfOT81lTpKZLkyhCvTETwM=
|
||||
github.com/mozilla/tls-observatory v0.0.0-20190404164649-a3c1b6cfecfd/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
|
||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d h1:AREM5mwr4u1ORQBMvzfzBgpsctsbQikCVpvC+tX285E=
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
|
||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
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 v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
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_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday v2.0.0+incompatible h1:cBXrhZNUf9C+La9/YpS+UHpUT8YD6Td9ZMSU9APFcsk=
|
||||
github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/securego/gosec v0.0.0-20190912120752-140048b2a218 h1:O0yPHYL49quNL4Oj2wVq+zbGMu4dAM6iLoOQtm49TrQ=
|
||||
github.com/securego/gosec v0.0.0-20190912120752-140048b2a218/go.mod h1:q6oYAujd2qyeU4cJqIri4LBIgdHXGvxWHZ1E29HNFRE=
|
||||
github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc=
|
||||
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
|
||||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e h1:MZM7FHLqUHYI0Y/mQAt3d2aYa0SiNms/hFqC9qJYolM=
|
||||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
||||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041 h1:llrF3Fs4018ePo4+G/HV/uQUqEI1HMDjCeOf2V6puPc=
|
||||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/sourcegraph/go-diff v0.5.1 h1:gO6i5zugwzo1RVTvgvfwCOSVegNuvnNi6bAD1QCmkHs=
|
||||
github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
|
||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/timakin/bodyclose v0.0.0-20190721030226-87058b9bfcec h1:AmoEvWAO3nDx1MEcMzPh+GzOOIA5Znpv6++c7bePPY0=
|
||||
github.com/timakin/bodyclose v0.0.0-20190721030226-87058b9bfcec/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ultraware/funlen v0.0.2 h1:Av96YVBwwNSe4MLR7iI/BIa3VyI7/djnto/pK3Uxbdo=
|
||||
github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
|
||||
github.com/ultraware/whitespace v0.0.3 h1:S5BCRRB5sttNy0bSOhbpw+0mb+cHiCmWfrvxpEzuUk0=
|
||||
github.com/ultraware/whitespace v0.0.3/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s=
|
||||
github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4=
|
||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190909003024-a7b16738d86b h1:XfVGCX+0T4WOStkaOsJRllbsiImhB2jgVBGc9L0lPGc=
|
||||
golang.org/x/net v0.0.0-20190909003024-a7b16738d86b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190911201528-7ad0cfa0b7b5 h1:SW/0nsKCUaozCUtZTakri5laocGx/5bkDSSLrFUsa5s=
|
||||
golang.org/x/sys v0.0.0-20190911201528-7ad0cfa0b7b5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
||||
golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911230505-6bfd74cf029c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190912215617-3720d1ec3678 h1:rM1Udd0CgtYI3KUIhu9ROz0QCqjW+n/ODp/hH7c60Xc=
|
||||
golang.org/x/tools v0.0.0-20190912215617-3720d1ec3678/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
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/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/utils v0.0.0-20191030222137-2b95a09bc58d/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I=
|
||||
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
|
||||
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphDJbHOQO1DFFFTeBo=
|
||||
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
|
||||
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f h1:Cq7MalBHYACRd6EesksG1Q8EoIAKOsiZviGKbOLIej4=
|
||||
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw=
|
||||
sigs.k8s.io/kustomize/pseudo/k8s v0.0.0-20191108212413-1f86a0ca5d6c h1:t7fk+ljA3Ru4pro+/0RuOAZcODDhByL1fvIdyHLhjTY=
|
||||
sigs.k8s.io/kustomize/pseudo/k8s v0.0.0-20191108212413-1f86a0ca5d6c/go.mod h1:bl/gVJgYYhJZCZdYU2BfnaKYAlqFkgbJEkpl302jEss=
|
||||
sigs.k8s.io/kustomize/pseudo/k8s v0.1.0 h1:otg4dLFc03c3gzl+2CV8GPGcd1kk8wjXwD+UhhcCn5I=
|
||||
sigs.k8s.io/kustomize/pseudo/k8s v0.1.0/go.mod h1:bl/gVJgYYhJZCZdYU2BfnaKYAlqFkgbJEkpl302jEss=
|
||||
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
||||
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4 h1:JPJh2pk3+X4lXAkZIk2RuE/7/FoK9maXw+TNPJhVS/c=
|
||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
||||
@@ -1,274 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package accumulator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/transform"
|
||||
)
|
||||
|
||||
type nameReferenceTransformer struct {
|
||||
backRefs []builtinconfig.NameBackReferences
|
||||
}
|
||||
|
||||
var _ resmap.Transformer = &nameReferenceTransformer{}
|
||||
|
||||
// newNameReferenceTransformer constructs a nameReferenceTransformer
|
||||
// with a given slice of NameBackReferences.
|
||||
func newNameReferenceTransformer(br []builtinconfig.NameBackReferences) resmap.Transformer {
|
||||
if br == nil {
|
||||
log.Fatal("backrefs not expected to be nil")
|
||||
}
|
||||
return &nameReferenceTransformer{backRefs: br}
|
||||
}
|
||||
|
||||
// Transform updates name references in resource A that
|
||||
// refer to resource B, given that B's name may have
|
||||
// changed.
|
||||
//
|
||||
// For example, a HorizontalPodAutoscaler (HPA)
|
||||
// necessarily refers to a Deployment, the thing that
|
||||
// the HPA scales. The Deployment name might change
|
||||
// (e.g. prefix added), and the reference in the HPA
|
||||
// has to be fixed.
|
||||
//
|
||||
// In the outer loop over the ResMap below, say we
|
||||
// encounter a specific HPA. Then, in scanning backrefs,
|
||||
// we encounter an entry like
|
||||
//
|
||||
// - kind: Deployment
|
||||
// fieldSpecs:
|
||||
// - kind: HorizontalPodAutoscaler
|
||||
// path: spec/scaleTargetRef/name
|
||||
//
|
||||
// This entry says that an HPA, via its
|
||||
// 'spec/scaleTargetRef/name' field, may refer to a
|
||||
// Deployment. This match to HPA means we may need to
|
||||
// modify the value in its 'spec/scaleTargetRef/name'
|
||||
// field, by searching for the thing it refers to,
|
||||
// and getting its new name.
|
||||
//
|
||||
// As a filter, and search optimization, we compute a
|
||||
// subset of all resources that the HPA could refer to,
|
||||
// by excluding objects from other namespaces, and
|
||||
// excluding objects that don't have the same prefix-
|
||||
// suffix mods as the HPA.
|
||||
//
|
||||
// We look in this subset for all Deployment objects
|
||||
// with a resId that has a Name matching the field value
|
||||
// present in the HPA. If no match do nothing; if more
|
||||
// than one match, it's an error.
|
||||
//
|
||||
// We overwrite the HPA name field with the value found
|
||||
// in the Deployment's name field (the name in the raw
|
||||
// object - the modified name - not the unmodified name
|
||||
// in the Deployment's resId).
|
||||
//
|
||||
// This process assumes that the name stored in a ResId
|
||||
// (the ResMap key) isn't modified by name transformers.
|
||||
// Name transformers should only modify the name in the
|
||||
// body of the resource object (the value in the ResMap).
|
||||
//
|
||||
func (o *nameReferenceTransformer) Transform(m resmap.ResMap) error {
|
||||
// TODO: Too much looping, here and in transitive calls.
|
||||
for _, referrer := range m.Resources() {
|
||||
var candidates resmap.ResMap
|
||||
for _, target := range o.backRefs {
|
||||
for _, fSpec := range target.FieldSpecs {
|
||||
if referrer.OrgId().IsSelected(&fSpec.Gvk) {
|
||||
if candidates == nil {
|
||||
candidates = m.SubsetThatCouldBeReferencedByResource(referrer)
|
||||
}
|
||||
err := transform.MutateField(
|
||||
referrer.Map(),
|
||||
fSpec.PathSlice(),
|
||||
fSpec.CreateIfNotPresent,
|
||||
o.getNewNameFunc(
|
||||
// referrer could be an HPA instance,
|
||||
// target could be Gvk for Deployment,
|
||||
// candidate a list of resources "reachable"
|
||||
// from the HPA.
|
||||
referrer, target.Gvk, candidates))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// selectReferral picks the referral among a subset of candidates.
|
||||
// It returns the current name and namespace of the selected candidate.
|
||||
// Note that the content of the referricalCandidateSubset slice is most of the time
|
||||
// identical to the referralCandidates resmap. Still in some cases, such
|
||||
// as ClusterRoleBinding, the subset only contains the resources of a specific
|
||||
// namespace.
|
||||
func (o *nameReferenceTransformer) selectReferral(
|
||||
oldName string,
|
||||
referrer *resource.Resource,
|
||||
target resid.Gvk,
|
||||
referralCandidates resmap.ResMap,
|
||||
referralCandidateSubset []*resource.Resource) (interface{}, interface{}, error) {
|
||||
|
||||
for _, res := range referralCandidateSubset {
|
||||
id := res.OrgId()
|
||||
if id.IsSelected(&target) && res.GetOriginalName() == oldName {
|
||||
matches := referralCandidates.GetMatchingResourcesByOriginalId(id.Equals)
|
||||
// If there's more than one match, there's no way
|
||||
// to know which one to pick, so emit error.
|
||||
if len(matches) > 1 {
|
||||
return nil, nil, fmt.Errorf(
|
||||
"multiple matches for %s:\n %v",
|
||||
id, getIds(matches))
|
||||
}
|
||||
// In the resource, note that it is referenced
|
||||
// by the referrer.
|
||||
res.AppendRefBy(referrer.CurId())
|
||||
// Return transformed name of the object,
|
||||
// complete with prefixes, hashes, etc.
|
||||
return res.GetName(), res.GetNamespace(), nil
|
||||
}
|
||||
}
|
||||
|
||||
return oldName, nil, nil
|
||||
}
|
||||
|
||||
// utility function to replace a simple string by the new name
|
||||
func (o *nameReferenceTransformer) getSimpleNameField(
|
||||
oldName string,
|
||||
referrer *resource.Resource,
|
||||
target resid.Gvk,
|
||||
referralCandidates resmap.ResMap,
|
||||
referralCandidateSubset []*resource.Resource) (interface{}, error) {
|
||||
|
||||
newName, _, err := o.selectReferral(oldName, referrer, target,
|
||||
referralCandidates, referralCandidateSubset)
|
||||
|
||||
return newName, err
|
||||
}
|
||||
|
||||
// utility function to replace name field within a map[string]interface{}
|
||||
// and leverage the namespace field.
|
||||
func (o *nameReferenceTransformer) getNameAndNsStruct(
|
||||
inMap map[string]interface{},
|
||||
referrer *resource.Resource,
|
||||
target resid.Gvk,
|
||||
referralCandidates resmap.ResMap) (interface{}, error) {
|
||||
|
||||
// Example:
|
||||
if _, ok := inMap["name"]; !ok {
|
||||
return nil, fmt.Errorf(
|
||||
"%#v is expected to contain a name field", inMap)
|
||||
}
|
||||
oldName, ok := inMap["name"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(
|
||||
"%#v is expected to contain a name field of type string", oldName)
|
||||
}
|
||||
|
||||
subset := referralCandidates.Resources()
|
||||
if namespacevalue, ok := inMap["namespace"]; ok {
|
||||
namespace := namespacevalue.(string)
|
||||
bynamespace := referralCandidates.GroupedByOriginalNamespace()
|
||||
if _, ok := bynamespace[namespace]; !ok {
|
||||
return inMap, nil
|
||||
}
|
||||
subset = bynamespace[namespace]
|
||||
}
|
||||
|
||||
newname, newnamespace, err := o.selectReferral(oldName, referrer, target,
|
||||
referralCandidates, subset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if (newname == oldName) && (newnamespace == nil) {
|
||||
// no candidate found.
|
||||
return inMap, nil
|
||||
}
|
||||
|
||||
inMap["name"] = newname
|
||||
if newnamespace != "" {
|
||||
// We don't want value "" to replace value "default" since
|
||||
// the empty string is handled as a wild card here not default namespace
|
||||
// by kubernetes.
|
||||
inMap["namespace"] = newnamespace
|
||||
}
|
||||
return inMap, nil
|
||||
|
||||
}
|
||||
|
||||
func (o *nameReferenceTransformer) getNewNameFunc(
|
||||
referrer *resource.Resource,
|
||||
target resid.Gvk,
|
||||
referralCandidates resmap.ResMap) func(in interface{}) (interface{}, error) {
|
||||
return func(in interface{}) (interface{}, error) {
|
||||
switch in.(type) {
|
||||
case string:
|
||||
oldName, _ := in.(string)
|
||||
return o.getSimpleNameField(oldName, referrer, target,
|
||||
referralCandidates, referralCandidates.Resources())
|
||||
case map[string]interface{}:
|
||||
// Kind: ValidatingWebhookConfiguration
|
||||
// FieldSpec is webhooks/clientConfig/service
|
||||
oldMap, _ := in.(map[string]interface{})
|
||||
return o.getNameAndNsStruct(oldMap, referrer, target,
|
||||
referralCandidates)
|
||||
case []interface{}:
|
||||
l, _ := in.([]interface{})
|
||||
for idx, item := range l {
|
||||
switch item.(type) {
|
||||
case string:
|
||||
// Kind: Role/ClusterRole
|
||||
// FieldSpec is rules.resourceNames
|
||||
oldName, _ := item.(string)
|
||||
newName, err := o.getSimpleNameField(oldName, referrer, target,
|
||||
referralCandidates, referralCandidates.Resources())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l[idx] = newName
|
||||
case map[string]interface{}:
|
||||
// Kind: RoleBinding/ClusterRoleBinding
|
||||
// FieldSpec is subjects
|
||||
// Note: The corresponding fieldSpec had been changed from
|
||||
// from path: subjects/name to just path: subjects. This is
|
||||
// what get mutatefield to request the mapping of the whole
|
||||
// map containing namespace and name instead of just a simple
|
||||
// string field containing the name
|
||||
oldMap, _ := item.(map[string]interface{})
|
||||
newMap, err := o.getNameAndNsStruct(oldMap, referrer, target,
|
||||
referralCandidates)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l[idx] = newMap
|
||||
default:
|
||||
return nil, fmt.Errorf(
|
||||
"%#v is expected to be either a []string or a []map[string]interface{}", in)
|
||||
}
|
||||
}
|
||||
return in, nil
|
||||
default:
|
||||
return nil, fmt.Errorf(
|
||||
"%#v is expected to be either a string or a []interface{}", in)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getIds(rs []*resource.Resource) []string {
|
||||
var result []string
|
||||
for _, r := range rs {
|
||||
result = append(result, r.CurId().String()+"\n")
|
||||
}
|
||||
return result
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,137 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package accumulator
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/testutils/resmaptest"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
func TestRefVarTransformer(t *testing.T) {
|
||||
type given struct {
|
||||
varMap map[string]interface{}
|
||||
fs []types.FieldSpec
|
||||
res resmap.ResMap
|
||||
}
|
||||
type expected struct {
|
||||
res resmap.ResMap
|
||||
unused []string
|
||||
}
|
||||
testCases := []struct {
|
||||
description string
|
||||
given given
|
||||
expected expected
|
||||
}{
|
||||
{
|
||||
description: "var replacement in map[string]",
|
||||
given: given{
|
||||
varMap: map[string]interface{}{
|
||||
"FOO": "replacementForFoo",
|
||||
"BAR": "replacementForBar",
|
||||
"BAZ": int64(5),
|
||||
"BOO": true,
|
||||
},
|
||||
fs: []types.FieldSpec{
|
||||
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/map"},
|
||||
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/slice"},
|
||||
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/interface"},
|
||||
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/nil"},
|
||||
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/num"},
|
||||
},
|
||||
res: resmaptest_test.NewRmBuilder(
|
||||
t, resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())).
|
||||
Add(map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm1",
|
||||
},
|
||||
"data": map[string]interface{}{
|
||||
"map": map[string]interface{}{
|
||||
"item1": "$(FOO)",
|
||||
"item2": "bla",
|
||||
"item3": "$(BAZ)",
|
||||
"item4": "$(BAZ)+$(BAZ)",
|
||||
"item5": "$(BOO)",
|
||||
"item6": "if $(BOO)",
|
||||
"item7": 2019,
|
||||
},
|
||||
"slice": []interface{}{
|
||||
"$(FOO)",
|
||||
"bla",
|
||||
"$(BAZ)",
|
||||
"$(BAZ)+$(BAZ)",
|
||||
"$(BOO)",
|
||||
"if $(BOO)",
|
||||
},
|
||||
"interface": "$(FOO)",
|
||||
"nil": nil,
|
||||
"num": 2019,
|
||||
}}).ResMap(),
|
||||
},
|
||||
expected: expected{
|
||||
res: resmaptest_test.NewRmBuilder(
|
||||
t, resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())).
|
||||
Add(map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm1",
|
||||
},
|
||||
"data": map[string]interface{}{
|
||||
"map": map[string]interface{}{
|
||||
"item1": "replacementForFoo",
|
||||
"item2": "bla",
|
||||
"item3": int64(5),
|
||||
"item4": "5+5",
|
||||
"item5": true,
|
||||
"item6": "if true",
|
||||
"item7": 2019,
|
||||
},
|
||||
"slice": []interface{}{
|
||||
"replacementForFoo",
|
||||
"bla",
|
||||
int64(5),
|
||||
"5+5",
|
||||
true,
|
||||
"if true",
|
||||
},
|
||||
"interface": "replacementForFoo",
|
||||
"nil": nil,
|
||||
"num": 2019,
|
||||
}}).ResMap(),
|
||||
unused: []string{"BAR"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.description, func(t *testing.T) {
|
||||
// arrange
|
||||
tr := newRefVarTransformer(tc.given.varMap, tc.given.fs)
|
||||
|
||||
// act
|
||||
err := tr.Transform(tc.given.res)
|
||||
|
||||
// assert
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
a, e := tc.given.res, tc.expected.res
|
||||
if !reflect.DeepEqual(a, e) {
|
||||
err = e.ErrorIfNotEqualLists(a)
|
||||
t.Fatalf("actual doesn't match expected: \nACTUAL:\n%v\nEXPECTED:\n%v\nERR: %v", a, e, err)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package builtinconfig provides legacy methods for
|
||||
// configuring builtin plugins from a common config file.
|
||||
// As a user, its best to configure plugins individually
|
||||
// with plugin config files specified in the `transformers:`
|
||||
// or `generators:` field, than to use this legacy
|
||||
// configuration technique.
|
||||
package builtinconfig
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package builtinconfig
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// loadDefaultConfig returns a TranformerConfig
|
||||
// object from a list of files.
|
||||
func loadDefaultConfig(
|
||||
ldr ifc.Loader, paths []string) (*TransformerConfig, error) {
|
||||
result := &TransformerConfig{}
|
||||
for _, path := range paths {
|
||||
data, err := ldr.Load(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t, err := makeTransformerConfigFromBytes(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result, err = result.Merge(t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// makeTransformerConfigFromBytes returns a TransformerConfig object from bytes
|
||||
func makeTransformerConfigFromBytes(data []byte) (*TransformerConfig, error) {
|
||||
var t TransformerConfig
|
||||
err := yaml.Unmarshal(data, &t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.sortFields()
|
||||
return &t, nil
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package builtinconfig
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sort"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/kustomize/api/konfig/builtinpluginconsts"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
// TransformerConfig holds the data needed to perform transformations.
|
||||
type TransformerConfig struct {
|
||||
NamePrefix types.FsSlice `json:"namePrefix,omitempty" yaml:"namePrefix,omitempty"`
|
||||
NameSuffix types.FsSlice `json:"nameSuffix,omitempty" yaml:"nameSuffix,omitempty"`
|
||||
NameSpace types.FsSlice `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
CommonLabels types.FsSlice `json:"commonLabels,omitempty" yaml:"commonLabels,omitempty"`
|
||||
CommonAnnotations types.FsSlice `json:"commonAnnotations,omitempty" yaml:"commonAnnotations,omitempty"`
|
||||
NameReference nbrSlice `json:"nameReference,omitempty" yaml:"nameReference,omitempty"`
|
||||
VarReference types.FsSlice `json:"varReference,omitempty" yaml:"varReference,omitempty"`
|
||||
Images types.FsSlice `json:"images,omitempty" yaml:"images,omitempty"`
|
||||
Replicas types.FsSlice `json:"replicas,omitempty" yaml:"replicas,omitempty"`
|
||||
}
|
||||
|
||||
// MakeEmptyConfig returns an empty TransformerConfig object
|
||||
func MakeEmptyConfig() *TransformerConfig {
|
||||
return &TransformerConfig{}
|
||||
}
|
||||
|
||||
// MakeDefaultConfig returns a default TransformerConfig.
|
||||
func MakeDefaultConfig() *TransformerConfig {
|
||||
c, err := makeTransformerConfigFromBytes(
|
||||
builtinpluginconsts.GetDefaultFieldSpecs())
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to make default transformconfig: %v", err)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// MakeTransformerConfig returns a merger of custom config,
|
||||
// if any, with default config.
|
||||
func MakeTransformerConfig(
|
||||
ldr ifc.Loader, paths []string) (*TransformerConfig, error) {
|
||||
t1 := MakeDefaultConfig()
|
||||
if len(paths) == 0 {
|
||||
return t1, nil
|
||||
}
|
||||
t2, err := loadDefaultConfig(ldr, paths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return t1.Merge(t2)
|
||||
}
|
||||
|
||||
// sortFields provides determinism in logging, tests, etc.
|
||||
func (t *TransformerConfig) sortFields() {
|
||||
sort.Sort(t.NamePrefix)
|
||||
sort.Sort(t.NameSpace)
|
||||
sort.Sort(t.CommonLabels)
|
||||
sort.Sort(t.CommonAnnotations)
|
||||
sort.Sort(t.NameReference)
|
||||
sort.Sort(t.VarReference)
|
||||
sort.Sort(t.Images)
|
||||
sort.Sort(t.Replicas)
|
||||
}
|
||||
|
||||
// AddPrefixFieldSpec adds a FieldSpec to NamePrefix
|
||||
func (t *TransformerConfig) AddPrefixFieldSpec(fs types.FieldSpec) (err error) {
|
||||
t.NamePrefix, err = t.NamePrefix.MergeOne(fs)
|
||||
return err
|
||||
}
|
||||
|
||||
// AddSuffixFieldSpec adds a FieldSpec to NameSuffix
|
||||
func (t *TransformerConfig) AddSuffixFieldSpec(fs types.FieldSpec) (err error) {
|
||||
t.NameSuffix, err = t.NameSuffix.MergeOne(fs)
|
||||
return err
|
||||
}
|
||||
|
||||
// AddLabelFieldSpec adds a FieldSpec to CommonLabels
|
||||
func (t *TransformerConfig) AddLabelFieldSpec(fs types.FieldSpec) (err error) {
|
||||
t.CommonLabels, err = t.CommonLabels.MergeOne(fs)
|
||||
return err
|
||||
}
|
||||
|
||||
// AddAnnotationFieldSpec adds a FieldSpec to CommonAnnotations
|
||||
func (t *TransformerConfig) AddAnnotationFieldSpec(fs types.FieldSpec) (err error) {
|
||||
t.CommonAnnotations, err = t.CommonAnnotations.MergeOne(fs)
|
||||
return err
|
||||
}
|
||||
|
||||
// AddNamereferenceFieldSpec adds a NameBackReferences to NameReference
|
||||
func (t *TransformerConfig) AddNamereferenceFieldSpec(
|
||||
nbrs NameBackReferences) (err error) {
|
||||
t.NameReference, err = t.NameReference.mergeOne(nbrs)
|
||||
return err
|
||||
}
|
||||
|
||||
// Merge merges two TransformerConfigs objects into
|
||||
// a new TransformerConfig object
|
||||
func (t *TransformerConfig) Merge(input *TransformerConfig) (
|
||||
merged *TransformerConfig, err error) {
|
||||
if input == nil {
|
||||
return t, nil
|
||||
}
|
||||
merged = &TransformerConfig{}
|
||||
merged.NamePrefix, err = t.NamePrefix.MergeAll(input.NamePrefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
merged.NameSuffix, err = t.NameSuffix.MergeAll(input.NameSuffix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
merged.NameSpace, err = t.NameSpace.MergeAll(input.NameSpace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
merged.CommonAnnotations, err = t.CommonAnnotations.MergeAll(
|
||||
input.CommonAnnotations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
merged.CommonLabels, err = t.CommonLabels.MergeAll(input.CommonLabels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
merged.VarReference, err = t.VarReference.MergeAll(input.VarReference)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
merged.NameReference, err = t.NameReference.mergeAll(input.NameReference)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
merged.Images, err = t.Images.MergeAll(input.Images)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
merged.Replicas, err = t.Replicas.MergeAll(input.Replicas)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
merged.sortFields()
|
||||
return merged, nil
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
// Code generated by "stringer -type=BuiltinPluginType"; DO NOT EDIT.
|
||||
|
||||
package builtinhelpers
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[Unknown-0]
|
||||
_ = x[AnnotationsTransformer-1]
|
||||
_ = x[ConfigMapGenerator-2]
|
||||
_ = x[HashTransformer-3]
|
||||
_ = x[ImageTagTransformer-4]
|
||||
_ = x[InventoryTransformer-5]
|
||||
_ = x[LabelTransformer-6]
|
||||
_ = x[LegacyOrderTransformer-7]
|
||||
_ = x[NamespaceTransformer-8]
|
||||
_ = x[PatchJson6902Transformer-9]
|
||||
_ = x[PatchStrategicMergeTransformer-10]
|
||||
_ = x[PatchTransformer-11]
|
||||
_ = x[PrefixSuffixTransformer-12]
|
||||
_ = x[ReplicaCountTransformer-13]
|
||||
_ = x[SecretGenerator-14]
|
||||
}
|
||||
|
||||
const _BuiltinPluginType_name = "UnknownAnnotationsTransformerConfigMapGeneratorHashTransformerImageTagTransformerInventoryTransformerLabelTransformerLegacyOrderTransformerNamespaceTransformerPatchJson6902TransformerPatchStrategicMergeTransformerPatchTransformerPrefixSuffixTransformerReplicaCountTransformerSecretGenerator"
|
||||
|
||||
var _BuiltinPluginType_index = [...]uint16{0, 7, 29, 47, 62, 81, 101, 117, 139, 159, 183, 213, 229, 252, 275, 290}
|
||||
|
||||
func (i BuiltinPluginType) String() string {
|
||||
if i < 0 || i >= BuiltinPluginType(len(_BuiltinPluginType_index)-1) {
|
||||
return "BuiltinPluginType(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _BuiltinPluginType_name[_BuiltinPluginType_index[i]:_BuiltinPluginType_index[i+1]]
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package builtinhelpers
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/builtins"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
)
|
||||
|
||||
//go:generate stringer -type=BuiltinPluginType
|
||||
type BuiltinPluginType int
|
||||
|
||||
const (
|
||||
Unknown BuiltinPluginType = iota
|
||||
AnnotationsTransformer
|
||||
ConfigMapGenerator
|
||||
HashTransformer
|
||||
ImageTagTransformer
|
||||
InventoryTransformer
|
||||
LabelTransformer
|
||||
LegacyOrderTransformer
|
||||
NamespaceTransformer
|
||||
PatchJson6902Transformer
|
||||
PatchStrategicMergeTransformer
|
||||
PatchTransformer
|
||||
PrefixSuffixTransformer
|
||||
ReplicaCountTransformer
|
||||
SecretGenerator
|
||||
)
|
||||
|
||||
var stringToBuiltinPluginTypeMap map[string]BuiltinPluginType
|
||||
|
||||
func init() {
|
||||
stringToBuiltinPluginTypeMap = makeStringToBuiltinPluginTypeMap()
|
||||
}
|
||||
|
||||
func makeStringToBuiltinPluginTypeMap() (result map[string]BuiltinPluginType) {
|
||||
result = make(map[string]BuiltinPluginType, 23)
|
||||
for k := range GeneratorFactories {
|
||||
result[k.String()] = k
|
||||
}
|
||||
for k := range TransformerFactories {
|
||||
result[k.String()] = k
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetBuiltinPluginType(n string) BuiltinPluginType {
|
||||
result, ok := stringToBuiltinPluginTypeMap[n]
|
||||
if ok {
|
||||
return result
|
||||
}
|
||||
return Unknown
|
||||
}
|
||||
|
||||
var GeneratorFactories = map[BuiltinPluginType]func() resmap.GeneratorPlugin{
|
||||
ConfigMapGenerator: builtins.NewConfigMapGeneratorPlugin,
|
||||
SecretGenerator: builtins.NewSecretGeneratorPlugin,
|
||||
}
|
||||
|
||||
var TransformerFactories = map[BuiltinPluginType]func() resmap.TransformerPlugin{
|
||||
AnnotationsTransformer: builtins.NewAnnotationsTransformerPlugin,
|
||||
HashTransformer: builtins.NewHashTransformerPlugin,
|
||||
ImageTagTransformer: builtins.NewImageTagTransformerPlugin,
|
||||
InventoryTransformer: builtins.NewInventoryTransformerPlugin,
|
||||
LabelTransformer: builtins.NewLabelTransformerPlugin,
|
||||
LegacyOrderTransformer: builtins.NewLegacyOrderTransformerPlugin,
|
||||
NamespaceTransformer: builtins.NewNamespaceTransformerPlugin,
|
||||
PatchJson6902Transformer: builtins.NewPatchJson6902TransformerPlugin,
|
||||
PatchStrategicMergeTransformer: builtins.NewPatchStrategicMergeTransformerPlugin,
|
||||
PatchTransformer: builtins.NewPatchTransformerPlugin,
|
||||
PrefixSuffixTransformer: builtins.NewPrefixSuffixTransformerPlugin,
|
||||
ReplicaCountTransformer: builtins.NewReplicaCountTransformerPlugin,
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package execplugin_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/internal/loadertest"
|
||||
. "sigs.k8s.io/kustomize/api/internal/plugins/execplugin"
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
||||
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
func TestExecPluginConfig(t *testing.T) {
|
||||
path := "/app"
|
||||
rf := resmap.NewFactory(
|
||||
resource.NewFactory(
|
||||
kunstruct.NewKunstructuredFactoryImpl()), nil)
|
||||
ldr := loadertest.NewFakeLoader(path)
|
||||
v := valtest_test.MakeFakeValidator()
|
||||
pluginConfig := rf.RF().FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "someteam.example.com/v1",
|
||||
"kind": "SedTransformer",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "some-random-name",
|
||||
},
|
||||
"argsOneLiner": "one two",
|
||||
"argsFromFile": "sed-input.txt",
|
||||
})
|
||||
|
||||
ldr.AddFile("/app/sed-input.txt", []byte(`
|
||||
s/$FOO/foo/g
|
||||
s/$BAR/bar/g
|
||||
\ \ \
|
||||
`))
|
||||
|
||||
p := NewExecPlugin(
|
||||
loader.AbsolutePluginPath(
|
||||
konfig.DisabledPluginConfig(),
|
||||
pluginConfig.OrgId()))
|
||||
// Not checking to see if the plugin is executable,
|
||||
// because this test does not run it.
|
||||
// This tests only covers sending configuration
|
||||
// to the plugin wrapper object and confirming
|
||||
// that it's properly prepared for execution.
|
||||
|
||||
yaml, err := pluginConfig.AsYAML()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
p.Config(resmap.NewPluginHelpers(ldr, v, rf), yaml)
|
||||
|
||||
expected := "someteam.example.com/v1/sedtransformer/SedTransformer"
|
||||
if !strings.HasSuffix(p.Path(), expected) {
|
||||
t.Fatalf("expected suffix '%s', got '%s'", expected, p.Path())
|
||||
}
|
||||
|
||||
expected = `apiVersion: someteam.example.com/v1
|
||||
argsFromFile: sed-input.txt
|
||||
argsOneLiner: one two
|
||||
kind: SedTransformer
|
||||
metadata:
|
||||
name: some-random-name
|
||||
`
|
||||
if expected != string(p.Cfg()) {
|
||||
t.Fatalf("expected cfg '%s', got '%s'", expected, string(p.Cfg()))
|
||||
|
||||
}
|
||||
if len(p.Args()) != 5 {
|
||||
t.Fatalf("unexpected arg len %d, %v", len(p.Args()), p.Args())
|
||||
}
|
||||
if p.Args()[0] != "one" ||
|
||||
p.Args()[1] != "two" ||
|
||||
p.Args()[2] != "s/$FOO/foo/g" ||
|
||||
p.Args()[3] != "s/$BAR/bar/g" ||
|
||||
p.Args()[4] != "\\ \\ \\ " {
|
||||
t.Fatalf("unexpected arg array: %v", p.Args())
|
||||
}
|
||||
}
|
||||
|
||||
func makeConfigMap(rf *resource.Factory, name, behavior string, hashValue *string) *resource.Resource {
|
||||
r := rf.FromMap(map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{"name": name},
|
||||
})
|
||||
annotations := map[string]string{}
|
||||
if behavior != "" {
|
||||
annotations[BehaviorAnnotation] = behavior
|
||||
}
|
||||
if hashValue != nil {
|
||||
annotations[HashAnnotation] = *hashValue
|
||||
}
|
||||
if len(annotations) > 0 {
|
||||
r.SetAnnotations(annotations)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func makeConfigMapOptions(rf *resource.Factory, name, behavior string, disableHash bool) *resource.Resource {
|
||||
return rf.FromMapAndOption(map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{"name": name},
|
||||
}, &types.GeneratorArgs{Behavior: behavior}, &types.GeneratorOptions{DisableNameSuffixHash: disableHash})
|
||||
}
|
||||
|
||||
func strptr(s string) *string {
|
||||
return &s
|
||||
}
|
||||
|
||||
func TestUpdateResourceOptions(t *testing.T) {
|
||||
p := NewExecPlugin("")
|
||||
if err := p.ErrIfNotExecutable(); err == nil {
|
||||
t.Fatalf("expected unexecutable error")
|
||||
}
|
||||
rf := resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())
|
||||
in := resmap.New()
|
||||
expected := resmap.New()
|
||||
cases := []struct {
|
||||
behavior string
|
||||
needsHash bool
|
||||
hashValue *string
|
||||
}{
|
||||
{hashValue: strptr("false")},
|
||||
{hashValue: strptr("true"), needsHash: true},
|
||||
{behavior: "replace"},
|
||||
{behavior: "merge"},
|
||||
{behavior: "create"},
|
||||
{behavior: "nonsense"},
|
||||
{behavior: "merge", hashValue: strptr("false")},
|
||||
{behavior: "merge", hashValue: strptr("true"), needsHash: true},
|
||||
}
|
||||
for i, c := range cases {
|
||||
name := fmt.Sprintf("test%d", i)
|
||||
in.Append(makeConfigMap(rf, name, c.behavior, c.hashValue))
|
||||
expected.Append(makeConfigMapOptions(rf, name, c.behavior, !c.needsHash))
|
||||
}
|
||||
actual, err := p.UpdateResourceOptions(in)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err.Error())
|
||||
}
|
||||
for i, a := range expected.Resources() {
|
||||
b := actual.GetByIndex(i)
|
||||
if b == nil {
|
||||
t.Fatalf("resource %d missing from processed map", i)
|
||||
}
|
||||
if !a.Equals(b) {
|
||||
t.Errorf("expected %v got %v", a, b)
|
||||
}
|
||||
if a.NeedHashSuffix() != b.NeedHashSuffix() {
|
||||
t.Errorf("")
|
||||
}
|
||||
if a.Behavior() != b.Behavior() {
|
||||
t.Errorf("expected %v got %v", a.Behavior(), b.Behavior())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateResourceOptionsWithInvalidHashAnnotationValues(t *testing.T) {
|
||||
p := NewExecPlugin("")
|
||||
if err := p.ErrIfNotExecutable(); err == nil {
|
||||
t.Fatalf("expected unexecutable error")
|
||||
}
|
||||
rf := resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())
|
||||
cases := []string{
|
||||
"",
|
||||
"FaLsE",
|
||||
"TrUe",
|
||||
"potato",
|
||||
}
|
||||
for i, c := range cases {
|
||||
name := fmt.Sprintf("test%d", i)
|
||||
in := resmap.New()
|
||||
in.Append(makeConfigMap(rf, name, "", &c))
|
||||
_, err := p.UpdateResourceOptions(in)
|
||||
if err == nil {
|
||||
t.Errorf("expected error from value %q", c)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,211 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package loader
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"plugin"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers"
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/execplugin"
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
type Loader struct {
|
||||
pc *types.PluginConfig
|
||||
rf *resmap.Factory
|
||||
}
|
||||
|
||||
func NewLoader(
|
||||
pc *types.PluginConfig, rf *resmap.Factory) *Loader {
|
||||
return &Loader{pc: pc, rf: rf}
|
||||
}
|
||||
|
||||
func (l *Loader) LoadGenerators(
|
||||
ldr ifc.Loader, v ifc.Validator, rm resmap.ResMap) ([]resmap.Generator, error) {
|
||||
var result []resmap.Generator
|
||||
for _, res := range rm.Resources() {
|
||||
g, err := l.LoadGenerator(ldr, v, res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, g)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (l *Loader) LoadGenerator(
|
||||
ldr ifc.Loader, v ifc.Validator, res *resource.Resource) (resmap.Generator, error) {
|
||||
c, err := l.loadAndConfigurePlugin(ldr, v, res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
g, ok := c.(resmap.Generator)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("plugin %s not a generator", res.OrgId())
|
||||
}
|
||||
return g, nil
|
||||
}
|
||||
|
||||
func (l *Loader) LoadTransformers(
|
||||
ldr ifc.Loader, v ifc.Validator, rm resmap.ResMap) ([]resmap.Transformer, error) {
|
||||
var result []resmap.Transformer
|
||||
for _, res := range rm.Resources() {
|
||||
t, err := l.LoadTransformer(ldr, v, res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, t)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (l *Loader) LoadTransformer(
|
||||
ldr ifc.Loader, v ifc.Validator, res *resource.Resource) (resmap.Transformer, error) {
|
||||
c, err := l.loadAndConfigurePlugin(ldr, v, res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t, ok := c.(resmap.Transformer)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("plugin %s not a transformer", res.OrgId())
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func relativePluginPath(id resid.ResId) string {
|
||||
return filepath.Join(
|
||||
id.Group,
|
||||
id.Version,
|
||||
strings.ToLower(id.Kind))
|
||||
}
|
||||
|
||||
func AbsolutePluginPath(pc *types.PluginConfig, id resid.ResId) string {
|
||||
return filepath.Join(
|
||||
pc.AbsPluginHome, relativePluginPath(id), id.Kind)
|
||||
}
|
||||
|
||||
func (l *Loader) absolutePluginPath(id resid.ResId) string {
|
||||
return AbsolutePluginPath(l.pc, id)
|
||||
}
|
||||
|
||||
func isBuiltinPlugin(res *resource.Resource) bool {
|
||||
// TODO: the special string should appear in Group, not Version.
|
||||
return res.GetGvk().Group == "" &&
|
||||
res.GetGvk().Version == konfig.BuiltinPluginApiVersion
|
||||
}
|
||||
|
||||
func (l *Loader) loadAndConfigurePlugin(
|
||||
ldr ifc.Loader, v ifc.Validator, res *resource.Resource) (c resmap.Configurable, err error) {
|
||||
if isBuiltinPlugin(res) {
|
||||
// Instead of looking for and loading a .so file, just
|
||||
// instantiate the plugin from a generated factory
|
||||
// function (see "pluginator"). Being able to do this
|
||||
// is what makes a plugin "builtin".
|
||||
c, err = l.makeBuiltinPlugin(res.GetGvk())
|
||||
} else if l.pc.PluginRestrictions == types.PluginRestrictionsNone {
|
||||
c, err = l.loadPlugin(res.OrgId())
|
||||
} else {
|
||||
err = types.NewErrOnlyBuiltinPluginsAllowed(res.OrgId().Kind)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
yaml, err := res.AsYAML()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "marshalling yaml from res %s", res.OrgId())
|
||||
}
|
||||
err = c.Config(resmap.NewPluginHelpers(ldr, v, l.rf), yaml)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(
|
||||
err, "plugin %s fails configuration", res.OrgId())
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (l *Loader) makeBuiltinPlugin(r resid.Gvk) (resmap.Configurable, error) {
|
||||
bpt := builtinhelpers.GetBuiltinPluginType(r.Kind)
|
||||
if f, ok := builtinhelpers.GeneratorFactories[bpt]; ok {
|
||||
return f(), nil
|
||||
}
|
||||
if f, ok := builtinhelpers.TransformerFactories[bpt]; ok {
|
||||
return f(), nil
|
||||
}
|
||||
return nil, errors.Errorf("unable to load builtin %s", r)
|
||||
}
|
||||
|
||||
func (l *Loader) loadPlugin(resId resid.ResId) (resmap.Configurable, error) {
|
||||
// First try to load the plugin as an executable.
|
||||
p := execplugin.NewExecPlugin(l.absolutePluginPath(resId))
|
||||
err := p.ErrIfNotExecutable()
|
||||
if err == nil {
|
||||
return p, nil
|
||||
}
|
||||
if !os.IsNotExist(err) {
|
||||
// The file exists, but something else is wrong,
|
||||
// likely it's not executable.
|
||||
// Assume the user forgot to set the exec bit,
|
||||
// and return an error, rather than adding ".so"
|
||||
// to the name and attempting to load it as a Go
|
||||
// plugin, which will likely fail and result
|
||||
// in an obscure message.
|
||||
return nil, err
|
||||
}
|
||||
// Failing the above, try loading it as a Go plugin.
|
||||
c, err := l.loadGoPlugin(resId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// registry is a means to avoid trying to load the same .so file
|
||||
// into memory more than once, which results in an error.
|
||||
// Each test makes its own loader, and tries to load its own plugins,
|
||||
// but the loaded .so files are in shared memory, so one will get
|
||||
// "this plugin already loaded" errors if the registry is maintained
|
||||
// as a Loader instance variable. So make it a package variable.
|
||||
var registry = make(map[string]resmap.Configurable)
|
||||
|
||||
func (l *Loader) loadGoPlugin(id resid.ResId) (resmap.Configurable, error) {
|
||||
regId := relativePluginPath(id)
|
||||
if c, ok := registry[regId]; ok {
|
||||
return copyPlugin(c), nil
|
||||
}
|
||||
absPath := l.absolutePluginPath(id)
|
||||
p, err := plugin.Open(absPath + ".so")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "plugin %s fails to load", absPath)
|
||||
}
|
||||
symbol, err := p.Lookup(konfig.PluginSymbol)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(
|
||||
err, "plugin %s doesn't have symbol %s",
|
||||
regId, konfig.PluginSymbol)
|
||||
}
|
||||
c, ok := symbol.(resmap.Configurable)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("plugin '%s' not configurable", regId)
|
||||
}
|
||||
registry[regId] = c
|
||||
return copyPlugin(c), nil
|
||||
}
|
||||
|
||||
func copyPlugin(c resmap.Configurable) resmap.Configurable {
|
||||
indirect := reflect.Indirect(reflect.ValueOf(c))
|
||||
newIndirect := reflect.New(indirect.Type())
|
||||
newIndirect.Elem().Set(reflect.ValueOf(indirect.Interface()))
|
||||
newNamed := newIndirect.Interface()
|
||||
return newNamed.(resmap.Configurable)
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package target_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "sigs.k8s.io/kustomize/api/internal/target"
|
||||
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||
)
|
||||
|
||||
func TestTargetMustHaveKustomizationFile(t *testing.T) {
|
||||
th := kusttest_test.NewKustTestHarness(t, "/app")
|
||||
th.WriteF("/app/service.yaml", `
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: aService
|
||||
`)
|
||||
th.WriteF("/app/deeper/service.yaml", `
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: anotherService
|
||||
`)
|
||||
_, err := th.MakeKustTargetOrErr()
|
||||
if err == nil {
|
||||
t.Fatalf("expected an error")
|
||||
}
|
||||
if !IsMissingKustomizationFileError(err) {
|
||||
t.Fatalf("unexpected error: %q", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResourceDirectoryMustHaveKustomizationFile(t *testing.T) {
|
||||
th := kusttest_test.NewKustTestHarness(t, "/app")
|
||||
th.WriteK("/app", `
|
||||
resources:
|
||||
- base
|
||||
`)
|
||||
th.WriteF("/app/base/service.yaml", `
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: myService
|
||||
spec:
|
||||
selector:
|
||||
backend: bungie
|
||||
ports:
|
||||
- port: 7002
|
||||
`)
|
||||
_, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||
if err == nil {
|
||||
t.Fatalf("expected an error")
|
||||
}
|
||||
if !IsMissingKustomizationFileError(err) {
|
||||
t.Fatalf("unexpected error: %q", err)
|
||||
}
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package target_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||
)
|
||||
|
||||
// Here is a structure of a kustomization of two components, component1
|
||||
// and component2, that both use a shared postgres definition, which
|
||||
// they would individually adjust. This test case checks that the name
|
||||
// prefix does not cause a name reference conflict.
|
||||
//
|
||||
// root
|
||||
// / \
|
||||
// component1/overlay component2/overlay
|
||||
// | |
|
||||
// component1/base component2/base
|
||||
// \ /
|
||||
// base
|
||||
//
|
||||
// This is the directory layout:
|
||||
//
|
||||
// ├── component1
|
||||
// │ ├── base
|
||||
// │ │ └── kustomization.yaml
|
||||
// │ └── overlay
|
||||
// │ └── kustomization.yaml
|
||||
// ├── component2
|
||||
// │ ├── base
|
||||
// │ │ └── kustomization.yaml
|
||||
// │ └── overlay
|
||||
// │ └── kustomization.yaml
|
||||
// ├── shared
|
||||
// │ ├── kustomization.yaml
|
||||
// │ └── resources.yaml
|
||||
// ├── kustomization.yaml
|
||||
|
||||
func TestBaseReuseNameConflict(t *testing.T) {
|
||||
th := kusttest_test.NewKustTestHarness(t, "/app")
|
||||
th.WriteK("/app/component1/base", `
|
||||
resources:
|
||||
- ../../shared
|
||||
|
||||
namePrefix: component1-
|
||||
`)
|
||||
th.WriteK("/app/component1/overlay", `
|
||||
resources:
|
||||
- ../base
|
||||
|
||||
namePrefix: overlay-
|
||||
`)
|
||||
|
||||
th.WriteK("/app/component2/base", `
|
||||
resources:
|
||||
- ../../shared
|
||||
|
||||
namePrefix: component2-
|
||||
`)
|
||||
th.WriteK("/app/component2/overlay", `
|
||||
resources:
|
||||
- ../base
|
||||
|
||||
namePrefix: overlay-
|
||||
`)
|
||||
|
||||
th.WriteK("/app/shared", `
|
||||
resources:
|
||||
- resources.yaml
|
||||
`)
|
||||
th.WriteF("/app/shared/resources.yaml", `
|
||||
---
|
||||
kind: PersistentVolumeClaim
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: postgres
|
||||
spec:
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: postgres
|
||||
spec:
|
||||
selector:
|
||||
matchLabels: {}
|
||||
strategy:
|
||||
type: Recreate
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: postgres
|
||||
image: postgres
|
||||
imagePullPolicy: IfNotPresent
|
||||
volumeMounts:
|
||||
- mountPath: /var/lib/postgresql
|
||||
name: data
|
||||
ports:
|
||||
- name: postgres
|
||||
containerPort: 5432
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: postgres
|
||||
`)
|
||||
|
||||
th.WriteK("/app", `
|
||||
resources:
|
||||
- component1/overlay
|
||||
- component2/overlay
|
||||
`)
|
||||
|
||||
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||
if err != nil {
|
||||
t.Fatalf("Err: %v", err)
|
||||
}
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: overlay-component1-postgres
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: overlay-component1-postgres
|
||||
spec:
|
||||
selector:
|
||||
matchLabels: {}
|
||||
strategy:
|
||||
type: Recreate
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: postgres
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: postgres
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
name: postgres
|
||||
volumeMounts:
|
||||
- mountPath: /var/lib/postgresql
|
||||
name: data
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: overlay-component1-postgres
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: overlay-component2-postgres
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: overlay-component2-postgres
|
||||
spec:
|
||||
selector:
|
||||
matchLabels: {}
|
||||
strategy:
|
||||
type: Recreate
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: postgres
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: postgres
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
name: postgres
|
||||
volumeMounts:
|
||||
- mountPath: /var/lib/postgresql
|
||||
name: data
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: overlay-component2-postgres
|
||||
`)
|
||||
}
|
||||
@@ -1,557 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package target_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||
)
|
||||
|
||||
const httpsService = `
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: my-https-svc
|
||||
spec:
|
||||
ports:
|
||||
- port: 443
|
||||
protocol: TCP
|
||||
name: https
|
||||
selector:
|
||||
app: my-app
|
||||
`
|
||||
|
||||
func writeStatefulSetBase(th *kusttest_test.KustTestHarness) {
|
||||
th.WriteK("/app/base", `
|
||||
resources:
|
||||
- statefulset.yaml
|
||||
`)
|
||||
th.WriteF("/app/base/statefulset.yaml", `
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: my-sts
|
||||
spec:
|
||||
serviceName: my-svc
|
||||
selector:
|
||||
matchLabels:
|
||||
app: my-app
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: my-app
|
||||
spec:
|
||||
containers:
|
||||
- name: app
|
||||
image: my-image
|
||||
volumeClaimTemplates:
|
||||
- spec:
|
||||
storageClassName: default
|
||||
`)
|
||||
}
|
||||
|
||||
func writeHTTPSOverlay(th *kusttest_test.KustTestHarness) {
|
||||
th.WriteK("/app/https", `
|
||||
resources:
|
||||
- ../base
|
||||
- https-svc.yaml
|
||||
patchesStrategicMerge:
|
||||
- sts-patch.yaml
|
||||
`)
|
||||
th.WriteF("/app/https/https-svc.yaml", httpsService)
|
||||
th.WriteF("/app/https/sts-patch.yaml", `
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: my-sts
|
||||
spec:
|
||||
serviceName: my-https-svc
|
||||
`)
|
||||
}
|
||||
|
||||
func writeHTTPSTransformerRaw(th *kusttest_test.KustTestHarness) {
|
||||
th.WriteF("/app/https/service/https-svc.yaml", httpsService)
|
||||
th.WriteF("/app/https/transformer/transformer.yaml", `
|
||||
apiVersion: builtin
|
||||
kind: PatchTransformer
|
||||
metadata:
|
||||
name: svcNameTran
|
||||
target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: StatefulSet
|
||||
name: my-sts
|
||||
patch: |-
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: my-sts
|
||||
spec:
|
||||
serviceName: my-https-svc
|
||||
`)
|
||||
}
|
||||
|
||||
func writeHTTPSTransformerBase(th *kusttest_test.KustTestHarness) {
|
||||
th.WriteK("/app/https/service", `
|
||||
resources:
|
||||
- https-svc.yaml
|
||||
`)
|
||||
th.WriteK("/app/https/transformer", `
|
||||
resources:
|
||||
- transformer.yaml
|
||||
`)
|
||||
writeHTTPSTransformerRaw(th)
|
||||
}
|
||||
|
||||
func writeConfigFromEnvOverlay(th *kusttest_test.KustTestHarness) {
|
||||
th.WriteK("/app/config", `
|
||||
resources:
|
||||
- ../base
|
||||
configMapGenerator:
|
||||
- name: my-config
|
||||
literals:
|
||||
- MY_ENV=foo
|
||||
generatorOptions:
|
||||
disableNameSuffixHash: true
|
||||
patchesStrategicMerge:
|
||||
- sts-patch.yaml
|
||||
`)
|
||||
th.WriteF("/app/config/sts-patch.yaml", `
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: my-sts
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: app
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: my-config
|
||||
`)
|
||||
}
|
||||
|
||||
func writeConfigFromEnvTransformerRaw(th *kusttest_test.KustTestHarness) {
|
||||
th.WriteF("/app/config/map/generator.yaml", `
|
||||
apiVersion: builtin
|
||||
kind: ConfigMapGenerator
|
||||
metadata:
|
||||
name: my-config
|
||||
disableNameSuffixHash: true
|
||||
literals:
|
||||
- MY_ENV=foo
|
||||
`)
|
||||
th.WriteF("/app/config/transformer/transformer.yaml", `
|
||||
apiVersion: builtin
|
||||
kind: PatchTransformer
|
||||
metadata:
|
||||
name: envFromConfigTrans
|
||||
target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: StatefulSet
|
||||
name: my-sts
|
||||
patch: |-
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: my-sts
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: app
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: my-config
|
||||
`)
|
||||
}
|
||||
func writeConfigFromEnvTransformerBase(th *kusttest_test.KustTestHarness) {
|
||||
th.WriteK("/app/config/map", `
|
||||
resources:
|
||||
- generator.yaml
|
||||
`)
|
||||
th.WriteK("/app/config/transformer", `
|
||||
resources:
|
||||
- transformer.yaml
|
||||
`)
|
||||
writeConfigFromEnvTransformerRaw(th)
|
||||
}
|
||||
|
||||
func writeTolerationsOverlay(th *kusttest_test.KustTestHarness) {
|
||||
th.WriteK("/app/tolerations", `
|
||||
resources:
|
||||
- ../base
|
||||
patchesStrategicMerge:
|
||||
- sts-patch.yaml
|
||||
`)
|
||||
th.WriteF("/app/tolerations/sts-patch.yaml", `
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: my-sts
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
tolerations:
|
||||
- effect: NoExecute
|
||||
key: node.kubernetes.io/not-ready
|
||||
tolerationSeconds: 30
|
||||
`)
|
||||
}
|
||||
|
||||
func writeTolerationsTransformerRaw(th *kusttest_test.KustTestHarness) {
|
||||
th.WriteF("/app/tolerations/transformer.yaml", `
|
||||
apiVersion: builtin
|
||||
kind: PatchTransformer
|
||||
metadata:
|
||||
name: tolTrans
|
||||
target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: StatefulSet
|
||||
name: my-sts
|
||||
patch: |-
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: my-sts
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
tolerations:
|
||||
- effect: NoExecute
|
||||
key: node.kubernetes.io/not-ready
|
||||
tolerationSeconds: 30
|
||||
`)
|
||||
}
|
||||
|
||||
func writeTolerationsTransformerBase(th *kusttest_test.KustTestHarness) {
|
||||
th.WriteK("/app/tolerations", `
|
||||
resources:
|
||||
- transformer.yaml
|
||||
`)
|
||||
writeTolerationsTransformerRaw(th)
|
||||
}
|
||||
|
||||
func writeStorageOverlay(th *kusttest_test.KustTestHarness) {
|
||||
th.WriteK("/app/storage", `
|
||||
resources:
|
||||
- ../base
|
||||
patchesJson6902:
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: StatefulSet
|
||||
name: my-sts
|
||||
path: sts-patch.json
|
||||
`)
|
||||
th.WriteF("/app/storage/sts-patch.json", `
|
||||
[{"op": "replace", "path": "/spec/volumeClaimTemplates/0/spec/storageClassName", "value": "my-sc"}]
|
||||
`)
|
||||
}
|
||||
|
||||
func writeStorageTransformerRaw(th *kusttest_test.KustTestHarness) {
|
||||
th.WriteF("/app/storage/transformer.yaml", `
|
||||
apiVersion: builtin
|
||||
kind: PatchTransformer
|
||||
metadata:
|
||||
name: storageTrans
|
||||
target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: StatefulSet
|
||||
name: my-sts
|
||||
patch: |-
|
||||
[{"op": "replace", "path": "/spec/volumeClaimTemplates/0/spec/storageClassName", "value": "my-sc"}]
|
||||
`)
|
||||
}
|
||||
|
||||
func writeStorageTransformerBase(th *kusttest_test.KustTestHarness) {
|
||||
th.WriteK("/app/storage", `
|
||||
resources:
|
||||
- transformer.yaml
|
||||
`)
|
||||
writeStorageTransformerRaw(th)
|
||||
}
|
||||
|
||||
func writePatchingOverlays(th *kusttest_test.KustTestHarness) {
|
||||
writeStorageOverlay(th)
|
||||
writeConfigFromEnvOverlay(th)
|
||||
writeTolerationsOverlay(th)
|
||||
writeHTTPSOverlay(th)
|
||||
}
|
||||
|
||||
func writePatchingTransformersRaw(th *kusttest_test.KustTestHarness) {
|
||||
writeStorageTransformerRaw(th)
|
||||
writeConfigFromEnvTransformerRaw(th)
|
||||
writeTolerationsTransformerRaw(th)
|
||||
writeHTTPSTransformerRaw(th)
|
||||
}
|
||||
|
||||
// Similar to writePatchingTransformersRaw, except here the
|
||||
// transformers and related artifacts are addressable as _bases_.
|
||||
// They are listed in a kustomization file, and consumers of
|
||||
// the plugin refer to the kustomization instead of to the local
|
||||
// file in the "transformers:" field.
|
||||
//
|
||||
// Using bases makes the set of files relocatable with
|
||||
// respect to the overlays, and avoids the need to relax load
|
||||
// restrictions on file paths reaching outside the `dev` and
|
||||
// `prod` kustomization roots. I.e. with bases tests can use
|
||||
// NewKustTestHarness instead of NewKustTestHarnessNoLoadRestrictor.
|
||||
//
|
||||
// Using transformer plugins from _bases_ means the plugin config
|
||||
// must be self-contained, i.e. the config may not have fields that
|
||||
// refer to local files, since those files won't be present when
|
||||
// the plugin is instantiated and used.
|
||||
func writePatchingTransformerBases(th *kusttest_test.KustTestHarness) {
|
||||
writeStorageTransformerBase(th)
|
||||
writeConfigFromEnvTransformerBase(th)
|
||||
writeTolerationsTransformerBase(th)
|
||||
writeHTTPSTransformerBase(th)
|
||||
}
|
||||
|
||||
// Here's a complex kustomization scenario that combines multiple overlays
|
||||
// on a common base:
|
||||
//
|
||||
// dev prod
|
||||
// | |
|
||||
// | |
|
||||
// + ------- + + ------------ + ------------- +
|
||||
// | | | | |
|
||||
// | | | | |
|
||||
// v | v v v
|
||||
// storage + -----> config tolerations https
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | + --- + + --- + |
|
||||
// | | | |
|
||||
// | v v |
|
||||
// + -----------------------> base <------------------ +
|
||||
//
|
||||
// The base resource is a statefulset. Each intermediate overlay manages or
|
||||
// generates new resources and patches different aspects of the same base
|
||||
// resource, without using any of the `namePrefix`, `nameSuffix` or `namespace`
|
||||
// kustomization keywords.
|
||||
//
|
||||
// Intermediate overlays:
|
||||
// - storage: Changes the storage class of the stateful set with a JSON patch.
|
||||
// - config: Generates a config map and adds a field as an environment
|
||||
// variable.
|
||||
// - tolerations: Adds a new tolerations field in the spec.
|
||||
// - https: Adds a new service resource and changes the service name in the
|
||||
// stateful set.
|
||||
//
|
||||
// Top overlays:
|
||||
// - dev: Combines the storage and config intermediate overlays.
|
||||
// - prod: Combines the config, tolerations and https intermediate overlays.
|
||||
|
||||
func TestComplexComposition_Dev_Failure(t *testing.T) {
|
||||
th := kusttest_test.NewKustTestHarness(t, "/app/dev")
|
||||
writeStatefulSetBase(th)
|
||||
writePatchingOverlays(th)
|
||||
th.WriteK("/app/dev", `
|
||||
resources:
|
||||
- ../storage
|
||||
- ../config
|
||||
`)
|
||||
_, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||
if err == nil {
|
||||
t.Fatalf("Expected resource accumulation error")
|
||||
}
|
||||
if !strings.Contains(
|
||||
err.Error(), "already registered id: apps_v1_StatefulSet|~X|my-sts") {
|
||||
t.Fatalf("Unexpected err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
const devDesiredResult = `
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: my-sts
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: my-app
|
||||
serviceName: my-svc
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: my-app
|
||||
spec:
|
||||
containers:
|
||||
- envFrom:
|
||||
- configMapRef:
|
||||
name: my-config
|
||||
image: my-image
|
||||
name: app
|
||||
volumeClaimTemplates:
|
||||
- spec:
|
||||
storageClassName: my-sc
|
||||
---
|
||||
apiVersion: v1
|
||||
data:
|
||||
MY_ENV: foo
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: my-config
|
||||
`
|
||||
|
||||
func TestComplexComposition_Dev_SuccessWithRawTransformers(t *testing.T) {
|
||||
th := kusttest_test.NewKustTestHarnessNoLoadRestrictor(t, "/app/dev")
|
||||
writeStatefulSetBase(th)
|
||||
writePatchingTransformersRaw(th)
|
||||
th.WriteK("/app/dev", `
|
||||
resources:
|
||||
- ../base
|
||||
generators:
|
||||
- ../config/map/generator.yaml
|
||||
transformers:
|
||||
- ../config/transformer/transformer.yaml
|
||||
- ../storage/transformer.yaml
|
||||
`)
|
||||
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected err: %v", err)
|
||||
}
|
||||
th.AssertActualEqualsExpected(m, devDesiredResult)
|
||||
}
|
||||
|
||||
func TestComplexComposition_Dev_SuccessWithBaseTransformers(t *testing.T) {
|
||||
th := kusttest_test.NewKustTestHarness(t, "/app/dev")
|
||||
writeStatefulSetBase(th)
|
||||
writePatchingTransformerBases(th)
|
||||
th.WriteK("/app/dev", `
|
||||
resources:
|
||||
- ../base
|
||||
generators:
|
||||
- ../config/map
|
||||
transformers:
|
||||
- ../config/transformer
|
||||
- ../storage
|
||||
`)
|
||||
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected err: %v", err)
|
||||
}
|
||||
th.AssertActualEqualsExpected(m, devDesiredResult)
|
||||
}
|
||||
|
||||
func TestComplexComposition_Prod_Failure(t *testing.T) {
|
||||
th := kusttest_test.NewKustTestHarness(t, "/app/prod")
|
||||
writeStatefulSetBase(th)
|
||||
writePatchingOverlays(th)
|
||||
th.WriteK("/app/prod", `
|
||||
resources:
|
||||
- ../config
|
||||
- ../tolerations
|
||||
- ../https
|
||||
`)
|
||||
_, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||
if err == nil {
|
||||
t.Fatalf("Expected resource accumulation error")
|
||||
}
|
||||
if !strings.Contains(
|
||||
err.Error(), "already registered id: apps_v1_StatefulSet|~X|my-sts") {
|
||||
t.Fatalf("Unexpected err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
const prodDesiredResult = `
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: my-sts
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: my-app
|
||||
serviceName: my-https-svc
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: my-app
|
||||
spec:
|
||||
containers:
|
||||
- envFrom:
|
||||
- configMapRef:
|
||||
name: my-config
|
||||
image: my-image
|
||||
name: app
|
||||
tolerations:
|
||||
- effect: NoExecute
|
||||
key: node.kubernetes.io/not-ready
|
||||
tolerationSeconds: 30
|
||||
volumeClaimTemplates:
|
||||
- spec:
|
||||
storageClassName: default
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: my-https-svc
|
||||
spec:
|
||||
ports:
|
||||
- name: https
|
||||
port: 443
|
||||
protocol: TCP
|
||||
selector:
|
||||
app: my-app
|
||||
---
|
||||
apiVersion: v1
|
||||
data:
|
||||
MY_ENV: foo
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: my-config
|
||||
`
|
||||
|
||||
func TestComplexComposition_Prod_SuccessWithRawTransformers(t *testing.T) {
|
||||
th := kusttest_test.NewKustTestHarnessNoLoadRestrictor(t, "/app/prod")
|
||||
writeStatefulSetBase(th)
|
||||
writePatchingTransformersRaw(th)
|
||||
th.WriteK("/app/prod", `
|
||||
resources:
|
||||
- ../base
|
||||
- ../https/service/https-svc.yaml
|
||||
generators:
|
||||
- ../config/map/generator.yaml
|
||||
transformers:
|
||||
- ../config/transformer/transformer.yaml
|
||||
- ../https/transformer/transformer.yaml
|
||||
- ../tolerations/transformer.yaml
|
||||
`)
|
||||
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected err: %v", err)
|
||||
}
|
||||
th.AssertActualEqualsExpected(m, prodDesiredResult)
|
||||
}
|
||||
|
||||
func TestComplexComposition_Prod_SuccessWithBaseTransformers(t *testing.T) {
|
||||
th := kusttest_test.NewKustTestHarness(t, "/app/prod")
|
||||
writeStatefulSetBase(th)
|
||||
writePatchingTransformerBases(th)
|
||||
th.WriteK("/app/prod", `
|
||||
resources:
|
||||
- ../base
|
||||
- ../https/service
|
||||
generators:
|
||||
- ../config/map
|
||||
transformers:
|
||||
- ../config/transformer
|
||||
- ../https/transformer
|
||||
- ../tolerations
|
||||
`)
|
||||
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected err: %v", err)
|
||||
}
|
||||
th.AssertActualEqualsExpected(m, prodDesiredResult)
|
||||
}
|
||||
@@ -1,216 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package target_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||
)
|
||||
|
||||
// Demo custom configuration of a builtin transformation.
|
||||
// This is a NamePrefixer that only touches Deployments
|
||||
// and Services.
|
||||
func TestCustomNamePrefixer(t *testing.T) {
|
||||
tc := kusttest_test.NewPluginTestEnv(t).Set()
|
||||
defer tc.Reset()
|
||||
|
||||
tc.BuildGoPlugin(
|
||||
"builtin", "", "PrefixSuffixTransformer")
|
||||
|
||||
th := kusttest_test.NewKustTestHarnessAllowPlugins(t, "/app")
|
||||
|
||||
th.WriteK("/app", `
|
||||
resources:
|
||||
- deployment.yaml
|
||||
- role.yaml
|
||||
- service.yaml
|
||||
transformers:
|
||||
- prefixer.yaml
|
||||
`)
|
||||
th.WriteF("/app/prefixer.yaml", `
|
||||
apiVersion: builtin
|
||||
kind: PrefixSuffixTransformer
|
||||
metadata:
|
||||
name: customPrefixer
|
||||
prefix: zzz-
|
||||
fieldSpecs:
|
||||
- kind: Deployment
|
||||
path: metadata/name
|
||||
- kind: Service
|
||||
path: metadata/name
|
||||
`)
|
||||
th.WriteF("/app/deployment.yaml", `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: myDeployment
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
backend: awesome
|
||||
spec:
|
||||
containers:
|
||||
- name: whatever
|
||||
image: whatever
|
||||
`)
|
||||
th.WriteF("/app/role.yaml", `
|
||||
apiVersion: v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: myRole
|
||||
`)
|
||||
th.WriteF("/app/service.yaml", `
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: myService
|
||||
`)
|
||||
|
||||
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||
if err != nil {
|
||||
t.Fatalf("Err: %v", err)
|
||||
}
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: zzz-myDeployment
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
backend: awesome
|
||||
spec:
|
||||
containers:
|
||||
- image: whatever
|
||||
name: whatever
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: myRole
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: zzz-myService
|
||||
`)
|
||||
}
|
||||
|
||||
// Demo custom configuration as a base.
|
||||
func TestReusableCustomNamePrefixer(t *testing.T) {
|
||||
tc := kusttest_test.NewPluginTestEnv(t).Set()
|
||||
defer tc.Reset()
|
||||
|
||||
tc.BuildGoPlugin(
|
||||
"builtin", "", "PrefixSuffixTransformer")
|
||||
tc.BuildGoPlugin(
|
||||
"builtin", "", "LabelTransformer")
|
||||
|
||||
th := kusttest_test.NewKustTestHarnessAllowPlugins(t, "/app/foo")
|
||||
|
||||
// This kustomization file contains resources that
|
||||
// all happen to be plugin configurations. This makes
|
||||
// these plugins all available as part of a base,
|
||||
// re-usable in any number of other kustomizations.
|
||||
// Just specify the path (or URL) to this base in the
|
||||
// "transformers:" field (not the "resources" field).
|
||||
th.WriteK("/app/mytransformers", `
|
||||
resources:
|
||||
- prefixer.yaml
|
||||
- labeller.yaml
|
||||
`)
|
||||
th.WriteF("/app/mytransformers/prefixer.yaml", `
|
||||
apiVersion: builtin
|
||||
kind: PrefixSuffixTransformer
|
||||
metadata:
|
||||
name: myPrefixer
|
||||
prefix: zzz-
|
||||
fieldSpecs:
|
||||
- kind: Deployment
|
||||
path: metadata/name
|
||||
- kind: Service
|
||||
path: metadata/name
|
||||
`)
|
||||
th.WriteF("/app/mytransformers/labeller.yaml", `
|
||||
apiVersion: builtin
|
||||
kind: LabelTransformer
|
||||
metadata:
|
||||
name: myLabeller
|
||||
labels:
|
||||
company: acmeCorp
|
||||
fieldSpecs:
|
||||
- path: spec/template/metadata/labels
|
||||
kind: Deployment
|
||||
`)
|
||||
|
||||
th.WriteK("/app/foo", `
|
||||
resources:
|
||||
- deployment.yaml
|
||||
- role.yaml
|
||||
- service.yaml
|
||||
transformers:
|
||||
- ../mytransformers
|
||||
`)
|
||||
th.WriteF("/app/foo/deployment.yaml", `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: myDeployment
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
backend: awesome
|
||||
spec:
|
||||
containers:
|
||||
- name: whatever
|
||||
image: whatever
|
||||
`)
|
||||
th.WriteF("/app/foo/role.yaml", `
|
||||
apiVersion: v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: myRole
|
||||
`)
|
||||
th.WriteF("/app/foo/service.yaml", `
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: myService
|
||||
`)
|
||||
|
||||
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||
if err != nil {
|
||||
t.Fatalf("Err: %v", err)
|
||||
}
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: zzz-myDeployment
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
backend: awesome
|
||||
company: acmeCorp
|
||||
spec:
|
||||
containers:
|
||||
- image: whatever
|
||||
name: whatever
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: myRole
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: zzz-myService
|
||||
`)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,244 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package target_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||
)
|
||||
|
||||
func makeResourcesForPatchTest(th *kusttest_test.KustTestHarness) {
|
||||
th.WriteF("/app/base/deployment.yaml", `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
volumeMounts:
|
||||
- name: nginx-persistent-storage
|
||||
mountPath: /tmp/ps
|
||||
volumes:
|
||||
- name: nginx-persistent-storage
|
||||
emptyDir: {}
|
||||
- configMap:
|
||||
name: configmap-in-base
|
||||
name: configmap-in-base
|
||||
`)
|
||||
}
|
||||
|
||||
func TestStrategicMergePatchInline(t *testing.T) {
|
||||
th := kusttest_test.NewKustTestHarness(t, "/app/base")
|
||||
makeResourcesForPatchTest(th)
|
||||
th.WriteK("/app/base", `
|
||||
resources:
|
||||
- deployment.yaml
|
||||
|
||||
patchesStrategicMerge:
|
||||
- |-
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: image1
|
||||
`)
|
||||
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||
if err != nil {
|
||||
t.Fatalf("Err: %v", err)
|
||||
}
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
name: nginx
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- image: image1
|
||||
name: nginx
|
||||
volumeMounts:
|
||||
- mountPath: /tmp/ps
|
||||
name: nginx-persistent-storage
|
||||
volumes:
|
||||
- emptyDir: {}
|
||||
name: nginx-persistent-storage
|
||||
- configMap:
|
||||
name: configmap-in-base
|
||||
name: configmap-in-base
|
||||
`)
|
||||
}
|
||||
|
||||
func TestJSONPatchInline(t *testing.T) {
|
||||
th := kusttest_test.NewKustTestHarness(t, "/app/base")
|
||||
makeResourcesForPatchTest(th)
|
||||
th.WriteK("/app/base", `
|
||||
resources:
|
||||
- deployment.yaml
|
||||
|
||||
patchesJson6902:
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: Deployment
|
||||
name: nginx
|
||||
patch: |-
|
||||
- op: replace
|
||||
path: /spec/template/spec/containers/0/image
|
||||
value: image1
|
||||
`)
|
||||
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||
if err != nil {
|
||||
t.Fatalf("Err: %v", err)
|
||||
}
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
name: nginx
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- image: image1
|
||||
name: nginx
|
||||
volumeMounts:
|
||||
- mountPath: /tmp/ps
|
||||
name: nginx-persistent-storage
|
||||
volumes:
|
||||
- emptyDir: {}
|
||||
name: nginx-persistent-storage
|
||||
- configMap:
|
||||
name: configmap-in-base
|
||||
name: configmap-in-base
|
||||
`)
|
||||
}
|
||||
|
||||
func TestExtendedPatchInlineJSON(t *testing.T) {
|
||||
th := kusttest_test.NewKustTestHarness(t, "/app/base")
|
||||
makeResourcesForPatchTest(th)
|
||||
th.WriteK("/app/base", `
|
||||
resources:
|
||||
- deployment.yaml
|
||||
|
||||
patches:
|
||||
- target:
|
||||
kind: Deployment
|
||||
name: nginx
|
||||
patch: |-
|
||||
- op: replace
|
||||
path: /spec/template/spec/containers/0/image
|
||||
value: image1
|
||||
`)
|
||||
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||
if err != nil {
|
||||
t.Fatalf("Err: %v", err)
|
||||
}
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
name: nginx
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- image: image1
|
||||
name: nginx
|
||||
volumeMounts:
|
||||
- mountPath: /tmp/ps
|
||||
name: nginx-persistent-storage
|
||||
volumes:
|
||||
- emptyDir: {}
|
||||
name: nginx-persistent-storage
|
||||
- configMap:
|
||||
name: configmap-in-base
|
||||
name: configmap-in-base
|
||||
`)
|
||||
}
|
||||
|
||||
func TestExtendedPatchInlineYAML(t *testing.T) {
|
||||
th := kusttest_test.NewKustTestHarness(t, "/app/base")
|
||||
makeResourcesForPatchTest(th)
|
||||
th.WriteK("/app/base", `
|
||||
resources:
|
||||
- deployment.yaml
|
||||
|
||||
patches:
|
||||
- target:
|
||||
kind: Deployment
|
||||
name: nginx
|
||||
patch: |-
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: image1
|
||||
`)
|
||||
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||
if err != nil {
|
||||
t.Fatalf("Err: %v", err)
|
||||
}
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
name: nginx
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- image: image1
|
||||
name: nginx
|
||||
volumeMounts:
|
||||
- mountPath: /tmp/ps
|
||||
name: nginx-persistent-storage
|
||||
volumes:
|
||||
- emptyDir: {}
|
||||
name: nginx-persistent-storage
|
||||
- configMap:
|
||||
name: configmap-in-base
|
||||
name: configmap-in-base
|
||||
`)
|
||||
}
|
||||
@@ -1,297 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package target
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
// Functions dedicated to configuring the builtin
|
||||
// transformer and generator plugins using config data
|
||||
// read from a kustomization file and from the
|
||||
// config.TransformerConfig, whose data may be a
|
||||
// mix of hardcoded values and data read from file.
|
||||
//
|
||||
// Non-builtin plugins will get their configuration
|
||||
// from their own dedicated structs and YAML files.
|
||||
//
|
||||
// There are some loops in the functions below because
|
||||
// the kustomization file would, say, allow someone to
|
||||
// request multiple secrets be made, or run multiple
|
||||
// image tag transforms. In these cases, we'll need
|
||||
// N plugin instances with differing configurations.
|
||||
|
||||
func (kt *KustTarget) configureBuiltinGenerators() (
|
||||
result []resmap.Generator, err error) {
|
||||
for _, bpt := range []builtinhelpers.BuiltinPluginType{
|
||||
builtinhelpers.ConfigMapGenerator,
|
||||
builtinhelpers.SecretGenerator,
|
||||
} {
|
||||
r, err := generatorConfigurators[bpt](
|
||||
kt, bpt, builtinhelpers.GeneratorFactories[bpt])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, r...)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (kt *KustTarget) configureBuiltinTransformers(
|
||||
tc *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
for _, bpt := range []builtinhelpers.BuiltinPluginType{
|
||||
builtinhelpers.PatchStrategicMergeTransformer,
|
||||
builtinhelpers.PatchTransformer,
|
||||
builtinhelpers.NamespaceTransformer,
|
||||
builtinhelpers.PrefixSuffixTransformer,
|
||||
builtinhelpers.LabelTransformer,
|
||||
builtinhelpers.AnnotationsTransformer,
|
||||
builtinhelpers.PatchJson6902Transformer,
|
||||
builtinhelpers.ReplicaCountTransformer,
|
||||
builtinhelpers.ImageTagTransformer,
|
||||
} {
|
||||
r, err := transformerConfigurators[bpt](
|
||||
kt, bpt, builtinhelpers.TransformerFactories[bpt], tc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, r...)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type gFactory func() resmap.GeneratorPlugin
|
||||
|
||||
var generatorConfigurators = map[builtinhelpers.BuiltinPluginType]func(
|
||||
kt *KustTarget,
|
||||
bpt builtinhelpers.BuiltinPluginType,
|
||||
factory gFactory) (result []resmap.Generator, err error){
|
||||
builtinhelpers.SecretGenerator: func(kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f gFactory) (
|
||||
result []resmap.Generator, err error) {
|
||||
var c struct {
|
||||
types.GeneratorOptions
|
||||
types.SecretArgs
|
||||
}
|
||||
if kt.kustomization.GeneratorOptions != nil {
|
||||
c.GeneratorOptions = *kt.kustomization.GeneratorOptions
|
||||
}
|
||||
for _, args := range kt.kustomization.SecretGenerator {
|
||||
c.SecretArgs = args
|
||||
p := f()
|
||||
err := kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
},
|
||||
|
||||
builtinhelpers.ConfigMapGenerator: func(kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f gFactory) (
|
||||
result []resmap.Generator, err error) {
|
||||
var c struct {
|
||||
types.GeneratorOptions
|
||||
types.ConfigMapArgs
|
||||
}
|
||||
if kt.kustomization.GeneratorOptions != nil {
|
||||
c.GeneratorOptions = *kt.kustomization.GeneratorOptions
|
||||
}
|
||||
for _, args := range kt.kustomization.ConfigMapGenerator {
|
||||
c.ConfigMapArgs = args
|
||||
p := f()
|
||||
err := kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
},
|
||||
}
|
||||
|
||||
type tFactory func() resmap.TransformerPlugin
|
||||
|
||||
var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func(
|
||||
kt *KustTarget,
|
||||
bpt builtinhelpers.BuiltinPluginType,
|
||||
f tFactory,
|
||||
tc *builtinconfig.TransformerConfig) (result []resmap.Transformer, err error){
|
||||
builtinhelpers.NamespaceTransformer: func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
var c struct {
|
||||
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||
FieldSpecs []types.FieldSpec
|
||||
}
|
||||
c.Namespace = kt.kustomization.Namespace
|
||||
c.FieldSpecs = tc.NameSpace
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
return
|
||||
},
|
||||
|
||||
builtinhelpers.PatchJson6902Transformer: func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, _ *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
var c struct {
|
||||
Target types.PatchTarget `json:"target,omitempty" yaml:"target,omitempty"`
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
JsonOp string `json:"jsonOp,omitempty" yaml:"jsonOp,omitempty"`
|
||||
}
|
||||
for _, args := range kt.kustomization.PatchesJson6902 {
|
||||
c.Target = *args.Target
|
||||
c.Path = args.Path
|
||||
c.JsonOp = args.Patch
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
},
|
||||
builtinhelpers.PatchStrategicMergeTransformer: func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, _ *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
if len(kt.kustomization.PatchesStrategicMerge) == 0 {
|
||||
return
|
||||
}
|
||||
var c struct {
|
||||
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
|
||||
Patches string `json:"patches,omitempty" yaml:"patches,omitempty"`
|
||||
}
|
||||
c.Paths = kt.kustomization.PatchesStrategicMerge
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
return
|
||||
},
|
||||
builtinhelpers.PatchTransformer: func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, _ *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
if len(kt.kustomization.Patches) == 0 {
|
||||
return
|
||||
}
|
||||
var c struct {
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
||||
Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"`
|
||||
}
|
||||
for _, pc := range kt.kustomization.Patches {
|
||||
c.Target = pc.Target
|
||||
c.Patch = pc.Patch
|
||||
c.Path = pc.Path
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
},
|
||||
builtinhelpers.LabelTransformer: func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
var c struct {
|
||||
Labels map[string]string
|
||||
FieldSpecs []types.FieldSpec
|
||||
}
|
||||
c.Labels = kt.kustomization.CommonLabels
|
||||
c.FieldSpecs = tc.CommonLabels
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
return
|
||||
},
|
||||
builtinhelpers.AnnotationsTransformer: func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
var c struct {
|
||||
Annotations map[string]string
|
||||
FieldSpecs []types.FieldSpec
|
||||
}
|
||||
c.Annotations = kt.kustomization.CommonAnnotations
|
||||
c.FieldSpecs = tc.CommonAnnotations
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
return
|
||||
},
|
||||
builtinhelpers.PrefixSuffixTransformer: func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
var c struct {
|
||||
Prefix string
|
||||
Suffix string
|
||||
FieldSpecs []types.FieldSpec
|
||||
}
|
||||
c.Prefix = kt.kustomization.NamePrefix
|
||||
c.Suffix = kt.kustomization.NameSuffix
|
||||
c.FieldSpecs = tc.NamePrefix
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
return
|
||||
},
|
||||
builtinhelpers.ImageTagTransformer: func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
var c struct {
|
||||
ImageTag types.Image
|
||||
FieldSpecs []types.FieldSpec
|
||||
}
|
||||
for _, args := range kt.kustomization.Images {
|
||||
c.ImageTag = args
|
||||
c.FieldSpecs = tc.Images
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
},
|
||||
builtinhelpers.ReplicaCountTransformer: func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
var c struct {
|
||||
Replica types.Replica
|
||||
FieldSpecs []types.FieldSpec
|
||||
}
|
||||
for _, args := range kt.kustomization.Replicas {
|
||||
c.Replica = args
|
||||
c.FieldSpecs = tc.Replicas
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
},
|
||||
}
|
||||
@@ -1,602 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package target_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||
)
|
||||
|
||||
func TestNamespacedSecrets(t *testing.T) {
|
||||
th := kusttest_test.NewKustTestHarness(t, "/app")
|
||||
|
||||
th.WriteF("/app/secrets.yaml", `
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: dummy
|
||||
namespace: default
|
||||
type: Opaque
|
||||
data:
|
||||
dummy: ""
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: dummy
|
||||
namespace: kube-system
|
||||
type: Opaque
|
||||
data:
|
||||
dummy: ""
|
||||
`)
|
||||
|
||||
// This should find the proper secret.
|
||||
th.WriteF("/app/role.yaml", `
|
||||
kind: ClusterRole
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: dummy
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
resourceNames: ["dummy"]
|
||||
verbs: ["get"]
|
||||
`)
|
||||
|
||||
th.WriteK("/app", `
|
||||
resources:
|
||||
- secrets.yaml
|
||||
- role.yaml
|
||||
`)
|
||||
|
||||
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||
// This validates Fix #1444. This should not be an error anymore -
|
||||
// the secrets have the same name but are in different namespaces.
|
||||
// The ClusterRole (by def) is not in a namespace,
|
||||
// an in this case applies to *any* Secret resource
|
||||
// named "dummy"
|
||||
if err != nil {
|
||||
t.Fatalf("Err: %v", err)
|
||||
}
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: v1
|
||||
data:
|
||||
dummy: ""
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: dummy
|
||||
namespace: default
|
||||
type: Opaque
|
||||
---
|
||||
apiVersion: v1
|
||||
data:
|
||||
dummy: ""
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: dummy
|
||||
namespace: kube-system
|
||||
type: Opaque
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: dummy
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resourceNames:
|
||||
- dummy
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
`)
|
||||
}
|
||||
|
||||
// TestNameAndNsTransformation validates that NamespaceTransformer,
|
||||
// PrefixSuffixTransformer and namereference transformers are
|
||||
// able to deal with simultaneous change of namespace and name.
|
||||
func TestNameAndNsTransformation(t *testing.T) {
|
||||
th := kusttest_test.NewKustTestHarness(t, "/nameandns")
|
||||
|
||||
th.WriteK("/nameandns", `
|
||||
namePrefix: p1-
|
||||
nameSuffix: -s1
|
||||
namespace: newnamespace
|
||||
resources:
|
||||
- resources.yaml
|
||||
`)
|
||||
|
||||
th.WriteF("/nameandns/resources.yaml", `
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm1
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm2
|
||||
namespace: ns1
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: svc1
|
||||
namespace: ns1
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: svc2
|
||||
namespace: ns1
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: sa1
|
||||
namespace: ns1
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: sa2
|
||||
namespace: ns1
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: manager-rolebinding
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: sa1
|
||||
namespace: ns1
|
||||
- kind: ServiceAccount
|
||||
name: sa2
|
||||
namespace: ns1
|
||||
- kind: ServiceAccount
|
||||
name: sa3
|
||||
namespace: random
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: irrelevant
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||
kind: ValidatingWebhookConfiguration
|
||||
metadata:
|
||||
name: example
|
||||
webhooks:
|
||||
- name: example1
|
||||
clientConfig:
|
||||
service:
|
||||
name: svc1
|
||||
namespace: ns1
|
||||
- name: example2
|
||||
clientConfig:
|
||||
service:
|
||||
name: svc2
|
||||
namespace: ns1
|
||||
- name: example3
|
||||
clientConfig:
|
||||
service:
|
||||
name: svc3
|
||||
namespace: random
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: crds.my.org
|
||||
---
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: cr1
|
||||
---
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: crb1
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: irrelevant
|
||||
---
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: pv1
|
||||
`)
|
||||
|
||||
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||
if err != nil {
|
||||
t.Fatalf("Err: %v", err)
|
||||
}
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: p1-cm1-s1
|
||||
namespace: newnamespace
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: p1-cm2-s1
|
||||
namespace: newnamespace
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: p1-svc1-s1
|
||||
namespace: newnamespace
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: p1-svc2-s1
|
||||
namespace: newnamespace
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: p1-sa1-s1
|
||||
namespace: newnamespace
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: p1-sa2-s1
|
||||
namespace: newnamespace
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: p1-manager-rolebinding-s1
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: p1-sa1-s1
|
||||
namespace: newnamespace
|
||||
- kind: ServiceAccount
|
||||
name: p1-sa2-s1
|
||||
namespace: newnamespace
|
||||
- kind: ServiceAccount
|
||||
name: sa3
|
||||
namespace: random
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: newnamespace
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||
kind: ValidatingWebhookConfiguration
|
||||
metadata:
|
||||
name: p1-example-s1
|
||||
webhooks:
|
||||
- clientConfig:
|
||||
service:
|
||||
name: p1-svc1-s1
|
||||
namespace: newnamespace
|
||||
name: example1
|
||||
- clientConfig:
|
||||
service:
|
||||
name: p1-svc2-s1
|
||||
namespace: newnamespace
|
||||
name: example2
|
||||
- clientConfig:
|
||||
service:
|
||||
name: svc3
|
||||
namespace: random
|
||||
name: example3
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: crds.my.org
|
||||
---
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: p1-cr1-s1
|
||||
---
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: p1-crb1-s1
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: newnamespace
|
||||
---
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: p1-pv1-s1
|
||||
`)
|
||||
}
|
||||
|
||||
// This serie of constants is used to prove the need of
|
||||
// the namespace field in the objref field of the var declaration.
|
||||
// The following tests demonstrate that it creates umbiguous variable
|
||||
// declaration if two entities of the kind with the same name
|
||||
// but in different namespaces are declared.
|
||||
// This is tracking the following issue:
|
||||
// https://github.com/kubernetes-sigs/kustomize/issues/1298
|
||||
const namespaceNeedInVarMyApp string = `
|
||||
resources:
|
||||
- elasticsearch-dev-service.yaml
|
||||
- elasticsearch-test-service.yaml
|
||||
vars:
|
||||
- name: elasticsearch-test-service-name
|
||||
objref:
|
||||
kind: Service
|
||||
name: elasticsearch
|
||||
apiVersion: v1
|
||||
fieldref:
|
||||
fieldpath: metadata.name
|
||||
- name: elasticsearch-test-protocol
|
||||
objref:
|
||||
kind: Service
|
||||
name: elasticsearch
|
||||
apiVersion: v1
|
||||
fieldref:
|
||||
fieldpath: spec.ports[0].protocol
|
||||
- name: elasticsearch-dev-service-name
|
||||
objref:
|
||||
kind: Service
|
||||
name: elasticsearch
|
||||
apiVersion: v1
|
||||
fieldref:
|
||||
fieldpath: metadata.name
|
||||
- name: elasticsearch-dev-protocol
|
||||
objref:
|
||||
kind: Service
|
||||
name: elasticsearch
|
||||
apiVersion: v1
|
||||
fieldref:
|
||||
fieldpath: spec.ports[0].protocol
|
||||
`
|
||||
|
||||
const namespaceNeedInVarDevResources string = `
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: elasticsearch
|
||||
namespace: dev
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: elasticsearch
|
||||
env:
|
||||
- name: DISCOVERY_SERVICE
|
||||
value: "$(elasticsearch-dev-service-name).monitoring.svc.cluster.local"
|
||||
- name: DISCOVERY_PROTOCOL
|
||||
value: "$(elasticsearch-dev-protocol)"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: elasticsearch
|
||||
namespace: dev
|
||||
spec:
|
||||
ports:
|
||||
- name: transport
|
||||
port: 9300
|
||||
protocol: TCP
|
||||
clusterIP: None
|
||||
`
|
||||
|
||||
const namespaceNeedInVarTestResources string = `
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: elasticsearch
|
||||
namespace: test
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: elasticsearch
|
||||
env:
|
||||
- name: DISCOVERY_SERVICE
|
||||
value: "$(elasticsearch-test-service-name).monitoring.svc.cluster.local"
|
||||
- name: DISCOVERY_PROTOCOL
|
||||
value: "$(elasticsearch-test-protocol)"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: elasticsearch
|
||||
namespace: test
|
||||
spec:
|
||||
ports:
|
||||
- name: transport
|
||||
port: 9300
|
||||
protocol: UDP
|
||||
clusterIP: None
|
||||
`
|
||||
|
||||
const namespaceNeedInVarExpectedOutput string = `
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: elasticsearch
|
||||
namespace: dev
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- env:
|
||||
- name: DISCOVERY_SERVICE
|
||||
value: elasticsearch.monitoring.svc.cluster.local
|
||||
- name: DISCOVERY_PROTOCOL
|
||||
value: TCP
|
||||
name: elasticsearch
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: elasticsearch
|
||||
namespace: dev
|
||||
spec:
|
||||
clusterIP: None
|
||||
ports:
|
||||
- name: transport
|
||||
port: 9300
|
||||
protocol: TCP
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: elasticsearch
|
||||
namespace: test
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- env:
|
||||
- name: DISCOVERY_SERVICE
|
||||
value: elasticsearch.monitoring.svc.cluster.local
|
||||
- name: DISCOVERY_PROTOCOL
|
||||
value: UDP
|
||||
name: elasticsearch
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: elasticsearch
|
||||
namespace: test
|
||||
spec:
|
||||
clusterIP: None
|
||||
ports:
|
||||
- name: transport
|
||||
port: 9300
|
||||
protocol: UDP
|
||||
`
|
||||
|
||||
// TestVariablesAmbiguous demonstrates how two variables pointing at two different resources
|
||||
// using the same name in different namespaces are treated as ambiguous if the namespace is
|
||||
// not specified
|
||||
func TestVariablesAmbiguous(t *testing.T) {
|
||||
th := kusttest_test.NewKustTestHarness(t, "/namespaceNeedInVar/myapp")
|
||||
th.WriteK("/namespaceNeedInVar/myapp", namespaceNeedInVarMyApp)
|
||||
th.WriteF("/namespaceNeedInVar/myapp/elasticsearch-dev-service.yaml", namespaceNeedInVarDevResources)
|
||||
th.WriteF("/namespaceNeedInVar/myapp/elasticsearch-test-service.yaml", namespaceNeedInVarTestResources)
|
||||
_, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||
if err == nil {
|
||||
t.Fatalf("expected error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "unable to disambiguate") {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
const namespaceNeedInVarDevFolder string = `
|
||||
resources:
|
||||
- elasticsearch-dev-service.yaml
|
||||
vars:
|
||||
- name: elasticsearch-dev-service-name
|
||||
objref:
|
||||
kind: Service
|
||||
name: elasticsearch
|
||||
apiVersion: v1
|
||||
fieldref:
|
||||
fieldpath: metadata.name
|
||||
- name: elasticsearch-dev-protocol
|
||||
objref:
|
||||
kind: Service
|
||||
name: elasticsearch
|
||||
apiVersion: v1
|
||||
fieldref:
|
||||
fieldpath: spec.ports[0].protocol
|
||||
`
|
||||
|
||||
const namespaceNeedInVarTestFolder string = `
|
||||
resources:
|
||||
- elasticsearch-test-service.yaml
|
||||
vars:
|
||||
- name: elasticsearch-test-service-name
|
||||
objref:
|
||||
kind: Service
|
||||
name: elasticsearch
|
||||
apiVersion: v1
|
||||
fieldref:
|
||||
fieldpath: metadata.name
|
||||
- name: elasticsearch-test-protocol
|
||||
objref:
|
||||
kind: Service
|
||||
name: elasticsearch
|
||||
apiVersion: v1
|
||||
fieldref:
|
||||
fieldpath: spec.ports[0].protocol
|
||||
`
|
||||
|
||||
// TestVariablesAmbiguousWorkaround demonstrates a possible workaround
|
||||
// to TestVariablesAmbiguous problem. It requires to separate the variables
|
||||
// and resources into multiple kustomization context/folders instead of one.
|
||||
func TestVariablesAmbiguousWorkaround(t *testing.T) {
|
||||
th := kusttest_test.NewKustTestHarness(t, "/namespaceNeedInVar/workaround")
|
||||
th.WriteK("/namespaceNeedInVar/dev", namespaceNeedInVarDevFolder)
|
||||
th.WriteF("/namespaceNeedInVar/dev/elasticsearch-dev-service.yaml", namespaceNeedInVarDevResources)
|
||||
th.WriteK("/namespaceNeedInVar/test", namespaceNeedInVarTestFolder)
|
||||
th.WriteF("/namespaceNeedInVar/test/elasticsearch-test-service.yaml", namespaceNeedInVarTestResources)
|
||||
th.WriteK("/namespaceNeedInVar/workaround", `
|
||||
resources:
|
||||
- ../dev
|
||||
- ../test
|
||||
`)
|
||||
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||
if err != nil {
|
||||
t.Fatalf("Err: %v", err)
|
||||
}
|
||||
th.AssertActualEqualsExpected(m, namespaceNeedInVarExpectedOutput)
|
||||
}
|
||||
|
||||
const namespaceNeedInVarMyAppWithNamespace string = `
|
||||
resources:
|
||||
- elasticsearch-dev-service.yaml
|
||||
- elasticsearch-test-service.yaml
|
||||
vars:
|
||||
- name: elasticsearch-test-service-name
|
||||
objref:
|
||||
kind: Service
|
||||
name: elasticsearch
|
||||
namespace: test
|
||||
apiVersion: v1
|
||||
fieldref:
|
||||
fieldpath: metadata.name
|
||||
- name: elasticsearch-test-protocol
|
||||
objref:
|
||||
kind: Service
|
||||
name: elasticsearch
|
||||
namespace: test
|
||||
apiVersion: v1
|
||||
fieldref:
|
||||
fieldpath: spec.ports[0].protocol
|
||||
- name: elasticsearch-dev-service-name
|
||||
objref:
|
||||
kind: Service
|
||||
name: elasticsearch
|
||||
namespace: dev
|
||||
apiVersion: v1
|
||||
fieldref:
|
||||
fieldpath: metadata.name
|
||||
- name: elasticsearch-dev-protocol
|
||||
objref:
|
||||
kind: Service
|
||||
name: elasticsearch
|
||||
namespace: dev
|
||||
apiVersion: v1
|
||||
fieldref:
|
||||
fieldpath: spec.ports[0].protocol
|
||||
`
|
||||
|
||||
// TestVariablesDisambiguatedWithNamespace demonstrates that adding the namespace
|
||||
// to the variable declarations allows to disambiguate the variables.
|
||||
func TestVariablesDisambiguatedWithNamespace(t *testing.T) {
|
||||
th := kusttest_test.NewKustTestHarness(t, "/namespaceNeedInVar/myapp")
|
||||
th.WriteK("/namespaceNeedInVar/myapp", namespaceNeedInVarMyAppWithNamespace)
|
||||
th.WriteF("/namespaceNeedInVar/myapp/elasticsearch-dev-service.yaml", namespaceNeedInVarDevResources)
|
||||
th.WriteF("/namespaceNeedInVar/myapp/elasticsearch-test-service.yaml", namespaceNeedInVarTestResources)
|
||||
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||
if err != nil {
|
||||
t.Fatalf("Err: %v", err)
|
||||
}
|
||||
th.AssertActualEqualsExpected(m, namespaceNeedInVarExpectedOutput)
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
// +build tools
|
||||
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// This file exists to trigger installs of the given tools.
|
||||
|
||||
package tools
|
||||
|
||||
import (
|
||||
// for code generation
|
||||
_ "golang.org/x/tools/cmd/stringer"
|
||||
// for lint checks
|
||||
_ "github.com/golangci/golangci-lint/cmd/golangci-lint"
|
||||
// for integration tests driven by the examples
|
||||
_ "github.com/monopole/mdrip"
|
||||
// TODO: See comment in Makefile.
|
||||
//_ "sigs.k8s.io/kustomize/pluginator"
|
||||
)
|
||||
@@ -1,8 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package builtinpluginconsts provides builtin plugin
|
||||
// configuration data. Builtin plugins can also be
|
||||
// configured individually with plugin config files,
|
||||
// in which case the constants in this package are ignored.
|
||||
package builtinpluginconsts
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package builtinpluginconsts
|
||||
|
||||
const (
|
||||
// imageFieldSpecs is left empty since `containers` and `initContainers`
|
||||
// of *ANY* kind in *ANY* path are builtin supported in code
|
||||
imagesFieldSpecs = ``
|
||||
)
|
||||
@@ -1,11 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package builtinpluginconsts
|
||||
|
||||
const (
|
||||
namePrefixFieldSpecs = `
|
||||
namePrefix:
|
||||
- path: metadata/name
|
||||
`
|
||||
)
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package builtinpluginconsts
|
||||
|
||||
const (
|
||||
namespaceFieldSpecs = `
|
||||
namespace:
|
||||
- path: metadata/namespace
|
||||
create: true
|
||||
- path: subjects
|
||||
kind: RoleBinding
|
||||
- path: subjects
|
||||
kind: ClusterRoleBinding
|
||||
`
|
||||
)
|
||||
@@ -1,6 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package konfig provides configuration methods and constants
|
||||
// for the kustomize API.
|
||||
package konfig
|
||||
@@ -1,33 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package konfig
|
||||
|
||||
// RecognizedKustomizationFileNames is a list of file names
|
||||
// that kustomize recognizes.
|
||||
// To avoid ambiguity, a kustomization directory may not
|
||||
// contain more than one match to this list.
|
||||
func RecognizedKustomizationFileNames() []string {
|
||||
return []string{
|
||||
"kustomization.yaml",
|
||||
"kustomization.yml",
|
||||
"Kustomization",
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultKustomizationFileName() string {
|
||||
return RecognizedKustomizationFileNames()[0]
|
||||
}
|
||||
|
||||
const (
|
||||
// An environment variable to consult for kustomization
|
||||
// configuration data. See:
|
||||
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
XdgConfigHomeEnv = "XDG_CONFIG_HOME"
|
||||
|
||||
// Use this when XdgConfigHomeEnv not defined.
|
||||
XdgConfigHomeEnvDefault = ".config"
|
||||
|
||||
// A program name, for use in help, finding the XDG_CONFIG_DIR, etc.
|
||||
ProgramName = "kustomize"
|
||||
)
|
||||
@@ -1,150 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package konfig
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
const (
|
||||
// Symbol that must be used inside Go plugins.
|
||||
PluginSymbol = "KustomizePlugin"
|
||||
|
||||
// Name of environment variable used to set AbsPluginHome.
|
||||
// See that variable for an explanation.
|
||||
KustomizePluginHomeEnv = "KUSTOMIZE_PLUGIN_HOME"
|
||||
|
||||
// Relative path below XDG_CONFIG_HOME/kustomize to find plugins.
|
||||
// e.g. AbsPluginHome = XDG_CONFIG_HOME/kustomize/plugin
|
||||
RelPluginHome = "plugin"
|
||||
|
||||
// Location of builtin plugins below AbsPluginHome.
|
||||
BuiltinPluginPackage = "builtin"
|
||||
|
||||
// The value of kubernetes ApiVersion to use in configuration
|
||||
// files for builtin plugins.
|
||||
// The value for non-builtins can be anything.
|
||||
BuiltinPluginApiVersion = BuiltinPluginPackage
|
||||
|
||||
// Domain from which kustomize code is imported, for locating
|
||||
// plugin source code under $GOPATH when GOPATH is defined.
|
||||
DomainName = "sigs.k8s.io"
|
||||
)
|
||||
|
||||
func EnabledPluginConfig() (*types.PluginConfig, error) {
|
||||
dir, err := DefaultAbsPluginHome(filesys.MakeFsOnDisk())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return MakePluginConfig(types.PluginRestrictionsNone, dir), nil
|
||||
}
|
||||
|
||||
func DisabledPluginConfig() *types.PluginConfig {
|
||||
return MakePluginConfig(
|
||||
types.PluginRestrictionsBuiltinsOnly, NoPluginHomeSentinal)
|
||||
}
|
||||
|
||||
func MakePluginConfig(
|
||||
pr types.PluginRestrictions, home string) *types.PluginConfig {
|
||||
return &types.PluginConfig{
|
||||
PluginRestrictions: pr,
|
||||
AbsPluginHome: home,
|
||||
}
|
||||
}
|
||||
|
||||
// Use an obviously erroneous path, in case it's accidentally used.
|
||||
const NoPluginHomeSentinal = "/no/non-builtin/plugins!"
|
||||
|
||||
type NotedFunc struct {
|
||||
Note string
|
||||
F func() string
|
||||
}
|
||||
|
||||
func DefaultAbsPluginHome(fSys filesys.FileSystem) (string, error) {
|
||||
return FirstDirThatExistsElseError(
|
||||
"plugin home directory", fSys, []NotedFunc{
|
||||
{
|
||||
Note: "homed in $" + KustomizePluginHomeEnv,
|
||||
F: func() string {
|
||||
return os.Getenv(KustomizePluginHomeEnv)
|
||||
},
|
||||
},
|
||||
{
|
||||
Note: "homed in $" + XdgConfigHomeEnv,
|
||||
F: func() string {
|
||||
return filepath.Join(
|
||||
os.Getenv(XdgConfigHomeEnv),
|
||||
ProgramName, RelPluginHome)
|
||||
},
|
||||
},
|
||||
{
|
||||
Note: "homed in default value of $" + XdgConfigHomeEnv,
|
||||
F: func() string {
|
||||
return filepath.Join(
|
||||
HomeDir(), XdgConfigHomeEnvDefault,
|
||||
ProgramName, RelPluginHome)
|
||||
},
|
||||
},
|
||||
{
|
||||
Note: "homed in home directory",
|
||||
F: func() string {
|
||||
return filepath.Join(
|
||||
HomeDir(), ProgramName, RelPluginHome)
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// FirstDirThatExistsElseError tests different path functions for
|
||||
// existence, returning the first that works, else error if all fail.
|
||||
func FirstDirThatExistsElseError(
|
||||
what string,
|
||||
fSys filesys.FileSystem,
|
||||
pathFuncs []NotedFunc) (string, error) {
|
||||
var nope []types.Pair
|
||||
for _, dt := range pathFuncs {
|
||||
dir := dt.F()
|
||||
if fSys.Exists(dir) {
|
||||
return dir, nil
|
||||
}
|
||||
nope = append(nope, types.Pair{Key: dt.Note, Value: dir})
|
||||
}
|
||||
return "", types.NewErrUnableToFind(what, nope)
|
||||
}
|
||||
|
||||
func HomeDir() string {
|
||||
home := os.Getenv(homeEnv())
|
||||
if len(home) > 0 {
|
||||
return home
|
||||
}
|
||||
return "~"
|
||||
}
|
||||
|
||||
func homeEnv() string {
|
||||
if runtime.GOOS == "windows" {
|
||||
return "USERPROFILE"
|
||||
}
|
||||
return "HOME"
|
||||
}
|
||||
|
||||
func CurrentWorkingDir() string {
|
||||
// Try for full path first to be explicit.
|
||||
pwd := os.Getenv(pwdEnv())
|
||||
if len(pwd) > 0 {
|
||||
return pwd
|
||||
}
|
||||
return "."
|
||||
}
|
||||
|
||||
func pwdEnv() string {
|
||||
if runtime.GOOS == "windows" {
|
||||
return "CD"
|
||||
}
|
||||
return "PWD"
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package konfig
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
func TestDefaultAbsPluginHome_NoKustomizePluginHomeEnv(t *testing.T) {
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
keep, isSet := os.LookupEnv(KustomizePluginHomeEnv)
|
||||
if isSet {
|
||||
_ = os.Unsetenv(KustomizePluginHomeEnv)
|
||||
}
|
||||
_, err := DefaultAbsPluginHome(fSys)
|
||||
if isSet {
|
||||
os.Setenv(KustomizePluginHomeEnv, keep)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("expected err")
|
||||
}
|
||||
if !types.IsErrUnableToFind(err) {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultAbsPluginHome_WithKustomizePluginHomeEnv(t *testing.T) {
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
keep, isSet := os.LookupEnv(KustomizePluginHomeEnv)
|
||||
if !isSet {
|
||||
keep = "whatever"
|
||||
os.Setenv(KustomizePluginHomeEnv, keep)
|
||||
}
|
||||
fSys.Mkdir(keep)
|
||||
h, err := DefaultAbsPluginHome(fSys)
|
||||
if !isSet {
|
||||
_ = os.Unsetenv(KustomizePluginHomeEnv)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
if h != keep {
|
||||
t.Fatalf("unexpected config dir: %s", h)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultAbsPluginHomeWithXdg(t *testing.T) {
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
keep, isSet := os.LookupEnv(XdgConfigHomeEnv)
|
||||
if !isSet {
|
||||
keep = "whatever"
|
||||
os.Setenv(XdgConfigHomeEnv, keep)
|
||||
}
|
||||
configDir := filepath.Join(keep, ProgramName, RelPluginHome)
|
||||
fSys.Mkdir(configDir)
|
||||
h, err := DefaultAbsPluginHome(fSys)
|
||||
if !isSet {
|
||||
_ = os.Unsetenv(XdgConfigHomeEnv)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
if h != configDir {
|
||||
t.Fatalf("unexpected config dir: %s", h)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultAbsPluginHomeNoConfig(t *testing.T) {
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
keep, isSet := os.LookupEnv(XdgConfigHomeEnv)
|
||||
if isSet {
|
||||
_ = os.Unsetenv(XdgConfigHomeEnv)
|
||||
}
|
||||
_, err := DefaultAbsPluginHome(fSys)
|
||||
if isSet {
|
||||
os.Setenv(XdgConfigHomeEnv, keep)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("expected err")
|
||||
}
|
||||
if !types.IsErrUnableToFind(err) {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultAbsPluginHomeNoXdgWithDotConfig(t *testing.T) {
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
configDir := filepath.Join(
|
||||
HomeDir(), XdgConfigHomeEnvDefault, ProgramName, RelPluginHome)
|
||||
fSys.Mkdir(configDir)
|
||||
keep, isSet := os.LookupEnv(XdgConfigHomeEnv)
|
||||
if isSet {
|
||||
_ = os.Unsetenv(XdgConfigHomeEnv)
|
||||
}
|
||||
s, _ := DefaultAbsPluginHome(fSys)
|
||||
if isSet {
|
||||
os.Setenv(XdgConfigHomeEnv, keep)
|
||||
}
|
||||
if s != configDir {
|
||||
t.Fatalf("unexpected config dir: %s", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultAbsPluginHomeNoXdgJustHomeDir(t *testing.T) {
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
configDir := filepath.Join(
|
||||
HomeDir(), ProgramName, RelPluginHome)
|
||||
fSys.Mkdir(configDir)
|
||||
keep, isSet := os.LookupEnv(XdgConfigHomeEnv)
|
||||
if isSet {
|
||||
_ = os.Unsetenv(XdgConfigHomeEnv)
|
||||
}
|
||||
s, _ := DefaultAbsPluginHome(fSys)
|
||||
if isSet {
|
||||
os.Setenv(XdgConfigHomeEnv, keep)
|
||||
}
|
||||
if s != configDir {
|
||||
t.Fatalf("unexpected config dir: %s", s)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package krusty holds a very high level API to kustomize.
|
||||
// The functions here should be similar to the CLI api.
|
||||
package krusty
|
||||
@@ -1,85 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/builtins"
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
"sigs.k8s.io/kustomize/api/internal/k8sdeps/transformer"
|
||||
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
||||
"sigs.k8s.io/kustomize/api/internal/target"
|
||||
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
|
||||
"sigs.k8s.io/kustomize/api/k8sdeps/validator"
|
||||
fLdr "sigs.k8s.io/kustomize/api/loader"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
// Kustomizer performs kustomizations. It's meant to behave
|
||||
// similarly to the kustomize CLI, and can be used instead of
|
||||
// performing an exec to a kustomize CLI subprocess.
|
||||
// To use, load a filesystem with kustomization files (any
|
||||
// number of overlays and bases), then make a Kustomizer
|
||||
// injected with the given fileystem, then call Build.
|
||||
type Kustomizer struct {
|
||||
fSys filesys.FileSystem
|
||||
options *Options
|
||||
}
|
||||
|
||||
// MakeKustomizer returns an instance of Kustomizer.
|
||||
func MakeKustomizer(fSys filesys.FileSystem, o *Options) *Kustomizer {
|
||||
return &Kustomizer{fSys: fSys, options: o}
|
||||
}
|
||||
|
||||
// Run performs a kustomization.
|
||||
//
|
||||
// It uses its internal filesystem reference to read the file at
|
||||
// the given path argument, interpret it as a kustomization.yaml
|
||||
// file, perform the kustomization it represents, and return the
|
||||
// resulting resources.
|
||||
//
|
||||
// Any files referenced by the kustomization must be present in the
|
||||
// internal filesystem. One may call Run any number of times,
|
||||
// on any number of internal paths (e.g. the filesystem may contain
|
||||
// multiple overlays, and Run can be called on each of them).
|
||||
func (b *Kustomizer) Run(path string) (resmap.ResMap, error) {
|
||||
pf := transformer.NewFactoryImpl()
|
||||
rf := resmap.NewFactory(
|
||||
resource.NewFactory(
|
||||
kunstruct.NewKunstructuredFactoryImpl()),
|
||||
pf)
|
||||
lr := fLdr.RestrictionNone
|
||||
if b.options.LoadRestrictions == types.LoadRestrictionsRootOnly {
|
||||
lr = fLdr.RestrictionRootOnly
|
||||
}
|
||||
ldr, err := fLdr.NewLoader(lr, path, b.fSys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer ldr.Cleanup()
|
||||
kt, err := target.NewKustTarget(
|
||||
ldr,
|
||||
validator.NewKustValidator(),
|
||||
rf,
|
||||
pf,
|
||||
pLdr.NewLoader(b.options.PluginConfig, rf),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var m resmap.ResMap
|
||||
if b.options.DoPrune {
|
||||
m, err = kt.MakePruneConfigMap()
|
||||
} else {
|
||||
m, err = kt.MakeCustomizedResMap()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if b.options.DoLegacyResourceSort {
|
||||
builtins.NewLegacyOrderTransformerPlugin().Transform(m)
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// TODO: move most of the tests in the api/target package to this package.
|
||||
package krusty_test
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
"sigs.k8s.io/kustomize/api/krusty"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TODO: make this more like kusttest_test.AssertActualEqualsExpected
|
||||
func assertOutput(t *testing.T, actual []byte, expected string) {
|
||||
if string(actual) != expected {
|
||||
t.Fatalf("Err: expected:\n%s\nbut got:\n%s\n", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSomething1(t *testing.T) {
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
b := krusty.MakeKustomizer(fSys, krusty.MakeDefaultOptions())
|
||||
_, err := b.Run("hey")
|
||||
if err == nil {
|
||||
t.Fatalf("expected error")
|
||||
}
|
||||
if err.Error() != "got file 'hey', but 'hey' must be a directory to be a root" {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package krusty
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
// Options holds high-level kustomize configuration options,
|
||||
// e.g. are plugins enabled, should the loader be restricted
|
||||
// to the kustomization root, etc.
|
||||
type Options struct {
|
||||
// When true, sort the resources before emitting them,
|
||||
// per a particular sort order. When false, don't do the
|
||||
// sort, and instead respect the depth-first resource input
|
||||
// order as specified by the kustomization file(s).
|
||||
DoLegacyResourceSort bool
|
||||
|
||||
// Restrictions on what can be loaded from the file system.
|
||||
// See type definition.
|
||||
LoadRestrictions types.LoadRestrictions
|
||||
|
||||
// Create an inventory object for pruning.
|
||||
DoPrune bool
|
||||
|
||||
// Options related to kustomize plugins.
|
||||
PluginConfig *types.PluginConfig
|
||||
}
|
||||
|
||||
// MakeDefaultOptions returns a default instance of Options.
|
||||
func MakeDefaultOptions() *Options {
|
||||
return &Options{
|
||||
DoLegacyResourceSort: true,
|
||||
LoadRestrictions: types.LoadRestrictionsRootOnly,
|
||||
DoPrune: false,
|
||||
PluginConfig: konfig.DisabledPluginConfig(),
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package loader has a data loading interface and various implementations.
|
||||
package loader
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/kustomize/api/internal/git"
|
||||
)
|
||||
|
||||
// NewLoader returns a Loader pointed at the given target.
|
||||
// If the target is remote, the loader will be restricted
|
||||
// to the root and below only. If the target is local, the
|
||||
// loader will have the restrictions passed in. Regardless,
|
||||
// if a local target attempts to transitively load remote bases,
|
||||
// the remote bases will all be root-only restricted.
|
||||
func NewLoader(
|
||||
lr LoadRestrictorFunc,
|
||||
target string, fSys filesys.FileSystem) (ifc.Loader, error) {
|
||||
repoSpec, err := git.NewRepoSpecFromUrl(target)
|
||||
if err == nil {
|
||||
// The target qualifies as a remote git target.
|
||||
return newLoaderAtGitClone(
|
||||
repoSpec, fSys, nil, git.ClonerUsingGitExec)
|
||||
}
|
||||
root, err := demandDirectoryRoot(fSys, target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newLoaderAtConfirmedDir(
|
||||
lr, root, fSys, nil, git.ClonerUsingGitExec), nil
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package loader
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
)
|
||||
|
||||
type LoadRestrictorFunc func(
|
||||
filesys.FileSystem, filesys.ConfirmedDir, string) (string, error)
|
||||
|
||||
func RestrictionRootOnly(
|
||||
fSys filesys.FileSystem, root filesys.ConfirmedDir, path string) (string, error) {
|
||||
d, f, err := fSys.CleanedAbs(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if f == "" {
|
||||
return "", fmt.Errorf("'%s' must be a file", path)
|
||||
}
|
||||
if !d.HasPrefix(root) {
|
||||
return "", fmt.Errorf(
|
||||
"security; file '%s' is not in or below '%s'",
|
||||
path, root)
|
||||
}
|
||||
return d.Join(f), nil
|
||||
}
|
||||
|
||||
func RestrictionNone(
|
||||
_ filesys.FileSystem, _ filesys.ConfirmedDir, path string) (string, error) {
|
||||
return path, nil
|
||||
}
|
||||
19
api/main.go
19
api/main.go
@@ -1,19 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// A dummy main to help with releasing the kustomize API module.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sigs.k8s.io/kustomize/api/provenance"
|
||||
)
|
||||
|
||||
// TODO: delete this when we find a better way to generate release notes.
|
||||
func main() {
|
||||
fmt.Println(`
|
||||
This 'main' exists only to make goreleaser create release notes for the API.
|
||||
See https://github.com/goreleaser/goreleaser/issues/981
|
||||
and https://github.com/kubernetes-sigs/kustomize/tree/master/releasing`)
|
||||
fmt.Println(provenance.GetProvenance())
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package provenance
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
version = "unknown"
|
||||
// sha1 from git, output of $(git rev-parse HEAD)
|
||||
gitCommit = "$Format:%H$"
|
||||
// build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ')
|
||||
buildDate = "1970-01-01T00:00:00Z"
|
||||
goos = runtime.GOOS
|
||||
goarch = runtime.GOARCH
|
||||
)
|
||||
|
||||
// Provenance holds information about the build of an executable.
|
||||
type Provenance struct {
|
||||
// Version of the kustomize binary.
|
||||
Version string `json:"version,omitempty"`
|
||||
// GitCommit is a git commit
|
||||
GitCommit string `json:"gitCommit,omitempty"`
|
||||
// BuildDate is date of the build.
|
||||
BuildDate string `json:"buildDate,omitempty"`
|
||||
// GoOs holds OS name.
|
||||
GoOs string `json:"goOs,omitempty"`
|
||||
// GoArch holds architecture name.
|
||||
GoArch string `json:"goArch,omitempty"`
|
||||
}
|
||||
|
||||
// GetProvenance returns an instance of Provenance.
|
||||
func GetProvenance() Provenance {
|
||||
return Provenance{
|
||||
version,
|
||||
gitCommit,
|
||||
buildDate,
|
||||
goos,
|
||||
goarch,
|
||||
}
|
||||
}
|
||||
|
||||
// Full returns the full provenance stamp.
|
||||
func (v Provenance) Full() string {
|
||||
return fmt.Sprintf("%+v", v)
|
||||
}
|
||||
|
||||
// Short returns the shortened provenance stamp.
|
||||
func (v Provenance) Short() string {
|
||||
return fmt.Sprintf(
|
||||
"%v",
|
||||
Provenance{
|
||||
Version: v.Version,
|
||||
BuildDate: v.BuildDate,
|
||||
})
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package patch holds miscellaneous interfaces used by kustomize.
|
||||
package resmap
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
)
|
||||
|
||||
// PatchFactory makes transformers that require k8sdeps.
|
||||
type PatchFactory interface {
|
||||
MergePatches(patches []*resource.Resource,
|
||||
rf *resource.Factory) (ResMap, error)
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package transform
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
// mapTransformer applies a string->string map to fieldSpecs.
|
||||
type mapTransformer struct {
|
||||
m map[string]string
|
||||
fieldSpecs []types.FieldSpec
|
||||
}
|
||||
|
||||
var _ resmap.Transformer = &mapTransformer{}
|
||||
|
||||
// NewMapTransformer construct a mapTransformer.
|
||||
func NewMapTransformer(
|
||||
pc []types.FieldSpec, m map[string]string) (resmap.Transformer, error) {
|
||||
if m == nil {
|
||||
return newNoOpTransformer(), nil
|
||||
}
|
||||
if pc == nil {
|
||||
return nil, errors.New("fieldSpecs is not expected to be nil")
|
||||
}
|
||||
return &mapTransformer{fieldSpecs: pc, m: m}, nil
|
||||
}
|
||||
|
||||
// Transform apply each <key, value> pair in the mapTransformer to the
|
||||
// fields specified in mapTransformer.
|
||||
func (o *mapTransformer) Transform(m resmap.ResMap) error {
|
||||
for _, r := range m.Resources() {
|
||||
for _, path := range o.fieldSpecs {
|
||||
if !r.OrgId().IsSelected(&path.Gvk) {
|
||||
continue
|
||||
}
|
||||
err := MutateField(
|
||||
r.Map(), path.PathSlice(),
|
||||
path.CreateIfNotPresent, o.addMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *mapTransformer) addMap(in interface{}) (interface{}, error) {
|
||||
m, ok := in.(map[string]interface{})
|
||||
if in == nil {
|
||||
m = map[string]interface{}{}
|
||||
} else if !ok {
|
||||
return nil, fmt.Errorf("%#v is expected to be %T", in, m)
|
||||
}
|
||||
for k, v := range o.m {
|
||||
m[k] = v
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package transform
|
||||
|
||||
import "sigs.k8s.io/kustomize/api/resmap"
|
||||
|
||||
// noOpTransformer contains a no-op transformer.
|
||||
type noOpTransformer struct{}
|
||||
|
||||
var _ resmap.Transformer = &noOpTransformer{}
|
||||
|
||||
// newNoOpTransformer constructs a noOpTransformer.
|
||||
func newNoOpTransformer() resmap.Transformer {
|
||||
return &noOpTransformer{}
|
||||
}
|
||||
|
||||
// Transform does nothing.
|
||||
func (o *noOpTransformer) Transform(_ resmap.ResMap) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// ConfigMapArgs contains the metadata of how to generate a configmap.
|
||||
type ConfigMapArgs struct {
|
||||
// GeneratorArgs for the configmap.
|
||||
GeneratorArgs `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package types holds the definition of the kustomization struct and
|
||||
// supporting structs. It's the k8s API conformant object that describes
|
||||
// a set of generation and transformation operations to create and/or
|
||||
// modify k8s resources.
|
||||
// A kustomization file is a serialization of this struct.
|
||||
package types
|
||||
@@ -1,32 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type errOnlyBuiltinPluginsAllowed struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (e *errOnlyBuiltinPluginsAllowed) Error() string {
|
||||
return fmt.Sprintf(
|
||||
"external plugins disabled; unable to load external plugin '%s'",
|
||||
e.name)
|
||||
}
|
||||
|
||||
func NewErrOnlyBuiltinPluginsAllowed(n string) *errOnlyBuiltinPluginsAllowed {
|
||||
return &errOnlyBuiltinPluginsAllowed{name: n}
|
||||
}
|
||||
|
||||
func IsErrOnlyBuiltinPluginsAllowed(err error) bool {
|
||||
_, ok := err.(*errOnlyBuiltinPluginsAllowed)
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
_, ok = errors.Cause(err).(*errOnlyBuiltinPluginsAllowed)
|
||||
return ok
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type errUnableToFind struct {
|
||||
// What are we unable to find?
|
||||
what string
|
||||
// What things did we try?
|
||||
attempts []Pair
|
||||
}
|
||||
|
||||
func (e *errUnableToFind) Error() string {
|
||||
var m []string
|
||||
for _, p := range e.attempts {
|
||||
m = append(m, "('"+p.Value+"'; "+p.Key+")")
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
"unable to find plugin root - tried: %s", strings.Join(m, ", "))
|
||||
}
|
||||
|
||||
func NewErrUnableToFind(w string, a []Pair) *errUnableToFind {
|
||||
return &errUnableToFind{what: w, attempts: a}
|
||||
}
|
||||
|
||||
func IsErrUnableToFind(err error) bool {
|
||||
_, ok := err.(*errUnableToFind)
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
_, ok = errors.Cause(err).(*errUnableToFind)
|
||||
return ok
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"log"
|
||||
"regexp"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// FixKustomizationPreUnmarshalling modies the raw data
|
||||
// before marshalling - e.g. changes old field names to
|
||||
// new field names.
|
||||
func FixKustomizationPreUnmarshalling(data []byte) []byte {
|
||||
deprecateFieldsMap := map[string]string{
|
||||
"imageTags:": "images:",
|
||||
}
|
||||
for oldname, newname := range deprecateFieldsMap {
|
||||
pattern := regexp.MustCompile(oldname)
|
||||
data = pattern.ReplaceAll(data, []byte(newname))
|
||||
}
|
||||
if useLegacyPatch(data) {
|
||||
pattern := regexp.MustCompile("patches:")
|
||||
data = pattern.ReplaceAll(data, []byte("patchesStrategicMerge:"))
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func useLegacyPatch(data []byte) bool {
|
||||
found := false
|
||||
var object map[string]interface{}
|
||||
err := yaml.Unmarshal(data, &object)
|
||||
if err != nil {
|
||||
log.Fatalf("invalid content from %s\n", string(data))
|
||||
}
|
||||
if rawPatches, ok := object["patches"]; ok {
|
||||
patches, ok := rawPatches.([]interface{})
|
||||
if !ok {
|
||||
log.Fatalf("invalid patches from %v\n", rawPatches)
|
||||
}
|
||||
for _, p := range patches {
|
||||
_, ok := p.(string)
|
||||
if ok {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return found
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
//go:generate stringer -type=GarbagePolicy
|
||||
type GarbagePolicy int
|
||||
|
||||
const (
|
||||
GarbageIgnore GarbagePolicy = iota + 1
|
||||
GarbageCollect
|
||||
)
|
||||
@@ -1,37 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
func TestGenArgs_String(t *testing.T) {
|
||||
tests := []struct {
|
||||
ga *GenArgs
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
ga: nil,
|
||||
expected: "{nilGenArgs}",
|
||||
},
|
||||
{
|
||||
ga: &GenArgs{},
|
||||
expected: "{nsfx:false,beh:unspecified}",
|
||||
},
|
||||
{
|
||||
ga: NewGenArgs(
|
||||
&GeneratorArgs{Behavior: "merge"},
|
||||
&GeneratorOptions{DisableNameSuffixHash: false}),
|
||||
expected: "{nsfx:true,beh:merge}",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
if test.ga.String() != test.expected {
|
||||
t.Fatalf("Expected '%s', got '%s'", test.expected, test.ga.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// GeneratorArgs contains arguments common to ConfigMap and Secret generators.
|
||||
type GeneratorArgs struct {
|
||||
// Namespace for the configmap, optional
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
|
||||
// Name - actually the partial name - of the generated resource.
|
||||
// The full name ends up being something like
|
||||
// NamePrefix + this.Name + hash(content of generated resource).
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
|
||||
// Behavior of generated resource, must be one of:
|
||||
// 'create': create a new one
|
||||
// 'replace': replace the existing one
|
||||
// 'merge': merge with the existing one
|
||||
Behavior string `json:"behavior,omitempty" yaml:"behavior,omitempty"`
|
||||
|
||||
// KvPairSources for the generator.
|
||||
KvPairSources `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// GeneratorOptions modify behavior of all ConfigMap and Secret generators.
|
||||
type GeneratorOptions struct {
|
||||
// Labels to add to all generated resources.
|
||||
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||
|
||||
// Annotations to add to all generated resources.
|
||||
Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
|
||||
|
||||
// DisableNameSuffixHash if true disables the default behavior of adding a
|
||||
// suffix to the names of generated resources that is a hash of the
|
||||
// resource contents.
|
||||
DisableNameSuffixHash bool `json:"disableNameSuffixHash,omitempty" yaml:"disableNameSuffixHash,omitempty"`
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Image contains an image name, a new name, a new tag or digest,
|
||||
// which will replace the original name and tag.
|
||||
type Image struct {
|
||||
// Name is a tag-less image name.
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
|
||||
// NewName is the value used to replace the original name.
|
||||
NewName string `json:"newName,omitempty" yaml:"newName,omitempty"`
|
||||
|
||||
// NewTag is the value used to replace the original tag.
|
||||
NewTag string `json:"newTag,omitempty" yaml:"newTag,omitempty"`
|
||||
|
||||
// Digest is the value used to replace the original image tag.
|
||||
// If digest is present NewTag value is ignored.
|
||||
Digest string `json:"digest,omitempty" yaml:"digest,omitempty"`
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Inventory records all objects touched in a build operation.
|
||||
type Inventory struct {
|
||||
Type string `json:"type,omitempty" yaml:"type,omitempty"`
|
||||
ConfigMap NameArgs `json:"configMap,omitempty" yaml:"configMap,omitempty"`
|
||||
}
|
||||
|
||||
// NameArgs holds both namespace and name.
|
||||
type NameArgs struct {
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
const (
|
||||
KustomizationVersion = "kustomize.config.k8s.io/v1beta1"
|
||||
KustomizationKind = "Kustomization"
|
||||
)
|
||||
|
||||
// Kustomization holds the information needed to generate customized k8s api resources.
|
||||
type Kustomization struct {
|
||||
TypeMeta `json:",inline" yaml:",inline"`
|
||||
|
||||
//
|
||||
// Operators - what kustomize can do.
|
||||
//
|
||||
|
||||
// NamePrefix will prefix the names of all resources mentioned in the kustomization
|
||||
// file including generated configmaps and secrets.
|
||||
NamePrefix string `json:"namePrefix,omitempty" yaml:"namePrefix,omitempty"`
|
||||
|
||||
// NameSuffix will suffix the names of all resources mentioned in the kustomization
|
||||
// file including generated configmaps and secrets.
|
||||
NameSuffix string `json:"nameSuffix,omitempty" yaml:"nameSuffix,omitempty"`
|
||||
|
||||
// Namespace to add to all objects.
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
|
||||
// CommonLabels to add to all objects and selectors.
|
||||
CommonLabels map[string]string `json:"commonLabels,omitempty" yaml:"commonLabels,omitempty"`
|
||||
|
||||
// CommonAnnotations to add to all objects.
|
||||
CommonAnnotations map[string]string `json:"commonAnnotations,omitempty" yaml:"commonAnnotations,omitempty"`
|
||||
|
||||
// PatchesStrategicMerge specifies the relative path to a file
|
||||
// containing a strategic merge patch. Format documented at
|
||||
// https://github.com/kubernetes/community/blob/master/contributors/devel/strategic-merge-patch.md
|
||||
// URLs and globs are not supported.
|
||||
PatchesStrategicMerge []PatchStrategicMerge `json:"patchesStrategicMerge,omitempty" yaml:"patchesStrategicMerge,omitempty"`
|
||||
|
||||
// JSONPatches is a list of JSONPatch for applying JSON patch.
|
||||
// Format documented at https://tools.ietf.org/html/rfc6902
|
||||
// and http://jsonpatch.com
|
||||
PatchesJson6902 []PatchJson6902 `json:"patchesJson6902,omitempty" yaml:"patchesJson6902,omitempty"`
|
||||
|
||||
// Patches is a list of patches, where each one can be either a
|
||||
// Strategic Merge Patch or a JSON patch.
|
||||
// Each patch can be applied to multiple target objects.
|
||||
Patches []Patch `json:"patches,omitempty" yaml:"patches,omitempty"`
|
||||
|
||||
// Images is a list of (image name, new name, new tag or digest)
|
||||
// for changing image names, tags or digests. This can also be achieved with a
|
||||
// patch, but this operator is simpler to specify.
|
||||
Images []Image `json:"images,omitempty" yaml:"images,omitempty"`
|
||||
|
||||
// Replicas is a list of {resourcename, count} that allows for simpler replica
|
||||
// specification. This can also be done with a patch.
|
||||
Replicas []Replica `json:"replicas,omitempty" yaml:"replicas,omitempty"`
|
||||
|
||||
// Vars allow things modified by kustomize to be injected into a
|
||||
// kubernetes object specification. A var is a name (e.g. FOO) associated
|
||||
// with a field in a specific resource instance. The field must
|
||||
// contain a value of type string/bool/int/float, and defaults to the name field
|
||||
// of the instance. Any appearance of "$(FOO)" in the object
|
||||
// spec will be replaced at kustomize build time, after the final
|
||||
// value of the specified field has been determined.
|
||||
Vars []Var `json:"vars,omitempty" yaml:"vars,omitempty"`
|
||||
|
||||
//
|
||||
// Operands - what kustomize operates on.
|
||||
//
|
||||
|
||||
// Resources specifies relative paths to files holding YAML representations
|
||||
// of kubernetes API objects, or specifcations of other kustomizations
|
||||
// via relative paths, absolute paths, or URLs.
|
||||
Resources []string `json:"resources,omitempty" yaml:"resources,omitempty"`
|
||||
|
||||
// Crds specifies relative paths to Custom Resource Definition files.
|
||||
// This allows custom resources to be recognized as operands, making
|
||||
// it possible to add them to the Resources list.
|
||||
// CRDs themselves are not modified.
|
||||
Crds []string `json:"crds,omitempty" yaml:"crds,omitempty"`
|
||||
|
||||
// Deprecated.
|
||||
// Anything that would have been specified here should
|
||||
// be specified in the Resources field instead.
|
||||
Bases []string `json:"bases,omitempty" yaml:"bases,omitempty"`
|
||||
|
||||
//
|
||||
// Generators (operators that create operands)
|
||||
//
|
||||
|
||||
// ConfigMapGenerator is a list of configmaps to generate from
|
||||
// local data (one configMap per list item).
|
||||
// The resulting resource is a normal operand, subject to
|
||||
// name prefixing, patching, etc. By default, the name of
|
||||
// the map will have a suffix hash generated from its contents.
|
||||
ConfigMapGenerator []ConfigMapArgs `json:"configMapGenerator,omitempty" yaml:"configMapGenerator,omitempty"`
|
||||
|
||||
// SecretGenerator is a list of secrets to generate from
|
||||
// local data (one secret per list item).
|
||||
// The resulting resource is a normal operand, subject to
|
||||
// name prefixing, patching, etc. By default, the name of
|
||||
// the map will have a suffix hash generated from its contents.
|
||||
SecretGenerator []SecretArgs `json:"secretGenerator,omitempty" yaml:"secretGenerator,omitempty"`
|
||||
|
||||
// GeneratorOptions modify behavior of all ConfigMap and Secret generators.
|
||||
GeneratorOptions *GeneratorOptions `json:"generatorOptions,omitempty" yaml:"generatorOptions,omitempty"`
|
||||
|
||||
// Configurations is a list of transformer configuration files
|
||||
Configurations []string `json:"configurations,omitempty" yaml:"configurations,omitempty"`
|
||||
|
||||
// Generators is a list of files containing custom generators
|
||||
Generators []string `json:"generators,omitempty" yaml:"generators,omitempty"`
|
||||
|
||||
// Transformers is a list of files containing transformers
|
||||
Transformers []string `json:"transformers,omitempty" yaml:"transformers,omitempty"`
|
||||
|
||||
// Inventory appends an object that contains the record
|
||||
// of all other objects, which can be used in apply, prune and delete
|
||||
Inventory *Inventory `json:"inventory,omitempty" yaml:"inventory,omitempty"`
|
||||
}
|
||||
|
||||
// FixKustomizationPostUnmarshalling fixes things
|
||||
// like empty fields that should not be empty, or
|
||||
// moving content of deprecated fields to newer
|
||||
// fields.
|
||||
func (k *Kustomization) FixKustomizationPostUnmarshalling() {
|
||||
if k.APIVersion == "" {
|
||||
k.APIVersion = KustomizationVersion
|
||||
}
|
||||
if k.Kind == "" {
|
||||
k.Kind = KustomizationKind
|
||||
}
|
||||
for _, b := range k.Bases {
|
||||
k.Resources = append(k.Resources, b)
|
||||
}
|
||||
k.Bases = nil
|
||||
}
|
||||
|
||||
func (k *Kustomization) EnforceFields() []string {
|
||||
var errs []string
|
||||
if k.APIVersion != "" && k.APIVersion != KustomizationVersion {
|
||||
errs = append(errs, "apiVersion should be "+KustomizationVersion)
|
||||
}
|
||||
if k.Kind != "" && k.Kind != KustomizationKind {
|
||||
errs = append(errs, "kind should be "+KustomizationKind)
|
||||
}
|
||||
return errs
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// KvPairSources defines places to obtain key value pairs.
|
||||
type KvPairSources struct {
|
||||
// LiteralSources is a list of literal
|
||||
// pair sources. Each literal source should
|
||||
// be a key and literal value, e.g. `key=value`
|
||||
LiteralSources []string `json:"literals,omitempty" yaml:"literals,omitempty"`
|
||||
|
||||
// FileSources is a list of file "sources" to
|
||||
// use in creating a list of key, value pairs.
|
||||
// A source takes the form: [{key}=]{path}
|
||||
// If the "key=" part is missing, the key is the
|
||||
// path's basename. If they "key=" part is present,
|
||||
// it becomes the key (replacing the basename).
|
||||
// In either case, the value is the file contents.
|
||||
// Specifying a directory will iterate each named
|
||||
// file in the directory whose basename is a
|
||||
// valid configmap key.
|
||||
FileSources []string `json:"files,omitempty" yaml:"files,omitempty"`
|
||||
|
||||
// EnvSources is a list of file paths.
|
||||
// The contents of each file should be one
|
||||
// key=value pair per line, e.g. a Docker
|
||||
// or npm ".env" file or a ".ini" file
|
||||
// (wikipedia.org/wiki/INI_file)
|
||||
EnvSources []string `json:"envs,omitempty" yaml:"envs,omitempty"`
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Restrictions on what things can be referred to
|
||||
// in a kustomization file.
|
||||
//
|
||||
//go:generate stringer -type=LoadRestrictions
|
||||
type LoadRestrictions int
|
||||
|
||||
const (
|
||||
LoadRestrictionsUnknown LoadRestrictions = iota
|
||||
|
||||
// Files referenced by a kustomization file must be in
|
||||
// or under the directory holding the kustomization
|
||||
// file itself.
|
||||
LoadRestrictionsRootOnly
|
||||
|
||||
// The kustomization file may specify absolute or
|
||||
// relative paths to patch or resources files outside
|
||||
// its own tree.
|
||||
LoadRestrictionsNone
|
||||
)
|
||||
@@ -1,25 +0,0 @@
|
||||
// Code generated by "stringer -type=LoadRestrictions"; DO NOT EDIT.
|
||||
|
||||
package types
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[LoadRestrictionsUnknown-0]
|
||||
_ = x[LoadRestrictionsRootOnly-1]
|
||||
_ = x[LoadRestrictionsNone-2]
|
||||
}
|
||||
|
||||
const _LoadRestrictions_name = "LoadRestrictionsUnknownLoadRestrictionsRootOnlyLoadRestrictionsNone"
|
||||
|
||||
var _LoadRestrictions_index = [...]uint8{0, 23, 47, 67}
|
||||
|
||||
func (i LoadRestrictions) String() string {
|
||||
if i < 0 || i >= LoadRestrictions(len(_LoadRestrictions_index)-1) {
|
||||
return "LoadRestrictions(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _LoadRestrictions_name[_LoadRestrictions_index[i]:_LoadRestrictions_index[i+1]]
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// ObjectMeta partially copies apimachinery/pkg/apis/meta/v1.ObjectMeta
|
||||
// No need for a direct dependence; the fields are stable.
|
||||
type ObjectMeta struct {
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Pair is a key value pair.
|
||||
type Pair struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Patch represent either a Strategic Merge Patch or a JSON patch
|
||||
// and its targets.
|
||||
// The content of the patch can either be from a file
|
||||
// or from an inline string.
|
||||
type Patch struct {
|
||||
// Path is a relative file path to the patch file.
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
|
||||
// Patch is the content of a patch.
|
||||
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
||||
|
||||
// Target points to the resources that the patch is applied to
|
||||
Target *Selector `json:"target,omitempty" yaml:"target,omitempty"`
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// PatchJson6902 represents a json patch for an object
|
||||
// with format documented https://tools.ietf.org/html/rfc6902.
|
||||
type PatchJson6902 struct {
|
||||
// PatchTarget refers to a Kubernetes object that the json patch will be
|
||||
// applied to. It must refer to a Kubernetes resource under the
|
||||
// purview of this kustomization. PatchTarget should use the
|
||||
// raw name of the object (the name specified in its YAML,
|
||||
// before addition of a namePrefix and a nameSuffix).
|
||||
Target *PatchTarget `json:"target" yaml:"target"`
|
||||
|
||||
// relative file path for a json patch file inside a kustomization
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
|
||||
// inline patch string
|
||||
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// PatchStrategicMerge represents a relative path to a
|
||||
// stategic merge patch with the format
|
||||
// https://github.com/kubernetes/community/blob/master/contributors/devel/sig-api-machinery/strategic-merge-patch.md
|
||||
type PatchStrategicMerge string
|
||||
@@ -1,15 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
)
|
||||
|
||||
// PatchTarget represents the kubernetes object that the patch is applied to
|
||||
type PatchTarget struct {
|
||||
resid.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
Name string `json:"name" yaml:"name"`
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// PluginConfig holds plugin configuration.
|
||||
type PluginConfig struct {
|
||||
// AbsPluginHome is the home of kustomize plugins.
|
||||
// Kustomize plugin configuration files are k8s-style objects
|
||||
// containing the fields 'apiVersion' and 'kind', e.g.
|
||||
// apiVersion: apps/v1
|
||||
// kind: Deployment
|
||||
// When kustomize reads a plugin configuration file (as as result
|
||||
// of seeing the file name in the 'generators:' or 'transformers:'
|
||||
// field in a kustomization file), it must then locate the plugin
|
||||
// code (Go plugin or exec plugin).
|
||||
// Every kustomize plugin (its code, its tests, supporting data
|
||||
// files, etc.) must be housed in its own directory at
|
||||
// ${AbsPluginHome}/${pluginApiVersion}/LOWERCASE(${pluginKind})
|
||||
// where
|
||||
// - ${AbsPluginHome} is an absolute path, defined below.
|
||||
// - ${pluginApiVersion} is taken from the plugin config file.
|
||||
// - ${pluginKind} is taken from the plugin config file.
|
||||
// The value of AbsPluginHome can be any absolute path, but might
|
||||
// default to $XDG_CONFIG_HOME/kustomize/plugin.
|
||||
AbsPluginHome string
|
||||
|
||||
// PluginRestrictions defines the plugin restriction state.
|
||||
// See type for more information.
|
||||
PluginRestrictions PluginRestrictions
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Some plugin classes
|
||||
// - builtin: plugins defined in the kustomize repo.
|
||||
// May be freely used and re-configured.
|
||||
// - local: plugins that aren't builtin but are
|
||||
// locally defined (presumably by the user), meaning
|
||||
// the kustomization refers to them via a relative
|
||||
// file path, not a URL.
|
||||
// - remote: require a build-time download to obtain.
|
||||
// Unadvised, unless one controls the
|
||||
// serving site.
|
||||
//
|
||||
//go:generate stringer -type=PluginRestrictions
|
||||
type PluginRestrictions int
|
||||
|
||||
const (
|
||||
PluginRestrictionsUnknown PluginRestrictions = iota
|
||||
|
||||
// Non-builtin plugins completely disabled.
|
||||
PluginRestrictionsBuiltinsOnly
|
||||
|
||||
// No restrictions, do whatever you want.
|
||||
PluginRestrictionsNone
|
||||
)
|
||||
@@ -1,25 +0,0 @@
|
||||
// Code generated by "stringer -type=PluginRestrictions"; DO NOT EDIT.
|
||||
|
||||
package types
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[PluginRestrictionsUnknown-0]
|
||||
_ = x[PluginRestrictionsBuiltinsOnly-1]
|
||||
_ = x[PluginRestrictionsNone-2]
|
||||
}
|
||||
|
||||
const _PluginRestrictions_name = "PluginRestrictionsUnknownPluginRestrictionsBuiltinsOnlyPluginRestrictionsNone"
|
||||
|
||||
var _PluginRestrictions_index = [...]uint8{0, 25, 55, 77}
|
||||
|
||||
func (i PluginRestrictions) String() string {
|
||||
if i < 0 || i >= PluginRestrictions(len(_PluginRestrictions_index)-1) {
|
||||
return "PluginRestrictions(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _PluginRestrictions_name[_PluginRestrictions_index[i]:_PluginRestrictions_index[i+1]]
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Replica specifies a modification to a replica config.
|
||||
// The number of replicas of a resource whose name matches will be set to count.
|
||||
// This struct is used by the ReplicaCountTransform, and is meant to supplement
|
||||
// the existing patch functionality with a simpler syntax for replica configuration.
|
||||
type Replica struct {
|
||||
// The name of the resource to change the replica count
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
|
||||
// The number of replicas required.
|
||||
Count int64 `json:"count" yaml:"count"`
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// SecretArgs contains the metadata of how to generate a secret.
|
||||
type SecretArgs struct {
|
||||
// GeneratorArgs for the secret.
|
||||
GeneratorArgs `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
|
||||
// Type of the secret.
|
||||
//
|
||||
// This is the same field as the secret type field in v1/Secret:
|
||||
// It can be "Opaque" (default), or "kubernetes.io/tls".
|
||||
//
|
||||
// If type is "kubernetes.io/tls", then "literals" or "files" must have exactly two
|
||||
// keys: "tls.key" and "tls.crt"
|
||||
Type string `json:"type,omitempty" yaml:"type,omitempty"`
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
)
|
||||
|
||||
// Selector specifies a set of resources.
|
||||
// Any resource that matches intersection of all conditions
|
||||
// is included in this set.
|
||||
type Selector struct {
|
||||
resid.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
|
||||
// AnnotationSelector is a string that follows the label selection expression
|
||||
// https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
|
||||
// It matches with the resource annotations.
|
||||
AnnotationSelector string `json:"annotationSelector,omitempty" yaml:"annotationSelector,omitempty"`
|
||||
|
||||
// LabelSelector is a string that follows the label selection expression
|
||||
// https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
|
||||
// It matches with the resource labels.
|
||||
LabelSelector string `json:"labelSelector,omitempty" yaml:"labelSelector,omitempty"`
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// TypeMeta partially copies apimachinery/pkg/apis/meta/v1.TypeMeta
|
||||
// No need for a direct dependence; the fields are stable.
|
||||
type TypeMeta struct {
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// The kustomize CLI.
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"sigs.k8s.io/kustomize/kustomize/v3/internal/commands"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/commands"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -1,54 +0,0 @@
|
||||
# Copyright 2019 The Kubernetes Authors.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
run:
|
||||
deadline: 5m
|
||||
|
||||
linters:
|
||||
# please, do not use `enable-all`: it's deprecated and will be removed soon.
|
||||
# inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint
|
||||
disable-all: true
|
||||
enable:
|
||||
- bodyclose
|
||||
- deadcode
|
||||
- depguard
|
||||
- dogsled
|
||||
- dupl
|
||||
# - errcheck
|
||||
# - funlen
|
||||
# - gochecknoinits
|
||||
# - goconst
|
||||
# - gocritic
|
||||
- gocyclo
|
||||
- gofmt
|
||||
- goimports
|
||||
# - golint
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- interfacer
|
||||
# - lll
|
||||
- misspell
|
||||
- nakedret
|
||||
# - scopelint
|
||||
- staticcheck
|
||||
- structcheck
|
||||
# - stylecheck
|
||||
- typecheck
|
||||
- unconvert
|
||||
# - unparam
|
||||
- unused
|
||||
- varcheck
|
||||
# - whitespace
|
||||
|
||||
|
||||
linters-settings:
|
||||
dupl:
|
||||
threshold: 400
|
||||
lll:
|
||||
line-length: 170
|
||||
gocyclo:
|
||||
min-complexity: 30
|
||||
golint:
|
||||
min-confidence: 0.85
|
||||
@@ -1,2 +0,0 @@
|
||||
Copyright {{.Year}} {{.Holder}}
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
@@ -1,38 +0,0 @@
|
||||
# Copyright 2019 The Kubernetes Authors.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
.PHONY: generate license fix vet fmt test build tidy
|
||||
|
||||
GOPATH := $(shell go env GOPATH)
|
||||
|
||||
build:
|
||||
go build -v -o $(GOPATH)/bin/kyaml .
|
||||
|
||||
all: generate license fix vet fmt test lint tidy
|
||||
|
||||
fix:
|
||||
go fix ./...
|
||||
|
||||
fmt:
|
||||
go fmt ./...
|
||||
|
||||
generate:
|
||||
go generate ./...
|
||||
|
||||
license:
|
||||
(which $(GOPATH)/bin/addlicense || go get github.com/google/addlicense)
|
||||
$(GOPATH)/bin/addlicense -y 2019 -c "The Kubernetes Authors." -f LICENSE_TEMPLATE .
|
||||
|
||||
tidy:
|
||||
go mod tidy
|
||||
|
||||
lint:
|
||||
(which $(GOPATH)/bin/golangci-lint || go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.19.1)
|
||||
$(GOPATH)/bin/golangci-lint run ./...
|
||||
|
||||
test:
|
||||
go test -cover ./...
|
||||
|
||||
vet:
|
||||
go vet ./...
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# cmd/kyaml
|
||||
|
||||
This package exists to expose kyaml filters directly as cli commands for the purposes
|
||||
of development of the kyaml package and as a reference implementation for using the libraries.
|
||||
@@ -1,130 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/filters"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
// GetCatRunner returns a command CatRunner.
|
||||
func GetCatRunner() *CatRunner {
|
||||
r := &CatRunner{}
|
||||
c := &cobra.Command{
|
||||
Use: "cat DIR...",
|
||||
Short: "Print Resource Config from a local directory",
|
||||
Long: `Print Resource Config from a local directory.
|
||||
|
||||
DIR:
|
||||
Path to local directory.
|
||||
`,
|
||||
Example: `# print Resource config from a directory
|
||||
kyaml cat my-dir/
|
||||
|
||||
# wrap Resource config from a directory in an ResourceList
|
||||
kyaml cat my-dir/ --wrap-kind ResourceList --wrap-version kyaml.kustomize.dev/v1alpha1 --function-config fn.yaml
|
||||
|
||||
# unwrap Resource config from a directory in an ResourceList
|
||||
... | kyaml cat
|
||||
`,
|
||||
RunE: r.runE,
|
||||
}
|
||||
c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
|
||||
"also print resources from subpackages.")
|
||||
c.Flags().BoolVar(&r.Format, "format", true,
|
||||
"format resource config yaml before printing.")
|
||||
c.Flags().BoolVar(&r.KeepAnnotations, "annotate", false,
|
||||
"annotate resources with their file origins.")
|
||||
c.Flags().StringVar(&r.WrapKind, "wrap-kind", "",
|
||||
"if set, wrap the output in this list type kind.")
|
||||
c.Flags().StringVar(&r.WrapApiVersion, "wrap-version", "",
|
||||
"if set, wrap the output in this list type apiVersion.")
|
||||
c.Flags().StringVar(&r.FunctionConfig, "function-config", "",
|
||||
"path to function config to put in ResourceList -- only if wrapped in a ResourceList.")
|
||||
c.Flags().StringSliceVar(&r.Styles, "style", []string{},
|
||||
"yaml styles to apply. may be 'TaggedStyle', 'DoubleQuotedStyle', 'LiteralStyle', "+
|
||||
"'FoldedStyle', 'FlowStyle'.")
|
||||
c.Flags().BoolVar(&r.StripComments, "strip-comments", false,
|
||||
"remove comments from yaml.")
|
||||
c.Flags().BoolVar(&r.IncludeReconcilers, "include-reconcilers", false,
|
||||
"if true, include reconciler Resources in the output.")
|
||||
c.Flags().BoolVar(&r.ExcludeNonReconcilers, "exclude-non-reconcilers", false,
|
||||
"if true, exclude non-reconciler Resources in the output.")
|
||||
r.Command = c
|
||||
return r
|
||||
}
|
||||
|
||||
func CatCommand() *cobra.Command {
|
||||
return GetCatRunner().Command
|
||||
}
|
||||
|
||||
// CatRunner contains the run function
|
||||
type CatRunner struct {
|
||||
IncludeSubpackages bool
|
||||
Format bool
|
||||
KeepAnnotations bool
|
||||
WrapKind string
|
||||
WrapApiVersion string
|
||||
FunctionConfig string
|
||||
Styles []string
|
||||
StripComments bool
|
||||
IncludeReconcilers bool
|
||||
ExcludeNonReconcilers bool
|
||||
Command *cobra.Command
|
||||
}
|
||||
|
||||
func (r *CatRunner) runE(c *cobra.Command, args []string) error {
|
||||
// if there is a function-config specified, emit it
|
||||
var functionConfig *yaml.RNode
|
||||
if r.FunctionConfig != "" {
|
||||
configs, err := kio.LocalPackageReader{PackagePath: r.FunctionConfig,
|
||||
OmitReaderAnnotations: !r.KeepAnnotations}.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(configs) != 1 {
|
||||
return fmt.Errorf("expected exactly 1 functionConfig, found %d", len(configs))
|
||||
}
|
||||
functionConfig = configs[0]
|
||||
}
|
||||
|
||||
var inputs []kio.Reader
|
||||
for _, a := range args {
|
||||
inputs = append(inputs, kio.LocalPackageReader{
|
||||
PackagePath: a,
|
||||
IncludeSubpackages: r.IncludeSubpackages,
|
||||
})
|
||||
}
|
||||
if len(inputs) == 0 {
|
||||
inputs = append(inputs, &kio.ByteReader{Reader: c.InOrStdin()})
|
||||
}
|
||||
var fltr []kio.Filter
|
||||
// don't include reconcilers
|
||||
fltr = append(fltr, &filters.IsReconcilerFilter{
|
||||
ExcludeReconcilers: !r.IncludeReconcilers,
|
||||
IncludeNonReconcilers: !r.ExcludeNonReconcilers,
|
||||
})
|
||||
if r.Format {
|
||||
fltr = append(fltr, filters.FormatFilter{})
|
||||
}
|
||||
if r.StripComments {
|
||||
fltr = append(fltr, filters.StripCommentsFilter{})
|
||||
}
|
||||
|
||||
var outputs []kio.Writer
|
||||
outputs = append(outputs, kio.ByteWriter{
|
||||
Writer: c.OutOrStdout(),
|
||||
KeepReaderAnnotations: r.KeepAnnotations,
|
||||
WrappingKind: r.WrapKind,
|
||||
WrappingApiVersion: r.WrapApiVersion,
|
||||
FunctionConfig: functionConfig,
|
||||
Style: yaml.GetStyle(r.Styles...),
|
||||
})
|
||||
|
||||
return kio.Pipeline{Inputs: inputs, Filters: fltr, Outputs: outputs}.Execute()
|
||||
}
|
||||
@@ -1,304 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package cmd_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/kustomize/cmd/kyaml/cmd"
|
||||
)
|
||||
|
||||
// TODO(pwittrock): write tests for reading / writing ResourceLists
|
||||
|
||||
func TestCmd_files(t *testing.T) {
|
||||
d, err := ioutil.TempDir("", "kustomize-cat-test")
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
defer os.RemoveAll(d)
|
||||
|
||||
err = ioutil.WriteFile(filepath.Join(d, "f1.yaml"), []byte(`
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx2
|
||||
name: foo
|
||||
annotations:
|
||||
app: nginx2
|
||||
spec:
|
||||
replicas: 1
|
||||
---
|
||||
kind: Service
|
||||
metadata:
|
||||
name: foo
|
||||
annotations:
|
||||
app: nginx
|
||||
spec:
|
||||
selector:
|
||||
app: nginx
|
||||
`), 0600)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
err = ioutil.WriteFile(filepath.Join(d, "f2.yaml"), []byte(`
|
||||
apiVersion: gcr.io/example/image:version
|
||||
kind: Abstraction
|
||||
metadata:
|
||||
name: foo
|
||||
spec:
|
||||
replicas: 3
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
name: bar
|
||||
annotations:
|
||||
app: nginx
|
||||
spec:
|
||||
replicas: 3
|
||||
`), 0600)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
// fmt the files
|
||||
b := &bytes.Buffer{}
|
||||
r := cmd.GetCatRunner()
|
||||
r.Command.SetArgs([]string{d})
|
||||
r.Command.SetOut(b)
|
||||
if !assert.NoError(t, r.Command.Execute()) {
|
||||
return
|
||||
}
|
||||
|
||||
if !assert.Equal(t, `kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx2
|
||||
name: foo
|
||||
annotations:
|
||||
app: nginx2
|
||||
config.kubernetes.io/package: .
|
||||
config.kubernetes.io/path: f1.yaml
|
||||
spec:
|
||||
replicas: 1
|
||||
---
|
||||
kind: Service
|
||||
metadata:
|
||||
name: foo
|
||||
annotations:
|
||||
app: nginx
|
||||
config.kubernetes.io/package: .
|
||||
config.kubernetes.io/path: f1.yaml
|
||||
spec:
|
||||
selector:
|
||||
app: nginx
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: bar
|
||||
labels:
|
||||
app: nginx
|
||||
annotations:
|
||||
app: nginx
|
||||
config.kubernetes.io/package: .
|
||||
config.kubernetes.io/path: f2.yaml
|
||||
spec:
|
||||
replicas: 3
|
||||
`, b.String()) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestCmd_filesWithReconcilers(t *testing.T) {
|
||||
d, err := ioutil.TempDir("", "kustomize-cat-test")
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
defer os.RemoveAll(d)
|
||||
|
||||
err = ioutil.WriteFile(filepath.Join(d, "f1.yaml"), []byte(`
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx2
|
||||
name: foo
|
||||
annotations:
|
||||
app: nginx2
|
||||
spec:
|
||||
replicas: 1
|
||||
---
|
||||
kind: Service
|
||||
metadata:
|
||||
name: foo
|
||||
annotations:
|
||||
app: nginx
|
||||
spec:
|
||||
selector:
|
||||
app: nginx
|
||||
`), 0600)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
err = ioutil.WriteFile(filepath.Join(d, "f2.yaml"), []byte(`
|
||||
apiVersion: gcr.io/example/image:version
|
||||
kind: Abstraction
|
||||
metadata:
|
||||
name: foo
|
||||
spec:
|
||||
replicas: 3
|
||||
---
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
name: bar
|
||||
annotations:
|
||||
app: nginx
|
||||
spec:
|
||||
replicas: 3
|
||||
`), 0600)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
// fmt the files
|
||||
b := &bytes.Buffer{}
|
||||
r := cmd.GetCatRunner()
|
||||
r.Command.SetArgs([]string{d, "--include-reconcilers"})
|
||||
r.Command.SetOut(b)
|
||||
if !assert.NoError(t, r.Command.Execute()) {
|
||||
return
|
||||
}
|
||||
|
||||
if !assert.Equal(t, `kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx2
|
||||
name: foo
|
||||
annotations:
|
||||
app: nginx2
|
||||
config.kubernetes.io/package: .
|
||||
config.kubernetes.io/path: f1.yaml
|
||||
spec:
|
||||
replicas: 1
|
||||
---
|
||||
kind: Service
|
||||
metadata:
|
||||
name: foo
|
||||
annotations:
|
||||
app: nginx
|
||||
config.kubernetes.io/package: .
|
||||
config.kubernetes.io/path: f1.yaml
|
||||
spec:
|
||||
selector:
|
||||
app: nginx
|
||||
---
|
||||
apiVersion: gcr.io/example/image:version
|
||||
kind: Abstraction
|
||||
metadata:
|
||||
name: foo
|
||||
annotations:
|
||||
config.kubernetes.io/package: .
|
||||
config.kubernetes.io/path: f2.yaml
|
||||
spec:
|
||||
replicas: 3
|
||||
---
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
name: bar
|
||||
annotations:
|
||||
app: nginx
|
||||
config.kubernetes.io/package: .
|
||||
config.kubernetes.io/path: f2.yaml
|
||||
spec:
|
||||
replicas: 3
|
||||
`, b.String()) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestCmd_filesWithoutNonReconcilers(t *testing.T) {
|
||||
d, err := ioutil.TempDir("", "kustomize-cat-test")
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
defer os.RemoveAll(d)
|
||||
|
||||
err = ioutil.WriteFile(filepath.Join(d, "f1.yaml"), []byte(`
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx2
|
||||
name: foo
|
||||
annotations:
|
||||
app: nginx2
|
||||
spec:
|
||||
replicas: 1
|
||||
---
|
||||
kind: Service
|
||||
metadata:
|
||||
name: foo
|
||||
annotations:
|
||||
app: nginx
|
||||
spec:
|
||||
selector:
|
||||
app: nginx
|
||||
`), 0600)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
err = ioutil.WriteFile(filepath.Join(d, "f2.yaml"), []byte(`
|
||||
apiVersion: gcr.io/example/image:version
|
||||
kind: Abstraction
|
||||
metadata:
|
||||
name: foo
|
||||
spec:
|
||||
replicas: 3
|
||||
---
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
name: bar
|
||||
annotations:
|
||||
app: nginx
|
||||
spec:
|
||||
replicas: 3
|
||||
`), 0600)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
// fmt the files
|
||||
b := &bytes.Buffer{}
|
||||
r := cmd.GetCatRunner()
|
||||
r.Command.SetArgs([]string{d, "--include-reconcilers", "--exclude-non-reconcilers"})
|
||||
r.Command.SetOut(b)
|
||||
if !assert.NoError(t, r.Command.Execute()) {
|
||||
return
|
||||
}
|
||||
|
||||
if !assert.Equal(t, `apiVersion: gcr.io/example/image:version
|
||||
kind: Abstraction
|
||||
metadata:
|
||||
name: foo
|
||||
annotations:
|
||||
config.kubernetes.io/package: .
|
||||
config.kubernetes.io/path: f2.yaml
|
||||
spec:
|
||||
replicas: 3
|
||||
`, b.String()) {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/sets"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
func GetCountRunner() *CountRunner {
|
||||
r := &CountRunner{}
|
||||
c := &cobra.Command{
|
||||
Use: "count DIR...",
|
||||
Short: "Count Resources Config from a local directory",
|
||||
Long: `Count Resources Config from a local directory.
|
||||
|
||||
DIR:
|
||||
Path to local directory.
|
||||
`,
|
||||
Example: `# print Resource counts from a directory
|
||||
kyaml count my-dir/
|
||||
`,
|
||||
RunE: r.runE,
|
||||
}
|
||||
c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
|
||||
"also print resources from subpackages.")
|
||||
c.Flags().BoolVar(&r.Kind, "kind", true,
|
||||
"count resources by kind.")
|
||||
|
||||
r.Command = c
|
||||
return r
|
||||
}
|
||||
|
||||
func CountCommand() *cobra.Command {
|
||||
return GetCountRunner().Command
|
||||
}
|
||||
|
||||
// CountRunner contains the run function
|
||||
type CountRunner struct {
|
||||
IncludeSubpackages bool
|
||||
Kind bool
|
||||
Command *cobra.Command
|
||||
}
|
||||
|
||||
func (r *CountRunner) runE(c *cobra.Command, args []string) error {
|
||||
var inputs []kio.Reader
|
||||
for _, a := range args {
|
||||
inputs = append(inputs, kio.LocalPackageReader{
|
||||
PackagePath: a,
|
||||
IncludeSubpackages: r.IncludeSubpackages,
|
||||
})
|
||||
}
|
||||
if len(inputs) == 0 {
|
||||
inputs = append(inputs, &kio.ByteReader{Reader: c.InOrStdin()})
|
||||
}
|
||||
|
||||
var out []kio.Writer
|
||||
if r.Kind {
|
||||
out = append(out, kio.WriterFunc(func(nodes []*yaml.RNode) error {
|
||||
count := map[string]int{}
|
||||
k := sets.String{}
|
||||
for _, n := range nodes {
|
||||
m, _ := n.GetMeta()
|
||||
count[m.Kind]++
|
||||
k.Insert(m.Kind)
|
||||
}
|
||||
order := k.List()
|
||||
sort.Strings(order)
|
||||
for _, k := range order {
|
||||
fmt.Fprintf(c.OutOrStdout(), "%s: %d\n", k, count[k])
|
||||
}
|
||||
|
||||
return nil
|
||||
}))
|
||||
|
||||
} else {
|
||||
out = append(out, kio.WriterFunc(func(nodes []*yaml.RNode) error {
|
||||
fmt.Fprintf(c.OutOrStdout(), "%d\n", len(nodes))
|
||||
return nil
|
||||
}))
|
||||
}
|
||||
return kio.Pipeline{
|
||||
Inputs: inputs,
|
||||
Outputs: out,
|
||||
}.Execute()
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package cmd_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/kustomize/cmd/kyaml/cmd"
|
||||
)
|
||||
|
||||
func TestCountCommand_files(t *testing.T) {
|
||||
d, err := ioutil.TempDir("", "kustomize-count-test")
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
defer os.RemoveAll(d)
|
||||
|
||||
err = ioutil.WriteFile(filepath.Join(d, "f1.yaml"), []byte(`
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx2
|
||||
name: foo
|
||||
annotations:
|
||||
app: nginx2
|
||||
spec:
|
||||
replicas: 1
|
||||
---
|
||||
kind: Service
|
||||
metadata:
|
||||
name: foo
|
||||
annotations:
|
||||
app: nginx
|
||||
spec:
|
||||
selector:
|
||||
app: nginx
|
||||
`), 0600)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
err = ioutil.WriteFile(filepath.Join(d, "f2.yaml"), []byte(`kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
name: bar
|
||||
annotations:
|
||||
app: nginx
|
||||
spec:
|
||||
replicas: 3
|
||||
`), 0600)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
// fmt the files
|
||||
b := &bytes.Buffer{}
|
||||
r := cmd.GetCountRunner()
|
||||
r.Command.SetArgs([]string{d})
|
||||
r.Command.SetOut(b)
|
||||
if !assert.NoError(t, r.Command.Execute()) {
|
||||
return
|
||||
}
|
||||
|
||||
if !assert.Equal(t, "Deployment: 2\nService: 1\n", b.String()) {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/filters"
|
||||
)
|
||||
|
||||
// FmtCmd returns a command FmtRunner.
|
||||
func GetFmtRunner() *FmtRunner {
|
||||
r := &FmtRunner{}
|
||||
c := &cobra.Command{
|
||||
Use: "fmt",
|
||||
Short: "Format yaml configuration files",
|
||||
Long: `Format yaml configuration files
|
||||
|
||||
Fmt will format input by ordering fields and unordered list items in Kubernetes
|
||||
objects. Inputs may be directories, files or stdin, and their contents must
|
||||
include both apiVersion and kind fields.
|
||||
|
||||
- Stdin inputs are formatted and written to stdout
|
||||
- File inputs (args) are formatted and written back to the file
|
||||
- Directory inputs (args) are walked, each encountered .yaml and .yml file
|
||||
acts as an input
|
||||
|
||||
For inputs which contain multiple yaml documents separated by \n---\n,
|
||||
each document will be formatted and written back to the file in the original
|
||||
order.
|
||||
|
||||
Field ordering roughly follows the ordering defined in the source Kubernetes
|
||||
resource definitions (i.e. go structures), falling back on lexicographical
|
||||
sorting for unrecognized fields.
|
||||
|
||||
Unordered list item ordering is defined for specific Resource types and
|
||||
field paths.
|
||||
|
||||
- .spec.template.spec.containers (by element name)
|
||||
- .webhooks.rules.operations (by element value)
|
||||
`,
|
||||
Example: `
|
||||
# format file1.yaml and file2.yml
|
||||
kyaml fmt file1.yaml file2.yml
|
||||
|
||||
# format all *.yaml and *.yml recursively traversing directories
|
||||
kyaml fmt my-dir/
|
||||
|
||||
# format kubectl output
|
||||
kubectl get -o yaml deployments | kyaml fmt
|
||||
|
||||
# format kustomize output
|
||||
kustomize build | kyaml fmt
|
||||
`,
|
||||
RunE: r.runE,
|
||||
PreRunE: r.preRunE,
|
||||
}
|
||||
c.Flags().StringVar(&r.FilenamePattern, "pattern", filters.DefaultFilenamePattern,
|
||||
`pattern to use for generating filenames for resources -- may contain the following
|
||||
formatting substitution verbs {'%n': 'metadata.name', '%s': 'metadata.namespace', '%k': 'kind'}`)
|
||||
c.Flags().BoolVar(&r.SetFilenames, "set-filenames", false,
|
||||
`if true, set default filenames on Resources without them`)
|
||||
c.Flags().BoolVar(&r.KeepAnnotations, "keep-annotations", false,
|
||||
`if true, keep index and filename annotations set on Resources.`)
|
||||
c.Flags().BoolVar(&r.Override, "override", false,
|
||||
`if true, override existing filepath annotations.`)
|
||||
r.Command = c
|
||||
return r
|
||||
}
|
||||
|
||||
func FmtCommand() *cobra.Command {
|
||||
return GetFmtRunner().Command
|
||||
}
|
||||
|
||||
// FmtRunner contains the run function
|
||||
type FmtRunner struct {
|
||||
Command *cobra.Command
|
||||
FilenamePattern string
|
||||
SetFilenames bool
|
||||
KeepAnnotations bool
|
||||
Override bool
|
||||
}
|
||||
|
||||
func (r *FmtRunner) preRunE(c *cobra.Command, args []string) error {
|
||||
if r.SetFilenames {
|
||||
r.KeepAnnotations = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *FmtRunner) runE(c *cobra.Command, args []string) error {
|
||||
f := []kio.Filter{filters.FormatFilter{}}
|
||||
|
||||
// format with file names
|
||||
if r.SetFilenames {
|
||||
f = append(f, &filters.FileSetter{
|
||||
FilenamePattern: r.FilenamePattern,
|
||||
Override: r.Override,
|
||||
})
|
||||
}
|
||||
|
||||
// format stdin if there are no args
|
||||
if len(args) == 0 {
|
||||
rw := &kio.ByteReadWriter{
|
||||
Reader: c.InOrStdin(),
|
||||
Writer: c.OutOrStdout(),
|
||||
KeepReaderAnnotations: r.KeepAnnotations,
|
||||
}
|
||||
return kio.Pipeline{
|
||||
Inputs: []kio.Reader{rw}, Filters: f, Outputs: []kio.Writer{rw}}.Execute()
|
||||
}
|
||||
|
||||
for i := range args {
|
||||
path := args[i]
|
||||
rw := &kio.LocalPackageReadWriter{
|
||||
NoDeleteFiles: true,
|
||||
PackagePath: path,
|
||||
KeepReaderAnnotations: r.KeepAnnotations}
|
||||
err := kio.Pipeline{
|
||||
Inputs: []kio.Reader{rw}, Filters: f, Outputs: []kio.Writer{rw}}.Execute()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package cmd_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/kustomize/cmd/kyaml/cmd"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/filters/testyaml"
|
||||
)
|
||||
|
||||
// TestCmd_files verifies the fmt command formats the files
|
||||
func TestFmtCommand_files(t *testing.T) {
|
||||
f1, err := ioutil.TempFile("", "cmdfmt*.yaml")
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
defer os.RemoveAll(f1.Name())
|
||||
err = ioutil.WriteFile(f1.Name(), testyaml.UnformattedYaml1, 0600)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
f2, err := ioutil.TempFile("", "cmdfmt*.yaml")
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
defer os.RemoveAll(f2.Name())
|
||||
err = ioutil.WriteFile(f2.Name(), testyaml.UnformattedYaml2, 0600)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
// fmt the files
|
||||
r := cmd.GetFmtRunner()
|
||||
r.Command.SetArgs([]string{f1.Name(), f2.Name()})
|
||||
err = r.Command.Execute()
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
// verify the contents
|
||||
b, err := ioutil.ReadFile(f1.Name())
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
if !assert.Equal(t, string(testyaml.FormattedYaml1), string(b)) {
|
||||
return
|
||||
}
|
||||
|
||||
b, err = ioutil.ReadFile(f2.Name())
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
if !assert.Equal(t, string(testyaml.FormattedYaml2), string(b)) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestFmtCommand_stdin(t *testing.T) {
|
||||
out := &bytes.Buffer{}
|
||||
r := cmd.GetFmtRunner()
|
||||
r.Command.SetOut(out)
|
||||
r.Command.SetIn(bytes.NewReader(testyaml.UnformattedYaml1))
|
||||
|
||||
// fmt the input
|
||||
err := r.Command.Execute()
|
||||
assert.NoError(t, err)
|
||||
|
||||
// verify the output
|
||||
assert.Equal(t, string(testyaml.FormattedYaml1), out.String())
|
||||
}
|
||||
|
||||
// TestCmd_filesAndstdin verifies that if both files and stdin input are provided, only
|
||||
// the files are formatted and the input is ignored
|
||||
func TestFmtCmd_filesAndStdin(t *testing.T) {
|
||||
f1, err := ioutil.TempFile("", "cmdfmt*.yaml")
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
err = ioutil.WriteFile(f1.Name(), testyaml.UnformattedYaml1, 0600)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
f2, err := ioutil.TempFile("", "cmdfmt*.yaml")
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
err = ioutil.WriteFile(f2.Name(), testyaml.UnformattedYaml2, 0600)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
out := &bytes.Buffer{}
|
||||
in := &bytes.Buffer{}
|
||||
r := cmd.GetFmtRunner()
|
||||
r.Command.SetOut(out)
|
||||
r.Command.SetIn(in)
|
||||
|
||||
// fmt the files
|
||||
r = cmd.GetFmtRunner()
|
||||
r.Command.SetArgs([]string{f1.Name(), f2.Name()})
|
||||
err = r.Command.Execute()
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
// verify the output
|
||||
b, err := ioutil.ReadFile(f1.Name())
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
if !assert.Equal(t, string(testyaml.FormattedYaml1), string(b)) {
|
||||
return
|
||||
}
|
||||
|
||||
b, err = ioutil.ReadFile(f2.Name())
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
if !assert.Equal(t, string(testyaml.FormattedYaml2), string(b)) {
|
||||
return
|
||||
}
|
||||
err = r.Command.Execute()
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
if !assert.Equal(t, "", out.String()) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// TestCmd_files verifies the fmt command formats the files
|
||||
func TestCmd_failFiles(t *testing.T) {
|
||||
// fmt the files
|
||||
r := cmd.GetFmtRunner()
|
||||
r.Command.SetArgs([]string{"notrealfile"})
|
||||
err := r.Command.Execute()
|
||||
assert.EqualError(t, err, "lstat notrealfile: no such file or directory")
|
||||
}
|
||||
|
||||
// TestCmd_files verifies the fmt command formats the files
|
||||
func TestCmd_failFileContents(t *testing.T) {
|
||||
out := &bytes.Buffer{}
|
||||
r := cmd.GetFmtRunner()
|
||||
r.Command.SetOut(out)
|
||||
r.Command.SetIn(strings.NewReader(`{`))
|
||||
|
||||
// fmt the input
|
||||
err := r.Command.Execute()
|
||||
|
||||
// expect an error
|
||||
assert.EqualError(t, err, "yaml: line 1: did not find expected node content")
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/api/resource"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/filters"
|
||||
)
|
||||
|
||||
// Cmd returns a command GrepRunner.
|
||||
func GetGrepRunner() *GrepRunner {
|
||||
r := &GrepRunner{}
|
||||
c := &cobra.Command{
|
||||
Use: "grep QUERY [DIR]...",
|
||||
Short: "Search for matching Resources in a directory or from stdin",
|
||||
Long: `Search for matching Resources in a directory or from stdin.
|
||||
QUERY:
|
||||
Query to match expressed as 'path.to.field=value'.
|
||||
Maps and fields are matched as '.field-name' or '.map-key'
|
||||
List elements are matched as '[list-elem-field=field-value]'
|
||||
The value to match is expressed as '=value'
|
||||
'.' as part of a key or value can be escaped as '\.'
|
||||
|
||||
DIR:
|
||||
Path to local directory.
|
||||
`,
|
||||
Example: `# find Deployment Resources
|
||||
kyaml grep "kind=Deployment" my-dir/
|
||||
|
||||
# find Resources named nginx
|
||||
kyaml grep "metadata.name=nginx" my-dir/
|
||||
|
||||
# use tree to display matching Resources
|
||||
kyaml grep "metadata.name=nginx" my-dir/ | kyaml tree
|
||||
|
||||
# look for Resources matching a specific container image
|
||||
kyaml grep "spec.template.spec.containers[name=nginx].image=nginx:1\.7\.9" my-dir/ | kyaml tree
|
||||
`,
|
||||
PreRunE: r.preRunE,
|
||||
RunE: r.runE,
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
}
|
||||
c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
|
||||
"also print resources from subpackages.")
|
||||
c.Flags().BoolVar(&r.KeepAnnotations, "annotate", true,
|
||||
"annotate resources with their file origins.")
|
||||
c.Flags().BoolVarP(&r.InvertMatch, "invert-match", "v", false,
|
||||
" Selected Resources are those not matching any of the specified patterns..")
|
||||
|
||||
r.Command = c
|
||||
return r
|
||||
}
|
||||
|
||||
func GrepCommand() *cobra.Command {
|
||||
return GetGrepRunner().Command
|
||||
}
|
||||
|
||||
// GrepRunner contains the run function
|
||||
type GrepRunner struct {
|
||||
IncludeSubpackages bool
|
||||
KeepAnnotations bool
|
||||
Command *cobra.Command
|
||||
filters.GrepFilter
|
||||
Format bool
|
||||
}
|
||||
|
||||
func (r *GrepRunner) preRunE(c *cobra.Command, args []string) error {
|
||||
r.GrepFilter.Compare = func(a, b string) (int, error) {
|
||||
qa, err := resource.ParseQuantity(a)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("%s: %v", a, err)
|
||||
}
|
||||
qb, err := resource.ParseQuantity(b)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return qa.Cmp(qb), err
|
||||
}
|
||||
parts, err := parseFieldPath(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var last []string
|
||||
if strings.Contains(parts[len(parts)-1], ">=") {
|
||||
last = strings.Split(parts[len(parts)-1], ">=")
|
||||
r.MatchType = filters.GreaterThanEq
|
||||
} else if strings.Contains(parts[len(parts)-1], "<=") {
|
||||
last = strings.Split(parts[len(parts)-1], "<=")
|
||||
r.MatchType = filters.LessThanEq
|
||||
} else if strings.Contains(parts[len(parts)-1], ">") {
|
||||
last = strings.Split(parts[len(parts)-1], ">")
|
||||
r.MatchType = filters.GreaterThan
|
||||
} else if strings.Contains(parts[len(parts)-1], "<") {
|
||||
last = strings.Split(parts[len(parts)-1], "<")
|
||||
r.MatchType = filters.LessThan
|
||||
} else {
|
||||
last = strings.Split(parts[len(parts)-1], "=")
|
||||
r.MatchType = filters.Regexp
|
||||
}
|
||||
if len(last) > 2 {
|
||||
return fmt.Errorf(
|
||||
"ambiguous match -- multiple of ['<', '>', '<=', '>=', '=' in final path element: %s",
|
||||
parts[len(parts)-1])
|
||||
}
|
||||
|
||||
if len(last) > 1 {
|
||||
r.Value = last[1]
|
||||
}
|
||||
|
||||
r.Path = append(parts[:len(parts)-1], last[0])
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *GrepRunner) runE(c *cobra.Command, args []string) error {
|
||||
var filters = []kio.Filter{r.GrepFilter}
|
||||
|
||||
var inputs []kio.Reader
|
||||
for _, a := range args[1:] {
|
||||
inputs = append(inputs, kio.LocalPackageReader{
|
||||
PackagePath: a,
|
||||
IncludeSubpackages: r.IncludeSubpackages,
|
||||
})
|
||||
}
|
||||
if len(inputs) == 0 {
|
||||
inputs = append(inputs, &kio.ByteReader{Reader: c.InOrStdin()})
|
||||
}
|
||||
|
||||
return kio.Pipeline{
|
||||
Inputs: inputs,
|
||||
Filters: filters,
|
||||
Outputs: []kio.Writer{kio.ByteWriter{
|
||||
Writer: c.OutOrStdout(),
|
||||
KeepReaderAnnotations: r.KeepAnnotations,
|
||||
}},
|
||||
}.Execute()
|
||||
}
|
||||
@@ -1,272 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package cmd_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/kustomize/cmd/kyaml/cmd"
|
||||
)
|
||||
|
||||
// TestGrepCommand_files verifies grep reads the files and filters them
|
||||
func TestGrepCommand_files(t *testing.T) {
|
||||
d, err := ioutil.TempDir("", "kustomize-kyaml-test")
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
defer os.RemoveAll(d)
|
||||
|
||||
err = ioutil.WriteFile(filepath.Join(d, "f1.yaml"), []byte(`
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx2
|
||||
name: foo
|
||||
annotations:
|
||||
app: nginx2
|
||||
spec:
|
||||
replicas: 1
|
||||
---
|
||||
kind: Service
|
||||
metadata:
|
||||
name: foo
|
||||
annotations:
|
||||
app: nginx
|
||||
spec:
|
||||
selector:
|
||||
app: nginx
|
||||
`), 0600)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
err = ioutil.WriteFile(filepath.Join(d, "f2.yaml"), []byte(`kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
name: bar
|
||||
annotations:
|
||||
app: nginx
|
||||
spec:
|
||||
replicas: 3
|
||||
`), 0600)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
// fmt the files
|
||||
b := &bytes.Buffer{}
|
||||
r := cmd.GetGrepRunner()
|
||||
r.Command.SetArgs([]string{"metadata.name=foo", d})
|
||||
r.Command.SetOut(b)
|
||||
if !assert.NoError(t, r.Command.Execute()) {
|
||||
return
|
||||
}
|
||||
|
||||
if !assert.Equal(t, `kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx2
|
||||
name: foo
|
||||
annotations:
|
||||
app: nginx2
|
||||
config.kubernetes.io/index: 0
|
||||
config.kubernetes.io/package: .
|
||||
config.kubernetes.io/path: f1.yaml
|
||||
spec:
|
||||
replicas: 1
|
||||
---
|
||||
kind: Service
|
||||
metadata:
|
||||
name: foo
|
||||
annotations:
|
||||
app: nginx
|
||||
config.kubernetes.io/index: 1
|
||||
config.kubernetes.io/package: .
|
||||
config.kubernetes.io/path: f1.yaml
|
||||
spec:
|
||||
selector:
|
||||
app: nginx
|
||||
`, b.String()) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// TestCmd_stdin verifies the grep command reads stdin if no files are provided
|
||||
func TestGrepCmd_stdin(t *testing.T) {
|
||||
// fmt the files
|
||||
b := &bytes.Buffer{}
|
||||
r := cmd.GetGrepRunner()
|
||||
r.Command.SetArgs([]string{"metadata.name=foo"})
|
||||
r.Command.SetOut(b)
|
||||
r.Command.SetIn(bytes.NewBufferString(`
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx2
|
||||
name: foo
|
||||
annotations:
|
||||
app: nginx2
|
||||
spec:
|
||||
replicas: 1
|
||||
---
|
||||
kind: Service
|
||||
metadata:
|
||||
name: foo
|
||||
annotations:
|
||||
app: nginx
|
||||
spec:
|
||||
selector:
|
||||
app: nginx
|
||||
---
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
name: bar
|
||||
annotations:
|
||||
app: nginx
|
||||
spec:
|
||||
replicas: 3
|
||||
`))
|
||||
if !assert.NoError(t, r.Command.Execute()) {
|
||||
return
|
||||
}
|
||||
|
||||
if !assert.Equal(t, `kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx2
|
||||
name: foo
|
||||
annotations:
|
||||
app: nginx2
|
||||
config.kubernetes.io/index: 0
|
||||
spec:
|
||||
replicas: 1
|
||||
---
|
||||
kind: Service
|
||||
metadata:
|
||||
name: foo
|
||||
annotations:
|
||||
app: nginx
|
||||
config.kubernetes.io/index: 1
|
||||
spec:
|
||||
selector:
|
||||
app: nginx
|
||||
`, b.String()) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// TestGrepCmd_errInputs verifies the grep command errors on invalid matches
|
||||
func TestGrepCmd_errInputs(t *testing.T) {
|
||||
b := &bytes.Buffer{}
|
||||
r := cmd.GetGrepRunner()
|
||||
r.Command.SetArgs([]string{"metadata.name=foo=bar"})
|
||||
r.Command.SetOut(b)
|
||||
r.Command.SetIn(bytes.NewBufferString(`
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx2
|
||||
name: foo
|
||||
annotations:
|
||||
app: nginx2
|
||||
spec:
|
||||
replicas: 1
|
||||
`))
|
||||
err := r.Command.Execute()
|
||||
if !assert.Error(t, err) {
|
||||
return
|
||||
}
|
||||
assert.Contains(t, err.Error(), "ambiguous match")
|
||||
|
||||
// fmt the files
|
||||
b = &bytes.Buffer{}
|
||||
r = cmd.GetGrepRunner()
|
||||
r.Command.SetArgs([]string{"spec.template.spec.containers[a[b=c].image=foo"})
|
||||
r.Command.SetOut(b)
|
||||
r.Command.SetIn(bytes.NewBufferString(`
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx2
|
||||
name: foo
|
||||
annotations:
|
||||
app: nginx2
|
||||
spec:
|
||||
replicas: 1
|
||||
`))
|
||||
err = r.Command.Execute()
|
||||
if !assert.Error(t, err) {
|
||||
return
|
||||
}
|
||||
assert.Contains(t, err.Error(), "unrecognized path element:")
|
||||
}
|
||||
|
||||
// TestGrepCommand_escapeDots verifies the grep command correctly escapes '\.' in inputs
|
||||
func TestGrepCommand_escapeDots(t *testing.T) {
|
||||
// fmt the files
|
||||
b := &bytes.Buffer{}
|
||||
r := cmd.GetGrepRunner()
|
||||
r.Command.SetArgs([]string{"spec.template.spec.containers[name=nginx].image=nginx:1\\.7\\.9",
|
||||
"--annotate=false"})
|
||||
r.Command.SetOut(b)
|
||||
r.Command.SetIn(bytes.NewBufferString(`
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx1.8
|
||||
name: nginx1.8
|
||||
annotations:
|
||||
app: nginx1.8
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.8.1
|
||||
---
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx1.7
|
||||
name: nginx1.7
|
||||
annotations:
|
||||
app: nginx1.7
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.7.9
|
||||
`))
|
||||
err := r.Command.Execute()
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
if !assert.Equal(t, `kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx1.7
|
||||
name: nginx1.7
|
||||
annotations:
|
||||
app: nginx1.7
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.7.9
|
||||
`, b.String()) {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/filters"
|
||||
)
|
||||
|
||||
func GetMergeRunner() *MergeRunner {
|
||||
r := &MergeRunner{}
|
||||
c := &cobra.Command{
|
||||
Use: "merge [SOURCE_DIR...] [DESTINATION_DIR]",
|
||||
Short: "Merge Resource configuration files",
|
||||
Long: `Merge Resource configuration files
|
||||
|
||||
Merge reads Kubernetes Resource yaml configuration files from stdin or sources packages and write
|
||||
the result to stdout or a destination package.
|
||||
|
||||
Resources are merged using the Resource [apiVersion, kind, name, namespace] as the key. If any of
|
||||
these are missing, merge will default the missing values to empty.
|
||||
|
||||
Resources specified later are high-precedence (the source) and Resources specified
|
||||
earlier are lower-precedence (the destination).
|
||||
|
||||
For information on merge rules, run:
|
||||
|
||||
kyaml help merge
|
||||
`,
|
||||
Example: `cat resources_and_patches.yaml | kyaml merge > merged_resources.yaml`,
|
||||
RunE: r.runE,
|
||||
}
|
||||
r.Command = c
|
||||
r.Command.Flags().BoolVar(&r.InvertOrder, "invert-order", false,
|
||||
"if true, merge Resources in the reverse order")
|
||||
return r
|
||||
}
|
||||
|
||||
func MergeCommand() *cobra.Command {
|
||||
return GetMergeRunner().Command
|
||||
}
|
||||
|
||||
// MergeRunner contains the run function
|
||||
type MergeRunner struct {
|
||||
Command *cobra.Command
|
||||
InvertOrder bool
|
||||
}
|
||||
|
||||
func (r *MergeRunner) runE(c *cobra.Command, args []string) error {
|
||||
var inputs []kio.Reader
|
||||
// add the packages in reverse order -- the arg list should be highest precedence first
|
||||
// e.g. merge from -> to, but the MergeFilter is highest precedence last
|
||||
for i := len(args) - 1; i >= 0; i-- {
|
||||
inputs = append(inputs, kio.LocalPackageReader{PackagePath: args[i]})
|
||||
}
|
||||
// if there is no "from" package, read from stdin
|
||||
rw := &kio.ByteReadWriter{
|
||||
Reader: c.InOrStdin(),
|
||||
Writer: c.OutOrStdout(),
|
||||
KeepReaderAnnotations: true,
|
||||
}
|
||||
if len(inputs) < 2 {
|
||||
inputs = append(inputs, rw)
|
||||
}
|
||||
|
||||
// write to the "to" package if specified
|
||||
var outputs []kio.Writer
|
||||
if len(args) != 0 {
|
||||
outputs = append(outputs, kio.LocalPackageWriter{PackagePath: args[len(args)-1]})
|
||||
}
|
||||
// if there is no "to" package, write to stdout
|
||||
if len(outputs) == 0 {
|
||||
outputs = append(outputs, rw)
|
||||
}
|
||||
|
||||
filters := []kio.Filter{filters.MergeFilter{}, filters.FormatFilter{}}
|
||||
return kio.Pipeline{Inputs: inputs, Filters: filters, Outputs: outputs}.Execute()
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user