diff --git a/cmd/icingadb-migrate/convert.go b/cmd/icingadb-migrate/convert.go index 64a6b3498..5cfa7bdcb 100644 --- a/cmd/icingadb-migrate/convert.go +++ b/cmd/icingadb-migrate/convert.go @@ -724,8 +724,8 @@ type stateRow = struct { StateTimeUsec uint32 State uint8 StateType uint8 - CurrentCheckAttempt uint16 - MaxCheckAttempts uint16 + CurrentCheckAttempt uint32 + MaxCheckAttempts uint32 LastState uint8 LastHardState uint8 Output sql.NullString @@ -798,10 +798,10 @@ func convertStateRows( HardState: row.LastHardState, PreviousSoftState: row.LastState, PreviousHardState: previousHardState, - CheckAttempt: uint8(row.CurrentCheckAttempt), + CheckAttempt: row.CurrentCheckAttempt, Output: icingadbTypes.String{NullString: row.Output}, LongOutput: icingadbTypes.String{NullString: row.LongOutput}, - MaxCheckAttempts: uint32(row.MaxCheckAttempts), + MaxCheckAttempts: row.MaxCheckAttempts, CheckSource: icingadbTypes.String{NullString: row.CheckSource}, }) diff --git a/doc/04-Upgrading.md b/doc/04-Upgrading.md index 5a085e027..cd74de96f 100644 --- a/doc/04-Upgrading.md +++ b/doc/04-Upgrading.md @@ -3,6 +3,47 @@ Specific version upgrades are described below. Please note that version upgrades are incremental. If you are upgrading across multiple versions, make sure to follow the steps for each of them. +## Upgrading to Icinga DB v1.1.2 + +Please apply the `1.1.2.sql` upgrade script to your database. +For package installations, you can find this file at `/usr/share/icingadb/schema/mysql/upgrades/` or +`/usr/share/icingadb/schema/pgsql/upgrades/`, depending on your database type. + +As the daemon checks the schema version, the recommended way to perform the upgrade is to stop the daemon, apply the +schema upgrade and then start the new daemon version. If you want to minimize downtime as much as possible, it is safe +to apply this schema upgrade while the Icinga DB v1.1.1 daemon is still running and then restart the daemon with the +new version. Please keep in mind that depending on the distribution, your package manager may automatically attempt to +restart the daemon when upgrading the package. + +### Upgrading the state_history Table (optional) + +Icinga DB 1.1.1 already handles hosts/services' `max_check_attempts` above 255. +But actual soft state changes with check attempt above 255 in your history will crash even Icinga DB 1.1.2 +(see [#655](https://github.com/Icinga/icingadb/issues/655)). +To avoid the latter, you can lower `max_check_attempts`. Optionally increase the respective `retry_interval` +not to change the timespan from an outage to a hard state (`max_check_attempts x retry_interval`). + +If lower `max_check_attempts` are not an option, you'll have to execute the SQL statements below. +Note that this can take a lot of time depending on the history size and the performance of the database. +Do not interrupt them! While the upgrade is running, that table will be locked and can't be accessed. +This means that the existing history can't be viewed in Icinga Web and new history entries will be buffered in Redis. + +This optional schema upgrade can be applied independent of the `max_check_attempts` setting, for completeness. +But, for the above reasons, do it during the next longer maintenance window. + +#### MySQL + +```mysql +ALTER TABLE state_history MODIFY COLUMN check_attempt int unsigned NOT NULL; +``` + +#### PostgreSQL + +```postgresql +ALTER TABLE state_history ALTER COLUMN check_attempt TYPE uint; +COMMENT ON COLUMN state_history.check_attempt IS NULL; +``` + ## Upgrading to Icinga DB v1.1.1 Please apply the `1.1.1.sql` upgrade script to your database. diff --git a/pkg/icingadb/db.go b/pkg/icingadb/db.go index 4ff3e0dde..4640f2595 100644 --- a/pkg/icingadb/db.go +++ b/pkg/icingadb/db.go @@ -85,8 +85,8 @@ func NewDb(db *sqlx.DB, logger *logging.Logger, options *Options) *DB { } const ( - expectedMysqlSchemaVersion = 4 - expectedPostgresSchemaVersion = 2 + expectedMysqlSchemaVersion = 5 + expectedPostgresSchemaVersion = 3 ) // CheckSchema asserts the database schema of the expected version being present. diff --git a/pkg/icingadb/v1/checkable.go b/pkg/icingadb/v1/checkable.go index dbb114cbc..4b1efeb9c 100644 --- a/pkg/icingadb/v1/checkable.go +++ b/pkg/icingadb/v1/checkable.go @@ -30,7 +30,7 @@ type Checkable struct { IconImageAlt string `json:"icon_image_alt"` IconImageId types.Binary `json:"icon_image_id"` IsVolatile types.Bool `json:"is_volatile"` - MaxCheckAttempts float64 `json:"max_check_attempts"` + MaxCheckAttempts uint32 `json:"max_check_attempts"` Notes string `json:"notes"` NotesUrlId types.Binary `json:"notes_url_id"` NotificationsEnabled types.Bool `json:"notifications_enabled"` diff --git a/pkg/icingadb/v1/history/state.go b/pkg/icingadb/v1/history/state.go index dec13b042..6320b738a 100644 --- a/pkg/icingadb/v1/history/state.go +++ b/pkg/icingadb/v1/history/state.go @@ -14,7 +14,7 @@ type StateHistory struct { HardState uint8 `json:"hard_state"` PreviousSoftState uint8 `json:"previous_soft_state"` PreviousHardState uint8 `json:"previous_hard_state"` - CheckAttempt uint8 `json:"check_attempt"` + CheckAttempt uint32 `json:"check_attempt"` Output types.String `json:"output"` LongOutput types.String `json:"long_output"` MaxCheckAttempts uint32 `json:"max_check_attempts"` diff --git a/pkg/icingadb/v1/state.go b/pkg/icingadb/v1/state.go index bad8f28c5..983b14d5a 100644 --- a/pkg/icingadb/v1/state.go +++ b/pkg/icingadb/v1/state.go @@ -9,7 +9,7 @@ type State struct { EnvironmentMeta `json:",inline"` AcknowledgementCommentId types.Binary `json:"acknowledgement_comment_id"` LastCommentId types.Binary `json:"last_comment_id"` - CheckAttempt uint8 `json:"check_attempt"` + CheckAttempt uint32 `json:"check_attempt"` CheckCommandline types.String `json:"check_commandline"` CheckSource types.String `json:"check_source"` SchedulingSource types.String `json:"scheduling_source"` diff --git a/schema/mysql/schema.sql b/schema/mysql/schema.sql index 26ae3940d..95f047e58 100644 --- a/schema/mysql/schema.sql +++ b/schema/mysql/schema.sql @@ -292,7 +292,7 @@ CREATE TABLE host_state ( hard_state tinyint unsigned NOT NULL, previous_soft_state tinyint unsigned NOT NULL, previous_hard_state tinyint unsigned NOT NULL, - check_attempt tinyint unsigned NOT NULL, + check_attempt int unsigned NOT NULL, severity smallint unsigned NOT NULL, output longtext DEFAULT NULL, @@ -460,7 +460,7 @@ CREATE TABLE service_state ( hard_state tinyint unsigned NOT NULL, previous_soft_state tinyint unsigned NOT NULL, previous_hard_state tinyint unsigned NOT NULL, - check_attempt tinyint unsigned NOT NULL, + check_attempt int unsigned NOT NULL, severity smallint unsigned NOT NULL, output longtext DEFAULT NULL, @@ -1147,7 +1147,7 @@ CREATE TABLE state_history ( hard_state tinyint unsigned NOT NULL, previous_soft_state tinyint unsigned NOT NULL, previous_hard_state tinyint unsigned NOT NULL, - check_attempt tinyint unsigned NOT NULL, + check_attempt int unsigned NOT NULL, -- may be a tinyint unsigned, see https://icinga.com/docs/icinga-db/latest/doc/04-Upgrading/#upgrading-to-icinga-db-v112 output longtext DEFAULT NULL, long_output longtext DEFAULT NULL, max_check_attempts int unsigned NOT NULL, @@ -1343,4 +1343,4 @@ CREATE TABLE icingadb_schema ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC; INSERT INTO icingadb_schema (version, timestamp) - VALUES (4, UNIX_TIMESTAMP() * 1000); + VALUES (5, UNIX_TIMESTAMP() * 1000); diff --git a/schema/mysql/upgrades/1.1.2.sql b/schema/mysql/upgrades/1.1.2.sql index 9f5edd5fa..51ba9567a 100644 --- a/schema/mysql/upgrades/1.1.2.sql +++ b/schema/mysql/upgrades/1.1.2.sql @@ -1 +1,10 @@ +ALTER TABLE host_state MODIFY COLUMN check_attempt int unsigned NOT NULL; + +ALTER TABLE service_state MODIFY COLUMN check_attempt int unsigned NOT NULL; + +ALTER TABLE state_history MODIFY COLUMN check_attempt tinyint unsigned NOT NULL COMMENT 'optional schema upgrade not applied yet, see https://icinga.com/docs/icinga-db/latest/doc/04-Upgrading/#upgrading-to-icinga-db-v112'; + UPDATE icingadb_schema SET timestamp = UNIX_TIMESTAMP(timestamp / 1000) * 1000 WHERE timestamp > 20000000000000000; + +INSERT INTO icingadb_schema (version, timestamp) + VALUES (5, UNIX_TIMESTAMP() * 1000); diff --git a/schema/mysql/upgrades/optional/1.1.2-history.sql b/schema/mysql/upgrades/optional/1.1.2-history.sql new file mode 100644 index 000000000..4081fcb21 --- /dev/null +++ b/schema/mysql/upgrades/optional/1.1.2-history.sql @@ -0,0 +1 @@ +ALTER TABLE state_history MODIFY COLUMN check_attempt int unsigned NOT NULL; diff --git a/schema/pgsql/schema.sql b/schema/pgsql/schema.sql index 13021031a..5b1bfc887 100644 --- a/schema/pgsql/schema.sql +++ b/schema/pgsql/schema.sql @@ -405,7 +405,7 @@ CREATE TABLE host_state ( hard_state tinyuint NOT NULL, previous_soft_state tinyuint NOT NULL, previous_hard_state tinyuint NOT NULL, - check_attempt tinyuint NOT NULL, + check_attempt uint NOT NULL, severity smalluint NOT NULL, output text DEFAULT NULL, @@ -675,7 +675,7 @@ CREATE TABLE service_state ( hard_state tinyuint NOT NULL, previous_soft_state tinyuint NOT NULL, previous_hard_state tinyuint NOT NULL, - check_attempt tinyuint NOT NULL, + check_attempt uint NOT NULL, severity smalluint NOT NULL, output text DEFAULT NULL, @@ -1846,7 +1846,7 @@ CREATE TABLE state_history ( hard_state tinyuint NOT NULL, previous_soft_state tinyuint NOT NULL, previous_hard_state tinyuint NOT NULL, - check_attempt tinyuint NOT NULL, + check_attempt uint NOT NULL, -- may be a tinyuint, see https://icinga.com/docs/icinga-db/latest/doc/04-Upgrading/#upgrading-to-icinga-db-v112 output text DEFAULT NULL, long_output text DEFAULT NULL, max_check_attempts uint NOT NULL, @@ -2181,4 +2181,4 @@ CREATE TABLE icingadb_schema ( ALTER SEQUENCE icingadb_schema_id_seq OWNED BY icingadb_schema.id; INSERT INTO icingadb_schema (version, timestamp) - VALUES (2, extract(epoch from now()) * 1000); + VALUES (3, extract(epoch from now()) * 1000); diff --git a/schema/pgsql/upgrades/1.1.2.sql b/schema/pgsql/upgrades/1.1.2.sql index ea619ec4c..407d9a039 100644 --- a/schema/pgsql/upgrades/1.1.2.sql +++ b/schema/pgsql/upgrades/1.1.2.sql @@ -137,3 +137,12 @@ BEGIN RETURN (100 * (total_time - problem_time)::decimal / total_time)::decimal(7, 4); END; $$; + +ALTER TABLE host_state ALTER COLUMN check_attempt TYPE uint; + +ALTER TABLE service_state ALTER COLUMN check_attempt TYPE uint; + +COMMENT ON COLUMN state_history.check_attempt IS 'optional schema upgrade not applied yet, see https://icinga.com/docs/icinga-db/latest/doc/04-Upgrading/#upgrading-to-icinga-db-v112'; + +INSERT INTO icingadb_schema (version, timestamp) + VALUES (3, extract(epoch from now()) * 1000); diff --git a/schema/pgsql/upgrades/optional/1.1.2-history.sql b/schema/pgsql/upgrades/optional/1.1.2-history.sql new file mode 100644 index 000000000..ea95765a0 --- /dev/null +++ b/schema/pgsql/upgrades/optional/1.1.2-history.sql @@ -0,0 +1,3 @@ +ALTER TABLE state_history ALTER COLUMN check_attempt TYPE uint; + +COMMENT ON COLUMN state_history.check_attempt IS NULL;