commit a17d3f9dc6856d0cb60bf176e66844dc2752782d
parent 8f08828e8134e1160b4be74544d3b6020059366e
Author: Oliver Lowe <o@olowe.co>
Date: Sat, 12 Feb 2022 10:45:54 +1100
Simplify service JSON marshalling
We don't need to have a MarshalJSON method just so that it can be
created ok. It's clearer to do stuff necessart for object creation at
the time of object creation, not way earlier in some unrelated bit of
the code.
While here simplify the tests to actually test what we're worried about.
Diffstat:
4 files changed, 68 insertions(+), 26 deletions(-)
diff --git a/object.go b/object.go
@@ -14,6 +14,38 @@ type object interface {
path() string
}
+// jsonForCreate marshals obj into the required JSON object to be sent
+// in the body of a PUT request to Icinga. Some fields of obj must not be set for
+// Icinga to create the object. Since some of those fields are structs
+// (and not pointers to structs), they are always included, even if unset.
+// jsonForCreate overrides those fields to always be empty. Other fields are left
+// alone to let Icinga report an error for us.
+func jsonForCreate(obj object) ([]byte, error) {
+ m := make(map[string]interface{})
+ switch v := obj.(type) {
+ case User, HostGroup:
+ m["attrs"] = v
+ case Host:
+ aux := &struct {
+ // fields not added to Host yet
+ // LastCheck struct{}
+ // LastCheckResult struct{}
+ Host
+ }{Host: v}
+ m["attrs"] = aux
+ case Service:
+ aux := &struct {
+ LastCheck *struct{} `json:",omitempty"`
+ LastCheckResult *struct{} `json:"last_check_result,omitempty"`
+ Service
+ }{Service: v}
+ m["attrs"] = aux
+ default:
+ return nil, fmt.Errorf("marshal %T for creation unsupported", v)
+ }
+ return json.Marshal(m)
+}
+
//go:generate ./crud.sh -o crud.go
func (c *Client) lookupObject(objpath string) (object, error) {
@@ -56,18 +88,11 @@ func (c *Client) filterObjects(objpath, expr string) ([]object, error) {
}
func (c *Client) createObject(obj object) error {
- buf := &bytes.Buffer{}
- switch v := obj.(type) {
- case Host, Service, User, HostGroup:
- m := make(map[string]interface{})
- m["attrs"] = v
- if err := json.NewEncoder(buf).Encode(m); err != nil {
- return err
- }
- default:
- return fmt.Errorf("create type %T unsupported", v)
+ b, err := jsonForCreate(obj)
+ if err != nil {
+ return fmt.Errorf("marshal into json: %v", err)
}
- resp, err := c.put(obj.path(), buf)
+ resp, err := c.put(obj.path(), bytes.NewReader(b))
if err != nil {
return err
}
diff --git a/service.go b/service.go
@@ -23,7 +23,7 @@ type Service struct {
CheckCommand string `json:"check_command"`
DisplayName string `json:"display_name,omitempty"`
LastCheck time.Time `json:",omitempty"`
- LastCheckResult *CheckResult `json:"last_check_result,omitempty"`
+ LastCheckResult CheckResult `json:"last_check_result,omitempty"`
Acknowledgement bool `json:",omitempty"`
}
diff --git a/service_test.go b/service_test.go
@@ -2,10 +2,11 @@ package icinga
import (
"os"
- "reflect"
"testing"
+ "time"
)
+// Tests the trickier parts of the custom Unmarshaller functionality.
func TestServiceUnmarshal(t *testing.T) {
f, err := os.Open("testdata/objects/services/9p.io!http")
if err != nil {
@@ -16,19 +17,35 @@ func TestServiceUnmarshal(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- want := Service{
- Name: "9p.io!http",
- Groups: []string{},
- State: ServiceOK,
- StateType: StateHard,
- CheckCommand: "http",
- DisplayName: "http",
- LastCheckResult: &CheckResult{
- Output: "HTTP OK: HTTP/1.1 200 OK - 1714 bytes in 1.083 second response time ",
+ svc := resp.Results[0].(Service)
+ if svc.LastCheck.IsZero() {
+ t.Error("zero time")
+ }
+ if !svc.Acknowledgement {
+ t.Error("should be acknowledged")
+ }
+ if t.Failed() {
+ t.Log(svc)
+ }
+}
+
+func TestServiceMarshalForCreate(t *testing.T) {
+ want := `{"attrs":{"check_command":"dummy","display_name":"test"}}`
+ service := Service{
+ CheckCommand: "dummy",
+ DisplayName: "test",
+ LastCheck: time.Now(),
+ LastCheckResult: CheckResult{
+ Output: "xxx",
+ CheckSource: "xxx",
+ Command: nil,
},
}
- got := resp.Results[0].(Service)
- if !reflect.DeepEqual(want, got) {
- t.Errorf("want %+v, got %+v", want, got)
+ got, err := jsonForCreate(service)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if want != string(got) {
+ t.Error("not matching", string(got))
}
}
diff --git a/testdata/objects/services/9p.io!http b/testdata/objects/services/9p.io!http
@@ -3,7 +3,7 @@
{
"attrs": {
"__name": "9p.io!http",
- "acknowledgement": 0,
+ "acknowledgement": 1,
"acknowledgement_expiry": 0,
"acknowledgement_last_change": 0,
"action_url": "",