Skip to content

Commit 81fd12b

Browse files
Merge pull request #549 from karelyatin/OSPRH-27985-job
[ovndbcluster] Allow config changes without pod restarts
2 parents 2885ca0 + ce8a17f commit 81fd12b

17 files changed

Lines changed: 563 additions & 39 deletions

api/bases/ovn.openstack.org_ovndbclusters.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,10 @@ spec:
260260
type: object
261261
probeIntervalToActive:
262262
default: 60000
263-
description: Active probe interval from standby to active ovsdb-server
264-
remote
263+
description: |-
264+
DEPRECATED: ProbeIntervalToActive is only relevant for active/standby ovsdb configurations.
265+
This parameter is not used in RAFT clustered deployments and will be ignored.
266+
Active probe interval from standby to active ovsdb-server remote
265267
format: int32
266268
type: integer
267269
replicas:

api/v1beta1/ovndbcluster_types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ type OVNDBClusterSpecCore struct {
100100

101101
// +kubebuilder:validation:Optional
102102
// +kubebuilder:default=60000
103+
// DEPRECATED: ProbeIntervalToActive is only relevant for active/standby ovsdb configurations.
104+
// This parameter is not used in RAFT clustered deployments and will be ignored.
103105
// Active probe interval from standby to active ovsdb-server remote
104106
ProbeIntervalToActive int32 `json:"probeIntervalToActive"`
105107

config/crd/bases/ovn.openstack.org_ovndbclusters.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,10 @@ spec:
260260
type: object
261261
probeIntervalToActive:
262262
default: 60000
263-
description: Active probe interval from standby to active ovsdb-server
264-
remote
263+
description: |-
264+
DEPRECATED: ProbeIntervalToActive is only relevant for active/standby ovsdb configurations.
265+
This parameter is not used in RAFT clustered deployments and will be ignored.
266+
Active probe interval from standby to active ovsdb-server remote
265267
format: int32
266268
type: integer
267269
replicas:

internal/controller/ovndbcluster_controller.go

Lines changed: 150 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import (
4646
"github.com/openstack-k8s-operators/lib-common/modules/common/configmap"
4747
"github.com/openstack-k8s-operators/lib-common/modules/common/env"
4848
"github.com/openstack-k8s-operators/lib-common/modules/common/helper"
49+
"github.com/openstack-k8s-operators/lib-common/modules/common/job"
4950
"github.com/openstack-k8s-operators/lib-common/modules/common/labels"
5051
nad "github.com/openstack-k8s-operators/lib-common/modules/common/networkattachment"
5152
common_rbac "github.com/openstack-k8s-operators/lib-common/modules/common/rbac"
@@ -562,6 +563,7 @@ func (r *OVNDBClusterReconciler) reconcileNormal(ctx context.Context, instance *
562563
// create Configmap required for dbcluster input
563564
// - %-config configmap holding minimal dbcluster config required to get the service up
564565
//
566+
// Create ConfigMaps with ALL parameters included for setup script (pods will use these)
565567
err = r.generateServiceConfigMaps(ctx, helper, instance, &configMapVars, serviceName)
566568
if err != nil {
567569
instance.Status.Conditions.Set(condition.FalseCondition(
@@ -662,6 +664,21 @@ func (r *OVNDBClusterReconciler) reconcileNormal(ctx context.Context, instance *
662664
instance.Status.ReadyCount = stateful.Status.ReadyReplicas
663665
}
664666

667+
// Only run runtime config when all pods are ready and no rolling update in progress
668+
if instance.Status.ReadyCount == *instance.Spec.Replicas &&
669+
stateful.Status.UpdatedReplicas == *instance.Spec.Replicas {
670+
err = r.reconcileRuntimeConfig(ctx, helper, instance, serviceLabels, serviceName)
671+
if err != nil {
672+
instance.Status.Conditions.Set(condition.FalseCondition(
673+
condition.ServiceConfigReadyCondition,
674+
condition.ErrorReason,
675+
condition.SeverityWarning,
676+
condition.ServiceConfigReadyErrorMessage,
677+
err.Error()))
678+
return ctrl.Result{}, err
679+
}
680+
}
681+
665682
// verify if network attachment matches expectations
666683
networkReady, networkAttachmentStatus, err := nad.VerifyNetworkStatusFromAnnotation(ctx, helper, networkAttachments, serviceLabels, instance.Status.ReadyCount)
667684
if err != nil {
@@ -1112,6 +1129,138 @@ func (r *OVNDBClusterReconciler) deleteExternalConfigMaps(
11121129
return nil
11131130
}
11141131

1132+
// reconcileRuntimeConfig - handle runtime configuration without pod restart using consolidated event-driven Jobs
1133+
func (r *OVNDBClusterReconciler) reconcileRuntimeConfig(
1134+
ctx context.Context,
1135+
h *helper.Helper,
1136+
instance *ovnv1.OVNDBCluster,
1137+
serviceLabels map[string]string,
1138+
serviceName string,
1139+
) error {
1140+
Log := r.GetLogger(ctx)
1141+
1142+
// Calculate combined hash for all runtime parameters using deterministic ordering
1143+
runtimeEnvVars := map[string]env.Setter{
1144+
"ElectionTimer": env.SetValue(fmt.Sprintf("%d", instance.Spec.ElectionTimer)),
1145+
"InactivityProbe": env.SetValue(fmt.Sprintf("%d", instance.Spec.InactivityProbe)),
1146+
"LogLevel": env.SetValue(instance.Spec.LogLevel),
1147+
}
1148+
mergedRuntimeVars := env.MergeEnvs([]corev1.EnvVar{}, runtimeEnvVars)
1149+
runtimeConfigHash, err := util.ObjectHash(mergedRuntimeVars)
1150+
if err != nil {
1151+
return err
1152+
}
1153+
1154+
// Check if any runtime config changed
1155+
runtimeConfigHashKey := "OvnDBClusterRuntimeConfigHash"
1156+
currentHash := instance.Status.Hash[runtimeConfigHashKey]
1157+
1158+
if runtimeConfigHash == currentHash {
1159+
// No changes detected
1160+
return nil
1161+
}
1162+
1163+
Log.Info("Runtime configuration changed",
1164+
"oldHash", currentHash,
1165+
"newHash", runtimeConfigHash,
1166+
"ElectionTimer", instance.Spec.ElectionTimer,
1167+
"InactivityProbe", instance.Spec.InactivityProbe,
1168+
"LogLevel", instance.Spec.LogLevel)
1169+
1170+
// Include all runtime configs for job creation when any changes detected
1171+
changedConfigs := map[string]interface{}{
1172+
"ElectionTimer": instance.Spec.ElectionTimer,
1173+
"InactivityProbe": instance.Spec.InactivityProbe,
1174+
"LogLevel": instance.Spec.LogLevel,
1175+
}
1176+
1177+
// Update hash BEFORE creating jobs to prevent continuous re-creation
1178+
instance.Status.Hash[runtimeConfigHashKey] = runtimeConfigHash
1179+
1180+
// Create runtime-config ConfigMap for the Jobs
1181+
err = r.ensureRuntimeConfigMap(ctx, h, instance, serviceName)
1182+
if err != nil {
1183+
Log.Error(err, "Failed to create runtime-config ConfigMap")
1184+
return err
1185+
}
1186+
1187+
// Create consolidated configuration jobs
1188+
jobsDef, err := ovndbcluster.RuntimeConfigJobs(ctx, r.Client, instance, serviceLabels, serviceName, changedConfigs)
1189+
if err != nil {
1190+
Log.Error(err, "Failed to create configuration Jobs")
1191+
return err
1192+
}
1193+
1194+
// Process each job using the job.NewJob pattern - submit ALL jobs first
1195+
var anyJobInProgress bool
1196+
for _, jobDef := range jobsDef {
1197+
configHashKey := "OvnDBClusterConfigHash-" + jobDef.Spec.Template.Spec.NodeName
1198+
configJob := job.NewJob(
1199+
jobDef,
1200+
configHashKey,
1201+
false,
1202+
time.Duration(5)*time.Second,
1203+
runtimeConfigHash,
1204+
)
1205+
ctrlResult, err := configJob.DoJob(ctx, h)
1206+
if err != nil {
1207+
Log.Error(err, "Failed to execute configuration job")
1208+
return err
1209+
}
1210+
if (ctrlResult != ctrl.Result{}) {
1211+
Log.Info("Configuration job in progress", "nodeName", jobDef.Spec.Template.Spec.NodeName)
1212+
anyJobInProgress = true // Don't return early, continue processing remaining jobs
1213+
}
1214+
}
1215+
1216+
// Return early only after ALL jobs have been submitted
1217+
if anyJobInProgress {
1218+
Log.Info("Some configuration jobs still in progress - requeuing")
1219+
return nil
1220+
}
1221+
1222+
Log.Info("All configuration jobs completed successfully")
1223+
1224+
return nil
1225+
}
1226+
1227+
// ensureRuntimeConfigMap creates the runtime-config ConfigMap needed by configuration Jobs
1228+
func (r *OVNDBClusterReconciler) ensureRuntimeConfigMap(
1229+
ctx context.Context,
1230+
h *helper.Helper,
1231+
instance *ovnv1.OVNDBCluster,
1232+
serviceName string,
1233+
) error {
1234+
// Create template parameters for runtime config script
1235+
templateParameters := make(map[string]any)
1236+
templateParameters["SERVICE_NAME"] = serviceName
1237+
templateParameters["DB_TYPE"] = strings.ToLower(instance.Spec.DBType)
1238+
templateParameters["DB_PORT"] = ovndbcluster.DbPortNB
1239+
if instance.Spec.DBType == ovnv1.SBDBType {
1240+
templateParameters["DB_PORT"] = ovndbcluster.DbPortSB
1241+
}
1242+
templateParameters["TLS"] = instance.Spec.TLS.Enabled()
1243+
1244+
cmLabels := labels.GetLabels(instance, labels.GetGroupLabel(serviceName), map[string]string{})
1245+
1246+
cms := []util.Template{
1247+
{
1248+
Name: fmt.Sprintf("%s-runtime-config", instance.Name),
1249+
Namespace: instance.Namespace,
1250+
Type: util.TemplateTypeNone,
1251+
AdditionalTemplate: map[string]string{
1252+
"runtime-config.sh": "/ovndbcluster/config/runtime-config.sh",
1253+
},
1254+
InstanceType: instance.Kind,
1255+
Labels: cmLabels,
1256+
ConfigOptions: templateParameters,
1257+
},
1258+
}
1259+
1260+
// Create just the runtime-config ConfigMap
1261+
return configmap.EnsureConfigMaps(ctx, h, instance, cms, &map[string]env.Setter{})
1262+
}
1263+
11151264
// generateServiceConfigMaps - create create configmaps which hold service configuration
11161265
func (r *OVNDBClusterReconciler) generateServiceConfigMaps(
11171266
ctx context.Context,
@@ -1125,7 +1274,6 @@ func (r *OVNDBClusterReconciler) generateServiceConfigMaps(
11251274

11261275
templateParameters := make(map[string]any)
11271276

1128-
templateParameters["OVN_LOG_LEVEL"] = instance.Spec.LogLevel
11291277
templateParameters["SERVICE_NAME"] = serviceName
11301278
templateParameters["NAMESPACE"] = instance.GetNamespace()
11311279
templateParameters["DB_TYPE"] = strings.ToLower(instance.Spec.DBType)
@@ -1135,15 +1283,13 @@ func (r *OVNDBClusterReconciler) generateServiceConfigMaps(
11351283
templateParameters["DB_PORT"] = ovndbcluster.DbPortSB
11361284
templateParameters["RAFT_PORT"] = ovndbcluster.RaftPortSB
11371285
}
1138-
templateParameters["OVN_ELECTION_TIMER"] = instance.Spec.ElectionTimer
1139-
templateParameters["OVN_INACTIVITY_PROBE"] = instance.Spec.InactivityProbe
1140-
templateParameters["OVN_PROBE_INTERVAL_TO_ACTIVE"] = instance.Spec.ProbeIntervalToActive
11411286
templateParameters["TLS"] = instance.Spec.TLS.Enabled()
11421287
templateParameters["OVNDB_CERT_PATH"] = ovn_common.OVNDbCertPath
11431288
templateParameters["OVNDB_KEY_PATH"] = ovn_common.OVNDbKeyPath
11441289
templateParameters["OVNDB_CACERT_PATH"] = ovn_common.OVNDbCaCertPath
11451290
templateParameters["OVN_METRICS_CERT_PATH"] = ovn_common.OVNMetricsCertPath
11461291
templateParameters["OVN_METRICS_KEY_PATH"] = ovn_common.OVNMetricsKeyPath
1292+
templateParameters["OVN_RUNDIR"] = "/etc/ovn"
11471293

11481294
cms := []util.Template{
11491295
// ScriptsConfigMap

0 commit comments

Comments
 (0)