mirror of
https://github.com/stakater/Reloader.git
synced 2026-02-14 18:09:50 +00:00
909 lines
30 KiB
Go
909 lines
30 KiB
Go
package testutil
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"math/rand"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
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/options"
|
|
"github.com/stakater/Reloader/internal/pkg/util"
|
|
"github.com/stakater/Reloader/pkg/kube"
|
|
appsv1 "k8s.io/api/apps/v1"
|
|
v1 "k8s.io/api/core/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/client-go/kubernetes"
|
|
core_v1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
|
)
|
|
|
|
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"
|
|
)
|
|
|
|
// CreateNamespace creates namespace for testing
|
|
func CreateNamespace(namespace string, client kubernetes.Interface) {
|
|
_, err := client.CoreV1().Namespaces().Create(context.TODO(), &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}, metav1.CreateOptions{})
|
|
if err != nil {
|
|
logrus.Fatalf("Failed to create namespace for testing %v", err)
|
|
} else {
|
|
logrus.Infof("Creating namespace for testing = %s", namespace)
|
|
}
|
|
}
|
|
|
|
// DeleteNamespace deletes namespace for testing
|
|
func DeleteNamespace(namespace string, client kubernetes.Interface) {
|
|
err := client.CoreV1().Namespaces().Delete(context.TODO(), namespace, metav1.DeleteOptions{})
|
|
if err != nil {
|
|
logrus.Fatalf("Failed to delete namespace that was created for testing %v", err)
|
|
} else {
|
|
logrus.Infof("Deleting namespace for testing = %s", namespace)
|
|
}
|
|
}
|
|
|
|
func getObjectMeta(namespace string, name string, autoReload bool) metav1.ObjectMeta {
|
|
return metav1.ObjectMeta{
|
|
Name: name,
|
|
Namespace: namespace,
|
|
Labels: map[string]string{"firstLabel": "temp"},
|
|
Annotations: getAnnotations(name, autoReload),
|
|
}
|
|
}
|
|
|
|
func getAnnotations(name string, autoReload bool) map[string]string {
|
|
if autoReload {
|
|
return map[string]string{
|
|
options.ReloaderAutoAnnotation: "true"}
|
|
}
|
|
|
|
return map[string]string{
|
|
options.ConfigmapUpdateOnChangeAnnotation: name,
|
|
options.SecretUpdateOnChangeAnnotation: name}
|
|
}
|
|
|
|
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{
|
|
{
|
|
Name: "projectedconfigmap",
|
|
VolumeSource: v1.VolumeSource{
|
|
Projected: &v1.ProjectedVolumeSource{
|
|
Sources: []v1.VolumeProjection{
|
|
{
|
|
ConfigMap: &v1.ConfigMapProjection{
|
|
LocalObjectReference: v1.LocalObjectReference{
|
|
Name: name,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "projectedsecret",
|
|
VolumeSource: v1.VolumeSource{
|
|
Projected: &v1.ProjectedVolumeSource{
|
|
Sources: []v1.VolumeProjection{
|
|
{
|
|
Secret: &v1.SecretProjection{
|
|
LocalObjectReference: v1.LocalObjectReference{
|
|
Name: name,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "configmap",
|
|
VolumeSource: v1.VolumeSource{
|
|
ConfigMap: &v1.ConfigMapVolumeSource{
|
|
LocalObjectReference: v1.LocalObjectReference{
|
|
Name: name,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "secret",
|
|
VolumeSource: v1.VolumeSource{
|
|
Secret: &v1.SecretVolumeSource{
|
|
SecretName: name,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func getVolumeMounts(name string) []v1.VolumeMount {
|
|
return []v1.VolumeMount{
|
|
{
|
|
MountPath: "etc/config",
|
|
Name: "configmap",
|
|
},
|
|
{
|
|
MountPath: "etc/sec",
|
|
Name: "secret",
|
|
},
|
|
{
|
|
MountPath: "etc/projectedconfig",
|
|
Name: "projectedconfigmap",
|
|
},
|
|
{
|
|
MountPath: "etc/projectedsec",
|
|
Name: "projectedsecret",
|
|
},
|
|
}
|
|
}
|
|
|
|
func getPodTemplateSpecWithEnvVars(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,
|
|
Env: []v1.EnvVar{
|
|
{
|
|
Name: "BUCKET_NAME",
|
|
Value: "test",
|
|
},
|
|
{
|
|
Name: "CONFIGMAP_" + util.ConvertToEnvVarName(name),
|
|
ValueFrom: &v1.EnvVarSource{
|
|
ConfigMapKeyRef: &v1.ConfigMapKeySelector{
|
|
LocalObjectReference: v1.LocalObjectReference{
|
|
Name: name,
|
|
},
|
|
Key: "test.url",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "SECRET_" + util.ConvertToEnvVarName(name),
|
|
ValueFrom: &v1.EnvVarSource{
|
|
SecretKeyRef: &v1.SecretKeySelector{
|
|
LocalObjectReference: v1.LocalObjectReference{
|
|
Name: name,
|
|
},
|
|
Key: "test.url",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
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{
|
|
Labels: map[string]string{"secondLabel": "temp"},
|
|
},
|
|
Spec: v1.PodSpec{
|
|
Containers: []v1.Container{
|
|
{
|
|
Image: "tutum/hello-world",
|
|
Name: name,
|
|
Env: []v1.EnvVar{
|
|
{
|
|
Name: "BUCKET_NAME",
|
|
Value: "test",
|
|
},
|
|
},
|
|
VolumeMounts: getVolumeMounts(name),
|
|
},
|
|
},
|
|
Volumes: getVolumes(name),
|
|
},
|
|
}
|
|
}
|
|
|
|
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(name),
|
|
},
|
|
},
|
|
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)
|
|
return &appsv1.Deployment{
|
|
ObjectMeta: getObjectMeta(namespace, deploymentName, false),
|
|
Spec: appsv1.DeploymentSpec{
|
|
Selector: &metav1.LabelSelector{
|
|
MatchLabels: map[string]string{"secondLabel": "temp"},
|
|
},
|
|
Replicas: &replicaset,
|
|
Strategy: appsv1.DeploymentStrategy{
|
|
Type: appsv1.RollingUpdateDeploymentStrategyType,
|
|
},
|
|
Template: getPodTemplateSpecWithVolumes(deploymentName),
|
|
},
|
|
}
|
|
}
|
|
|
|
// 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),
|
|
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),
|
|
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),
|
|
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{
|
|
ObjectMeta: getObjectMeta(namespace, deploymentName, true),
|
|
Spec: appsv1.DeploymentSpec{
|
|
Selector: &metav1.LabelSelector{
|
|
MatchLabels: map[string]string{"secondLabel": "temp"},
|
|
},
|
|
Replicas: &replicaset,
|
|
Strategy: appsv1.DeploymentStrategy{
|
|
Type: appsv1.RollingUpdateDeploymentStrategyType,
|
|
},
|
|
Template: getPodTemplateSpecWithEnvVars(deploymentName),
|
|
},
|
|
}
|
|
}
|
|
|
|
func GetDeploymentConfigWithEnvVars(namespace string, deploymentConfigName string) *openshiftv1.DeploymentConfig {
|
|
replicaset := int32(1)
|
|
podTemplateSpecWithEnvVars := getPodTemplateSpecWithEnvVars(deploymentConfigName)
|
|
return &openshiftv1.DeploymentConfig{
|
|
ObjectMeta: getObjectMeta(namespace, deploymentConfigName, false),
|
|
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),
|
|
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),
|
|
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.ObjectMeta.Annotations = nil
|
|
}
|
|
deployment.Spec.Template.ObjectMeta.Annotations = getAnnotations(deploymentName, true)
|
|
return deployment
|
|
}
|
|
|
|
// GetDaemonSet provides daemonset for testing
|
|
func GetDaemonSet(namespace string, daemonsetName string) *appsv1.DaemonSet {
|
|
return &appsv1.DaemonSet{
|
|
ObjectMeta: getObjectMeta(namespace, daemonsetName, false),
|
|
Spec: appsv1.DaemonSetSpec{
|
|
Selector: &metav1.LabelSelector{
|
|
MatchLabels: map[string]string{"secondLabel": "temp"},
|
|
},
|
|
UpdateStrategy: appsv1.DaemonSetUpdateStrategy{
|
|
Type: appsv1.RollingUpdateDaemonSetStrategyType,
|
|
},
|
|
Template: getPodTemplateSpecWithVolumes(daemonsetName),
|
|
},
|
|
}
|
|
}
|
|
|
|
func GetDaemonSetWithEnvVars(namespace string, daemonSetName string) *appsv1.DaemonSet {
|
|
return &appsv1.DaemonSet{
|
|
ObjectMeta: getObjectMeta(namespace, daemonSetName, true),
|
|
Spec: appsv1.DaemonSetSpec{
|
|
Selector: &metav1.LabelSelector{
|
|
MatchLabels: map[string]string{"secondLabel": "temp"},
|
|
},
|
|
UpdateStrategy: appsv1.DaemonSetUpdateStrategy{
|
|
Type: appsv1.RollingUpdateDaemonSetStrategyType,
|
|
},
|
|
Template: getPodTemplateSpecWithEnvVars(daemonSetName),
|
|
},
|
|
}
|
|
}
|
|
|
|
// GetStatefulSet provides statefulset for testing
|
|
func GetStatefulSet(namespace string, statefulsetName string) *appsv1.StatefulSet {
|
|
return &appsv1.StatefulSet{
|
|
ObjectMeta: getObjectMeta(namespace, statefulsetName, false),
|
|
Spec: appsv1.StatefulSetSpec{
|
|
Selector: &metav1.LabelSelector{
|
|
MatchLabels: map[string]string{"secondLabel": "temp"},
|
|
},
|
|
UpdateStrategy: appsv1.StatefulSetUpdateStrategy{
|
|
Type: appsv1.RollingUpdateStatefulSetStrategyType,
|
|
},
|
|
Template: getPodTemplateSpecWithVolumes(statefulsetName),
|
|
},
|
|
}
|
|
}
|
|
|
|
// GetStatefulSet provides statefulset for testing
|
|
func GetStatefulSetWithEnvVar(namespace string, statefulsetName string) *appsv1.StatefulSet {
|
|
return &appsv1.StatefulSet{
|
|
ObjectMeta: getObjectMeta(namespace, statefulsetName, true),
|
|
Spec: appsv1.StatefulSetSpec{
|
|
Selector: &metav1.LabelSelector{
|
|
MatchLabels: map[string]string{"secondLabel": "temp"},
|
|
},
|
|
UpdateStrategy: appsv1.StatefulSetUpdateStrategy{
|
|
Type: appsv1.RollingUpdateStatefulSetStrategyType,
|
|
},
|
|
Template: getPodTemplateSpecWithEnvVars(statefulsetName),
|
|
},
|
|
}
|
|
}
|
|
|
|
// GetConfigmap provides configmap for testing
|
|
func GetConfigmap(namespace string, configmapName string, testData string) *v1.ConfigMap {
|
|
return &v1.ConfigMap{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: configmapName,
|
|
Namespace: namespace,
|
|
Labels: map[string]string{"firstLabel": "temp"},
|
|
},
|
|
Data: map[string]string{"test.url": testData},
|
|
}
|
|
}
|
|
|
|
// GetConfigmapWithUpdatedLabel provides configmap for testing
|
|
func GetConfigmapWithUpdatedLabel(namespace string, configmapName string, testLabel string, testData string) *v1.ConfigMap {
|
|
return &v1.ConfigMap{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: configmapName,
|
|
Namespace: namespace,
|
|
Labels: map[string]string{"firstLabel": testLabel},
|
|
},
|
|
Data: map[string]string{"test.url": testData},
|
|
}
|
|
}
|
|
|
|
// 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)},
|
|
}
|
|
}
|
|
|
|
// 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 {
|
|
envs := containers[i].Env
|
|
for j := range envs {
|
|
if envs[j].Name == envVar {
|
|
return envs[j].Value
|
|
}
|
|
}
|
|
}
|
|
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 util.ReloadSource
|
|
bytes := []byte(annotationJson)
|
|
err := json.Unmarshal(bytes, &last)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
|
|
return last.Hash
|
|
}
|
|
|
|
//ConvertResourceToSHA generates SHA from secret or configmap data
|
|
func ConvertResourceToSHA(resourceType string, namespace string, resourceName string, data string) string {
|
|
values := []string{}
|
|
if resourceType == SecretResourceType {
|
|
secret := GetSecret(namespace, resourceName, data)
|
|
for k, v := range secret.Data {
|
|
values = append(values, k+"="+string(v[:]))
|
|
}
|
|
} else if resourceType == ConfigmapResourceType {
|
|
configmap := GetConfigmap(namespace, resourceName, data)
|
|
for k, v := range configmap.Data {
|
|
values = append(values, k+"="+v)
|
|
}
|
|
}
|
|
sort.Strings(values)
|
|
return crypto.GenerateSHA(strings.Join(values, ";"))
|
|
}
|
|
|
|
// CreateConfigMap creates a configmap in given namespace and returns the ConfigMapInterface
|
|
func CreateConfigMap(client kubernetes.Interface, namespace string, configmapName string, data string) (core_v1.ConfigMapInterface, error) {
|
|
logrus.Infof("Creating configmap")
|
|
configmapClient := client.CoreV1().ConfigMaps(namespace)
|
|
_, err := configmapClient.Create(context.TODO(), GetConfigmap(namespace, configmapName, data), metav1.CreateOptions{})
|
|
time.Sleep(3 * time.Second)
|
|
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")
|
|
deploymentClient := client.AppsV1().Deployments(namespace)
|
|
var deploymentObj *appsv1.Deployment
|
|
if volumeMount {
|
|
deploymentObj = GetDeployment(namespace, deploymentName)
|
|
} else {
|
|
deploymentObj = GetDeploymentWithEnvVars(namespace, deploymentName)
|
|
}
|
|
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
|
|
}
|
|
|
|
// 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")
|
|
daemonsetClient := client.AppsV1().DaemonSets(namespace)
|
|
var daemonsetObj *appsv1.DaemonSet
|
|
if volumeMount {
|
|
daemonsetObj = GetDaemonSet(namespace, daemonsetName)
|
|
} else {
|
|
daemonsetObj = GetDaemonSetWithEnvVars(namespace, daemonsetName)
|
|
}
|
|
daemonset, err := daemonsetClient.Create(context.TODO(), daemonsetObj, metav1.CreateOptions{})
|
|
time.Sleep(3 * time.Second)
|
|
return daemonset, err
|
|
}
|
|
|
|
// CreateStatefulSet creates a deployment in given namespace and returns the StatefulSet
|
|
func CreateStatefulSet(client kubernetes.Interface, statefulsetName string, namespace string, volumeMount bool) (*appsv1.StatefulSet, error) {
|
|
logrus.Infof("Creating StatefulSet")
|
|
statefulsetClient := client.AppsV1().StatefulSets(namespace)
|
|
var statefulsetObj *appsv1.StatefulSet
|
|
if volumeMount {
|
|
statefulsetObj = GetStatefulSet(namespace, statefulsetName)
|
|
} else {
|
|
statefulsetObj = GetStatefulSetWithEnvVar(namespace, statefulsetName)
|
|
}
|
|
statefulset, err := statefulsetClient.Create(context.TODO(), statefulsetObj, metav1.CreateOptions{})
|
|
time.Sleep(3 * time.Second)
|
|
return statefulset, err
|
|
}
|
|
|
|
// DeleteDeployment creates a deployment in given namespace and returns the error if any
|
|
func DeleteDeployment(client kubernetes.Interface, namespace string, deploymentName string) error {
|
|
logrus.Infof("Deleting Deployment")
|
|
deploymentError := client.AppsV1().Deployments(namespace).Delete(context.TODO(), deploymentName, metav1.DeleteOptions{})
|
|
time.Sleep(3 * time.Second)
|
|
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)
|
|
daemonsetError := client.AppsV1().DaemonSets(namespace).Delete(context.TODO(), daemonsetName, metav1.DeleteOptions{})
|
|
time.Sleep(3 * time.Second)
|
|
return daemonsetError
|
|
}
|
|
|
|
// DeleteStatefulSet creates a statefulset in given namespace and returns the error if any
|
|
func DeleteStatefulSet(client kubernetes.Interface, namespace string, statefulsetName string) error {
|
|
logrus.Infof("Deleting StatefulSet %s", statefulsetName)
|
|
statefulsetError := client.AppsV1().StatefulSets(namespace).Delete(context.TODO(), statefulsetName, metav1.DeleteOptions{})
|
|
time.Sleep(3 * time.Second)
|
|
return statefulsetError
|
|
}
|
|
|
|
// UpdateConfigMap updates a configmap in given namespace and returns the error if any
|
|
func UpdateConfigMap(configmapClient core_v1.ConfigMapInterface, namespace string, configmapName string, label string, data string) error {
|
|
logrus.Infof("Updating configmap %q.\n", configmapName)
|
|
var configmap *v1.ConfigMap
|
|
if label != "" {
|
|
configmap = GetConfigmapWithUpdatedLabel(namespace, configmapName, label, data)
|
|
} else {
|
|
configmap = GetConfigmap(namespace, configmapName, data)
|
|
}
|
|
_, updateErr := configmapClient.Update(context.TODO(), configmap, metav1.UpdateOptions{})
|
|
time.Sleep(3 * time.Second)
|
|
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)
|
|
err := client.CoreV1().ConfigMaps(namespace).Delete(context.TODO(), configmapName, metav1.DeleteOptions{})
|
|
time.Sleep(3 * time.Second)
|
|
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 {
|
|
rand.Seed(time.Now().UnixNano())
|
|
b := make([]rune, n)
|
|
for i := range b {
|
|
b[i] = letters[rand.Intn(len(letters))]
|
|
}
|
|
return string(b)
|
|
}
|
|
|
|
// VerifyResourceEnvVarUpdate verifies whether the rolling upgrade happened or not
|
|
func VerifyResourceEnvVarUpdate(clients kube.Clients, config util.Config, envVarPostfix string, upgradeFuncs callbacks.RollingUpgradeFuncs) bool {
|
|
items := upgradeFuncs.ItemsFunc(clients, config.Namespace)
|
|
for _, i := range items {
|
|
containers := upgradeFuncs.ContainersFunc(i)
|
|
// match statefulsets with the correct annotation
|
|
annotationValue := util.ToObjectMeta(i).Annotations[config.Annotation]
|
|
searchAnnotationValue := util.ToObjectMeta(i).Annotations[options.AutoSearchAnnotation]
|
|
reloaderEnabledValue := util.ToObjectMeta(i).Annotations[options.ReloaderAutoAnnotation]
|
|
reloaderEnabled, err := strconv.ParseBool(reloaderEnabledValue)
|
|
matches := false
|
|
if err == nil && reloaderEnabled {
|
|
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
|
|
updated := GetResourceSHAFromEnvVar(containers, envName)
|
|
if updated == config.SHAValue {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// VerifyResourceAnnotationUpdate verifies whether the rolling upgrade happened or not
|
|
func VerifyResourceAnnotationUpdate(clients kube.Clients, config util.Config, upgradeFuncs callbacks.RollingUpgradeFuncs) bool {
|
|
items := upgradeFuncs.ItemsFunc(clients, config.Namespace)
|
|
for _, i := range items {
|
|
podAnnotations := upgradeFuncs.PodAnnotationsFunc(i)
|
|
// match statefulsets with the correct annotation
|
|
annotationValue := util.ToObjectMeta(i).Annotations[config.Annotation]
|
|
searchAnnotationValue := util.ToObjectMeta(i).Annotations[options.AutoSearchAnnotation]
|
|
reloaderEnabledValue := util.ToObjectMeta(i).Annotations[options.ReloaderAutoAnnotation]
|
|
reloaderEnabled, err := strconv.ParseBool(reloaderEnabledValue)
|
|
matches := false
|
|
if err == nil && reloaderEnabled {
|
|
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
|
|
}
|