Merge pull request #14692 from rook/mergify/bp/release-1.15/pr-14667

mon: Remove extra mon from quorum before taking down pod (backport #14667)
This commit is contained in:
mergify[bot] authored and GitHub committed 2024-09-05 17:40:32 +00:00
commit 917bb0160e
3 files changed
+108 -26

No files matched your search

+31 -25
View File
@@ -730,20 +730,6 @@ func (c *Cluster) removeMonWithOptionalQuorum(daemonName string, shouldRemoveFro
}
logger.Infof("ensuring removal of unhealthy monitor %s", daemonName)
resourceName := resourceName(daemonName)
// Remove the mon pod if it is still there
var gracePeriod int64
propagation := metav1.DeletePropagationForeground
options := &metav1.DeleteOptions{GracePeriodSeconds: &gracePeriod, PropagationPolicy: &propagation}
if err := c.context.Clientset.AppsV1().Deployments(c.Namespace).Delete(c.ClusterInfo.Context, resourceName, *options); err != nil {
if kerrors.IsNotFound(err) {
logger.Infof("dead mon %s was already gone", resourceName)
} else {
logger.Errorf("failed to remove dead mon deployment %q. %v", resourceName, err)
}
}
// Remove the bad monitor from quorum
if shouldRemoveFromQuorum {
if err := c.removeMonitorFromQuorum(daemonName); err != nil {
@@ -751,10 +737,33 @@ func (c *Cluster) removeMonWithOptionalQuorum(daemonName string, shouldRemoveFro
}
}
delete(c.ClusterInfo.Monitors, daemonName)
delete(c.mapping.Schedule, daemonName)
if err := c.saveMonConfig(); err != nil {
return errors.Wrapf(err, "failed to save mon config after failing over mon %s", daemonName)
}
// Update cluster-wide RBD bootstrap peer token since Monitors have changed
_, err := controller.CreateBootstrapPeerSecret(c.context, c.ClusterInfo, &cephv1.CephCluster{ObjectMeta: metav1.ObjectMeta{Name: c.ClusterInfo.NamespacedName().Name, Namespace: c.Namespace}}, c.ownerInfo)
if err != nil {
return errors.Wrap(err, "failed to update cluster rbd bootstrap peer token")
}
// When the mon is removed from quorum, it is possible that the operator will be restarted
// before the mon pod is deleted. In this case, the operator will need to delete the mon
// during the next reconcile. If the reconcile finds an extra mon pod, it will be removed
// at that later reconcile. Thus, we delete the mon pod last during the failover
// and in case the failover is interrupted, the operator can detect the resources to finish the cleanup.
c.removeMonResources(daemonName)
return nil
}
func (c *Cluster) removeMonResources(daemonName string) {
// Remove the service endpoint
resourceName := resourceName(daemonName)
var gracePeriod int64
propagation := metav1.DeletePropagationForeground
options := &metav1.DeleteOptions{GracePeriodSeconds: &gracePeriod, PropagationPolicy: &propagation}
if err := c.context.Clientset.CoreV1().Services(c.Namespace).Delete(c.ClusterInfo.Context, resourceName, *options); err != nil {
if kerrors.IsNotFound(err) {
logger.Infof("dead mon service %s was already gone", resourceName)
@@ -772,17 +781,14 @@ func (c *Cluster) removeMonWithOptionalQuorum(daemonName string, shouldRemoveFro
}
}
if err := c.saveMonConfig(); err != nil {
return errors.Wrapf(err, "failed to save mon config after failing over mon %s", daemonName)
// Remove the mon pod if it is still there
if err := c.context.Clientset.AppsV1().Deployments(c.Namespace).Delete(c.ClusterInfo.Context, resourceName, *options); err != nil {
if kerrors.IsNotFound(err) {
logger.Infof("dead mon %s was already gone", resourceName)
} else {
logger.Errorf("failed to remove dead mon deployment %q. %v", resourceName, err)
}
}
// Update cluster-wide RBD bootstrap peer token since Monitors have changed
_, err := controller.CreateBootstrapPeerSecret(c.context, c.ClusterInfo, &cephv1.CephCluster{ObjectMeta: metav1.ObjectMeta{Name: c.ClusterInfo.NamespacedName().Name, Namespace: c.Namespace}}, c.ownerInfo)
if err != nil {
return errors.Wrap(err, "failed to update cluster rbd bootstrap peer token")
}
return nil
}
func (c *Cluster) removeMonitorFromQuorum(name string) error {
+33 -1
View File
@@ -1060,7 +1060,39 @@ func (c *Cluster) startDeployments(mons []*monConfig, requireAllInQuorum bool) e
requireAllInQuorum = true
}
}
return c.waitForMonsToJoin(mons, requireAllInQuorum)
err = c.waitForMonsToJoin(mons, requireAllInQuorum)
// Check for the rare case of an extra mon deployment that needs to be cleaned up
c.checkForExtraMonResources(mons, deployments.Items)
return err
}
func (c *Cluster) checkForExtraMonResources(mons []*monConfig, deployments []apps.Deployment) string {
if len(deployments) <= c.spec.Mon.Count || len(deployments) <= len(mons) {
return ""
}
// If there are more deployments than expected mons from the ceph quorum,
// find the extra mon deployment and clean it up.
logger.Infof("there is an extra mon deployment that is not needed and not in quorum")
for _, deploy := range deployments {
monName := deploy.Labels[controller.DaemonIDLabel]
found := false
// Search for the mon in the list of mons expected in quorum
for _, monDaemon := range mons {
if monName == monDaemon.DaemonName {
found = true
break
}
}
if !found {
logger.Infof("deleting extra mon deployment %q", deploy.Name)
c.removeMonResources(monName)
return monName
}
}
return ""
}
func (c *Cluster) waitForMonsToJoin(mons []*monConfig, requireAllInQuorum bool) error {
+44
View File
@@ -676,6 +676,50 @@ func TestMonVolumeClaimTemplate(t *testing.T) {
})
}
}
func TestRemoveExtraMonDeployments(t *testing.T) {
namespace := "ns"
context, err := newTestStartCluster(t, namespace)
assert.NoError(t, err)
c := newCluster(context, namespace, true, v1.ResourceRequirements{})
c.ClusterInfo = clienttest.CreateTestClusterInfo(1)
// Nothing to remove when the mons match the deployment
mons := []*monConfig{
{ResourceName: "rook-ceph-mon-a", DaemonName: "a"},
}
deployments := []apps.Deployment{
{
ObjectMeta: metav1.ObjectMeta{
Name: "rook-ceph-mon-a",
Labels: map[string]string{"ceph_daemon_id": "a"},
},
},
}
c.spec.Mon.Count = 1
removed := c.checkForExtraMonResources(mons, deployments)
assert.Equal(t, "", removed)
// Remove an extra mon deployment
deployments = append(deployments, apps.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "rook-ceph-mon-b",
Labels: map[string]string{"ceph_daemon_id": "b"},
}})
removed = c.checkForExtraMonResources(mons, deployments)
assert.Equal(t, "b", removed)
// Nothing to remove when there are not enough deployments for the expected mons
mons = []*monConfig{
{ResourceName: "rook-ceph-mon-a", DaemonName: "a"},
{ResourceName: "rook-ceph-mon-b", DaemonName: "b"},
{ResourceName: "rook-ceph-mon-c", DaemonName: "c"},
}
c.spec.Mon.Count = 3
removed = c.checkForExtraMonResources(mons, deployments)
assert.Equal(t, "", removed)
}
func TestStretchMonVolumeClaimTemplate(t *testing.T) {
generalSC := "generalSC"
zoneSC := "zoneSC"