Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
74a64a9f
Commit
74a64a9f
authored
Feb 11, 2019
by
Jingfang Liu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
copy kustomize/k8sdeps into cli-runtime
parent
23a9b0c2
Show whitespace changes
Inline
Side-by-side
Showing
34 changed files
with
3542 additions
and
24 deletions
+3542
-24
Godeps.json
staging/src/k8s.io/cli-runtime/Godeps/Godeps.json
+24
-24
BUILD
staging/src/k8s.io/cli-runtime/pkg/kustomize/BUILD
+38
-0
BUILD
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/BUILD
+39
-0
BUILD
...li-runtime/pkg/kustomize/k8sdeps/configmapandsecret/BUILD
+53
-0
configmapfactory.go
.../kustomize/k8sdeps/configmapandsecret/configmapfactory.go
+126
-0
configmapfactory_test.go
...omize/k8sdeps/configmapandsecret/configmapfactory_test.go
+154
-0
kv.go
...li-runtime/pkg/kustomize/k8sdeps/configmapandsecret/kv.go
+107
-0
kv_test.go
...ntime/pkg/kustomize/k8sdeps/configmapandsecret/kv_test.go
+57
-0
secretfactory.go
...pkg/kustomize/k8sdeps/configmapandsecret/secretfactory.go
+106
-0
secretfactory_test.go
...ustomize/k8sdeps/configmapandsecret/secretfactory_test.go
+151
-0
doc.go
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/doc.go
+76
-0
factory.go
...g/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/factory.go
+34
-0
BUILD
.../k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kunstruct/BUILD
+47
-0
factory.go
...io/cli-runtime/pkg/kustomize/k8sdeps/kunstruct/factory.go
+118
-0
factory_test.go
...i-runtime/pkg/kustomize/k8sdeps/kunstruct/factory_test.go
+175
-0
helper.go
....io/cli-runtime/pkg/kustomize/k8sdeps/kunstruct/helper.go
+71
-0
kunstruct.go
.../cli-runtime/pkg/kustomize/k8sdeps/kunstruct/kunstruct.go
+92
-0
kunstruct_test.go
...runtime/pkg/kustomize/k8sdeps/kunstruct/kunstruct_test.go
+148
-0
BUILD
...ing/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kv/BUILD
+30
-0
kv.go
...ing/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kv/kv.go
+102
-0
kv_test.go
...rc/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kv/kv_test.go
+68
-0
BUILD
...8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/BUILD
+33
-0
factory.go
.../cli-runtime/pkg/kustomize/k8sdeps/transformer/factory.go
+43
-0
BUILD
.../cli-runtime/pkg/kustomize/k8sdeps/transformer/hash/BUILD
+50
-0
hash.go
...li-runtime/pkg/kustomize/k8sdeps/transformer/hash/hash.go
+168
-0
hash_test.go
...ntime/pkg/kustomize/k8sdeps/transformer/hash/hash_test.go
+208
-0
namehash.go
...untime/pkg/kustomize/k8sdeps/transformer/hash/namehash.go
+47
-0
namehash_test.go
...e/pkg/kustomize/k8sdeps/transformer/hash/namehash_test.go
+162
-0
BUILD
...cli-runtime/pkg/kustomize/k8sdeps/transformer/patch/BUILD
+51
-0
patch.go
...-runtime/pkg/kustomize/k8sdeps/transformer/patch/patch.go
+174
-0
patch_test.go
...ime/pkg/kustomize/k8sdeps/transformer/patch/patch_test.go
+563
-0
patchconflictdetector.go
...tomize/k8sdeps/transformer/patch/patchconflictdetector.go
+137
-0
BUILD
.../k8s.io/cli-runtime/pkg/kustomize/k8sdeps/validator/BUILD
+29
-0
validators.go
...cli-runtime/pkg/kustomize/k8sdeps/validator/validators.go
+61
-0
No files found.
staging/src/k8s.io/cli-runtime/Godeps/Godeps.json
View file @
74a64a9f
...
...
@@ -644,11 +644,11 @@
},
{
"ImportPath"
:
"k8s.io/kube-openapi/pkg/common"
,
"Rev"
:
"
ced9eb3070a5f1c548ef46e8dfe2a97c208d9f03
"
"Rev"
:
"
d7c86cdc46e3a4fcf892b32dd7bc3aa775e0870e
"
},
{
"ImportPath"
:
"k8s.io/kube-openapi/pkg/util/proto"
,
"Rev"
:
"
ced9eb3070a5f1c548ef46e8dfe2a97c208d9f03
"
"Rev"
:
"
d7c86cdc46e3a4fcf892b32dd7bc3aa775e0870e
"
},
{
"ImportPath"
:
"k8s.io/client-go/discovery"
,
...
...
@@ -700,91 +700,91 @@
},
{
"ImportPath"
:
"sigs.k8s.io/kustomize/pkg/commands/build"
,
"Rev"
:
"
0184d5b69700607a1b9280f303152e2959bc19e7
"
"Rev"
:
"
ce7e5ee2c30cc5856fea01fe423cf167f2a2d0c3
"
},
{
"ImportPath"
:
"sigs.k8s.io/kustomize/pkg/constants"
,
"Rev"
:
"
0184d5b69700607a1b9280f303152e2959bc19e7
"
"Rev"
:
"
ce7e5ee2c30cc5856fea01fe423cf167f2a2d0c3
"
},
{
"ImportPath"
:
"sigs.k8s.io/kustomize/pkg/expansion"
,
"Rev"
:
"
0184d5b69700607a1b9280f303152e2959bc19e7
"
"Rev"
:
"
ce7e5ee2c30cc5856fea01fe423cf167f2a2d0c3
"
},
{
"ImportPath"
:
"sigs.k8s.io/kustomize/pkg/factory"
,
"Rev"
:
"
0184d5b69700607a1b9280f303152e2959bc19e7
"
"Rev"
:
"
ce7e5ee2c30cc5856fea01fe423cf167f2a2d0c3
"
},
{
"ImportPath"
:
"sigs.k8s.io/kustomize/pkg/fs"
,
"Rev"
:
"
0184d5b69700607a1b9280f303152e2959bc19e7
"
"Rev"
:
"
ce7e5ee2c30cc5856fea01fe423cf167f2a2d0c3
"
},
{
"ImportPath"
:
"sigs.k8s.io/kustomize/pkg/git"
,
"Rev"
:
"
0184d5b69700607a1b9280f303152e2959bc19e7
"
"Rev"
:
"
ce7e5ee2c30cc5856fea01fe423cf167f2a2d0c3
"
},
{
"ImportPath"
:
"sigs.k8s.io/kustomize/pkg/gvk"
,
"Rev"
:
"
0184d5b69700607a1b9280f303152e2959bc19e7
"
"Rev"
:
"
ce7e5ee2c30cc5856fea01fe423cf167f2a2d0c3
"
},
{
"ImportPath"
:
"sigs.k8s.io/kustomize/pkg/ifc"
,
"Rev"
:
"
0184d5b69700607a1b9280f303152e2959bc19e7
"
"Rev"
:
"
ce7e5ee2c30cc5856fea01fe423cf167f2a2d0c3
"
},
{
"ImportPath"
:
"sigs.k8s.io/kustomize/pkg/ifc/transformer"
,
"Rev"
:
"
0184d5b69700607a1b9280f303152e2959bc19e7
"
"Rev"
:
"
ce7e5ee2c30cc5856fea01fe423cf167f2a2d0c3
"
},
{
"ImportPath"
:
"sigs.k8s.io/kustomize/pkg/image"
,
"Rev"
:
"
0184d5b69700607a1b9280f303152e2959bc19e7
"
"Rev"
:
"
ce7e5ee2c30cc5856fea01fe423cf167f2a2d0c3
"
},
{
"ImportPath"
:
"sigs.k8s.io/kustomize/pkg/internal/error"
,
"Rev"
:
"
0184d5b69700607a1b9280f303152e2959bc19e7
"
"Rev"
:
"
ce7e5ee2c30cc5856fea01fe423cf167f2a2d0c3
"
},
{
"ImportPath"
:
"sigs.k8s.io/kustomize/pkg/loader"
,
"Rev"
:
"
0184d5b69700607a1b9280f303152e2959bc19e7
"
"Rev"
:
"
ce7e5ee2c30cc5856fea01fe423cf167f2a2d0c3
"
},
{
"ImportPath"
:
"sigs.k8s.io/kustomize/pkg/patch"
,
"Rev"
:
"
0184d5b69700607a1b9280f303152e2959bc19e7
"
"Rev"
:
"
ce7e5ee2c30cc5856fea01fe423cf167f2a2d0c3
"
},
{
"ImportPath"
:
"sigs.k8s.io/kustomize/pkg/patch/transformer"
,
"Rev"
:
"
0184d5b69700607a1b9280f303152e2959bc19e7
"
"Rev"
:
"
ce7e5ee2c30cc5856fea01fe423cf167f2a2d0c3
"
},
{
"ImportPath"
:
"sigs.k8s.io/kustomize/pkg/resid"
,
"Rev"
:
"
0184d5b69700607a1b9280f303152e2959bc19e7
"
"Rev"
:
"
ce7e5ee2c30cc5856fea01fe423cf167f2a2d0c3
"
},
{
"ImportPath"
:
"sigs.k8s.io/kustomize/pkg/resmap"
,
"Rev"
:
"
0184d5b69700607a1b9280f303152e2959bc19e7
"
"Rev"
:
"
ce7e5ee2c30cc5856fea01fe423cf167f2a2d0c3
"
},
{
"ImportPath"
:
"sigs.k8s.io/kustomize/pkg/resource"
,
"Rev"
:
"
0184d5b69700607a1b9280f303152e2959bc19e7
"
"Rev"
:
"
ce7e5ee2c30cc5856fea01fe423cf167f2a2d0c3
"
},
{
"ImportPath"
:
"sigs.k8s.io/kustomize/pkg/target"
,
"Rev"
:
"
0184d5b69700607a1b9280f303152e2959bc19e7
"
"Rev"
:
"
ce7e5ee2c30cc5856fea01fe423cf167f2a2d0c3
"
},
{
"ImportPath"
:
"sigs.k8s.io/kustomize/pkg/transformers"
,
"Rev"
:
"
0184d5b69700607a1b9280f303152e2959bc19e7
"
"Rev"
:
"
ce7e5ee2c30cc5856fea01fe423cf167f2a2d0c3
"
},
{
"ImportPath"
:
"sigs.k8s.io/kustomize/pkg/transformers/config"
,
"Rev"
:
"
0184d5b69700607a1b9280f303152e2959bc19e7
"
"Rev"
:
"
ce7e5ee2c30cc5856fea01fe423cf167f2a2d0c3
"
},
{
"ImportPath"
:
"sigs.k8s.io/kustomize/pkg/transformers/config/defaultconfig"
,
"Rev"
:
"
0184d5b69700607a1b9280f303152e2959bc19e7
"
"Rev"
:
"
ce7e5ee2c30cc5856fea01fe423cf167f2a2d0c3
"
},
{
"ImportPath"
:
"sigs.k8s.io/kustomize/pkg/types"
,
"Rev"
:
"
0184d5b69700607a1b9280f303152e2959bc19e7
"
"Rev"
:
"
ce7e5ee2c30cc5856fea01fe423cf167f2a2d0c3
"
},
{
"ImportPath"
:
"sigs.k8s.io/structured-merge-diff/fieldpath"
,
...
...
staging/src/k8s.io/cli-runtime/pkg/kustomize/BUILD
0 → 100644
View file @
74a64a9f
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = ["builder.go"],
importmap = "k8s.io/kubernetes/vendor/k8s.io/cli-runtime/pkg/kustomize",
importpath = "k8s.io/cli-runtime/pkg/kustomize",
visibility = ["//visibility:public"],
deps = [
"//staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/commands/build:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/fs:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = ["builder_test.go"],
embed = [":go_default_library"],
deps = ["//vendor/sigs.k8s.io/kustomize/pkg/fs:go_default_library"],
)
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/BUILD
0 → 100644
View file @
74a64a9f
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"doc.go",
"factory.go",
],
importmap = "k8s.io/kubernetes/vendor/k8s.io/cli-runtime/pkg/kustomize/k8sdeps",
importpath = "k8s.io/cli-runtime/pkg/kustomize/k8sdeps",
visibility = ["//visibility:public"],
deps = [
"//staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kunstruct:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/validator:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/factory:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/configmapandsecret:all-srcs",
"//staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kunstruct:all-srcs",
"//staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kv:all-srcs",
"//staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer:all-srcs",
"//staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/validator:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/configmapandsecret/BUILD
0 → 100644
View file @
74a64a9f
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"configmapfactory.go",
"kv.go",
"secretfactory.go",
],
importmap = "k8s.io/kubernetes/vendor/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/configmapandsecret",
importpath = "k8s.io/cli-runtime/pkg/kustomize/k8sdeps/configmapandsecret",
visibility = ["//visibility:public"],
deps = [
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/validation:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kv:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/ifc:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/types:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"configmapfactory_test.go",
"kv_test.go",
"secretfactory_test.go",
],
embed = [":go_default_library"],
deps = [
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kv:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/fs:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/loader:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/types:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/configmapandsecret/configmapfactory.go
0 → 100644
View file @
74a64a9f
/*
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 configmapandsecret generates configmaps and secrets per generator rules.
package
configmapandsecret
import
(
"fmt"
"strings"
"unicode/utf8"
"github.com/pkg/errors"
"k8s.io/api/core/v1"
corev1
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kv"
"sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/types"
)
// ConfigMapFactory makes ConfigMaps.
type
ConfigMapFactory
struct
{
ldr
ifc
.
Loader
}
// NewConfigMapFactory returns a new ConfigMapFactory.
func
NewConfigMapFactory
(
l
ifc
.
Loader
)
*
ConfigMapFactory
{
return
&
ConfigMapFactory
{
ldr
:
l
}
}
func
(
f
*
ConfigMapFactory
)
makeFreshConfigMap
(
args
*
types
.
ConfigMapArgs
)
*
corev1
.
ConfigMap
{
cm
:=
&
corev1
.
ConfigMap
{}
cm
.
APIVersion
=
"v1"
cm
.
Kind
=
"ConfigMap"
cm
.
Name
=
args
.
Name
cm
.
Namespace
=
args
.
Namespace
cm
.
Data
=
map
[
string
]
string
{}
return
cm
}
// MakeConfigMap returns a new ConfigMap, or nil and an error.
func
(
f
*
ConfigMapFactory
)
MakeConfigMap
(
args
*
types
.
ConfigMapArgs
,
options
*
types
.
GeneratorOptions
)
(
*
corev1
.
ConfigMap
,
error
)
{
var
all
[]
kv
.
Pair
var
err
error
cm
:=
f
.
makeFreshConfigMap
(
args
)
pairs
,
err
:=
keyValuesFromEnvFile
(
f
.
ldr
,
args
.
EnvSource
)
if
err
!=
nil
{
return
nil
,
errors
.
Wrap
(
err
,
fmt
.
Sprintf
(
"env source file: %s"
,
args
.
EnvSource
))
}
all
=
append
(
all
,
pairs
...
)
pairs
,
err
=
keyValuesFromLiteralSources
(
args
.
LiteralSources
)
if
err
!=
nil
{
return
nil
,
errors
.
Wrap
(
err
,
fmt
.
Sprintf
(
"literal sources %v"
,
args
.
LiteralSources
))
}
all
=
append
(
all
,
pairs
...
)
pairs
,
err
=
keyValuesFromFileSources
(
f
.
ldr
,
args
.
FileSources
)
if
err
!=
nil
{
return
nil
,
errors
.
Wrap
(
err
,
fmt
.
Sprintf
(
"file sources: %v"
,
args
.
FileSources
))
}
all
=
append
(
all
,
pairs
...
)
for
_
,
kv
:=
range
all
{
err
=
addKvToConfigMap
(
cm
,
kv
.
Key
,
kv
.
Value
)
if
err
!=
nil
{
return
nil
,
err
}
}
if
options
!=
nil
{
cm
.
SetLabels
(
options
.
Labels
)
cm
.
SetAnnotations
(
options
.
Annotations
)
}
return
cm
,
nil
}
// addKvToConfigMap adds the given key and data to the given config map.
// Error if key invalid, or already exists.
func
addKvToConfigMap
(
configMap
*
v1
.
ConfigMap
,
keyName
,
data
string
)
error
{
// Note, the rules for ConfigMap keys are the exact same as the ones for SecretKeys.
if
errs
:=
validation
.
IsConfigMapKey
(
keyName
);
len
(
errs
)
!=
0
{
return
fmt
.
Errorf
(
"%q is not a valid key name for a ConfigMap: %s"
,
keyName
,
strings
.
Join
(
errs
,
";"
))
}
keyExistsErrorMsg
:=
"cannot add key %s, another key by that name already exists: %v"
// If the configmap data contains byte sequences that are all in the UTF-8
// range, we will write it to .Data
if
utf8
.
Valid
([]
byte
(
data
))
{
if
_
,
entryExists
:=
configMap
.
Data
[
keyName
];
entryExists
{
return
fmt
.
Errorf
(
keyExistsErrorMsg
,
keyName
,
configMap
.
Data
)
}
configMap
.
Data
[
keyName
]
=
data
return
nil
}
// otherwise, it's BinaryData
if
configMap
.
BinaryData
==
nil
{
configMap
.
BinaryData
=
map
[
string
][]
byte
{}
}
if
_
,
entryExists
:=
configMap
.
BinaryData
[
keyName
];
entryExists
{
return
fmt
.
Errorf
(
keyExistsErrorMsg
,
keyName
,
configMap
.
BinaryData
)
}
configMap
.
BinaryData
[
keyName
]
=
[]
byte
(
data
)
return
nil
}
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/configmapandsecret/configmapfactory_test.go
0 → 100644
View file @
74a64a9f
/*
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
configmapandsecret
import
(
"reflect"
"testing"
corev1
"k8s.io/api/core/v1"
metav1
"k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/loader"
"sigs.k8s.io/kustomize/pkg/types"
)
func
makeEnvConfigMap
(
name
string
)
*
corev1
.
ConfigMap
{
return
&
corev1
.
ConfigMap
{
TypeMeta
:
metav1
.
TypeMeta
{
APIVersion
:
"v1"
,
Kind
:
"ConfigMap"
,
},
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
name
,
},
Data
:
map
[
string
]
string
{
"DB_USERNAME"
:
"admin"
,
"DB_PASSWORD"
:
"somepw"
,
},
}
}
func
makeFileConfigMap
(
name
string
)
*
corev1
.
ConfigMap
{
return
&
corev1
.
ConfigMap
{
TypeMeta
:
metav1
.
TypeMeta
{
APIVersion
:
"v1"
,
Kind
:
"ConfigMap"
,
},
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
name
,
},
Data
:
map
[
string
]
string
{
"app-init.ini"
:
`FOO=bar
BAR=baz
`
,
},
BinaryData
:
map
[
string
][]
byte
{
"app.bin"
:
{
0xff
,
0xfd
},
},
}
}
func
makeLiteralConfigMap
(
name
string
)
*
corev1
.
ConfigMap
{
cm
:=
&
corev1
.
ConfigMap
{
TypeMeta
:
metav1
.
TypeMeta
{
APIVersion
:
"v1"
,
Kind
:
"ConfigMap"
,
},
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
name
,
},
Data
:
map
[
string
]
string
{
"a"
:
"x"
,
"b"
:
"y"
,
"c"
:
"Hello World"
,
"d"
:
"true"
,
},
}
cm
.
SetLabels
(
map
[
string
]
string
{
"foo"
:
"bar"
})
return
cm
}
func
TestConstructConfigMap
(
t
*
testing
.
T
)
{
type
testCase
struct
{
description
string
input
types
.
ConfigMapArgs
options
*
types
.
GeneratorOptions
expected
*
corev1
.
ConfigMap
}
testCases
:=
[]
testCase
{
{
description
:
"construct config map from env"
,
input
:
types
.
ConfigMapArgs
{
GeneratorArgs
:
types
.
GeneratorArgs
{
Name
:
"envConfigMap"
,
DataSources
:
types
.
DataSources
{
EnvSource
:
"configmap/app.env"
,
},
},
},
options
:
nil
,
expected
:
makeEnvConfigMap
(
"envConfigMap"
),
},
{
description
:
"construct config map from file"
,
input
:
types
.
ConfigMapArgs
{
GeneratorArgs
:
types
.
GeneratorArgs
{
Name
:
"fileConfigMap"
,
DataSources
:
types
.
DataSources
{
FileSources
:
[]
string
{
"configmap/app-init.ini"
,
"configmap/app.bin"
},
},
},
},
options
:
nil
,
expected
:
makeFileConfigMap
(
"fileConfigMap"
),
},
{
description
:
"construct config map from literal"
,
input
:
types
.
ConfigMapArgs
{
GeneratorArgs
:
types
.
GeneratorArgs
{
Name
:
"literalConfigMap"
,
DataSources
:
types
.
DataSources
{
LiteralSources
:
[]
string
{
"a=x"
,
"b=y"
,
"c=
\"
Hello World
\"
"
,
"d='true'"
},
},
},
},
options
:
&
types
.
GeneratorOptions
{
Labels
:
map
[
string
]
string
{
"foo"
:
"bar"
,
},
},
expected
:
makeLiteralConfigMap
(
"literalConfigMap"
),
},
}
fSys
:=
fs
.
MakeFakeFS
()
fSys
.
WriteFile
(
"/configmap/app.env"
,
[]
byte
(
"DB_USERNAME=admin
\n
DB_PASSWORD=somepw
\n
"
))
fSys
.
WriteFile
(
"/configmap/app-init.ini"
,
[]
byte
(
"FOO=bar
\n
BAR=baz
\n
"
))
fSys
.
WriteFile
(
"/configmap/app.bin"
,
[]
byte
{
0xff
,
0xfd
})
f
:=
NewConfigMapFactory
(
loader
.
NewFileLoaderAtRoot
(
fSys
))
for
_
,
tc
:=
range
testCases
{
cm
,
err
:=
f
.
MakeConfigMap
(
&
tc
.
input
,
tc
.
options
)
if
err
!=
nil
{
t
.
Fatalf
(
"unexpected error: %v"
,
err
)
}
if
!
reflect
.
DeepEqual
(
*
cm
,
*
tc
.
expected
)
{
t
.
Fatalf
(
"in testcase: %q updated:
\n
%#v
\n
doesn't match expected:
\n
%#v
\n
"
,
tc
.
description
,
*
cm
,
tc
.
expected
)
}
}
}
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/configmapandsecret/kv.go
0 → 100644
View file @
74a64a9f
/*
Copyright 2019 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
configmapandsecret
import
(
"fmt"
"path"
"strings"
"github.com/pkg/errors"
"k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kv"
"sigs.k8s.io/kustomize/pkg/ifc"
)
func
keyValuesFromLiteralSources
(
sources
[]
string
)
([]
kv
.
Pair
,
error
)
{
var
kvs
[]
kv
.
Pair
for
_
,
s
:=
range
sources
{
k
,
v
,
err
:=
parseLiteralSource
(
s
)
if
err
!=
nil
{
return
nil
,
err
}
kvs
=
append
(
kvs
,
kv
.
Pair
{
Key
:
k
,
Value
:
v
})
}
return
kvs
,
nil
}
func
keyValuesFromFileSources
(
ldr
ifc
.
Loader
,
sources
[]
string
)
([]
kv
.
Pair
,
error
)
{
var
kvs
[]
kv
.
Pair
for
_
,
s
:=
range
sources
{
k
,
fPath
,
err
:=
parseFileSource
(
s
)
if
err
!=
nil
{
return
nil
,
err
}
content
,
err
:=
ldr
.
Load
(
fPath
)
if
err
!=
nil
{
return
nil
,
err
}
kvs
=
append
(
kvs
,
kv
.
Pair
{
Key
:
k
,
Value
:
string
(
content
)})
}
return
kvs
,
nil
}
func
keyValuesFromEnvFile
(
l
ifc
.
Loader
,
path
string
)
([]
kv
.
Pair
,
error
)
{
if
path
==
""
{
return
nil
,
nil
}
content
,
err
:=
l
.
Load
(
path
)
if
err
!=
nil
{
return
nil
,
err
}
return
kv
.
KeyValuesFromLines
(
content
)
}
// parseFileSource parses the source given.
//
// Acceptable formats include:
// 1. source-path: the basename will become the key name
// 2. source-name=source-path: the source-name will become the key name and
// source-path is the path to the key file.
//
// Key names cannot include '='.
func
parseFileSource
(
source
string
)
(
keyName
,
filePath
string
,
err
error
)
{
numSeparators
:=
strings
.
Count
(
source
,
"="
)
switch
{
case
numSeparators
==
0
:
return
path
.
Base
(
source
),
source
,
nil
case
numSeparators
==
1
&&
strings
.
HasPrefix
(
source
,
"="
)
:
return
""
,
""
,
fmt
.
Errorf
(
"key name for file path %v missing"
,
strings
.
TrimPrefix
(
source
,
"="
))
case
numSeparators
==
1
&&
strings
.
HasSuffix
(
source
,
"="
)
:
return
""
,
""
,
fmt
.
Errorf
(
"file path for key name %v missing"
,
strings
.
TrimSuffix
(
source
,
"="
))
case
numSeparators
>
1
:
return
""
,
""
,
errors
.
New
(
"key names or file paths cannot contain '='"
)
default
:
components
:=
strings
.
Split
(
source
,
"="
)
return
components
[
0
],
components
[
1
],
nil
}
}
// parseLiteralSource parses the source key=val pair into its component pieces.
// This functionality is distinguished from strings.SplitN(source, "=", 2) since
// it returns an error in the case of empty keys, values, or a missing equals sign.
func
parseLiteralSource
(
source
string
)
(
keyName
,
value
string
,
err
error
)
{
// leading equal is invalid
if
strings
.
Index
(
source
,
"="
)
==
0
{
return
""
,
""
,
fmt
.
Errorf
(
"invalid literal source %v, expected key=value"
,
source
)
}
// split after the first equal (so values can have the = character)
items
:=
strings
.
SplitN
(
source
,
"="
,
2
)
if
len
(
items
)
!=
2
{
return
""
,
""
,
fmt
.
Errorf
(
"invalid literal source %v, expected key=value"
,
source
)
}
return
items
[
0
],
strings
.
Trim
(
items
[
1
],
"
\"
'"
),
nil
}
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/configmapandsecret/kv_test.go
0 → 100644
View file @
74a64a9f
/*
Copyright 2019 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
configmapandsecret
import
(
"reflect"
"testing"
"k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kv"
"sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/loader"
)
func
TestKeyValuesFromFileSources
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
description
string
sources
[]
string
expected
[]
kv
.
Pair
}{
{
description
:
"create kvs from file sources"
,
sources
:
[]
string
{
"files/app-init.ini"
},
expected
:
[]
kv
.
Pair
{
{
Key
:
"app-init.ini"
,
Value
:
"FOO=bar"
,
},
},
},
}
fSys
:=
fs
.
MakeFakeFS
()
fSys
.
WriteFile
(
"/files/app-init.ini"
,
[]
byte
(
"FOO=bar"
))
for
_
,
tc
:=
range
tests
{
kvs
,
err
:=
keyValuesFromFileSources
(
loader
.
NewFileLoaderAtRoot
(
fSys
),
tc
.
sources
)
if
err
!=
nil
{
t
.
Fatalf
(
"unexpected error: %v"
,
err
)
}
if
!
reflect
.
DeepEqual
(
kvs
,
tc
.
expected
)
{
t
.
Fatalf
(
"in testcase: %q updated:
\n
%#v
\n
doesn't match expected:
\n
%#v
\n
"
,
tc
.
description
,
kvs
,
tc
.
expected
)
}
}
}
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/configmapandsecret/secretfactory.go
0 → 100644
View file @
74a64a9f
/*
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
configmapandsecret
import
(
"fmt"
"strings"
"github.com/pkg/errors"
corev1
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kv"
"sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/types"
)
// SecretFactory makes Secrets.
type
SecretFactory
struct
{
ldr
ifc
.
Loader
}
// NewSecretFactory returns a new SecretFactory.
func
NewSecretFactory
(
ldr
ifc
.
Loader
)
*
SecretFactory
{
return
&
SecretFactory
{
ldr
:
ldr
}
}
func
(
f
*
SecretFactory
)
makeFreshSecret
(
args
*
types
.
SecretArgs
)
*
corev1
.
Secret
{
s
:=
&
corev1
.
Secret
{}
s
.
APIVersion
=
"v1"
s
.
Kind
=
"Secret"
s
.
Name
=
args
.
Name
s
.
Namespace
=
args
.
Namespace
s
.
Type
=
corev1
.
SecretType
(
args
.
Type
)
if
s
.
Type
==
""
{
s
.
Type
=
corev1
.
SecretTypeOpaque
}
s
.
Data
=
map
[
string
][]
byte
{}
return
s
}
// MakeSecret returns a new secret.
func
(
f
*
SecretFactory
)
MakeSecret
(
args
*
types
.
SecretArgs
,
options
*
types
.
GeneratorOptions
)
(
*
corev1
.
Secret
,
error
)
{
var
all
[]
kv
.
Pair
var
err
error
s
:=
f
.
makeFreshSecret
(
args
)
pairs
,
err
:=
keyValuesFromEnvFile
(
f
.
ldr
,
args
.
EnvSource
)
if
err
!=
nil
{
return
nil
,
errors
.
Wrap
(
err
,
fmt
.
Sprintf
(
"env source file: %s"
,
args
.
EnvSource
))
}
all
=
append
(
all
,
pairs
...
)
pairs
,
err
=
keyValuesFromLiteralSources
(
args
.
LiteralSources
)
if
err
!=
nil
{
return
nil
,
errors
.
Wrap
(
err
,
fmt
.
Sprintf
(
"literal sources %v"
,
args
.
LiteralSources
))
}
all
=
append
(
all
,
pairs
...
)
pairs
,
err
=
keyValuesFromFileSources
(
f
.
ldr
,
args
.
FileSources
)
if
err
!=
nil
{
return
nil
,
errors
.
Wrap
(
err
,
fmt
.
Sprintf
(
"file sources: %v"
,
args
.
FileSources
))
}
all
=
append
(
all
,
pairs
...
)
for
_
,
kv
:=
range
all
{
err
=
addKvToSecret
(
s
,
kv
.
Key
,
kv
.
Value
)
if
err
!=
nil
{
return
nil
,
err
}
}
if
options
!=
nil
{
s
.
SetLabels
(
options
.
Labels
)
s
.
SetAnnotations
(
options
.
Annotations
)
}
return
s
,
nil
}
func
addKvToSecret
(
secret
*
corev1
.
Secret
,
keyName
,
data
string
)
error
{
// Note, the rules for SecretKeys keys are the exact same as the ones for ConfigMap.
if
errs
:=
validation
.
IsConfigMapKey
(
keyName
);
len
(
errs
)
!=
0
{
return
fmt
.
Errorf
(
"%q is not a valid key name for a Secret: %s"
,
keyName
,
strings
.
Join
(
errs
,
";"
))
}
if
_
,
entryExists
:=
secret
.
Data
[
keyName
];
entryExists
{
return
fmt
.
Errorf
(
"cannot add key %s, another key by that name already exists"
,
keyName
)
}
secret
.
Data
[
keyName
]
=
[]
byte
(
data
)
return
nil
}
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/configmapandsecret/secretfactory_test.go
0 → 100644
View file @
74a64a9f
/*
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
configmapandsecret
import
(
"reflect"
"testing"
corev1
"k8s.io/api/core/v1"
metav1
"k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/loader"
"sigs.k8s.io/kustomize/pkg/types"
)
func
makeEnvSecret
(
name
string
)
*
corev1
.
Secret
{
return
&
corev1
.
Secret
{
TypeMeta
:
metav1
.
TypeMeta
{
APIVersion
:
"v1"
,
Kind
:
"Secret"
,
},
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
name
,
},
Data
:
map
[
string
][]
byte
{
"DB_PASSWORD"
:
[]
byte
(
"somepw"
),
"DB_USERNAME"
:
[]
byte
(
"admin"
),
},
Type
:
"Opaque"
,
}
}
func
makeFileSecret
(
name
string
)
*
corev1
.
Secret
{
return
&
corev1
.
Secret
{
TypeMeta
:
metav1
.
TypeMeta
{
APIVersion
:
"v1"
,
Kind
:
"Secret"
,
},
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
name
,
},
Data
:
map
[
string
][]
byte
{
"app-init.ini"
:
[]
byte
(
`FOO=bar
BAR=baz
`
),
},
Type
:
"Opaque"
,
}
}
func
makeLiteralSecret
(
name
string
)
*
corev1
.
Secret
{
s
:=
&
corev1
.
Secret
{
TypeMeta
:
metav1
.
TypeMeta
{
APIVersion
:
"v1"
,
Kind
:
"Secret"
,
},
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
name
,
},
Data
:
map
[
string
][]
byte
{
"a"
:
[]
byte
(
"x"
),
"b"
:
[]
byte
(
"y"
),
},
Type
:
"Opaque"
,
}
s
.
SetLabels
(
map
[
string
]
string
{
"foo"
:
"bar"
})
return
s
}
func
TestConstructSecret
(
t
*
testing
.
T
)
{
type
testCase
struct
{
description
string
input
types
.
SecretArgs
options
*
types
.
GeneratorOptions
expected
*
corev1
.
Secret
}
testCases
:=
[]
testCase
{
{
description
:
"construct secret from env"
,
input
:
types
.
SecretArgs
{
GeneratorArgs
:
types
.
GeneratorArgs
{
Name
:
"envSecret"
,
DataSources
:
types
.
DataSources
{
EnvSource
:
"secret/app.env"
,
},
},
},
options
:
nil
,
expected
:
makeEnvSecret
(
"envSecret"
),
},
{
description
:
"construct secret from file"
,
input
:
types
.
SecretArgs
{
GeneratorArgs
:
types
.
GeneratorArgs
{
Name
:
"fileSecret"
,
DataSources
:
types
.
DataSources
{
FileSources
:
[]
string
{
"secret/app-init.ini"
},
},
},
},
options
:
nil
,
expected
:
makeFileSecret
(
"fileSecret"
),
},
{
description
:
"construct secret from literal"
,
input
:
types
.
SecretArgs
{
GeneratorArgs
:
types
.
GeneratorArgs
{
Name
:
"literalSecret"
,
DataSources
:
types
.
DataSources
{
LiteralSources
:
[]
string
{
"a=x"
,
"b=y"
},
},
},
},
options
:
&
types
.
GeneratorOptions
{
Labels
:
map
[
string
]
string
{
"foo"
:
"bar"
,
},
},
expected
:
makeLiteralSecret
(
"literalSecret"
),
},
}
fSys
:=
fs
.
MakeFakeFS
()
fSys
.
WriteFile
(
"/secret/app.env"
,
[]
byte
(
"DB_USERNAME=admin
\n
DB_PASSWORD=somepw
\n
"
))
fSys
.
WriteFile
(
"/secret/app-init.ini"
,
[]
byte
(
"FOO=bar
\n
BAR=baz
\n
"
))
f
:=
NewSecretFactory
(
loader
.
NewFileLoaderAtRoot
(
fSys
))
for
_
,
tc
:=
range
testCases
{
cm
,
err
:=
f
.
MakeSecret
(
&
tc
.
input
,
tc
.
options
)
if
err
!=
nil
{
t
.
Fatalf
(
"unexpected error: %v"
,
err
)
}
if
!
reflect
.
DeepEqual
(
*
cm
,
*
tc
.
expected
)
{
t
.
Fatalf
(
"in testcase: %q updated:
\n
%#v
\n
doesn't match expected:
\n
%#v
\n
"
,
tc
.
description
,
*
cm
,
tc
.
expected
)
}
}
}
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/doc.go
0 → 100644
View file @
74a64a9f
/*
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.
*/
// It's possible that kustomize's features will be vendored into
// the kubernetes/kubernetes repo and made available to kubectl
// commands, while at the same time the kustomize program will
// continue to exist as an independent CLI. Vendoring snapshots
// would be taken just before a kubectl release.
//
// This creates a problem in that freestanding-kustomize depends on
// (for example):
//
// https://github.com/kubernetes/apimachinery/
// tree/master/pkg/util/yaml
//
// It vendors that package into
// sigs.k8s.io/kustomize/vendor/k8s.io/apimachinery/
//
// Whereas kubectl-kustomize would have to depend on the "staging"
// version of this code, located at
//
// https://github.com/kubernetes/kubernetes/
// blob/master/staging/src/k8s.io/apimachinery/pkg/util/yaml
//
// which is "vendored" via symlinks:
// k8s.io/kubernetes/vendor/k8s.io/apimachinery
// is a symlink to
// ../../staging/src/k8s.io/apimachinery
//
// The staging version is the canonical, under-development
// version of the code that kubectl depends on, whereas the packages
// at kubernetes/apimachinery are periodic snapshots of staging made
// for outside tools to depend on.
//
// apimachinery isn't the only package that poses this problem, just
// using it as a specific example.
//
// The kubectl binary cannot vendor in kustomize code that in
// turn vendors in the non-staging packages.
//
// One way to fix some of this would be to copy code - a hard fork.
// This has all the problems associated with a hard forking.
//
// Another way would be to break the kustomize repo into three:
//
// (1) kustomize - repo with the main() function,
// vendoring (2) and (3).
//
// (2) kustomize-libs - packages used by (1) with no
// apimachinery dependence.
//
// (3) kustomize-k8sdeps - A thin code layer that depends
// on (vendors) apimachinery to provide thin implementations
// to interfaces used in (2).
//
// The kubectl repo would then vendor from (2) only, and have
// a local implementation of (3). With that in mind, it's clear
// that (3) doesn't have to be a repo; the kustomize version of
// the thin layer can live directly in (1).
//
// This package is the code in (3), meant for kustomize.
package
k8sdeps
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/factory.go
0 → 100644
View file @
74a64a9f
/*
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 k8sdeps provides kustomize factory with k8s dependencies
package
k8sdeps
import
(
"k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kunstruct"
"k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer"
"k8s.io/cli-runtime/pkg/kustomize/k8sdeps/validator"
"sigs.k8s.io/kustomize/pkg/factory"
)
// NewFactory creates an instance of KustFactory using k8sdeps factories
func
NewFactory
()
*
factory
.
KustFactory
{
return
factory
.
NewKustFactory
(
kunstruct
.
NewKunstructuredFactoryImpl
(),
validator
.
NewKustValidator
(),
transformer
.
NewFactoryImpl
(),
)
}
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kunstruct/BUILD
0 → 100644
View file @
74a64a9f
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"factory.go",
"helper.go",
"kunstruct.go",
],
importmap = "k8s.io/kubernetes/vendor/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kunstruct",
importpath = "k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kunstruct",
visibility = ["//visibility:public"],
deps = [
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/yaml:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/configmapandsecret:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/gvk:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/ifc:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/types:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"factory_test.go",
"kunstruct_test.go",
],
embed = [":go_default_library"],
deps = ["//vendor/sigs.k8s.io/kustomize/pkg/ifc:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kunstruct/factory.go
0 → 100644
View file @
74a64a9f
/*
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
kunstruct
import
(
"bytes"
"fmt"
"io"
"strings"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/cli-runtime/pkg/kustomize/k8sdeps/configmapandsecret"
"sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/types"
)
// KunstructuredFactoryImpl hides construction using apimachinery types.
type
KunstructuredFactoryImpl
struct
{
cmFactory
*
configmapandsecret
.
ConfigMapFactory
secretFactory
*
configmapandsecret
.
SecretFactory
}
var
_
ifc
.
KunstructuredFactory
=
&
KunstructuredFactoryImpl
{}
// NewKunstructuredFactoryImpl returns a factory.
func
NewKunstructuredFactoryImpl
()
ifc
.
KunstructuredFactory
{
return
&
KunstructuredFactoryImpl
{}
}
// SliceFromBytes returns a slice of Kunstructured.
func
(
kf
*
KunstructuredFactoryImpl
)
SliceFromBytes
(
in
[]
byte
)
([]
ifc
.
Kunstructured
,
error
)
{
decoder
:=
yaml
.
NewYAMLOrJSONDecoder
(
bytes
.
NewReader
(
in
),
1024
)
var
result
[]
ifc
.
Kunstructured
var
err
error
for
err
==
nil
||
isEmptyYamlError
(
err
)
{
var
out
unstructured
.
Unstructured
err
=
decoder
.
Decode
(
&
out
)
if
err
==
nil
{
if
len
(
out
.
Object
)
==
0
{
continue
}
err
=
kf
.
validate
(
out
)
if
err
!=
nil
{
return
nil
,
err
}
result
=
append
(
result
,
&
UnstructAdapter
{
Unstructured
:
out
})
}
}
if
err
!=
io
.
EOF
{
return
nil
,
err
}
return
result
,
nil
}
func
isEmptyYamlError
(
err
error
)
bool
{
return
strings
.
Contains
(
err
.
Error
(),
"is missing in 'null'"
)
}
// FromMap returns an instance of Kunstructured.
func
(
kf
*
KunstructuredFactoryImpl
)
FromMap
(
m
map
[
string
]
interface
{})
ifc
.
Kunstructured
{
return
&
UnstructAdapter
{
Unstructured
:
unstructured
.
Unstructured
{
Object
:
m
}}
}
// MakeConfigMap returns an instance of Kunstructured for ConfigMap
func
(
kf
*
KunstructuredFactoryImpl
)
MakeConfigMap
(
args
*
types
.
ConfigMapArgs
,
options
*
types
.
GeneratorOptions
)
(
ifc
.
Kunstructured
,
error
)
{
cm
,
err
:=
kf
.
cmFactory
.
MakeConfigMap
(
args
,
options
)
if
err
!=
nil
{
return
nil
,
err
}
return
NewKunstructuredFromObject
(
cm
)
}
// MakeSecret returns an instance of Kunstructured for Secret
func
(
kf
*
KunstructuredFactoryImpl
)
MakeSecret
(
args
*
types
.
SecretArgs
,
options
*
types
.
GeneratorOptions
)
(
ifc
.
Kunstructured
,
error
)
{
sec
,
err
:=
kf
.
secretFactory
.
MakeSecret
(
args
,
options
)
if
err
!=
nil
{
return
nil
,
err
}
return
NewKunstructuredFromObject
(
sec
)
}
// Set sets loader
func
(
kf
*
KunstructuredFactoryImpl
)
Set
(
ldr
ifc
.
Loader
)
{
kf
.
cmFactory
=
configmapandsecret
.
NewConfigMapFactory
(
ldr
)
kf
.
secretFactory
=
configmapandsecret
.
NewSecretFactory
(
ldr
)
}
// validate validates that u has kind and name
// except for kind `List`, which doesn't require a name
func
(
kf
*
KunstructuredFactoryImpl
)
validate
(
u
unstructured
.
Unstructured
)
error
{
kind
:=
u
.
GetKind
()
if
kind
==
""
{
return
fmt
.
Errorf
(
"missing kind in object %v"
,
u
)
}
else
if
kind
==
"List"
{
return
nil
}
if
u
.
GetName
()
==
""
{
return
fmt
.
Errorf
(
"missing metadata.name in object %v"
,
u
)
}
return
nil
}
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kunstruct/factory_test.go
0 → 100644
View file @
74a64a9f
/*
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
kunstruct
import
(
"reflect"
"testing"
"sigs.k8s.io/kustomize/pkg/ifc"
)
func
TestSliceFromBytes
(
t
*
testing
.
T
)
{
factory
:=
NewKunstructuredFactoryImpl
()
testConfigMap
:=
factory
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"v1"
,
"kind"
:
"ConfigMap"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"winnie"
,
},
})
testList
:=
factory
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"v1"
,
"kind"
:
"List"
,
"items"
:
[]
interface
{}{
testConfigMap
.
Map
(),
testConfigMap
.
Map
(),
},
})
tests
:=
[]
struct
{
name
string
input
[]
byte
expectedOut
[]
ifc
.
Kunstructured
expectedErr
bool
}{
{
name
:
"garbage"
,
input
:
[]
byte
(
"garbageIn: garbageOut"
),
expectedOut
:
[]
ifc
.
Kunstructured
{},
expectedErr
:
true
,
},
{
name
:
"noBytes"
,
input
:
[]
byte
{},
expectedOut
:
[]
ifc
.
Kunstructured
{},
expectedErr
:
false
,
},
{
name
:
"goodJson"
,
input
:
[]
byte
(
`
{"apiVersion":"v1","kind":"ConfigMap","metadata":{"name":"winnie"}}
`
),
expectedOut
:
[]
ifc
.
Kunstructured
{
testConfigMap
},
expectedErr
:
false
,
},
{
name
:
"goodYaml1"
,
input
:
[]
byte
(
`
apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
`
),
expectedOut
:
[]
ifc
.
Kunstructured
{
testConfigMap
},
expectedErr
:
false
,
},
{
name
:
"goodYaml2"
,
input
:
[]
byte
(
`
apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
---
apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
`
),
expectedOut
:
[]
ifc
.
Kunstructured
{
testConfigMap
,
testConfigMap
},
expectedErr
:
false
,
},
{
name
:
"garbageInOneOfTwoObjects"
,
input
:
[]
byte
(
`
apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
---
WOOOOOOOOOOOOOOOOOOOOOOOOT: woot
`
),
expectedOut
:
[]
ifc
.
Kunstructured
{},
expectedErr
:
true
,
},
{
name
:
"emptyObjects"
,
input
:
[]
byte
(
`
---
#a comment
---
`
),
expectedOut
:
[]
ifc
.
Kunstructured
{},
expectedErr
:
false
,
},
{
name
:
"Missing .metadata.name in object"
,
input
:
[]
byte
(
`
apiVersion: v1
kind: Namespace
metadata:
annotations:
foo: bar
`
),
expectedOut
:
nil
,
expectedErr
:
true
,
},
{
name
:
"List"
,
input
:
[]
byte
(
`
apiVersion: v1
kind: List
items:
- apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
- apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
`
),
expectedOut
:
[]
ifc
.
Kunstructured
{
testList
},
expectedErr
:
false
,
},
}
for
_
,
test
:=
range
tests
{
rs
,
err
:=
factory
.
SliceFromBytes
(
test
.
input
)
if
test
.
expectedErr
&&
err
==
nil
{
t
.
Fatalf
(
"%v: should return error"
,
test
.
name
)
}
if
!
test
.
expectedErr
&&
err
!=
nil
{
t
.
Fatalf
(
"%v: unexpected error: %s"
,
test
.
name
,
err
)
}
if
len
(
rs
)
!=
len
(
test
.
expectedOut
)
{
t
.
Fatalf
(
"%s: length mismatch %d != %d"
,
test
.
name
,
len
(
rs
),
len
(
test
.
expectedOut
))
}
for
i
:=
range
rs
{
if
!
reflect
.
DeepEqual
(
test
.
expectedOut
[
i
],
rs
[
i
])
{
t
.
Fatalf
(
"%s: Got: %v
\n
expected:%v"
,
test
.
name
,
test
.
expectedOut
[
i
],
rs
[
i
])
}
}
}
}
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kunstruct/helper.go
0 → 100644
View file @
74a64a9f
/*
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 kunstruct provides unstructured from api machinery and factory for creating unstructured
package
kunstruct
import
(
"fmt"
"strings"
)
func
parseFields
(
path
string
)
([]
string
,
error
)
{
if
!
strings
.
Contains
(
path
,
"["
)
{
return
strings
.
Split
(
path
,
"."
),
nil
}
var
fields
[]
string
start
:=
0
insideParentheses
:=
false
for
i
:=
range
path
{
switch
path
[
i
]
{
case
'.'
:
if
!
insideParentheses
{
fields
=
append
(
fields
,
path
[
start
:
i
])
start
=
i
+
1
}
case
'['
:
if
!
insideParentheses
{
if
i
==
start
{
start
=
i
+
1
}
else
{
fields
=
append
(
fields
,
path
[
start
:
i
])
start
=
i
+
1
}
insideParentheses
=
true
}
else
{
return
nil
,
fmt
.
Errorf
(
"nested parentheses are not allowed: %s"
,
path
)
}
case
']'
:
if
insideParentheses
{
fields
=
append
(
fields
,
path
[
start
:
i
])
start
=
i
+
1
insideParentheses
=
false
}
else
{
return
nil
,
fmt
.
Errorf
(
"invalid field path %s"
,
path
)
}
}
}
if
start
<
len
(
path
)
-
1
{
fields
=
append
(
fields
,
path
[
start
:
])
}
for
i
,
f
:=
range
fields
{
if
strings
.
HasPrefix
(
f
,
"
\"
"
)
||
strings
.
HasPrefix
(
f
,
"'"
)
{
fields
[
i
]
=
strings
.
Trim
(
f
,
"
\"
'"
)
}
}
return
fields
,
nil
}
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kunstruct/kunstruct.go
0 → 100644
View file @
74a64a9f
/*
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 kunstruct provides unstructured from api machinery and factory for creating unstructured
package
kunstruct
import
(
"encoding/json"
"fmt"
metav1
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/kustomize/pkg/gvk"
"sigs.k8s.io/kustomize/pkg/ifc"
)
var
_
ifc
.
Kunstructured
=
&
UnstructAdapter
{}
// UnstructAdapter wraps unstructured.Unstructured from
// https://github.com/kubernetes/apimachinery/blob/master/
// pkg/apis/meta/v1/unstructured/unstructured.go
// to isolate dependence on apimachinery.
type
UnstructAdapter
struct
{
unstructured
.
Unstructured
}
// NewKunstructuredFromObject returns a new instance of Kunstructured.
func
NewKunstructuredFromObject
(
obj
runtime
.
Object
)
(
ifc
.
Kunstructured
,
error
)
{
// Convert obj to a byte stream, then convert that to JSON (Unstructured).
marshaled
,
err
:=
json
.
Marshal
(
obj
)
if
err
!=
nil
{
return
&
UnstructAdapter
{},
err
}
var
u
unstructured
.
Unstructured
err
=
u
.
UnmarshalJSON
(
marshaled
)
// creationTimestamp always 'null', remove it
u
.
SetCreationTimestamp
(
metav1
.
Time
{})
return
&
UnstructAdapter
{
Unstructured
:
u
},
err
}
// GetGvk returns the Gvk name of the object.
func
(
fs
*
UnstructAdapter
)
GetGvk
()
gvk
.
Gvk
{
x
:=
fs
.
GroupVersionKind
()
return
gvk
.
Gvk
{
Group
:
x
.
Group
,
Version
:
x
.
Version
,
Kind
:
x
.
Kind
,
}
}
// Copy provides a copy behind an interface.
func
(
fs
*
UnstructAdapter
)
Copy
()
ifc
.
Kunstructured
{
return
&
UnstructAdapter
{
*
fs
.
DeepCopy
()}
}
// Map returns the unstructured content map.
func
(
fs
*
UnstructAdapter
)
Map
()
map
[
string
]
interface
{}
{
return
fs
.
Object
}
// SetMap overrides the unstructured content map.
func
(
fs
*
UnstructAdapter
)
SetMap
(
m
map
[
string
]
interface
{})
{
fs
.
Object
=
m
}
// GetFieldValue returns value at the given fieldpath.
func
(
fs
*
UnstructAdapter
)
GetFieldValue
(
path
string
)
(
string
,
error
)
{
fields
,
err
:=
parseFields
(
path
)
if
err
!=
nil
{
return
""
,
err
}
s
,
found
,
err
:=
unstructured
.
NestedString
(
fs
.
UnstructuredContent
(),
fields
...
)
if
found
||
err
!=
nil
{
return
s
,
err
}
return
""
,
fmt
.
Errorf
(
"no field named '%s'"
,
path
)
}
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kunstruct/kunstruct_test.go
0 → 100644
View file @
74a64a9f
/*
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
kunstruct
import
(
"testing"
)
func
TestGetFieldValue
(
t
*
testing
.
T
)
{
factory
:=
NewKunstructuredFactoryImpl
()
kunstructured
:=
factory
.
FromMap
(
map
[
string
]
interface
{}{
"Kind"
:
"Service"
,
"metadata"
:
map
[
string
]
interface
{}{
"labels"
:
map
[
string
]
string
{
"app"
:
"application-name"
,
},
"name"
:
"service-name"
,
},
"spec"
:
map
[
string
]
interface
{}{
"ports"
:
map
[
string
]
interface
{}{
"port"
:
"80"
,
},
},
"this"
:
map
[
string
]
interface
{}{
"is"
:
map
[
string
]
interface
{}{
"aNumber"
:
1000
,
"aNilValue"
:
nil
,
"anEmptyMap"
:
map
[
string
]
interface
{}{},
"unrecognizable"
:
testing
.
InternalExample
{
Name
:
"fooBar"
,
},
},
},
})
tests
:=
[]
struct
{
name
string
pathToField
string
expectedValue
string
errorExpected
bool
errorMsg
string
}{
{
name
:
"oneField"
,
pathToField
:
"Kind"
,
expectedValue
:
"Service"
,
errorExpected
:
false
,
},
{
name
:
"twoFields"
,
pathToField
:
"metadata.name"
,
expectedValue
:
"service-name"
,
errorExpected
:
false
,
},
{
name
:
"threeFields"
,
pathToField
:
"spec.ports.port"
,
expectedValue
:
"80"
,
errorExpected
:
false
,
},
{
name
:
"empty"
,
pathToField
:
""
,
errorExpected
:
true
,
errorMsg
:
"no field named ''"
,
},
{
name
:
"emptyDotEmpty"
,
pathToField
:
"."
,
errorExpected
:
true
,
errorMsg
:
"no field named '.'"
,
},
{
name
:
"twoFieldsOneMissing"
,
pathToField
:
"metadata.banana"
,
errorExpected
:
true
,
errorMsg
:
"no field named 'metadata.banana'"
,
},
{
name
:
"deeperMissingField"
,
pathToField
:
"this.is.aDeep.field.that.does.not.exist"
,
errorExpected
:
true
,
errorMsg
:
"no field named 'this.is.aDeep.field.that.does.not.exist'"
,
},
{
name
:
"emptyMap"
,
pathToField
:
"this.is.anEmptyMap"
,
errorExpected
:
true
,
errorMsg
:
".this.is.anEmptyMap accessor error: map[] is of the type map[string]interface {}, expected string"
,
},
{
name
:
"numberAsValue"
,
pathToField
:
"this.is.aNumber"
,
errorExpected
:
true
,
errorMsg
:
".this.is.aNumber accessor error: 1000 is of the type int, expected string"
,
},
{
name
:
"nilAsValue"
,
pathToField
:
"this.is.aNilValue"
,
errorExpected
:
true
,
errorMsg
:
".this.is.aNilValue accessor error: <nil> is of the type <nil>, expected string"
,
},
{
name
:
"unrecognizable"
,
pathToField
:
"this.is.unrecognizable.Name"
,
errorExpected
:
true
,
errorMsg
:
".this.is.unrecognizable.Name accessor error: {fooBar <nil> false} is of the type testing.InternalExample, expected map[string]interface{}"
,
},
}
for
_
,
test
:=
range
tests
{
s
,
err
:=
kunstructured
.
GetFieldValue
(
test
.
pathToField
)
if
test
.
errorExpected
{
if
err
==
nil
{
t
.
Fatalf
(
"%q; path %q - should return error, but no error returned"
,
test
.
name
,
test
.
pathToField
)
}
if
test
.
errorMsg
!=
err
.
Error
()
{
t
.
Fatalf
(
"%q; path %q - expected error:
\"
%s
\"
, got error:
\"
%v
\"
"
,
test
.
name
,
test
.
pathToField
,
test
.
errorMsg
,
err
.
Error
())
}
continue
}
if
err
!=
nil
{
t
.
Fatalf
(
"%q; path %q - unexpected error %v"
,
test
.
name
,
test
.
pathToField
,
err
)
}
if
test
.
expectedValue
!=
s
{
t
.
Fatalf
(
"%q; Got: %s expected: %s"
,
test
.
name
,
s
,
test
.
expectedValue
)
}
}
}
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kv/BUILD
0 → 100644
View file @
74a64a9f
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = ["kv.go"],
importmap = "k8s.io/kubernetes/vendor/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kv",
importpath = "k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kv",
visibility = ["//visibility:public"],
deps = ["//staging/src/k8s.io/apimachinery/pkg/util/validation:go_default_library"],
)
go_test(
name = "go_default_test",
srcs = ["kv_test.go"],
embed = [":go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kv/kv.go
0 → 100644
View file @
74a64a9f
/*
Copyright 2019 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
kv
import
(
"bufio"
"bytes"
"fmt"
"os"
"strings"
"unicode"
"unicode/utf8"
"k8s.io/apimachinery/pkg/util/validation"
)
// Pair represents a <key, value> pair.
type
Pair
struct
{
Key
string
Value
string
}
var
utf8bom
=
[]
byte
{
0xEF
,
0xBB
,
0xBF
}
// KeyValuesFromLines parses given content in to a list of key-value pairs.
func
KeyValuesFromLines
(
content
[]
byte
)
([]
Pair
,
error
)
{
var
kvs
[]
Pair
scanner
:=
bufio
.
NewScanner
(
bytes
.
NewReader
(
content
))
currentLine
:=
0
for
scanner
.
Scan
()
{
// Process the current line, retrieving a key/value pair if
// possible.
scannedBytes
:=
scanner
.
Bytes
()
kv
,
err
:=
KeyValuesFromLine
(
scannedBytes
,
currentLine
)
if
err
!=
nil
{
return
nil
,
err
}
currentLine
++
if
len
(
kv
.
Key
)
==
0
{
// no key means line was empty or a comment
continue
}
kvs
=
append
(
kvs
,
kv
)
}
return
kvs
,
nil
}
// KeyValuesFromLine returns a kv with blank key if the line is empty or a comment.
// The value will be retrieved from the environment if necessary.
func
KeyValuesFromLine
(
line
[]
byte
,
currentLine
int
)
(
Pair
,
error
)
{
kv
:=
Pair
{}
if
!
utf8
.
Valid
(
line
)
{
return
kv
,
fmt
.
Errorf
(
"line %d has invalid utf8 bytes : %v"
,
line
,
string
(
line
))
}
// We trim UTF8 BOM from the first line of the file but no others
if
currentLine
==
0
{
line
=
bytes
.
TrimPrefix
(
line
,
utf8bom
)
}
// trim the line from all leading whitespace first
line
=
bytes
.
TrimLeftFunc
(
line
,
unicode
.
IsSpace
)
// If the line is empty or a comment, we return a blank key/value pair.
if
len
(
line
)
==
0
||
line
[
0
]
==
'#'
{
return
kv
,
nil
}
data
:=
strings
.
SplitN
(
string
(
line
),
"="
,
2
)
key
:=
data
[
0
]
if
errs
:=
validation
.
IsEnvVarName
(
key
);
len
(
errs
)
!=
0
{
return
kv
,
fmt
.
Errorf
(
"%q is not a valid key name: %s"
,
key
,
strings
.
Join
(
errs
,
";"
))
}
if
len
(
data
)
==
2
{
kv
.
Value
=
data
[
1
]
}
else
{
// No value (no `=` in the line) is a signal to obtain the value
// from the environment.
kv
.
Value
=
os
.
Getenv
(
key
)
}
kv
.
Key
=
key
return
kv
,
nil
}
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kv/kv_test.go
0 → 100644
View file @
74a64a9f
/*
Copyright 2019 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
kv
import
(
"reflect"
"testing"
)
func
TestKeyValuesFromLines
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
desc
string
content
string
expectedPairs
[]
Pair
expectedErr
bool
}{
{
desc
:
"valid kv content parse"
,
content
:
`
k1=v1
k2=v2
`
,
expectedPairs
:
[]
Pair
{
{
Key
:
"k1"
,
Value
:
"v1"
},
{
Key
:
"k2"
,
Value
:
"v2"
},
},
expectedErr
:
false
,
},
{
desc
:
"content with comments"
,
content
:
`
k1=v1
#k2=v2
`
,
expectedPairs
:
[]
Pair
{
{
Key
:
"k1"
,
Value
:
"v1"
},
},
expectedErr
:
false
,
},
// TODO: add negative testcases
}
for
_
,
test
:=
range
tests
{
pairs
,
err
:=
KeyValuesFromLines
([]
byte
(
test
.
content
))
if
test
.
expectedErr
&&
err
==
nil
{
t
.
Fatalf
(
"%s should not return error"
,
test
.
desc
)
}
if
!
reflect
.
DeepEqual
(
pairs
,
test
.
expectedPairs
)
{
t
.
Errorf
(
"%s should succeed, got:%v exptected:%v"
,
test
.
desc
,
pairs
,
test
.
expectedPairs
)
}
}
}
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/BUILD
0 → 100644
View file @
74a64a9f
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["factory.go"],
importmap = "k8s.io/kubernetes/vendor/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer",
importpath = "k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer",
visibility = ["//visibility:public"],
deps = [
"//staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/hash:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/patch:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/resource:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/transformers:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/hash:all-srcs",
"//staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/patch:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/factory.go
0 → 100644
View file @
74a64a9f
/*
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 transformer provides transformer factory
package
transformer
import
(
"k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/hash"
"k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/patch"
"sigs.k8s.io/kustomize/pkg/resource"
"sigs.k8s.io/kustomize/pkg/transformers"
)
// FactoryImpl makes patch transformer and name hash transformer
type
FactoryImpl
struct
{}
// NewFactoryImpl makes a new factoryImpl instance
func
NewFactoryImpl
()
*
FactoryImpl
{
return
&
FactoryImpl
{}
}
// MakePatchTransformer makes a new patch transformer
func
(
p
*
FactoryImpl
)
MakePatchTransformer
(
slice
[]
*
resource
.
Resource
,
rf
*
resource
.
Factory
)
(
transformers
.
Transformer
,
error
)
{
return
patch
.
NewPatchTransformer
(
slice
,
rf
)
}
// MakeHashTransformer makes a new name hash transformer
func
(
p
*
FactoryImpl
)
MakeHashTransformer
()
transformers
.
Transformer
{
return
hash
.
NewNameHashTransformer
()
}
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/hash/BUILD
0 → 100644
View file @
74a64a9f
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"hash.go",
"namehash.go",
],
importmap = "k8s.io/kubernetes/vendor/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/hash",
importpath = "k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/hash",
visibility = ["//visibility:public"],
deps = [
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/resmap:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/transformers:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"hash_test.go",
"namehash_test.go",
],
embed = [":go_default_library"],
deps = [
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kunstruct:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/gvk:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/resid:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/resmap:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/resource:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/types:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/hash/hash.go
0 → 100644
View file @
74a64a9f
/*
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"
"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
}
// 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
}
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/hash/hash_test.go
0 → 100644
View file @
74a64a9f
/*
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
(
"reflect"
"strings"
"testing"
"k8s.io/api/core/v1"
"sigs.k8s.io/kustomize/pkg/gvk"
)
var
service
=
gvk
.
Gvk
{
Version
:
"v1"
,
Kind
:
"Service"
}
var
secret
=
gvk
.
Gvk
{
Version
:
"v1"
,
Kind
:
"Secret"
}
var
cmap
=
gvk
.
Gvk
{
Version
:
"v1"
,
Kind
:
"ConfigMap"
}
var
deploy
=
gvk
.
Gvk
{
Group
:
"apps"
,
Version
:
"v1"
,
Kind
:
"Deployment"
}
func
TestConfigMapHash
(
t
*
testing
.
T
)
{
cases
:=
[]
struct
{
desc
string
cm
*
v1
.
ConfigMap
hash
string
err
string
}{
// empty map
{
"empty data"
,
&
v1
.
ConfigMap
{
Data
:
map
[
string
]
string
{},
BinaryData
:
map
[
string
][]
byte
{}},
"42745tchd9"
,
""
},
// one key
{
"one key"
,
&
v1
.
ConfigMap
{
Data
:
map
[
string
]
string
{
"one"
:
""
}},
"9g67k2htb6"
,
""
},
// three keys (tests sorting order)
{
"three keys"
,
&
v1
.
ConfigMap
{
Data
:
map
[
string
]
string
{
"two"
:
"2"
,
"one"
:
""
,
"three"
:
"3"
}},
"f5h7t85m9b"
,
""
},
// empty binary data map
{
"empty binary data"
,
&
v1
.
ConfigMap
{
BinaryData
:
map
[
string
][]
byte
{}},
"dk855m5d49"
,
""
},
// one key with binary data
{
"one key with binary data"
,
&
v1
.
ConfigMap
{
BinaryData
:
map
[
string
][]
byte
{
"one"
:
[]
byte
(
""
)}},
"mk79584b8c"
,
""
},
// three keys with binary data (tests sorting order)
{
"three keys with binary data"
,
&
v1
.
ConfigMap
{
BinaryData
:
map
[
string
][]
byte
{
"two"
:
[]
byte
(
"2"
),
"one"
:
[]
byte
(
""
),
"three"
:
[]
byte
(
"3"
)}},
"t458mc6db2"
,
""
},
// two keys, one with string and another with binary data
{
"two keys with one each"
,
&
v1
.
ConfigMap
{
Data
:
map
[
string
]
string
{
"one"
:
""
},
BinaryData
:
map
[
string
][]
byte
{
"two"
:
[]
byte
(
""
)}},
"698h7c7t9m"
,
""
},
}
for
_
,
c
:=
range
cases
{
h
,
err
:=
ConfigMapHash
(
c
.
cm
)
if
SkipRest
(
t
,
c
.
desc
,
err
,
c
.
err
)
{
continue
}
if
c
.
hash
!=
h
{
t
.
Errorf
(
"case %q, expect hash %q but got %q"
,
c
.
desc
,
c
.
hash
,
h
)
}
}
}
func
TestSecretHash
(
t
*
testing
.
T
)
{
cases
:=
[]
struct
{
desc
string
secret
*
v1
.
Secret
hash
string
err
string
}{
// empty map
{
"empty data"
,
&
v1
.
Secret
{
Type
:
"my-type"
,
Data
:
map
[
string
][]
byte
{}},
"t75bgf6ctb"
,
""
},
// one key
{
"one key"
,
&
v1
.
Secret
{
Type
:
"my-type"
,
Data
:
map
[
string
][]
byte
{
"one"
:
[]
byte
(
""
)}},
"74bd68bm66"
,
""
},
// three keys (tests sorting order)
{
"three keys"
,
&
v1
.
Secret
{
Type
:
"my-type"
,
Data
:
map
[
string
][]
byte
{
"two"
:
[]
byte
(
"2"
),
"one"
:
[]
byte
(
""
),
"three"
:
[]
byte
(
"3"
)}},
"dgcb6h9tmk"
,
""
},
}
for
_
,
c
:=
range
cases
{
h
,
err
:=
SecretHash
(
c
.
secret
)
if
SkipRest
(
t
,
c
.
desc
,
err
,
c
.
err
)
{
continue
}
if
c
.
hash
!=
h
{
t
.
Errorf
(
"case %q, expect hash %q but got %q"
,
c
.
desc
,
c
.
hash
,
h
)
}
}
}
func
TestEncodeConfigMap
(
t
*
testing
.
T
)
{
cases
:=
[]
struct
{
desc
string
cm
*
v1
.
ConfigMap
expect
string
err
string
}{
// empty map
{
"empty data"
,
&
v1
.
ConfigMap
{
Data
:
map
[
string
]
string
{}},
`{"data":{},"kind":"ConfigMap","name":""}`
,
""
},
// one key
{
"one key"
,
&
v1
.
ConfigMap
{
Data
:
map
[
string
]
string
{
"one"
:
""
}},
`{"data":{"one":""},"kind":"ConfigMap","name":""}`
,
""
},
// three keys (tests sorting order)
{
"three keys"
,
&
v1
.
ConfigMap
{
Data
:
map
[
string
]
string
{
"two"
:
"2"
,
"one"
:
""
,
"three"
:
"3"
}},
`{"data":{"one":"","three":"3","two":"2"},"kind":"ConfigMap","name":""}`
,
""
},
// empty binary map
{
"empty data"
,
&
v1
.
ConfigMap
{
BinaryData
:
map
[
string
][]
byte
{}},
`{"data":null,"kind":"ConfigMap","name":""}`
,
""
},
// one key with binary data
{
"one key"
,
&
v1
.
ConfigMap
{
BinaryData
:
map
[
string
][]
byte
{
"one"
:
[]
byte
(
""
)}},
`{"binaryData":{"one":""},"data":null,"kind":"ConfigMap","name":""}`
,
""
},
// three keys with binary data (tests sorting order)
{
"three keys"
,
&
v1
.
ConfigMap
{
BinaryData
:
map
[
string
][]
byte
{
"two"
:
[]
byte
(
"2"
),
"one"
:
[]
byte
(
""
),
"three"
:
[]
byte
(
"3"
)}},
`{"binaryData":{"one":"","three":"Mw==","two":"Mg=="},"data":null,"kind":"ConfigMap","name":""}`
,
""
},
// two keys, one string and one binary values
{
"two keys with one each"
,
&
v1
.
ConfigMap
{
Data
:
map
[
string
]
string
{
"one"
:
""
},
BinaryData
:
map
[
string
][]
byte
{
"two"
:
[]
byte
(
""
)}},
`{"binaryData":{"two":""},"data":{"one":""},"kind":"ConfigMap","name":""}`
,
""
},
}
for
_
,
c
:=
range
cases
{
s
,
err
:=
encodeConfigMap
(
c
.
cm
)
if
SkipRest
(
t
,
c
.
desc
,
err
,
c
.
err
)
{
continue
}
if
s
!=
c
.
expect
{
t
.
Errorf
(
"case %q, expect %q but got %q from encode %#v"
,
c
.
desc
,
c
.
expect
,
s
,
c
.
cm
)
}
}
}
func
TestEncodeSecret
(
t
*
testing
.
T
)
{
cases
:=
[]
struct
{
desc
string
secret
*
v1
.
Secret
expect
string
err
string
}{
// empty map
{
"empty data"
,
&
v1
.
Secret
{
Type
:
"my-type"
,
Data
:
map
[
string
][]
byte
{}},
`{"data":{},"kind":"Secret","name":"","type":"my-type"}`
,
""
},
// one key
{
"one key"
,
&
v1
.
Secret
{
Type
:
"my-type"
,
Data
:
map
[
string
][]
byte
{
"one"
:
[]
byte
(
""
)}},
`{"data":{"one":""},"kind":"Secret","name":"","type":"my-type"}`
,
""
},
// three keys (tests sorting order) - note json.Marshal base64 encodes the values because they come in as []byte
{
"three keys"
,
&
v1
.
Secret
{
Type
:
"my-type"
,
Data
:
map
[
string
][]
byte
{
"two"
:
[]
byte
(
"2"
),
"one"
:
[]
byte
(
""
),
"three"
:
[]
byte
(
"3"
)},
},
`{"data":{"one":"","three":"Mw==","two":"Mg=="},"kind":"Secret","name":"","type":"my-type"}`
,
""
},
}
for
_
,
c
:=
range
cases
{
s
,
err
:=
encodeSecret
(
c
.
secret
)
if
SkipRest
(
t
,
c
.
desc
,
err
,
c
.
err
)
{
continue
}
if
s
!=
c
.
expect
{
t
.
Errorf
(
"case %q, expect %q but got %q from encode %#v"
,
c
.
desc
,
c
.
expect
,
s
,
c
.
secret
)
}
}
}
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
// not perfect, as it only checks the number of top-level fields
func
TestTypeStability
(
t
*
testing
.
T
)
{
errfmt
:=
`case %q, expected %d fields but got %d
Depending on the field(s) you added, you may need to modify the hash function for this type.
To guide you: the hash function targets fields that comprise the contents of objects,
not their metadata (e.g. the Data of a ConfigMap, but nothing in ObjectMeta).
`
cases
:=
[]
struct
{
typeName
string
obj
interface
{}
expect
int
}{
{
"ConfigMap"
,
v1
.
ConfigMap
{},
4
},
{
"Secret"
,
v1
.
Secret
{},
5
},
}
for
_
,
c
:=
range
cases
{
val
:=
reflect
.
ValueOf
(
c
.
obj
)
if
num
:=
val
.
NumField
();
c
.
expect
!=
num
{
t
.
Errorf
(
errfmt
,
c
.
typeName
,
c
.
expect
,
num
)
}
}
}
// SkipRest returns true if there was a non-nil error or if we expected an error that didn't happen,
// and logs the appropriate error on the test object.
// The return value indicates whether we should skip the rest of the test case due to the error result.
func
SkipRest
(
t
*
testing
.
T
,
desc
string
,
err
error
,
contains
string
)
bool
{
if
err
!=
nil
{
if
len
(
contains
)
==
0
{
t
.
Errorf
(
"case %q, expect nil error but got %q"
,
desc
,
err
.
Error
())
}
else
if
!
strings
.
Contains
(
err
.
Error
(),
contains
)
{
t
.
Errorf
(
"case %q, expect error to contain %q but got %q"
,
desc
,
contains
,
err
.
Error
())
}
return
true
}
else
if
len
(
contains
)
>
0
{
t
.
Errorf
(
"case %q, expect error to contain %q but got nil error"
,
desc
,
contains
)
return
true
}
return
false
}
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/hash/namehash.go
0 → 100644
View file @
74a64a9f
/*
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
}
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/hash/namehash_test.go
0 → 100644
View file @
74a64a9f
/*
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
(
"reflect"
"testing"
"k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/pkg/resid"
"sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/resource"
"sigs.k8s.io/kustomize/pkg/types"
)
func
TestNameHashTransformer
(
t
*
testing
.
T
)
{
rf
:=
resource
.
NewFactory
(
kunstruct
.
NewKunstructuredFactoryImpl
())
objs
:=
resmap
.
ResMap
{
resid
.
NewResId
(
cmap
,
"cm1"
)
:
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"v1"
,
"kind"
:
"ConfigMap"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"cm1"
,
},
}),
resid
.
NewResId
(
deploy
,
"deploy1"
)
:
rf
.
FromMap
(
map
[
string
]
interface
{}{
"group"
:
"apps"
,
"apiVersion"
:
"v1"
,
"kind"
:
"Deployment"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"deploy1"
,
},
"spec"
:
map
[
string
]
interface
{}{
"template"
:
map
[
string
]
interface
{}{
"metadata"
:
map
[
string
]
interface
{}{
"labels"
:
map
[
string
]
interface
{}{
"old-label"
:
"old-value"
,
},
},
"spec"
:
map
[
string
]
interface
{}{
"containers"
:
[]
interface
{}{
map
[
string
]
interface
{}{
"name"
:
"nginx"
,
"image"
:
"nginx:1.7.9"
,
},
},
},
},
},
}),
resid
.
NewResId
(
service
,
"svc1"
)
:
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"v1"
,
"kind"
:
"Service"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"svc1"
,
},
"spec"
:
map
[
string
]
interface
{}{
"ports"
:
[]
interface
{}{
map
[
string
]
interface
{}{
"name"
:
"port1"
,
"port"
:
"12345"
,
},
},
},
}),
resid
.
NewResId
(
secret
,
"secret1"
)
:
rf
.
FromMapAndOption
(
map
[
string
]
interface
{}{
"apiVersion"
:
"v1"
,
"kind"
:
"Secret"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"secret1"
,
},
},
&
types
.
GeneratorArgs
{
Behavior
:
"create"
},
&
types
.
GeneratorOptions
{
DisableNameSuffixHash
:
false
}),
}
expected
:=
resmap
.
ResMap
{
resid
.
NewResId
(
cmap
,
"cm1"
)
:
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"v1"
,
"kind"
:
"ConfigMap"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"cm1"
,
},
}),
resid
.
NewResId
(
deploy
,
"deploy1"
)
:
rf
.
FromMap
(
map
[
string
]
interface
{}{
"group"
:
"apps"
,
"apiVersion"
:
"v1"
,
"kind"
:
"Deployment"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"deploy1"
,
},
"spec"
:
map
[
string
]
interface
{}{
"template"
:
map
[
string
]
interface
{}{
"metadata"
:
map
[
string
]
interface
{}{
"labels"
:
map
[
string
]
interface
{}{
"old-label"
:
"old-value"
,
},
},
"spec"
:
map
[
string
]
interface
{}{
"containers"
:
[]
interface
{}{
map
[
string
]
interface
{}{
"name"
:
"nginx"
,
"image"
:
"nginx:1.7.9"
,
},
},
},
},
},
}),
resid
.
NewResId
(
service
,
"svc1"
)
:
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"v1"
,
"kind"
:
"Service"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"svc1"
,
},
"spec"
:
map
[
string
]
interface
{}{
"ports"
:
[]
interface
{}{
map
[
string
]
interface
{}{
"name"
:
"port1"
,
"port"
:
"12345"
,
},
},
},
}),
resid
.
NewResId
(
secret
,
"secret1"
)
:
rf
.
FromMapAndOption
(
map
[
string
]
interface
{}{
"apiVersion"
:
"v1"
,
"kind"
:
"Secret"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"secret1-7kc45hd5f7"
,
},
},
&
types
.
GeneratorArgs
{
Behavior
:
"create"
},
&
types
.
GeneratorOptions
{
DisableNameSuffixHash
:
false
}),
}
tran
:=
NewNameHashTransformer
()
tran
.
Transform
(
objs
)
if
!
reflect
.
DeepEqual
(
objs
,
expected
)
{
err
:=
expected
.
ErrorIfNotEqual
(
objs
)
t
.
Fatalf
(
"actual doesn't match expected: %v"
,
err
)
}
}
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/patch/BUILD
0 → 100644
View file @
74a64a9f
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"patch.go",
"patchconflictdetector.go",
],
importmap = "k8s.io/kubernetes/vendor/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/patch",
importpath = "k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/patch",
visibility = ["//visibility:public"],
deps = [
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/mergepatch:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library",
"//vendor/github.com/evanphx/json-patch:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/gvk:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/resmap:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/resource:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/transformers:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["patch_test.go"],
embed = [":go_default_library"],
deps = [
"//staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kunstruct:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/gvk:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/resid:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/resmap:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/resource:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/patch/patch.go
0 → 100644
View file @
74a64a9f
/*
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
patch
import
(
"encoding/json"
"fmt"
"github.com/evanphx/json-patch"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/strategicpatch"
"k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/kustomize/pkg/gvk"
"sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/resource"
"sigs.k8s.io/kustomize/pkg/transformers"
)
// patchTransformer applies patches.
type
patchTransformer
struct
{
patches
[]
*
resource
.
Resource
rf
*
resource
.
Factory
}
var
_
transformers
.
Transformer
=
&
patchTransformer
{}
// NewPatchTransformer constructs a patchTransformer.
func
NewPatchTransformer
(
slice
[]
*
resource
.
Resource
,
rf
*
resource
.
Factory
)
(
transformers
.
Transformer
,
error
)
{
if
len
(
slice
)
==
0
{
return
transformers
.
NewNoOpTransformer
(),
nil
}
return
&
patchTransformer
{
patches
:
slice
,
rf
:
rf
},
nil
}
// Transform apply the patches on top of the base resources.
func
(
pt
*
patchTransformer
)
Transform
(
baseResourceMap
resmap
.
ResMap
)
error
{
// Merge and then index the patches by Id.
patches
,
err
:=
pt
.
mergePatches
()
if
err
!=
nil
{
return
err
}
// Strategic merge the resources exist in both base and patches.
for
_
,
patch
:=
range
patches
{
// Merge patches with base resource.
id
:=
patch
.
Id
()
matchedIds
:=
baseResourceMap
.
FindByGVKN
(
id
)
if
len
(
matchedIds
)
==
0
{
return
fmt
.
Errorf
(
"failed to find an object with %s to apply the patch"
,
id
.
GvknString
())
}
if
len
(
matchedIds
)
>
1
{
return
fmt
.
Errorf
(
"found multiple objects %#v targeted by patch %#v (ambiguous)"
,
matchedIds
,
id
)
}
id
=
matchedIds
[
0
]
base
:=
baseResourceMap
[
id
]
merged
:=
map
[
string
]
interface
{}{}
versionedObj
,
err
:=
scheme
.
Scheme
.
New
(
toSchemaGvk
(
id
.
Gvk
()))
baseName
:=
base
.
GetName
()
switch
{
case
runtime
.
IsNotRegisteredError
(
err
)
:
// Use JSON merge patch to handle types w/o schema
baseBytes
,
err
:=
json
.
Marshal
(
base
.
Map
())
if
err
!=
nil
{
return
err
}
patchBytes
,
err
:=
json
.
Marshal
(
patch
.
Map
())
if
err
!=
nil
{
return
err
}
mergedBytes
,
err
:=
jsonpatch
.
MergePatch
(
baseBytes
,
patchBytes
)
if
err
!=
nil
{
return
err
}
err
=
json
.
Unmarshal
(
mergedBytes
,
&
merged
)
if
err
!=
nil
{
return
err
}
case
err
!=
nil
:
return
err
default
:
// Use Strategic-Merge-Patch to handle types w/ schema
// TODO: Change this to use the new Merge package.
// Store the name of the base object, because this name may have been munged.
// Apply this name to the patched object.
lookupPatchMeta
,
err
:=
strategicpatch
.
NewPatchMetaFromStruct
(
versionedObj
)
if
err
!=
nil
{
return
err
}
merged
,
err
=
strategicpatch
.
StrategicMergeMapPatchUsingLookupPatchMeta
(
base
.
Map
(),
patch
.
Map
(),
lookupPatchMeta
)
if
err
!=
nil
{
return
err
}
}
base
.
SetName
(
baseName
)
baseResourceMap
[
id
]
.
SetMap
(
merged
)
}
return
nil
}
// mergePatches merge and index patches by Id.
// It errors out if there is conflict between patches.
func
(
pt
*
patchTransformer
)
mergePatches
()
(
resmap
.
ResMap
,
error
)
{
rc
:=
resmap
.
ResMap
{}
for
ix
,
patch
:=
range
pt
.
patches
{
id
:=
patch
.
Id
()
existing
,
found
:=
rc
[
id
]
if
!
found
{
rc
[
id
]
=
patch
continue
}
versionedObj
,
err
:=
scheme
.
Scheme
.
New
(
toSchemaGvk
(
id
.
Gvk
()))
if
err
!=
nil
&&
!
runtime
.
IsNotRegisteredError
(
err
)
{
return
nil
,
err
}
var
cd
conflictDetector
if
err
!=
nil
{
cd
=
newJMPConflictDetector
(
pt
.
rf
)
}
else
{
cd
,
err
=
newSMPConflictDetector
(
versionedObj
,
pt
.
rf
)
if
err
!=
nil
{
return
nil
,
err
}
}
conflict
,
err
:=
cd
.
hasConflict
(
existing
,
patch
)
if
err
!=
nil
{
return
nil
,
err
}
if
conflict
{
conflictingPatch
,
err
:=
cd
.
findConflict
(
ix
,
pt
.
patches
)
if
err
!=
nil
{
return
nil
,
err
}
return
nil
,
fmt
.
Errorf
(
"conflict between %#v and %#v"
,
conflictingPatch
.
Map
(),
patch
.
Map
())
}
merged
,
err
:=
cd
.
mergePatches
(
existing
,
patch
)
if
err
!=
nil
{
return
nil
,
err
}
rc
[
id
]
=
merged
}
return
rc
,
nil
}
// toSchemaGvk converts to a schema.GroupVersionKind.
func
toSchemaGvk
(
x
gvk
.
Gvk
)
schema
.
GroupVersionKind
{
return
schema
.
GroupVersionKind
{
Group
:
x
.
Group
,
Version
:
x
.
Version
,
Kind
:
x
.
Kind
,
}
}
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/patch/patch_test.go
0 → 100644
View file @
74a64a9f
/*
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
patch
import
(
"reflect"
"strings"
"testing"
"k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/pkg/gvk"
"sigs.k8s.io/kustomize/pkg/resid"
"sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/resource"
)
var
rf
=
resource
.
NewFactory
(
kunstruct
.
NewKunstructuredFactoryImpl
())
var
deploy
=
gvk
.
Gvk
{
Group
:
"apps"
,
Version
:
"v1"
,
Kind
:
"Deployment"
}
var
foo
=
gvk
.
Gvk
{
Group
:
"example.com"
,
Version
:
"v1"
,
Kind
:
"Foo"
}
func
TestOverlayRun
(
t
*
testing
.
T
)
{
base
:=
resmap
.
ResMap
{
resid
.
NewResId
(
deploy
,
"deploy1"
)
:
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"apps/v1"
,
"kind"
:
"Deployment"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"deploy1"
,
},
"spec"
:
map
[
string
]
interface
{}{
"template"
:
map
[
string
]
interface
{}{
"metadata"
:
map
[
string
]
interface
{}{
"labels"
:
map
[
string
]
interface
{}{
"old-label"
:
"old-value"
,
},
},
"spec"
:
map
[
string
]
interface
{}{
"containers"
:
[]
interface
{}{
map
[
string
]
interface
{}{
"name"
:
"nginx"
,
"image"
:
"nginx"
,
},
},
},
},
},
}),
}
patch
:=
[]
*
resource
.
Resource
{
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"apps/v1"
,
"kind"
:
"Deployment"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"deploy1"
,
},
"spec"
:
map
[
string
]
interface
{}{
"template"
:
map
[
string
]
interface
{}{
"metadata"
:
map
[
string
]
interface
{}{
"labels"
:
map
[
string
]
interface
{}{
"another-label"
:
"foo"
,
},
},
"spec"
:
map
[
string
]
interface
{}{
"containers"
:
[]
interface
{}{
map
[
string
]
interface
{}{
"name"
:
"nginx"
,
"image"
:
"nginx:latest"
,
"env"
:
[]
interface
{}{
map
[
string
]
interface
{}{
"name"
:
"SOMEENV"
,
"value"
:
"BAR"
,
},
},
},
},
},
},
},
},
),
}
expected
:=
resmap
.
ResMap
{
resid
.
NewResId
(
deploy
,
"deploy1"
)
:
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"apps/v1"
,
"kind"
:
"Deployment"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"deploy1"
,
},
"spec"
:
map
[
string
]
interface
{}{
"template"
:
map
[
string
]
interface
{}{
"metadata"
:
map
[
string
]
interface
{}{
"labels"
:
map
[
string
]
interface
{}{
"old-label"
:
"old-value"
,
"another-label"
:
"foo"
,
},
},
"spec"
:
map
[
string
]
interface
{}{
"containers"
:
[]
interface
{}{
map
[
string
]
interface
{}{
"name"
:
"nginx"
,
"image"
:
"nginx:latest"
,
"env"
:
[]
interface
{}{
map
[
string
]
interface
{}{
"name"
:
"SOMEENV"
,
"value"
:
"BAR"
,
},
},
},
},
},
},
},
}),
}
lt
,
err
:=
NewPatchTransformer
(
patch
,
rf
)
if
err
!=
nil
{
t
.
Fatalf
(
"unexpected error: %v"
,
err
)
}
err
=
lt
.
Transform
(
base
)
if
err
!=
nil
{
t
.
Fatalf
(
"unexpected error: %v"
,
err
)
}
if
!
reflect
.
DeepEqual
(
base
,
expected
)
{
err
=
expected
.
ErrorIfNotEqual
(
base
)
t
.
Fatalf
(
"actual doesn't match expected: %v"
,
err
)
}
}
func
TestMultiplePatches
(
t
*
testing
.
T
)
{
base
:=
resmap
.
ResMap
{
resid
.
NewResId
(
deploy
,
"deploy1"
)
:
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"apps/v1"
,
"kind"
:
"Deployment"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"deploy1"
,
},
"spec"
:
map
[
string
]
interface
{}{
"template"
:
map
[
string
]
interface
{}{
"spec"
:
map
[
string
]
interface
{}{
"containers"
:
[]
interface
{}{
map
[
string
]
interface
{}{
"name"
:
"nginx"
,
"image"
:
"nginx"
,
},
},
},
},
},
}),
}
patch
:=
[]
*
resource
.
Resource
{
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"apps/v1"
,
"kind"
:
"Deployment"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"deploy1"
,
},
"spec"
:
map
[
string
]
interface
{}{
"template"
:
map
[
string
]
interface
{}{
"spec"
:
map
[
string
]
interface
{}{
"containers"
:
[]
interface
{}{
map
[
string
]
interface
{}{
"name"
:
"nginx"
,
"image"
:
"nginx:latest"
,
"env"
:
[]
interface
{}{
map
[
string
]
interface
{}{
"name"
:
"SOMEENV"
,
"value"
:
"BAR"
,
},
},
},
},
},
},
},
},
),
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"apps/v1"
,
"kind"
:
"Deployment"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"deploy1"
,
},
"spec"
:
map
[
string
]
interface
{}{
"template"
:
map
[
string
]
interface
{}{
"spec"
:
map
[
string
]
interface
{}{
"containers"
:
[]
interface
{}{
map
[
string
]
interface
{}{
"name"
:
"nginx"
,
"env"
:
[]
interface
{}{
map
[
string
]
interface
{}{
"name"
:
"ANOTHERENV"
,
"value"
:
"HELLO"
,
},
},
},
map
[
string
]
interface
{}{
"name"
:
"busybox"
,
"image"
:
"busybox"
,
},
},
},
},
},
},
),
}
expected
:=
resmap
.
ResMap
{
resid
.
NewResId
(
deploy
,
"deploy1"
)
:
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"apps/v1"
,
"kind"
:
"Deployment"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"deploy1"
,
},
"spec"
:
map
[
string
]
interface
{}{
"template"
:
map
[
string
]
interface
{}{
"spec"
:
map
[
string
]
interface
{}{
"containers"
:
[]
interface
{}{
map
[
string
]
interface
{}{
"name"
:
"nginx"
,
"image"
:
"nginx:latest"
,
"env"
:
[]
interface
{}{
map
[
string
]
interface
{}{
"name"
:
"ANOTHERENV"
,
"value"
:
"HELLO"
,
},
map
[
string
]
interface
{}{
"name"
:
"SOMEENV"
,
"value"
:
"BAR"
,
},
},
},
map
[
string
]
interface
{}{
"name"
:
"busybox"
,
"image"
:
"busybox"
,
},
},
},
},
},
}),
}
lt
,
err
:=
NewPatchTransformer
(
patch
,
rf
)
if
err
!=
nil
{
t
.
Fatalf
(
"unexpected error: %v"
,
err
)
}
err
=
lt
.
Transform
(
base
)
if
err
!=
nil
{
t
.
Fatalf
(
"unexpected error: %v"
,
err
)
}
if
!
reflect
.
DeepEqual
(
base
,
expected
)
{
err
=
expected
.
ErrorIfNotEqual
(
base
)
t
.
Fatalf
(
"actual doesn't match expected: %v"
,
err
)
}
}
func
TestMultiplePatchesWithConflict
(
t
*
testing
.
T
)
{
base
:=
resmap
.
ResMap
{
resid
.
NewResId
(
deploy
,
"deploy1"
)
:
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"apps/v1"
,
"kind"
:
"Deployment"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"deploy1"
,
},
"spec"
:
map
[
string
]
interface
{}{
"template"
:
map
[
string
]
interface
{}{
"spec"
:
map
[
string
]
interface
{}{
"containers"
:
[]
interface
{}{
map
[
string
]
interface
{}{
"name"
:
"nginx"
,
"image"
:
"nginx"
,
},
},
},
},
},
}),
}
patch
:=
[]
*
resource
.
Resource
{
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"apps/v1"
,
"kind"
:
"Deployment"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"deploy1"
,
},
"spec"
:
map
[
string
]
interface
{}{
"template"
:
map
[
string
]
interface
{}{
"spec"
:
map
[
string
]
interface
{}{
"containers"
:
[]
interface
{}{
map
[
string
]
interface
{}{
"name"
:
"nginx"
,
"image"
:
"nginx:latest"
,
"env"
:
[]
interface
{}{
map
[
string
]
interface
{}{
"name"
:
"SOMEENV"
,
"value"
:
"BAR"
,
},
},
},
},
},
},
},
},
),
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"apps/v1"
,
"kind"
:
"Deployment"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"deploy1"
,
},
"spec"
:
map
[
string
]
interface
{}{
"template"
:
map
[
string
]
interface
{}{
"spec"
:
map
[
string
]
interface
{}{
"containers"
:
[]
interface
{}{
map
[
string
]
interface
{}{
"name"
:
"nginx"
,
"image"
:
"nginx:1.7.9"
,
},
},
},
},
},
},
),
}
lt
,
err
:=
NewPatchTransformer
(
patch
,
rf
)
if
err
!=
nil
{
t
.
Fatalf
(
"unexpected error: %v"
,
err
)
}
err
=
lt
.
Transform
(
base
)
if
err
==
nil
{
t
.
Fatalf
(
"did not get expected error"
)
}
if
!
strings
.
Contains
(
err
.
Error
(),
"conflict"
)
{
t
.
Fatalf
(
"expected error to contain %q but get %v"
,
"conflict"
,
err
)
}
}
func
TestNoSchemaOverlayRun
(
t
*
testing
.
T
)
{
base
:=
resmap
.
ResMap
{
resid
.
NewResId
(
foo
,
"my-foo"
)
:
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"example.com/v1"
,
"kind"
:
"Foo"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"my-foo"
,
},
"spec"
:
map
[
string
]
interface
{}{
"bar"
:
map
[
string
]
interface
{}{
"A"
:
"X"
,
"B"
:
"Y"
,
},
},
}),
}
patch
:=
[]
*
resource
.
Resource
{
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"example.com/v1"
,
"kind"
:
"Foo"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"my-foo"
,
},
"spec"
:
map
[
string
]
interface
{}{
"bar"
:
map
[
string
]
interface
{}{
"B"
:
nil
,
"C"
:
"Z"
,
},
},
},
),
}
expected
:=
resmap
.
ResMap
{
resid
.
NewResId
(
foo
,
"my-foo"
)
:
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"example.com/v1"
,
"kind"
:
"Foo"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"my-foo"
,
},
"spec"
:
map
[
string
]
interface
{}{
"bar"
:
map
[
string
]
interface
{}{
"A"
:
"X"
,
"C"
:
"Z"
,
},
},
}),
}
lt
,
err
:=
NewPatchTransformer
(
patch
,
rf
)
if
err
!=
nil
{
t
.
Fatalf
(
"unexpected error: %v"
,
err
)
}
err
=
lt
.
Transform
(
base
)
if
err
!=
nil
{
t
.
Fatalf
(
"unexpected error: %v"
,
err
)
}
if
err
=
expected
.
ErrorIfNotEqual
(
base
);
err
!=
nil
{
t
.
Fatalf
(
"actual doesn't match expected: %v"
,
err
)
}
}
func
TestNoSchemaMultiplePatches
(
t
*
testing
.
T
)
{
base
:=
resmap
.
ResMap
{
resid
.
NewResId
(
foo
,
"my-foo"
)
:
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"example.com/v1"
,
"kind"
:
"Foo"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"my-foo"
,
},
"spec"
:
map
[
string
]
interface
{}{
"bar"
:
map
[
string
]
interface
{}{
"A"
:
"X"
,
"B"
:
"Y"
,
},
},
}),
}
patch
:=
[]
*
resource
.
Resource
{
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"example.com/v1"
,
"kind"
:
"Foo"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"my-foo"
,
},
"spec"
:
map
[
string
]
interface
{}{
"bar"
:
map
[
string
]
interface
{}{
"B"
:
nil
,
"C"
:
"Z"
,
},
},
},
),
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"example.com/v1"
,
"kind"
:
"Foo"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"my-foo"
,
},
"spec"
:
map
[
string
]
interface
{}{
"bar"
:
map
[
string
]
interface
{}{
"C"
:
"Z"
,
"D"
:
"W"
,
},
"baz"
:
map
[
string
]
interface
{}{
"hello"
:
"world"
,
},
},
},
),
}
expected
:=
resmap
.
ResMap
{
resid
.
NewResId
(
foo
,
"my-foo"
)
:
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"example.com/v1"
,
"kind"
:
"Foo"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"my-foo"
,
},
"spec"
:
map
[
string
]
interface
{}{
"bar"
:
map
[
string
]
interface
{}{
"A"
:
"X"
,
"C"
:
"Z"
,
"D"
:
"W"
,
},
"baz"
:
map
[
string
]
interface
{}{
"hello"
:
"world"
,
},
},
}),
}
lt
,
err
:=
NewPatchTransformer
(
patch
,
rf
)
if
err
!=
nil
{
t
.
Fatalf
(
"unexpected error: %v"
,
err
)
}
err
=
lt
.
Transform
(
base
)
if
err
!=
nil
{
t
.
Fatalf
(
"unexpected error: %v"
,
err
)
}
if
err
=
expected
.
ErrorIfNotEqual
(
base
);
err
!=
nil
{
t
.
Fatalf
(
"actual doesn't match expected: %v"
,
err
)
}
}
func
TestNoSchemaMultiplePatchesWithConflict
(
t
*
testing
.
T
)
{
base
:=
resmap
.
ResMap
{
resid
.
NewResId
(
foo
,
"my-foo"
)
:
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"example.com/v1"
,
"kind"
:
"Foo"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"my-foo"
,
},
"spec"
:
map
[
string
]
interface
{}{
"bar"
:
map
[
string
]
interface
{}{
"A"
:
"X"
,
"B"
:
"Y"
,
},
},
}),
}
patch
:=
[]
*
resource
.
Resource
{
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"example.com/v1"
,
"kind"
:
"Foo"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"my-foo"
,
},
"spec"
:
map
[
string
]
interface
{}{
"bar"
:
map
[
string
]
interface
{}{
"B"
:
nil
,
"C"
:
"Z"
,
},
},
}),
rf
.
FromMap
(
map
[
string
]
interface
{}{
"apiVersion"
:
"example.com/v1"
,
"kind"
:
"Foo"
,
"metadata"
:
map
[
string
]
interface
{}{
"name"
:
"my-foo"
,
},
"spec"
:
map
[
string
]
interface
{}{
"bar"
:
map
[
string
]
interface
{}{
"C"
:
"NOT_Z"
,
},
},
}),
}
lt
,
err
:=
NewPatchTransformer
(
patch
,
rf
)
if
err
!=
nil
{
t
.
Fatalf
(
"unexpected error: %v"
,
err
)
}
err
=
lt
.
Transform
(
base
)
if
err
==
nil
{
t
.
Fatalf
(
"did not get expected error"
)
}
if
!
strings
.
Contains
(
err
.
Error
(),
"conflict"
)
{
t
.
Fatalf
(
"expected error to contain %q but get %v"
,
"conflict"
,
err
)
}
}
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/patch/patchconflictdetector.go
0 → 100644
View file @
74a64a9f
/*
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
patch
import
(
"encoding/json"
"github.com/evanphx/json-patch"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/mergepatch"
"k8s.io/apimachinery/pkg/util/strategicpatch"
"sigs.k8s.io/kustomize/pkg/resource"
)
type
conflictDetector
interface
{
hasConflict
(
patch1
,
patch2
*
resource
.
Resource
)
(
bool
,
error
)
findConflict
(
conflictingPatchIdx
int
,
patches
[]
*
resource
.
Resource
)
(
*
resource
.
Resource
,
error
)
mergePatches
(
patch1
,
patch2
*
resource
.
Resource
)
(
*
resource
.
Resource
,
error
)
}
type
jsonMergePatch
struct
{
rf
*
resource
.
Factory
}
var
_
conflictDetector
=
&
jsonMergePatch
{}
func
newJMPConflictDetector
(
rf
*
resource
.
Factory
)
conflictDetector
{
return
&
jsonMergePatch
{
rf
:
rf
}
}
func
(
jmp
*
jsonMergePatch
)
hasConflict
(
patch1
,
patch2
*
resource
.
Resource
)
(
bool
,
error
)
{
return
mergepatch
.
HasConflicts
(
patch1
.
Map
(),
patch2
.
Map
())
}
func
(
jmp
*
jsonMergePatch
)
findConflict
(
conflictingPatchIdx
int
,
patches
[]
*
resource
.
Resource
)
(
*
resource
.
Resource
,
error
)
{
for
i
,
patch
:=
range
patches
{
if
i
==
conflictingPatchIdx
{
continue
}
if
!
patches
[
conflictingPatchIdx
]
.
Id
()
.
GvknEquals
(
patch
.
Id
())
{
continue
}
conflict
,
err
:=
mergepatch
.
HasConflicts
(
patch
.
Map
(),
patches
[
conflictingPatchIdx
]
.
Map
())
if
err
!=
nil
{
return
nil
,
err
}
if
conflict
{
return
patch
,
nil
}
}
return
nil
,
nil
}
func
(
jmp
*
jsonMergePatch
)
mergePatches
(
patch1
,
patch2
*
resource
.
Resource
)
(
*
resource
.
Resource
,
error
)
{
baseBytes
,
err
:=
json
.
Marshal
(
patch1
.
Map
())
if
err
!=
nil
{
return
nil
,
err
}
patchBytes
,
err
:=
json
.
Marshal
(
patch2
.
Map
())
if
err
!=
nil
{
return
nil
,
err
}
mergedBytes
,
err
:=
jsonpatch
.
MergeMergePatches
(
baseBytes
,
patchBytes
)
if
err
!=
nil
{
return
nil
,
err
}
mergedMap
:=
make
(
map
[
string
]
interface
{})
err
=
json
.
Unmarshal
(
mergedBytes
,
&
mergedMap
)
return
jmp
.
rf
.
FromMap
(
mergedMap
),
err
}
type
strategicMergePatch
struct
{
lookupPatchMeta
strategicpatch
.
LookupPatchMeta
rf
*
resource
.
Factory
}
var
_
conflictDetector
=
&
strategicMergePatch
{}
func
newSMPConflictDetector
(
versionedObj
runtime
.
Object
,
rf
*
resource
.
Factory
)
(
conflictDetector
,
error
)
{
lookupPatchMeta
,
err
:=
strategicpatch
.
NewPatchMetaFromStruct
(
versionedObj
)
return
&
strategicMergePatch
{
lookupPatchMeta
:
lookupPatchMeta
,
rf
:
rf
},
err
}
func
(
smp
*
strategicMergePatch
)
hasConflict
(
p1
,
p2
*
resource
.
Resource
)
(
bool
,
error
)
{
return
strategicpatch
.
MergingMapsHaveConflicts
(
p1
.
Map
(),
p2
.
Map
(),
smp
.
lookupPatchMeta
)
}
func
(
smp
*
strategicMergePatch
)
findConflict
(
conflictingPatchIdx
int
,
patches
[]
*
resource
.
Resource
)
(
*
resource
.
Resource
,
error
)
{
for
i
,
patch
:=
range
patches
{
if
i
==
conflictingPatchIdx
{
continue
}
if
!
patches
[
conflictingPatchIdx
]
.
Id
()
.
GvknEquals
(
patch
.
Id
())
{
continue
}
conflict
,
err
:=
strategicpatch
.
MergingMapsHaveConflicts
(
patch
.
Map
(),
patches
[
conflictingPatchIdx
]
.
Map
(),
smp
.
lookupPatchMeta
)
if
err
!=
nil
{
return
nil
,
err
}
if
conflict
{
return
patch
,
nil
}
}
return
nil
,
nil
}
func
(
smp
*
strategicMergePatch
)
mergePatches
(
patch1
,
patch2
*
resource
.
Resource
)
(
*
resource
.
Resource
,
error
)
{
mergeJSONMap
,
err
:=
strategicpatch
.
MergeStrategicMergeMapPatchUsingLookupPatchMeta
(
smp
.
lookupPatchMeta
,
patch1
.
Map
(),
patch2
.
Map
())
return
smp
.
rf
.
FromMap
(
mergeJSONMap
),
err
}
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/validator/BUILD
0 → 100644
View file @
74a64a9f
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["validators.go"],
importmap = "k8s.io/kubernetes/vendor/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/validator",
importpath = "k8s.io/cli-runtime/pkg/kustomize/k8sdeps/validator",
visibility = ["//visibility:public"],
deps = [
"//staging/src/k8s.io/apimachinery/pkg/api/validation:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/validation:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/validation:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/validator/validators.go
0 → 100644
View file @
74a64a9f
/*
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 validator provides functions to validate labels, annotations, namespace using apimachinery
package
validator
import
(
"errors"
apivalidation
"k8s.io/apimachinery/pkg/api/validation"
v1validation
"k8s.io/apimachinery/pkg/apis/meta/v1/validation"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/validation/field"
)
// KustValidator validates Labels and annotations by apimachinery
type
KustValidator
struct
{}
// NewKustValidator returns a KustValidator object
func
NewKustValidator
()
*
KustValidator
{
return
&
KustValidator
{}
}
// MakeAnnotationValidator returns a MapValidatorFunc using apimachinery.
func
(
v
*
KustValidator
)
MakeAnnotationValidator
()
func
(
map
[
string
]
string
)
error
{
return
func
(
x
map
[
string
]
string
)
error
{
errs
:=
apivalidation
.
ValidateAnnotations
(
x
,
field
.
NewPath
(
"field"
))
if
len
(
errs
)
>
0
{
return
errors
.
New
(
errs
.
ToAggregate
()
.
Error
())
}
return
nil
}
}
// MakeLabelValidator returns a MapValidatorFunc using apimachinery.
func
(
v
*
KustValidator
)
MakeLabelValidator
()
func
(
map
[
string
]
string
)
error
{
return
func
(
x
map
[
string
]
string
)
error
{
errs
:=
v1validation
.
ValidateLabels
(
x
,
field
.
NewPath
(
"field"
))
if
len
(
errs
)
>
0
{
return
errors
.
New
(
errs
.
ToAggregate
()
.
Error
())
}
return
nil
}
}
// ValidateNamespace validates a string is a valid namespace using apimachinery.
func
(
v
*
KustValidator
)
ValidateNamespace
(
s
string
)
[]
string
{
return
validation
.
IsDNS1123Label
(
s
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment