Skip to content

Commit 85c46e5

Browse files
committed
Delete next cell irrespective of last deletion
Right now when multiple cells gets deleted if any one the cell deletion fails, the control exits with error msg. This change stores the errors in a list and let next cells deleted. Adds a functional test Closes #OSPRH-10550
1 parent 92f1636 commit 85c46e5

File tree

3 files changed

+217
-4
lines changed

3 files changed

+217
-4
lines changed

controllers/nova_controller.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ package controllers
1818

1919
import (
2020
"context"
21+
"errors"
2122
"fmt"
23+
"sort"
2224
"strings"
2325

2426
batchv1 "k8s.io/api/batch/v1"
@@ -600,19 +602,35 @@ func (r *NovaReconciler) Reconcile(ctx context.Context, req ctrl.Request) (resul
600602
return ctrl.Result{}, err
601603
}
602604

605+
sortNovaCellListByName := func(cellList *novav1.NovaCellList) {
606+
sort.SliceStable(cellList.Items, func(i, j int) bool {
607+
return cellList.Items[i].Name < cellList.Items[j].Name
608+
})
609+
}
610+
611+
sortNovaCellListByName(novaCellList)
612+
613+
var deleteErrs []error
614+
603615
for _, cr := range novaCellList.Items {
604616
_, ok := instance.Spec.CellTemplates[cr.Spec.CellName]
605617
if !ok {
606618
err := r.ensureCellDeleted(ctx, h, instance,
607619
cr.Spec.CellName, apiTransportURL,
608620
secret, apiDB, cellDBs[novav1.Cell0Name].Database.GetDatabaseHostname(), cells[novav1.Cell0Name])
609621
if err != nil {
610-
return ctrl.Result{}, err
622+
deleteErrs = append(deleteErrs, fmt.Errorf("Cell '%s' deletion failed, because: %w", cr.Spec.CellName, err))
623+
624+
} else {
625+
Log.Info("Cell deleted", "cell", cr.Spec.CellName)
626+
delete(instance.Status.RegisteredCells, cr.Name)
611627
}
612-
Log.Info("Cell deleted", "cell", cr.Spec.CellName)
613-
delete(instance.Status.RegisteredCells, cr.Name)
614628
}
629+
}
615630

631+
if len(deleteErrs) > 0 {
632+
delErrs := errors.Join(deleteErrs...)
633+
return ctrl.Result{}, delErrs
616634
}
617635

618636
Log.Info("Successfully reconciled")

test/functional/nova_multicell_test.go

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -960,3 +960,196 @@ var _ = Describe("Nova multi cell", func() {
960960
})
961961
})
962962
})
963+
964+
func CreateNovaWith4CellsAndEnsureReady(novaNames NovaNames) {
965+
cell0 := novaNames.Cells["cell0"]
966+
cell1 := novaNames.Cells["cell1"]
967+
cell2 := novaNames.Cells["cell2"]
968+
cell3 := novaNames.Cells["cell3"]
969+
970+
DeferCleanup(k8sClient.Delete, ctx, CreateNovaSecret(novaNames.NovaName.Namespace, SecretName))
971+
DeferCleanup(k8sClient.Delete, ctx, CreateNovaMessageBusSecret(cell0))
972+
DeferCleanup(k8sClient.Delete, ctx, CreateNovaMessageBusSecret(cell1))
973+
DeferCleanup(k8sClient.Delete, ctx, CreateNovaMessageBusSecret(cell2))
974+
DeferCleanup(k8sClient.Delete, ctx, CreateNovaMessageBusSecret(cell3))
975+
976+
serviceSpec := corev1.ServiceSpec{Ports: []corev1.ServicePort{{Port: 3306}}}
977+
DeferCleanup(
978+
mariadb.DeleteDBService,
979+
mariadb.CreateDBService(novaNames.APIMariaDBDatabaseName.Namespace, novaNames.APIMariaDBDatabaseName.Name, serviceSpec))
980+
DeferCleanup(mariadb.DeleteDBService, mariadb.CreateDBService(cell0.MariaDBDatabaseName.Namespace, cell0.MariaDBDatabaseName.Name, serviceSpec))
981+
DeferCleanup(mariadb.DeleteDBService, mariadb.CreateDBService(cell1.MariaDBDatabaseName.Namespace, cell1.MariaDBDatabaseName.Name, serviceSpec))
982+
DeferCleanup(mariadb.DeleteDBService, mariadb.CreateDBService(cell2.MariaDBDatabaseName.Namespace, cell2.MariaDBDatabaseName.Name, serviceSpec))
983+
DeferCleanup(mariadb.DeleteDBService, mariadb.CreateDBService(cell3.MariaDBDatabaseName.Namespace, cell3.MariaDBDatabaseName.Name, serviceSpec))
984+
985+
apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccountAndSecret(
986+
novaNames.APIMariaDBDatabaseAccount, mariadbv1.MariaDBAccountSpec{})
987+
DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount)
988+
DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret)
989+
990+
cell0Account, cell0Secret := mariadb.CreateMariaDBAccountAndSecret(
991+
cell0.MariaDBAccountName, mariadbv1.MariaDBAccountSpec{})
992+
DeferCleanup(k8sClient.Delete, ctx, cell0Account)
993+
DeferCleanup(k8sClient.Delete, ctx, cell0Secret)
994+
995+
cell1Account, cell1Secret := mariadb.CreateMariaDBAccountAndSecret(
996+
cell1.MariaDBAccountName, mariadbv1.MariaDBAccountSpec{})
997+
DeferCleanup(th.DeleteInstance, cell1Account)
998+
DeferCleanup(
999+
th.DeleteSecret,
1000+
types.NamespacedName{Name: cell1Secret.Name, Namespace: cell1Secret.Namespace})
1001+
1002+
cell2Account, cell2Secret := mariadb.CreateMariaDBAccountAndSecret(
1003+
cell2.MariaDBAccountName, mariadbv1.MariaDBAccountSpec{})
1004+
// DeferCleanup(k8sClient.Delete, ctx, cell2Account)
1005+
// DeferCleanup(k8sClient.Delete, ctx, cell2Secret)
1006+
logger.Info("Not Creating defercleanup for cell2 ...", " -- ", cell2Secret)
1007+
1008+
cell3Account, cell3Secret := mariadb.CreateMariaDBAccountAndSecret(
1009+
cell3.MariaDBAccountName, mariadbv1.MariaDBAccountSpec{})
1010+
// DeferCleanup(k8sClient.Delete, ctx, cell3Account)
1011+
// DeferCleanup(k8sClient.Delete, ctx, cell3Secret)
1012+
logger.Info("Not Creating defercleanup for cell3 ...", " -- ", cell3Secret)
1013+
1014+
spec := GetDefaultNovaSpec()
1015+
cell0Template := GetDefaultNovaCellTemplate()
1016+
cell0Template["cellDatabaseInstance"] = cell0.MariaDBDatabaseName.Name
1017+
cell0Template["cellDatabaseAccount"] = cell0Account.Name
1018+
1019+
cell1Template := GetDefaultNovaCellTemplate()
1020+
cell1Template["cellDatabaseInstance"] = cell1.MariaDBDatabaseName.Name
1021+
cell1Template["cellDatabaseAccount"] = cell1Account.Name
1022+
cell1Template["cellMessageBusInstance"] = cell1.TransportURLName.Name
1023+
cell1Template["novaComputeTemplates"] = map[string]interface{}{
1024+
ironicComputeName: GetDefaultNovaComputeTemplate(),
1025+
}
1026+
1027+
cell2Template := GetDefaultNovaCellTemplate()
1028+
cell2Template["cellDatabaseInstance"] = cell2.MariaDBDatabaseName.Name
1029+
cell2Template["cellDatabaseAccount"] = cell2Account.Name
1030+
cell2Template["cellMessageBusInstance"] = cell2.TransportURLName.Name
1031+
cell2Template["hasAPIAccess"] = false
1032+
1033+
cell3Template := GetDefaultNovaCellTemplate()
1034+
cell3Template["cellDatabaseInstance"] = cell3.MariaDBDatabaseName.Name
1035+
cell3Template["cellDatabaseAccount"] = cell3Account.Name
1036+
cell3Template["cellMessageBusInstance"] = cell3.TransportURLName.Name
1037+
cell3Template["hasAPIAccess"] = false
1038+
1039+
spec["cellTemplates"] = map[string]interface{}{
1040+
"cell0": cell0Template,
1041+
"cell1": cell1Template,
1042+
"cell2": cell2Template,
1043+
"cell3": cell3Template,
1044+
}
1045+
spec["apiDatabaseInstance"] = novaNames.APIMariaDBDatabaseName.Name
1046+
spec["apiMessageBusInstance"] = cell0.TransportURLName.Name
1047+
1048+
DeferCleanup(th.DeleteInstance, CreateNova(novaNames.NovaName, spec))
1049+
DeferCleanup(keystone.DeleteKeystoneAPI, keystone.CreateKeystoneAPI(novaNames.NovaName.Namespace))
1050+
memcachedSpec := memcachedv1.MemcachedSpec{
1051+
MemcachedSpecCore: memcachedv1.MemcachedSpecCore{
1052+
Replicas: ptr.To(int32(3)),
1053+
},
1054+
}
1055+
1056+
DeferCleanup(infra.DeleteMemcached, infra.CreateMemcached(novaNames.NovaName.Namespace, MemcachedInstance, memcachedSpec))
1057+
infra.SimulateMemcachedReady(novaNames.MemcachedNamespace)
1058+
keystone.SimulateKeystoneServiceReady(novaNames.KeystoneServiceName)
1059+
// END of common logic with Nova multi cell test
1060+
1061+
mariadb.SimulateMariaDBDatabaseCompleted(novaNames.APIMariaDBDatabaseName)
1062+
mariadb.SimulateMariaDBDatabaseCompleted(cell0.MariaDBDatabaseName)
1063+
mariadb.SimulateMariaDBDatabaseCompleted(cell1.MariaDBDatabaseName)
1064+
mariadb.SimulateMariaDBDatabaseCompleted(cell2.MariaDBDatabaseName)
1065+
mariadb.SimulateMariaDBDatabaseCompleted(cell3.MariaDBDatabaseName)
1066+
1067+
mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseAccount)
1068+
mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBAccountName)
1069+
mariadb.SimulateMariaDBAccountCompleted(cell1.MariaDBAccountName)
1070+
mariadb.SimulateMariaDBAccountCompleted(cell2.MariaDBAccountName)
1071+
mariadb.SimulateMariaDBAccountCompleted(cell3.MariaDBAccountName)
1072+
1073+
infra.SimulateTransportURLReady(cell0.TransportURLName)
1074+
infra.SimulateTransportURLReady(cell1.TransportURLName)
1075+
infra.SimulateTransportURLReady(cell2.TransportURLName)
1076+
infra.SimulateTransportURLReady(cell3.TransportURLName)
1077+
1078+
th.SimulateJobSuccess(cell0.DBSyncJobName)
1079+
th.SimulateStatefulSetReplicaReady(cell0.ConductorStatefulSetName)
1080+
th.SimulateJobSuccess(cell0.CellMappingJobName)
1081+
1082+
th.SimulateStatefulSetReplicaReady(cell1.NoVNCProxyStatefulSetName)
1083+
th.SimulateJobSuccess(cell1.DBSyncJobName)
1084+
th.SimulateStatefulSetReplicaReady(cell1.ConductorStatefulSetName)
1085+
th.SimulateStatefulSetReplicaReady(cell1.NovaComputeStatefulSetName)
1086+
th.SimulateJobSuccess(cell1.CellMappingJobName)
1087+
th.SimulateJobSuccess(cell1.HostDiscoveryJobName)
1088+
1089+
th.SimulateStatefulSetReplicaReady(cell2.NoVNCProxyStatefulSetName)
1090+
th.SimulateJobSuccess(cell2.DBSyncJobName)
1091+
th.SimulateStatefulSetReplicaReady(cell2.ConductorStatefulSetName)
1092+
th.SimulateJobSuccess(cell2.CellMappingJobName)
1093+
1094+
th.SimulateStatefulSetReplicaReady(cell3.NoVNCProxyStatefulSetName)
1095+
th.SimulateJobSuccess(cell3.DBSyncJobName)
1096+
th.SimulateStatefulSetReplicaReady(cell3.ConductorStatefulSetName)
1097+
th.SimulateJobSuccess(cell3.CellMappingJobName)
1098+
1099+
th.ExpectCondition(
1100+
novaNames.NovaName,
1101+
ConditionGetterFunc(NovaConditionGetter),
1102+
novav1.NovaAllCellsReadyCondition,
1103+
corev1.ConditionTrue,
1104+
)
1105+
SimulateReadyOfNovaTopServices()
1106+
th.ExpectCondition(
1107+
novaNames.NovaName,
1108+
ConditionGetterFunc(NovaConditionGetter),
1109+
condition.ReadyCondition,
1110+
corev1.ConditionTrue,
1111+
)
1112+
}
1113+
1114+
var _ = Describe("Nova multi cell deletion", func() {
1115+
BeforeEach(func() {
1116+
1117+
CreateNovaWith4CellsAndEnsureReady(novaNames)
1118+
1119+
})
1120+
1121+
When("Nova CR instance is created with 4 cells", func() {
1122+
It("delete cell2 and cell3, verify for cell2", func() {
1123+
1124+
nova := GetNova(novaNames.NovaName)
1125+
Expect(nova.Status.RegisteredCells).To(HaveKey(cell0.CellCRName.Name), "cell0 is not in the RegisteredCells", nova.Status.RegisteredCells)
1126+
Expect(nova.Status.RegisteredCells).To(HaveKey(cell1.CellCRName.Name), "cell1 is not in the RegisteredCells", nova.Status.RegisteredCells)
1127+
Expect(nova.Status.RegisteredCells).To(HaveKey(cell2.CellCRName.Name), "cell2 is not in the RegisteredCells", nova.Status.RegisteredCells)
1128+
Expect(nova.Status.RegisteredCells).To(HaveKey(cell3.CellCRName.Name), "cell3 is not in the RegisteredCells", nova.Status.RegisteredCells)
1129+
1130+
cell2Account := mariadb.GetMariaDBAccount(cell2.MariaDBAccountName)
1131+
cell2Account.Spec.Secret = ""
1132+
Expect(k8sClient.Update(ctx, cell2Account)).To(Succeed())
1133+
1134+
Eventually(func(g Gomega) {
1135+
// remove from cells CR
1136+
nova := GetNova(novaNames.NovaName)
1137+
delete(nova.Spec.CellTemplates, "cell2")
1138+
delete(nova.Spec.CellTemplates, "cell3")
1139+
g.Expect(k8sClient.Update(ctx, nova)).To(Succeed())
1140+
}, timeout, interval).Should(Succeed())
1141+
1142+
Eventually(func(g Gomega) {
1143+
nova := GetNova(novaNames.NovaName)
1144+
g.Expect(nova.Status.RegisteredCells).To(HaveKey(cell2.CellCRName.Name))
1145+
g.Expect(nova.Status.RegisteredCells).NotTo(HaveKey(cell3.CellCRName.Name))
1146+
}, timeout, interval).Should(Succeed())
1147+
1148+
GetNovaCell(cell2.CellCRName)
1149+
NovaCellNotExists(cell3.CellCRName)
1150+
1151+
})
1152+
1153+
})
1154+
1155+
})

test/functional/suite_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ var (
8484
cell0 CellNames
8585
cell1 CellNames
8686
cell2 CellNames
87+
cell3 CellNames
8788
)
8889

8990
func TestAPIs(t *testing.T) {
@@ -283,8 +284,9 @@ var _ = BeforeEach(func() {
283284
Name: uuid.New().String()[:25],
284285
}
285286

286-
novaNames = GetNovaNames(novaName, []string{"cell0", "cell1", "cell2"})
287+
novaNames = GetNovaNames(novaName, []string{"cell0", "cell1", "cell2", "cell3"})
287288
cell0 = novaNames.Cells["cell0"]
288289
cell1 = novaNames.Cells["cell1"]
289290
cell2 = novaNames.Cells["cell2"]
291+
cell3 = novaNames.Cells["cell3"]
290292
})

0 commit comments

Comments
 (0)