From c2cdb82fc46d162759ce3cad9a80d543e25f59d2 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Tue, 23 Mar 2021 16:18:10 +0100 Subject: [PATCH 1/2] Introduce types.NotificationTypes --- pkg/icingadb/v1/notification.go | 20 ++++----- pkg/icingadb/v1/user.go | 16 +++---- pkg/types/notification_types.go | 79 +++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 18 deletions(-) create mode 100644 pkg/types/notification_types.go diff --git a/pkg/icingadb/v1/notification.go b/pkg/icingadb/v1/notification.go index e3256ec5..048e653a 100644 --- a/pkg/icingadb/v1/notification.go +++ b/pkg/icingadb/v1/notification.go @@ -9,16 +9,16 @@ type Notification struct { EntityWithChecksum `json:",inline"` EnvironmentMeta `json:",inline"` NameCiMeta `json:",inline"` - HostId types.Binary `json:"host_id"` - ServiceId types.Binary `json:"service_id"` - CommandId types.Binary `json:"command_id"` - TimesBegin types.Int `json:"times_begin"` - TimesEnd types.Int `json:"times_end"` - NotificationInterval uint32 `json:"notification_interval"` - TimeperiodId types.Binary `json:"timeperiod_id"` - States uint8 `json:"states"` - Types uint16 `json:"types"` - ZoneId types.Binary `json:"zone_id"` + HostId types.Binary `json:"host_id"` + ServiceId types.Binary `json:"service_id"` + CommandId types.Binary `json:"command_id"` + TimesBegin types.Int `json:"times_begin"` + TimesEnd types.Int `json:"times_end"` + NotificationInterval uint32 `json:"notification_interval"` + TimeperiodId types.Binary `json:"timeperiod_id"` + States uint8 `json:"states"` + Types types.NotificationTypes `json:"types"` + ZoneId types.Binary `json:"zone_id"` } type NotificationUser struct { diff --git a/pkg/icingadb/v1/user.go b/pkg/icingadb/v1/user.go index 96e61688..d2d35e36 100644 --- a/pkg/icingadb/v1/user.go +++ b/pkg/icingadb/v1/user.go @@ -9,14 +9,14 @@ type User struct { EntityWithChecksum `json:",inline"` EnvironmentMeta `json:",inline"` NameCiMeta `json:",inline"` - DisplayName string `json:"display_name"` - Email string `json:"email"` - Pager string `json:"pager"` - NotificationsEnabled types.Bool `json:"notifications_enabled"` - TimeperiodId types.Binary `json:"timeperiod_id"` - States uint8 `json:"states"` - Types uint16 `json:"types"` - ZoneId types.Binary `json:"zone_id"` + DisplayName string `json:"display_name"` + Email string `json:"email"` + Pager string `json:"pager"` + NotificationsEnabled types.Bool `json:"notifications_enabled"` + TimeperiodId types.Binary `json:"timeperiod_id"` + States uint8 `json:"states"` + Types types.NotificationTypes `json:"types"` + ZoneId types.Binary `json:"zone_id"` } type UserCustomvar struct { diff --git a/pkg/types/notification_types.go b/pkg/types/notification_types.go new file mode 100644 index 00000000..f6b8714f --- /dev/null +++ b/pkg/types/notification_types.go @@ -0,0 +1,79 @@ +package types + +import ( + "database/sql/driver" + "encoding/json" + "fmt" +) + +// NotificationTypes specifies the set of reasons a notification may be sent for. +type NotificationTypes uint16 + +// UnmarshalJSON implements the json.Unmarshaler interface. +func (nt *NotificationTypes) UnmarshalJSON(bytes []byte) error { + var types []string + if err := json.Unmarshal(bytes, &types); err != nil { + return err + } + + var n NotificationTypes + for _, typ := range types { + if v, ok := notificationTypeNames[typ]; ok { + n |= v + } else { + return BadNotificationTypes{types} + } + } + + *nt = n + return nil +} + +// Value implements the driver.Valuer interface. +func (nt NotificationTypes) Value() (driver.Value, error) { + if nt&^allNotificationTypes == 0 { + return int64(nt), nil + } else { + return nil, BadNotificationTypes{nt} + } +} + +// BadNotificationTypes complains about syntactically, but not semantically valid NotificationTypes. +type BadNotificationTypes struct { + Types interface{} +} + +// Error implements the error interface. +func (bnt BadNotificationTypes) Error() string { + return fmt.Sprintf("bad notification types: %#v", bnt.Types) +} + +// notificationTypeNames maps all valid NotificationTypes values to their SQL representation. +var notificationTypeNames = map[string]NotificationTypes{ + "DowntimeStart": 1, + "DowntimeEnd": 2, + "DowntimeRemoved": 4, + "Custom": 8, + "Acknowledgement": 16, + "Problem": 32, + "Recovery": 64, + "FlappingStart": 128, + "FlappingEnd": 256, +} + +// allNotificationTypes is the largest valid NotificationTypes value. +var allNotificationTypes = func() NotificationTypes { + var nt NotificationTypes + for _, v := range notificationTypeNames { + nt |= v + } + + return nt +}() + +// Assert interface compliance. +var ( + _ error = BadNotificationTypes{} + _ json.Unmarshaler = (*NotificationTypes)(nil) + _ driver.Valuer = NotificationTypes(0) +) From d782d41b796263b9d999a85ab7f75ae8df22de2f Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Tue, 23 Mar 2021 16:23:51 +0100 Subject: [PATCH 2/2] Introduce types.NotificationStates --- pkg/icingadb/v1/notification.go | 20 ++++----- pkg/icingadb/v1/user.go | 16 +++---- pkg/types/notification_states.go | 76 ++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 18 deletions(-) create mode 100644 pkg/types/notification_states.go diff --git a/pkg/icingadb/v1/notification.go b/pkg/icingadb/v1/notification.go index 048e653a..a733605b 100644 --- a/pkg/icingadb/v1/notification.go +++ b/pkg/icingadb/v1/notification.go @@ -9,16 +9,16 @@ type Notification struct { EntityWithChecksum `json:",inline"` EnvironmentMeta `json:",inline"` NameCiMeta `json:",inline"` - HostId types.Binary `json:"host_id"` - ServiceId types.Binary `json:"service_id"` - CommandId types.Binary `json:"command_id"` - TimesBegin types.Int `json:"times_begin"` - TimesEnd types.Int `json:"times_end"` - NotificationInterval uint32 `json:"notification_interval"` - TimeperiodId types.Binary `json:"timeperiod_id"` - States uint8 `json:"states"` - Types types.NotificationTypes `json:"types"` - ZoneId types.Binary `json:"zone_id"` + HostId types.Binary `json:"host_id"` + ServiceId types.Binary `json:"service_id"` + CommandId types.Binary `json:"command_id"` + TimesBegin types.Int `json:"times_begin"` + TimesEnd types.Int `json:"times_end"` + NotificationInterval uint32 `json:"notification_interval"` + TimeperiodId types.Binary `json:"timeperiod_id"` + States types.NotificationStates `json:"states"` + Types types.NotificationTypes `json:"types"` + ZoneId types.Binary `json:"zone_id"` } type NotificationUser struct { diff --git a/pkg/icingadb/v1/user.go b/pkg/icingadb/v1/user.go index d2d35e36..4bdf5b93 100644 --- a/pkg/icingadb/v1/user.go +++ b/pkg/icingadb/v1/user.go @@ -9,14 +9,14 @@ type User struct { EntityWithChecksum `json:",inline"` EnvironmentMeta `json:",inline"` NameCiMeta `json:",inline"` - DisplayName string `json:"display_name"` - Email string `json:"email"` - Pager string `json:"pager"` - NotificationsEnabled types.Bool `json:"notifications_enabled"` - TimeperiodId types.Binary `json:"timeperiod_id"` - States uint8 `json:"states"` - Types types.NotificationTypes `json:"types"` - ZoneId types.Binary `json:"zone_id"` + DisplayName string `json:"display_name"` + Email string `json:"email"` + Pager string `json:"pager"` + NotificationsEnabled types.Bool `json:"notifications_enabled"` + TimeperiodId types.Binary `json:"timeperiod_id"` + States types.NotificationStates `json:"states"` + Types types.NotificationTypes `json:"types"` + ZoneId types.Binary `json:"zone_id"` } type UserCustomvar struct { diff --git a/pkg/types/notification_states.go b/pkg/types/notification_states.go new file mode 100644 index 00000000..ab3ce589 --- /dev/null +++ b/pkg/types/notification_states.go @@ -0,0 +1,76 @@ +package types + +import ( + "database/sql/driver" + "encoding/json" + "fmt" +) + +// NotificationStates specifies the set of states a notification may be sent for. +type NotificationStates uint8 + +// UnmarshalJSON implements the json.Unmarshaler interface. +func (nst *NotificationStates) UnmarshalJSON(bytes []byte) error { + var states []string + if err := json.Unmarshal(bytes, &states); err != nil { + return err + } + + var n NotificationStates + for _, state := range states { + if v, ok := notificationStateNames[state]; ok { + n |= v + } else { + return BadNotificationStates{states} + } + } + + *nst = n + return nil +} + +// Value implements the driver.Valuer interface. +func (nst NotificationStates) Value() (driver.Value, error) { + if nst&^allNotificationStates == 0 { + return int64(nst), nil + } else { + return nil, BadNotificationStates{nst} + } +} + +// BadNotificationStates complains about syntactically, but not semantically valid NotificationStates. +type BadNotificationStates struct { + States interface{} +} + +// Error implements the error interface. +func (bns BadNotificationStates) Error() string { + return fmt.Sprintf("bad notification states: %#v", bns.States) +} + +// notificationStateNames maps all valid NotificationStates values to their SQL representation. +var notificationStateNames = map[string]NotificationStates{ + "OK": 1, + "Warning": 2, + "Critical": 4, + "Unknown": 8, + "Up": 16, + "Down": 32, +} + +// allNotificationStates is the largest valid NotificationStates value. +var allNotificationStates = func() NotificationStates { + var nt NotificationStates + for _, v := range notificationStateNames { + nt |= v + } + + return nt +}() + +// Assert interface compliance. +var ( + _ error = BadNotificationStates{} + _ json.Unmarshaler = (*NotificationStates)(nil) + _ driver.Valuer = NotificationStates(0) +)