Add support for connecting using pg_service.conf files. Fixes #3140

This commit is contained in:
Murtuza Zabuawala
2018-03-12 16:45:56 -04:00
committed by Dave Page
parent 985a004766
commit 03b772bf64
10 changed files with 2227 additions and 2017 deletions

View File

@@ -478,7 +478,8 @@ class ServerNode(PGChildNodeView):
'sslcrl': 'sslcrl',
'sslcompression': 'sslcompression',
'bgcolor': 'bgcolor',
'fgcolor': 'fgcolor'
'fgcolor': 'fgcolor',
'service': 'service'
}
disp_lbl = {
@@ -515,7 +516,7 @@ class ServerNode(PGChildNodeView):
if connected:
for arg in (
'host', 'hostaddr', 'port', 'db', 'username', 'sslmode',
'role'
'role', 'service'
):
if arg in data:
return forbidden(
@@ -663,7 +664,8 @@ class ServerNode(PGChildNodeView):
'sslrootcert': server.sslrootcert if is_ssl else None,
'sslcrl': server.sslcrl if is_ssl else None,
'sslcompression': True if is_ssl and server.sslcompression
else False
else False,
'service': server.service if server.service else None
}
)
@@ -672,18 +674,22 @@ class ServerNode(PGChildNodeView):
"""Add a server node to the settings database"""
required_args = [
u'name',
u'host',
u'port',
u'db',
u'username',
u'sslmode',
u'role'
u'username'
]
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
# Some fields can be provided with service file so they are optional
if 'service' in data and not data['service']:
required_args.extend([
u'host',
u'db',
u'role'
])
for arg in required_args:
if arg not in data:
return make_json_response(
@@ -711,29 +717,26 @@ class ServerNode(PGChildNodeView):
try:
server = Server(
user_id=current_user.id,
servergroup_id=data[u'gid'] if u'gid' in data else gid,
name=data[u'name'],
host=data[u'host'],
hostaddr=data[u'hostaddr'] if u'hostaddr' in data else None,
port=data[u'port'],
maintenance_db=data[u'db'],
username=data[u'username'],
ssl_mode=data[u'sslmode'],
comment=data[u'comment'] if u'comment' in data else None,
role=data[u'role'] if u'role' in data else None,
servergroup_id=data.get('gid', gid),
name=data.get('name'),
host=data.get('host', None),
hostaddr=data.get('hostaddr', None),
port=data.get('port'),
maintenance_db=data.get('db', None),
username=data.get('username'),
ssl_mode=data.get('sslmode'),
comment=data.get('comment', None),
role=data.get('role', None),
db_res=','.join(data[u'db_res'])
if u'db_res' in data
else None,
sslcert=data['sslcert'] if is_ssl else None,
sslkey=data['sslkey'] if is_ssl else None,
sslrootcert=data['sslrootcert'] if is_ssl else None,
sslcrl=data['sslcrl'] if is_ssl else None,
if u'db_res' in data else None,
sslcert=data.get('sslcert', None),
sslkey=data.get('sslkey', None),
sslrootcert=data.get('sslrootcert', None),
sslcrl=data.get('sslcrl', None),
sslcompression=1 if is_ssl and data['sslcompression'] else 0,
bgcolor=data['bgcolor'] if u'bgcolor' in data
else None,
fgcolor=data['fgcolor'] if u'fgcolor' in data
else None
bgcolor=data.get('bgcolor', None),
fgcolor=data.get('fgcolor', None),
service=data.get('service', None)
)
db.session.add(server)
db.session.commit()
@@ -930,7 +933,7 @@ class ServerNode(PGChildNodeView):
if 'password' not in data:
conn_passwd = getattr(conn, 'password', None)
if conn_passwd is None and server.password is None and \
server.passfile is None:
server.passfile is None and server.service is None:
# Return the password template in case password is not
# provided, or password has not been saved earlier.
return make_json_response(

View File

@@ -665,6 +665,7 @@ define('pgadmin.node.server', [
sslkey: undefined,
sslrootcert: undefined,
sslcrl: undefined,
service: undefined,
},
// Default values!
initialize: function(attrs, args) {
@@ -841,12 +842,18 @@ define('pgadmin.node.server', [
var passfile = m.get('passfile');
return !_.isUndefined(passfile) && !_.isNull(passfile);
},
},{
id: 'service', label: gettext('Service'), type: 'text',
mode: ['properties', 'edit', 'create'], disabled: 'isConnected',
group: gettext('Connection'),
}],
validate: function() {
var err = {},
errmsg,
self = this;
var service_id = this.get('service');
var check_for_empty = function(id, msg) {
var v = self.get(id);
if (
@@ -903,26 +910,41 @@ define('pgadmin.node.server', [
}
check_for_empty('name', gettext('Name must be specified.'));
if (check_for_empty(
'host', gettext('Either Host name or Host address must be specified.')
) && check_for_empty('hostaddr', gettext('Either Host name or Host address must be specified.'))){
errmsg = errmsg || gettext('Either Host name or Host address must be specified');
// If no service id then only check
if (
_.isUndefined(service_id) || _.isNull(service_id) ||
String(service_id).replace(/^\s+|\s+$/g, '') == ''
) {
if (check_for_empty(
'host', gettext('Either Host name, Address or Service must be specified.')
) && check_for_empty('hostaddr', gettext('Either Host name, Address or Service must be specified.'))){
errmsg = errmsg || gettext('Either Host name, Address or Service must be specified.');
} else {
errmsg = undefined;
delete err['host'];
delete err['hostaddr'];
}
check_for_empty(
'db', gettext('Maintenance database must be specified.')
);
check_for_valid_ip(
'hostaddr', gettext('Host address must be valid IPv4 or IPv6 address.')
);
check_for_valid_ip(
'hostaddr', gettext('Host address must be valid IPv4 or IPv6 address.')
);
} else {
errmsg = undefined;
delete err['host'];
delete err['hostaddr'];
_.each(['host', 'hostaddr', 'db'], (item) => {
self.errorModel.unset(item);
});
}
check_for_empty(
'db', gettext('Maintenance database must be specified.')
);
check_for_empty(
'username', gettext('Username must be specified.')
);
check_for_empty('port', gettext('Port must be specified.'));
check_for_valid_ip(
'hostaddr', gettext('Host address must be valid IPv4 or IPv6 address.')
);
this.errorModel.set(err);
if (_.size(err)) {

View File

@@ -0,0 +1,47 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import json
from pgadmin.utils.route import BaseTestGenerator
from regression.python_test_utils import test_utils as utils
class ServersWithServiceIDAddTestCase(BaseTestGenerator):
""" This class will add the servers under default server group. """
scenarios = [
# Fetch the default url for server object
(
'Default Server Node url', dict(
url='/browser/server/obj/'
)
)
]
def setUp(self):
pass
def runTest(self):
""" This function will add the server under default server group."""
url = "{0}{1}/".format(self.url, utils.SERVER_GROUP)
# Add service name in the config
self.server['service'] = "TestDB"
response = self.tester.post(
url,
data=json.dumps(self.server),
content_type='html/json'
)
self.assertEquals(response.status_code, 200)
response_data = json.loads(response.data.decode('utf-8'))
self.server_id = response_data['node']['_id']
def tearDown(self):
"""This function delete the server from SQLite """
utils.delete_server_with_api(self.tester, self.server_id)