commit 191337d0c3d59aa9a990eb5192664d5c5079f187 from: Oliver Lowe date: Tue Jan 18 08:21:15 2022 UTC Add checking of services and hosts And also add a icinga_test package that does the black-box tests i.e. tests which speak to a real icinga server. commit - e6fcfaf5b395db10ed791a73814b9e002be4a980 commit + 191337d0c3d59aa9a990eb5192664d5c5079f187 blob - /dev/null blob + f81739c5afa8cc400c9e3e2556618fa8566ff45e (mode 644) --- /dev/null +++ checker.go @@ -0,0 +1,83 @@ +package icinga + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "strings" +) + +type checker interface { + object + Check(*Client) error +} + +type StateType int + +const ( + StateSoft StateType = 0 + iota + StateHard +) + +func (st StateType) String() string { + switch st { + case StateSoft: + return "StateSoft" + case StateHard: + return "StateHard" + } + return "unsupported state type" +} + +func (s Service) Check(c *Client) error { + return c.check(s) +} + +func (h Host) Check(c *Client) error { + return c.check(h) +} + +func splitServiceName(name string) []string { + return strings.SplitN(name, "!", 2) +} + +func (c *Client) check(ch checker) error { + var filter struct { + Type string `json:"type"` + Expr string `json:"filter"` + } + switch v := ch.(type) { + case Host: + filter.Type = "Host" + filter.Expr = fmt.Sprintf("host.name == %q", v.Name) + case Service: + filter.Type = "Service" + a := splitServiceName(v.Name) + if len(a) != 2 { + return fmt.Errorf("check %s: invalid service name", v.Name) + } + host := a[0] + service := a[1] + filter.Expr = fmt.Sprintf("host.name == %q && service.name == %q", host, service) + default: + return fmt.Errorf("cannot check %T", v) + } + + buf := &bytes.Buffer{} + if err := json.NewEncoder(buf).Encode(filter); err != nil { + return err + } + resp, err := c.post("/actions/reschedule-check", buf) + if err != nil { + return fmt.Errorf("check %s: %w", ch.name(), err) + } + switch resp.StatusCode { + case http.StatusOK: + return nil + case http.StatusNotFound: + return fmt.Errorf("check %s: %w", ch.name(), ErrNotExist) + default: + return fmt.Errorf("check %s: %s", ch.name(), resp.Status) + } +} blob - cfb416dc03d1d61daf3291217af43e419123563b (mode 644) blob + /dev/null --- host_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package icinga - -import ( - "errors" - "math/rand" - "sort" - "testing" -) - -func randomHostname() string { - var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") - b := make([]rune, 8) - for i := range b { - b[i] = letters[rand.Intn(len(letters))] - } - return string(b) + ".example.org" -} - -func compareStringSlice(a, b []string) bool { - if len(a) != len(b) { - return false - } - for i, v := range a { - if v != b[i] { - return false - } - } - return true -} - -func TestFilter(t *testing.T) { - client, err := newTestClient() - if err != nil { - t.Skipf("no local test icinga? got: %v", err) - } - - hostgroup := HostGroup{Name: "examples", DisplayName: "Test Group"} - if err := client.CreateHostGroup(hostgroup); err != nil { - t.Error(err) - } - hostgroup, err = client.LookupHostGroup(hostgroup.Name) - if err != nil { - t.Error(err) - } - defer client.DeleteHostGroup(hostgroup.Name) - - var want, got []string - for i := 0; i < 5; i++ { - h := Host{ - Name: randomHostname(), - CheckCommand: "hostalive", - Groups: []string{hostgroup.Name}, - } - want = append(want, h.Name) - if err := client.CreateHost(h); err != nil { - if !errors.Is(err, ErrExist) { - t.Error(err) - } - continue - } - t.Logf("created host %s", h.Name) - } - defer func() { - for _, name := range want { - if err := client.DeleteHost(name); err != nil { - t.Log(err) - } - } - }() - hosts, err := client.Hosts("match(\"*example.org\", host.name)") - if err != nil { - t.Fatal(err) - } - for _, h := range hosts { - got = append(got, h.Name) - } - sort.Strings(want) - sort.Strings(got) - if !compareStringSlice(want, got) { - t.Fail() - } - t.Logf("want %+v got %+v", want, got) -} blob - /dev/null blob + d6de04aa780b601ace52aa53f0fdb4d82850dcdd (mode 644) --- /dev/null +++ icinga_test.go @@ -0,0 +1,136 @@ +package icinga_test + +import ( + "crypto/tls" + "errors" + "math/rand" + "net/http" + "reflect" + "sort" + "testing" + + "olowe.co/icinga" +) + +func randomHostname() string { + var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") + b := make([]rune, 8) + for i := range b { + b[i] = letters[rand.Intn(len(letters))] + } + return string(b) + ".example.org" +} + +func newTestClient() (*icinga.Client, error) { + tp := http.DefaultTransport.(*http.Transport) + tp.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + c := http.DefaultClient + c.Transport = tp + return icinga.Dial("127.0.0.1:5665", "root", "icinga", c) +} + +func compareStringSlice(a, b []string) bool { + if len(a) != len(b) { + return false + } + for i, v := range a { + if v != b[i] { + return false + } + } + return true +} + +func TestFilter(t *testing.T) { + client, err := newTestClient() + if err != nil { + t.Skipf("no local test icinga? got: %v", err) + } + + hostgroup := icinga.HostGroup{Name: "examples", DisplayName: "Test Group"} + if err := client.CreateHostGroup(hostgroup); err != nil { + t.Error(err) + } + hostgroup, err = client.LookupHostGroup(hostgroup.Name) + if err != nil { + t.Error(err) + } + defer client.DeleteHostGroup(hostgroup.Name) + + var want, got []string + for i := 0; i < 5; i++ { + h := icinga.Host{ + Name: randomHostname(), + CheckCommand: "hostalive", + Groups: []string{hostgroup.Name}, + } + want = append(want, h.Name) + if err := client.CreateHost(h); err != nil { + if !errors.Is(err, icinga.ErrExist) { + t.Error(err) + } + continue + } + t.Logf("created host %s", h.Name) + } + defer func() { + for _, name := range want { + if err := client.DeleteHost(name); err != nil { + t.Log(err) + } + } + }() + hosts, err := client.Hosts("match(\"*example.org\", host.name)") + if err != nil { + t.Fatal(err) + } + for _, h := range hosts { + got = append(got, h.Name) + } + sort.Strings(want) + sort.Strings(got) + if !compareStringSlice(want, got) { + t.Fail() + } + t.Logf("want %+v got %+v", want, got) +} + +func TestUserRoundTrip(t *testing.T) { + client, err := newTestClient() + if err != nil { + t.Skipf("no local test icinga? got: %v", err) + } + want := icinga.User{Name: "olly", Email: "olly@example.com", Groups: []string{}} + if err := client.CreateUser(want); err != nil && !errors.Is(err, icinga.ErrExist) { + t.Fatal(err) + } + defer func() { + if err := client.DeleteUser(want.Name); err != nil { + t.Error(err) + } + }() + got, err := client.LookupUser(want.Name) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(want, got) { + t.Errorf("want %+v, got %+v", want, got) + } +} + +func TestChecker(t *testing.T) { + client, err := newTestClient() + if err != nil { + t.Skipf("no local test icinga? got: %v", err) + } + + s := icinga.Service{Name: "9p.io!http"} + if err := s.Check(client); err != nil { + t.Fatal(err) + } + s, err = client.LookupService("9p.io!http") + if err != nil { + t.Fatal(err) + } + t.Logf("%+v\n", s) +} blob - f6c54ed27fec491ddd88b23d317b3dab0177b880 blob + 8accc7e71cba819abb61b5a00fc62fd80432b8b1 --- user_test.go +++ user_test.go @@ -1,23 +1,12 @@ package icinga import ( - "crypto/tls" "encoding/json" - "errors" - "net/http" "os" "reflect" "testing" ) -func newTestClient() (*Client, error) { - tp := http.DefaultTransport.(*http.Transport) - tp.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} - c := http.DefaultClient - c.Transport = tp - return Dial("127.0.0.1:5665", "root", "icinga", c) -} - func TestUser(t *testing.T) { want := User{Name: "test", Email: "test@example.com", Groups: []string{}} f, err := os.Open("testdata/users.json") @@ -54,26 +43,3 @@ func TestUserMarshal(t *testing.T) { } t.Logf("want %s, got %s", want, got) } - -func TestUserRoundTrip(t *testing.T) { - client, err := newTestClient() - if err != nil { - t.Skipf("no local test icinga? got: %v", err) - } - want := User{Name: "olly", Email: "olly@example.com", Groups: []string{}} - if err := client.CreateUser(want); err != nil && !errors.Is(err, ErrExist) { - t.Fatal(err) - } - defer func() { - if err := client.DeleteUser(want.Name); err != nil { - t.Error(err) - } - }() - got, err := client.LookupUser(want.Name) - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(want, got) { - t.Errorf("want %+v, got %+v", want, got) - } -}