Table definition consumed by * api_plugin_db_table_create()/db_update_table(). */ function monitor_notify_history_table_data(): array { $data = []; $data['columns'][] = ['name' => 'id', 'type' => 'int(10)', 'unsigned' => true, 'NULL' => false, 'auto_increment' => true]; $data['columns'][] = ['name' => 'host_id', 'type' => 'int(10)', 'unsigned' => true, 'NULL' => true, 'default' => null]; $data['columns'][] = ['name' => 'notify_type', 'type' => 'tinyint(3)', 'unsigned' => true, 'NULL' => true, 'default' => null]; $data['columns'][] = ['name' => 'ping_time', 'type' => 'double', 'NULL' => true, 'default' => null]; $data['columns'][] = ['name' => 'ping_threshold', 'type' => 'int(10)', 'unsigned' => true, 'NULL' => true, 'default' => null]; $data['columns'][] = ['name' => 'notification_time', 'type' => 'timestamp', 'NULL' => false, 'default' => '0000-00-00 00:00:00']; $data['columns'][] = ['name' => 'notes', 'type' => 'varchar(255)', 'NULL' => true, 'default' => null]; $data['primary'] = ['id']; $data['unique_keys'][] = ['name' => 'unique_key', 'columns' => ['host_id', 'notify_type', 'notification_time']]; $data['type'] = 'InnoDB'; $data['comment'] = 'Stores Notification Event History'; return $data; } /** * The plugin_monitor_reboot_history table definition (one row per detected * device reboot). * * @return array Table definition. */ function monitor_reboot_history_table_data(): array { $data = []; $data['columns'][] = ['name' => 'id', 'type' => 'int(10)', 'unsigned' => true, 'NULL' => false, 'auto_increment' => true]; $data['columns'][] = ['name' => 'host_id', 'type' => 'int(10)', 'unsigned' => true, 'NULL' => true, 'default' => null]; $data['columns'][] = ['name' => 'reboot_time', 'type' => 'timestamp', 'NULL' => false, 'default' => '0000-00-00 00:00:00']; $data['columns'][] = ['name' => 'log_time', 'type' => 'timestamp', 'NULL' => false, 'default' => 'CURRENT_TIMESTAMP']; $data['primary'] = ['id']; $data['keys'][] = ['name' => 'host_id', 'columns' => ['host_id']]; $data['keys'][] = ['name' => 'log_time', 'columns' => ['log_time']]; $data['keys'][] = ['name' => 'reboot_time', 'columns' => ['reboot_time']]; $data['type'] = 'InnoDB'; $data['comment'] = 'Keeps Track of Device Reboot Times'; return $data; } /** * The plugin_monitor_uptime table definition (last known uptime per * device). Uses the current column layout (uptime NOT NULL). * * @return array Table definition. */ function monitor_uptime_table_data(): array { $data = []; $data['columns'][] = ['name' => 'host_id', 'type' => 'int(10)', 'unsigned' => true, 'NULL' => false, 'default' => 0]; $data['columns'][] = ['name' => 'uptime', 'type' => 'bigint(20)', 'unsigned' => true, 'NULL' => false, 'default' => 0]; $data['primary'] = ['host_id']; $data['keys'][] = ['name' => 'uptime', 'columns' => ['uptime']]; $data['type'] = 'InnoDB'; $data['comment'] = 'Keeps Track of the Devices last uptime to track agent restarts and reboots'; return $data; } /** * The plugin_monitor_dashboards table definition (per-user predefined * dashboards). * * @return array Table definition. */ function monitor_dashboards_table_data(): array { $data = []; $data['columns'][] = ['name' => 'id', 'type' => 'int(10)', 'unsigned' => true, 'NULL' => false, 'auto_increment' => true]; $data['columns'][] = ['name' => 'user_id', 'type' => 'int(10)', 'unsigned' => true, 'NULL' => true, 'default' => 0]; $data['columns'][] = ['name' => 'name', 'type' => 'varchar(128)', 'NULL' => true, 'default' => '']; $data['columns'][] = ['name' => 'properties', 'type' => 'varchar(4096)', 'NULL' => true, 'default' => '']; $data['primary'] = ['id']; $data['keys'][] = ['name' => 'user_id', 'columns' => ['user_id']]; $data['type'] = 'InnoDB'; $data['comment'] = 'Stores predefined dashboard information for a user or users'; return $data; } /** * Returns a copy of a table definition with an array-valued 'primary' * flattened to the backtick-joined scalar form api_plugin_db_table_create() * expects. Down to this plugin's Cacti 1.2.29 compat floor that API * interpolates $data['primary'] straight into PRIMARY KEY (`...`), so an * array would render as PRIMARY KEY (`Array`) and fail the create. The array * form is kept in the *_table_data() definitions for db_update_table(). * * @param array $data The table definition (array primary). * * @return array The definition with a scalar primary key. */ function monitor_create_definition(array $data): array { if (isset($data['primary']) && is_array($data['primary'])) { $data['primary'] = implode('`,`', $data['primary']); } return $data; } /** * Parse a legacy dashboard url string (monitor.php?a=b&c=d) into the current * properties structure, a JSON object of the dashboard's filter variables. * * @param string $url Legacy stored url value. * * @return array{vars: array} */ function monitor_url_to_properties(string $url): array { $url = str_replace('monitor.php?', '', (string) $url); $vars = []; if ($url !== '') { foreach (explode('&', $url) as $pair) { $kv = explode('=', $pair, 2); if ($kv[0] !== '' && isset($kv[1])) { $vars[$kv[0]] = urldecode($kv[1]); } } } return ['vars' => $vars]; } /** * Restructure plugin_monitor_dashboards from the legacy raw-url column to the * JSON `properties` column: add the column, migrate each row's url into the * properties structure, then drop the now-redundant url column. * * @return void */ function monitor_migrate_dashboard_properties() { if (!db_table_exists('plugin_monitor_dashboards')) { return; } if (!db_column_exists('plugin_monitor_dashboards', 'properties')) { api_plugin_db_add_column('monitor', 'plugin_monitor_dashboards', ['name' => 'properties', 'type' => 'varchar(4096)', 'NULL' => true, 'default' => '', 'after' => 'name']); } if (db_column_exists('plugin_monitor_dashboards', 'url')) { $rows = db_fetch_assoc("SELECT id, url FROM plugin_monitor_dashboards WHERE properties IS NULL OR properties = ''"); if (cacti_sizeof($rows)) { foreach ($rows as $r) { db_execute_prepared('UPDATE plugin_monitor_dashboards SET properties = ? WHERE id = ?', [json_encode(monitor_url_to_properties($r['url'])), $r['id']]); } } db_remove_column('plugin_monitor_dashboards', 'url'); } } /** * Removes the plugin_db_changes 'create' ownership record for the user-owned * dashboards table so api_plugin_db_changes_remove() (run by * api_plugin_uninstall()) does not drop it, preserving user dashboards across * an uninstall. * * @return void */ function monitor_disown_dashboards_table() { db_execute("DELETE FROM plugin_db_changes WHERE plugin = 'monitor' AND `table` = 'plugin_monitor_dashboards' AND method = 'create'"); } /** * Creates this plugin's own tables through Cacti's tracked plugin table * API and ensures the core host table carries the monitoring columns this * plugin relies on. Called from plugin_monitor_install() and (idempotently) * from monitor_check_upgrade(). * * @return void */ function monitor_setup_table() { api_plugin_db_table_create('monitor', 'plugin_monitor_notify_history', monitor_create_definition(monitor_notify_history_table_data())); api_plugin_db_table_create('monitor', 'plugin_monitor_reboot_history', monitor_create_definition(monitor_reboot_history_table_data())); api_plugin_db_table_create('monitor', 'plugin_monitor_uptime', monitor_create_definition(monitor_uptime_table_data())); api_plugin_db_table_create('monitor', 'plugin_monitor_dashboards', monitor_create_definition(monitor_dashboards_table_data())); /* dashboards holds user data: create it but do not record plugin ownership, so uninstall preserves it. */ monitor_disown_dashboards_table(); if (db_table_exists('host')) { $row_format = db_fetch_cell("SELECT ROW_FORMAT FROM information_schema.tables WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'host'"); if (strtoupper((string) $row_format) !== 'DYNAMIC') { db_execute('ALTER TABLE host ROW_FORMAT=DYNAMIC'); } } db_execute('SET SESSION innodb_strict_mode=0'); api_plugin_db_add_column('monitor', 'host', ['name' => 'monitor', 'type' => 'char(3)', 'NULL' => true, 'default' => 'on']); api_plugin_db_add_column('monitor', 'host', ['name' => 'monitor_text', 'type' => 'text', 'NULL' => false]); api_plugin_db_add_column('monitor', 'host', ['name' => 'monitor_criticality', 'type' => 'tinyint', 'unsigned' => true, 'NULL' => false, 'default' => '0']); api_plugin_db_add_column('monitor', 'host', ['name' => 'monitor_warn', 'type' => 'double', 'NULL' => false, 'default' => '0']); api_plugin_db_add_column('monitor', 'host', ['name' => 'monitor_alert', 'type' => 'double', 'NULL' => false, 'default' => '0']); api_plugin_db_add_column('monitor', 'host', ['name' => 'monitor_icon', 'type' => 'varchar(30)', 'NULL' => false, 'default' => '']); db_execute('SET SESSION innodb_strict_mode=1'); } /** * Refreshes this plugin's own tables to their current definition on * upgrade: db_update_table() diffs the live schema against the definition * and issues the exact ALTER when the table already exists, otherwise the * table is created outright. Called from monitor_check_upgrade(). * * @return void */ function monitor_upgrade_tables() { monitor_migrate_dashboard_properties(); $tables = [ 'plugin_monitor_notify_history' => monitor_notify_history_table_data(), 'plugin_monitor_reboot_history' => monitor_reboot_history_table_data(), 'plugin_monitor_uptime' => monitor_uptime_table_data(), 'plugin_monitor_dashboards' => monitor_dashboards_table_data(), ]; foreach ($tables as $table => $table_data) { if (db_table_exists($table)) { db_update_table($table, $table_data); } else { api_plugin_db_table_create('monitor', $table, monitor_create_definition($table_data)); } } monitor_disown_dashboards_table(); } /** * Drops the tables this plugin owns that hold transient monitoring state * (notification/reboot history and uptime). The user-defined dashboards * table is intentionally left in place. Called from * plugin_monitor_uninstall(). * * @return void */ function monitor_drop_tables() { db_execute('DROP TABLE IF EXISTS plugin_monitor_notify_history'); db_execute('DROP TABLE IF EXISTS plugin_monitor_reboot_history'); db_execute('DROP TABLE IF EXISTS plugin_monitor_uptime'); }