diff --git a/conf/zabbix_server.conf b/conf/zabbix_server.conf index 87b37fdd27..1c5f87f3d2 100644 --- a/conf/zabbix_server.conf +++ b/conf/zabbix_server.conf @@ -75,6 +75,17 @@ LogFile=/tmp/zabbix_server.log # Default: # SocketDir=/tmp +### Option: DBConnectionString +# Connectionstring to connect to database. +# Currently used for PostgreSQL only. +# When used, other DBConnection parameters are ignored. +# +# example: DBConnectionString="postgresql://zabbix:ZabbixPassword@localhost/zabbix?target_session_attrs=read-write" +# +# Mandatory: no +# Default: +# DBConnectionString= + ### Option: DBHost # Database host name. # If set to localhost, socket is used for MySQL. @@ -86,6 +97,16 @@ LogFile=/tmp/zabbix_server.log # Default: # DBHost=localhost +### Option: DBTargetSessionAttr +# Database target session attribute. +# Used for PostgreSQL only. +# For values refer to https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS `target_session_attrs` +# By default is set to 'read-write' to choose server where writing is possible +# +# Mandatory: no +# Default: +# DBTargetSessionAttr=read-write + ### Option: DBName # Database name. # If the Net Service Name connection method is used to connect to Oracle database, specify the service name from diff --git a/include/db.h b/include/db.h index 53b95faad8..11f04ed1b5 100644 --- a/include/db.h +++ b/include/db.h @@ -25,7 +25,9 @@ #include "zbxdb.h" #include "dbschema.h" +extern char *CONFIG_DBCONNSTRING; extern char *CONFIG_DBHOST; +extern char *CONFIG_DBTARGETATTR; extern char *CONFIG_DBNAME; extern char *CONFIG_DBSCHEMA; extern char *CONFIG_DBUSER; diff --git a/include/zbxdb.h b/include/zbxdb.h index 4bdf66eb56..a1492a27a1 100644 --- a/include/zbxdb.h +++ b/include/zbxdb.h @@ -85,8 +85,8 @@ void zbx_db_deinit(void); void zbx_db_init_autoincrement_options(void); -int zbx_db_connect(char *host, char *user, char *password, char *dbname, char *dbschema, char *dbsocket, int port, - char *tls_connect, char *cert, char *key, char *ca, char *cipher, char *cipher_13); +int zbx_db_connect(char *host, char *target_session_attr, char *user, char *password, char *dbname, char *dbschema, char *dbsocket, int port, + char *tls_connect, char *cert, char *key, char *ca, char *cipher, char *cipher_13, char *connectionstring); void zbx_db_close(void); int zbx_db_begin(void); diff --git a/src/libs/zbxdb/db.c b/src/libs/zbxdb/db.c index 1db05cabf1..7e9d15b1d4 100644 --- a/src/libs/zbxdb/db.c +++ b/src/libs/zbxdb/db.c @@ -374,8 +374,8 @@ void zbx_db_init_autoincrement_options(void) * ZBX_DB_FAIL - failed to connect * * * ******************************************************************************/ -int zbx_db_connect(char *host, char *user, char *password, char *dbname, char *dbschema, char *dbsocket, int port, - char *tls_connect, char *cert, char *key, char *ca, char *cipher, char *cipher_13) +int zbx_db_connect(char *host, char *target_session_attr, char *user, char *password, char *dbname, char *dbschema, char *dbsocket, int port, + char *tls_connect, char *cert, char *key, char *ca, char *cipher, char *cipher_13, char *connectionstring) { int ret = ZBX_DB_OK, last_txn_error, last_txn_level; #if defined(HAVE_MYSQL) @@ -699,72 +699,84 @@ int zbx_db_connect(char *host, char *user, char *password, char *dbname, char *d ZBX_UNUSED(cipher); ZBX_UNUSED(cipher_13); - if (NULL != tls_connect) + if NULL != connectionstring { - keywords[i] = "sslmode"; + conn = PQconnectdb(connectionstring); + } else { + if (NULL != tls_connect) + { + keywords[i] = "sslmode"; - if (0 == strcmp(tls_connect, ZBX_DB_TLS_CONNECT_REQUIRED_TXT)) - values[i++] = "require"; - else if (0 == strcmp(tls_connect, ZBX_DB_TLS_CONNECT_VERIFY_CA_TXT)) - values[i++] = "verify-ca"; - else - values[i++] = "verify-full"; - } + if (0 == strcmp(tls_connect, ZBX_DB_TLS_CONNECT_REQUIRED_TXT)) + values[i++] = "require"; + else if (0 == strcmp(tls_connect, ZBX_DB_TLS_CONNECT_VERIFY_CA_TXT)) + values[i++] = "verify-ca"; + else + values[i++] = "verify-full"; + } - if (NULL != cert) - { - keywords[i] = "sslcert"; - values[i++] = cert; - } + if (NULL != cert) + { + keywords[i] = "sslcert"; + values[i++] = cert; + } - if (NULL != key) - { - keywords[i] = "sslkey"; - values[i++] = key; - } + if (NULL != key) + { + keywords[i] = "sslkey"; + values[i++] = key; + } - if (NULL != ca) - { - keywords[i] = "sslrootcert"; - values[i++] = ca; - } + if (NULL != ca) + { + keywords[i] = "sslrootcert"; + values[i++] = ca; + } - if (NULL != host) - { - keywords[i] = "host"; - values[i++] = host; - } + if (NULL != host) + { + keywords[i] = "host"; + values[i++] = host; + } - if (NULL != dbname) - { - keywords[i] = "dbname"; - values[i++] = dbname; - } + if (NULL != dbname) + { + keywords[i] = "dbname"; + values[i++] = dbname; + } - if (NULL != user) - { - keywords[i] = "user"; - values[i++] = user; - } + if (NULL != user) + { + keywords[i] = "user"; + values[i++] = user; + } - if (NULL != password) - { - keywords[i] = "password"; - values[i++] = password; - } + if (NULL != password) + { + keywords[i] = "password"; + values[i++] = password; + } - if (0 != port) - { - keywords[i] = "port"; - values[i++] = cport = zbx_dsprintf(cport, "%d", port); - } + if (0 != port) + { + keywords[i] = "port"; + values[i++] = cport = zbx_dsprintf(cport, "%d", port); + } - keywords[i] = NULL; - values[i] = NULL; + if (NULL != target_session_attr) + { + keywords[i] = "target_session_attr"; + values[i++] = target_session_attr; + } + + keywords[i] = NULL; + values[i] = NULL; - conn = PQconnectdbParams(keywords, values, 0); + conn = PQconnectdbParams(keywords, values, 0); - zbx_free(cport); + zbx_free(cport); + + } /* check to see that the backend connection was successfully made */ if (CONNECTION_OK != PQstatus(conn)) diff --git a/src/libs/zbxdbhigh/db.c b/src/libs/zbxdbhigh/db.c index 3e2ee0cba9..7663dc9350 100644 --- a/src/libs/zbxdbhigh/db.c +++ b/src/libs/zbxdbhigh/db.c @@ -182,10 +182,10 @@ int DBconnect(int flag) zabbix_log(LOG_LEVEL_DEBUG, "In %s() flag:%d", __func__, flag); - while (ZBX_DB_OK != (err = zbx_db_connect(CONFIG_DBHOST, CONFIG_DBUSER, CONFIG_DBPASSWORD, + while (ZBX_DB_OK != (err = zbx_db_connect(CONFIG_DBHOST, CONFIG_DBTARGETATTR, CONFIG_DBUSER, CONFIG_DBPASSWORD, CONFIG_DBNAME, CONFIG_DBSCHEMA, CONFIG_DBSOCKET, CONFIG_DBPORT, CONFIG_DB_TLS_CONNECT, CONFIG_DB_TLS_CERT_FILE, CONFIG_DB_TLS_KEY_FILE, CONFIG_DB_TLS_CA_FILE, CONFIG_DB_TLS_CIPHER, - CONFIG_DB_TLS_CIPHER_13))) + CONFIG_DB_TLS_CIPHER_13, CONFIG_DBCONNSTRING))) { if (ZBX_DB_CONNECT_ONCE == flag) break; diff --git a/src/zabbix_server/server.c b/src/zabbix_server/server.c index fbf07303f4..44b1b5441b 100644 --- a/src/zabbix_server/server.c +++ b/src/zabbix_server/server.c @@ -259,7 +259,9 @@ char *CONFIG_EXTERNALSCRIPTS = NULL; char *CONFIG_TMPDIR = NULL; char *CONFIG_FPING_LOCATION = NULL; char *CONFIG_FPING6_LOCATION = NULL; +char *CONFIG_DBCONNSTRING = NULL; char *CONFIG_DBHOST = NULL; +char *CONFIG_DBTARGETATTR = NULL; char *CONFIG_DBNAME = NULL; char *CONFIG_DBSCHEMA = NULL; char *CONFIG_DBUSER = NULL; @@ -552,6 +554,9 @@ static void zbx_set_defaults(void) if (NULL == CONFIG_DBHOST) CONFIG_DBHOST = zbx_strdup(CONFIG_DBHOST, "localhost"); + if (NULL == CONFIG_DBTARGETATTR) + CONFIG_DBTARGETATTR = zbx_strdup(CONFIG_DBTARGETATTR, "read-write"); + if (NULL == CONFIG_SNMPTRAP_FILE) CONFIG_SNMPTRAP_FILE = zbx_strdup(CONFIG_SNMPTRAP_FILE, "/tmp/zabbix_traps.tmp"); @@ -832,8 +837,12 @@ static void zbx_load_config(ZBX_TASK_EX *task) PARM_OPT, 0, 0}, {"ExternalScripts", &CONFIG_EXTERNALSCRIPTS, TYPE_STRING, PARM_OPT, 0, 0}, + {"DBConnectionString", &CONFIG_DBCONNSTRING, TYPE_STRING, + PARM_OPT, 0, 0}, {"DBHost", &CONFIG_DBHOST, TYPE_STRING, PARM_OPT, 0, 0}, + {"DBTargetSessionAttr", &CONFIG_DBTARGETATTR, TYPE_STRING, + PARM_OPT, 0, 0}, {"DBName", &CONFIG_DBNAME, TYPE_STRING, PARM_MAND, 0, 0}, {"DBSchema", &CONFIG_DBSCHEMA, TYPE_STRING, diff --git a/ui/conf/zabbix.conf.php.example b/ui/conf/zabbix.conf.php.example index 72507132e4..750f78ed42 100644 --- a/ui/conf/zabbix.conf.php.example +++ b/ui/conf/zabbix.conf.php.example @@ -2,11 +2,18 @@ // Zabbix GUI configuration file. $DB['TYPE'] = 'MYSQL'; +// If $DB['CONNECTIONSTRING'] used with PostgreSQL, then rest of DB connection parameters are ignored for connection. +// $DB['DATABASE'] and $DB['USER'] are required for internal purposes. +// $DB['CONNECTIONSTRING'] = 'postgresql://zabbix:ZabbixPassword@localhost/zabbix'; + +// DB Connection parameters $DB['SERVER'] = 'localhost'; $DB['PORT'] = '0'; $DB['DATABASE'] = 'zabbix'; $DB['USER'] = 'zabbix'; $DB['PASSWORD'] = ''; +// Uncomment and set to desired values for PG target_session_attr. If not set or empty, defaults to 'read-write'. +// $DB['TARGET_SESSION_ATTR'] = ''; // Schema name. Used for PostgreSQL. $DB['SCHEMA'] = ''; diff --git a/ui/include/classes/core/CConfigFile.php b/ui/include/classes/core/CConfigFile.php index b29a3813d7..d10e07ad98 100644 --- a/ui/include/classes/core/CConfigFile.php +++ b/ui/include/classes/core/CConfigFile.php @@ -94,6 +94,14 @@ class CConfigFile { $this->config['DB']['TYPE'] = $DB['TYPE']; $this->config['DB']['DATABASE'] = $DB['DATABASE']; + if (isset($DB['CONNECTIONSTRING'])) { + $this->config['DB']['CONNECTIONSTRING'] = $DB['CONNECTIONSTRING']; + } + + if (isset($DB['TARGET_SESSION_ATTR'])) { + $this->config['DB']['TARGET_SESSION_ATTR'] = $DB['TARGET_SESSION_ATTR']; + } + if (isset($DB['SERVER'])) { $this->config['DB']['SERVER'] = $DB['SERVER']; } @@ -274,12 +282,19 @@ class CConfigFile { 'config['DB']['TYPE'], "'\\").'\'; -$DB[\'SERVER\'] = \''.addcslashes($this->config['DB']['SERVER'], "'\\").'\'; -$DB[\'PORT\'] = \''.addcslashes($this->config['DB']['PORT'], "'\\").'\'; -$DB[\'DATABASE\'] = \''.addcslashes($this->config['DB']['DATABASE'], "'\\").'\'; -$DB[\'USER\'] = \''.addcslashes($this->config['DB']['USER'], "'\\").'\'; -$DB[\'PASSWORD\'] = \''.addcslashes($this->config['DB']['PASSWORD'], "'\\").'\'; +// If $DB[\'CONNECTIONSTRING\'] used with PostgreSQL, then rest of DB connection parameters are ignored for connection. +// $DB[\'DATABASE\'] and $DB[\'USER\'] are required for internal purposes. +// $DB[\'CONNECTIONSTRING\'] = \''.addcslashes($this->config['DB']['CONNECTIONSTRING'], "'\\") . '\'; + +// DB Connection parameters +$DB[\'TYPE\'] = \''.addcslashes($this->config['DB']['TYPE'], "'\\").'\'; +$DB[\'SERVER\'] = \''.addcslashes($this->config['DB']['SERVER'], "'\\").'\'; +$DB[\'PORT\'] = \''.addcslashes($this->config['DB']['PORT'], "'\\").'\'; +$DB[\'DATABASE\'] = \''.addcslashes($this->config['DB']['DATABASE'], "'\\").'\'; +$DB[\'USER\'] = \''.addcslashes($this->config['DB']['USER'], "'\\").'\'; +$DB[\'PASSWORD\'] = \''.addcslashes($this->config['DB']['PASSWORD'], "'\\").'\'; +// Uncomment and set to desired values for PG target_session_attr. If not set or empty, defaults to \'read-write\'. +// $DB[\'TARGET_SESSION_ATTR\'] = \''.addcslashes($this->config['DB']['TARGET_SESSION_ATTR'], "'\\") . '\'; // Schema name. Used for PostgreSQL. $DB[\'SCHEMA\'] = \''.addcslashes($this->config['DB']['SCHEMA'], "'\\").'\'; diff --git a/ui/include/classes/db/PostgresqlDbBackend.php b/ui/include/classes/db/PostgresqlDbBackend.php index f07e8a02fc..8d984c366d 100644 --- a/ui/include/classes/db/PostgresqlDbBackend.php +++ b/ui/include/classes/db/PostgresqlDbBackend.php @@ -44,6 +44,13 @@ class PostgresqlDbBackend extends DbBackend { */ protected $user = ''; + /** + * Target session attrs. + * + * @var string + */ + protected $target_session_attrs = ''; + /** * Check if 'dbversion' table exists. * @@ -189,6 +196,17 @@ class PostgresqlDbBackend extends DbBackend { return $is_secure; } + /** + * Sets target_session_attrs. + * + * @param string $target_session_attrs Postgres target_session_attr parameter value. + * + */ + public function set_target_attr($target_session_attrs) + { + $this->target_session_attrs = $target_session_attrs; + } + /** * Create connection to database server. * @@ -217,6 +235,10 @@ class PostgresqlDbBackend extends DbBackend { ]; } + $params += [ + 'target_session_attrs' => $this->target_session_attrs ? $this->target_session_attrs : 'read-write' + ]; + $conn_string = ''; foreach ($params as $key => $param) { @@ -233,6 +255,33 @@ class PostgresqlDbBackend extends DbBackend { return $resource; } + /** + * Create connection to database server using connectionstring. + * + * @param string $connectionstring ConnectionString to connect to PG + * @param string $user User name. + * @param string $dbname Database name. + * @param string $schema DB schema. + * + * @param + * @return resource|null + */ + public function connect_connectionstring($connectionstring, $user, $dbname, $schema) + { + $this->user = $user; + $this->dbname = $dbname; + $this->schema = ($schema) ? $schema : 'public'; + + $resource = @pg_connect($connectionstring); + + if (!$resource) { + $this->setError('Error connecting to database.'); + return null; + } + + return $resource; + } + /** * Initialize database connection. * diff --git a/ui/include/db.inc.php b/ui/include/db.inc.php index c9b96e566f..711f118d4d 100644 --- a/ui/include/db.inc.php +++ b/ui/include/db.inc.php @@ -66,7 +66,14 @@ function DBconnect(&$error) { ); } - $DB['DB'] = $db->connect($DB['SERVER'], $DB['PORT'], $DB['USER'], $DB['PASSWORD'], $DB['DATABASE'], $DB['SCHEMA']); + if ($DB['TYPE'] == ZBX_DB_POSTGRESQL && isset($DB['TARGET_SESSION_ATTR'])) { + $db->set_target_attr($DB['TARGET_SESSION_ATTR']); + } + if ($DB['TYPE'] == ZBX_DB_POSTGRESQL and isset($DB['CONNECTIONSTRING']) and $DB['CONNECTIONSTRING']) { + $DB['DB'] = $db->connect_connectionstring($DB['CONNECTIONSTRING'], $DB['USER'], $DB['DATABASE'], $DB['SCHEMA']); + } else { + $DB['DB'] = $db->connect($DB['SERVER'], $DB['PORT'], $DB['USER'], $DB['PASSWORD'], $DB['DATABASE'], $DB['SCHEMA']); + } if ($DB['DB']) { $db->init();