diff --git a/patroni/config.py b/patroni/config.py index 1afce2f6..f6fa4854 100644 --- a/patroni/config.py +++ b/patroni/config.py @@ -22,7 +22,9 @@ _AUTH_ALLOWED_PARAMETERS = ( 'sslcert', 'sslkey', 'sslrootcert', - 'sslcrl' + 'sslcrl', + 'gssencmode', + 'channel_binding' ) diff --git a/patroni/postgresql/config.py b/patroni/postgresql/config.py index e6b33d63..fcab640e 100644 --- a/patroni/postgresql/config.py +++ b/patroni/postgresql/config.py @@ -113,17 +113,17 @@ def parse_dsn(value): Very simple equivalent of `psycopg2.extensions.parse_dsn` introduced in 2.7.0. We are not using psycopg2 function in order to remain compatible with 2.5.4+. There is one minor difference though, this function removes `dbname` from the result - and sets the sslmode` to `prefer` if it is not present in the connection string. - This is necessary to simplify comparison of the old and the new values. + and sets the `sslmode`, 'gssencmode', and `channel_binding` to `prefer` if it is not present in + the connection string. This is necessary to simplify comparison of the old and the new values. >>> r = parse_dsn('postgresql://u%2Fse:pass@:%2f123,[%2Fhost2]/db%2Fsdf?application_name=mya%2Fpp&ssl=true') >>> r == {'application_name': 'mya/pp', 'host': ',/host2', 'sslmode': 'require',\ - 'password': 'pass', 'port': '/123', 'user': 'u/se'} + 'password': 'pass', 'port': '/123', 'user': 'u/se', 'gssencmode': 'prefer', 'channel_binding': 'prefer'} True >>> r = parse_dsn(" host = 'host' dbname = db\\\\ name requiressl=1 ") - >>> r == {'host': 'host', 'sslmode': 'require'} + >>> r == {'host': 'host', 'sslmode': 'require', 'gssencmode': 'prefer', 'channel_binding': 'prefer'} True - >>> parse_dsn('requiressl = 0\\\\') == {'sslmode': 'prefer'} + >>> parse_dsn('requiressl = 0\\\\') == {'sslmode': 'prefer', 'gssencmode': 'prefer', 'channel_binding': 'prefer'} True >>> parse_dsn("host=a foo = '") is None True @@ -147,6 +147,8 @@ def parse_dsn(value): ret.setdefault('sslmode', 'prefer') if 'dbname' in ret: del ret['dbname'] + ret.setdefault('gssencmode', 'prefer') + ret.setdefault('channel_binding', 'prefer') return ret @@ -492,6 +494,10 @@ class ConfigHandler(object): ret = member.conn_kwargs(self.replication) ret['application_name'] = self._postgresql.name ret.setdefault('sslmode', 'prefer') + if self._postgresql.major_version >= 120000: + ret.setdefault('gssencmode', 'prefer') + if self._postgresql.major_version >= 130000: + ret.setdefault('channel_binding', 'prefer') if self._krbsrvname: ret['krbsrvname'] = self._krbsrvname if 'database' in ret: @@ -500,8 +506,9 @@ class ConfigHandler(object): def format_dsn(self, params, include_dbname=False): # A list of keywords that can be found in a conninfo string. Follows what is acceptable by libpq - keywords = ('dbname', 'user', 'passfile' if params.get('passfile') else 'password', 'host', 'port', 'sslmode', - 'sslcompression', 'sslcert', 'sslkey', 'sslrootcert', 'sslcrl', 'application_name', 'krbsrvname') + keywords = ('dbname', 'user', 'passfile' if params.get('passfile') else 'password', 'host', 'port', + 'sslmode', 'sslcompression', 'sslcert', 'sslkey', 'sslrootcert', 'sslcrl', + 'application_name', 'krbsrvname', 'gssencmode', 'channel_binding') if include_dbname: params = params.copy() params['dbname'] = params.get('database') or self._postgresql.database diff --git a/tests/test_postgresql.py b/tests/test_postgresql.py index fabab68a..78a9eeb5 100644 --- a/tests/test_postgresql.py +++ b/tests/test_postgresql.py @@ -93,7 +93,7 @@ class TestPostgresql(BaseTestPostgresql): @patch('subprocess.call', Mock(return_value=0)) @patch('os.rename', Mock()) @patch('patroni.postgresql.CallbackExecutor', Mock()) - @patch.object(Postgresql, 'get_major_version', Mock(return_value=120000)) + @patch.object(Postgresql, 'get_major_version', Mock(return_value=130000)) @patch.object(Postgresql, 'is_running', Mock(return_value=True)) def setUp(self): super(TestPostgresql, self).setUp()