@@ -1164,58 +1164,27 @@ func (r *Reconciler) reconcileKafkaPvc(ctx context.Context, log logr.Logger, bro
11641164 return errorfactory .New (errorfactory.APIFailure {}, err , "getting resource failed" , "kind" , desiredType )
11651165 }
11661166
1167- // Handle disk removal
1168- if len (pvcList .Items ) > len (desiredPvcs ) {
1169- for _ , pvc := range pvcList .Items {
1170- foundInDesired := false
1171- existingMountPath := pvc .Annotations ["mountPath" ]
1172-
1173- for _ , desiredPvc := range desiredPvcs {
1174- desiredMountPath := desiredPvc .Annotations ["mountPath" ]
1175-
1176- if existingMountPath == desiredMountPath {
1177- foundInDesired = true
1178- break
1179- }
1180- }
1181-
1182- if foundInDesired {
1183- continue
1184- }
1167+ isController , err := r .isController (util .ConvertStringToInt32 (brokerId ))
1168+ if err != nil {
1169+ return errors .WrapIfWithDetails (err , "could not determine if broker is controller" , "brokerId" , brokerId )
1170+ }
11851171
1186- mountPathToRemove := existingMountPath
1187- if brokerState , ok := r .KafkaCluster .Status .BrokersState [brokerId ]; ok {
1188- volumeStateStatus , found := brokerState .GracefulActionState .VolumeStates [mountPathToRemove ]
1189- if ! found {
1190- // If the state is not found, it means that the disk removal was done according to the disk removal succeeded branch
1191- log .Info ("Disk removal was completed, waiting for Rolling Upgrade to remove PVC" , "brokerId" , brokerId , "mountPath" , mountPathToRemove )
1192- continue
1193- }
1172+ if isController {
1173+ if len (desiredPvcs ) != 1 {
1174+ return errors .New ("controller broker can have only one volume" )
1175+ }
1176+ // changing the controller's mount path leads to a new disk being added and the controller in an unrecoverable state
1177+ // due to the new disk not being initialized for kafka. we want to avoid this situation.
1178+ if len (pvcList .Items ) == 1 && pvcList .Items [0 ].Annotations ["mountPath" ] != desiredPvcs [0 ].Annotations ["mountPath" ] {
1179+ return errors .New ("controller broker volume mount path cannot be changed" )
1180+ }
1181+ }
11941182
1195- // Check the volume state
1196- ccVolumeState := volumeStateStatus .CruiseControlVolumeState
1197- switch {
1198- case ccVolumeState .IsDiskRemovalSucceeded ():
1199- if err := r .Client .Delete (ctx , & pvc ); err != nil {
1200- return errorfactory .New (errorfactory.APIFailure {}, err , "deleting resource failed" , "kind" , desiredType )
1201- }
1202- log .Info ("resource deleted" )
1203- err = k8sutil .DeleteVolumeStatus (r .Client , brokerId , mountPathToRemove , r .KafkaCluster , log )
1204- if err != nil {
1205- return errors .WrapIfWithDetails (err , "could not delete volume status for broker volume" , "brokerId" , brokerId , "mountPath" , mountPathToRemove )
1206- }
1207- case ccVolumeState .IsDiskRemoval ():
1208- log .Info ("Graceful disk removal is in progress" , "brokerId" , brokerId , "mountPath" , mountPathToRemove )
1209- waitForDiskRemovalToFinish = true
1210- case ccVolumeState .IsDiskRebalance ():
1211- log .Info ("Graceful disk rebalance is in progress, waiting to mark disk for removal" , "brokerId" , brokerId , "mountPath" , mountPathToRemove )
1212- waitForDiskRemovalToFinish = true
1213- default :
1214- brokerVolumesState [mountPathToRemove ] = v1beta1.VolumeState {CruiseControlVolumeState : v1beta1 .GracefulDiskRemovalRequired }
1215- log .Info ("Marked the volume for removal" , "brokerId" , brokerId , "mountPath" , mountPathToRemove )
1216- waitForDiskRemovalToFinish = true
1217- }
1218- }
1183+ // Handle disk removal
1184+ if len (pvcList .Items ) > len (desiredPvcs ) {
1185+ waitForDiskRemovalToFinish , err = handleDiskRemoval (ctx , pvcList , desiredPvcs , r , brokerId , log , desiredType , brokerVolumesState )
1186+ if err != nil {
1187+ return err
12191188 }
12201189 }
12211190
@@ -1314,6 +1283,63 @@ func (r *Reconciler) reconcileKafkaPvc(ctx context.Context, log logr.Logger, bro
13141283 return nil
13151284}
13161285
1286+ func handleDiskRemoval (ctx context.Context , pvcList * corev1.PersistentVolumeClaimList , desiredPvcs []* corev1.PersistentVolumeClaim ,
1287+ r * Reconciler , brokerId string , log logr.Logger , desiredType reflect.Type , brokerVolumesState map [string ]v1beta1.VolumeState ) (bool , error ) {
1288+ waitForDiskRemovalToFinish := false
1289+ for _ , pvc := range pvcList .Items {
1290+ foundInDesired := false
1291+ existingMountPath := pvc .Annotations ["mountPath" ]
1292+
1293+ for _ , desiredPvc := range desiredPvcs {
1294+ desiredMountPath := desiredPvc .Annotations ["mountPath" ]
1295+
1296+ if existingMountPath == desiredMountPath {
1297+ foundInDesired = true
1298+ break
1299+ }
1300+ }
1301+
1302+ if foundInDesired {
1303+ continue
1304+ }
1305+
1306+ mountPathToRemove := existingMountPath
1307+ if brokerState , ok := r .KafkaCluster .Status .BrokersState [brokerId ]; ok {
1308+ volumeStateStatus , found := brokerState .GracefulActionState .VolumeStates [mountPathToRemove ]
1309+ if ! found {
1310+ // If the state is not found, it means that the disk removal was done according to the disk removal succeeded branch
1311+ log .Info ("Disk removal was completed, waiting for Rolling Upgrade to remove PVC" , "brokerId" , brokerId , "mountPath" , mountPathToRemove )
1312+ continue
1313+ }
1314+
1315+ // Check the volume state
1316+ ccVolumeState := volumeStateStatus .CruiseControlVolumeState
1317+ switch {
1318+ case ccVolumeState .IsDiskRemovalSucceeded ():
1319+ if err := r .Client .Delete (ctx , & pvc ); err != nil {
1320+ return false , errorfactory .New (errorfactory.APIFailure {}, err , "deleting resource failed" , "kind" , desiredType )
1321+ }
1322+ log .Info ("resource deleted" )
1323+ err := k8sutil .DeleteVolumeStatus (r .Client , brokerId , mountPathToRemove , r .KafkaCluster , log )
1324+ if err != nil {
1325+ return false , errors .WrapIfWithDetails (err , "could not delete volume status for broker volume" , "brokerId" , brokerId , "mountPath" , mountPathToRemove )
1326+ }
1327+ case ccVolumeState .IsDiskRemoval ():
1328+ log .Info ("Graceful disk removal is in progress" , "brokerId" , brokerId , "mountPath" , mountPathToRemove )
1329+ waitForDiskRemovalToFinish = true
1330+ case ccVolumeState .IsDiskRebalance ():
1331+ log .Info ("Graceful disk rebalance is in progress, waiting to mark disk for removal" , "brokerId" , brokerId , "mountPath" , mountPathToRemove )
1332+ waitForDiskRemovalToFinish = true
1333+ default :
1334+ brokerVolumesState [mountPathToRemove ] = v1beta1.VolumeState {CruiseControlVolumeState : v1beta1 .GracefulDiskRemovalRequired }
1335+ log .Info ("Marked the volume for removal" , "brokerId" , brokerId , "mountPath" , mountPathToRemove )
1336+ waitForDiskRemovalToFinish = true
1337+ }
1338+ }
1339+ }
1340+ return waitForDiskRemovalToFinish , nil
1341+ }
1342+
13171343// GetBrokersWithPendingOrRunningCCTask returns list of brokers that are either waiting for CC
13181344// to start executing a broker task (add broker, remove broker, etc) or CC already running a task for it.
13191345func GetBrokersWithPendingOrRunningCCTask (kafkaCluster * v1beta1.KafkaCluster ) []int32 {
@@ -1732,3 +1758,16 @@ func generateServicePortForAdditionalPorts(containerPorts []corev1.ContainerPort
17321758 }
17331759 return usedPorts
17341760}
1761+
1762+ func (r * Reconciler ) isController (brokerId int32 ) (bool , error ) {
1763+ for _ , broker := range r .KafkaCluster .Spec .Brokers {
1764+ if broker .Id == brokerId {
1765+ brokerConfig , err := broker .GetBrokerConfig (r .KafkaCluster .Spec )
1766+ if err != nil {
1767+ return false , errors .WrapIf (err , "failed to reconcile resource" )
1768+ }
1769+ return brokerConfig .IsControllerNode (), nil
1770+ }
1771+ }
1772+ return false , errors .NewWithDetails ("could not find broker in the spec" , "brokerId" , brokerId )
1773+ }
0 commit comments