Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Also apply volumes and custom configs from spec to init containers #29

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ env:

jobs:
# All test running sequentially take around ~2h.
# Sppliting them in groups that take more or less the same time makes PR's readiness faster
# Splitting them in groups that take more or less the same time makes PR's readiness faster
test-group:
strategy:
fail-fast: false
matrix:
label:
- "group:1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ package failover

import (
"errors"
"strconv"

core "k8s.io/api/core/v1"
v1 "reactive-tech.io/kubegres/api/v1"
"reactive-tech.io/kubegres/controllers/ctx"
"reactive-tech.io/kubegres/controllers/operation"
"reactive-tech.io/kubegres/controllers/states"
"reactive-tech.io/kubegres/controllers/states/statefulset"
"strconv"
)

type PrimaryToReplicaFailOver struct {
Expand Down Expand Up @@ -244,9 +245,9 @@ func (r *PrimaryToReplicaFailOver) promoteReplicaToPrimary(newPrimary statefulse
newPrimary.StatefulSet.Labels["replicationRole"] = ctx.PrimaryRoleName
newPrimary.StatefulSet.Spec.Template.Labels["replicationRole"] = ctx.PrimaryRoleName
volumeMount := core.VolumeMount{
Name: "base-config",
Name: r.resourcesStates.Config.ConfigLocations.PromoteReplica,
MountPath: "/tmp/promote_replica_to_primary.sh",
SubPath: "promote_replica_to_primary.sh",
SubPath: states.ConfigMapDataKeyPromoteReplica,
}

initContainer := &newPrimary.StatefulSet.Spec.Template.Spec.InitContainers[0]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@ func (r *CustomConfigSpecEnforcer) GetSpecName() string {

func (r *CustomConfigSpecEnforcer) CheckForSpecDifference(statefulSet *apps.StatefulSet) StatefulSetSpecDifference {

statefulSetCopy := *statefulSet
hasStatefulSetChanged, changesDetails := r.customConfigSpecHelper.ConfigureStatefulSet(&statefulSetCopy)
// We need to create a deep copy of the statefulSet to avoid modifying the original object, as we are only checking for differences.
// Original statefulSet will be modified by the EnforceSpec method.
statefulSetCopy := statefulSet.DeepCopy()
hasStatefulSetChanged, changesDetails := r.customConfigSpecHelper.ConfigureStatefulSet(statefulSetCopy)

if hasStatefulSetChanged {
return StatefulSetSpecDifference{
Expand All @@ -58,6 +60,6 @@ func (r *CustomConfigSpecEnforcer) EnforceSpec(statefulSet *apps.StatefulSet) (w
return wasSpecUpdated, nil
}

func (r *CustomConfigSpecEnforcer) OnSpecEnforcedSuccessfully(statefulSet *apps.StatefulSet) error {
func (r *CustomConfigSpecEnforcer) OnSpecEnforcedSuccessfully(*apps.StatefulSet) error {
return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,22 @@ func extractCustom(src map[string]string) map[string]string {

func (r *CustomMetadataSpecEnforcer) EnforceSpec(statefulSet *apps.StatefulSet) (bool, error) {
md := getCustomMetadata(r.kubegresContext.Kubegres.GetObjectMeta())
merge(statefulSet.ObjectMeta.Labels, md.Labels)
merge(statefulSet.ObjectMeta.Annotations, md.Annotations)
merge(statefulSet.Spec.Template.ObjectMeta.Labels, md.Labels)
merge(statefulSet.Spec.Template.ObjectMeta.Annotations, md.Annotations)
statefulSet.ObjectMeta.Labels = merge(statefulSet.ObjectMeta.Labels, md.Labels)
statefulSet.ObjectMeta.Annotations = merge(statefulSet.ObjectMeta.Annotations, md.Annotations)
statefulSet.Spec.Template.ObjectMeta.Labels = merge(statefulSet.Spec.Template.ObjectMeta.Labels, md.Labels)
statefulSet.Spec.Template.ObjectMeta.Annotations = merge(statefulSet.Spec.Template.ObjectMeta.Annotations, md.Annotations)
return true, nil
}

func merge(dst map[string]string, src map[string]string) {
for key, value := range src {
dst[key] = value
func merge(a map[string]string, b map[string]string) map[string]string {
result := make(map[string]string, len(a)+len(b))
for key, value := range a {
result[key] = value
}
for key, value := range b {
result[key] = value
}
return result
}

func (r *CustomMetadataSpecEnforcer) OnSpecEnforcedSuccessfully(*apps.StatefulSet) error {
Expand Down
60 changes: 56 additions & 4 deletions controllers/spec/enforcer/statefulset_spec/VolumeSpecEnforcer.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ limitations under the License.
package statefulset_spec

import (
"reflect"

apps "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
"reactive-tech.io/kubegres/controllers/ctx"
"reflect"
)

type VolumeSpecEnforcer struct {
Expand Down Expand Up @@ -52,12 +53,21 @@ func (r *VolumeSpecEnforcer) CheckForSpecDifference(statefulSet *apps.StatefulSe
}
}

currentCustomVolumeMountsInit, hasInitContainer := r.getVolumeMountsFromInitContainer(statefulSet)
currentCustomVolumeMounts := r.getCurrentCustomVolumeMounts(statefulSet)
expectedCustomVolumeMounts := r.kubegresContext.Kubegres.Spec.Volume.VolumeMounts

if hasInitContainer && !r.compareVolumeMounts(currentCustomVolumeMountsInit, expectedCustomVolumeMounts) {
return StatefulSetSpecDifference{
SpecName: "Volume.VolumeMounts[initContainer]",
Current: r.volumeMountsToString(currentCustomVolumeMountsInit),
Expected: r.volumeMountsToString(expectedCustomVolumeMounts),
}
}

if !r.compareVolumeMounts(currentCustomVolumeMounts, expectedCustomVolumeMounts) {
return StatefulSetSpecDifference{
SpecName: "Volume.VolumeMounts",
SpecName: "Volume.VolumeMounts[container]",
Current: r.volumeMountsToString(currentCustomVolumeMounts),
Expected: r.volumeMountsToString(expectedCustomVolumeMounts),
}
Expand All @@ -70,6 +80,7 @@ func (r *VolumeSpecEnforcer) EnforceSpec(statefulSet *apps.StatefulSet) (wasSpec

r.removeCustomVolumes(statefulSet)
r.removeCustomVolumeMounts(statefulSet)
r.removeCustomVolumeMountsFromInitContainer(statefulSet)

if r.kubegresContext.Kubegres.Spec.Volume.Volumes != nil {
statefulSet.Spec.Template.Spec.Volumes = append(statefulSet.Spec.Template.Spec.Volumes, r.kubegresContext.Kubegres.Spec.Volume.Volumes...)
Expand All @@ -79,10 +90,14 @@ func (r *VolumeSpecEnforcer) EnforceSpec(statefulSet *apps.StatefulSet) (wasSpec
statefulSet.Spec.Template.Spec.Containers[0].VolumeMounts = append(statefulSet.Spec.Template.Spec.Containers[0].VolumeMounts, r.kubegresContext.Kubegres.Spec.Volume.VolumeMounts...)
}

if len(statefulSet.Spec.Template.Spec.InitContainers) > 0 && statefulSet.Spec.Template.Spec.InitContainers[0].VolumeMounts != nil {
statefulSet.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(statefulSet.Spec.Template.Spec.InitContainers[0].VolumeMounts, r.kubegresContext.Kubegres.Spec.Volume.VolumeMounts...)
}

return true, nil
}

func (r *VolumeSpecEnforcer) OnSpecEnforcedSuccessfully(statefulSet *apps.StatefulSet) error {
func (r *VolumeSpecEnforcer) OnSpecEnforcedSuccessfully(*apps.StatefulSet) error {
return nil
}

Expand All @@ -109,7 +124,7 @@ func (r *VolumeSpecEnforcer) doesExpectedVolumeExist(expectedCustomVolume v1.Vol
return false
}

func (r *VolumeSpecEnforcer) compareVolumeMounts(currentCustomVolumeMounts []v1.VolumeMount, expectedCustomVolumeMounts []v1.VolumeMount) bool {
func (r *VolumeSpecEnforcer) compareVolumeMounts(currentCustomVolumeMounts, expectedCustomVolumeMounts []v1.VolumeMount) bool {

if len(expectedCustomVolumeMounts) != len(currentCustomVolumeMounts) {
return false
Expand Down Expand Up @@ -158,6 +173,23 @@ func (r *VolumeSpecEnforcer) getCurrentCustomVolumeMounts(statefulSet *apps.Stat
return customVolumeMounts
}

func (r *VolumeSpecEnforcer) getVolumeMountsFromInitContainer(statefulSet *apps.StatefulSet) ([]v1.VolumeMount, bool) {

if len(statefulSet.Spec.Template.Spec.InitContainers) == 0 {
return nil, false
}

initContainer := &statefulSet.Spec.Template.Spec.InitContainers[0]
var customVolumeMounts []v1.VolumeMount

for _, volumeMount := range initContainer.VolumeMounts {
if !r.kubegresContext.IsReservedVolumeName(volumeMount.Name) {
customVolumeMounts = append(customVolumeMounts, volumeMount)
}
}
return customVolumeMounts, true
}

func (r *VolumeSpecEnforcer) removeCustomVolumes(statefulSet *apps.StatefulSet) {

currentCustomVolumes := r.getCurrentCustomVolumes(statefulSet)
Expand Down Expand Up @@ -209,6 +241,26 @@ func (r *VolumeSpecEnforcer) removeCustomVolumeMounts(statefulSet *apps.Stateful
}
}

func (r *VolumeSpecEnforcer) removeCustomVolumeMountsFromInitContainer(statefulSet *apps.StatefulSet) {

currentCustomVolumeMounts, hasInit := r.getVolumeMountsFromInitContainer(statefulSet)
if !hasInit || len(currentCustomVolumeMounts) == 0 {
return
}

currentCustomVolumeMountsCopy := make([]v1.VolumeMount, len(currentCustomVolumeMounts))
copy(currentCustomVolumeMountsCopy, currentCustomVolumeMounts)

initContainer := &statefulSet.Spec.Template.Spec.InitContainers[0]

for _, customVolumeMount := range currentCustomVolumeMountsCopy {
index := r.getIndexOfVolumeMount(customVolumeMount, initContainer.VolumeMounts)
if index >= 0 {
initContainer.VolumeMounts = append(initContainer.VolumeMounts[:index], initContainer.VolumeMounts[index+1:]...)
}
}
}

func (r *VolumeSpecEnforcer) getIndexOfVolumeMount(volumeMountToSearch v1.VolumeMount, volumeMounts []v1.VolumeMount) int {
index := 0
for _, volumeMount := range volumeMounts {
Expand Down
37 changes: 23 additions & 14 deletions controllers/spec/template/CustomConfigSpecHelper.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ func (r *CustomConfigSpecHelper) ConfigureStatefulSet(statefulSet *v1.StatefulSe
hasStatefulSetChanged = true
}

if r.updateVolumeMountNameIfChanged(configMap.ConfigLocations.CopyPrimaryDataToReplica, states.ConfigMapDataKeyCopyPrimaryDataToReplica, statefulSet) {
differenceDetails += r.createDescriptionMsg(configMap.ConfigLocations.CopyPrimaryDataToReplica, states.ConfigMapDataKeyCopyPrimaryDataToReplica)
hasStatefulSetChanged = true
}

if r.updateVolumeMountNameIfChanged(configMap.ConfigLocations.PrimaryCreateReplicaRole, states.ConfigMapDataKeyPrimaryCreateReplicaRole, statefulSet) {
differenceDetails += r.createDescriptionMsg(configMap.ConfigLocations.PrimaryCreateReplicaRole, states.ConfigMapDataKeyPrimaryCreateReplicaRole)
hasStatefulSetChanged = true
}

// No need to check for states.ConfigMapDataKeyPromoteReplica as this is only used by the failover enforcer

statefulSetTemplateSpec := &statefulSet.Spec.Template.Spec

customConfigMapVolume := r.getCustomConfigMapVolume(statefulSetTemplateSpec.Volumes)
Expand Down Expand Up @@ -89,32 +101,29 @@ func (r *CustomConfigSpecHelper) ConfigureStatefulSet(statefulSet *v1.StatefulSe

func (r *CustomConfigSpecHelper) updateVolumeMountNameIfChanged(volumeName, configMapDataKey string, statefulSet *v1.StatefulSet) (updated bool) {

volumeMounts := statefulSet.Spec.Template.Spec.Containers[0].VolumeMounts

for i := 0; i < len(volumeMounts); i++ {
volumeMount := volumeMounts[i]
for i, volumeMount := range statefulSet.Spec.Template.Spec.Containers[0].VolumeMounts {
if volumeMount.SubPath == configMapDataKey && volumeMount.Name != volumeName {
statefulSet.Spec.Template.Spec.Containers[0].VolumeMounts[i].Name = volumeName
updated = true
}
}

if len(statefulSet.Spec.Template.Spec.InitContainers) > 0 {
for i, volume := range statefulSet.Spec.Template.Spec.InitContainers[0].VolumeMounts {
if volume.SubPath == configMapDataKey && volume.Name != volumeName {
statefulSet.Spec.Template.Spec.InitContainers[0].VolumeMounts[i].Name = volumeName
updated = true
}
}
}

return updated
}

func (r *CustomConfigSpecHelper) createDescriptionMsg(volumeMountName, configMapDataKey string) string {
return "VolumeMount with subPath: '" + configMapDataKey + "' was updated to name: '" + volumeMountName + "' - "
}

func (r *CustomConfigSpecHelper) getVolumeMountIndex(configMapDataKey string, statefulSet *v1.StatefulSet) int {
volumeMounts := statefulSet.Spec.Template.Spec.Containers[0].VolumeMounts
for i := 0; i < len(volumeMounts); i++ {
if volumeMounts[i].SubPath == configMapDataKey {
return i
}
}
return -1
}

func (r *CustomConfigSpecHelper) getCustomConfigMapVolume(volumes []core.Volume) *core.Volume {
for _, volume := range volumes {
if volume.Name == ctx.CustomConfigMapVolumeName {
Expand Down
3 changes: 3 additions & 0 deletions controllers/spec/template/ResourcesCreatorFromTemplate.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,9 @@ func (r *ResourcesCreatorFromTemplate) initStatefulSet(

if postgresSpec.Volume.VolumeMounts != nil {
statefulSetTemplate.Spec.Template.Spec.Containers[0].VolumeMounts = append(statefulSetTemplate.Spec.Template.Spec.Containers[0].VolumeMounts, r.kubegresContext.Kubegres.Spec.Volume.VolumeMounts...)
if len(statefulSetTemplate.Spec.Template.Spec.InitContainers) > 0 {
statefulSetTemplate.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(statefulSetTemplate.Spec.Template.Spec.InitContainers[0].VolumeMounts, r.kubegresContext.Kubegres.Spec.Volume.VolumeMounts...)
}
}

if postgresSpec.SecurityContext != nil {
Expand Down
37 changes: 29 additions & 8 deletions controllers/states/ConfigStates.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,13 @@ import (
)

const (
ConfigMapDataKeyPostgresConf = "postgres.conf"
ConfigMapDataKeyPrimaryInitScript = "primary_init_script.sh"
ConfigMapDataKeyPgHbaConf = "pg_hba.conf"
ConfigMapDataKeyBackUpScript = "backup_database.sh"
ConfigMapDataKeyPostgresConf = "postgres.conf"
ConfigMapDataKeyPrimaryInitScript = "primary_init_script.sh"
ConfigMapDataKeyPgHbaConf = "pg_hba.conf"
ConfigMapDataKeyBackUpScript = "backup_database.sh"
ConfigMapDataKeyCopyPrimaryDataToReplica = "copy_primary_data_to_replica.sh"
ConfigMapDataKeyPrimaryCreateReplicaRole = "primary_create_replication_role.sh"
ConfigMapDataKeyPromoteReplica = "promote_replica_to_primary.sh"
)

type ConfigStates struct {
Expand All @@ -46,10 +49,13 @@ type ConfigStates struct {

// Stores as string the volume-name for each config-type which can be either 'base-config' or 'custom-config'
type ConfigLocations struct {
PostgreConf string
PrimaryInitScript string
BackUpScript string
PgHbaConf string
PostgreConf string
PrimaryInitScript string
BackUpScript string
PgHbaConf string
CopyPrimaryDataToReplica string
PrimaryCreateReplicaRole string
PromoteReplica string
}

func loadConfigStates(kubegresContext ctx.KubegresContext) (ConfigStates, error) {
Expand All @@ -69,6 +75,9 @@ func (r *ConfigStates) loadStates() (err error) {
r.ConfigLocations.PrimaryInitScript = ctx.BaseConfigMapVolumeName
r.ConfigLocations.BackUpScript = ctx.BaseConfigMapVolumeName
r.ConfigLocations.PgHbaConf = ctx.BaseConfigMapVolumeName
r.ConfigLocations.CopyPrimaryDataToReplica = ctx.BaseConfigMapVolumeName
r.ConfigLocations.PrimaryCreateReplicaRole = ctx.BaseConfigMapVolumeName
r.ConfigLocations.PromoteReplica = ctx.BaseConfigMapVolumeName

baseConfigMap, err := r.getBaseDeployedConfigMap()
if err != nil {
Expand Down Expand Up @@ -107,6 +116,18 @@ func (r *ConfigStates) loadStates() (err error) {
if customConfigMap.Data[ConfigMapDataKeyPgHbaConf] != "" {
r.ConfigLocations.PgHbaConf = ctx.CustomConfigMapVolumeName
}

if customConfigMap.Data[ConfigMapDataKeyCopyPrimaryDataToReplica] != "" {
r.ConfigLocations.CopyPrimaryDataToReplica = ctx.CustomConfigMapVolumeName
}

if customConfigMap.Data[ConfigMapDataKeyPrimaryCreateReplicaRole] != "" {
r.ConfigLocations.PrimaryCreateReplicaRole = ctx.CustomConfigMapVolumeName
}

if customConfigMap.Data[ConfigMapDataKeyPromoteReplica] != "" {
r.ConfigLocations.PromoteReplica = ctx.CustomConfigMapVolumeName
}
}

return nil
Expand Down
Loading