591 lines
16 KiB
Go
591 lines
16 KiB
Go
package overridemanager
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
|
|
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
|
|
)
|
|
|
|
func generateDeploymentYaml() *unstructured.Unstructured {
|
|
return &unstructured.Unstructured{
|
|
Object: map[string]interface{}{
|
|
"apiVersion": "apps/v1",
|
|
"kind": "Deployment",
|
|
"metadata": map[string]interface{}{
|
|
"name": "nginx",
|
|
"labels": map[string]interface{}{
|
|
"app": "nginx",
|
|
},
|
|
},
|
|
"spec": map[string]interface{}{
|
|
"replicas": 1,
|
|
"selector": map[string]interface{}{
|
|
"matchLabels": map[string]interface{}{
|
|
"app": "nginx",
|
|
},
|
|
},
|
|
"template": map[string]interface{}{
|
|
"metadata": map[string]interface{}{
|
|
"labels": map[string]interface{}{
|
|
"app": "nginx",
|
|
},
|
|
},
|
|
"spec": map[string]interface{}{
|
|
"containers": []interface{}{
|
|
map[string]interface{}{
|
|
"image": "fictional.registry.example/imagename:v1.0.0",
|
|
"name": "nginx",
|
|
}}}}}}}
|
|
}
|
|
|
|
func generatePodYaml() *unstructured.Unstructured {
|
|
return &unstructured.Unstructured{
|
|
Object: map[string]interface{}{
|
|
"apiVersion": "v1",
|
|
"kind": "Pod",
|
|
"metadata": map[string]interface{}{
|
|
"name": "nginx",
|
|
"labels": map[string]interface{}{
|
|
"app": "nginx",
|
|
},
|
|
},
|
|
"spec": map[string]interface{}{
|
|
"containers": []interface{}{
|
|
map[string]interface{}{
|
|
"image": "fictional.registry.example/imagename:v1.0.0",
|
|
"name": "nginx",
|
|
}}}}}
|
|
}
|
|
|
|
func generateStatefulSetYaml() *unstructured.Unstructured {
|
|
return &unstructured.Unstructured{
|
|
Object: map[string]interface{}{
|
|
"apiVersion": "apps/v1",
|
|
"kind": "StatefulSet",
|
|
"metadata": map[string]interface{}{
|
|
"name": "web",
|
|
},
|
|
"spec": map[string]interface{}{
|
|
"replicas": 2,
|
|
"selector": map[string]interface{}{
|
|
"matchLabels": map[string]interface{}{
|
|
"app": "nginx",
|
|
},
|
|
},
|
|
"template": map[string]interface{}{
|
|
"metadata": map[string]interface{}{
|
|
"labels": map[string]interface{}{
|
|
"app": "nginx",
|
|
},
|
|
},
|
|
"spec": map[string]interface{}{
|
|
"containers": []interface{}{
|
|
map[string]interface{}{
|
|
"image": "fictional.registry.example/imagename:v1.0.0",
|
|
"name": "nginx",
|
|
}}}}}}}
|
|
}
|
|
|
|
func generateReplicaSetYaml() *unstructured.Unstructured {
|
|
return &unstructured.Unstructured{
|
|
Object: map[string]interface{}{
|
|
"apiVersion": "apps/v1",
|
|
"kind": "ReplicaSet",
|
|
"metadata": map[string]interface{}{
|
|
"name": "nginx",
|
|
"labels": map[string]interface{}{
|
|
"app": "nginx",
|
|
},
|
|
},
|
|
"spec": map[string]interface{}{
|
|
"replicas": 1,
|
|
"selector": map[string]interface{}{
|
|
"matchLabels": map[string]interface{}{
|
|
"app": "nginx",
|
|
},
|
|
},
|
|
"template": map[string]interface{}{
|
|
"metadata": map[string]interface{}{
|
|
"labels": map[string]interface{}{
|
|
"app": "nginx",
|
|
},
|
|
},
|
|
"spec": map[string]interface{}{
|
|
"containers": []interface{}{
|
|
map[string]interface{}{
|
|
"image": "fictional.registry.example/imagename:v1.0.0",
|
|
"name": "nginx",
|
|
}}}}}}}
|
|
}
|
|
|
|
func generateDaemonSetYaml() *unstructured.Unstructured {
|
|
return &unstructured.Unstructured{
|
|
Object: map[string]interface{}{
|
|
"apiVersion": "apps/v1",
|
|
"kind": "DaemonSet",
|
|
"metadata": map[string]interface{}{
|
|
"name": "nginx",
|
|
"labels": map[string]interface{}{
|
|
"app": "nginx",
|
|
},
|
|
},
|
|
"spec": map[string]interface{}{
|
|
"selector": map[string]interface{}{
|
|
"matchLabels": map[string]interface{}{
|
|
"app": "nginx",
|
|
},
|
|
},
|
|
"template": map[string]interface{}{
|
|
"metadata": map[string]interface{}{
|
|
"labels": map[string]interface{}{
|
|
"app": "nginx",
|
|
},
|
|
},
|
|
"spec": map[string]interface{}{
|
|
"containers": []interface{}{
|
|
map[string]interface{}{
|
|
"image": "fictional.registry.example/imagename:v1.0.0",
|
|
"name": "nginx",
|
|
}}}}}}}
|
|
}
|
|
|
|
func generateDeploymentYamlWithTwoContainer() *unstructured.Unstructured {
|
|
return &unstructured.Unstructured{
|
|
Object: map[string]interface{}{
|
|
"apiVersion": "apps/v1",
|
|
"kind": "Deployment",
|
|
"metadata": map[string]interface{}{
|
|
"name": "nginx",
|
|
"labels": map[string]interface{}{
|
|
"app": "nginx",
|
|
},
|
|
},
|
|
"spec": map[string]interface{}{
|
|
"replicas": 1,
|
|
"selector": map[string]interface{}{
|
|
"matchLabels": map[string]interface{}{
|
|
"app": "nginx",
|
|
},
|
|
},
|
|
"template": map[string]interface{}{
|
|
"metadata": map[string]interface{}{
|
|
"labels": map[string]interface{}{
|
|
"app": "nginx",
|
|
},
|
|
},
|
|
"spec": map[string]interface{}{
|
|
"containers": []interface{}{
|
|
map[string]interface{}{
|
|
"image": "fictional.registry.example/imagename:v1.0.0",
|
|
"name": "nginx",
|
|
},
|
|
map[string]interface{}{
|
|
"image": "registry.k8s.io/nginx-slim:0.8",
|
|
"name": "nginx",
|
|
}}}}}}}
|
|
}
|
|
|
|
func generateJobYaml() *unstructured.Unstructured {
|
|
return &unstructured.Unstructured{
|
|
Object: map[string]interface{}{
|
|
"apiVersion": "batch/v1",
|
|
"kind": "Job",
|
|
"metadata": map[string]interface{}{
|
|
"name": "pi",
|
|
},
|
|
"spec": map[string]interface{}{
|
|
"template": map[string]interface{}{
|
|
"spec": map[string]interface{}{
|
|
"containers": []interface{}{
|
|
map[string]interface{}{
|
|
"image": "perl:5.34.0",
|
|
"name": "perl",
|
|
},
|
|
}}}}}}
|
|
}
|
|
|
|
func TestParseJSONPatchesByImageOverrider(t *testing.T) {
|
|
type args struct {
|
|
rawObj *unstructured.Unstructured
|
|
imageOverrider *policyv1alpha1.ImageOverrider
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want []overrideOption
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "imageOverrider with empty predicate, resource kind: Job, component: Registry, operator: add",
|
|
args: args{
|
|
rawObj: generateJobYaml(),
|
|
imageOverrider: &policyv1alpha1.ImageOverrider{
|
|
Component: "Registry",
|
|
Operator: "add",
|
|
Value: "registry.k8s.io",
|
|
},
|
|
},
|
|
want: []overrideOption{
|
|
{
|
|
Op: "replace",
|
|
Path: "/spec/template/spec/containers/0/image",
|
|
Value: "registry.k8s.io/perl:5.34.0",
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "imageOverrider with predicate, resource kind: Job, component: Registry, operator: add",
|
|
args: args{
|
|
rawObj: generateJobYaml(),
|
|
imageOverrider: &policyv1alpha1.ImageOverrider{
|
|
Predicate: &policyv1alpha1.ImagePredicate{
|
|
Path: "/spec/template/spec/containers/0/image",
|
|
},
|
|
Component: "Registry",
|
|
Operator: "add",
|
|
Value: "registry.k8s.io",
|
|
},
|
|
},
|
|
want: []overrideOption{
|
|
{
|
|
Op: "replace",
|
|
Path: "/spec/template/spec/containers/0/image",
|
|
Value: "registry.k8s.io/perl:5.34.0",
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "imageOverrider with empty predicate, resource kind: Deployment, component: Registry, operator: add",
|
|
args: args{
|
|
rawObj: generateDeploymentYaml(),
|
|
imageOverrider: &policyv1alpha1.ImageOverrider{
|
|
Component: "Registry",
|
|
Operator: "add",
|
|
Value: ".test",
|
|
},
|
|
},
|
|
want: []overrideOption{
|
|
{
|
|
Op: "replace",
|
|
Path: "/spec/template/spec/containers/0/image",
|
|
Value: "fictional.registry.example.test/imagename:v1.0.0",
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "imageOverrider with empty predicate, resource kind: Deployment, component: Registry, operator: replace",
|
|
args: args{
|
|
rawObj: generateDeploymentYaml(),
|
|
imageOverrider: &policyv1alpha1.ImageOverrider{
|
|
Component: "Registry",
|
|
Operator: "replace",
|
|
Value: "fictional.registry.us",
|
|
},
|
|
},
|
|
want: []overrideOption{
|
|
{
|
|
Op: "replace",
|
|
Path: "/spec/template/spec/containers/0/image",
|
|
Value: "fictional.registry.us/imagename:v1.0.0",
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "imageOverrider with empty predicate, resource kind: Deployment, component: Registry, operator: remove",
|
|
args: args{
|
|
rawObj: generateDeploymentYaml(),
|
|
imageOverrider: &policyv1alpha1.ImageOverrider{
|
|
Component: "Registry",
|
|
Operator: "remove",
|
|
Value: "fictional.registry.us",
|
|
},
|
|
},
|
|
want: []overrideOption{
|
|
{
|
|
Op: "replace",
|
|
Path: "/spec/template/spec/containers/0/image",
|
|
Value: "imagename:v1.0.0",
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "imageOverrider with empty predicate, resource kind: Deployment, component: Repository, operator: add",
|
|
args: args{
|
|
rawObj: generateDeploymentYaml(),
|
|
imageOverrider: &policyv1alpha1.ImageOverrider{
|
|
Component: "Repository",
|
|
Operator: "add",
|
|
Value: "/nginx",
|
|
},
|
|
},
|
|
want: []overrideOption{
|
|
{
|
|
Op: "replace",
|
|
Path: "/spec/template/spec/containers/0/image",
|
|
Value: "fictional.registry.example/imagename/nginx:v1.0.0",
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "imageOverrider with empty predicate, resource kind: Deployment, component: Repository, operator: replace",
|
|
args: args{
|
|
rawObj: generateDeploymentYaml(),
|
|
imageOverrider: &policyv1alpha1.ImageOverrider{
|
|
Component: "Repository",
|
|
Operator: "replace",
|
|
Value: "nginx",
|
|
},
|
|
},
|
|
want: []overrideOption{
|
|
{
|
|
Op: "replace",
|
|
Path: "/spec/template/spec/containers/0/image",
|
|
Value: "fictional.registry.example/nginx:v1.0.0",
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "imageOverrider with empty predicate, resource kind: Deployment, component: Repository, operator: remove",
|
|
args: args{
|
|
rawObj: generateDeploymentYaml(),
|
|
imageOverrider: &policyv1alpha1.ImageOverrider{
|
|
Component: "Repository",
|
|
Operator: "remove",
|
|
Value: "nginx",
|
|
},
|
|
},
|
|
want: []overrideOption{
|
|
{
|
|
Op: "replace",
|
|
Path: "/spec/template/spec/containers/0/image",
|
|
Value: "fictional.registry.example/:v1.0.0",
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "imageOverrider with empty predicate, resource kind: Deployment, component: Tag, operator: add",
|
|
args: args{
|
|
rawObj: generateDeploymentYaml(),
|
|
imageOverrider: &policyv1alpha1.ImageOverrider{
|
|
Component: "Tag",
|
|
Operator: "add",
|
|
Value: "sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
|
},
|
|
},
|
|
want: []overrideOption{
|
|
{
|
|
Op: "replace",
|
|
Path: "/spec/template/spec/containers/0/image",
|
|
Value: "fictional.registry.example/imagename:v1.0.0", // only one of tag and digest is valid.
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "imageOverrider with empty predicate, resource kind: Deployment, component: Tag, operator: replace",
|
|
args: args{
|
|
rawObj: generateDeploymentYaml(),
|
|
imageOverrider: &policyv1alpha1.ImageOverrider{
|
|
Component: "Tag",
|
|
Operator: "replace",
|
|
Value: "sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
|
},
|
|
},
|
|
want: []overrideOption{
|
|
{
|
|
Op: "replace",
|
|
Path: "/spec/template/spec/containers/0/image",
|
|
Value: "fictional.registry.example/imagename@sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "imageOverrider with empty predicate, resource kind: Deployment, component: Tag, operator: remove",
|
|
args: args{
|
|
rawObj: generateDeploymentYaml(),
|
|
imageOverrider: &policyv1alpha1.ImageOverrider{
|
|
Component: "Tag",
|
|
Operator: "remove",
|
|
Value: "sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
|
},
|
|
},
|
|
want: []overrideOption{
|
|
{
|
|
Op: "replace",
|
|
Path: "/spec/template/spec/containers/0/image",
|
|
Value: "fictional.registry.example/imagename",
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "imageOverrider with empty predicate, resource kind: Pod",
|
|
args: args{
|
|
rawObj: generatePodYaml(),
|
|
imageOverrider: &policyv1alpha1.ImageOverrider{
|
|
Component: "Repository",
|
|
Operator: "replace",
|
|
Value: "nginx",
|
|
},
|
|
},
|
|
want: []overrideOption{
|
|
{
|
|
Op: "replace",
|
|
Path: "/spec/containers/0/image",
|
|
Value: "fictional.registry.example/nginx:v1.0.0",
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "imageOverrider with empty predicate, resource kind: StatefulSet",
|
|
args: args{
|
|
rawObj: generateStatefulSetYaml(),
|
|
imageOverrider: &policyv1alpha1.ImageOverrider{
|
|
Component: "Repository",
|
|
Operator: "replace",
|
|
Value: "nginx",
|
|
},
|
|
},
|
|
want: []overrideOption{
|
|
{
|
|
Op: "replace",
|
|
Path: "/spec/template/spec/containers/0/image",
|
|
Value: "fictional.registry.example/nginx:v1.0.0",
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "imageOverrider with empty predicate, resource kind: ReplicaSet",
|
|
args: args{
|
|
rawObj: generateReplicaSetYaml(),
|
|
imageOverrider: &policyv1alpha1.ImageOverrider{
|
|
Component: "Repository",
|
|
Operator: "replace",
|
|
Value: "nginx",
|
|
},
|
|
},
|
|
want: []overrideOption{
|
|
{
|
|
Op: "replace",
|
|
Path: "/spec/template/spec/containers/0/image",
|
|
Value: "fictional.registry.example/nginx:v1.0.0",
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "imageOverrider with empty predicate, resource kind: DaemonSet",
|
|
args: args{
|
|
rawObj: generateDaemonSetYaml(),
|
|
imageOverrider: &policyv1alpha1.ImageOverrider{
|
|
Component: "Repository",
|
|
Operator: "replace",
|
|
Value: "nginx",
|
|
},
|
|
},
|
|
want: []overrideOption{
|
|
{
|
|
Op: "replace",
|
|
Path: "/spec/template/spec/containers/0/image",
|
|
Value: "fictional.registry.example/nginx:v1.0.0",
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "imageOverrider with empty predicate, resource has more than one container",
|
|
args: args{
|
|
rawObj: generateDeploymentYamlWithTwoContainer(),
|
|
imageOverrider: &policyv1alpha1.ImageOverrider{
|
|
Component: "Repository",
|
|
Operator: "replace",
|
|
Value: "nginx",
|
|
},
|
|
},
|
|
want: []overrideOption{
|
|
{
|
|
Op: "replace",
|
|
Path: "/spec/template/spec/containers/0/image",
|
|
Value: "fictional.registry.example/nginx:v1.0.0",
|
|
},
|
|
{
|
|
Op: "replace",
|
|
Path: "/spec/template/spec/containers/1/image",
|
|
Value: "registry.k8s.io/nginx:0.8",
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "imageOverrider with predicate, resource has one container",
|
|
args: args{
|
|
rawObj: generateDeploymentYaml(),
|
|
imageOverrider: &policyv1alpha1.ImageOverrider{
|
|
Predicate: &policyv1alpha1.ImagePredicate{
|
|
Path: "/spec/template/spec/containers/0/image",
|
|
},
|
|
Component: "Repository",
|
|
Operator: "replace",
|
|
Value: "nginx",
|
|
},
|
|
},
|
|
want: []overrideOption{
|
|
{
|
|
Op: "replace",
|
|
Path: "/spec/template/spec/containers/0/image",
|
|
Value: "fictional.registry.example/nginx:v1.0.0",
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "imageOverrider with predicate, resource has more than one container",
|
|
args: args{
|
|
rawObj: generateDeploymentYamlWithTwoContainer(),
|
|
imageOverrider: &policyv1alpha1.ImageOverrider{
|
|
Predicate: &policyv1alpha1.ImagePredicate{
|
|
Path: "/spec/template/spec/containers/1/image",
|
|
},
|
|
Component: "Repository",
|
|
Operator: "replace",
|
|
Value: "nginx",
|
|
},
|
|
},
|
|
want: []overrideOption{
|
|
{
|
|
Op: "replace",
|
|
Path: "/spec/template/spec/containers/1/image",
|
|
Value: "registry.k8s.io/nginx:0.8",
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := buildPatches(tt.args.rawObj, tt.args.imageOverrider)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("buildPatches() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("buildPatches() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|