additional labels and annotations util
This commit is contained in:
parent
6da251948c
commit
808a43fad6
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
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 util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ApplyAdditionalMapOptions struct {
|
||||||
|
additionalMap map[string]string
|
||||||
|
pathConfigs []PathConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Transformer = &ApplyAdditionalMapOptions{}
|
||||||
|
|
||||||
|
func (o *ApplyAdditionalMapOptions) CompleteForLabels(m map[string]string, pathConfigs []PathConfig) {
|
||||||
|
o.additionalMap = m
|
||||||
|
if pathConfigs == nil {
|
||||||
|
pathConfigs = DefaultLabelsPathConfigs
|
||||||
|
}
|
||||||
|
o.pathConfigs = pathConfigs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ApplyAdditionalMapOptions) CompleteForAnnotations(m map[string]string, pathConfigs []PathConfig) {
|
||||||
|
o.additionalMap = m
|
||||||
|
if pathConfigs == nil {
|
||||||
|
pathConfigs = DefaultAnnotationsPathConfigs
|
||||||
|
}
|
||||||
|
o.pathConfigs = pathConfigs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ApplyAdditionalMapOptions) Transform(m map[GroupVersionKindName]*unstructured.Unstructured) error {
|
||||||
|
for gvkn := range m {
|
||||||
|
obj := m[gvkn]
|
||||||
|
objMap := obj.UnstructuredContent()
|
||||||
|
for _, path := range o.pathConfigs {
|
||||||
|
if !SelectByGVK(gvkn.gvk, path.GroupVersionKind) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err := mutateField(objMap, path.Path, path.CreateIfNotPresent, o.addMap)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ApplyAdditionalMapOptions) TransformBytes(in []byte) ([]byte, error) {
|
||||||
|
m, err := Decode(in)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = o.Transform(m)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return Encode(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ApplyAdditionalMapOptions) addMap(in interface{}) (interface{}, error) {
|
||||||
|
m, ok := in.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("%#v is expectd to be %T", in, m)
|
||||||
|
}
|
||||||
|
for k, v := range o.additionalMap {
|
||||||
|
m[k] = v
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,320 @@
|
||||||
|
/*
|
||||||
|
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 util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
var labelsOps = ApplyAdditionalMapOptions{
|
||||||
|
additionalMap: map[string]string{"label-key1": "label-value1", "label-key2": "label-value2"},
|
||||||
|
pathConfigs: DefaultLabelsPathConfigs,
|
||||||
|
}
|
||||||
|
|
||||||
|
var annotationsOps = ApplyAdditionalMapOptions{
|
||||||
|
additionalMap: map[string]string{"anno-key1": "anno-value1", "anno-key2": "anno-value2"},
|
||||||
|
pathConfigs: DefaultAnnotationsPathConfigs,
|
||||||
|
}
|
||||||
|
|
||||||
|
func getConfigmap() *unstructured.Unstructured {
|
||||||
|
return &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "cm1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDeployment() *unstructured.Unstructured {
|
||||||
|
return &unstructured.Unstructured{
|
||||||
|
Object: 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",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getService() *unstructured.Unstructured {
|
||||||
|
return &unstructured.Unstructured{
|
||||||
|
Object: 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",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTestMap() map[GroupVersionKindName]*unstructured.Unstructured {
|
||||||
|
return map[GroupVersionKindName]*unstructured.Unstructured{
|
||||||
|
{
|
||||||
|
gvk: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
|
name: "cm1",
|
||||||
|
}: getConfigmap(),
|
||||||
|
{
|
||||||
|
gvk: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||||
|
name: "deploy1",
|
||||||
|
}: getDeployment(),
|
||||||
|
{
|
||||||
|
gvk: schema.GroupVersionKind{Version: "v1", Kind: "Service"},
|
||||||
|
name: "svc1",
|
||||||
|
}: getService(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var labeledObj1 = unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "cm1",
|
||||||
|
"labels": map[string]interface{}{
|
||||||
|
"label-key1": "label-value1",
|
||||||
|
"label-key2": "label-value2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var labeledObj2 = unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"group": "apps",
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "deploy1",
|
||||||
|
"labels": map[string]interface{}{
|
||||||
|
"label-key1": "label-value1",
|
||||||
|
"label-key2": "label-value2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"selector": map[string]interface{}{
|
||||||
|
"matchLabels": map[string]interface{}{
|
||||||
|
"label-key1": "label-value1",
|
||||||
|
"label-key2": "label-value2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"template": map[string]interface{}{
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"labels": map[string]interface{}{
|
||||||
|
"old-label": "old-value",
|
||||||
|
"label-key1": "label-value1",
|
||||||
|
"label-key2": "label-value2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"containers": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"name": "nginx",
|
||||||
|
"image": "nginx:1.7.9",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var labeledObj3 = unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Service",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "svc1",
|
||||||
|
"labels": map[string]interface{}{
|
||||||
|
"label-key1": "label-value1",
|
||||||
|
"label-key2": "label-value2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"ports": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"name": "port1",
|
||||||
|
"port": "12345",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"selector": map[string]interface{}{
|
||||||
|
"label-key1": "label-value1",
|
||||||
|
"label-key2": "label-value2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var labeledM = map[GroupVersionKindName]*unstructured.Unstructured{
|
||||||
|
{
|
||||||
|
gvk: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
|
name: "cm1",
|
||||||
|
}: &labeledObj1,
|
||||||
|
{
|
||||||
|
gvk: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||||
|
name: "deploy1",
|
||||||
|
}: &labeledObj2,
|
||||||
|
{
|
||||||
|
gvk: schema.GroupVersionKind{Version: "v1", Kind: "Service"},
|
||||||
|
name: "svc1",
|
||||||
|
}: &labeledObj3,
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLabelsRun(t *testing.T) {
|
||||||
|
m := getTestMap()
|
||||||
|
err := labelsOps.Transform(m)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(m, labeledM) {
|
||||||
|
err = CompareMap(m, labeledM)
|
||||||
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var annotatedObj1 = unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "cm1",
|
||||||
|
"annotations": map[string]interface{}{
|
||||||
|
"anno-key1": "anno-value1",
|
||||||
|
"anno-key2": "anno-value2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var annotatedObj2 = unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"group": "apps",
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "deploy1",
|
||||||
|
"annotations": map[string]interface{}{
|
||||||
|
"anno-key1": "anno-value1",
|
||||||
|
"anno-key2": "anno-value2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"template": map[string]interface{}{
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"annotations": map[string]interface{}{
|
||||||
|
"anno-key1": "anno-value1",
|
||||||
|
"anno-key2": "anno-value2",
|
||||||
|
},
|
||||||
|
"labels": map[string]interface{}{
|
||||||
|
"old-label": "old-value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"containers": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"name": "nginx",
|
||||||
|
"image": "nginx:1.7.9",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var annotatedObj3 = unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Service",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "svc1",
|
||||||
|
"annotations": map[string]interface{}{
|
||||||
|
"anno-key1": "anno-value1",
|
||||||
|
"anno-key2": "anno-value2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"ports": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"name": "port1",
|
||||||
|
"port": "12345",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var annotatedM = map[GroupVersionKindName]*unstructured.Unstructured{
|
||||||
|
{
|
||||||
|
gvk: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
|
name: "cm1",
|
||||||
|
}: &annotatedObj1,
|
||||||
|
{
|
||||||
|
gvk: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||||
|
name: "deploy1",
|
||||||
|
}: &annotatedObj2,
|
||||||
|
{
|
||||||
|
gvk: schema.GroupVersionKind{Version: "v1", Kind: "Service"},
|
||||||
|
name: "svc1",
|
||||||
|
}: &annotatedObj3,
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAnnotationsRun(t *testing.T) {
|
||||||
|
m := getTestMap()
|
||||||
|
err := annotationsOps.Transform(m)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(m, annotatedM) {
|
||||||
|
err = CompareMap(m, annotatedM)
|
||||||
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,155 @@
|
||||||
|
/*
|
||||||
|
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 util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
var DefaultLabelsPathConfigs = []PathConfig{
|
||||||
|
{
|
||||||
|
Path: []string{"metadata", "labels"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Version: "v1", Kind: "Service"},
|
||||||
|
Path: []string{"spec", "selector"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Version: "v1", Kind: "ReplicationController"},
|
||||||
|
Path: []string{"spec", "selector"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Version: "v1", Kind: "ReplicationController"},
|
||||||
|
Path: []string{"spec", "template", "metadata", "labels"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Kind: "Deployment"},
|
||||||
|
Path: []string{"spec", "selector", "matchLabels"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Kind: "Deployment"},
|
||||||
|
Path: []string{"spec", "template", "metadata", "labels"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Kind: "ReplicaSet"},
|
||||||
|
Path: []string{"spec", "selector", "matchLabels"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Kind: "ReplicaSet"},
|
||||||
|
Path: []string{"spec", "template", "metadata", "labels"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Kind: "DaemonSet"},
|
||||||
|
Path: []string{"spec", "selector", "matchLabels"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Kind: "DaemonSet"},
|
||||||
|
Path: []string{"spec", "template", "metadata", "labels"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Group: "apps", Kind: "StatefulSet"},
|
||||||
|
Path: []string{"spec", "selector", "matchLabels"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Group: "apps", Kind: "StatefulSet"},
|
||||||
|
Path: []string{"spec", "template", "metadata", "labels"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Group: "batch", Kind: "Job"},
|
||||||
|
Path: []string{"spec", "selector", "matchLabels"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Group: "batch", Kind: "Job"},
|
||||||
|
Path: []string{"spec", "template", "metadata", "labels"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Group: "batch", Kind: "CronJob"},
|
||||||
|
Path: []string{"spec", "jobTemplate", "spec", "selector", "matchLabels"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Group: "batch", Kind: "CronJob"},
|
||||||
|
Path: []string{"spec", "jobTemplate", "spec", "metadata", "labels"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Group: "batch", Kind: "CronJob"},
|
||||||
|
Path: []string{"spec", "jobTemplate", "spec", "template", "metadata", "labels"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var DefaultAnnotationsPathConfigs = []PathConfig{
|
||||||
|
{
|
||||||
|
Path: []string{"metadata", "annotations"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Version: "v1", Kind: "ReplicationController"},
|
||||||
|
Path: []string{"spec", "template", "metadata", "annotations"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Kind: "Deployment"},
|
||||||
|
Path: []string{"spec", "template", "metadata", "annotations"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Kind: "ReplicaSet"},
|
||||||
|
Path: []string{"spec", "template", "metadata", "annotations"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Kind: "DaemonSet"},
|
||||||
|
Path: []string{"spec", "template", "metadata", "annotations"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Group: "apps", Kind: "StatefulSet"},
|
||||||
|
Path: []string{"spec", "template", "metadata", "annotations"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Group: "batch", Kind: "Job"},
|
||||||
|
Path: []string{"spec", "template", "metadata", "annotations"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Group: "batch", Kind: "CronJob"},
|
||||||
|
Path: []string{"spec", "jobTemplate", "metadata", "annotations"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersionKind: &schema.GroupVersionKind{Group: "batch", Kind: "CronJob"},
|
||||||
|
Path: []string{"spec", "jobTemplate", "spec", "template", "metadata", "annotations"},
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
@ -16,7 +16,17 @@ limitations under the License.
|
||||||
|
|
||||||
package util
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
)
|
||||||
|
|
||||||
type PathConfig struct {
|
type PathConfig struct {
|
||||||
Path []string
|
// If true, it will create the path if it is not found.
|
||||||
CreateIfNotPresent bool
|
CreateIfNotPresent bool
|
||||||
|
// The GVK that this path tied to.
|
||||||
|
// If unset, it applied to any GVK
|
||||||
|
// If some fields are set, it applies to all matching GVK.
|
||||||
|
GroupVersionKind *schema.GroupVersionKind
|
||||||
|
// Path to the field that will be munged.
|
||||||
|
Path []string
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,9 @@ func (o *PrefixNameOptions) Transform(m map[GroupVersionKindName]*unstructured.U
|
||||||
obj := m[gvkn]
|
obj := m[gvkn]
|
||||||
objMap := obj.UnstructuredContent()
|
objMap := obj.UnstructuredContent()
|
||||||
for _, path := range o.pathConfigs {
|
for _, path := range o.pathConfigs {
|
||||||
|
if !SelectByGVK(gvkn.gvk, path.GroupVersionKind) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
err := mutateField(objMap, path.Path, path.CreateIfNotPresent, o.addPrefix)
|
err := mutateField(objMap, path.Path, path.CreateIfNotPresent, o.addPrefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/ghodss/yaml"
|
"github.com/ghodss/yaml"
|
||||||
|
|
@ -111,6 +112,53 @@ func Encode(in map[GroupVersionKindName]*unstructured.Unstructured) ([]byte, err
|
||||||
return buf.Bytes(), nil
|
return buf.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SelectByGVK returns true if selector is a superset of in; otherwise, false.
|
||||||
|
func SelectByGVK(in schema.GroupVersionKind, selector *schema.GroupVersionKind) bool {
|
||||||
|
if selector == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if len(selector.Group) > 0 {
|
||||||
|
if in.Group != selector.Group {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(selector.Version) > 0 {
|
||||||
|
if in.Version != selector.Version {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(selector.Kind) > 0 {
|
||||||
|
if in.Kind != selector.Kind {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func CompareMap(m1, m2 map[GroupVersionKindName]*unstructured.Unstructured) error {
|
||||||
|
if len(m1) != len(m2) {
|
||||||
|
keySet1 := []GroupVersionKindName{}
|
||||||
|
keySet2 := []GroupVersionKindName{}
|
||||||
|
for gvkn := range m1 {
|
||||||
|
keySet1 = append(keySet1, gvkn)
|
||||||
|
}
|
||||||
|
for gvkn := range m1 {
|
||||||
|
keySet2 = append(keySet2, gvkn)
|
||||||
|
}
|
||||||
|
return fmt.Errorf("maps has different number of entries: %#v doesn't equals %#v", keySet1, keySet2)
|
||||||
|
}
|
||||||
|
for gvkn, obj1 := range m1 {
|
||||||
|
obj2, found := m2[gvkn]
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("%#v doesn't exist in %#v", gvkn, m2)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(obj1, obj2) {
|
||||||
|
return fmt.Errorf("%#v doesn't match %#v", obj1, obj2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type mutateFunc func(interface{}) (interface{}, error)
|
type mutateFunc func(interface{}) (interface{}, error)
|
||||||
|
|
||||||
func mutateField(m map[string]interface{}, pathToField []string, createIfNotPresent bool, fns ...mutateFunc) error {
|
func mutateField(m map[string]interface{}, pathToField []string, createIfNotPresent bool, fns ...mutateFunc) error {
|
||||||
|
|
|
||||||
|
|
@ -87,3 +87,111 @@ func TestEncode(t *testing.T) {
|
||||||
t.Fatalf("%s doesn't match expected %s", out, encoded)
|
t.Fatalf("%s doesn't match expected %s", out, encoded)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFilterByGVK(t *testing.T) {
|
||||||
|
type testCase struct {
|
||||||
|
description string
|
||||||
|
in schema.GroupVersionKind
|
||||||
|
filter *schema.GroupVersionKind
|
||||||
|
expected bool
|
||||||
|
}
|
||||||
|
testCases := []testCase{
|
||||||
|
{
|
||||||
|
description: "nil filter",
|
||||||
|
in: schema.GroupVersionKind{},
|
||||||
|
filter: nil,
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "gvk matches",
|
||||||
|
in: schema.GroupVersionKind{
|
||||||
|
Group: "group1",
|
||||||
|
Version: "version1",
|
||||||
|
Kind: "kind1",
|
||||||
|
},
|
||||||
|
filter: &schema.GroupVersionKind{
|
||||||
|
Group: "group1",
|
||||||
|
Version: "version1",
|
||||||
|
Kind: "kind1",
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "group doesn't matches",
|
||||||
|
in: schema.GroupVersionKind{
|
||||||
|
Group: "group1",
|
||||||
|
Version: "version1",
|
||||||
|
Kind: "kind1",
|
||||||
|
},
|
||||||
|
filter: &schema.GroupVersionKind{
|
||||||
|
Group: "group2",
|
||||||
|
Version: "version1",
|
||||||
|
Kind: "kind1",
|
||||||
|
},
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "version doesn't matches",
|
||||||
|
in: schema.GroupVersionKind{
|
||||||
|
Group: "group1",
|
||||||
|
Version: "version1",
|
||||||
|
Kind: "kind1",
|
||||||
|
},
|
||||||
|
filter: &schema.GroupVersionKind{
|
||||||
|
Group: "group1",
|
||||||
|
Version: "version2",
|
||||||
|
Kind: "kind1",
|
||||||
|
},
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "kind doesn't matches",
|
||||||
|
in: schema.GroupVersionKind{
|
||||||
|
Group: "group1",
|
||||||
|
Version: "version1",
|
||||||
|
Kind: "kind1",
|
||||||
|
},
|
||||||
|
filter: &schema.GroupVersionKind{
|
||||||
|
Group: "group1",
|
||||||
|
Version: "version1",
|
||||||
|
Kind: "kind2",
|
||||||
|
},
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "no version in filter",
|
||||||
|
in: schema.GroupVersionKind{
|
||||||
|
Group: "group1",
|
||||||
|
Version: "version1",
|
||||||
|
Kind: "kind1",
|
||||||
|
},
|
||||||
|
filter: &schema.GroupVersionKind{
|
||||||
|
Group: "group1",
|
||||||
|
Version: "",
|
||||||
|
Kind: "kind1",
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "only kind is set in filter",
|
||||||
|
in: schema.GroupVersionKind{
|
||||||
|
Group: "group1",
|
||||||
|
Version: "version1",
|
||||||
|
Kind: "kind1",
|
||||||
|
},
|
||||||
|
filter: &schema.GroupVersionKind{
|
||||||
|
Group: "",
|
||||||
|
Version: "",
|
||||||
|
Kind: "kind1",
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
filtered := SelectByGVK(tc.in, tc.filter)
|
||||||
|
if filtered != tc.expected {
|
||||||
|
t.Fatalf("unexpected filter result for test case: %v", tc.description)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue