diff options
30 files changed, 775 insertions, 56 deletions
diff --git a/ChangeLog.d/bugfix/ZBX-19063 b/ChangeLog.d/bugfix/ZBX-19063 new file mode 100644 index 00000000000..b7710bf7c65 --- /dev/null +++ b/ChangeLog.d/bugfix/ZBX-19063 @@ -0,0 +1 @@ +...G...... [ZBX-19063] fixed logging for unsupported windows service command in Zabbix agent 2 (esneiders) diff --git a/ChangeLog.d/bugfix/ZBX-19099 b/ChangeLog.d/bugfix/ZBX-19099 new file mode 100644 index 00000000000..d6fb2138d13 --- /dev/null +++ b/ChangeLog.d/bugfix/ZBX-19099 @@ -0,0 +1 @@ +...G...... [ZBX-19099] fixed Zabbix agent 2 windows services plugin second parameter (esneiders) diff --git a/ChangeLog.d/feature/ZBXNEXT-4910 b/ChangeLog.d/feature/ZBXNEXT-4910 new file mode 100644 index 00000000000..dc28d12ee38 --- /dev/null +++ b/ChangeLog.d/feature/ZBXNEXT-4910 @@ -0,0 +1 @@ +........S. [ZBXNEXT-4910] added severity in problem real-time export protocol (akozlovs) diff --git a/create/src/schema.tmpl b/create/src/schema.tmpl index 889c35916f3..31d76a54827 100644 --- a/create/src/schema.tmpl +++ b/create/src/schema.tmpl @@ -577,6 +577,7 @@ FIELD |item_test_timeout |t_varchar(32) |'60s' |NOT NULL |ZBX_NODATA FIELD |session_key |t_varchar(32)|'' |NOT NULL |ZBX_NODATA FIELD |url |t_varchar(255) |'' |NOT NULL |ZBX_NODATA FIELD |report_test_timeout|t_varchar(32)|'60s'|NOT NULL |ZBX_NODATA +FIELD |dbversion_status |t_varchar(1024)|'' |NOT NULL |ZBX_NODATA INDEX |1 |alert_usrgrpid INDEX |2 |discovery_groupid @@ -1846,4 +1847,4 @@ INDEX |1 |reportid TABLE|dbversion|| FIELD |mandatory |t_integer |'0' |NOT NULL | FIELD |optional |t_integer |'0' |NOT NULL | -ROW |5030169 |5030169 +ROW |5030170 |5030170 diff --git a/include/db.h b/include/db.h index 89645695535..5a49bec9a06 100644 --- a/include/db.h +++ b/include/db.h @@ -526,7 +526,9 @@ const ZBX_FIELD *DBget_field(const ZBX_TABLE *table, const char *fieldname); #define DBget_maxid(table) DBget_maxid_num(table, 1) zbx_uint64_t DBget_maxid_num(const char *tablename, int num); -void DBcheck_capabilities(void); +zbx_uint32_t DBextract_version(struct zbx_json *json); +void DBflush_version_requirements(const char *version); +int DBcheck_capabilities(zbx_uint32_t db_version); #ifdef HAVE_POSTGRESQL char *zbx_db_get_schema_esc(void); diff --git a/include/zbxdb.h b/include/zbxdb.h index 1631ee022d7..50a8a87797c 100644 --- a/include/zbxdb.h +++ b/include/zbxdb.h @@ -21,6 +21,7 @@ #define ZABBIX_ZBXDB_H #include "common.h" +#include "zbxjson.h" #define ZBX_DB_OK 0 #define ZBX_DB_FAIL -1 @@ -97,7 +98,6 @@ int zbx_db_txn_end_error(void); const char *zbx_db_last_strerr(void); #ifdef HAVE_POSTGRESQL -int zbx_dbms_get_version(void); int zbx_tsdb_get_version(void); #define ZBX_DB_TSDB_V1 (20000 > zbx_tsdb_get_version()) #endif @@ -145,6 +145,51 @@ char *zbx_db_dyn_escape_string(const char *src, size_t max_bytes, size_t max_ch #define ZBX_SQL_LIKE_ESCAPE_CHAR '!' char *zbx_db_dyn_escape_like_pattern(const char *src); -int zbx_db_strlen_n(const char *text, size_t maxlen); +int zbx_db_strlen_n(const char *text_loc, size_t maxlen); + +#define ZBX_MYSQL_MIN_VERSION 50728 +#define ZBX_MYSQL_MIN_VERSION_FRIENDLY "5.07.28" +#define ZBX_MYSQL_MAX_VERSION 80099 +#define ZBX_MYSQL_MAX_VERSION_FRIENDLY "8.00.x" + +#define ZBX_MARIA_MIN_VERSION 100037 +#define ZBX_MARIA_MIN_VERSION_FRIENDLY "10.00.37" +#define ZBX_MARIA_MAX_VERSION 100599 +#define ZBX_MARIA_MAX_VERSION_FRIENDLY "10.05.x" + +#define ZBX_POSTGRESQL_MIN_VERSION 100900 +#define ZBX_POSTGRESQL_MIN_VERSION_FRIENDLY "10.9" +#define ZBX_POSTGRESQL_MAX_VERSION 139999 +#define ZBX_POSTGRESQL_MAX_VERSION_FRIENDLY "13.x" + +#define ZBX_ORACLE_MIN_VERSION 1201000200 +#define ZBX_ORACLE_MIN_VERSION_FRIENDLY "Database 12c Release 12.01.00.02.x" +#define ZBX_ORACLE_MAX_VERSION 1901000000 +#define ZBX_ORACLE_MAX_VERSION_FRIENDLY "Database 19c Release 19.1.0" + +#define ZBX_ELASTIC_MIN_VERSION 70000 +#define ZBX_ELASTIC_MIN_VERSION_FRIENDLY "7.x" + +#define ZBX_DBVERSION_UNDEFINED 0 + +typedef enum +{ /* db version status flags shared with FRONTEND */ + DB_VERSION_SUPPORTED, + DB_VERSION_LOWER_THAN_MINIMUM, + DB_VERSION_HIGHER_THAN_MAXIMUM, + DB_VERSION_FAILED_TO_RETRIEVE +} zbx_db_version_status_t; + +zbx_uint32_t zbx_dbms_version_get(void); +zbx_uint32_t zbx_dbms_version_extract(struct zbx_json *json); + +#ifdef HAVE_MYSQL +int zbx_dbms_mariadb_used(void); +#endif + +int zbx_db_version_check(const char *database, zbx_uint32_t current_version, zbx_uint32_t min_version, + zbx_uint32_t max_version); +void zbx_db_version_json_create(struct zbx_json *json, const char *database, const char *friendly_current_version, + const char *friendly_min_version, const char *friendly_max_version, int flag); #endif diff --git a/include/zbxhistory.h b/include/zbxhistory.h index 788864aa1e5..e02bee7568a 100644 --- a/include/zbxhistory.h +++ b/include/zbxhistory.h @@ -21,6 +21,7 @@ #define ZABBIX_ZBXHISTORY_H #include "zbxvariant.h" +#include "zbxjson.h" /* the item history value */ typedef struct @@ -58,6 +59,6 @@ int zbx_history_get_values(zbx_uint64_t itemid, int value_type, int start, int c zbx_vector_history_record_t *values); int zbx_history_requires_trends(int value_type); - +void zbx_history_check_version(struct zbx_json *json); #endif diff --git a/include/zbxjson.h b/include/zbxjson.h index 1a3971e02be..ba766305d69 100644 --- a/include/zbxjson.h +++ b/include/zbxjson.h @@ -80,6 +80,7 @@ #define ZBX_PROTO_TAG_JMX_ENDPOINT "jmx_endpoint" #define ZBX_PROTO_TAG_EVENTID "eventid" #define ZBX_PROTO_TAG_NAME "name" +#define ZBX_PROTO_TAG_SEVERITY "severity" #define ZBX_PROTO_TAG_HOSTS "hosts" #define ZBX_PROTO_TAG_GROUPS "groups" #define ZBX_PROTO_TAG_TAGS "tags" @@ -289,8 +290,6 @@ void zbx_json_escape(char **string); int zbx_json_open_path(const struct zbx_json_parse *jp, const char *path, struct zbx_json_parse *out); zbx_json_type_t zbx_json_valuetype(const char *p); -void zbx_json_log(const struct zbx_json_parse *jp, int loglevel); - /* jsonpath support */ typedef struct zbx_jsonpath_segment zbx_jsonpath_segment_t; diff --git a/m4/ax_lib_oracle_oci.m4 b/m4/ax_lib_oracle_oci.m4 index cb8ccdb4785..ec1efd0a5e9 100644 --- a/m4/ax_lib_oracle_oci.m4 +++ b/m4/ax_lib_oracle_oci.m4 @@ -291,7 +291,7 @@ Please, locate Oracle directories using --with-oracle or \ AC_LINK_IFELSE([ AC_LANG_PROGRAM([[@%:@include <oci.h>]], [[ -OCIEnv* envh = 0; +OCIEnv *envh = 0; OCIEnvNlsCreate(&envh, OCI_DEFAULT, 0, 0, 0, 0, 0, 0, 0, 0); if (envh) OCIHandleFree(envh, OCI_HTYPE_ENV); ]] @@ -309,6 +309,33 @@ if (envh) OCIHandleFree(envh, OCI_HTYPE_ENV); ) fi + dnl + dnl Check OCIServerRelease2() API + dnl + if test "$oci_header_found" = "yes"; then + + AC_MSG_CHECKING([for Oracle OCIServerRelease2() API in $oracle_lib_dir]) + + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[@%:@include <oci.h>]], + [[ +OCIEnv *envh = 0; +OCIError *errh = 0; +OraText buf[256]; +ub4 version; +sword ret = OCIServerRelease2(envh, errh, buf, (ub4)sizeof(buf), OCI_HTYPE_SVCCTX, &version, OCI_DEFAULT); + ]] + )], + [ + AC_DEFINE(HAVE_OCI_SERVER_RELEASE2, 1, [Define to 1 if OCIServerRelease2 API are supported.]) + AC_MSG_RESULT(yes) + ], + [ + AC_MSG_RESULT([no]) + ] + ) + fi + CPPFLAGS="$saved_CPPFLAGS" LDFLAGS="$saved_LDFLAGS" LIBS="$saved_LIBS" diff --git a/src/go/cmd/zabbix_agent2/service_windows.go b/src/go/cmd/zabbix_agent2/service_windows.go index 441de2b96c7..e7f21ce59a3 100644 --- a/src/go/cmd/zabbix_agent2/service_windows.go +++ b/src/go/cmd/zabbix_agent2/service_windows.go @@ -463,7 +463,7 @@ loop: closeChan <- true break loop default: - log.Warningf("unsupported windows service command received") + log.Debugf("unsupported windows service command '%s' received", getCmdName(c.Cmd)) } case <-stopChan: changes <- svc.Status{State: svc.StopPending} @@ -478,3 +478,38 @@ loop: return } + +func getCmdName(cmd svc.Cmd) string { + switch cmd { + case svc.Stop: + return "Stop" + case svc.Pause: + return "Pause" + case svc.Continue: + return "Continue" + case svc.Interrogate: + return "Interrogate" + case svc.Shutdown: + return "Shutdown" + case svc.ParamChange: + return "ParamChange" + case svc.NetBindAdd: + return "NetBindAdd" + case svc.NetBindRemove: + return "NetBindRemove" + case svc.NetBindEnable: + return "NetBindEnable" + case svc.NetBindDisable: + return "NetBindDisable" + case svc.DeviceEvent: + return "DeviceEvent" + case svc.HardwareProfileChange: + return "HardwareProfileChange" + case svc.PowerEvent: + return "PowerEvent" + case svc.SessionChange: + return "SessionChange" + default: + return "unknown" + } +} diff --git a/src/go/plugins/windows/services/services_windows.go b/src/go/plugins/windows/services/services_windows.go index 0e14aa9fb20..e179ff08180 100644 --- a/src/go/plugins/windows/services/services_windows.go +++ b/src/go/plugins/windows/services/services_windows.go @@ -420,7 +420,7 @@ func (p *Plugin) exportServices(params []string) (result interface{}, err error) } stateFilter := stateFlagAll - if len(params) > 1 && params[1] != "" { + if len(params) > 1 && params[1] != "all" && params[1] != "" { switch params[1] { case "stopped": stateFilter = stateFlagStopped diff --git a/src/libs/zbxdb/db.c b/src/libs/zbxdb/db.c index 8a385625755..672f5226b67 100644 --- a/src/libs/zbxdb/db.c +++ b/src/libs/zbxdb/db.c @@ -45,7 +45,7 @@ struct zbx_db_result MYSQL_RES *result; #elif defined(HAVE_ORACLE) OCIStmt *stmthp; /* the statement handle for select operations */ - int ncolumn; + int ncolumn; DB_ROW values; ub4 *values_alloc; OCILobLocator **clobs; @@ -76,6 +76,8 @@ static int db_auto_increment; #if defined(HAVE_MYSQL) static MYSQL *conn = NULL; +static zbx_uint32_t ZBX_MYSQL_SVERSION = ZBX_DBVERSION_UNDEFINED; +static int ZBX_MARIADB_SFORK = OFF; #elif defined(HAVE_ORACLE) #include "zbxalgo.h" @@ -90,6 +92,8 @@ typedef struct } zbx_oracle_db_handle_t; +static zbx_uint32_t ZBX_ORACLE_SVERSION = ZBX_DBVERSION_UNDEFINED; + static zbx_oracle_db_handle_t oracle; static ub4 OCI_DBserver_status(void); @@ -97,7 +101,8 @@ static ub4 OCI_DBserver_status(void); #elif defined(HAVE_POSTGRESQL) static PGconn *conn = NULL; static unsigned int ZBX_PG_BYTEAOID = 0; -static int ZBX_PG_SVERSION = 0, ZBX_TSDB_VERSION = -1; +static int ZBX_TSDB_VERSION = -1; +static zbx_uint32_t ZBX_PG_SVERSION = ZBX_DBVERSION_UNDEFINED; char ZBX_PG_ESCAPE_BACKSLASH = 1; #elif defined(HAVE_SQLITE3) static sqlite3 *conn = NULL; @@ -786,9 +791,6 @@ int zbx_db_connect(char *host, char *user, char *password, char *dbname, char *d ZBX_PG_BYTEAOID = atoi(row[0]); DBfree_result(result); - ZBX_PG_SVERSION = PQserverVersion(conn); - zabbix_log(LOG_LEVEL_DEBUG, "PostgreSQL Server version: %d", ZBX_PG_SVERSION); - /* disable "nonstandard use of \' in a string literal" warning */ if (0 < (ret = zbx_db_execute("set escape_string_warning to off"))) ret = ZBX_DB_OK; @@ -2438,31 +2440,304 @@ char *zbx_db_dyn_escape_like_pattern(const char *src) * Return value: the string length in bytes * * * ******************************************************************************/ -int zbx_db_strlen_n(const char *text, size_t maxlen) +int zbx_db_strlen_n(const char *text_loc, size_t maxlen) { - return zbx_strlen_utf8_nchars(text, maxlen); + return zbx_strlen_utf8_nchars(text_loc, maxlen); } -#if defined(HAVE_POSTGRESQL) /****************************************************************************** * * - * Function: zbx_dbms_get_version * + * Function: zbx_db_version_check * + * * + * Purpose: determine if a vendor database(MySQL, MariaDB, PostgreSQL, * + * Oracle, ElasticDB) version satisfies Zabbix requirements * + * * + * Parameters: database - [IN] database name * + * current_version - [IN] detected numeric version * + * min_version - [IN] minimum required numeric version * + * max_version - [IN] maximum required numeric version * + * * + * Return value: resulting status flag * + * * + ******************************************************************************/ +int zbx_db_version_check(const char *database, zbx_uint32_t current_version, zbx_uint32_t min_version, + zbx_uint32_t max_version) +{ + int flag; + + if (ZBX_DBVERSION_UNDEFINED == current_version) + { + flag = DB_VERSION_FAILED_TO_RETRIEVE; + zabbix_log(LOG_LEVEL_WARNING, "Failed to retrieve %s version", database); + } + else if (min_version > current_version && ZBX_DBVERSION_UNDEFINED != min_version) + { + flag = DB_VERSION_LOWER_THAN_MINIMUM; + zabbix_log(LOG_LEVEL_WARNING, "Unsupported DB! %s version is %lu which is smaller than minimum of %lu", + database, (unsigned long)current_version, (unsigned long)min_version); + } + else if (max_version < current_version && ZBX_DBVERSION_UNDEFINED != max_version) + { + flag = DB_VERSION_HIGHER_THAN_MAXIMUM; + zabbix_log(LOG_LEVEL_WARNING, "Unsupported DB! %s version is %lu which is higher than maximum of %lu", + database, (unsigned long)current_version, (unsigned long)max_version); + } + else + flag = DB_VERSION_SUPPORTED; + + return flag; +} + +/****************************************************************************** + * * + * Function: zbx_db_version_json_create * + * * + * Purpose: prepare json for front-end with the DB current, minimum and * + * maximum versions and a flag that indicates if the version * + * satisfies the requirements * * * - * Purpose: returns DBMS version as integer: MMmmuu * + * Parameters: json - [IN/OUT] json data * + * database - [IN] name of DB (MySQL/ElasticDB) * + * friendly_current_version - [IN] string current version * + * friendly_min_version - [IN] string min version * + * friendly_max_version - [IN] string max version * + * flag - [IN] status if DB satisfies the * + * requirements * + * * + ******************************************************************************/ +void zbx_db_version_json_create(struct zbx_json *json, const char *database, const char *friendly_current_version, + const char *friendly_min_version, const char *friendly_max_version, int flag) +{ + zbx_json_addobject(json, NULL); + zbx_json_addstring(json, "database", database, ZBX_JSON_TYPE_STRING); + + if (DB_VERSION_FAILED_TO_RETRIEVE != flag) + zbx_json_addstring(json, "current_version", friendly_current_version, ZBX_JSON_TYPE_STRING); + + zbx_json_addstring(json, "min_version", friendly_min_version, ZBX_JSON_TYPE_STRING); + zbx_json_addstring(json, "max_version", friendly_max_version, ZBX_JSON_TYPE_STRING); + zbx_json_addint64(json, "flag", flag); + zbx_json_close(json); +} + +/****************************************************************************** + * * + * Function: zbx_dbms_version_get * + * * + * Purpose: For PostgreSQL, MySQL and MariaDB: * + * returns DBMS version as integer: MMmmuu * * M = major version part * * m = minor version part * * u = patch version part * * * - * Example: 1.2.34 version will be returned as 10234 * + * Example: if the original DB version was 1.2.34 then 10234 gets returned * + * * + * Purpose: For OracleDB: * + * returns DBMS version as integer: MRruRRivUU * + * MR = major release version part * + * ru = release update version part * + * RR = release update version revision part * + * iv = increment version part * + * UU = unused, reserved for future use * + * * + * Example: if the OracleDB version was 18.1.0.0.7 then 1801000007 gets * + * returned * * * - * Return value: DBMS version or 0 if unknown * + * Return value: DBMS version or DBVERSION_UNDEFINED if unknown * * * ******************************************************************************/ -int zbx_dbms_get_version(void) +zbx_uint32_t zbx_dbms_version_get(void) { +#if defined(HAVE_MYSQL) + return ZBX_MYSQL_SVERSION; +#elif defined(HAVE_POSTGRESQL) return ZBX_PG_SVERSION; +#elif defined(HAVE_ORACLE) + return ZBX_ORACLE_SVERSION; +#else + return ZBX_DBVERSION_UNDEFINED; +#endif } +#ifdef HAVE_MYSQL +/****************************************************************************** + * * + * Function: zbx_dbms_mariadb_used * + * * + * Purpose: returns flag if the mariadb was detected * + * * + * Return value: ON - mariadb detected * + * OFF - otherwise (it is unforked mysql) * + ******************************************************************************/ +int zbx_dbms_mariadb_used(void) +{ + return ZBX_MARIADB_SFORK; +} +#endif + +/*************************************************************************************************************** + * * + * Function: zbx_dbms_version_extract * + * * + * Purpose: retrieves the DB version and makes sure it is stored in the numeric format, also fills the json * + * to report to front-end * + * * + * For PostgreSQL: * + * numeric version is available from the API * + * * + * For MySQL and MariaDB: * + * numeric version is available from the API, but also the additional processing is required * + * to determine if it is a MySQL or MariaDB and save this result as well * + * * + * For Oracle: * + * numeric version needs to be manually parsed from the string result * + * Oracle DB format is like 18.1.2.3.0 where * + * 18 - major release version * + * 1 - release update version * + * 2 - release update version revision * + * 3 - increment version * + * 0 - unused, reserved for future use * + * * + * Oracle Examples: * + * For "Oracle Database 18c Express Edition Release 1.0.0.0.0 - Production" => 100000000 * + * For "Oracle Database 18c Express Edition Release 18.2.0.0.7 - Production" => 1802000007 * + * For "Oracle Database 18c Express Edition Release 0.0.34.123.7 - Production" => DBVERSION_UNDEFINED * + * For "Oracle Database 18c Express Edition Release 1.0.3.x.7 - Production" => DBVERISON_UNDEFINED * + * For "<anything else>" => DBVERSION_UNDEFINED * + * * + **************************************************************************************************************/ +zbx_uint32_t zbx_dbms_version_extract(struct zbx_json *json) +{ +#define RIGHT2(x) ((int)((zbx_uint32_t)(x) - ((zbx_uint32_t)((x)/100))*100)) +#if defined(HAVE_MYSQL) + int flag; + const char *info; + char *version_friendly; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + ZBX_MYSQL_SVERSION = (zbx_uint32_t)mysql_get_server_version(conn); + + if (NULL != (info = mysql_get_server_info(conn)) && NULL != strstr(info, "MariaDB")) + { + zabbix_log(LOG_LEVEL_DEBUG, "MariaDB fork detected"); + ZBX_MARIADB_SFORK = ON; + } + + version_friendly = zbx_dsprintf(NULL, "%d.%.2d.%.2d", RIGHT2(ZBX_MYSQL_SVERSION/10000), + RIGHT2(ZBX_MYSQL_SVERSION/100), RIGHT2(ZBX_MYSQL_SVERSION)); + + if (ON == ZBX_MARIADB_SFORK) + { + flag = zbx_db_version_check("MariaDB", ZBX_MYSQL_SVERSION, ZBX_MARIA_MIN_VERSION, ZBX_DBVERSION_UNDEFINED); + zbx_db_version_json_create(json, "MariaDB", version_friendly, + ZBX_MARIA_MIN_VERSION_FRIENDLY, ZBX_MARIA_MAX_VERSION_FRIENDLY, flag); + } + else + { + flag = zbx_db_version_check("MySQL", ZBX_MYSQL_SVERSION, ZBX_MYSQL_MIN_VERSION, ZBX_MYSQL_MAX_VERSION); + zbx_db_version_json_create(json, "MySQL", version_friendly, + ZBX_MYSQL_MIN_VERSION_FRIENDLY, ZBX_MYSQL_MAX_VERSION_FRIENDLY, flag); + } + + zbx_free(version_friendly); +#elif defined(HAVE_POSTGRESQL) + int flag; + char *version_friendly; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + ZBX_PG_SVERSION = PQserverVersion(conn); + version_friendly = zbx_dsprintf(NULL, "%d.%d.%d", RIGHT2(ZBX_PG_SVERSION/10000), + RIGHT2(ZBX_PG_SVERSION/100), RIGHT2(ZBX_PG_SVERSION)); + flag = zbx_db_version_check("PostgreSQL", ZBX_PG_SVERSION, ZBX_POSTGRESQL_MIN_VERSION, + ZBX_POSTGRESQL_MAX_VERSION); + zbx_db_version_json_create(json, "PostgreSQL", version_friendly, + ZBX_POSTGRESQL_MIN_VERSION_FRIENDLY, ZBX_POSTGRESQL_MAX_VERSION_FRIENDLY, flag); + zbx_free(version_friendly); +#elif defined(HAVE_ORACLE) +# ifdef HAVE_OCI_SERVER_RELEASE2 + char *version_str = "Version "; + ub4 oci_ver = 0; +# endif + char *start, *release_str = "Release "; + char version_friendly[MAX_STRING_LEN / 8]; + int flag, major_release_version, release_update_version, release_update_version_revision, + increment_version, reserved_for_future_use, overall_status = SUCCEED; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); +# ifdef HAVE_OCI_SERVER_RELEASE2 + if (OCI_SUCCESS != OCIServerRelease2(oracle.svchp, oracle.errhp, (OraText *) version_friendly, + (ub4)sizeof(version_friendly), OCI_HTYPE_SVCCTX, &oci_ver, OCI_DEFAULT)) +# else + if (OCI_SUCCESS != OCIServerVersion(oracle.svchp, oracle.errhp, (OraText *) version_friendly, + (ub4)sizeof(version_friendly), OCI_HTYPE_SVCCTX)) +# endif + { + overall_status = FAIL; + goto out; + } + + zabbix_log(LOG_LEVEL_DEBUG, "OracleDB version retrieved unparsed: %s", version_friendly); + + if ( +# ifdef HAVE_OCI_SERVER_RELEASE2 + NULL != (start = strstr(version_friendly, version_str)) || +# endif + NULL != (start = strstr(version_friendly, release_str))) + { + size_t next_start_index; + + next_start_index = start - version_friendly + strlen(release_str); /* same length for version_str */ + + if (5 != sscanf(version_friendly + next_start_index, "%d.%d.%d.%d.%d", &major_release_version, + &release_update_version, &release_update_version_revision, &increment_version, + &reserved_for_future_use) || major_release_version >= 100 || + major_release_version <= 0 || release_update_version >= 100 || + release_update_version < 0 || release_update_version_revision >= 100 || + release_update_version_revision < 0 || increment_version >= 100 || + increment_version < 0) + { + zabbix_log(LOG_LEVEL_WARNING, "Unexpected Oracle DB version format: %s", version_friendly); + overall_status = FAIL; + } + } + else + { + zabbix_log(LOG_LEVEL_WARNING, "Cannot find Release keyword in Oracle DB version."); + overall_status = FAIL; + } +out: + if (FAIL == overall_status) + { + zabbix_log(LOG_LEVEL_WARNING, "Failed to detect OracleDB version"); + ZBX_ORACLE_SVERSION = ZBX_DBVERSION_UNDEFINED; + } + else + { + ZBX_ORACLE_SVERSION = major_release_version * 100000000 + release_update_version * 1000000 + + release_update_version_revision * 10000 + increment_version * 100 + + reserved_for_future_use; +# ifndef HAVE_OCI_SERVER_RELEASE2 + if (18 <= major_release_version) + { + zabbix_log(LOG_LEVEL_WARNING, "Unable to determine the accurate Oracle DB version " + "(possibly there is a DB driver - DB version mismatch, " + "only the major Oracle DB version can be established): %s", version_friendly); + } +# endif + } + + flag = zbx_db_version_check("Oracle", ZBX_ORACLE_SVERSION, ZBX_ORACLE_MIN_VERSION, ZBX_ORACLE_MAX_VERSION); + zbx_db_version_json_create(json, "Oracle", version_friendly, ZBX_ORACLE_MIN_VERSION_FRIENDLY, + ZBX_ORACLE_MAX_VERSION_FRIENDLY, flag); +#else + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); +#endif + zabbix_log(LOG_LEVEL_DEBUG, "End of %s() version:%lu", __func__, (unsigned long)zbx_dbms_version_get()); + + return zbx_dbms_version_get(); +} + +#if defined(HAVE_POSTGRESQL) /****************************************************************************** * * * Function: zbx_tsdb_get_version * diff --git a/src/libs/zbxdbhigh/db.c b/src/libs/zbxdbhigh/db.c index 9b2b1fe7c17..7b4bdc7ab36 100644 --- a/src/libs/zbxdbhigh/db.c +++ b/src/libs/zbxdbhigh/db.c @@ -851,18 +851,65 @@ zbx_uint64_t DBget_maxid_num(const char *tablename, int num) /****************************************************************************** * * + * Function: DBextract_version * + * * + * Purpose: connects to DB and tries to detect DB version * + * * + ******************************************************************************/ +zbx_uint32_t DBextract_version(struct zbx_json *json) +{ + zbx_uint32_t ret; + + DBconnect(ZBX_DB_CONNECT_NORMAL); + ret = zbx_dbms_version_extract(json); + DBclose(); + + return ret; +} + +/****************************************************************************** + * * + * Function: DBflush_version_requirements * + * * + * Purpose: writes a json entry in DB with the result for the front-end * + * * + * Parameters: version - [IN] entry of DB versions * + * * + ******************************************************************************/ +void DBflush_version_requirements(const char *version) +{ + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + DBconnect(ZBX_DB_CONNECT_NORMAL); + + if (ZBX_DB_OK > DBexecute("update config set dbversion_status='%s'", version)) + zabbix_log(LOG_LEVEL_CRIT, "Failed to set dbversion_status"); + + DBclose(); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * * Function: DBcheck_capabilities * * * * Purpose: checks DBMS for optional features and exit if is not suitable * * * + * Parameters: db_version - [IN] version of DB * + * * + * Return value: SUCCEED - if optional features were checked successfully * + * FAIL - otherwise * + * * ******************************************************************************/ -void DBcheck_capabilities(void) +int DBcheck_capabilities(zbx_uint32_t db_version) { + int ret = SUCCEED; #ifdef HAVE_POSTGRESQL #define MIN_POSTGRESQL_VERSION_WITH_TIMESCALEDB 100002 #define MIN_TIMESCALEDB_VERSION 10500 - int postgresql_version, timescaledb_version; + int timescaledb_version; DB_RESULT result; DB_ROW row; @@ -880,22 +927,20 @@ void DBcheck_capabilities(void) if (0 != zbx_strcmp_null(row[0], ZBX_CONFIG_DB_EXTENSION_TIMESCALE)) goto clean; + ret = FAIL; /* In case of major upgrade, db_extension may be missing */ + /* Timescale compression feature is available in PostgreSQL 10.2 and TimescaleDB 1.5.0 */ - if (MIN_POSTGRESQL_VERSION_WITH_TIMESCALEDB > (postgresql_version = zbx_dbms_get_version())) + if (MIN_POSTGRESQL_VERSION_WITH_TIMESCALEDB > db_version) { - zabbix_log(LOG_LEVEL_CRIT, "PostgreSQL version %d is not supported with TimescaleDB, minimum is %d", - postgresql_version, MIN_POSTGRESQL_VERSION_WITH_TIMESCALEDB); - DBfree_result(result); - DBclose(); - exit(EXIT_FAILURE); + zabbix_log(LOG_LEVEL_CRIT, "PostgreSQL version %lu is not supported with TimescaleDB, minimum is %d", + (unsigned long)db_version, MIN_POSTGRESQL_VERSION_WITH_TIMESCALEDB); + goto clean; } if (0 == (timescaledb_version = zbx_tsdb_get_version())) { zabbix_log(LOG_LEVEL_CRIT, "Cannot determine TimescaleDB version"); - DBfree_result(result); - DBclose(); - exit(EXIT_FAILURE); + goto clean; } zabbix_log(LOG_LEVEL_INFORMATION, "TimescaleDB version: %d", timescaledb_version); @@ -904,15 +949,18 @@ void DBcheck_capabilities(void) { zabbix_log(LOG_LEVEL_CRIT, "TimescaleDB version %d is not supported, minimum is %d", timescaledb_version, MIN_TIMESCALEDB_VERSION); - DBfree_result(result); - DBclose(); - exit(EXIT_FAILURE); + goto clean; } + + ret = SUCCEED; clean: DBfree_result(result); out: DBclose(); +#else + ZBX_UNUSED(db_version); #endif + return ret; } #define MAX_EXPRESSIONS 950 diff --git a/src/libs/zbxdbupgrade/dbupgrade_5030.c b/src/libs/zbxdbupgrade/dbupgrade_5030.c index 58642d87a83..cbc421eb2fa 100644 --- a/src/libs/zbxdbupgrade/dbupgrade_5030.c +++ b/src/libs/zbxdbupgrade/dbupgrade_5030.c @@ -4654,6 +4654,13 @@ static int DBpatch_5030163(void) return DBadd_field("config", &field); } +static int DBpatch_5030164(void) +{ + const ZBX_FIELD field = {"dbversion_status", "", NULL, NULL, 1024, ZBX_TYPE_CHAR, ZBX_NOTNULL, 0}; + + return DBadd_field("config", &field); +} + /* trigger function conversion to new syntax */ #define ZBX_DBPATCH_FUNCTION_UPDATE_NAME 0x01 @@ -5632,7 +5639,7 @@ static int dbpatch_convert_trigger(zbx_dbpatch_trigger_t *trigger, zbx_vector_pt return SUCCEED; } -static int DBpatch_5030164(void) +static int DBpatch_5030165(void) { int i, ret = SUCCEED; DB_ROW row; @@ -5776,7 +5783,7 @@ static int DBpatch_5030164(void) return ret; } -static int DBpatch_5030165(void) +static int DBpatch_5030166(void) { if (0 == (program_type & ZBX_PROGRAM_TYPE_SERVER)) return SUCCEED; @@ -5966,7 +5973,7 @@ static int dbpatch_convert_expression_macro(const char *expression, const zbx_st return SUCCEED; } -static int DBpatch_5030166(void) +static int DBpatch_5030167(void) { DB_ROW row; DB_RESULT result; @@ -6160,7 +6167,7 @@ static char *dbpatch_formula_to_expression(zbx_uint64_t itemid, const char *form return exp; } -static int DBpatch_5030167(void) +static int DBpatch_5030168(void) { DB_ROW row; DB_RESULT result; @@ -6370,7 +6377,7 @@ static int dbpatch_aggregate2formula(const char *itemid, const AGENT_REQUEST *re return SUCCEED; } -static int DBpatch_5030168(void) +static int DBpatch_5030169(void) { DB_ROW row; DB_RESULT result; @@ -6429,7 +6436,7 @@ static int DBpatch_5030168(void) return ret; } -static int DBpatch_5030169(void) +static int DBpatch_5030170(void) { #ifdef HAVE_MYSQL return DBcreate_index("items", "items_8", "key_(1024)", 0); @@ -6614,5 +6621,6 @@ DBPATCH_ADD(5030166, 0, 1) DBPATCH_ADD(5030167, 0, 1) DBPATCH_ADD(5030168, 0, 1) DBPATCH_ADD(5030169, 0, 1) +DBPATCH_ADD(5030170, 0, 1) DBPATCH_END() diff --git a/src/libs/zbxhistory/history.c b/src/libs/zbxhistory/history.c index 54bc95ba1a9..3afcdabd790 100644 --- a/src/libs/zbxhistory/history.c +++ b/src/libs/zbxhistory/history.c @@ -456,3 +456,16 @@ void zbx_history_value2variant(const history_value_t *value, unsigned char value } } +/****************************************************************************** + * * + * Function: zbx_history_check_version * + * * + * Purpose: relays the version retrieval logic to the history implementation * + * functions * + * * + ******************************************************************************/ +void zbx_history_check_version(struct zbx_json *json) +{ + if (NULL != CONFIG_HISTORY_STORAGE_URL) + zbx_elastic_version_extract(json); +} diff --git a/src/libs/zbxhistory/history.h b/src/libs/zbxhistory/history.h index e086fa455db..710b9575d70 100644 --- a/src/libs/zbxhistory/history.h +++ b/src/libs/zbxhistory/history.h @@ -20,6 +20,8 @@ #ifndef ZABBIX_HISTORY_H #define ZABBIX_HISTORY_H +#include "zbxjson.h" + #define ZBX_HISTORY_IFACE_SQL 0 #define ZBX_HISTORY_IFACE_ELASTIC 1 @@ -48,5 +50,7 @@ int zbx_history_sql_init(zbx_history_iface_t *hist, unsigned char value_type, ch /* elastic hist */ int zbx_history_elastic_init(zbx_history_iface_t *hist, unsigned char value_type, char **error); +void zbx_elastic_version_extract(struct zbx_json *json); +zbx_uint32_t zbx_elastic_version_get(void); #endif diff --git a/src/libs/zbxhistory/history_elastic.c b/src/libs/zbxhistory/history_elastic.c index 313de56b563..c55e0a97a69 100644 --- a/src/libs/zbxhistory/history_elastic.c +++ b/src/libs/zbxhistory/history_elastic.c @@ -19,7 +19,6 @@ #include "common.h" #include "log.h" -#include "zbxjson.h" #include "zbxalgo.h" #include "dbcache.h" #include "zbxhistory.h" @@ -34,12 +33,13 @@ #define ZBX_IDX_JSON_ALLOCATE 256 #define ZBX_JSON_ALLOCATE 2048 - const char *value_type_str[] = {"dbl", "str", "log", "uint", "text"}; extern char *CONFIG_HISTORY_STORAGE_URL; extern int CONFIG_HISTORY_STORAGE_PIPELINES; +static zbx_uint32_t ZBX_ELASTIC_SVERSION = ZBX_DBVERSION_UNDEFINED; + typedef struct { char *base_url; @@ -479,7 +479,7 @@ try_again: { int fds; CURLMcode code; - char *error; + char *error; zbx_curlpage_t *curl_page; if (CURLM_OK != (code = curl_multi_perform(writer.handle, &running))) @@ -1015,15 +1015,134 @@ int zbx_history_elastic_init(zbx_history_iface_t *hist, unsigned char value_type return SUCCEED; } -#else +/************************************************************************************ + * * + * Function: zbx_elastic_version_extract * + * * + * Purpose: queries elastic search version and extracts the numeric version from * + * the response string * + * * + ************************************************************************************/ +void zbx_elastic_version_extract(struct zbx_json *json) +{ +#define RIGHT2(x) ((int)((zbx_uint32_t)(x) - ((zbx_uint32_t)((x)/100))*100)) + zbx_httppage_t page; + struct zbx_json_parse jp, jp_values, jp_sub; + struct curl_slist *curl_headers; + CURLcode err; + CURLoption opt; + CURL *handle; + size_t version_len = 0; + char *version_friendly = NULL, errbuf[CURL_ERROR_SIZE]; + int flag, major_num, minor_num, increment_num, ret = FAIL; + zbx_uint32_t version; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + memset(&page, 0, sizeof(zbx_httppage_t)); + + if (0 != curl_global_init(CURL_GLOBAL_ALL)) + { + zabbix_log(LOG_LEVEL_WARNING, "cannot initialize cURL library"); + goto out; + } + + if (NULL == (handle = curl_easy_init())) + { + zabbix_log(LOG_LEVEL_WARNING, "cannot initialize cURL session"); + goto out; + } + + curl_headers = curl_slist_append(NULL, "Content-Type: application/json"); + + if (CURLE_OK != (err = curl_easy_setopt(handle, opt = CURLOPT_URL, CONFIG_HISTORY_STORAGE_URL)) || + CURLE_OK != (err = curl_easy_setopt(handle, opt = CURLOPT_WRITEFUNCTION, curl_write_cb)) || + CURLE_OK != (err = curl_easy_setopt(handle, opt = CURLOPT_WRITEDATA, &page)) || + CURLE_OK != (err = curl_easy_setopt(handle, opt = CURLOPT_HTTPHEADER, curl_headers)) || + CURLE_OK != (err = curl_easy_setopt(handle, opt = CURLOPT_FAILONERROR, 1L)) || + CURLE_OK != (err = curl_easy_setopt(handle, opt = CURLOPT_ERRORBUFFER, errbuf))) + { + zabbix_log(LOG_LEVEL_WARNING, "cannot set cURL option %d: [%s]", (int)opt, curl_easy_strerror(err)); + goto clean; + } + + *errbuf = '\0'; + + if (CURLE_OK != (err = curl_easy_perform(handle))) + { + elastic_log_error(handle, err, errbuf); + goto clean; + + } + if (SUCCEED != zbx_json_open(page.data, &jp) || + SUCCEED != zbx_json_brackets_open(jp.start, &jp_values) || + SUCCEED != zbx_json_brackets_by_name(&jp_values, "version", &jp_sub) || + SUCCEED != zbx_json_value_by_name_dyn(&jp_sub, "number", &version_friendly, &version_len, NULL)) + { + goto clean; + } + + ret = SUCCEED; +clean: + curl_slist_free_all(curl_headers); + curl_easy_cleanup(handle); +out: + if (FAIL == ret) + { + zabbix_log(LOG_LEVEL_CRIT, "Failed to extract ElasticDB version"); + version = ZBX_DBVERSION_UNDEFINED; + } + else + { + zabbix_log(LOG_LEVEL_DEBUG, "ElasticDB version retrieved unparsed: %s", version_friendly); + + if (3 != sscanf(version_friendly, "%d.%d.%d", &major_num, &minor_num, &increment_num) || + major_num >= 100 || major_num <= 0 || minor_num >= 100 || minor_num < 0 || + increment_num >= 100 || increment_num < 0) + { + zabbix_log(LOG_LEVEL_WARNING, "Failed to detect ElasticDB version from the " + "following query result: %s", version_friendly); + version = ZBX_DBVERSION_UNDEFINED; + } + else + { + version = major_num * 10000 + minor_num * 100 + increment_num; + } + } + + flag = zbx_db_version_check("ElasticDB", version, ZBX_ELASTIC_MIN_VERSION, ZBX_DBVERSION_UNDEFINED); + zbx_db_version_json_create(json, "ElasticDB", version_friendly, ZBX_ELASTIC_MIN_VERSION_FRIENDLY, "", flag); + ZBX_ELASTIC_SVERSION = version; + zbx_free(version_friendly); + zbx_free(page.data); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s version:%lu", __func__, zbx_result_string(ret), + (unsigned long)version); +} + +zbx_uint32_t zbx_elastic_version_get(void) +{ + return ZBX_ELASTIC_SVERSION; +} +#else int zbx_history_elastic_init(zbx_history_iface_t *hist, unsigned char value_type, char **error) { ZBX_UNUSED(hist); ZBX_UNUSED(value_type); *error = zbx_strdup(*error, "cURL library support >= 7.28.0 is required for Elasticsearch history backend"); + return FAIL; } +void zbx_elastic_version_extract(struct zbx_json *json) +{ + ZBX_UNUSED(json); +} + +zbx_uint32_t zbx_elastic_version_get(void) +{ + return ZBX_DBVERSION_UNDEFINED; +} #endif diff --git a/src/libs/zbxjson/json.c b/src/libs/zbxjson/json.c index 7f73a05c0aa..5b0e4a6860e 100644 --- a/src/libs/zbxjson/json.c +++ b/src/libs/zbxjson/json.c @@ -875,11 +875,11 @@ static const char *zbx_json_copy_string(const char *p, char *out, size_t size) while ('\0' != *p) { + unsigned int nbytes, i; + unsigned char uc[4]; /* decoded Unicode character takes 1-4 bytes in UTF-8 */ + switch (*p) { - unsigned int nbytes, i; - unsigned char uc[4]; /* decoded Unicode character takes 1-4 bytes in UTF-8 */ - case '\\': ++p; if (0 == (nbytes = zbx_json_decode_character(&p, uc))) diff --git a/src/libs/zbxtrends/cache.c b/src/libs/zbxtrends/cache.c index 797eb56dfc8..f44f37fad79 100644 --- a/src/libs/zbxtrends/cache.c +++ b/src/libs/zbxtrends/cache.c @@ -90,7 +90,7 @@ static void tfc_free_slot(zbx_tfc_slot_t *slot) cache->free_head = index; } -static zbx_tfc_slot_t *tfc_alloc_slot() +static zbx_tfc_slot_t *tfc_alloc_slot(void) { zbx_uint32_t index; @@ -289,7 +289,7 @@ static void tfc_free_data(zbx_tfc_data_t *data) * Purpose: ensure there is a free slot available * * * ******************************************************************************/ -static void tfc_reserve_slot() +static void tfc_reserve_slot(void) { if (UINT32_MAX == cache->free_head && cache->slots_num == cache->free_slot) { diff --git a/src/zabbix_server/events.c b/src/zabbix_server/events.c index 469c7e33939..67e599fa174 100644 --- a/src/zabbix_server/events.c +++ b/src/zabbix_server/events.c @@ -1829,6 +1829,7 @@ void zbx_export_events(void) zbx_json_addint64(&json, ZBX_PROTO_TAG_VALUE, event->value); zbx_json_adduint64(&json, ZBX_PROTO_TAG_EVENTID, event->eventid); zbx_json_addstring(&json, ZBX_PROTO_TAG_NAME, event->name, ZBX_JSON_TYPE_STRING); + zbx_json_addint64(&json, ZBX_PROTO_TAG_SEVERITY, event->severity); db_trigger_get_hosts(&hosts, &event->trigger); diff --git a/src/zabbix_server/server.c b/src/zabbix_server/server.c index f6b8b348f06..acf3b21a482 100644 --- a/src/zabbix_server/server.c +++ b/src/zabbix_server/server.c @@ -1058,6 +1058,23 @@ static void zbx_main_sigusr_handler(int flags) } +static void zbx_check_db(void) +{ + struct zbx_json db_ver; + + zbx_json_initarray(&db_ver, ZBX_JSON_STAT_BUF_LEN); + + if (SUCCEED != DBcheck_capabilities(DBextract_version(&db_ver)) || SUCCEED != DBcheck_version()) + { + zbx_json_free(&db_ver); + exit(EXIT_FAILURE); + } + + zbx_history_check_version(&db_ver); + DBflush_version_requirements(db_ver.buffer); + zbx_json_free(&db_ver); +} + int MAIN_ZABBIX_ENTRY(int flags) { zbx_socket_t listen_sock; @@ -1252,10 +1269,8 @@ int MAIN_ZABBIX_ENTRY(int flags) exit(EXIT_FAILURE); } - DBcheck_capabilities(); + zbx_check_db(); - if (SUCCEED != DBcheck_version()) - exit(EXIT_FAILURE); DBcheck_character_set(); if (SUCCEED == DBcheck_double_type()) diff --git a/tests/libs/zbxdbcache/Makefile.am b/tests/libs/zbxdbcache/Makefile.am index 42ec3ded75b..df2e13eb9d5 100644 --- a/tests/libs/zbxdbcache/Makefile.am +++ b/tests/libs/zbxdbcache/Makefile.am @@ -82,6 +82,8 @@ COMMON_WRAP_FUNCS = \ -Wl,--wrap=zbx_history_add_values \ -Wl,--wrap=zbx_history_sql_init \ -Wl,--wrap=zbx_history_elastic_init \ + -Wl,--wrap=zbx_elastic_version_extract \ + -Wl,--wrap=zbx_elastic_version_get \ -Wl,--wrap=time zbx_vc_get_values_SOURCES = \ diff --git a/tests/libs/zbxhistory/Makefile.am b/tests/libs/zbxhistory/Makefile.am index 6f8f5eacfee..c28a45c55e9 100644 --- a/tests/libs/zbxhistory/Makefile.am +++ b/tests/libs/zbxhistory/Makefile.am @@ -22,6 +22,9 @@ HISTORY_LIBS = \ $(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \ $(top_srcdir)/src/libs/zbxdbhigh/libzbxdbhigh.a \ $(top_srcdir)/src/libs/zbxdb/libzbxdb.a \ + $(top_srcdir)/src/libs/zbxjson/libzbxjson.a \ + $(top_srcdir)/src/libs/zbxregexp/libzbxregexp.a \ + $(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \ $(top_srcdir)/tests/libzbxmockdata.a zbx_history_get_values_SOURCES = \ diff --git a/tests/libs/zbxserver/Makefile.am b/tests/libs/zbxserver/Makefile.am index b4c9a175ce1..17ac0c03494 100755 --- a/tests/libs/zbxserver/Makefile.am +++ b/tests/libs/zbxserver/Makefile.am @@ -139,6 +139,8 @@ VALUECACHE_WRAP_FUNCS = \ -Wl,--wrap=zbx_history_add_values \ -Wl,--wrap=zbx_history_sql_init \ -Wl,--wrap=zbx_history_elastic_init \ + -Wl,--wrap=zbx_elastic_version_extract \ + -Wl,--wrap=zbx_elastic_version_get \ -Wl,--wrap=time \ -Wl,--wrap=substitute_simple_macros \ -Wl,--wrap=DCget_data_expected_from \ diff --git a/tests/mocks/valuecache/valuecache_mock.c b/tests/mocks/valuecache/valuecache_mock.c index f8564929d4f..323bc8fc773 100644 --- a/tests/mocks/valuecache/valuecache_mock.c +++ b/tests/mocks/valuecache/valuecache_mock.c @@ -54,6 +54,8 @@ int __wrap_zbx_history_get_values(zbx_uint64_t itemid, int value_type, int start int __wrap_zbx_history_add_values(const zbx_vector_ptr_t *history); int __wrap_zbx_history_sql_init(zbx_history_iface_t *hist, unsigned char value_type, char **error); int __wrap_zbx_history_elastic_init(zbx_history_iface_t *hist, unsigned char value_type, char **error); +void __wrap_zbx_elastic_version_extract(void); +int __wrap_zbx_elastic_version_get(void); time_t __wrap_time(time_t *ptr); void __wrap_zbx_timespec(zbx_timespec_t *ts); @@ -685,6 +687,15 @@ int __wrap_zbx_history_elastic_init(zbx_history_iface_t *hist, unsigned char val return SUCCEED; } +void __wrap_zbx_elastic_version_extract(void) +{ +} + +int __wrap_zbx_elastic_version_get(void) +{ + return ZBX_DBVERSION_UNDEFINED; +} + /* * cache allocator size limit handling */ diff --git a/ui/include/defines.inc.php b/ui/include/defines.inc.php index f6f8ac3bd0b..faa34521a68 100644 --- a/ui/include/defines.inc.php +++ b/ui/include/defines.inc.php @@ -21,7 +21,7 @@ define('ZABBIX_VERSION', '5.4.0rc1'); define('ZABBIX_API_VERSION', '5.4.0'); define('ZABBIX_EXPORT_VERSION', '5.4'); -define('ZABBIX_DB_VERSION', 5030169); +define('ZABBIX_DB_VERSION', 5030170); define('ZABBIX_COPYRIGHT_FROM', '2001'); define('ZABBIX_COPYRIGHT_TO', '2021'); diff --git a/ui/include/schema.inc.php b/ui/include/schema.inc.php index 69b7237bb63..041f9b75932 100644 --- a/ui/include/schema.inc.php +++ b/ui/include/schema.inc.php @@ -2712,6 +2712,12 @@ return [ 'type' => DB::FIELD_TYPE_CHAR, 'length' => 32, 'default' => '60s' + ], + 'dbversion_status' => [ + 'null' => false, + 'type' => DB::FIELD_TYPE_CHAR, + 'length' => 1024, + 'default' => '' ] ] ], diff --git a/ui/tests/bootstrap.php.template b/ui/tests/bootstrap.php.template index 5ee1a8d5d5d..468b34b683b 100644 --- a/ui/tests/bootstrap.php.template +++ b/ui/tests/bootstrap.php.template @@ -26,6 +26,9 @@ define('PHPUNIT_CONFIG_DIR', '{CONFIG_DIR}'); define('PHPUNIT_COMPONENT_DIR', '{COMPONENT_DIR}'); define('PHPUNIT_PORT_PREFIX', '{PORT_PREFIX}'); +define('PHPUNIT_DATA_DIR', '{DATA_DIR}'); +define('PHPUNIT_DATA_SOURCES_DIR', '{DATA_SOURCES_DIR}'); + // SAML settings. define('PHPUNIT_SAML_TESTS_ENABLED', false); define('PHPUNIT_IDP_ENTITY_ID', '{PHPUNIT_IDP_ENTITY_ID}'); diff --git a/ui/tests/include/CTest.php b/ui/tests/include/CTest.php index 021798b0ee9..78b77aaafd2 100644 --- a/ui/tests/include/CTest.php +++ b/ui/tests/include/CTest.php @@ -25,6 +25,7 @@ require_once dirname(__FILE__).'/../../include/hosts.inc.php'; require_once dirname(__FILE__).'/helpers/CDBHelper.php'; require_once dirname(__FILE__).'/helpers/CAPIHelper.php'; +require_once dirname(__FILE__).'/helpers/CDataHelper.php'; require_once dirname(__FILE__).'/helpers/CExceptionHelper.php'; require_once dirname(__FILE__).'/helpers/CTestArrayHelper.php'; require_once dirname(__FILE__).'/helpers/CDateTimeHelper.php'; @@ -200,6 +201,12 @@ class CTest extends PHPUnit_Framework_TestCase { // Test suite level annotations. $class_annotations = $this->getAnnotationsByType($this->annotations, 'class'); + // Data sources are processed before the backups. + $data_source = $this->getAnnotationTokensByName($class_annotations, 'dataSource'); + if ($data_source) { + CDataHelper::load($data_source); + } + // Backup performed before test suite execution. $suite_backup = $this->getAnnotationTokensByName($class_annotations, 'backup'); @@ -274,6 +281,12 @@ class CTest extends PHPUnit_Framework_TestCase { $method_annotations = $this->getAnnotationsByType($this->annotations, 'method'); if ($method_annotations !== null) { + // Data sources are processed before the backups. + $data_source = $this->getAnnotationTokensByName($method_annotations, 'dataSource'); + if ($data_source) { + CDataHelper::load($data_source); + } + // Backup performed before every test case execution. $case_backup = $this->getAnnotationTokensByName($method_annotations, 'backup'); diff --git a/ui/tests/include/helpers/CDataHelper.php b/ui/tests/include/helpers/CDataHelper.php index 764ab0c9c81..6814d576012 100644 --- a/ui/tests/include/helpers/CDataHelper.php +++ b/ui/tests/include/helpers/CDataHelper.php @@ -26,6 +26,7 @@ require_once dirname(__FILE__).'/../../../include/hosts.inc.php'; class CDataHelper extends CAPIHelper { + protected static $data = null; protected static $request = []; protected static $response = []; @@ -216,4 +217,86 @@ class CDataHelper extends CAPIHelper { return $result; } + + /** + * Load the data source data from the file cache. + */ + protected static function preload() { + if (static::$data === null) { + static::$data = []; + + if (!defined('PHPUNIT_DATA_DIR')) { + return; + } + + foreach (new DirectoryIterator(PHPUNIT_DATA_DIR) as $file) { + if ($file->isDot() || $file->isDir() || strtolower($file->getExtension()) !== 'json') { + continue; + } + + $name = $file->getBasename('.'.$file->getExtension()); + static::$data[$name] = json_decode(file_get_contents($file->getPathname()), true); + } + } + } + + /** + * Get data from the data sources. + * + * @param mixed $path data path to look for + * @param mixed $default default value to be returned if data doesn't exist + * + * @return mixed + */ + public static function get($path, $default = null) { + return CTestArrayHelper::get(static::$data, $path, $default); + } + + /** + * Load specific data source data. + * + * @param mixed $source name of the data source(s) + * + * @return boolean + * + * @throws \Exception + */ + public static function load($source) { + if (is_array($source)) { + $result = true; + foreach ($source as $name) { + $result &= static::load($name); + } + + return $result; + } + + static::preload(); + + if (array_key_exists($source, static::$data)) { + return true; + } + + try { + $path = PHPUNIT_DATA_SOURCES_DIR.$source.'.php'; + if (!file_exists($path)) { + throw new \Exception('File "'.$path.'" doesn\'t exist.'); + } + + require_once $path; + static::$data[$source] = forward_static_call([$source, 'load']); + + if (defined('PHPUNIT_DATA_DIR')) { + $data = json_encode(static::get($source)); + file_put_contents(PHPUNIT_DATA_DIR.$source.'.json', $data); + } + } + catch (\Exception $e) { + echo 'Failed to load data from data source "'.$source.'".'."\n\n".$e->getMessage()."\n".$e->getTraceAsString(); + + return false; + } + + return true; + } } |