@@ -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
11161265func (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