mirror of
https://github.com/stakater/Reloader.git
synced 2026-05-17 06:06:39 +00:00
feat: Initial e2e tests and migrate old ones into e2e
This commit is contained in:
File diff suppressed because it is too large
Load Diff
358
internal/pkg/handler/create_test.go
Normal file
358
internal/pkg/handler/create_test.go
Normal file
@@ -0,0 +1,358 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stakater/Reloader/internal/pkg/constants"
|
||||
"github.com/stakater/Reloader/internal/pkg/metrics"
|
||||
"github.com/stretchr/testify/assert"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestResourceCreatedHandler_GetConfig(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
resource interface{}
|
||||
expectedName string
|
||||
expectedNS string
|
||||
expectedType string
|
||||
expectSHANotEmpty bool
|
||||
expectOldSHAEmpty bool
|
||||
}{
|
||||
{
|
||||
name: "ConfigMap with data",
|
||||
resource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "my-configmap",
|
||||
Namespace: "test-ns",
|
||||
},
|
||||
Data: map[string]string{
|
||||
"key1": "value1",
|
||||
"key2": "value2",
|
||||
},
|
||||
},
|
||||
expectedName: "my-configmap",
|
||||
expectedNS: "test-ns",
|
||||
expectedType: constants.ConfigmapEnvVarPostfix,
|
||||
expectSHANotEmpty: true,
|
||||
expectOldSHAEmpty: true,
|
||||
},
|
||||
{
|
||||
name: "ConfigMap with empty data",
|
||||
resource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "empty-configmap",
|
||||
Namespace: "default",
|
||||
},
|
||||
Data: map[string]string{},
|
||||
},
|
||||
expectedName: "empty-configmap",
|
||||
expectedNS: "default",
|
||||
expectedType: constants.ConfigmapEnvVarPostfix,
|
||||
expectSHANotEmpty: true,
|
||||
expectOldSHAEmpty: true,
|
||||
},
|
||||
{
|
||||
name: "ConfigMap with binary data",
|
||||
resource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "binary-configmap",
|
||||
Namespace: "default",
|
||||
},
|
||||
BinaryData: map[string][]byte{
|
||||
"binary-key": []byte("binary-value"),
|
||||
},
|
||||
},
|
||||
expectedName: "binary-configmap",
|
||||
expectedNS: "default",
|
||||
expectedType: constants.ConfigmapEnvVarPostfix,
|
||||
expectSHANotEmpty: true,
|
||||
expectOldSHAEmpty: true,
|
||||
},
|
||||
{
|
||||
name: "ConfigMap with annotations",
|
||||
resource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "annotated-configmap",
|
||||
Namespace: "default",
|
||||
Annotations: map[string]string{
|
||||
"reloader.stakater.com/match": "true",
|
||||
},
|
||||
},
|
||||
Data: map[string]string{"key": "value"},
|
||||
},
|
||||
expectedName: "annotated-configmap",
|
||||
expectedNS: "default",
|
||||
expectedType: constants.ConfigmapEnvVarPostfix,
|
||||
expectSHANotEmpty: true,
|
||||
expectOldSHAEmpty: true,
|
||||
},
|
||||
{
|
||||
name: "Secret with data",
|
||||
resource: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "my-secret",
|
||||
Namespace: "secret-ns",
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"password": []byte("secret-password"),
|
||||
},
|
||||
},
|
||||
expectedName: "my-secret",
|
||||
expectedNS: "secret-ns",
|
||||
expectedType: constants.SecretEnvVarPostfix,
|
||||
expectSHANotEmpty: true,
|
||||
expectOldSHAEmpty: true,
|
||||
},
|
||||
{
|
||||
name: "Secret with empty data",
|
||||
resource: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "empty-secret",
|
||||
Namespace: "default",
|
||||
},
|
||||
Data: map[string][]byte{},
|
||||
},
|
||||
expectedName: "empty-secret",
|
||||
expectedNS: "default",
|
||||
expectedType: constants.SecretEnvVarPostfix,
|
||||
expectSHANotEmpty: true,
|
||||
expectOldSHAEmpty: true,
|
||||
},
|
||||
{
|
||||
name: "Secret with StringData",
|
||||
resource: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "stringdata-secret",
|
||||
Namespace: "default",
|
||||
},
|
||||
StringData: map[string]string{
|
||||
"username": "admin",
|
||||
},
|
||||
},
|
||||
expectedName: "stringdata-secret",
|
||||
expectedNS: "default",
|
||||
expectedType: constants.SecretEnvVarPostfix,
|
||||
expectSHANotEmpty: true,
|
||||
expectOldSHAEmpty: true,
|
||||
},
|
||||
{
|
||||
name: "Secret with labels",
|
||||
resource: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "labeled-secret",
|
||||
Namespace: "default",
|
||||
Labels: map[string]string{
|
||||
"app": "test",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{"key": []byte("value")},
|
||||
},
|
||||
expectedName: "labeled-secret",
|
||||
expectedNS: "default",
|
||||
expectedType: constants.SecretEnvVarPostfix,
|
||||
expectSHANotEmpty: true,
|
||||
expectOldSHAEmpty: true,
|
||||
},
|
||||
{
|
||||
name: "Invalid resource type - string",
|
||||
resource: "invalid-string",
|
||||
expectedName: "",
|
||||
expectedNS: "",
|
||||
expectedType: "",
|
||||
expectSHANotEmpty: false,
|
||||
expectOldSHAEmpty: true,
|
||||
},
|
||||
{
|
||||
name: "Invalid resource type - int",
|
||||
resource: 123,
|
||||
expectedName: "",
|
||||
expectedNS: "",
|
||||
expectedType: "",
|
||||
expectSHANotEmpty: false,
|
||||
expectOldSHAEmpty: true,
|
||||
},
|
||||
{
|
||||
name: "Invalid resource type - struct",
|
||||
resource: struct{ Name string }{Name: "test"},
|
||||
expectedName: "",
|
||||
expectedNS: "",
|
||||
expectedType: "",
|
||||
expectSHANotEmpty: false,
|
||||
expectOldSHAEmpty: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
handler := ResourceCreatedHandler{
|
||||
Resource: tt.resource,
|
||||
Collectors: metrics.NewCollectors(),
|
||||
}
|
||||
|
||||
config, oldSHA := handler.GetConfig()
|
||||
|
||||
assert.Equal(t, tt.expectedName, config.ResourceName)
|
||||
assert.Equal(t, tt.expectedNS, config.Namespace)
|
||||
assert.Equal(t, tt.expectedType, config.Type)
|
||||
|
||||
if tt.expectSHANotEmpty {
|
||||
assert.NotEmpty(t, config.SHAValue, "SHA should not be empty")
|
||||
}
|
||||
|
||||
if tt.expectOldSHAEmpty {
|
||||
assert.Empty(t, oldSHA, "oldSHA should always be empty for create handler")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestResourceCreatedHandler_GetConfig_Annotations(t *testing.T) {
|
||||
// Test that annotations are properly captured in config
|
||||
cm := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "annotated-cm",
|
||||
Namespace: "default",
|
||||
Annotations: map[string]string{
|
||||
"reloader.stakater.com/match": "true",
|
||||
"reloader.stakater.com/search": "true",
|
||||
},
|
||||
},
|
||||
Data: map[string]string{"key": "value"},
|
||||
}
|
||||
|
||||
handler := ResourceCreatedHandler{
|
||||
Resource: cm,
|
||||
Collectors: metrics.NewCollectors(),
|
||||
}
|
||||
|
||||
config, _ := handler.GetConfig()
|
||||
|
||||
assert.NotNil(t, config.ResourceAnnotations)
|
||||
assert.Equal(t, "true", config.ResourceAnnotations["reloader.stakater.com/match"])
|
||||
assert.Equal(t, "true", config.ResourceAnnotations["reloader.stakater.com/search"])
|
||||
}
|
||||
|
||||
func TestResourceCreatedHandler_GetConfig_Labels(t *testing.T) {
|
||||
// Test that labels are properly captured in config
|
||||
secret := &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "labeled-secret",
|
||||
Namespace: "default",
|
||||
Labels: map[string]string{
|
||||
"app": "myapp",
|
||||
"version": "v1",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{"key": []byte("value")},
|
||||
}
|
||||
|
||||
handler := ResourceCreatedHandler{
|
||||
Resource: secret,
|
||||
Collectors: metrics.NewCollectors(),
|
||||
}
|
||||
|
||||
config, _ := handler.GetConfig()
|
||||
|
||||
assert.NotNil(t, config.Labels)
|
||||
assert.Equal(t, "myapp", config.Labels["app"])
|
||||
assert.Equal(t, "v1", config.Labels["version"])
|
||||
}
|
||||
|
||||
func TestResourceCreatedHandler_Handle(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
resource interface{}
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "Nil resource",
|
||||
resource: nil,
|
||||
expectError: false, // logs error but returns nil
|
||||
},
|
||||
{
|
||||
name: "Valid ConfigMap - no workloads to update",
|
||||
resource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-cm",
|
||||
Namespace: "default",
|
||||
},
|
||||
Data: map[string]string{"key": "value"},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Valid Secret - no workloads to update",
|
||||
resource: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-secret",
|
||||
Namespace: "default",
|
||||
},
|
||||
Data: map[string][]byte{"key": []byte("value")},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
handler := ResourceCreatedHandler{
|
||||
Resource: tt.resource,
|
||||
Collectors: metrics.NewCollectors(),
|
||||
}
|
||||
|
||||
err := handler.Handle()
|
||||
|
||||
if tt.expectError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestResourceCreatedHandler_SHAConsistency(t *testing.T) {
|
||||
// Test that same data produces same SHA
|
||||
data := map[string]string{"key": "value"}
|
||||
|
||||
cm1 := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "cm1", Namespace: "default"},
|
||||
Data: data,
|
||||
}
|
||||
cm2 := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "cm2", Namespace: "default"},
|
||||
Data: data,
|
||||
}
|
||||
|
||||
handler1 := ResourceCreatedHandler{Resource: cm1, Collectors: metrics.NewCollectors()}
|
||||
handler2 := ResourceCreatedHandler{Resource: cm2, Collectors: metrics.NewCollectors()}
|
||||
|
||||
config1, _ := handler1.GetConfig()
|
||||
config2, _ := handler2.GetConfig()
|
||||
|
||||
// Same data should produce same SHA
|
||||
assert.Equal(t, config1.SHAValue, config2.SHAValue)
|
||||
}
|
||||
|
||||
func TestResourceCreatedHandler_SHADifference(t *testing.T) {
|
||||
// Test that different data produces different SHA
|
||||
cm1 := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "cm", Namespace: "default"},
|
||||
Data: map[string]string{"key": "value1"},
|
||||
}
|
||||
cm2 := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "cm", Namespace: "default"},
|
||||
Data: map[string]string{"key": "value2"},
|
||||
}
|
||||
|
||||
handler1 := ResourceCreatedHandler{Resource: cm1, Collectors: metrics.NewCollectors()}
|
||||
handler2 := ResourceCreatedHandler{Resource: cm2, Collectors: metrics.NewCollectors()}
|
||||
|
||||
config1, _ := handler1.GetConfig()
|
||||
config2, _ := handler2.GetConfig()
|
||||
|
||||
// Different data should produce different SHA
|
||||
assert.NotEqual(t, config1.SHAValue, config2.SHAValue)
|
||||
}
|
||||
356
internal/pkg/handler/delete_test.go
Normal file
356
internal/pkg/handler/delete_test.go
Normal file
@@ -0,0 +1,356 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stakater/Reloader/internal/pkg/callbacks"
|
||||
"github.com/stakater/Reloader/internal/pkg/constants"
|
||||
"github.com/stakater/Reloader/internal/pkg/options"
|
||||
"github.com/stakater/Reloader/pkg/common"
|
||||
"github.com/stretchr/testify/assert"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// mockDeploymentForDelete creates a deployment with containers for testing delete strategies
|
||||
func mockDeploymentForDelete(name, namespace string, containers []v1.Container, volumes []v1.Volume) *appsv1.Deployment {
|
||||
return &appsv1.Deployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Spec: appsv1.DeploymentSpec{
|
||||
Template: v1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: containers,
|
||||
Volumes: volumes,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Mock funcs for testing
|
||||
func mockContainersFunc(item runtime.Object) []v1.Container {
|
||||
deployment, ok := item.(*appsv1.Deployment)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return deployment.Spec.Template.Spec.Containers
|
||||
}
|
||||
|
||||
func mockInitContainersFunc(item runtime.Object) []v1.Container {
|
||||
deployment, ok := item.(*appsv1.Deployment)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return deployment.Spec.Template.Spec.InitContainers
|
||||
}
|
||||
|
||||
func mockVolumesFunc(item runtime.Object) []v1.Volume {
|
||||
deployment, ok := item.(*appsv1.Deployment)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return deployment.Spec.Template.Spec.Volumes
|
||||
}
|
||||
|
||||
func mockPodAnnotationsFunc(item runtime.Object) map[string]string {
|
||||
deployment, ok := item.(*appsv1.Deployment)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return deployment.Spec.Template.Annotations
|
||||
}
|
||||
|
||||
func mockPatchTemplatesFunc() callbacks.PatchTemplates {
|
||||
return callbacks.PatchTemplates{
|
||||
AnnotationTemplate: `{"spec":{"template":{"metadata":{"annotations":{"%s":"%s"}}}}}`,
|
||||
EnvVarTemplate: `{"spec":{"template":{"spec":{"containers":[{"name":"%s","env":[{"name":"%s","value":"%s"}]}]}}}}`,
|
||||
DeleteEnvVarTemplate: `[{"op":"remove","path":"/spec/template/spec/containers/%d/env/%d"}]`,
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveContainerEnvVars(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
containers []v1.Container
|
||||
volumes []v1.Volume
|
||||
config common.Config
|
||||
autoReload bool
|
||||
expected constants.Result
|
||||
envVarRemoved bool
|
||||
}{
|
||||
{
|
||||
name: "Remove existing env var - configmap envFrom",
|
||||
containers: []v1.Container{
|
||||
{
|
||||
Name: "app",
|
||||
EnvFrom: []v1.EnvFromSource{
|
||||
{
|
||||
ConfigMapRef: &v1.ConfigMapEnvSource{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: "my-configmap",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Env: []v1.EnvVar{
|
||||
{Name: "STAKATER_MY_CONFIGMAP_CONFIGMAP", Value: "sha-value"},
|
||||
},
|
||||
},
|
||||
},
|
||||
volumes: []v1.Volume{},
|
||||
config: common.Config{
|
||||
ResourceName: "my-configmap",
|
||||
Type: constants.ConfigmapEnvVarPostfix,
|
||||
},
|
||||
autoReload: true,
|
||||
expected: constants.Updated,
|
||||
envVarRemoved: true,
|
||||
},
|
||||
{
|
||||
name: "No env var to remove",
|
||||
containers: []v1.Container{
|
||||
{
|
||||
Name: "app",
|
||||
EnvFrom: []v1.EnvFromSource{
|
||||
{
|
||||
ConfigMapRef: &v1.ConfigMapEnvSource{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: "my-configmap",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Env: []v1.EnvVar{}, // No env vars
|
||||
},
|
||||
},
|
||||
volumes: []v1.Volume{},
|
||||
config: common.Config{
|
||||
ResourceName: "my-configmap",
|
||||
Type: constants.ConfigmapEnvVarPostfix,
|
||||
},
|
||||
autoReload: true,
|
||||
expected: constants.NotUpdated,
|
||||
envVarRemoved: false,
|
||||
},
|
||||
{
|
||||
name: "Remove existing env var - secret envFrom",
|
||||
containers: []v1.Container{
|
||||
{
|
||||
Name: "app",
|
||||
EnvFrom: []v1.EnvFromSource{
|
||||
{
|
||||
SecretRef: &v1.SecretEnvSource{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: "my-secret",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Env: []v1.EnvVar{
|
||||
{Name: "STAKATER_MY_SECRET_SECRET", Value: "sha-value"},
|
||||
},
|
||||
},
|
||||
},
|
||||
volumes: []v1.Volume{},
|
||||
config: common.Config{
|
||||
ResourceName: "my-secret",
|
||||
Type: constants.SecretEnvVarPostfix,
|
||||
},
|
||||
autoReload: true,
|
||||
expected: constants.Updated,
|
||||
envVarRemoved: true,
|
||||
},
|
||||
{
|
||||
name: "No container found",
|
||||
containers: []v1.Container{},
|
||||
volumes: []v1.Volume{},
|
||||
config: common.Config{
|
||||
ResourceName: "my-configmap",
|
||||
Type: constants.ConfigmapEnvVarPostfix,
|
||||
},
|
||||
autoReload: true,
|
||||
expected: constants.NoContainerFound,
|
||||
envVarRemoved: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
deployment := mockDeploymentForDelete("test-deploy", "default", tt.containers, tt.volumes)
|
||||
|
||||
funcs := callbacks.RollingUpgradeFuncs{
|
||||
ContainersFunc: mockContainersFunc,
|
||||
InitContainersFunc: mockInitContainersFunc,
|
||||
VolumesFunc: mockVolumesFunc,
|
||||
PodAnnotationsFunc: mockPodAnnotationsFunc,
|
||||
PatchTemplatesFunc: mockPatchTemplatesFunc,
|
||||
SupportsPatch: true,
|
||||
}
|
||||
|
||||
result := removeContainerEnvVars(funcs, deployment, tt.config, tt.autoReload)
|
||||
|
||||
assert.Equal(t, tt.expected, result.Result)
|
||||
|
||||
if tt.envVarRemoved {
|
||||
// Verify env var was removed from container
|
||||
containers := deployment.Spec.Template.Spec.Containers
|
||||
for _, c := range containers {
|
||||
for _, env := range c.Env {
|
||||
envVarName := getEnvVarName(tt.config.ResourceName, tt.config.Type)
|
||||
assert.NotEqual(t, envVarName, env.Name, "Env var should have been removed")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvokeDeleteStrategy(t *testing.T) {
|
||||
// Save original strategy and restore after test
|
||||
originalStrategy := options.ReloadStrategy
|
||||
defer func() {
|
||||
options.ReloadStrategy = originalStrategy
|
||||
}()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
reloadStrategy string
|
||||
containers []v1.Container
|
||||
volumes []v1.Volume
|
||||
config common.Config
|
||||
}{
|
||||
{
|
||||
name: "Annotations strategy",
|
||||
reloadStrategy: constants.AnnotationsReloadStrategy,
|
||||
containers: []v1.Container{
|
||||
{
|
||||
Name: "app",
|
||||
EnvFrom: []v1.EnvFromSource{
|
||||
{
|
||||
ConfigMapRef: &v1.ConfigMapEnvSource{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: "my-configmap",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
volumes: []v1.Volume{},
|
||||
config: common.Config{
|
||||
ResourceName: "my-configmap",
|
||||
Type: constants.ConfigmapEnvVarPostfix,
|
||||
SHAValue: "sha-value",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "EnvVars strategy",
|
||||
reloadStrategy: constants.EnvVarsReloadStrategy,
|
||||
containers: []v1.Container{
|
||||
{
|
||||
Name: "app",
|
||||
EnvFrom: []v1.EnvFromSource{
|
||||
{
|
||||
ConfigMapRef: &v1.ConfigMapEnvSource{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: "my-configmap",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Env: []v1.EnvVar{
|
||||
{Name: "STAKATER_MY_CONFIGMAP_CONFIGMAP", Value: "sha-value"},
|
||||
},
|
||||
},
|
||||
},
|
||||
volumes: []v1.Volume{},
|
||||
config: common.Config{
|
||||
ResourceName: "my-configmap",
|
||||
Type: constants.ConfigmapEnvVarPostfix,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
options.ReloadStrategy = tt.reloadStrategy
|
||||
|
||||
deployment := mockDeploymentForDelete("test-deploy", "default", tt.containers, tt.volumes)
|
||||
|
||||
funcs := callbacks.RollingUpgradeFuncs{
|
||||
ContainersFunc: mockContainersFunc,
|
||||
InitContainersFunc: mockInitContainersFunc,
|
||||
VolumesFunc: mockVolumesFunc,
|
||||
PodAnnotationsFunc: mockPodAnnotationsFunc,
|
||||
PatchTemplatesFunc: mockPatchTemplatesFunc,
|
||||
SupportsPatch: true,
|
||||
}
|
||||
|
||||
result := invokeDeleteStrategy(funcs, deployment, tt.config, true)
|
||||
|
||||
// Should return a valid result
|
||||
assert.NotNil(t, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemovePodAnnotations(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
containers []v1.Container
|
||||
volumes []v1.Volume
|
||||
config common.Config
|
||||
}{
|
||||
{
|
||||
name: "Remove pod annotations - configmap",
|
||||
containers: []v1.Container{
|
||||
{
|
||||
Name: "app",
|
||||
EnvFrom: []v1.EnvFromSource{
|
||||
{
|
||||
ConfigMapRef: &v1.ConfigMapEnvSource{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: "my-configmap",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
volumes: []v1.Volume{},
|
||||
config: common.Config{
|
||||
ResourceName: "my-configmap",
|
||||
Type: constants.ConfigmapEnvVarPostfix,
|
||||
SHAValue: "sha-value",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
deployment := mockDeploymentForDelete("test-deploy", "default", tt.containers, tt.volumes)
|
||||
|
||||
funcs := callbacks.RollingUpgradeFuncs{
|
||||
ContainersFunc: mockContainersFunc,
|
||||
InitContainersFunc: mockInitContainersFunc,
|
||||
VolumesFunc: mockVolumesFunc,
|
||||
PodAnnotationsFunc: mockPodAnnotationsFunc,
|
||||
PatchTemplatesFunc: mockPatchTemplatesFunc,
|
||||
SupportsPatch: false, // No patch for annotations removal test
|
||||
}
|
||||
|
||||
result := removePodAnnotations(funcs, deployment, tt.config, true)
|
||||
|
||||
// Should return Updated since it sets the SHA to empty data hash
|
||||
assert.Equal(t, constants.Updated, result.Result)
|
||||
})
|
||||
}
|
||||
}
|
||||
288
internal/pkg/handler/handlers_test.go
Normal file
288
internal/pkg/handler/handlers_test.go
Normal file
@@ -0,0 +1,288 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stakater/Reloader/internal/pkg/constants"
|
||||
"github.com/stakater/Reloader/internal/pkg/metrics"
|
||||
"github.com/stretchr/testify/assert"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// Helper function to create a test ConfigMap
|
||||
func createTestConfigMap(name, namespace string, data map[string]string) *v1.ConfigMap {
|
||||
return &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Data: data,
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to create a test Secret
|
||||
func createTestSecret(name, namespace string, data map[string][]byte) *v1.Secret {
|
||||
return &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Data: data,
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to create test metrics collectors
|
||||
func createTestCollectors() metrics.Collectors {
|
||||
return metrics.NewCollectors()
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// ResourceCreatedHandler Tests
|
||||
// ============================================================
|
||||
|
||||
func TestResourceCreatedHandler_GetConfig_ConfigMap(t *testing.T) {
|
||||
cm := createTestConfigMap("test-cm", "default", map[string]string{"key": "value"})
|
||||
handler := ResourceCreatedHandler{
|
||||
Resource: cm,
|
||||
Collectors: createTestCollectors(),
|
||||
}
|
||||
|
||||
config, oldSHA := handler.GetConfig()
|
||||
|
||||
assert.Equal(t, "test-cm", config.ResourceName)
|
||||
assert.Equal(t, "default", config.Namespace)
|
||||
assert.Equal(t, constants.ConfigmapEnvVarPostfix, config.Type)
|
||||
assert.NotEmpty(t, config.SHAValue)
|
||||
assert.Empty(t, oldSHA) // oldSHA is always empty for create handler
|
||||
}
|
||||
|
||||
func TestResourceCreatedHandler_GetConfig_Secret(t *testing.T) {
|
||||
secret := createTestSecret("test-secret", "default", map[string][]byte{"key": []byte("value")})
|
||||
handler := ResourceCreatedHandler{
|
||||
Resource: secret,
|
||||
Collectors: createTestCollectors(),
|
||||
}
|
||||
|
||||
config, oldSHA := handler.GetConfig()
|
||||
|
||||
assert.Equal(t, "test-secret", config.ResourceName)
|
||||
assert.Equal(t, "default", config.Namespace)
|
||||
assert.Equal(t, constants.SecretEnvVarPostfix, config.Type)
|
||||
assert.NotEmpty(t, config.SHAValue)
|
||||
assert.Empty(t, oldSHA)
|
||||
}
|
||||
|
||||
func TestResourceCreatedHandler_GetConfig_InvalidResource(t *testing.T) {
|
||||
// Test with an invalid resource type
|
||||
handler := ResourceCreatedHandler{
|
||||
Resource: "invalid",
|
||||
Collectors: createTestCollectors(),
|
||||
}
|
||||
|
||||
config, _ := handler.GetConfig()
|
||||
|
||||
// Config should be empty/zero for invalid resources
|
||||
assert.Empty(t, config.ResourceName)
|
||||
}
|
||||
|
||||
func TestResourceCreatedHandler_Handle_NilResource(t *testing.T) {
|
||||
handler := ResourceCreatedHandler{
|
||||
Resource: nil,
|
||||
Collectors: createTestCollectors(),
|
||||
}
|
||||
|
||||
err := handler.Handle()
|
||||
|
||||
// Should not return error even with nil resource (just logs error)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// ResourceDeleteHandler Tests
|
||||
// ============================================================
|
||||
|
||||
func TestResourceDeleteHandler_GetConfig_ConfigMap(t *testing.T) {
|
||||
cm := createTestConfigMap("test-cm", "default", map[string]string{"key": "value"})
|
||||
handler := ResourceDeleteHandler{
|
||||
Resource: cm,
|
||||
Collectors: createTestCollectors(),
|
||||
}
|
||||
|
||||
config, oldSHA := handler.GetConfig()
|
||||
|
||||
assert.Equal(t, "test-cm", config.ResourceName)
|
||||
assert.Equal(t, "default", config.Namespace)
|
||||
assert.Equal(t, constants.ConfigmapEnvVarPostfix, config.Type)
|
||||
assert.NotEmpty(t, config.SHAValue)
|
||||
assert.Empty(t, oldSHA)
|
||||
}
|
||||
|
||||
func TestResourceDeleteHandler_GetConfig_Secret(t *testing.T) {
|
||||
secret := createTestSecret("test-secret", "default", map[string][]byte{"key": []byte("value")})
|
||||
handler := ResourceDeleteHandler{
|
||||
Resource: secret,
|
||||
Collectors: createTestCollectors(),
|
||||
}
|
||||
|
||||
config, oldSHA := handler.GetConfig()
|
||||
|
||||
assert.Equal(t, "test-secret", config.ResourceName)
|
||||
assert.Equal(t, "default", config.Namespace)
|
||||
assert.Equal(t, constants.SecretEnvVarPostfix, config.Type)
|
||||
assert.NotEmpty(t, config.SHAValue)
|
||||
assert.Empty(t, oldSHA)
|
||||
}
|
||||
|
||||
func TestResourceDeleteHandler_GetConfig_InvalidResource(t *testing.T) {
|
||||
handler := ResourceDeleteHandler{
|
||||
Resource: "invalid",
|
||||
Collectors: createTestCollectors(),
|
||||
}
|
||||
|
||||
config, _ := handler.GetConfig()
|
||||
|
||||
assert.Empty(t, config.ResourceName)
|
||||
}
|
||||
|
||||
func TestResourceDeleteHandler_Handle_NilResource(t *testing.T) {
|
||||
handler := ResourceDeleteHandler{
|
||||
Resource: nil,
|
||||
Collectors: createTestCollectors(),
|
||||
}
|
||||
|
||||
err := handler.Handle()
|
||||
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// ResourceUpdatedHandler Tests
|
||||
// ============================================================
|
||||
|
||||
func TestResourceUpdatedHandler_GetConfig_ConfigMap(t *testing.T) {
|
||||
oldCM := createTestConfigMap("test-cm", "default", map[string]string{"key": "old-value"})
|
||||
newCM := createTestConfigMap("test-cm", "default", map[string]string{"key": "new-value"})
|
||||
|
||||
handler := ResourceUpdatedHandler{
|
||||
Resource: newCM,
|
||||
OldResource: oldCM,
|
||||
Collectors: createTestCollectors(),
|
||||
}
|
||||
|
||||
config, oldSHA := handler.GetConfig()
|
||||
|
||||
assert.Equal(t, "test-cm", config.ResourceName)
|
||||
assert.Equal(t, "default", config.Namespace)
|
||||
assert.Equal(t, constants.ConfigmapEnvVarPostfix, config.Type)
|
||||
assert.NotEmpty(t, config.SHAValue)
|
||||
assert.NotEmpty(t, oldSHA)
|
||||
// SHAs should be different since data changed
|
||||
assert.NotEqual(t, config.SHAValue, oldSHA)
|
||||
}
|
||||
|
||||
func TestResourceUpdatedHandler_GetConfig_ConfigMap_SameData(t *testing.T) {
|
||||
oldCM := createTestConfigMap("test-cm", "default", map[string]string{"key": "same-value"})
|
||||
newCM := createTestConfigMap("test-cm", "default", map[string]string{"key": "same-value"})
|
||||
|
||||
handler := ResourceUpdatedHandler{
|
||||
Resource: newCM,
|
||||
OldResource: oldCM,
|
||||
Collectors: createTestCollectors(),
|
||||
}
|
||||
|
||||
config, oldSHA := handler.GetConfig()
|
||||
|
||||
assert.Equal(t, "test-cm", config.ResourceName)
|
||||
// SHAs should be the same since data didn't change
|
||||
assert.Equal(t, config.SHAValue, oldSHA)
|
||||
}
|
||||
|
||||
func TestResourceUpdatedHandler_GetConfig_Secret(t *testing.T) {
|
||||
oldSecret := createTestSecret("test-secret", "default", map[string][]byte{"key": []byte("old-value")})
|
||||
newSecret := createTestSecret("test-secret", "default", map[string][]byte{"key": []byte("new-value")})
|
||||
|
||||
handler := ResourceUpdatedHandler{
|
||||
Resource: newSecret,
|
||||
OldResource: oldSecret,
|
||||
Collectors: createTestCollectors(),
|
||||
}
|
||||
|
||||
config, oldSHA := handler.GetConfig()
|
||||
|
||||
assert.Equal(t, "test-secret", config.ResourceName)
|
||||
assert.Equal(t, "default", config.Namespace)
|
||||
assert.Equal(t, constants.SecretEnvVarPostfix, config.Type)
|
||||
assert.NotEmpty(t, config.SHAValue)
|
||||
assert.NotEmpty(t, oldSHA)
|
||||
assert.NotEqual(t, config.SHAValue, oldSHA)
|
||||
}
|
||||
|
||||
func TestResourceUpdatedHandler_GetConfig_Secret_SameData(t *testing.T) {
|
||||
oldSecret := createTestSecret("test-secret", "default", map[string][]byte{"key": []byte("same-value")})
|
||||
newSecret := createTestSecret("test-secret", "default", map[string][]byte{"key": []byte("same-value")})
|
||||
|
||||
handler := ResourceUpdatedHandler{
|
||||
Resource: newSecret,
|
||||
OldResource: oldSecret,
|
||||
Collectors: createTestCollectors(),
|
||||
}
|
||||
|
||||
config, oldSHA := handler.GetConfig()
|
||||
|
||||
assert.Equal(t, "test-secret", config.ResourceName)
|
||||
// SHAs should be the same since data didn't change
|
||||
assert.Equal(t, config.SHAValue, oldSHA)
|
||||
}
|
||||
|
||||
func TestResourceUpdatedHandler_GetConfig_InvalidResource(t *testing.T) {
|
||||
handler := ResourceUpdatedHandler{
|
||||
Resource: "invalid",
|
||||
OldResource: "invalid",
|
||||
Collectors: createTestCollectors(),
|
||||
}
|
||||
|
||||
config, _ := handler.GetConfig()
|
||||
|
||||
assert.Empty(t, config.ResourceName)
|
||||
}
|
||||
|
||||
func TestResourceUpdatedHandler_Handle_NilResource(t *testing.T) {
|
||||
handler := ResourceUpdatedHandler{
|
||||
Resource: nil,
|
||||
OldResource: nil,
|
||||
Collectors: createTestCollectors(),
|
||||
}
|
||||
|
||||
err := handler.Handle()
|
||||
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestResourceUpdatedHandler_Handle_NilOldResource(t *testing.T) {
|
||||
cm := createTestConfigMap("test-cm", "default", map[string]string{"key": "value"})
|
||||
handler := ResourceUpdatedHandler{
|
||||
Resource: cm,
|
||||
OldResource: nil,
|
||||
Collectors: createTestCollectors(),
|
||||
}
|
||||
|
||||
err := handler.Handle()
|
||||
|
||||
// Should not return error (just logs error)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestResourceUpdatedHandler_Handle_NoChange(t *testing.T) {
|
||||
// When SHA values are the same, Handle should return nil without doing anything
|
||||
cm := createTestConfigMap("test-cm", "default", map[string]string{"key": "same-value"})
|
||||
handler := ResourceUpdatedHandler{
|
||||
Resource: cm,
|
||||
OldResource: cm, // Same resource = same SHA
|
||||
Collectors: createTestCollectors(),
|
||||
}
|
||||
|
||||
err := handler.Handle()
|
||||
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
530
internal/pkg/handler/update_test.go
Normal file
530
internal/pkg/handler/update_test.go
Normal file
@@ -0,0 +1,530 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stakater/Reloader/internal/pkg/constants"
|
||||
"github.com/stakater/Reloader/internal/pkg/metrics"
|
||||
"github.com/stretchr/testify/assert"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestResourceUpdatedHandler_GetConfig(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
oldResource any
|
||||
newResource any
|
||||
expectedName string
|
||||
expectedNS string
|
||||
expectedType string
|
||||
expectSHANotEmpty bool
|
||||
expectSHAChanged bool
|
||||
}{
|
||||
{
|
||||
name: "ConfigMap data changed",
|
||||
oldResource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "my-cm", Namespace: "default"},
|
||||
Data: map[string]string{"key": "old-value"},
|
||||
},
|
||||
newResource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "my-cm", Namespace: "default"},
|
||||
Data: map[string]string{"key": "new-value"},
|
||||
},
|
||||
expectedName: "my-cm",
|
||||
expectedNS: "default",
|
||||
expectedType: constants.ConfigmapEnvVarPostfix,
|
||||
expectSHANotEmpty: true,
|
||||
expectSHAChanged: true,
|
||||
},
|
||||
{
|
||||
name: "ConfigMap data unchanged",
|
||||
oldResource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "my-cm", Namespace: "default"},
|
||||
Data: map[string]string{"key": "same-value"},
|
||||
},
|
||||
newResource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "my-cm", Namespace: "default"},
|
||||
Data: map[string]string{"key": "same-value"},
|
||||
},
|
||||
expectedName: "my-cm",
|
||||
expectedNS: "default",
|
||||
expectedType: constants.ConfigmapEnvVarPostfix,
|
||||
expectSHANotEmpty: true,
|
||||
expectSHAChanged: false,
|
||||
},
|
||||
{
|
||||
name: "ConfigMap key added",
|
||||
oldResource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "my-cm", Namespace: "default"},
|
||||
Data: map[string]string{"key1": "value1"},
|
||||
},
|
||||
newResource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "my-cm", Namespace: "default"},
|
||||
Data: map[string]string{"key1": "value1", "key2": "value2"},
|
||||
},
|
||||
expectedName: "my-cm",
|
||||
expectedNS: "default",
|
||||
expectedType: constants.ConfigmapEnvVarPostfix,
|
||||
expectSHANotEmpty: true,
|
||||
expectSHAChanged: true,
|
||||
},
|
||||
{
|
||||
name: "ConfigMap key removed",
|
||||
oldResource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "my-cm", Namespace: "default"},
|
||||
Data: map[string]string{"key1": "value1", "key2": "value2"},
|
||||
},
|
||||
newResource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "my-cm", Namespace: "default"},
|
||||
Data: map[string]string{"key1": "value1"},
|
||||
},
|
||||
expectedName: "my-cm",
|
||||
expectedNS: "default",
|
||||
expectedType: constants.ConfigmapEnvVarPostfix,
|
||||
expectSHANotEmpty: true,
|
||||
expectSHAChanged: true,
|
||||
},
|
||||
{
|
||||
name: "ConfigMap only labels changed - SHA unchanged",
|
||||
oldResource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "my-cm",
|
||||
Namespace: "default",
|
||||
Labels: map[string]string{"version": "v1"},
|
||||
},
|
||||
Data: map[string]string{"key": "value"},
|
||||
},
|
||||
newResource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "my-cm",
|
||||
Namespace: "default",
|
||||
Labels: map[string]string{"version": "v2"},
|
||||
},
|
||||
Data: map[string]string{"key": "value"},
|
||||
},
|
||||
expectedName: "my-cm",
|
||||
expectedNS: "default",
|
||||
expectedType: constants.ConfigmapEnvVarPostfix,
|
||||
expectSHANotEmpty: true,
|
||||
expectSHAChanged: false, // Only data affects SHA, not labels
|
||||
},
|
||||
{
|
||||
name: "ConfigMap only annotations changed - SHA unchanged",
|
||||
oldResource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "my-cm",
|
||||
Namespace: "default",
|
||||
Annotations: map[string]string{"note": "old"},
|
||||
},
|
||||
Data: map[string]string{"key": "value"},
|
||||
},
|
||||
newResource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "my-cm",
|
||||
Namespace: "default",
|
||||
Annotations: map[string]string{"note": "new"},
|
||||
},
|
||||
Data: map[string]string{"key": "value"},
|
||||
},
|
||||
expectedName: "my-cm",
|
||||
expectedNS: "default",
|
||||
expectedType: constants.ConfigmapEnvVarPostfix,
|
||||
expectSHANotEmpty: true,
|
||||
expectSHAChanged: false, // Only data affects SHA, not annotations
|
||||
},
|
||||
{
|
||||
name: "Secret data changed",
|
||||
oldResource: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "my-secret", Namespace: "default"},
|
||||
Data: map[string][]byte{"password": []byte("old-pass")},
|
||||
},
|
||||
newResource: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "my-secret", Namespace: "default"},
|
||||
Data: map[string][]byte{"password": []byte("new-pass")},
|
||||
},
|
||||
expectedName: "my-secret",
|
||||
expectedNS: "default",
|
||||
expectedType: constants.SecretEnvVarPostfix,
|
||||
expectSHANotEmpty: true,
|
||||
expectSHAChanged: true,
|
||||
},
|
||||
{
|
||||
name: "Secret data unchanged",
|
||||
oldResource: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "my-secret", Namespace: "default"},
|
||||
Data: map[string][]byte{"password": []byte("same-pass")},
|
||||
},
|
||||
newResource: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "my-secret", Namespace: "default"},
|
||||
Data: map[string][]byte{"password": []byte("same-pass")},
|
||||
},
|
||||
expectedName: "my-secret",
|
||||
expectedNS: "default",
|
||||
expectedType: constants.SecretEnvVarPostfix,
|
||||
expectSHANotEmpty: true,
|
||||
expectSHAChanged: false,
|
||||
},
|
||||
{
|
||||
name: "Secret key added",
|
||||
oldResource: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "my-secret", Namespace: "default"},
|
||||
Data: map[string][]byte{"key1": []byte("value1")},
|
||||
},
|
||||
newResource: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "my-secret", Namespace: "default"},
|
||||
Data: map[string][]byte{"key1": []byte("value1"), "key2": []byte("value2")},
|
||||
},
|
||||
expectedName: "my-secret",
|
||||
expectedNS: "default",
|
||||
expectedType: constants.SecretEnvVarPostfix,
|
||||
expectSHANotEmpty: true,
|
||||
expectSHAChanged: true,
|
||||
},
|
||||
{
|
||||
name: "Secret only labels changed - SHA unchanged",
|
||||
oldResource: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "my-secret",
|
||||
Namespace: "default",
|
||||
Labels: map[string]string{"env": "dev"},
|
||||
},
|
||||
Data: map[string][]byte{"key": []byte("value")},
|
||||
},
|
||||
newResource: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "my-secret",
|
||||
Namespace: "default",
|
||||
Labels: map[string]string{"env": "prod"},
|
||||
},
|
||||
Data: map[string][]byte{"key": []byte("value")},
|
||||
},
|
||||
expectedName: "my-secret",
|
||||
expectedNS: "default",
|
||||
expectedType: constants.SecretEnvVarPostfix,
|
||||
expectSHANotEmpty: true,
|
||||
expectSHAChanged: false,
|
||||
},
|
||||
{
|
||||
name: "Invalid resource type",
|
||||
oldResource: "invalid",
|
||||
newResource: "invalid",
|
||||
expectedName: "",
|
||||
expectedNS: "",
|
||||
expectedType: "",
|
||||
expectSHANotEmpty: false,
|
||||
expectSHAChanged: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
handler := ResourceUpdatedHandler{
|
||||
Resource: tt.newResource,
|
||||
OldResource: tt.oldResource,
|
||||
Collectors: metrics.NewCollectors(),
|
||||
}
|
||||
|
||||
config, oldSHA := handler.GetConfig()
|
||||
|
||||
assert.Equal(t, tt.expectedName, config.ResourceName)
|
||||
assert.Equal(t, tt.expectedNS, config.Namespace)
|
||||
assert.Equal(t, tt.expectedType, config.Type)
|
||||
|
||||
if tt.expectSHANotEmpty {
|
||||
assert.NotEmpty(t, config.SHAValue, "new SHA should not be empty")
|
||||
assert.NotEmpty(t, oldSHA, "old SHA should not be empty")
|
||||
}
|
||||
|
||||
if tt.expectSHAChanged {
|
||||
assert.NotEqual(t, config.SHAValue, oldSHA, "SHA should have changed")
|
||||
} else if tt.expectSHANotEmpty {
|
||||
assert.Equal(t, config.SHAValue, oldSHA, "SHA should not have changed")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestResourceUpdatedHandler_Handle(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
oldResource any
|
||||
newResource any
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "Both resources nil",
|
||||
oldResource: nil,
|
||||
newResource: nil,
|
||||
expectError: false, // logs error but returns nil
|
||||
},
|
||||
{
|
||||
name: "Old resource nil",
|
||||
oldResource: nil,
|
||||
newResource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "cm", Namespace: "default"},
|
||||
Data: map[string]string{"key": "value"},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "New resource nil",
|
||||
oldResource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "cm", Namespace: "default"},
|
||||
Data: map[string]string{"key": "value"},
|
||||
},
|
||||
newResource: nil,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "ConfigMap unchanged - no action",
|
||||
oldResource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "cm", Namespace: "default"},
|
||||
Data: map[string]string{"key": "same"},
|
||||
},
|
||||
newResource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "cm", Namespace: "default"},
|
||||
Data: map[string]string{"key": "same"},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "ConfigMap changed - triggers update",
|
||||
oldResource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "cm", Namespace: "default"},
|
||||
Data: map[string]string{"key": "old"},
|
||||
},
|
||||
newResource: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "cm", Namespace: "default"},
|
||||
Data: map[string]string{"key": "new"},
|
||||
},
|
||||
expectError: false, // No error, but no workloads to update in test
|
||||
},
|
||||
{
|
||||
name: "Secret unchanged - no action",
|
||||
oldResource: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "secret", Namespace: "default"},
|
||||
Data: map[string][]byte{"key": []byte("same")},
|
||||
},
|
||||
newResource: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "secret", Namespace: "default"},
|
||||
Data: map[string][]byte{"key": []byte("same")},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Secret changed - triggers update",
|
||||
oldResource: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "secret", Namespace: "default"},
|
||||
Data: map[string][]byte{"key": []byte("old")},
|
||||
},
|
||||
newResource: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "secret", Namespace: "default"},
|
||||
Data: map[string][]byte{"key": []byte("new")},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
handler := ResourceUpdatedHandler{
|
||||
Resource: tt.newResource,
|
||||
OldResource: tt.oldResource,
|
||||
Collectors: metrics.NewCollectors(),
|
||||
}
|
||||
|
||||
err := handler.Handle()
|
||||
|
||||
if tt.expectError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestResourceUpdatedHandler_GetConfig_Annotations(t *testing.T) {
|
||||
// Test that annotations from the new resource are captured
|
||||
oldCM := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "cm",
|
||||
Namespace: "default",
|
||||
Annotations: map[string]string{
|
||||
"old-annotation": "old-value",
|
||||
},
|
||||
},
|
||||
Data: map[string]string{"key": "value"},
|
||||
}
|
||||
|
||||
newCM := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "cm",
|
||||
Namespace: "default",
|
||||
Annotations: map[string]string{
|
||||
"new-annotation": "new-value",
|
||||
},
|
||||
},
|
||||
Data: map[string]string{"key": "value"},
|
||||
}
|
||||
|
||||
handler := ResourceUpdatedHandler{
|
||||
Resource: newCM,
|
||||
OldResource: oldCM,
|
||||
Collectors: metrics.NewCollectors(),
|
||||
}
|
||||
|
||||
config, _ := handler.GetConfig()
|
||||
|
||||
// Should have new annotations
|
||||
assert.Equal(t, "new-value", config.ResourceAnnotations["new-annotation"])
|
||||
// Should not have old annotations
|
||||
_, hasOld := config.ResourceAnnotations["old-annotation"]
|
||||
assert.False(t, hasOld)
|
||||
}
|
||||
|
||||
func TestResourceUpdatedHandler_GetConfig_Labels(t *testing.T) {
|
||||
// Test that labels from the new resource are captured
|
||||
oldSecret := &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "secret",
|
||||
Namespace: "default",
|
||||
Labels: map[string]string{"version": "v1"},
|
||||
},
|
||||
Data: map[string][]byte{"key": []byte("value")},
|
||||
}
|
||||
|
||||
newSecret := &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "secret",
|
||||
Namespace: "default",
|
||||
Labels: map[string]string{"version": "v2"},
|
||||
},
|
||||
Data: map[string][]byte{"key": []byte("value")},
|
||||
}
|
||||
|
||||
handler := ResourceUpdatedHandler{
|
||||
Resource: newSecret,
|
||||
OldResource: oldSecret,
|
||||
Collectors: metrics.NewCollectors(),
|
||||
}
|
||||
|
||||
config, _ := handler.GetConfig()
|
||||
|
||||
// Should have new labels
|
||||
assert.Equal(t, "v2", config.Labels["version"])
|
||||
}
|
||||
|
||||
func TestResourceUpdatedHandler_EmptyToNonEmpty(t *testing.T) {
|
||||
// Test transition from empty data to non-empty data
|
||||
oldCM := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "cm", Namespace: "default"},
|
||||
Data: map[string]string{},
|
||||
}
|
||||
newCM := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "cm", Namespace: "default"},
|
||||
Data: map[string]string{"key": "value"},
|
||||
}
|
||||
|
||||
handler := ResourceUpdatedHandler{
|
||||
Resource: newCM,
|
||||
OldResource: oldCM,
|
||||
Collectors: metrics.NewCollectors(),
|
||||
}
|
||||
|
||||
config, oldSHA := handler.GetConfig()
|
||||
|
||||
assert.NotEqual(t, config.SHAValue, oldSHA, "SHA should change when data is added")
|
||||
}
|
||||
|
||||
func TestResourceUpdatedHandler_NonEmptyToEmpty(t *testing.T) {
|
||||
// Test transition from non-empty data to empty data
|
||||
oldCM := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "cm", Namespace: "default"},
|
||||
Data: map[string]string{"key": "value"},
|
||||
}
|
||||
newCM := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "cm", Namespace: "default"},
|
||||
Data: map[string]string{},
|
||||
}
|
||||
|
||||
handler := ResourceUpdatedHandler{
|
||||
Resource: newCM,
|
||||
OldResource: oldCM,
|
||||
Collectors: metrics.NewCollectors(),
|
||||
}
|
||||
|
||||
config, oldSHA := handler.GetConfig()
|
||||
|
||||
assert.NotEqual(t, config.SHAValue, oldSHA, "SHA should change when data is removed")
|
||||
}
|
||||
|
||||
func TestResourceUpdatedHandler_BinaryDataChange(t *testing.T) {
|
||||
// Test ConfigMap binary data change
|
||||
oldCM := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "cm", Namespace: "default"},
|
||||
BinaryData: map[string][]byte{"binary": []byte("old-binary")},
|
||||
}
|
||||
newCM := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "cm", Namespace: "default"},
|
||||
BinaryData: map[string][]byte{"binary": []byte("new-binary")},
|
||||
}
|
||||
|
||||
handler := ResourceUpdatedHandler{
|
||||
Resource: newCM,
|
||||
OldResource: oldCM,
|
||||
Collectors: metrics.NewCollectors(),
|
||||
}
|
||||
|
||||
config, oldSHA := handler.GetConfig()
|
||||
|
||||
assert.NotEqual(t, config.SHAValue, oldSHA, "SHA should change when binary data changes")
|
||||
}
|
||||
|
||||
func TestResourceUpdatedHandler_MixedDataAndBinaryData(t *testing.T) {
|
||||
// Test ConfigMap with both Data and BinaryData
|
||||
oldCM := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "cm", Namespace: "default"},
|
||||
Data: map[string]string{"text": "value"},
|
||||
BinaryData: map[string][]byte{"binary": []byte("binary-value")},
|
||||
}
|
||||
newCM := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "cm", Namespace: "default"},
|
||||
Data: map[string]string{"text": "value"},
|
||||
BinaryData: map[string][]byte{"binary": []byte("new-binary-value")},
|
||||
}
|
||||
|
||||
handler := ResourceUpdatedHandler{
|
||||
Resource: newCM,
|
||||
OldResource: oldCM,
|
||||
Collectors: metrics.NewCollectors(),
|
||||
}
|
||||
|
||||
config, oldSHA := handler.GetConfig()
|
||||
|
||||
assert.NotEqual(t, config.SHAValue, oldSHA, "SHA should change when binary data changes")
|
||||
}
|
||||
|
||||
func TestResourceUpdatedHandler_DifferentNamespaces(t *testing.T) {
|
||||
// Edge case: what if namespaces are different (shouldn't happen in practice)
|
||||
oldCM := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "cm", Namespace: "ns1"},
|
||||
Data: map[string]string{"key": "value"},
|
||||
}
|
||||
newCM := &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "cm", Namespace: "ns2"},
|
||||
Data: map[string]string{"key": "value"},
|
||||
}
|
||||
|
||||
handler := ResourceUpdatedHandler{
|
||||
Resource: newCM,
|
||||
OldResource: oldCM,
|
||||
Collectors: metrics.NewCollectors(),
|
||||
}
|
||||
|
||||
config, _ := handler.GetConfig()
|
||||
|
||||
// Should use new resource's namespace
|
||||
assert.Equal(t, "ns2", config.Namespace)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,8 +2,6 @@ package testutil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sort"
|
||||
"strconv"
|
||||
@@ -12,13 +10,10 @@ import (
|
||||
|
||||
argorolloutv1alpha1 "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1"
|
||||
argorollout "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned"
|
||||
openshiftv1 "github.com/openshift/api/apps/v1"
|
||||
appsclient "github.com/openshift/client-go/apps/clientset/versioned"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stakater/Reloader/internal/pkg/callbacks"
|
||||
"github.com/stakater/Reloader/internal/pkg/constants"
|
||||
"github.com/stakater/Reloader/internal/pkg/crypto"
|
||||
"github.com/stakater/Reloader/internal/pkg/metrics"
|
||||
"github.com/stakater/Reloader/internal/pkg/options"
|
||||
"github.com/stakater/Reloader/internal/pkg/util"
|
||||
"github.com/stakater/Reloader/pkg/common"
|
||||
@@ -36,8 +31,6 @@ var (
|
||||
letters = []rune("abcdefghijklmnopqrstuvwxyz")
|
||||
// ConfigmapResourceType is a resource type which controller watches for changes
|
||||
ConfigmapResourceType = "configMaps"
|
||||
// SecretResourceType is a resource type which controller watches for changes
|
||||
SecretResourceType = "secrets"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -45,11 +38,6 @@ var (
|
||||
Pod = "test-reloader-" + RandSeq(5)
|
||||
Namespace = "test-reloader-" + RandSeq(5)
|
||||
ConfigmapNamePrefix = "testconfigmap-reloader"
|
||||
SecretNamePrefix = "testsecret-reloader"
|
||||
Data = "dGVzdFNlY3JldEVuY29kaW5nRm9yUmVsb2FkZXI="
|
||||
NewData = "dGVzdE5ld1NlY3JldEVuY29kaW5nRm9yUmVsb2FkZXI="
|
||||
UpdatedData = "dGVzdFVwZGF0ZWRTZWNyZXRFbmNvZGluZ0ZvclJlbG9hZGVy"
|
||||
Collectors = metrics.NewCollectors()
|
||||
SleepDuration = 3 * time.Second
|
||||
)
|
||||
|
||||
@@ -105,25 +93,6 @@ func getAnnotations(name string, autoReload bool, secretAutoReload bool, configm
|
||||
return annotations
|
||||
}
|
||||
|
||||
func getEnvVarSources(name string) []v1.EnvFromSource {
|
||||
return []v1.EnvFromSource{
|
||||
{
|
||||
ConfigMapRef: &v1.ConfigMapEnvSource{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
SecretRef: &v1.SecretEnvSource{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getVolumes(name string) []v1.Volume {
|
||||
return []v1.Volume{
|
||||
{
|
||||
@@ -244,23 +213,6 @@ func getPodTemplateSpecWithEnvVars(name string) v1.PodTemplateSpec {
|
||||
}
|
||||
}
|
||||
|
||||
func getPodTemplateSpecWithEnvVarSources(name string) v1.PodTemplateSpec {
|
||||
return v1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{"secondLabel": "temp"},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Image: "tutum/hello-world",
|
||||
Name: name,
|
||||
EnvFrom: getEnvVarSources(name),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getPodTemplateSpecWithVolumes(name string) v1.PodTemplateSpec {
|
||||
return v1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@@ -285,65 +237,6 @@ func getPodTemplateSpecWithVolumes(name string) v1.PodTemplateSpec {
|
||||
}
|
||||
}
|
||||
|
||||
func getPodTemplateSpecWithInitContainer(name string) v1.PodTemplateSpec {
|
||||
return v1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{"secondLabel": "temp"},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
InitContainers: []v1.Container{
|
||||
{
|
||||
Image: "busybox",
|
||||
Name: "busyBox",
|
||||
VolumeMounts: getVolumeMounts(),
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Image: "tutum/hello-world",
|
||||
Name: name,
|
||||
Env: []v1.EnvVar{
|
||||
{
|
||||
Name: "BUCKET_NAME",
|
||||
Value: "test",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Volumes: getVolumes(name),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getPodTemplateSpecWithInitContainerAndEnv(name string) v1.PodTemplateSpec {
|
||||
return v1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{"secondLabel": "temp"},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
InitContainers: []v1.Container{
|
||||
{
|
||||
Image: "busybox",
|
||||
Name: "busyBox",
|
||||
EnvFrom: getEnvVarSources(name),
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Image: "tutum/hello-world",
|
||||
Name: name,
|
||||
Env: []v1.EnvVar{
|
||||
{
|
||||
Name: "BUCKET_NAME",
|
||||
Value: "test",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetDeployment provides deployment for testing
|
||||
func GetDeployment(namespace string, deploymentName string) *appsv1.Deployment {
|
||||
replicaset := int32(1)
|
||||
@@ -362,58 +255,6 @@ func GetDeployment(namespace string, deploymentName string) *appsv1.Deployment {
|
||||
}
|
||||
}
|
||||
|
||||
// GetDeploymentConfig provides deployment for testing
|
||||
func GetDeploymentConfig(namespace string, deploymentConfigName string) *openshiftv1.DeploymentConfig {
|
||||
replicaset := int32(1)
|
||||
podTemplateSpecWithVolume := getPodTemplateSpecWithVolumes(deploymentConfigName)
|
||||
return &openshiftv1.DeploymentConfig{
|
||||
ObjectMeta: getObjectMeta(namespace, deploymentConfigName, false, false, false, map[string]string{}),
|
||||
Spec: openshiftv1.DeploymentConfigSpec{
|
||||
Replicas: replicaset,
|
||||
Strategy: openshiftv1.DeploymentStrategy{
|
||||
Type: openshiftv1.DeploymentStrategyTypeRolling,
|
||||
},
|
||||
Template: &podTemplateSpecWithVolume,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetDeploymentWithInitContainer provides deployment with init container and volumeMounts
|
||||
func GetDeploymentWithInitContainer(namespace string, deploymentName string) *appsv1.Deployment {
|
||||
replicaset := int32(1)
|
||||
return &appsv1.Deployment{
|
||||
ObjectMeta: getObjectMeta(namespace, deploymentName, false, false, false, map[string]string{}),
|
||||
Spec: appsv1.DeploymentSpec{
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{"secondLabel": "temp"},
|
||||
},
|
||||
Replicas: &replicaset,
|
||||
Strategy: appsv1.DeploymentStrategy{
|
||||
Type: appsv1.RollingUpdateDeploymentStrategyType,
|
||||
},
|
||||
Template: getPodTemplateSpecWithInitContainer(deploymentName),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetDeploymentWithInitContainerAndEnv provides deployment with init container and EnvSource
|
||||
func GetDeploymentWithInitContainerAndEnv(namespace string, deploymentName string) *appsv1.Deployment {
|
||||
replicaset := int32(1)
|
||||
return &appsv1.Deployment{
|
||||
ObjectMeta: getObjectMeta(namespace, deploymentName, true, false, false, map[string]string{}),
|
||||
Spec: appsv1.DeploymentSpec{
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{"secondLabel": "temp"},
|
||||
},
|
||||
Replicas: &replicaset,
|
||||
Strategy: appsv1.DeploymentStrategy{
|
||||
Type: appsv1.RollingUpdateDeploymentStrategyType,
|
||||
},
|
||||
Template: getPodTemplateSpecWithInitContainerAndEnv(deploymentName),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func GetDeploymentWithEnvVars(namespace string, deploymentName string) *appsv1.Deployment {
|
||||
replicaset := int32(1)
|
||||
return &appsv1.Deployment{
|
||||
@@ -431,117 +272,6 @@ func GetDeploymentWithEnvVars(namespace string, deploymentName string) *appsv1.D
|
||||
}
|
||||
}
|
||||
|
||||
func GetDeploymentConfigWithEnvVars(namespace string, deploymentConfigName string) *openshiftv1.DeploymentConfig {
|
||||
replicaset := int32(1)
|
||||
podTemplateSpecWithEnvVars := getPodTemplateSpecWithEnvVars(deploymentConfigName)
|
||||
return &openshiftv1.DeploymentConfig{
|
||||
ObjectMeta: getObjectMeta(namespace, deploymentConfigName, false, false, false, map[string]string{}),
|
||||
Spec: openshiftv1.DeploymentConfigSpec{
|
||||
Replicas: replicaset,
|
||||
Strategy: openshiftv1.DeploymentStrategy{
|
||||
Type: openshiftv1.DeploymentStrategyTypeRolling,
|
||||
},
|
||||
Template: &podTemplateSpecWithEnvVars,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func GetDeploymentWithEnvVarSources(namespace string, deploymentName string) *appsv1.Deployment {
|
||||
replicaset := int32(1)
|
||||
return &appsv1.Deployment{
|
||||
ObjectMeta: getObjectMeta(namespace, deploymentName, true, false, false, map[string]string{}),
|
||||
Spec: appsv1.DeploymentSpec{
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{"secondLabel": "temp"},
|
||||
},
|
||||
Replicas: &replicaset,
|
||||
Strategy: appsv1.DeploymentStrategy{
|
||||
Type: appsv1.RollingUpdateDeploymentStrategyType,
|
||||
},
|
||||
Template: getPodTemplateSpecWithEnvVarSources(deploymentName),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func GetDeploymentWithPodAnnotations(namespace string, deploymentName string, both bool) *appsv1.Deployment {
|
||||
replicaset := int32(1)
|
||||
deployment := &appsv1.Deployment{
|
||||
ObjectMeta: getObjectMeta(namespace, deploymentName, false, false, false, map[string]string{}),
|
||||
Spec: appsv1.DeploymentSpec{
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{"secondLabel": "temp"},
|
||||
},
|
||||
Replicas: &replicaset,
|
||||
Strategy: appsv1.DeploymentStrategy{
|
||||
Type: appsv1.RollingUpdateDeploymentStrategyType,
|
||||
},
|
||||
Template: getPodTemplateSpecWithEnvVarSources(deploymentName),
|
||||
},
|
||||
}
|
||||
if !both {
|
||||
deployment.Annotations = nil
|
||||
}
|
||||
deployment.Spec.Template.Annotations = getAnnotations(deploymentName, true, false, false, map[string]string{})
|
||||
return deployment
|
||||
}
|
||||
|
||||
func GetDeploymentWithTypedAutoAnnotation(namespace string, deploymentName string, resourceType string) *appsv1.Deployment {
|
||||
replicaset := int32(1)
|
||||
var objectMeta metav1.ObjectMeta
|
||||
switch resourceType {
|
||||
case SecretResourceType:
|
||||
objectMeta = getObjectMeta(namespace, deploymentName, false, true, false, map[string]string{})
|
||||
case ConfigmapResourceType:
|
||||
objectMeta = getObjectMeta(namespace, deploymentName, false, false, true, map[string]string{})
|
||||
}
|
||||
|
||||
return &appsv1.Deployment{
|
||||
ObjectMeta: objectMeta,
|
||||
Spec: appsv1.DeploymentSpec{
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{"secondLabel": "temp"},
|
||||
},
|
||||
Replicas: &replicaset,
|
||||
Strategy: appsv1.DeploymentStrategy{
|
||||
Type: appsv1.RollingUpdateDeploymentStrategyType,
|
||||
},
|
||||
Template: getPodTemplateSpecWithVolumes(deploymentName),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func GetDeploymentWithExcludeAnnotation(namespace string, deploymentName string, resourceType string) *appsv1.Deployment {
|
||||
replicaset := int32(1)
|
||||
|
||||
annotation := map[string]string{}
|
||||
|
||||
switch resourceType {
|
||||
case SecretResourceType:
|
||||
annotation[options.SecretExcludeReloaderAnnotation] = deploymentName
|
||||
case ConfigmapResourceType:
|
||||
annotation[options.ConfigmapExcludeReloaderAnnotation] = deploymentName
|
||||
}
|
||||
|
||||
return &appsv1.Deployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: deploymentName,
|
||||
Namespace: namespace,
|
||||
Labels: map[string]string{"firstLabel": "temp"},
|
||||
Annotations: annotation,
|
||||
},
|
||||
Spec: appsv1.DeploymentSpec{
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{"secondLabel": "temp"},
|
||||
},
|
||||
Replicas: &replicaset,
|
||||
Strategy: appsv1.DeploymentStrategy{
|
||||
Type: appsv1.RollingUpdateDeploymentStrategyType,
|
||||
},
|
||||
Template: getPodTemplateSpecWithVolumes(deploymentName),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetDaemonSet provides daemonset for testing
|
||||
func GetDaemonSet(namespace string, daemonsetName string) *appsv1.DaemonSet {
|
||||
return &appsv1.DaemonSet{
|
||||
@@ -629,18 +359,6 @@ func GetConfigmapWithUpdatedLabel(namespace string, configmapName string, testLa
|
||||
}
|
||||
}
|
||||
|
||||
// GetSecret provides secret for testing
|
||||
func GetSecret(namespace string, secretName string, data string) *v1.Secret {
|
||||
return &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: secretName,
|
||||
Namespace: namespace,
|
||||
Labels: map[string]string{"firstLabel": "temp"},
|
||||
},
|
||||
Data: map[string][]byte{"test.url": []byte(data)},
|
||||
}
|
||||
}
|
||||
|
||||
func GetCronJob(namespace string, cronJobName string) *batchv1.CronJob {
|
||||
return &batchv1.CronJob{
|
||||
ObjectMeta: getObjectMeta(namespace, cronJobName, false, false, false, map[string]string{}),
|
||||
@@ -699,18 +417,6 @@ func GetJobWithEnvVar(namespace string, jobName string) *batchv1.Job {
|
||||
}
|
||||
}
|
||||
|
||||
// GetSecretWithUpdatedLabel provides secret for testing
|
||||
func GetSecretWithUpdatedLabel(namespace string, secretName string, label string, data string) *v1.Secret {
|
||||
return &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: secretName,
|
||||
Namespace: namespace,
|
||||
Labels: map[string]string{"firstLabel": label},
|
||||
},
|
||||
Data: map[string][]byte{"test.url": []byte(data)},
|
||||
}
|
||||
}
|
||||
|
||||
// GetResourceSHAFromEnvVar returns the SHA value of given environment variable
|
||||
func GetResourceSHAFromEnvVar(containers []v1.Container, envVar string) string {
|
||||
for i := range containers {
|
||||
@@ -724,38 +430,10 @@ func GetResourceSHAFromEnvVar(containers []v1.Container, envVar string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetResourceSHAFromAnnotation returns the SHA value of given environment variable
|
||||
func GetResourceSHAFromAnnotation(podAnnotations map[string]string) string {
|
||||
lastReloadedResourceName := fmt.Sprintf("%s/%s",
|
||||
constants.ReloaderAnnotationPrefix,
|
||||
constants.LastReloadedFromAnnotation,
|
||||
)
|
||||
|
||||
annotationJson, ok := podAnnotations[lastReloadedResourceName]
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
var last common.ReloadSource
|
||||
bytes := []byte(annotationJson)
|
||||
err := json.Unmarshal(bytes, &last)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return last.Hash
|
||||
}
|
||||
|
||||
// ConvertResourceToSHA generates SHA from secret or configmap data
|
||||
// ConvertResourceToSHA generates SHA from configmap data
|
||||
func ConvertResourceToSHA(resourceType string, namespace string, resourceName string, data string) string {
|
||||
values := []string{}
|
||||
switch resourceType {
|
||||
case SecretResourceType:
|
||||
secret := GetSecret(namespace, resourceName, data)
|
||||
for k, v := range secret.Data {
|
||||
values = append(values, k+"="+string(v[:]))
|
||||
}
|
||||
case ConfigmapResourceType:
|
||||
if resourceType == ConfigmapResourceType {
|
||||
configmap := GetConfigmap(namespace, resourceName, data)
|
||||
for k, v := range configmap.Data {
|
||||
values = append(values, k+"="+v)
|
||||
@@ -774,15 +452,6 @@ func CreateConfigMap(client kubernetes.Interface, namespace string, configmapNam
|
||||
return configmapClient, err
|
||||
}
|
||||
|
||||
// CreateSecret creates a secret in given namespace and returns the SecretInterface
|
||||
func CreateSecret(client kubernetes.Interface, namespace string, secretName string, data string) (core_v1.SecretInterface, error) {
|
||||
logrus.Infof("Creating secret")
|
||||
secretClient := client.CoreV1().Secrets(namespace)
|
||||
_, err := secretClient.Create(context.TODO(), GetSecret(namespace, secretName, data), metav1.CreateOptions{})
|
||||
time.Sleep(3 * time.Second)
|
||||
return secretClient, err
|
||||
}
|
||||
|
||||
// CreateDeployment creates a deployment in given namespace and returns the Deployment
|
||||
func CreateDeployment(client kubernetes.Interface, deploymentName string, namespace string, volumeMount bool) (*appsv1.Deployment, error) {
|
||||
logrus.Infof("Creating Deployment")
|
||||
@@ -798,108 +467,6 @@ func CreateDeployment(client kubernetes.Interface, deploymentName string, namesp
|
||||
return deployment, err
|
||||
}
|
||||
|
||||
// CreateDeployment creates a deployment in given namespace and returns the Deployment
|
||||
func CreateDeploymentWithAnnotations(client kubernetes.Interface, deploymentName string, namespace string, additionalAnnotations map[string]string, volumeMount bool) (*appsv1.Deployment, error) {
|
||||
logrus.Infof("Creating Deployment")
|
||||
deploymentClient := client.AppsV1().Deployments(namespace)
|
||||
var deploymentObj *appsv1.Deployment
|
||||
if volumeMount {
|
||||
deploymentObj = GetDeployment(namespace, deploymentName)
|
||||
} else {
|
||||
deploymentObj = GetDeploymentWithEnvVars(namespace, deploymentName)
|
||||
}
|
||||
|
||||
for annotationKey, annotationValue := range additionalAnnotations {
|
||||
deploymentObj.Annotations[annotationKey] = annotationValue
|
||||
}
|
||||
|
||||
deployment, err := deploymentClient.Create(context.TODO(), deploymentObj, metav1.CreateOptions{})
|
||||
time.Sleep(3 * time.Second)
|
||||
return deployment, err
|
||||
}
|
||||
|
||||
// CreateDeploymentConfig creates a deploymentConfig in given namespace and returns the DeploymentConfig
|
||||
func CreateDeploymentConfig(client appsclient.Interface, deploymentName string, namespace string, volumeMount bool) (*openshiftv1.DeploymentConfig, error) {
|
||||
logrus.Infof("Creating DeploymentConfig")
|
||||
deploymentConfigsClient := client.AppsV1().DeploymentConfigs(namespace)
|
||||
var deploymentConfigObj *openshiftv1.DeploymentConfig
|
||||
if volumeMount {
|
||||
deploymentConfigObj = GetDeploymentConfig(namespace, deploymentName)
|
||||
} else {
|
||||
deploymentConfigObj = GetDeploymentConfigWithEnvVars(namespace, deploymentName)
|
||||
}
|
||||
deploymentConfig, err := deploymentConfigsClient.Create(context.TODO(), deploymentConfigObj, metav1.CreateOptions{})
|
||||
time.Sleep(5 * time.Second)
|
||||
return deploymentConfig, err
|
||||
}
|
||||
|
||||
// CreateDeploymentWithInitContainer creates a deployment in given namespace with init container and returns the Deployment
|
||||
func CreateDeploymentWithInitContainer(client kubernetes.Interface, deploymentName string, namespace string, volumeMount bool) (*appsv1.Deployment, error) {
|
||||
logrus.Infof("Creating Deployment")
|
||||
deploymentClient := client.AppsV1().Deployments(namespace)
|
||||
var deploymentObj *appsv1.Deployment
|
||||
if volumeMount {
|
||||
deploymentObj = GetDeploymentWithInitContainer(namespace, deploymentName)
|
||||
} else {
|
||||
deploymentObj = GetDeploymentWithInitContainerAndEnv(namespace, deploymentName)
|
||||
}
|
||||
deployment, err := deploymentClient.Create(context.TODO(), deploymentObj, metav1.CreateOptions{})
|
||||
time.Sleep(3 * time.Second)
|
||||
return deployment, err
|
||||
}
|
||||
|
||||
// CreateDeploymentWithEnvVarSource creates a deployment in given namespace and returns the Deployment
|
||||
func CreateDeploymentWithEnvVarSource(client kubernetes.Interface, deploymentName string, namespace string) (*appsv1.Deployment, error) {
|
||||
logrus.Infof("Creating Deployment")
|
||||
deploymentClient := client.AppsV1().Deployments(namespace)
|
||||
deploymentObj := GetDeploymentWithEnvVarSources(namespace, deploymentName)
|
||||
deployment, err := deploymentClient.Create(context.TODO(), deploymentObj, metav1.CreateOptions{})
|
||||
time.Sleep(3 * time.Second)
|
||||
return deployment, err
|
||||
|
||||
}
|
||||
|
||||
// CreateDeploymentWithPodAnnotations creates a deployment in given namespace and returns the Deployment
|
||||
func CreateDeploymentWithPodAnnotations(client kubernetes.Interface, deploymentName string, namespace string, both bool) (*appsv1.Deployment, error) {
|
||||
logrus.Infof("Creating Deployment")
|
||||
deploymentClient := client.AppsV1().Deployments(namespace)
|
||||
deploymentObj := GetDeploymentWithPodAnnotations(namespace, deploymentName, both)
|
||||
deployment, err := deploymentClient.Create(context.TODO(), deploymentObj, metav1.CreateOptions{})
|
||||
time.Sleep(3 * time.Second)
|
||||
return deployment, err
|
||||
}
|
||||
|
||||
// CreateDeploymentWithEnvVarSourceAndAnnotations returns a deployment in given
|
||||
// namespace with given annotations.
|
||||
func CreateDeploymentWithEnvVarSourceAndAnnotations(client kubernetes.Interface, deploymentName string, namespace string, annotations map[string]string) (*appsv1.Deployment, error) {
|
||||
logrus.Infof("Creating Deployment")
|
||||
deploymentClient := client.AppsV1().Deployments(namespace)
|
||||
deploymentObj := GetDeploymentWithEnvVarSources(namespace, deploymentName)
|
||||
deploymentObj.Annotations = annotations
|
||||
deployment, err := deploymentClient.Create(context.TODO(), deploymentObj, metav1.CreateOptions{})
|
||||
time.Sleep(3 * time.Second)
|
||||
return deployment, err
|
||||
}
|
||||
|
||||
// CreateDeploymentWithTypedAutoAnnotation creates a deployment in given namespace and returns the Deployment with typed auto annotation
|
||||
func CreateDeploymentWithTypedAutoAnnotation(client kubernetes.Interface, deploymentName string, namespace string, resourceType string) (*appsv1.Deployment, error) {
|
||||
logrus.Infof("Creating Deployment")
|
||||
deploymentClient := client.AppsV1().Deployments(namespace)
|
||||
deploymentObj := GetDeploymentWithTypedAutoAnnotation(namespace, deploymentName, resourceType)
|
||||
deployment, err := deploymentClient.Create(context.TODO(), deploymentObj, metav1.CreateOptions{})
|
||||
time.Sleep(3 * time.Second)
|
||||
return deployment, err
|
||||
}
|
||||
|
||||
// CreateDeploymentWithExcludeAnnotation creates a deployment in given namespace and returns the Deployment with typed auto annotation
|
||||
func CreateDeploymentWithExcludeAnnotation(client kubernetes.Interface, deploymentName string, namespace string, resourceType string) (*appsv1.Deployment, error) {
|
||||
logrus.Infof("Creating Deployment")
|
||||
deploymentClient := client.AppsV1().Deployments(namespace)
|
||||
deploymentObj := GetDeploymentWithExcludeAnnotation(namespace, deploymentName, resourceType)
|
||||
deployment, err := deploymentClient.Create(context.TODO(), deploymentObj, metav1.CreateOptions{})
|
||||
return deployment, err
|
||||
}
|
||||
|
||||
// CreateDaemonSet creates a deployment in given namespace and returns the DaemonSet
|
||||
func CreateDaemonSet(client kubernetes.Interface, daemonsetName string, namespace string, volumeMount bool) (*appsv1.DaemonSet, error) {
|
||||
logrus.Infof("Creating DaemonSet")
|
||||
@@ -968,14 +535,6 @@ func DeleteDeployment(client kubernetes.Interface, namespace string, deploymentN
|
||||
return deploymentError
|
||||
}
|
||||
|
||||
// DeleteDeploymentConfig deletes a deploymentConfig in given namespace and returns the error if any
|
||||
func DeleteDeploymentConfig(client appsclient.Interface, namespace string, deploymentConfigName string) error {
|
||||
logrus.Infof("Deleting DeploymentConfig")
|
||||
deploymentConfigError := client.AppsV1().DeploymentConfigs(namespace).Delete(context.TODO(), deploymentConfigName, metav1.DeleteOptions{})
|
||||
time.Sleep(3 * time.Second)
|
||||
return deploymentConfigError
|
||||
}
|
||||
|
||||
// DeleteDaemonSet creates a daemonset in given namespace and returns the error if any
|
||||
func DeleteDaemonSet(client kubernetes.Interface, namespace string, daemonsetName string) error {
|
||||
logrus.Infof("Deleting DaemonSet %s", daemonsetName)
|
||||
@@ -1022,20 +581,6 @@ func UpdateConfigMap(configmapClient core_v1.ConfigMapInterface, namespace strin
|
||||
return updateErr
|
||||
}
|
||||
|
||||
// UpdateSecret updates a secret in given namespace and returns the error if any
|
||||
func UpdateSecret(secretClient core_v1.SecretInterface, namespace string, secretName string, label string, data string) error {
|
||||
logrus.Infof("Updating secret %q.\n", secretName)
|
||||
var secret *v1.Secret
|
||||
if label != "" {
|
||||
secret = GetSecretWithUpdatedLabel(namespace, secretName, label, data)
|
||||
} else {
|
||||
secret = GetSecret(namespace, secretName, data)
|
||||
}
|
||||
_, updateErr := secretClient.Update(context.TODO(), secret, metav1.UpdateOptions{})
|
||||
time.Sleep(3 * time.Second)
|
||||
return updateErr
|
||||
}
|
||||
|
||||
// DeleteConfigMap deletes a configmap in given namespace and returns the error if any
|
||||
func DeleteConfigMap(client kubernetes.Interface, namespace string, configmapName string) error {
|
||||
logrus.Infof("Deleting configmap %q.\n", configmapName)
|
||||
@@ -1044,14 +589,6 @@ func DeleteConfigMap(client kubernetes.Interface, namespace string, configmapNam
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteSecret deletes a secret in given namespace and returns the error if any
|
||||
func DeleteSecret(client kubernetes.Interface, namespace string, secretName string) error {
|
||||
logrus.Infof("Deleting secret %q.\n", secretName)
|
||||
err := client.CoreV1().Secrets(namespace).Delete(context.TODO(), secretName, metav1.DeleteOptions{})
|
||||
time.Sleep(3 * time.Second)
|
||||
return err
|
||||
}
|
||||
|
||||
// RandSeq generates a random sequence
|
||||
func RandSeq(n int) string {
|
||||
b := make([]rune, n)
|
||||
@@ -1107,100 +644,6 @@ func VerifyResourceEnvVarUpdate(clients kube.Clients, config common.Config, envV
|
||||
return false
|
||||
}
|
||||
|
||||
// VerifyResourceEnvVarRemoved verifies whether the rolling upgrade happened or not and all Envvars SKAKATER_name_CONFIGMAP/SECRET are removed
|
||||
func VerifyResourceEnvVarRemoved(clients kube.Clients, config common.Config, envVarPostfix string, upgradeFuncs callbacks.RollingUpgradeFuncs) bool {
|
||||
items := upgradeFuncs.ItemsFunc(clients, config.Namespace)
|
||||
for _, i := range items {
|
||||
containers := upgradeFuncs.ContainersFunc(i)
|
||||
accessor, err := meta.Accessor(i)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
annotations := accessor.GetAnnotations()
|
||||
// match statefulsets with the correct annotation
|
||||
|
||||
annotationValue := annotations[config.Annotation]
|
||||
searchAnnotationValue := annotations[options.AutoSearchAnnotation]
|
||||
reloaderEnabledValue := annotations[options.ReloaderAutoAnnotation]
|
||||
typedAutoAnnotationEnabledValue := annotations[config.TypedAutoAnnotation]
|
||||
reloaderEnabled, err := strconv.ParseBool(reloaderEnabledValue)
|
||||
typedAutoAnnotationEnabled, errTyped := strconv.ParseBool(typedAutoAnnotationEnabledValue)
|
||||
|
||||
matches := false
|
||||
if err == nil && reloaderEnabled || errTyped == nil && typedAutoAnnotationEnabled {
|
||||
matches = true
|
||||
} else if annotationValue != "" {
|
||||
values := strings.Split(annotationValue, ",")
|
||||
for _, value := range values {
|
||||
value = strings.Trim(value, " ")
|
||||
if value == config.ResourceName {
|
||||
matches = true
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if searchAnnotationValue == "true" {
|
||||
if config.ResourceAnnotations[options.SearchMatchAnnotation] == "true" {
|
||||
matches = true
|
||||
}
|
||||
}
|
||||
|
||||
if matches {
|
||||
envName := constants.EnvVarPrefix + util.ConvertToEnvVarName(config.ResourceName) + "_" + envVarPostfix
|
||||
value := GetResourceSHAFromEnvVar(containers, envName)
|
||||
if value == "" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// VerifyResourceAnnotationUpdate verifies whether the rolling upgrade happened or not
|
||||
func VerifyResourceAnnotationUpdate(clients kube.Clients, config common.Config, upgradeFuncs callbacks.RollingUpgradeFuncs) bool {
|
||||
items := upgradeFuncs.ItemsFunc(clients, config.Namespace)
|
||||
for _, i := range items {
|
||||
podAnnotations := upgradeFuncs.PodAnnotationsFunc(i)
|
||||
accessor, err := meta.Accessor(i)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
annotations := accessor.GetAnnotations()
|
||||
// match statefulsets with the correct annotation
|
||||
annotationValue := annotations[config.Annotation]
|
||||
searchAnnotationValue := annotations[options.AutoSearchAnnotation]
|
||||
reloaderEnabledValue := annotations[options.ReloaderAutoAnnotation]
|
||||
typedAutoAnnotationEnabledValue := annotations[config.TypedAutoAnnotation]
|
||||
reloaderEnabled, _ := strconv.ParseBool(reloaderEnabledValue)
|
||||
typedAutoAnnotationEnabled, _ := strconv.ParseBool(typedAutoAnnotationEnabledValue)
|
||||
matches := false
|
||||
if reloaderEnabled || typedAutoAnnotationEnabled || reloaderEnabledValue == "" && typedAutoAnnotationEnabledValue == "" && options.AutoReloadAll {
|
||||
matches = true
|
||||
} else if annotationValue != "" {
|
||||
values := strings.Split(annotationValue, ",")
|
||||
for _, value := range values {
|
||||
value = strings.Trim(value, " ")
|
||||
if value == config.ResourceName {
|
||||
matches = true
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if searchAnnotationValue == "true" {
|
||||
if config.ResourceAnnotations[options.SearchMatchAnnotation] == "true" {
|
||||
matches = true
|
||||
}
|
||||
}
|
||||
|
||||
if matches {
|
||||
updated := GetResourceSHAFromAnnotation(podAnnotations)
|
||||
if updated == config.SHAValue {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func GetSHAfromEmptyData() string {
|
||||
return crypto.GenerateSHA("")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user