mirror of
https://github.com/outbackdingo/patroni.git
synced 2026-08-25 14:53:37 +00:00
Call initdb directly (#2633)
Previously it was called via `pg_ctl`, what required a special quoting of parameters passed to `initdb`. Co-authored-by: Israel <[email protected]>
This commit is contained in:
@@ -3,10 +3,11 @@ import os
|
||||
import shlex
|
||||
import tempfile
|
||||
import time
|
||||
from typing import List, Dict, Union, Callable, Tuple
|
||||
|
||||
from ..dcs import RemoteMember
|
||||
from ..psycopg import quote_ident, quote_literal
|
||||
from ..utils import deep_compare
|
||||
from ..utils import deep_compare, unquote
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -26,7 +27,56 @@ class Bootstrap(object):
|
||||
return self._running_custom_bootstrap and self._keep_existing_recovery_conf
|
||||
|
||||
@staticmethod
|
||||
def process_user_options(tool, options, not_allowed_options, error_handler):
|
||||
def process_user_options(tool: str,
|
||||
options: Union[Dict[str, str], List[Union[str, Dict[str, str]]]],
|
||||
not_allowed_options: Tuple[str, ...],
|
||||
error_handler: Callable[[str], None]) -> List:
|
||||
"""Format *options* in a list or dictionary format into command line long form arguments.
|
||||
|
||||
.. note::
|
||||
The format of the output of this method is to prepare arguments for use in the ``initdb``
|
||||
method of `self._postgres`.
|
||||
|
||||
:Example:
|
||||
|
||||
The *options* can be defined as a dictionary of key, values to be converted into arguments:
|
||||
>>> Bootstrap.process_user_options('foo', {'foo': 'bar'}, (), print)
|
||||
['--foo=bar']
|
||||
|
||||
Or as a list of single string arguments
|
||||
>>> Bootstrap.process_user_options('foo', ['yes'], (), print)
|
||||
['--yes']
|
||||
|
||||
Or as a list of key, value options
|
||||
>>> Bootstrap.process_user_options('foo', [{'foo': 'bar'}], (), print)
|
||||
['--foo=bar']
|
||||
|
||||
Or a combination of single and key, values
|
||||
>>> Bootstrap.process_user_options('foo', ['yes', {'foo': 'bar'}], (), print)
|
||||
['--yes', '--foo=bar']
|
||||
|
||||
Options that contain spaces are passed as is to ``subprocess.call``
|
||||
>>> Bootstrap.process_user_options('foo', [{'foo': 'bar baz'}], (), print)
|
||||
['--foo=bar baz']
|
||||
|
||||
Options that are quoted will be unquoted, so the quotes aren't interpreted
|
||||
literally by the postgres command
|
||||
>>> Bootstrap.process_user_options('foo', [{'foo': '"bar baz"'}], (), print)
|
||||
['--foo=bar baz']
|
||||
|
||||
.. note::
|
||||
The *error_handler* is called when any of these conditions are met:
|
||||
|
||||
* Key, value dictionaries in the list form contains multiple keys.
|
||||
* If a key is listed in *not_allowed_options*.
|
||||
* If the options list is not in the required structure.
|
||||
|
||||
:param tool: The name of the tool used in error reports to *error_handler*
|
||||
:param options: Options to parse as a list of key, values or single values, or a dictionary
|
||||
:param not_allowed_options: List of keys that cannot be used in the list of key, value formatted options
|
||||
:param error_handler: A function which will be called when an error condition is encountered
|
||||
:returns: List of long form arguments to pass to the named tool
|
||||
"""
|
||||
user_options = []
|
||||
|
||||
def option_is_allowed(name):
|
||||
@@ -36,9 +86,9 @@ class Bootstrap(object):
|
||||
return ret
|
||||
|
||||
if isinstance(options, dict):
|
||||
for k, v in options.items():
|
||||
if k and v:
|
||||
user_options.append('--{0}={1}'.format(k, v))
|
||||
for key, val in options.items():
|
||||
if key and val:
|
||||
user_options.append('--{0}={1}'.format(key, unquote(val)))
|
||||
elif isinstance(options, list):
|
||||
for opt in options:
|
||||
if isinstance(opt, str) and option_is_allowed(opt):
|
||||
@@ -48,7 +98,7 @@ class Bootstrap(object):
|
||||
if len(keys) != 1 or not isinstance(opt[keys[0]], str) or not option_is_allowed(keys[0]):
|
||||
error_handler('Error when parsing {0} key-value option {1}: only one key-value is allowed'
|
||||
' and value should be a string'.format(tool, opt[keys[0]]))
|
||||
user_options.append('--{0}={1}'.format(keys[0], opt[keys[0]]))
|
||||
user_options.append('--{0}={1}'.format(keys[0], unquote(opt[keys[0]])))
|
||||
else:
|
||||
error_handler('Error when parsing {0} option {1}: value should be string value'
|
||||
' or a single key-value pair'.format(tool, opt))
|
||||
@@ -74,9 +124,8 @@ class Bootstrap(object):
|
||||
os.write(fd, self._postgresql.config.superuser['password'].encode('utf-8'))
|
||||
os.close(fd)
|
||||
options.append('--pwfile={0}'.format(pwfile))
|
||||
options = ['-o', ' '.join(options)] if options else []
|
||||
|
||||
ret = self._postgresql.pg_ctl('initdb', *options)
|
||||
ret = self._postgresql.initdb(*options)
|
||||
if pwfile:
|
||||
os.remove(pwfile)
|
||||
if ret:
|
||||
|
||||
Reference in New Issue
Block a user