add unit test for appendEnvVar

This commit is contained in:
Felix Kunde 2022-04-13 17:34:37 +02:00
parent 4b833c2436
commit 4b0602e911
5 changed files with 94 additions and 27 deletions

View File

@ -603,9 +603,9 @@ spec:
The operator will assign a set of environment variables to the database pods
that cannot be overridden to guarantee core functionality. Only variables with
'WAL_' and 'LOG_' prefixes can be customized, to allow backup and log shipping
to be specified differently. There are three ways to specify extra environment
variables (or override existing ones) for database pods:
'WAL_' and 'LOG_' prefixes can be customized to allow for backup and log
shipping to be specified differently. There are three ways to specify extra
environment variables (or override existing ones) for database pods:
* [Via ConfigMap](#via-configmap)
* [Via Secret](#via-secret)
@ -975,7 +975,7 @@ generated automatically. `WALG_S3_PREFIX` is identical to `WALE_S3_PREFIX`.
`SCOPE` is the Postgres cluster name.
:warning: If both `AWS_REGION` and `AWS_ENDPOINT` or `WALE_S3_ENDPOINT` are
defined, backups with WAL-E will fail. You can fix it by switching to WAL-G
defined backups with WAL-E will fail. You can fix it by switching to WAL-G
with `USE_WALG_BACKUP: "true"`.
### Google Cloud Platform setup

View File

@ -648,7 +648,7 @@ yet officially supported.
AWS region used to store EBS volumes. The default is `eu-central-1`. Note,
this option is not meant for specifying the AWS region for backups and
restore, since it can be separate from the EBS region. You have to define
AWS_REGION as a [custom environment variable](https://github.com/zalando/postgres-operator/blob/master/docs/administrator.md#custom-pod-environment-variables).
AWS_REGION as a [custom environment variable](../administrator.md#custom-pod-environment-variables).
* **additional_secret_mount**
Additional Secret (aws or gcp credentials) to mount in the pod.

View File

@ -770,8 +770,7 @@ spec:
Here `cluster` is a name of a source cluster that is going to be cloned. A new
cluster will be cloned from S3, using the latest backup before the `timestamp`.
Note, that a time zone is required for `timestamp` in the format of `+00:00`
which is UTC.
Note, a time zone is required for `timestamp` in the format of `+00:00` (UTC).
The operator will try to find the WAL location based on the configured
`wal_[s3|gs]_bucket` or `wal_az_storage_account` and the specified `uid`.
@ -790,7 +789,7 @@ configuration you can specify the full path under `s3_wal_path`. For
[Google Cloud Plattform](administrator.md#google-cloud-platform-setup)
or [Azure](administrator.md#azure-setup)
it can only be set globally with [custom Pod environment variables](administrator.md#custom-pod-environment-variables)
or locally in the Postgres manifest's [`env`]() section.
or locally in the Postgres manifest's [`env`](administrator.md#via-postgres-cluster-manifest) section.
For non AWS S3 following settings can be set to support cloning from other S3

View File

@ -937,14 +937,14 @@ func (c *Cluster) generateSpiloPodEnvVars(
}
func appendEnvVars(envs []v1.EnvVar, appEnv ...v1.EnvVar) []v1.EnvVar {
jenvs := envs
collectedEnvs := envs
for _, env := range appEnv {
env.Name = strings.ToUpper(env.Name)
if !isEnvVarPresent(jenvs, env.Name) {
jenvs = append(jenvs, env)
if !isEnvVarPresent(collectedEnvs, env.Name) {
collectedEnvs = append(collectedEnvs, env)
}
}
return jenvs
return collectedEnvs
}
func isEnvVarPresent(envs []v1.EnvVar, key string) bool {
@ -961,7 +961,7 @@ func (c *Cluster) getPodEnvironmentConfigMapVariables() ([]v1.EnvVar, error) {
configMapPodEnvVarsList := make([]v1.EnvVar, 0)
if c.OpConfig.PodEnvironmentConfigMap.Name == "" {
return configMapPodEnvVarsList, nil
return nil, nil
}
cm, err := c.KubeClient.ConfigMaps(c.OpConfig.PodEnvironmentConfigMap.Namespace).Get(
@ -977,7 +977,7 @@ func (c *Cluster) getPodEnvironmentConfigMapVariables() ([]v1.EnvVar, error) {
metav1.GetOptions{})
}
if err != nil {
return configMapPodEnvVarsList, fmt.Errorf("could not read PodEnvironmentConfigMap: %v", err)
return nil, fmt.Errorf("could not read PodEnvironmentConfigMap: %v", err)
}
}
@ -993,7 +993,7 @@ func (c *Cluster) getPodEnvironmentSecretVariables() ([]v1.EnvVar, error) {
secretPodEnvVarsList := make([]v1.EnvVar, 0)
if c.OpConfig.PodEnvironmentSecret == "" {
return secretPodEnvVarsList, nil
return nil, nil
}
secret := &v1.Secret{}
@ -1019,7 +1019,7 @@ func (c *Cluster) getPodEnvironmentSecretVariables() ([]v1.EnvVar, error) {
err = errors.Wrap(notFoundErr, err.Error())
}
if err != nil {
return secretPodEnvVarsList, errors.Wrap(err, "could not read Secret PodEnvironmentSecretName")
return nil, errors.Wrap(err, "could not read Secret PodEnvironmentSecretName")
}
for k := range secret.Data {
@ -1859,7 +1859,7 @@ func (c *Cluster) generateCloneEnvironment(description *acidv1.CloneDescription)
c.logger.Debugf("found WALAZStorageAccount %s - will set CLONE_AZURE_STORAGE_ACCOUNT", c.OpConfig.WALAZStorageAccount)
result = append(result, v1.EnvVar{Name: "CLONE_AZURE_STORAGE_ACCOUNT", Value: c.OpConfig.WALAZStorageAccount})
} else {
c.logger.Error("cannot figure out S3 or GS bucket or AZ storage account. All are empty in config.")
c.logger.Error("cannot figure out S3 or GS bucket or AZ storage account. All options are empty in the config.")
}
// append suffix because WAL location name is not the whole path
@ -1915,7 +1915,7 @@ func (c *Cluster) generateStandbyEnvironment(description *acidv1.StandbyDescript
result := make([]v1.EnvVar, 0)
if description.StandbyHost != "" {
c.logger.Info("preparing standby streaming from remote primary")
c.logger.Info("standby cluster streaming from remote primary")
result = append(result, v1.EnvVar{
Name: "STANDBY_HOST",
Value: description.StandbyHost,
@ -1927,7 +1927,7 @@ func (c *Cluster) generateStandbyEnvironment(description *acidv1.StandbyDescript
})
}
} else {
c.logger.Info("preparing standby streaming from WAL location")
c.logger.Info("standby cluster streaming from WAL location")
if description.S3WalPath != "" {
result = append(result, v1.EnvVar{
Name: "STANDBY_WALE_S3_PREFIX",

View File

@ -250,7 +250,6 @@ func TestPodEnvironmentConfigMapVariables(t *testing.T) {
}{
{
subTest: "no PodEnvironmentConfigMap",
envVars: []v1.EnvVar{},
},
{
subTest: "missing PodEnvironmentConfigMap",
@ -261,8 +260,7 @@ func TestPodEnvironmentConfigMapVariables(t *testing.T) {
},
},
},
envVars: []v1.EnvVar{},
err: fmt.Errorf("could not read PodEnvironmentConfigMap: NotFound"),
err: fmt.Errorf("could not read PodEnvironmentConfigMap: NotFound"),
},
{
subTest: "Pod environment vars configured by PodEnvironmentConfigMap",
@ -326,7 +324,6 @@ func TestPodEnvironmentSecretVariables(t *testing.T) {
}{
{
subTest: "No PodEnvironmentSecret configured",
envVars: []v1.EnvVar{},
},
{
subTest: "Secret referenced by PodEnvironmentSecret does not exist",
@ -337,8 +334,7 @@ func TestPodEnvironmentSecretVariables(t *testing.T) {
ResourceCheckTimeout: time.Duration(testResourceCheckTimeout),
},
},
envVars: []v1.EnvVar{},
err: fmt.Errorf("could not read Secret PodEnvironmentSecretName: still failing after %d retries: secret.core %q not found", maxRetries, testPodEnvironmentObjectNotExists),
err: fmt.Errorf("could not read Secret PodEnvironmentSecretName: still failing after %d retries: secret.core %q not found", maxRetries, testPodEnvironmentObjectNotExists),
},
{
subTest: "API error during PodEnvironmentSecret retrieval",
@ -349,8 +345,7 @@ func TestPodEnvironmentSecretVariables(t *testing.T) {
ResourceCheckTimeout: time.Duration(testResourceCheckTimeout),
},
},
envVars: []v1.EnvVar{},
err: fmt.Errorf("could not read Secret PodEnvironmentSecretName: Secret PodEnvironmentSecret API error"),
err: fmt.Errorf("could not read Secret PodEnvironmentSecretName: Secret PodEnvironmentSecret API error"),
},
{
subTest: "Pod environment vars reference all keys from secret configured by PodEnvironmentSecret",
@ -945,6 +940,79 @@ func TestCloneEnv(t *testing.T) {
}
}
func TestAppendEnvVar(t *testing.T) {
testName := "TestAppendEnvVar"
tests := []struct {
subTest string
envs []v1.EnvVar
envsToAppend []v1.EnvVar
expectedSize int
}{
{
subTest: "append two variables - one with same key that should get rejected",
envs: []v1.EnvVar{
{
Name: "CUSTOM_VARIABLE",
Value: "test",
},
},
envsToAppend: []v1.EnvVar{
{
Name: "CUSTOM_VARIABLE",
Value: "new-test",
},
{
Name: "ANOTHER_CUSTOM_VARIABLE",
Value: "another-test",
},
},
expectedSize: 2,
},
{
subTest: "append empty slice",
envs: []v1.EnvVar{
{
Name: "CUSTOM_VARIABLE",
Value: "test",
},
},
envsToAppend: []v1.EnvVar{},
expectedSize: 1,
},
{
subTest: "append nil",
envs: []v1.EnvVar{
{
Name: "CUSTOM_VARIABLE",
Value: "test",
},
},
envsToAppend: nil,
expectedSize: 1,
},
}
for _, tt := range tests {
finalEnvs := appendEnvVars(tt.envs, tt.envsToAppend...)
if len(finalEnvs) != tt.expectedSize {
t.Errorf("%s %s: expected %d env variables, got %d",
testName, tt.subTest, tt.expectedSize, len(finalEnvs))
}
for _, env := range tt.envs {
for _, finalEnv := range finalEnvs {
if env.Name == finalEnv.Name {
if env.Value != finalEnv.Value {
t.Errorf("%s %s: expected env value %s of variable %s, got %s instead",
testName, tt.subTest, env.Value, env.Name, finalEnv.Value)
}
}
}
}
}
}
func TestStandbyEnv(t *testing.T) {
testName := "TestStandbyEnv"
tests := []struct {