diff --git a/pkg/icingadb/v1/host.go b/pkg/icingadb/v1/host.go index b65cba05..b4cf86a0 100644 --- a/pkg/icingadb/v1/host.go +++ b/pkg/icingadb/v1/host.go @@ -69,6 +69,11 @@ type HostCustomvar struct { HostId types.Binary `json:"object_id"` } +type HostState struct { + State `json:",inline"` + HostId types.Binary `json:"object_id"` +} + type Hostgroup struct { GroupMeta `json:",inline"` } @@ -92,6 +97,10 @@ func NewHostCustomvar() contracts.Entity { return &HostCustomvar{} } +func NewHostState() contracts.Entity { + return &HostState{} +} + func NewHostgroup() contracts.Entity { return &Hostgroup{} } diff --git a/pkg/icingadb/v1/service.go b/pkg/icingadb/v1/service.go index d8f6192f..66ff3d17 100644 --- a/pkg/icingadb/v1/service.go +++ b/pkg/icingadb/v1/service.go @@ -15,6 +15,11 @@ type ServiceCustomvar struct { ServiceId types.Binary `json:"object_id"` } +type ServiceState struct { + State `json:",inline"` + ServiceId types.Binary `json:"object_id"` +} + type Servicegroup struct { GroupMeta `json:",inline"` } @@ -38,6 +43,10 @@ func NewServiceCustomvar() contracts.Entity { return &ServiceCustomvar{} } +func NewServiceState() contracts.Entity { + return &ServiceState{} +} + func NewServicegroup() contracts.Entity { return &Servicegroup{} } diff --git a/pkg/icingadb/v1/state.go b/pkg/icingadb/v1/state.go new file mode 100644 index 00000000..85837532 --- /dev/null +++ b/pkg/icingadb/v1/state.go @@ -0,0 +1,35 @@ +package v1 + +import ( + "github.com/icinga/icingadb/pkg/types" +) + +type State struct { + EntityWithChecksum `json:",inline"` + EnvironmentMeta `json:",inline"` + AcknowledgementCommentId types.Binary `json:"acknowledgement_comment_id"` + Attempt uint8 `json:"check_attempt"` + CheckCommandline types.String `json:"commandline"` + CheckSource types.String `json:"check_source"` + ExecutionTime float64 `json:"execution_time"` + HardState uint8 `json:"hard_state"` + InDowntime types.Bool `json:"in_downtime"` + IsAcknowledged types.AcknowledgementState `json:"acknowledgement"` + IsFlapping types.Bool `json:"is_flapping"` + IsHandled types.Bool `json:"is_handled"` + IsProblem types.Bool `json:"is_problem"` + IsReachable types.Bool `json:"is_reachable"` + LastStateChange types.UnixMilli `json:"last_state_change"` + LastUpdate types.UnixMilli `json:"last_update"` + Latency float64 `json:"latency"` + LongOutput types.String `json:"long_output"` + NextCheck types.UnixMilli `json:"next_check"` + NextUpdate types.UnixMilli `json:"next_update"` + Output types.String `json:"output"` + PerformanceData types.String `json:"performance_data"` + PreviousHardState uint8 `json:"previous_hard_state"` + Severity uint16 `json:"severity"` + SoftState uint8 `json:"state"` + StateType types.StateType `json:"state_type"` + Timeout float64 `json:"check_timeout"` +} diff --git a/pkg/icingadb/v1/v1.go b/pkg/icingadb/v1/v1.go index 8eacf1b6..f8cef88a 100644 --- a/pkg/icingadb/v1/v1.go +++ b/pkg/icingadb/v1/v1.go @@ -20,6 +20,7 @@ var Factories = []contracts.EntityFactoryFunc{ NewEventcommandEnvvar, NewHost, NewHostCustomvar, + NewHostState, NewHostgroup, NewHostgroupCustomvar, NewHostgroupMember, @@ -36,6 +37,7 @@ var Factories = []contracts.EntityFactoryFunc{ NewNotificationUsergroup, NewService, NewServiceCustomvar, + NewServiceState, NewServicegroup, NewServicegroupCustomvar, NewServicegroupMember, diff --git a/pkg/types/acknowledgement_state.go b/pkg/types/acknowledgement_state.go new file mode 100644 index 00000000..b47a49c7 --- /dev/null +++ b/pkg/types/acknowledgement_state.go @@ -0,0 +1,66 @@ +package types + +import ( + "database/sql/driver" + "encoding" + "encoding/json" + "fmt" +) + +// Acknowledgement specifies an acknowledgement state (yes, no, sticky). +type AcknowledgementState uint8 + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +func (as *AcknowledgementState) UnmarshalText(bytes []byte) error { + return as.UnmarshalJSON(bytes) +} + +// UnmarshalJSON implements the json.Unmarshaler interface. +func (as *AcknowledgementState) UnmarshalJSON(data []byte) error { + var i uint8 + if err := json.Unmarshal(data, &i); err != nil { + return err + } + + a := AcknowledgementState(i) + if _, ok := acknowledgementStates[a]; !ok { + return BadAcknowledgementState{data} + } + + *as = a + return nil +} + +// Value implements the driver.Valuer interface. +func (as AcknowledgementState) Value() (driver.Value, error) { + if v, ok := acknowledgementStates[as]; ok { + return v, nil + } else { + return nil, BadAcknowledgementState{as} + } +} + +// BadAcknowledgementState complains about a syntactically, but not semantically valid AcknowledgementState. +type BadAcknowledgementState struct { + State interface{} +} + +// Error implements the error interface. +func (bas BadAcknowledgementState) Error() string { + return fmt.Sprintf("bad acknowledgement state: %#v", bas.State) +} + +// acknowledgementStates maps all valid AcknowledgementState values to their SQL representation. +var acknowledgementStates = map[AcknowledgementState]string{ + 0: "y", + 1: "n", + 2: "sticky", +} + +// Assert interface compliance. +var ( + _ error = BadAcknowledgementState{} + _ encoding.TextUnmarshaler = (*AcknowledgementState)(nil) + _ json.Unmarshaler = (*AcknowledgementState)(nil) + _ driver.Valuer = AcknowledgementState(0) +) diff --git a/pkg/types/state_type.go b/pkg/types/state_type.go index e2539ba9..1f45686e 100644 --- a/pkg/types/state_type.go +++ b/pkg/types/state_type.go @@ -3,8 +3,8 @@ package types import ( "database/sql/driver" "encoding" + "encoding/json" "fmt" - "strconv" ) // StateType specifies a state's hardness. @@ -12,21 +12,19 @@ type StateType uint8 // UnmarshalText implements the encoding.TextUnmarshaler interface. func (st *StateType) UnmarshalText(bytes []byte) error { - text := string(bytes) + return st.UnmarshalJSON(bytes) +} - i, err := strconv.ParseUint(text, 10, 64) - if err != nil { +// UnmarshalJSON implements the json.Unmarshaler interface. +func (st *StateType) UnmarshalJSON(data []byte) error { + var i uint8 + if err := json.Unmarshal(data, &i); err != nil { return err } s := StateType(i) - if uint64(s) != i { - // Truncated due to above cast, obviously too high - return BadStateType{text} - } - if _, ok := stateTypes[s]; !ok { - return BadStateType{text} + return BadStateType{data} } *st = s @@ -62,5 +60,6 @@ var stateTypes = map[StateType]string{ var ( _ error = BadStateType{} _ encoding.TextUnmarshaler = (*StateType)(nil) + _ json.Unmarshaler = (*StateType)(nil) _ driver.Valuer = StateType(0) ) diff --git a/schema/1.0.0-rc2.sql b/schema/1.0.0-rc2.sql new file mode 100644 index 00000000..6ada9b00 --- /dev/null +++ b/schema/1.0.0-rc2.sql @@ -0,0 +1,15 @@ +ALTER TABLE host_state DROP PRIMARY KEY; +ALTER TABLE host_state ADD COLUMN id binary(20) NOT NULL FIRST; +UPDATE host_state SET id = host_id; +ALTER TABLE host_state ADD PRIMARY KEY (id); +ALTER TABLE host_state ADD COLUMN properties_checksum binary(20) AFTER environment_id; +UPDATE host_state SET properties_checksum = 0; +ALTER TABLE host_state MODIFY COLUMN properties_checksum binary(20) NOT NULL; + +ALTER TABLE service_state DROP PRIMARY KEY; +ALTER TABLE service_state ADD COLUMN id binary(20) NOT NULL FIRST; +UPDATE service_state SET id = service_id; +ALTER TABLE service_state ADD PRIMARY KEY (id); +ALTER TABLE service_state ADD COLUMN properties_checksum binary(20) AFTER environment_id; +UPDATE service_state SET properties_checksum = 0; +ALTER TABLE service_state MODIFY COLUMN properties_checksum binary(20) NOT NULL;