commit e0c24850440b8bcaa5bf6a49c0dd493fb30e94fb
parent 7aa5b0553214edbb1a6e71187215972e1e4877c6
Author: Oliver Lowe <o@olowe.co>
Date: Fri, 14 Jan 2022 11:21:29 +1100
Support Icinga2 hostgroups
Tests of hostgroup operations are done in TestFilter
Diffstat:
7 files changed, 113 insertions(+), 6 deletions(-)
diff --git a/crud.go b/crud.go
@@ -156,3 +156,55 @@ func (c *Client) DeleteUser(name string) error {
}
return nil
}
+
+// HostGroups returns a slice of HostGroup matching the filter expression filter.
+// If no hostgroups match, error wraps ErrNoMatch.
+// To fetch all hostgroup, set filter to the empty string ("").
+func (c *Client) HostGroups(filter string) ([]HostGroup, error) {
+ objects, err := c.filterObjects("/objects/hostgroups", filter)
+ if err != nil {
+ return nil, fmt.Errorf("get hostgroups filter %q: %w", filter, err)
+ }
+ var hostgroups []HostGroup
+ for _, o := range objects {
+ v, ok := o.(HostGroup)
+ if !ok {
+ return nil, fmt.Errorf("get hostgroups filter %q: %T in response", filter, v)
+ }
+ hostgroups = append(hostgroups, v)
+ }
+ return hostgroups, nil
+}
+
+// LookupHostGroup returns the HostGroup identified by name. If no HostGroup is found, error
+// wraps ErrNotExist.
+func (c *Client) LookupHostGroup(name string) (HostGroup, error) {
+ obj, err := c.lookupObject("/objects/hostgroups/" + name)
+ if err != nil {
+ return HostGroup{}, fmt.Errorf("lookup hostgroup %s: %w", name, err)
+ }
+ v, ok := obj.(HostGroup)
+ if !ok {
+ return HostGroup{}, fmt.Errorf("lookup hostgroup %s: result type %T is not HostGroup", name, v)
+ }
+ return v, nil
+}
+
+// CreateHostGroup creates hostgroup. Some fields of hostgroup must be set for successful
+// creation; see the type definition of HostGroup for details.
+func (c *Client) CreateHostGroup(hostgroup HostGroup) error {
+ if err := c.createObject(hostgroup); err != nil {
+ return fmt.Errorf("create hostgroup %s: %w", hostgroup.Name, err)
+ }
+ return nil
+}
+
+// DeleteHostGroup deletes the HostGroup identified by name.
+// If no HostGroup is found, error wraps ErrNotExist.
+func (c *Client) DeleteHostGroup(name string) error {
+ if err := c.deleteObject("/objects/hostgroups/" + name); err != nil {
+ return fmt.Errorf("delete hostgroup %s: %w", name, err)
+ }
+ return nil
+}
+
diff --git a/crud.sh b/crud.sh
@@ -1,6 +1,6 @@
#!/bin/sh
-types="Host Service User"
+types="Host Service User HostGroup"
args=`getopt o: $*`
if test $? -ne 0
diff --git a/host.go b/host.go
@@ -2,7 +2,8 @@ package icinga
import "encoding/json"
-// Host represents a Host object.
+// Host represents a Host object. To create a Host, the Name and CheckCommand
+// fields must be set.
type Host struct {
Name string `json:"name"`
Address string `json:"address"`
@@ -13,6 +14,11 @@ type Host struct {
DisplayName string `json:"display_name"`
}
+type HostGroup struct {
+ Name string `json:"name"`
+ DisplayName string `json:"display_name"`
+}
+
type HostState int
const (
@@ -41,6 +47,14 @@ func (h Host) path() string {
return "/objects/hosts/" + h.Name
}
+func (hg HostGroup) name() string {
+ return hg.Name
+}
+
+func (hg HostGroup) path() string {
+ return "/objects/hostgroups/" + hg.Name
+}
+
func (h Host) MarshalJSON() ([]byte, error) {
type Attrs struct {
Address string `json:"address"`
@@ -59,3 +73,17 @@ func (h Host) MarshalJSON() ([]byte, error) {
}
return json.Marshal(jhost)
}
+
+func (hg HostGroup) MarshalJSON() ([]byte, error) {
+ type attrs struct {
+ DisplayName string `json:"display_name"`
+ }
+ type group struct {
+ Attrs attrs `json:"attrs"`
+ }
+ return json.Marshal(&group{
+ Attrs: attrs{
+ DisplayName: hg.DisplayName,
+ },
+ })
+}
diff --git a/host_test.go b/host_test.go
@@ -35,14 +35,28 @@ func TestFilter(t *testing.T) {
tp.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
c := http.DefaultClient
c.Transport = tp
- client, err := Dial("127.0.0.1:5665", "root", "8eec5ede1673b757", c)
+ client, err := Dial("127.0.0.1:5665", "root", "icinga", c)
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"}
+ 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) {
@@ -52,6 +66,13 @@ func TestFilter(t *testing.T) {
}
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)
diff --git a/object.go b/object.go
@@ -60,7 +60,7 @@ 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:
+ case Host, Service, User, HostGroup:
if err := json.NewEncoder(buf).Encode(v); err != nil {
return err
}
diff --git a/response.go b/response.go
@@ -71,6 +71,12 @@ func parseResponse(r io.Reader) (*response, error) {
return nil, err
}
resp.Results = append(resp.Results, u)
+ case "HostGroup":
+ var h HostGroup
+ if err := json.Unmarshal(r.Attrs, &h); err != nil {
+ return nil, err
+ }
+ resp.Results = append(resp.Results, h)
default:
return nil, fmt.Errorf("unsupported unmarshal of type %s", r.Type)
}
diff --git a/user_test.go b/user_test.go
@@ -52,7 +52,7 @@ func TestUserRoundTrip(t *testing.T) {
tp.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
c := http.DefaultClient
c.Transport = tp
- client, err := Dial("127.0.0.1:5665", "root", "8eec5ede1673b757", c)
+ client, err := Dial("127.0.0.1:5665", "root", "icinga", c)
if err != nil {
t.Skipf("no local test icinga? got: %v", err)
}