mirror of
https://github.com/outbackdingo/patroni.git
synced 2026-08-26 15:40:21 +00:00
More improvements in patronictl (#590)
Make specifying cluster_name optional for some more commands. If it is not specified, it's value would be taken from config file.
This commit is contained in:
+18
-17
@@ -101,6 +101,8 @@ option_format = click.option('--format', '-f', 'fmt', help='Output format (prett
|
||||
option_watchrefresh = click.option('-w', '--watch', type=float, help='Auto update the screen every X seconds')
|
||||
option_watch = click.option('-W', is_flag=True, help='Auto update the screen every 2 seconds')
|
||||
option_force = click.option('--force', is_flag=True, help='Do not ask for confirmation at any point')
|
||||
arg_cluster_name = click.argument('cluster_name', required=False,
|
||||
default=lambda: click.get_current_context().obj.get('scope'))
|
||||
|
||||
|
||||
@click.group()
|
||||
@@ -150,12 +152,12 @@ def print_output(columns, rows=None, alignment=None, fmt='pretty', header=True,
|
||||
click.echo(t)
|
||||
return
|
||||
|
||||
if fmt in ['json', 'yaml']:
|
||||
if fmt in ['json', 'yaml', 'yml']:
|
||||
elements = [dict(zip(columns, r)) for r in rows]
|
||||
if fmt == 'json':
|
||||
click.echo(json.dumps(elements))
|
||||
elif fmt == 'yaml':
|
||||
click.echo(yaml.safe_dump(elements, encoding=None, allow_unicode=True, width=200))
|
||||
elif fmt in ('yaml', 'yml'):
|
||||
click.echo(yaml.safe_dump(elements, encoding=None, default_flow_style=False, allow_unicode=True, width=200))
|
||||
|
||||
if fmt == 'tsv':
|
||||
if columns is not None and header:
|
||||
@@ -277,7 +279,7 @@ def get_members(cluster, cluster_name, member_names, role, force, action):
|
||||
@click.option('--role', '-r', help='Give a dsn of any member with this role', type=click.Choice(['master', 'replica',
|
||||
'any']), default=None)
|
||||
@click.option('--member', '-m', help='Generate a dsn for this member', type=str)
|
||||
@click.argument('cluster_name')
|
||||
@arg_cluster_name
|
||||
@click.pass_obj
|
||||
def dsn(obj, cluster_name, role, member):
|
||||
if role is not None and member is not None:
|
||||
@@ -295,7 +297,7 @@ def dsn(obj, cluster_name, role, member):
|
||||
|
||||
|
||||
@ctl.command('query', help='Query a Patroni PostgreSQL member')
|
||||
@click.argument('cluster_name')
|
||||
@arg_cluster_name
|
||||
@option_format
|
||||
@click.option('--format', 'fmt', help='Output format (pretty, json)', default='tsv')
|
||||
@click.option('--file', '-f', 'p_file', help='Execute the SQL commands from this file', type=click.File('rb'))
|
||||
@@ -534,7 +536,7 @@ def reinit(obj, cluster_name, member_names, force):
|
||||
|
||||
|
||||
@ctl.command('failover', help='Failover to a replica')
|
||||
@click.argument('cluster_name')
|
||||
@arg_cluster_name
|
||||
@click.option('--master', help='The name of the current master', default=None)
|
||||
@click.option('--candidate', help='The name of the candidate', default=None)
|
||||
@click.option('--scheduled', help='Timestamp of a scheduled failover in unambiguous format (e.g. ISO 8601)',
|
||||
@@ -702,25 +704,24 @@ def output_members(cluster, name, extended=False, fmt='pretty'):
|
||||
@ctl.command('list', help='List the Patroni members for a given Patroni')
|
||||
@click.argument('cluster_names', nargs=-1)
|
||||
@click.option('--extended', '-e', help='Show some extra information', is_flag=True)
|
||||
@click.option('--timestamp', '-t', help='Print timestamp', is_flag=True)
|
||||
@click.option('--timestamp', '-t', 'ts', help='Print timestamp', is_flag=True)
|
||||
@option_format
|
||||
@option_watch
|
||||
@option_watchrefresh
|
||||
@click.pass_obj
|
||||
def members(obj, cluster_names, fmt, watch, w, extended, timestamp):
|
||||
def members(obj, cluster_names, fmt, watch, w, extended, ts):
|
||||
if not cluster_names:
|
||||
if 'scope' not in obj:
|
||||
logging.warning('Listing members: No cluster names were provided')
|
||||
return
|
||||
else:
|
||||
if 'scope' in obj:
|
||||
cluster_names = [obj['scope']]
|
||||
if not cluster_names:
|
||||
return logging.warning('Listing members: No cluster names were provided')
|
||||
|
||||
for cluster_name in cluster_names:
|
||||
dcs = get_dcs(obj, cluster_name)
|
||||
|
||||
for _ in watching(w, watch):
|
||||
if timestamp:
|
||||
click.echo(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
|
||||
if ts:
|
||||
click.echo(timestamp(0))
|
||||
|
||||
cluster = dcs.get_cluster()
|
||||
output_members(cluster, cluster_name, extended, fmt)
|
||||
@@ -842,14 +843,14 @@ def toggle_pause(config, cluster_name, paused):
|
||||
|
||||
|
||||
@ctl.command('pause', help='Disable auto failover')
|
||||
@click.argument('cluster_name')
|
||||
@arg_cluster_name
|
||||
@click.pass_obj
|
||||
def pause(obj, cluster_name):
|
||||
return toggle_pause(obj, cluster_name, True)
|
||||
|
||||
|
||||
@ctl.command('resume', help='Resume auto failover')
|
||||
@click.argument('cluster_name')
|
||||
@arg_cluster_name
|
||||
@click.pass_obj
|
||||
def resume(obj, cluster_name):
|
||||
return toggle_pause(obj, cluster_name, False)
|
||||
@@ -994,7 +995,7 @@ def invoke_editor(before_editing, cluster_name):
|
||||
|
||||
|
||||
@ctl.command('edit-config', help="Edit cluster configuration")
|
||||
@click.argument('cluster_name')
|
||||
@arg_cluster_name
|
||||
@click.option('--quiet', '-q', is_flag=True, help='Do not show changes')
|
||||
@click.option('--set', '-s', 'kvpairs', multiple=True,
|
||||
help='Set specific configuration value. Can be specified multiple times')
|
||||
|
||||
+5
-3
@@ -7,7 +7,7 @@ import unittest
|
||||
from click.testing import CliRunner
|
||||
from datetime import datetime, timedelta
|
||||
from mock import patch, Mock
|
||||
from patroni.ctl import ctl, members, store_config, load_config, output_members, request_patroni, get_dcs, parse_dcs, \
|
||||
from patroni.ctl import ctl, store_config, load_config, output_members, request_patroni, get_dcs, parse_dcs, \
|
||||
get_all_members, get_any_member, get_cursor, query_member, configure, PatroniCtlException, apply_config_changes, \
|
||||
format_config_for_editing, show_diff, invoke_editor, format_pg_version
|
||||
from patroni.dcs.etcd import Client, Failover
|
||||
@@ -33,7 +33,7 @@ def test_rw_config():
|
||||
|
||||
|
||||
@patch('patroni.ctl.load_config',
|
||||
Mock(return_value={'postgresql': {'data_dir': '.', 'parameters': {}, 'retry_timeout': 5},
|
||||
Mock(return_value={'scope': 'alpha', 'postgresql': {'data_dir': '.', 'parameters': {}, 'retry_timeout': 5},
|
||||
'restapi': {'auth': 'u:p', 'listen': ''}, 'etcd': {'host': 'localhost:2379'}}))
|
||||
class TestCtl(unittest.TestCase):
|
||||
|
||||
@@ -346,9 +346,11 @@ class TestCtl(unittest.TestCase):
|
||||
@patch('patroni.ctl.get_dcs')
|
||||
def test_members(self, mock_get_dcs):
|
||||
mock_get_dcs.return_value.get_cluster = get_cluster_initialized_with_leader
|
||||
result = self.runner.invoke(members, ['alpha'])
|
||||
result = self.runner.invoke(ctl, ['list'])
|
||||
assert '127.0.0.1' in result.output
|
||||
assert result.exit_code == 0
|
||||
with patch('patroni.ctl.load_config', Mock(return_value={})):
|
||||
self.runner.invoke(ctl, ['list'])
|
||||
|
||||
def test_configure(self):
|
||||
result = self.runner.invoke(configure, ['--dcs', 'abc', '-c', 'dummy', '-n', 'bla'])
|
||||
|
||||
@@ -861,6 +861,7 @@ class TestHa(unittest.TestCase):
|
||||
|
||||
def test_shutdown(self):
|
||||
self.p.is_running = false
|
||||
self.ha.has_lock = true
|
||||
self.ha.shutdown()
|
||||
|
||||
@patch('time.sleep', Mock())
|
||||
|
||||
Reference in New Issue
Block a user