mirror of
https://github.com/open-cluster-management-io/ocm.git
synced 2026-08-20 12:46:59 +00:00
432 lines
12 KiB
Go
432 lines
12 KiB
Go
package templateagent
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
rbacv1 "k8s.io/api/rbac/v1"
|
|
"k8s.io/apimachinery/pkg/api/resource"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
"k8s.io/klog/v2"
|
|
|
|
"open-cluster-management.io/addon-framework/pkg/addonfactory"
|
|
addonapiv1beta1 "open-cluster-management.io/api/addon/v1beta1"
|
|
|
|
testingcommon "open-cluster-management.io/ocm/pkg/common/testing"
|
|
)
|
|
|
|
func TestNamespaceDecorator(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
namespace string
|
|
object *unstructured.Unstructured
|
|
validateObject func(t *testing.T, obj *unstructured.Unstructured)
|
|
}{
|
|
{
|
|
name: "no namespace set",
|
|
object: testingcommon.NewUnstructured("v1", "Pod", "default", "test"),
|
|
validateObject: func(t *testing.T, obj *unstructured.Unstructured) {
|
|
testingcommon.AssertEqualNameNamespace(t, obj.GetName(), obj.GetNamespace(), "test", "default")
|
|
},
|
|
},
|
|
{
|
|
name: "namespace set",
|
|
object: testingcommon.NewUnstructured("v1", "Pod", "default", "test"),
|
|
namespace: "newns",
|
|
validateObject: func(t *testing.T, obj *unstructured.Unstructured) {
|
|
testingcommon.AssertEqualNameNamespace(t, obj.GetName(), obj.GetNamespace(), "test", "newns")
|
|
},
|
|
},
|
|
{
|
|
name: "clusterRoleBinding",
|
|
object: func() *unstructured.Unstructured {
|
|
clusterRoleBinding := &rbacv1.ClusterRoleBinding{
|
|
TypeMeta: metav1.TypeMeta{
|
|
Kind: "ClusterRoleBinding",
|
|
},
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "test",
|
|
},
|
|
Subjects: []rbacv1.Subject{
|
|
{
|
|
Name: "user1",
|
|
Namespace: "default",
|
|
},
|
|
{
|
|
Name: "user2",
|
|
Namespace: "default",
|
|
},
|
|
},
|
|
}
|
|
data, _ := runtime.DefaultUnstructuredConverter.ToUnstructured(clusterRoleBinding)
|
|
return &unstructured.Unstructured{Object: data}
|
|
}(),
|
|
namespace: "newns",
|
|
validateObject: func(t *testing.T, obj *unstructured.Unstructured) {
|
|
binding := &rbacv1.ClusterRoleBinding{}
|
|
err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, binding)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, s := range binding.Subjects {
|
|
if s.Namespace != "newns" {
|
|
t.Errorf("namespace of subject is not correct, got %v", s)
|
|
}
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "roleBinding",
|
|
object: func() *unstructured.Unstructured {
|
|
roleBinding := &rbacv1.RoleBinding{
|
|
TypeMeta: metav1.TypeMeta{
|
|
Kind: "RoleBinding",
|
|
},
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "test",
|
|
Namespace: "default",
|
|
},
|
|
Subjects: []rbacv1.Subject{
|
|
{
|
|
Name: "user1",
|
|
Namespace: "default",
|
|
},
|
|
{
|
|
Name: "user2",
|
|
Namespace: "default",
|
|
},
|
|
},
|
|
}
|
|
data, _ := runtime.DefaultUnstructuredConverter.ToUnstructured(roleBinding)
|
|
return &unstructured.Unstructured{Object: data}
|
|
}(),
|
|
namespace: "newns",
|
|
validateObject: func(t *testing.T, obj *unstructured.Unstructured) {
|
|
testingcommon.AssertEqualNameNamespace(t, obj.GetName(), obj.GetNamespace(), "test", "newns")
|
|
binding := &rbacv1.RoleBinding{}
|
|
err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, binding)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, s := range binding.Subjects {
|
|
if s.Namespace != "newns" {
|
|
t.Errorf("namespace of subject is not correct, got %v", s)
|
|
}
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "namespace",
|
|
object: func() *unstructured.Unstructured {
|
|
ns := &corev1.Namespace{
|
|
TypeMeta: metav1.TypeMeta{
|
|
Kind: "Namespace",
|
|
},
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "test",
|
|
},
|
|
}
|
|
data, _ := runtime.DefaultUnstructuredConverter.ToUnstructured(ns)
|
|
return &unstructured.Unstructured{Object: data}
|
|
}(),
|
|
namespace: "newns",
|
|
validateObject: func(t *testing.T, obj *unstructured.Unstructured) {
|
|
ns := &corev1.Namespace{}
|
|
err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, ns)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ns.Name != "newns" {
|
|
t.Errorf("name of namespace is not correct, got %v", ns.Name)
|
|
}
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
values := addonfactory.Values{}
|
|
if len(tc.namespace) > 0 {
|
|
values[InstallNamespacePrivateValueKey] = tc.namespace
|
|
}
|
|
|
|
d := newNamespaceDecorator(values)
|
|
result, err := d.decorate(tc.object)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tc.validateObject(t, result)
|
|
})
|
|
}
|
|
|
|
}
|
|
|
|
func TestProxyDecorator(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
config addonapiv1beta1.AddOnDeploymentConfig
|
|
pod *corev1.PodTemplateSpec
|
|
validateObject func(t *testing.T, pod *corev1.PodTemplateSpec)
|
|
}{
|
|
{
|
|
name: "no proxy set",
|
|
pod: &corev1.PodTemplateSpec{
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: "test",
|
|
Image: "test",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
validateObject: func(t *testing.T, pod *corev1.PodTemplateSpec) {
|
|
for _, c := range pod.Spec.Containers {
|
|
if c.Env != nil {
|
|
for _, e := range c.Env {
|
|
if e.Name == "HTTP_PROXY" || e.Name == "HTTPS_PROXY" || e.Name == "NO_PROXY" ||
|
|
e.Name == "http_proxy" || e.Name == "https_proxy" || e.Name == "no_proxy" {
|
|
t.Errorf("proxy env is not expected, got %v", e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "proxy set",
|
|
pod: &corev1.PodTemplateSpec{
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: "test",
|
|
Image: "test",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
config: addonapiv1beta1.AddOnDeploymentConfig{
|
|
Spec: addonapiv1beta1.AddOnDeploymentConfigSpec{
|
|
ProxyConfig: addonapiv1beta1.ProxyConfig{
|
|
HTTPProxy: "http://proxy",
|
|
HTTPSProxy: "https://proxy",
|
|
NoProxy: "no-proxy",
|
|
},
|
|
},
|
|
},
|
|
validateObject: func(t *testing.T, pod *corev1.PodTemplateSpec) {
|
|
for _, c := range pod.Spec.Containers {
|
|
if c.Env != nil {
|
|
for _, e := range c.Env {
|
|
if e.Name == "HTTP_PROXY" || e.Name == "http_proxy" { //nolint:gocritic
|
|
if e.Value != "http://proxy" {
|
|
t.Errorf("http proxy env is not correct, got %v", e)
|
|
}
|
|
} else if e.Name == "HTTPS_PROXY" || e.Name == "https_proxy" {
|
|
if e.Value != "https://proxy" {
|
|
t.Errorf("https proxy env is not correct, got %v", e)
|
|
}
|
|
} else if e.Name == "NO_PROXY" || e.Name == "no_proxy" {
|
|
if e.Value != "no-proxy" {
|
|
t.Errorf("no proxy env is not correct, got %v", e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
values, err := ToAddOnProxyPrivateValues(tc.config)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ctx := context.TODO()
|
|
logger := klog.FromContext(ctx)
|
|
d := newProxyHandler(logger, "addon1", values)
|
|
err = d.decorate("", tc.pod)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tc.validateObject(t, tc.pod)
|
|
})
|
|
}
|
|
|
|
}
|
|
|
|
func TestResourceRequirementsDecorator(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
config addonapiv1beta1.AddOnDeploymentConfig
|
|
resourceName string
|
|
pod *corev1.PodTemplateSpec
|
|
supportResource supportResource
|
|
validateObject func(t *testing.T, pod *corev1.PodTemplateSpec)
|
|
}{
|
|
{
|
|
name: "deployment",
|
|
pod: &corev1.PodTemplateSpec{
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: "c1",
|
|
Image: "test",
|
|
},
|
|
{
|
|
Name: "c2",
|
|
Image: "test",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
resourceName: "d1",
|
|
supportResource: supportResourceDeployment,
|
|
config: addonapiv1beta1.AddOnDeploymentConfig{
|
|
Spec: addonapiv1beta1.AddOnDeploymentConfigSpec{
|
|
ResourceRequirements: []addonapiv1beta1.ContainerResourceRequirements{
|
|
{
|
|
ContainerID: "deployments:d1:c1",
|
|
Resources: corev1.ResourceRequirements{
|
|
Requests: corev1.ResourceList{
|
|
corev1.ResourceMemory: resource.MustParse("128Mi"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
validateObject: func(t *testing.T, pod *corev1.PodTemplateSpec) {
|
|
for _, c := range pod.Spec.Containers {
|
|
if c.Name == "c1" {
|
|
if c.Resources.Requests.Memory() == nil || c.Resources.Requests.Memory().String() != "128Mi" {
|
|
t.Errorf("memory request for c1 is not corrent, got %v", c.Resources)
|
|
}
|
|
} else {
|
|
if c.Resources.Requests.Memory() != nil && c.Resources.Requests.Memory().String() != "0" {
|
|
t.Errorf("memory request for other containers should not be set, got %v", c.Resources)
|
|
}
|
|
}
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "daemonset",
|
|
pod: &corev1.PodTemplateSpec{
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: "c1",
|
|
Image: "test",
|
|
},
|
|
{
|
|
Name: "c2",
|
|
Image: "test",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
resourceName: "d1",
|
|
supportResource: supportResourceDaemonset,
|
|
config: addonapiv1beta1.AddOnDeploymentConfig{
|
|
Spec: addonapiv1beta1.AddOnDeploymentConfigSpec{
|
|
ResourceRequirements: []addonapiv1beta1.ContainerResourceRequirements{
|
|
{
|
|
ContainerID: "daemonsets:d1:c1",
|
|
Resources: corev1.ResourceRequirements{
|
|
Requests: corev1.ResourceList{
|
|
corev1.ResourceMemory: resource.MustParse("128Mi"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
validateObject: func(t *testing.T, pod *corev1.PodTemplateSpec) {
|
|
for _, c := range pod.Spec.Containers {
|
|
if c.Name == "c1" {
|
|
if c.Resources.Requests.Memory() == nil || c.Resources.Requests.Memory().String() != "128Mi" {
|
|
t.Errorf("memory request for c1 is not corrent, got %v", c.Resources)
|
|
}
|
|
} else {
|
|
if c.Resources.Requests.Memory() != nil && c.Resources.Requests.Memory().String() != "0" {
|
|
t.Errorf("memory request for other containers should not be set, got %v", c.Resources)
|
|
}
|
|
}
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "regex match",
|
|
pod: &corev1.PodTemplateSpec{
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: "c1",
|
|
Image: "test",
|
|
},
|
|
{
|
|
Name: "c2",
|
|
Image: "test",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
resourceName: "d1",
|
|
supportResource: supportResourceDeployment,
|
|
config: addonapiv1beta1.AddOnDeploymentConfig{
|
|
Spec: addonapiv1beta1.AddOnDeploymentConfigSpec{
|
|
ResourceRequirements: []addonapiv1beta1.ContainerResourceRequirements{
|
|
{
|
|
ContainerID: "deployments:d1:c1",
|
|
Resources: corev1.ResourceRequirements{
|
|
Requests: corev1.ResourceList{
|
|
corev1.ResourceMemory: resource.MustParse("128Mi"),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
ContainerID: "*:*:*",
|
|
Resources: corev1.ResourceRequirements{
|
|
Requests: corev1.ResourceList{
|
|
corev1.ResourceMemory: resource.MustParse("256Mi"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
validateObject: func(t *testing.T, pod *corev1.PodTemplateSpec) {
|
|
for _, c := range pod.Spec.Containers {
|
|
if c.Resources.Requests.Memory() == nil || c.Resources.Requests.Memory().String() != "256Mi" {
|
|
t.Errorf("memory request for c1 is not corrent, got %v", c.Resources)
|
|
}
|
|
}
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
values, err := ToAddOnResourceRequirementsPrivateValues(tc.config)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ctx := context.TODO()
|
|
logger := klog.FromContext(ctx)
|
|
d := newResourceRequirementsDecorator(logger, tc.supportResource, values)
|
|
err = d.decorate(tc.resourceName, tc.pod)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tc.validateObject(t, tc.pod)
|
|
})
|
|
}
|
|
|
|
}
|