Skip to content

Commit 917b086

Browse files
authored
Merge pull request #10 from cybertec-postgresql/fix/ctl-site-switchover
Fix patronictl site-switchover behaviour
2 parents e010dc9 + 7de3c7e commit 917b086

File tree

2 files changed

+24
-21
lines changed

2 files changed

+24
-21
lines changed

patroni/ctl.py

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ def is_citus_cluster() -> bool:
367367

368368

369369
# Cache DCS instances for given scope and group
370-
__dcs_cache: Dict[Tuple[str, Optional[int]], AbstractDCS] = {}
370+
__dcs_cache: Dict[Tuple[str, Optional[int], Optional[bool]], AbstractDCS] = {}
371371

372372

373373
def get_dcs(scope: str, group: Optional[int], multisite: Optional[bool] = False) -> AbstractDCS:
@@ -383,10 +383,14 @@ def get_dcs(scope: str, group: Optional[int], multisite: Optional[bool] = False)
383383
:raises:
384384
:class:`PatroniCtlException`: if not suitable DCS configuration could be found.
385385
"""
386-
if (scope, group) in __dcs_cache:
387-
return __dcs_cache[(scope, group)]
386+
if (scope, group, multisite) in __dcs_cache:
387+
return __dcs_cache[(scope, group, multisite)]
388388

389389
config = _get_configuration()
390+
391+
if multisite:
392+
config = config['multisite']
393+
390394
config.update({'scope': scope, 'patronictl': True})
391395
if group is not None:
392396
config['citus'] = {'group': group, 'database': 'postgres'}
@@ -402,7 +406,7 @@ def get_dcs(scope: str, group: Optional[int], multisite: Optional[bool] = False)
402406
if is_citus_cluster() and group is None:
403407
dcs.is_mpp_coordinator = lambda: True
404408
click.get_current_context().obj['__mpp'] = dcs.mpp
405-
__dcs_cache[(scope, group)] = dcs
409+
__dcs_cache[(scope, group, multisite)] = dcs
406410
return dcs
407411
except PatroniException as e:
408412
raise PatroniCtlException(str(e))
@@ -1461,11 +1465,6 @@ def _do_site_switchover(cluster_name: str, group: Optional[int],
14611465

14621466
config = global_config.from_cluster(cluster)
14631467

1464-
cluster_leader = cluster.leader and cluster.leader.name
1465-
1466-
if not cluster_leader:
1467-
raise PatroniCtlException('This cluster has no leader')
1468-
14691468
if cluster.leader and cluster.leader.multisite:
14701469
leader_site = (cluster.leader.multisite.get('name') if not cluster.leader.multisite.get('standby_config') else
14711470
cluster.leader.multisite.get('standby_config', {}).get('leader_site'))
@@ -1482,23 +1481,26 @@ def _do_site_switchover(cluster_name: str, group: Optional[int],
14821481
if leader_site != switchover_leader:
14831482
raise PatroniCtlException(f'Site {switchover_leader} is not the leader of cluster {cluster_name}')
14841483

1485-
# multisite_dcs = get_dcs(cluster_name, group, True)
1486-
# multisite_cluster = multisite_dcs.get_cluster()
1484+
ms_dcs = get_dcs(cluster_name, group, True)
1485+
ms_cluster = ms_dcs.get_cluster()
1486+
1487+
candidate_names = [str(m.name) for m in ms_cluster.members
1488+
if m.name != leader_site]
14871489

1488-
candidate_names = [str(m.multisite['name']) for m in cluster.members
1489-
if m.multisite and m.multisite['name'] != leader_site]
14901490
# We sort the names for consistent output to the client
14911491
candidate_names.sort()
14921492

1493-
# TODO: once there is a reliable way for getting the candidate sites when on the leader site, turn this back on
1494-
# if not candidate_names:
1495-
# raise PatroniCtlException('No candidates found to switch over to')
1493+
if not candidate_names:
1494+
raise PatroniCtlException('No candidates found to switch over to')
14961495

14971496
if candidate is None and not force:
1498-
candidate = click.prompt('Candidate ' + str(candidate_names), type=str, default='')
1497+
if len(candidate_names) == 1:
1498+
candidate = click.prompt('Candidate ', type=str, default=candidate_names[0])
1499+
else:
1500+
candidate = click.prompt('Candidate ' + str(candidate_names), type=str, default='')
14991501

15001502
if candidate and candidate not in candidate_names:
1501-
if candidate == cluster_leader:
1503+
if candidate == leader_site:
15021504
raise PatroniCtlException(
15031505
f'Site {candidate} is already the leader of cluster {cluster_name}')
15041506
raise PatroniCtlException(
@@ -1518,7 +1520,7 @@ def _do_site_switchover(cluster_name: str, group: Optional[int],
15181520
raise PatroniCtlException("Can't schedule switchover in the paused state")
15191521
scheduled_at_str = scheduled_at.isoformat()
15201522

1521-
switchover_value = {'candidate': candidate}
1523+
switchover_value = {'target_site': candidate}
15221524

15231525
if scheduled_at_str:
15241526
switchover_value['scheduled_at'] = scheduled_at_str
@@ -1527,7 +1529,7 @@ def _do_site_switchover(cluster_name: str, group: Optional[int],
15271529

15281530
# By now we have established that the leader site exists and the candidate also exists
15291531
if not force:
1530-
demote_msg = f' to another site, demoting current site {cluster_leader}' if cluster_leader else ''
1532+
demote_msg = f' to another site, demoting current site {leader_site}' if leader_site else ''
15311533
if scheduled_at_str:
15321534
if not click.confirm(f'Are you sure you want to schedule switchover of cluster '
15331535
f'{cluster_name} at {scheduled_at_str}{demote_msg}?'):

patroni/ha.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1628,7 +1628,8 @@ def before_shutdown() -> None:
16281628
self.release_leader_key_voluntarily(checkpoint_location)
16291629
time.sleep(2) # Give a time to somebody to take the leader lock
16301630
if mode == 'multisite':
1631-
self.patroni.multisite.on_shutdown(self.state_handler.latest_checkpoint_location(), None)
1631+
self.patroni.multisite.on_shutdown(
1632+
self.state_handler.latest_checkpoint_location(), None) # pyright: ignore [reportArgumentType]
16321633
if mode_control['offline']:
16331634
node_to_follow, leader = None, None
16341635
else:

0 commit comments

Comments
 (0)