mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-12 01:14:22 +00:00
Merge branch 'master' into transformer-no-create-arrays
This commit is contained in:
@@ -27,7 +27,7 @@ env:
|
|||||||
- GOLANGCI_RELEASE="v1.12"
|
- GOLANGCI_RELEASE="v1.12"
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- source ./bin/consider-early-travis-exit.sh
|
- source ./travis/consider-early-travis-exit.sh
|
||||||
- curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $GOPATH/bin ${GOLANGCI_RELEASE}
|
- curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $GOPATH/bin ${GOLANGCI_RELEASE}
|
||||||
- go get -u github.com/monopole/mdrip
|
- go get -u github.com/monopole/mdrip
|
||||||
# The following would install Helm if needed for some reason.
|
# The following would install Helm if needed for some reason.
|
||||||
@@ -39,7 +39,7 @@ before_install:
|
|||||||
install: true
|
install: true
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- ./bin/pre-commit.sh
|
- ./travis/pre-commit.sh
|
||||||
|
|
||||||
# TBD. Suppressing for now.
|
# TBD. Suppressing for now.
|
||||||
notifications:
|
notifications:
|
||||||
|
|||||||
@@ -1,23 +1,8 @@
|
|||||||
# Copyright 2018 The Kubernetes Authors.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
# TODO(droot): add instructions for running in production.
|
|
||||||
steps:
|
steps:
|
||||||
- name: "gcr.io/cloud-builders/git"
|
- name: "gcr.io/cloud-builders/git"
|
||||||
args: [fetch, --tags, --depth=100]
|
args: [fetch, --tags, --depth=100]
|
||||||
- name: "gcr.io/kustomize-199618/golang_with_goreleaser:1.10-stretch"
|
- name: "gcr.io/kustomize-199618/golang_with_goreleaser:1.10-stretch"
|
||||||
args: ["bash", "build/build.sh"]
|
args: ["bash", "build/cloudbuild.sh"]
|
||||||
secretEnv: ['GITHUB_TOKEN']
|
secretEnv: ['GITHUB_TOKEN']
|
||||||
secrets:
|
secrets:
|
||||||
- kmsKeyName: projects/kustomize-199618/locations/global/keyRings/github-tokens/cryptoKeys/gh-release-token
|
- kmsKeyName: projects/kustomize-199618/locations/global/keyRings/github-tokens/cryptoKeys/gh-release-token
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
# Copyright 2018 The Kubernetes Authors.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
# Instructions to run locally:
|
|
||||||
# Download google container builder: https://github.com/kubernetes-sigs/container-builder-local
|
|
||||||
# Set you GOOS and GOARCH vars to match your system
|
|
||||||
# Set OUTPUT to the location to write the directory containing the tar.gz
|
|
||||||
# $ container-builder-local --config=build/cloudbuild_local.yaml --dryrun=false \
|
|
||||||
# --substitutions=_GOOS=$GOOS,_GOARCH=$GOARCH --write-workspace=$OUTPUT .
|
|
||||||
# Release tar will be in $OUTPUT
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: "gcr.io/kustomize-199618/golang_with_goreleaser:1.10-stretch"
|
|
||||||
args: ["bash", "build/build.sh", "--snapshot"]
|
|
||||||
secretEnv: ['GITHUB_TOKEN']
|
|
||||||
secrets:
|
|
||||||
- kmsKeyName: projects/kustomize-199618/locations/global/keyRings/github-tokens/cryptoKeys/gh-release-token
|
|
||||||
secretEnv:
|
|
||||||
GITHUB_TOKEN: CiQAyrREbPgXJOeT7M3t+WlxkhXwlMPudixBeiyWTjmLOMLqdK4SUQA0W+xUmDJKAhyfHCcwqSEzUn9OwKC7XAYcmwe0CCKTCbPbDgmioDK24q3LVapndXNvnnHvCjhOJNEr1o+P1DCF+LlzYV2YL8lP09rrKrslPg==
|
|
||||||
67
build/localbuild.sh
Executable file
67
build/localbuild.sh
Executable file
@@ -0,0 +1,67 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
#
|
||||||
|
# ./build/localbuild.sh
|
||||||
|
#
|
||||||
|
# The script attempts to use cloudbuild configuration
|
||||||
|
# to create a release "locally".
|
||||||
|
#
|
||||||
|
# At the time of writing,
|
||||||
|
#
|
||||||
|
# https://pantheon.corp.google.com/cloud-build/triggers?project=kustomize-199618
|
||||||
|
#
|
||||||
|
# has a trigger such that whenever a git tag is
|
||||||
|
# applied to the kustomize repo, the cloud builder
|
||||||
|
# reads the repository-relative file
|
||||||
|
#
|
||||||
|
# build/cloudbuild.yaml
|
||||||
|
#
|
||||||
|
# Inside this yaml file is a reference to the script
|
||||||
|
#
|
||||||
|
# build/cloudbuild.sh
|
||||||
|
#
|
||||||
|
# The script you are reading now does something
|
||||||
|
# analogous via docker tricks.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
# set -x
|
||||||
|
|
||||||
|
if [ -z ${GOPATH+x} ]; then
|
||||||
|
echo GOPATH is unset; cannot proceed.
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
WORK=$(mktemp -d)
|
||||||
|
|
||||||
|
pushd $GOPATH/src/sigs.k8s.io/kustomize
|
||||||
|
pwd
|
||||||
|
|
||||||
|
echo "Building in $WORK"
|
||||||
|
|
||||||
|
cat <<EOF >/tmp/localbuild.yaml
|
||||||
|
steps:
|
||||||
|
- name: "gcr.io/kustomize-199618/golang_with_goreleaser:1.10-stretch"
|
||||||
|
args: ["bash", "build/cloudbuild.sh", "--snapshot"]
|
||||||
|
secretEnv: ['GITHUB_TOKEN']
|
||||||
|
secrets:
|
||||||
|
- kmsKeyName: projects/kustomize-199618/locations/global/keyRings/github-tokens/cryptoKeys/gh-release-token
|
||||||
|
secretEnv:
|
||||||
|
GITHUB_TOKEN: CiQAyrREbPgXJOeT7M3t+WlxkhXwlMPudixBeiyWTjmLOMLqdK4SUQA0W+xUmDJKAhyfHCcwqSEzUn9OwKC7XAYcmwe0CCKTCbPbDgmioDK24q3LVapndXNvnnHvCjhOJNEr1o+P1DCF+LlzYV2YL8lP09rrKrslPg==
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# --substitutions=_GOOS=linux,_GOARCH=amd64
|
||||||
|
|
||||||
|
config=build/cloudbuild.yaml
|
||||||
|
config=/tmp/localbuild.yaml
|
||||||
|
|
||||||
|
# See https://cloud.google.com/cloud-build/docs/build-debug-locally
|
||||||
|
cloud-build-local \
|
||||||
|
--config=$config \
|
||||||
|
--dryrun=false \
|
||||||
|
--write-workspace=$WORK \
|
||||||
|
.
|
||||||
|
|
||||||
|
tree $WORK
|
||||||
|
|
||||||
|
popd
|
||||||
@@ -26,12 +26,12 @@ func NewFactoryImpl() *FactoryImpl {
|
|||||||
func (p *FactoryImpl) MakePatchTransformer(
|
func (p *FactoryImpl) MakePatchTransformer(
|
||||||
slice []*resource.Resource,
|
slice []*resource.Resource,
|
||||||
rf *resource.Factory) (transformers.Transformer, error) {
|
rf *resource.Factory) (transformers.Transformer, error) {
|
||||||
return patch.NewPatchTransformer(slice, rf)
|
return patch.NewTransformer(slice, rf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeHashTransformer makes a new name hash transformer
|
// MakeHashTransformer makes a new name hash transformer
|
||||||
func (p *FactoryImpl) MakeHashTransformer() transformers.Transformer {
|
func (p *FactoryImpl) MakeHashTransformer() transformers.Transformer {
|
||||||
return hash.NewNameHashTransformer()
|
return hash.NewTransformer()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *FactoryImpl) MakeInventoryTransformer(
|
func (p *FactoryImpl) MakeInventoryTransformer(
|
||||||
@@ -39,5 +39,5 @@ func (p *FactoryImpl) MakeInventoryTransformer(
|
|||||||
ldr ifc.Loader,
|
ldr ifc.Loader,
|
||||||
namespace string,
|
namespace string,
|
||||||
gp types.GarbagePolicy) transformers.Transformer {
|
gp types.GarbagePolicy) transformers.Transformer {
|
||||||
return inventory.NewInventoryTransformer(arg, ldr, namespace, gp)
|
return inventory.NewTransformer(arg, ldr, namespace, gp)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,184 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hash
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
||||||
)
|
|
||||||
|
|
||||||
// KustHash compute hash for unstructured objects
|
|
||||||
type KustHash struct{}
|
|
||||||
|
|
||||||
// NewKustHash returns a KustHash object
|
|
||||||
func NewKustHash() *KustHash {
|
|
||||||
return &KustHash{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash returns a hash of either a ConfigMap or a Secret
|
|
||||||
func (h *KustHash) Hash(m map[string]interface{}) (string, error) {
|
|
||||||
u := unstructured.Unstructured{
|
|
||||||
Object: m,
|
|
||||||
}
|
|
||||||
kind := u.GetKind()
|
|
||||||
switch kind {
|
|
||||||
case "ConfigMap":
|
|
||||||
cm, err := unstructuredToConfigmap(u)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return ConfigMapHash(cm)
|
|
||||||
case "Secret":
|
|
||||||
sec, err := unstructuredToSecret(u)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return SecretHash(sec)
|
|
||||||
default:
|
|
||||||
return "", fmt.Errorf("type %s is supported for hashing in %v", kind, m)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConfigMapHash returns a hash of the ConfigMap.
|
|
||||||
// The Data, Kind, and Name are taken into account.
|
|
||||||
func ConfigMapHash(cm *v1.ConfigMap) (string, error) {
|
|
||||||
encoded, err := encodeConfigMap(cm)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
h, err := encodeHash(hash(encoded))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return h, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SecretHash returns a hash of the Secret.
|
|
||||||
// The Data, Kind, Name, and Type are taken into account.
|
|
||||||
func SecretHash(sec *v1.Secret) (string, error) {
|
|
||||||
encoded, err := encodeSecret(sec)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
h, err := encodeHash(hash(encoded))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return h, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SortArrayAndComputeHash sorts a string array and
|
|
||||||
// returns a hash for it
|
|
||||||
func SortArrayAndComputeHash(s []string) (string, error) {
|
|
||||||
sort.Strings(s)
|
|
||||||
data, err := json.Marshal(s)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
h, err := encodeHash(hash(string(data)))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return h, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// encodeConfigMap encodes a ConfigMap.
|
|
||||||
// Data, Kind, and Name are taken into account.
|
|
||||||
func encodeConfigMap(cm *v1.ConfigMap) (string, error) {
|
|
||||||
// json.Marshal sorts the keys in a stable order in the encoding
|
|
||||||
m := map[string]interface{}{"kind": "ConfigMap", "name": cm.Name, "data": cm.Data}
|
|
||||||
if len(cm.BinaryData) > 0 {
|
|
||||||
m["binaryData"] = cm.BinaryData
|
|
||||||
}
|
|
||||||
data, err := json.Marshal(m)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return string(data), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// encodeSecret encodes a Secret.
|
|
||||||
// Data, Kind, Name, and Type are taken into account.
|
|
||||||
func encodeSecret(sec *v1.Secret) (string, error) {
|
|
||||||
// json.Marshal sorts the keys in a stable order in the encoding
|
|
||||||
data, err := json.Marshal(map[string]interface{}{"kind": "Secret", "type": sec.Type, "name": sec.Name, "data": sec.Data})
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return string(data), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// encodeHash extracts the first 40 bits of the hash from the hex string
|
|
||||||
// (1 hex char represents 4 bits), and then maps vowels and vowel-like hex
|
|
||||||
// characters to consonants to prevent bad words from being formed (the theory
|
|
||||||
// is that no vowels makes it really hard to make bad words). Since the string
|
|
||||||
// is hex, the only vowels it can contain are 'a' and 'e'.
|
|
||||||
// We picked some arbitrary consonants to map to from the same character set as GenerateName.
|
|
||||||
// See: https://github.com/kubernetes/apimachinery/blob/dc1f89aff9a7509782bde3b68824c8043a3e58cc/pkg/util/rand/rand.go#L75
|
|
||||||
// If the hex string contains fewer than ten characters, returns an error.
|
|
||||||
func encodeHash(hex string) (string, error) {
|
|
||||||
if len(hex) < 10 {
|
|
||||||
return "", fmt.Errorf("the hex string must contain at least 10 characters")
|
|
||||||
}
|
|
||||||
enc := []rune(hex[:10])
|
|
||||||
for i := range enc {
|
|
||||||
switch enc[i] {
|
|
||||||
case '0':
|
|
||||||
enc[i] = 'g'
|
|
||||||
case '1':
|
|
||||||
enc[i] = 'h'
|
|
||||||
case '3':
|
|
||||||
enc[i] = 'k'
|
|
||||||
case 'a':
|
|
||||||
enc[i] = 'm'
|
|
||||||
case 'e':
|
|
||||||
enc[i] = 't'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return string(enc), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// hash hashes `data` with sha256 and returns the hex string
|
|
||||||
func hash(data string) string {
|
|
||||||
return fmt.Sprintf("%x", sha256.Sum256([]byte(data)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func unstructuredToConfigmap(u unstructured.Unstructured) (*v1.ConfigMap, error) {
|
|
||||||
marshaled, err := json.Marshal(u.Object)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var out v1.ConfigMap
|
|
||||||
err = json.Unmarshal(marshaled, &out)
|
|
||||||
return &out, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func unstructuredToSecret(u unstructured.Unstructured) (*v1.Secret, error) {
|
|
||||||
marshaled, err := json.Marshal(u.Object)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var out v1.Secret
|
|
||||||
err = json.Unmarshal(marshaled, &out)
|
|
||||||
return &out, err
|
|
||||||
}
|
|
||||||
121
k8sdeps/transformer/hash/kusthash.go
Normal file
121
k8sdeps/transformer/hash/kusthash.go
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package hash
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/hasher"
|
||||||
|
)
|
||||||
|
|
||||||
|
// kustHash computes a hash of an unstructured object.
|
||||||
|
type kustHash struct{}
|
||||||
|
|
||||||
|
// NewKustHash returns a kustHash object
|
||||||
|
func NewKustHash() *kustHash {
|
||||||
|
return &kustHash{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash returns a hash of either a ConfigMap or a Secret
|
||||||
|
func (h *kustHash) Hash(m map[string]interface{}) (string, error) {
|
||||||
|
u := unstructured.Unstructured{
|
||||||
|
Object: m,
|
||||||
|
}
|
||||||
|
kind := u.GetKind()
|
||||||
|
switch kind {
|
||||||
|
case "ConfigMap":
|
||||||
|
cm, err := unstructuredToConfigmap(u)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return configMapHash(cm)
|
||||||
|
case "Secret":
|
||||||
|
sec, err := unstructuredToSecret(u)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return secretHash(sec)
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf(
|
||||||
|
"type %s is not supported for hashing in %v", kind, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// configMapHash returns a hash of the ConfigMap.
|
||||||
|
// The Data, Kind, and Name are taken into account.
|
||||||
|
func configMapHash(cm *v1.ConfigMap) (string, error) {
|
||||||
|
encoded, err := encodeConfigMap(cm)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
h, err := hasher.Encode(hasher.Hash(encoded))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return h, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecretHash returns a hash of the Secret.
|
||||||
|
// The Data, Kind, Name, and Type are taken into account.
|
||||||
|
func secretHash(sec *v1.Secret) (string, error) {
|
||||||
|
encoded, err := encodeSecret(sec)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
h, err := hasher.Encode(hasher.Hash(encoded))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return h, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeConfigMap encodes a ConfigMap.
|
||||||
|
// Data, Kind, and Name are taken into account.
|
||||||
|
func encodeConfigMap(cm *v1.ConfigMap) (string, error) {
|
||||||
|
// json.Marshal sorts the keys in a stable order in the encoding
|
||||||
|
m := map[string]interface{}{"kind": "ConfigMap", "name": cm.Name, "data": cm.Data}
|
||||||
|
if len(cm.BinaryData) > 0 {
|
||||||
|
m["binaryData"] = cm.BinaryData
|
||||||
|
}
|
||||||
|
data, err := json.Marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(data), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeSecret encodes a Secret.
|
||||||
|
// Data, Kind, Name, and Type are taken into account.
|
||||||
|
func encodeSecret(sec *v1.Secret) (string, error) {
|
||||||
|
// json.Marshal sorts the keys in a stable order in the encoding
|
||||||
|
data, err := json.Marshal(map[string]interface{}{"kind": "Secret", "type": sec.Type, "name": sec.Name, "data": sec.Data})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(data), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unstructuredToConfigmap(u unstructured.Unstructured) (*v1.ConfigMap, error) {
|
||||||
|
marshaled, err := json.Marshal(u.Object)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var out v1.ConfigMap
|
||||||
|
err = json.Unmarshal(marshaled, &out)
|
||||||
|
return &out, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func unstructuredToSecret(u unstructured.Unstructured) (*v1.Secret, error) {
|
||||||
|
marshaled, err := json.Marshal(u.Object)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var out v1.Secret
|
||||||
|
err = json.Unmarshal(marshaled, &out)
|
||||||
|
return &out, err
|
||||||
|
}
|
||||||
@@ -1,18 +1,5 @@
|
|||||||
/*
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
Copyright 2017 The Kubernetes Authors.
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hash
|
package hash
|
||||||
|
|
||||||
@@ -54,7 +41,7 @@ func TestConfigMapHash(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
h, err := ConfigMapHash(c.cm)
|
h, err := configMapHash(c.cm)
|
||||||
if SkipRest(t, c.desc, err, c.err) {
|
if SkipRest(t, c.desc, err, c.err) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -80,7 +67,7 @@ func TestSecretHash(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
h, err := SecretHash(c.secret)
|
h, err := secretHash(c.secret)
|
||||||
if SkipRest(t, c.desc, err, c.err) {
|
if SkipRest(t, c.desc, err, c.err) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -90,28 +77,6 @@ func TestSecretHash(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestArrayHash(t *testing.T) {
|
|
||||||
array1 := []string{"a", "b", "c"}
|
|
||||||
array2 := []string{"c", "b", "a"}
|
|
||||||
h1, err := SortArrayAndComputeHash(array1)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error %v", err)
|
|
||||||
}
|
|
||||||
if h1 == "" {
|
|
||||||
t.Errorf("failed to hash %v", array1)
|
|
||||||
}
|
|
||||||
h2, err := SortArrayAndComputeHash(array2)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error %v", err)
|
|
||||||
}
|
|
||||||
if h2 == "" {
|
|
||||||
t.Errorf("failed to hash %v", array2)
|
|
||||||
}
|
|
||||||
if h1 != h2 {
|
|
||||||
t.Errorf("hash is not consistent with reordered list: %s %s", h1, h2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEncodeConfigMap(t *testing.T) {
|
func TestEncodeConfigMap(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
desc string
|
desc string
|
||||||
@@ -178,15 +143,6 @@ func TestEncodeSecret(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHash(t *testing.T) {
|
|
||||||
// hash the empty string to be sure that sha256 is being used
|
|
||||||
expect := "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
|
||||||
sum := hash("")
|
|
||||||
if expect != sum {
|
|
||||||
t.Errorf("expected hash %q but got %q", expect, sum)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// warn devs who change types that they might have to update a hash function
|
// warn devs who change types that they might have to update a hash function
|
||||||
// not perfect, as it only checks the number of top-level fields
|
// not perfect, as it only checks the number of top-level fields
|
||||||
func TestTypeStability(t *testing.T) {
|
func TestTypeStability(t *testing.T) {
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2018 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hash
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
|
||||||
"sigs.k8s.io/kustomize/pkg/transformers"
|
|
||||||
)
|
|
||||||
|
|
||||||
type nameHashTransformer struct{}
|
|
||||||
|
|
||||||
var _ transformers.Transformer = &nameHashTransformer{}
|
|
||||||
|
|
||||||
// NewNameHashTransformer construct a nameHashTransformer.
|
|
||||||
func NewNameHashTransformer() transformers.Transformer {
|
|
||||||
return &nameHashTransformer{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transform appends hash to generated resources.
|
|
||||||
func (o *nameHashTransformer) Transform(m resmap.ResMap) error {
|
|
||||||
for _, res := range m {
|
|
||||||
if res.NeedHashSuffix() {
|
|
||||||
h, err := NewKustHash().Hash(res.Map())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
res.SetName(fmt.Sprintf("%s-%s", res.GetName(), h))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
34
k8sdeps/transformer/hash/transformer.go
Normal file
34
k8sdeps/transformer/hash/transformer.go
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package hash
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/transformers"
|
||||||
|
)
|
||||||
|
|
||||||
|
type transformer struct{}
|
||||||
|
|
||||||
|
var _ transformers.Transformer = &transformer{}
|
||||||
|
|
||||||
|
// NewTransformer make a hash transformer.
|
||||||
|
func NewTransformer() transformers.Transformer {
|
||||||
|
return &transformer{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform appends hash to generated resources.
|
||||||
|
func (tf *transformer) Transform(m resmap.ResMap) error {
|
||||||
|
for _, res := range m {
|
||||||
|
if res.NeedHashSuffix() {
|
||||||
|
h, err := NewKustHash().Hash(res.Map())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
res.SetName(fmt.Sprintf("%s-%s", res.GetName(), h))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,18 +1,5 @@
|
|||||||
/*
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
Copyright 2018 The Kubernetes Authors.
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hash
|
package hash
|
||||||
|
|
||||||
@@ -152,7 +139,7 @@ func TestNameHashTransformer(t *testing.T) {
|
|||||||
}, &types.GeneratorArgs{Behavior: "create"}, &types.GeneratorOptions{DisableNameSuffixHash: false}),
|
}, &types.GeneratorArgs{Behavior: "create"}, &types.GeneratorOptions{DisableNameSuffixHash: false}),
|
||||||
}
|
}
|
||||||
|
|
||||||
tran := NewNameHashTransformer()
|
tran := NewTransformer()
|
||||||
tran.Transform(objs)
|
tran.Transform(objs)
|
||||||
|
|
||||||
if !reflect.DeepEqual(objs, expected) {
|
if !reflect.DeepEqual(objs, expected) {
|
||||||
@@ -5,9 +5,10 @@ package inventory
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
|
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
|
||||||
"sigs.k8s.io/kustomize/k8sdeps/transformer/hash"
|
|
||||||
"sigs.k8s.io/kustomize/pkg/gvk"
|
"sigs.k8s.io/kustomize/pkg/gvk"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/hasher"
|
||||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||||
"sigs.k8s.io/kustomize/pkg/inventory"
|
"sigs.k8s.io/kustomize/pkg/inventory"
|
||||||
"sigs.k8s.io/kustomize/pkg/resid"
|
"sigs.k8s.io/kustomize/pkg/resid"
|
||||||
@@ -17,18 +18,18 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/pkg/types"
|
"sigs.k8s.io/kustomize/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// inventoryTransformer compute the inventory object used in prune
|
// transformer compute the inventory object used in prune
|
||||||
type inventoryTransformer struct {
|
type transformer struct {
|
||||||
garbagePolicy types.GarbagePolicy
|
garbagePolicy types.GarbagePolicy
|
||||||
ldr ifc.Loader
|
ldr ifc.Loader
|
||||||
cmName string
|
cmName string
|
||||||
cmNamespace string
|
cmNamespace string
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ transformers.Transformer = &inventoryTransformer{}
|
var _ transformers.Transformer = &transformer{}
|
||||||
|
|
||||||
// NewInventoryTransformer makes a inventoryTransformer.
|
// NewTransformer makes a new inventory transformer.
|
||||||
func NewInventoryTransformer(
|
func NewTransformer(
|
||||||
p *types.Inventory,
|
p *types.Inventory,
|
||||||
ldr ifc.Loader,
|
ldr ifc.Loader,
|
||||||
namespace string,
|
namespace string,
|
||||||
@@ -36,7 +37,7 @@ func NewInventoryTransformer(
|
|||||||
if p == nil || p.Type != "ConfigMap" || p.ConfigMap.Namespace != namespace {
|
if p == nil || p.Type != "ConfigMap" || p.ConfigMap.Namespace != namespace {
|
||||||
return transformers.NewNoOpTransformer()
|
return transformers.NewNoOpTransformer()
|
||||||
}
|
}
|
||||||
return &inventoryTransformer{
|
return &transformer{
|
||||||
garbagePolicy: gp,
|
garbagePolicy: gp,
|
||||||
ldr: ldr,
|
ldr: ldr,
|
||||||
cmName: p.ConfigMap.Name,
|
cmName: p.ConfigMap.Name,
|
||||||
@@ -52,7 +53,7 @@ func NewInventoryTransformer(
|
|||||||
// The inventory data is written to annotation since
|
// The inventory data is written to annotation since
|
||||||
// 1. The key in data field is constrained and couldn't include arbitrary letters
|
// 1. The key in data field is constrained and couldn't include arbitrary letters
|
||||||
// 2. The annotation can be put into any kind of objects
|
// 2. The annotation can be put into any kind of objects
|
||||||
func (o *inventoryTransformer) Transform(m resmap.ResMap) error {
|
func (tf *transformer) Transform(m resmap.ResMap) error {
|
||||||
invty := inventory.NewInventory()
|
invty := inventory.NewInventory()
|
||||||
var keys []string
|
var keys []string
|
||||||
for _, r := range m {
|
for _, r := range m {
|
||||||
@@ -68,14 +69,14 @@ func (o *inventoryTransformer) Transform(m resmap.ResMap) error {
|
|||||||
invty.Current[item] = refs
|
invty.Current[item] = refs
|
||||||
keys = append(keys, item.String())
|
keys = append(keys, item.String())
|
||||||
}
|
}
|
||||||
h, err := hash.SortArrayAndComputeHash(keys)
|
h, err := hasher.SortArrayAndComputeHash(keys)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
args := &types.ConfigMapArgs{}
|
args := &types.ConfigMapArgs{}
|
||||||
args.Name = o.cmName
|
args.Name = tf.cmName
|
||||||
args.Namespace = o.cmNamespace
|
args.Namespace = tf.cmNamespace
|
||||||
opts := &types.GeneratorOptions{
|
opts := &types.GeneratorOptions{
|
||||||
Annotations: make(map[string]string),
|
Annotations: make(map[string]string),
|
||||||
}
|
}
|
||||||
@@ -86,12 +87,12 @@ func (o *inventoryTransformer) Transform(m resmap.ResMap) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
kf := kunstruct.NewKunstructuredFactoryImpl()
|
kf := kunstruct.NewKunstructuredFactoryImpl()
|
||||||
k, err := kf.MakeConfigMap(o.ldr, opts, args)
|
k, err := kf.MakeConfigMap(tf.ldr, opts, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.garbagePolicy == types.GarbageCollect {
|
if tf.garbagePolicy == types.GarbageCollect {
|
||||||
for k := range m {
|
for k := range m {
|
||||||
delete(m, k)
|
delete(m, k)
|
||||||
}
|
}
|
||||||
@@ -102,8 +103,8 @@ func (o *inventoryTransformer) Transform(m resmap.ResMap) error {
|
|||||||
Version: "v1",
|
Version: "v1",
|
||||||
Kind: "ConfigMap",
|
Kind: "ConfigMap",
|
||||||
},
|
},
|
||||||
o.cmName,
|
tf.cmName,
|
||||||
"", o.cmNamespace)
|
"", tf.cmNamespace)
|
||||||
if _, ok := m[id]; ok {
|
if _, ok := m[id]; ok {
|
||||||
return fmt.Errorf("id %v is already used, please use a different name in the prune field", id)
|
return fmt.Errorf("id %v is already used, please use a different name in the prune field", id)
|
||||||
}
|
}
|
||||||
@@ -139,7 +139,7 @@ func TestInventoryTransformer(t *testing.T) {
|
|||||||
objs := makeResMap()
|
objs := makeResMap()
|
||||||
|
|
||||||
// include the original resmap; only return the ConfigMap for pruning
|
// include the original resmap; only return the ConfigMap for pruning
|
||||||
tran := NewInventoryTransformer(p, ldr, "default", types.GarbageCollect)
|
tran := NewTransformer(p, ldr, "default", types.GarbageCollect)
|
||||||
tran.Transform(objs)
|
tran.Transform(objs)
|
||||||
|
|
||||||
if !reflect.DeepEqual(objs, expected) {
|
if !reflect.DeepEqual(objs, expected) {
|
||||||
@@ -151,7 +151,7 @@ func TestInventoryTransformer(t *testing.T) {
|
|||||||
expected = objs.DeepCopy(rf)
|
expected = objs.DeepCopy(rf)
|
||||||
expected[resid.NewResIdWithPrefixNamespace(cmap, "pruneCM", "", "default")] = pruneMap
|
expected[resid.NewResIdWithPrefixNamespace(cmap, "pruneCM", "", "default")] = pruneMap
|
||||||
// append the ConfigMap for pruning to the original resmap
|
// append the ConfigMap for pruning to the original resmap
|
||||||
tran = NewInventoryTransformer(p, ldr, "default", types.GarbageIgnore)
|
tran = NewTransformer(p, ldr, "default", types.GarbageIgnore)
|
||||||
tran.Transform(objs)
|
tran.Transform(objs)
|
||||||
|
|
||||||
if !reflect.DeepEqual(objs, expected) {
|
if !reflect.DeepEqual(objs, expected) {
|
||||||
@@ -1,18 +1,5 @@
|
|||||||
/*
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
Copyright 2018 The Kubernetes Authors.
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package patch
|
package patch
|
||||||
|
|
||||||
@@ -1,18 +1,5 @@
|
|||||||
/*
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
Copyright 2018 The Kubernetes Authors.
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package patch
|
package patch
|
||||||
|
|
||||||
@@ -31,27 +18,27 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/pkg/transformers"
|
"sigs.k8s.io/kustomize/pkg/transformers"
|
||||||
)
|
)
|
||||||
|
|
||||||
// patchTransformer applies patches.
|
// transformer applies strategic merge patches.
|
||||||
type patchTransformer struct {
|
type transformer struct {
|
||||||
patches []*resource.Resource
|
patches []*resource.Resource
|
||||||
rf *resource.Factory
|
rf *resource.Factory
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ transformers.Transformer = &patchTransformer{}
|
var _ transformers.Transformer = &transformer{}
|
||||||
|
|
||||||
// NewPatchTransformer constructs a patchTransformer.
|
// NewTransformer constructs a strategic merge patch transformer.
|
||||||
func NewPatchTransformer(
|
func NewTransformer(
|
||||||
slice []*resource.Resource, rf *resource.Factory) (transformers.Transformer, error) {
|
slice []*resource.Resource, rf *resource.Factory) (transformers.Transformer, error) {
|
||||||
if len(slice) == 0 {
|
if len(slice) == 0 {
|
||||||
return transformers.NewNoOpTransformer(), nil
|
return transformers.NewNoOpTransformer(), nil
|
||||||
}
|
}
|
||||||
return &patchTransformer{patches: slice, rf: rf}, nil
|
return &transformer{patches: slice, rf: rf}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transform apply the patches on top of the base resources.
|
// Transform apply the patches on top of the base resources.
|
||||||
func (pt *patchTransformer) Transform(baseResourceMap resmap.ResMap) error {
|
func (tf *transformer) Transform(baseResourceMap resmap.ResMap) error {
|
||||||
// Merge and then index the patches by Id.
|
// Merge and then index the patches by Id.
|
||||||
patches, err := pt.mergePatches()
|
patches, err := tf.mergePatches()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -118,9 +105,9 @@ func (pt *patchTransformer) Transform(baseResourceMap resmap.ResMap) error {
|
|||||||
|
|
||||||
// mergePatches merge and index patches by Id.
|
// mergePatches merge and index patches by Id.
|
||||||
// It errors out if there is conflict between patches.
|
// It errors out if there is conflict between patches.
|
||||||
func (pt *patchTransformer) mergePatches() (resmap.ResMap, error) {
|
func (tf *transformer) mergePatches() (resmap.ResMap, error) {
|
||||||
rc := resmap.ResMap{}
|
rc := resmap.ResMap{}
|
||||||
for ix, patch := range pt.patches {
|
for ix, patch := range tf.patches {
|
||||||
id := patch.Id()
|
id := patch.Id()
|
||||||
existing, found := rc[id]
|
existing, found := rc[id]
|
||||||
if !found {
|
if !found {
|
||||||
@@ -134,9 +121,9 @@ func (pt *patchTransformer) mergePatches() (resmap.ResMap, error) {
|
|||||||
}
|
}
|
||||||
var cd conflictDetector
|
var cd conflictDetector
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cd = newJMPConflictDetector(pt.rf)
|
cd = newJMPConflictDetector(tf.rf)
|
||||||
} else {
|
} else {
|
||||||
cd, err = newSMPConflictDetector(versionedObj, pt.rf)
|
cd, err = newSMPConflictDetector(versionedObj, tf.rf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -147,7 +134,7 @@ func (pt *patchTransformer) mergePatches() (resmap.ResMap, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if conflict {
|
if conflict {
|
||||||
conflictingPatch, err := cd.findConflict(ix, pt.patches)
|
conflictingPatch, err := cd.findConflict(ix, tf.patches)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1,18 +1,5 @@
|
|||||||
/*
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
Copyright 2018 The Kubernetes Authors.
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package patch
|
package patch
|
||||||
|
|
||||||
@@ -128,7 +115,7 @@ func TestOverlayRun(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
lt, err := NewPatchTransformer(patch, rf)
|
lt, err := NewTransformer(patch, rf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -258,7 +245,7 @@ func TestMultiplePatches(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
lt, err := NewPatchTransformer(patch, rf)
|
lt, err := NewTransformer(patch, rf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -344,7 +331,7 @@ func TestMultiplePatchesWithConflict(t *testing.T) {
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
lt, err := NewPatchTransformer(patch, rf)
|
lt, err := NewTransformer(patch, rf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -407,7 +394,7 @@ func TestNoSchemaOverlayRun(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
lt, err := NewPatchTransformer(patch, rf)
|
lt, err := NewTransformer(patch, rf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -491,7 +478,7 @@ func TestNoSchemaMultiplePatches(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
lt, err := NewPatchTransformer(patch, rf)
|
lt, err := NewTransformer(patch, rf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -549,7 +536,7 @@ func TestNoSchemaMultiplePatchesWithConflict(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
lt, err := NewPatchTransformer(patch, rf)
|
lt, err := NewTransformer(patch, rf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
52
pkg/hasher/hasher.go
Normal file
52
pkg/hasher/hasher.go
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package hasher
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SortArrayAndComputeHash sorts a string array and
|
||||||
|
// returns a hash for it
|
||||||
|
func SortArrayAndComputeHash(s []string) (string, error) {
|
||||||
|
sort.Strings(s)
|
||||||
|
data, err := json.Marshal(s)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return Encode(Hash(string(data)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copied from https://github.com/kubernetes/kubernetes
|
||||||
|
// /blob/master/pkg/kubectl/util/hash/hash.go
|
||||||
|
func Encode(hex string) (string, error) {
|
||||||
|
if len(hex) < 10 {
|
||||||
|
return "", fmt.Errorf(
|
||||||
|
"input length must be at least 10.")
|
||||||
|
}
|
||||||
|
enc := []rune(hex[:10])
|
||||||
|
for i := range enc {
|
||||||
|
switch enc[i] {
|
||||||
|
case '0':
|
||||||
|
enc[i] = 'g'
|
||||||
|
case '1':
|
||||||
|
enc[i] = 'h'
|
||||||
|
case '3':
|
||||||
|
enc[i] = 'k'
|
||||||
|
case 'a':
|
||||||
|
enc[i] = 'm'
|
||||||
|
case 'e':
|
||||||
|
enc[i] = 't'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(enc), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash returns the hex form of the sha256 of the argument.
|
||||||
|
func Hash(data string) string {
|
||||||
|
return fmt.Sprintf("%x", sha256.Sum256([]byte(data)))
|
||||||
|
}
|
||||||
41
pkg/hasher/hasher_test.go
Normal file
41
pkg/hasher/hasher_test.go
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package hasher_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "sigs.k8s.io/kustomize/pkg/hasher"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSortArrayAndComputeHash(t *testing.T) {
|
||||||
|
array1 := []string{"a", "b", "c", "d"}
|
||||||
|
array2 := []string{"c", "b", "d", "a"}
|
||||||
|
h1, err := SortArrayAndComputeHash(array1)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error %v", err)
|
||||||
|
}
|
||||||
|
if h1 == "" {
|
||||||
|
t.Errorf("failed to hash %v", array1)
|
||||||
|
}
|
||||||
|
h2, err := SortArrayAndComputeHash(array2)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error %v", err)
|
||||||
|
}
|
||||||
|
if h2 == "" {
|
||||||
|
t.Errorf("failed to hash %v", array2)
|
||||||
|
}
|
||||||
|
if h1 != h2 {
|
||||||
|
t.Errorf("hash is not consistent with reordered list: %s %s", h1, h2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHash(t *testing.T) {
|
||||||
|
// hash the empty string to be sure that sha256 is being used
|
||||||
|
expect := "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||||
|
sum := Hash("")
|
||||||
|
if expect != sum {
|
||||||
|
t.Errorf("expected hash %q but got %q", expect, sum)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -61,7 +61,7 @@ kind: Secret
|
|||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: release-name-minecraft
|
app: release-name-minecraft
|
||||||
chart: minecraft-1.0.0
|
chart: minecraft-1.0.1
|
||||||
heritage: Tiller
|
heritage: Tiller
|
||||||
release: release-name
|
release: release-name
|
||||||
name: LOOOOOOOONG-release-name-minecraft
|
name: LOOOOOOOONG-release-name-minecraft
|
||||||
@@ -72,7 +72,7 @@ kind: Service
|
|||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: release-name-minecraft
|
app: release-name-minecraft
|
||||||
chart: minecraft-1.0.0
|
chart: minecraft-1.0.1
|
||||||
heritage: Tiller
|
heritage: Tiller
|
||||||
release: release-name
|
release: release-name
|
||||||
name: LOOOOOOOONG-release-name-minecraft
|
name: LOOOOOOOONG-release-name-minecraft
|
||||||
@@ -93,7 +93,7 @@ metadata:
|
|||||||
volume.alpha.kubernetes.io/storage-class: default
|
volume.alpha.kubernetes.io/storage-class: default
|
||||||
labels:
|
labels:
|
||||||
app: release-name-minecraft
|
app: release-name-minecraft
|
||||||
chart: minecraft-1.0.0
|
chart: minecraft-1.0.1
|
||||||
heritage: Tiller
|
heritage: Tiller
|
||||||
release: release-name
|
release: release-name
|
||||||
name: LOOOOOOOONG-release-name-minecraft-datadir
|
name: LOOOOOOOONG-release-name-minecraft-datadir
|
||||||
|
|||||||
@@ -31,24 +31,26 @@ namePrefix: blah-
|
|||||||
configMapGenerator:
|
configMapGenerator:
|
||||||
- name: bob
|
- name: bob
|
||||||
literals:
|
literals:
|
||||||
- fruit=apple
|
- fruit=apple
|
||||||
- vegetable=broccoli
|
- vegetable=broccoli
|
||||||
env: foo.env
|
envs:
|
||||||
|
- foo.env
|
||||||
files:
|
files:
|
||||||
- passphrase=phrase.dat
|
- passphrase=phrase.dat
|
||||||
- forces.txt
|
- forces.txt
|
||||||
- name: json
|
- name: json
|
||||||
literals:
|
literals:
|
||||||
- 'v2=[{"path": "var/druid/segment-cache"}]'
|
- 'v2=[{"path": "var/druid/segment-cache"}]'
|
||||||
secretGenerator:
|
secretGenerator:
|
||||||
- name: bob
|
- name: bob
|
||||||
literals:
|
literals:
|
||||||
- fruit=apple
|
- fruit=apple
|
||||||
- vegetable=broccoli
|
- vegetable=broccoli
|
||||||
env: foo.env
|
envs:
|
||||||
|
- foo.env
|
||||||
files:
|
files:
|
||||||
- passphrase=phrase.dat
|
- passphrase=phrase.dat
|
||||||
- forces.txt
|
- forces.txt
|
||||||
`)
|
`)
|
||||||
th.WriteF("/app/foo.env", `
|
th.WriteF("/app/foo.env", `
|
||||||
MOUNTAIN=everest
|
MOUNTAIN=everest
|
||||||
@@ -122,15 +124,15 @@ configMapGenerator:
|
|||||||
- name: bob
|
- name: bob
|
||||||
behavior: create
|
behavior: create
|
||||||
literals:
|
literals:
|
||||||
- bean=pinto
|
- bean=pinto
|
||||||
- star=wolf-rayet
|
- star=wolf-rayet
|
||||||
literals:
|
literals:
|
||||||
- fruit=apple
|
- fruit=apple
|
||||||
- vegetable=broccoli
|
- vegetable=broccoli
|
||||||
files:
|
files:
|
||||||
- forces.txt
|
- forces.txt
|
||||||
files:
|
files:
|
||||||
- nobles=nobility.txt
|
- nobles=nobility.txt
|
||||||
`)
|
`)
|
||||||
th.WriteF("/app/forces.txt", `
|
th.WriteF("/app/forces.txt", `
|
||||||
gravitational
|
gravitational
|
||||||
@@ -177,7 +179,7 @@ configMapGenerator:
|
|||||||
- name: com1
|
- name: com1
|
||||||
behavior: create
|
behavior: create
|
||||||
literals:
|
literals:
|
||||||
- from=base
|
- from=base
|
||||||
`)
|
`)
|
||||||
th.WriteK("/app/base2", `
|
th.WriteK("/app/base2", `
|
||||||
namePrefix: p2-
|
namePrefix: p2-
|
||||||
@@ -185,7 +187,7 @@ configMapGenerator:
|
|||||||
- name: com2
|
- name: com2
|
||||||
behavior: create
|
behavior: create
|
||||||
literals:
|
literals:
|
||||||
- from=base
|
- from=base
|
||||||
`)
|
`)
|
||||||
th.WriteK("/app/overlay/o1", `
|
th.WriteK("/app/overlay/o1", `
|
||||||
bases:
|
bases:
|
||||||
@@ -194,7 +196,7 @@ configMapGenerator:
|
|||||||
- name: com1
|
- name: com1
|
||||||
behavior: merge
|
behavior: merge
|
||||||
literals:
|
literals:
|
||||||
- from=overlay
|
- from=overlay
|
||||||
`)
|
`)
|
||||||
th.WriteK("/app/overlay/o2", `
|
th.WriteK("/app/overlay/o2", `
|
||||||
bases:
|
bases:
|
||||||
@@ -203,7 +205,7 @@ configMapGenerator:
|
|||||||
- name: com2
|
- name: com2
|
||||||
behavior: merge
|
behavior: merge
|
||||||
literals:
|
literals:
|
||||||
- from=overlay
|
- from=overlay
|
||||||
`)
|
`)
|
||||||
th.WriteK("/app/overlay", `
|
th.WriteK("/app/overlay", `
|
||||||
bases:
|
bases:
|
||||||
@@ -213,8 +215,8 @@ configMapGenerator:
|
|||||||
- name: com1
|
- name: com1
|
||||||
behavior: merge
|
behavior: merge
|
||||||
literals:
|
literals:
|
||||||
- foo=bar
|
- foo=bar
|
||||||
- baz=qux
|
- baz=qux
|
||||||
`)
|
`)
|
||||||
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -178,14 +178,14 @@ resources:
|
|||||||
- deployment.yaml
|
- deployment.yaml
|
||||||
- service.yaml
|
- service.yaml
|
||||||
configMapGenerator:
|
configMapGenerator:
|
||||||
- name: configmap-in-base
|
- name: configmap-in-base
|
||||||
literals:
|
literals:
|
||||||
- foo=bar
|
- foo=bar
|
||||||
secretGenerator:
|
secretGenerator:
|
||||||
- name: secret-in-base
|
- name: secret-in-base
|
||||||
literals:
|
literals:
|
||||||
- username=admin
|
- username=admin
|
||||||
- password=somepw
|
- password=somepw
|
||||||
`)
|
`)
|
||||||
th.WriteF("/app/deployment.yaml", `
|
th.WriteF("/app/deployment.yaml", `
|
||||||
apiVersion: apps/v1beta2
|
apiVersion: apps/v1beta2
|
||||||
@@ -354,18 +354,18 @@ patchesStrategicMerge:
|
|||||||
bases:
|
bases:
|
||||||
- ../app
|
- ../app
|
||||||
configMapGenerator:
|
configMapGenerator:
|
||||||
- name: configmap-in-overlay
|
- name: configmap-in-overlay
|
||||||
literals:
|
literals:
|
||||||
- hello=world
|
- hello=world
|
||||||
- name: configmap-in-base
|
- name: configmap-in-base
|
||||||
behavior: replace
|
behavior: replace
|
||||||
literals:
|
literals:
|
||||||
- foo=override-bar
|
- foo=override-bar
|
||||||
secretGenerator:
|
secretGenerator:
|
||||||
- name: secret-in-base
|
- name: secret-in-base
|
||||||
behavior: merge
|
behavior: merge
|
||||||
literals:
|
literals:
|
||||||
- proxy=haproxy
|
- proxy=haproxy
|
||||||
`)
|
`)
|
||||||
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -38,9 +38,9 @@ resources:
|
|||||||
- deployment.yaml
|
- deployment.yaml
|
||||||
- service.yaml
|
- service.yaml
|
||||||
configMapGenerator:
|
configMapGenerator:
|
||||||
- name: configmap-in-base
|
- name: configmap-in-base
|
||||||
literals:
|
literals:
|
||||||
- foo=bar
|
- foo=bar
|
||||||
`)
|
`)
|
||||||
th.WriteF("/app/base/deployment.yaml", `
|
th.WriteF("/app/base/deployment.yaml", `
|
||||||
apiVersion: apps/v1beta2
|
apiVersion: apps/v1beta2
|
||||||
@@ -93,9 +93,9 @@ patchesStrategicMerge:
|
|||||||
bases:
|
bases:
|
||||||
- ../../base
|
- ../../base
|
||||||
configMapGenerator:
|
configMapGenerator:
|
||||||
- name: configmap-in-overlay
|
- name: configmap-in-overlay
|
||||||
literals:
|
literals:
|
||||||
- hello=world
|
- hello=world
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,10 +42,10 @@ secretGenerator:
|
|||||||
- name: the-non-default-namespace-secret
|
- name: the-non-default-namespace-secret
|
||||||
namespace: non-default
|
namespace: non-default
|
||||||
literals:
|
literals:
|
||||||
- password.txt=verySecret
|
- password.txt=verySecret
|
||||||
- name: the-secret
|
- name: the-secret
|
||||||
literals:
|
literals:
|
||||||
- password.txt=anotherSecret
|
- password.txt=anotherSecret
|
||||||
`)
|
`)
|
||||||
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ resources:
|
|||||||
configMapGenerator:
|
configMapGenerator:
|
||||||
- name: test-config-map
|
- name: test-config-map
|
||||||
literals:
|
literals:
|
||||||
- foo=bar
|
- foo=bar
|
||||||
- baz=qux
|
- baz=qux
|
||||||
vars:
|
vars:
|
||||||
- name: CDB_PUBLIC_SVC
|
- name: CDB_PUBLIC_SVC
|
||||||
objref:
|
objref:
|
||||||
|
|||||||
@@ -252,6 +252,12 @@ nameReference:
|
|||||||
- path: spec/service/name
|
- path: spec/service/name
|
||||||
kind: APIService
|
kind: APIService
|
||||||
group: apiregistration.k8s.io
|
group: apiregistration.k8s.io
|
||||||
|
- path: webhooks/clientConfig/service/name
|
||||||
|
kind: ValidatingWebhookConfiguration
|
||||||
|
group: admissionregistration.k8s.io
|
||||||
|
- path: webhooks/clientConfig/service/name
|
||||||
|
kind: MutatingWebhookConfiguration
|
||||||
|
group: admissionregistration.k8s.io
|
||||||
|
|
||||||
- kind: Role
|
- kind: Role
|
||||||
group: rbac.authorization.k8s.io
|
group: rbac.authorization.k8s.io
|
||||||
|
|||||||
@@ -24,6 +24,10 @@
|
|||||||
# Example execution:
|
# Example execution:
|
||||||
# ./plugin/someteam.example.com/v1/ChartInflator configFile.yaml
|
# ./plugin/someteam.example.com/v1/ChartInflator configFile.yaml
|
||||||
|
|
||||||
|
# TODO: allow specification of a specific chart VERSION
|
||||||
|
# so this test doesn't break every time minecraft is upgraded :P
|
||||||
|
# See https://github.com/helm/helm/issues/4008
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Yaml parsing is a ridiculous thing to do in bash,
|
# Yaml parsing is a ridiculous thing to do in bash,
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ kind: Secret
|
|||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: release-name-minecraft
|
app: release-name-minecraft
|
||||||
chart: minecraft-1.0.0
|
chart: minecraft-1.0.1
|
||||||
heritage: Tiller
|
heritage: Tiller
|
||||||
release: release-name
|
release: release-name
|
||||||
name: release-name-minecraft
|
name: release-name-minecraft
|
||||||
@@ -53,7 +53,7 @@ kind: Service
|
|||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: release-name-minecraft
|
app: release-name-minecraft
|
||||||
chart: minecraft-1.0.0
|
chart: minecraft-1.0.1
|
||||||
heritage: Tiller
|
heritage: Tiller
|
||||||
release: release-name
|
release: release-name
|
||||||
name: release-name-minecraft
|
name: release-name-minecraft
|
||||||
@@ -74,7 +74,7 @@ metadata:
|
|||||||
volume.alpha.kubernetes.io/storage-class: default
|
volume.alpha.kubernetes.io/storage-class: default
|
||||||
labels:
|
labels:
|
||||||
app: release-name-minecraft
|
app: release-name-minecraft
|
||||||
chart: minecraft-1.0.0
|
chart: minecraft-1.0.1
|
||||||
heritage: Tiller
|
heritage: Tiller
|
||||||
release: release-name
|
release: release-name
|
||||||
name: release-name-minecraft-datadir
|
name: release-name-minecraft-datadir
|
||||||
|
|||||||
Reference in New Issue
Block a user