Merge pull request #2175 from pwittrock/m3

Optionally use filepath as part of merge key for merge3
This commit is contained in:
Kubernetes Prow Robot
2020-02-04 10:01:27 -08:00
committed by GitHub
11 changed files with 422 additions and 3 deletions

View File

@@ -25,6 +25,8 @@ func GetMerge3Runner(name string) *Merge3Runner {
"Path to updated package")
c.Flags().StringVar(&r.toDir, "to", "",
"Path to destination package")
c.Flags().BoolVar(&r.path, "path-merge-key", false,
"Use the path as part of the merge key when merging resources")
r.Command = c
return r
@@ -40,6 +42,7 @@ type Merge3Runner struct {
ancestor string
fromDir string
toDir string
path bool
}
func (r *Merge3Runner) runE(c *cobra.Command, args []string) error {
@@ -47,6 +50,7 @@ func (r *Merge3Runner) runE(c *cobra.Command, args []string) error {
OriginalPath: r.ancestor,
UpdatedPath: r.fromDir,
DestPath: r.toDir,
MergeOnPath: r.path,
}.Merge()
if err != nil {
return err

View File

@@ -7,6 +7,7 @@ import (
"fmt"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
"sigs.k8s.io/kustomize/kyaml/yaml"
"sigs.k8s.io/kustomize/kyaml/yaml/merge3"
)
@@ -24,6 +25,11 @@ type Merge3 struct {
UpdatedPath string
DestPath string
MatchFilesGlob []string
// MergeOnPath will use the relative filepath as part of the merge key.
// This may be necessary if the directory contains multiple copies of
// the same resource, or resources patches.
MergeOnPath bool
}
func (m Merge3) Merge() error {
@@ -61,7 +67,7 @@ func (m Merge3) Merge() error {
// Filter combines Resources with the same GVK + N + NS into tuples, and then merges them
func (m Merge3) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
// index the nodes by their identity
tl := tuples{}
tl := tuples{mergeOnPath: m.MergeOnPath}
for i := range nodes {
if err := tl.add(nodes[i]); err != nil {
return nil, err
@@ -102,6 +108,37 @@ func (m Merge3) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
// tuples combines nodes with the same GVK + N + NS
type tuples struct {
list []*tuple
// mergeOnPath if set to true will use the resource filepath
// as part of the merge key
mergeOnPath bool
}
// isSameResource returns true if meta1 and meta2 are for the same logic resource
func (ts *tuples) isSameResource(meta1, meta2 yaml.ResourceMeta) bool {
if meta1.Name != meta2.Name {
return false
}
if meta1.Namespace != meta2.Namespace {
return false
}
if meta1.APIVersion != meta2.APIVersion {
return false
}
if meta1.Kind != meta2.Kind {
return false
}
if ts.mergeOnPath {
// directories may contain multiple copies of a resource with the same
// name, namespace, apiVersion and kind -- e.g. kustomize patches, or
// multiple environments
// mergeOnPath configures the merge logic to use the path as part of the
// resource key
if meta1.Annotations[kioutil.PathAnnotation] != meta2.Annotations[kioutil.PathAnnotation] {
return false
}
}
return true
}
// add adds a node to the list, combining it with an existing matching Resource if found
@@ -112,8 +149,7 @@ func (ts *tuples) add(node *yaml.RNode) error {
}
for i := range ts.list {
t := ts.list[i]
if t.meta.Name == nodeMeta.Name && t.meta.Namespace == nodeMeta.Namespace &&
t.meta.APIVersion == nodeMeta.APIVersion && t.meta.Kind == nodeMeta.Kind {
if ts.isSameResource(t.meta, nodeMeta) {
return t.add(node)
}
}

View File

@@ -54,3 +54,78 @@ func TestMerge3_Merge(t *testing.T) {
t.FailNow()
}
}
// TestMerge3_Merge_path tests that if the same resource is specified multiple times
// with MergeOnPath, that the resources will be merged by the filepath name.
func TestMerge3_Merge_path(t *testing.T) {
_, datadir, _, ok := runtime.Caller(0)
if !assert.True(t, ok) {
t.FailNow()
}
datadir = filepath.Join(filepath.Dir(datadir), "testdata2")
// setup the local directory
dir, err := ioutil.TempDir("", "kyaml-test")
if !assert.NoError(t, err) {
t.FailNow()
}
defer os.RemoveAll(dir)
if !assert.NoError(t, copyutil.CopyDir(
filepath.Join(datadir, "dataset1-localupdates"),
filepath.Join(dir, "dataset1"))) {
t.FailNow()
}
err = filters.Merge3{
OriginalPath: filepath.Join(datadir, "dataset1"),
UpdatedPath: filepath.Join(datadir, "dataset1-remoteupdates"),
DestPath: filepath.Join(dir, "dataset1"),
MergeOnPath: true,
}.Merge()
if !assert.NoError(t, err) {
t.FailNow()
}
diffs, err := copyutil.Diff(
filepath.Join(dir, "dataset1"),
filepath.Join(datadir, "dataset1-expected"))
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.Empty(t, diffs.List()) {
t.FailNow()
}
}
// TestMerge3_Merge_fail tests that if the same resource is defined multiple times
// that merge will fail
func TestMerge3_Merge_fail(t *testing.T) {
_, datadir, _, ok := runtime.Caller(0)
if !assert.True(t, ok) {
t.FailNow()
}
datadir = filepath.Join(filepath.Dir(datadir), "testdata2")
// setup the local directory
dir, err := ioutil.TempDir("", "kyaml-test")
if !assert.NoError(t, err) {
t.FailNow()
}
defer os.RemoveAll(dir)
if !assert.NoError(t, copyutil.CopyDir(
filepath.Join(datadir, "dataset1-localupdates"),
filepath.Join(dir, "dataset1"))) {
t.FailNow()
}
err = filters.Merge3{
OriginalPath: filepath.Join(datadir, "dataset1"),
UpdatedPath: filepath.Join(datadir, "dataset1-remoteupdates"),
DestPath: filepath.Join(dir, "dataset1"),
}.Merge()
if !assert.Error(t, err) {
t.FailNow()
}
}

View File

@@ -0,0 +1,38 @@
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
#
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
labels:
app: java
spec:
replicas: 1
selector:
matchLabels:
app: java2
template:
metadata:
labels:
app: java2
spec:
restartPolicy: Always
containers:
- name: app
image: gcr.io/project/app:version
command:
- java
- -jar
- /app.jar
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: app-config
env:
- name: JAVA_OPTS
value: -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
-Djava.security.egd=file:/dev/./urandom
imagePullPolicy: Always
minReadySeconds: 15

View File

@@ -0,0 +1,38 @@
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
#
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
labels:
app: java3
spec:
replicas: 4
selector:
matchLabels:
app: java
template:
metadata:
labels:
app: java
spec:
restartPolicy: Always
containers:
- name: app
image: gcr.io/project/app:version
command:
- java
- -jar
- /app.jar
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: app-config
env:
- name: JAVA_OPTS
value: -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
-Djava.security.egd=file:/dev/./urandom
imagePullPolicy: Always
minReadySeconds: 25

View File

@@ -0,0 +1,38 @@
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
#
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
labels:
app: java
spec:
replicas: 1
selector:
matchLabels:
app: java
template:
metadata:
labels:
app: java
spec:
restartPolicy: Always
containers:
- name: app
image: gcr.io/project/app:version
command:
- java
- -jar
- /app.jar
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: app-config
env:
- name: JAVA_OPTS
value: -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
-Djava.security.egd=file:/dev/./urandom
imagePullPolicy: Always
minReadySeconds: 15

View File

@@ -0,0 +1,38 @@
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
#
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
labels:
app: java
spec:
replicas: 4
selector:
matchLabels:
app: java
template:
metadata:
labels:
app: java
spec:
restartPolicy: Always
containers:
- name: app
image: gcr.io/project/app:version
command:
- java
- -jar
- /app.jar
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: app-config
env:
- name: JAVA_OPTS
value: -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
-Djava.security.egd=file:/dev/./urandom
imagePullPolicy: Always
minReadySeconds: 25

View File

@@ -0,0 +1,38 @@
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
#
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
labels:
app: java
spec:
replicas: 1
selector:
matchLabels:
app: java2
template:
metadata:
labels:
app: java2
spec:
restartPolicy: Always
containers:
- name: app
image: gcr.io/project/app:version
command:
- java
- -jar
- /app.jar
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: app-config
env:
- name: JAVA_OPTS
value: -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
-Djava.security.egd=file:/dev/./urandom
imagePullPolicy: Always
minReadySeconds: 5

View File

@@ -0,0 +1,38 @@
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
#
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
labels:
app: java3
spec:
replicas: 4
selector:
matchLabels:
app: java
template:
metadata:
labels:
app: java
spec:
restartPolicy: Always
containers:
- name: app
image: gcr.io/project/app:version
command:
- java
- -jar
- /app.jar
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: app-config
env:
- name: JAVA_OPTS
value: -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
-Djava.security.egd=file:/dev/./urandom
imagePullPolicy: Always
minReadySeconds: 10

View File

@@ -0,0 +1,38 @@
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
#
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
labels:
app: java
spec:
replicas: 1
selector:
matchLabels:
app: java
template:
metadata:
labels:
app: java
spec:
restartPolicy: Always
containers:
- name: app
image: gcr.io/project/app:version
command:
- java
- -jar
- /app.jar
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: app-config
env:
- name: JAVA_OPTS
value: -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
-Djava.security.egd=file:/dev/./urandom
imagePullPolicy: Always
minReadySeconds: 5

View File

@@ -0,0 +1,38 @@
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
#
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
labels:
app: java
spec:
replicas: 4
selector:
matchLabels:
app: java
template:
metadata:
labels:
app: java
spec:
restartPolicy: Always
containers:
- name: app
image: gcr.io/project/app:version
command:
- java
- -jar
- /app.jar
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: app-config
env:
- name: JAVA_OPTS
value: -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
-Djava.security.egd=file:/dev/./urandom
imagePullPolicy: Always
minReadySeconds: 10