icinga

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 27, 2023 License: ISC Imports: 10 Imported by: 2

README

package icinga provides a client to the Icinga2 HTTP API.

builds.sr.ht status

godocs.io

Send patches, questions or a friendly "hello" to the mailing list: ~otl/public-inbox@lists.sr.ht Or, read the archives.

Quick Start

See the package overview godoc for getting started examples.

Development

Some code is automatically generated. Ensure it's up-to-date before starting work:

go generate

Make some changes, then run the tests:

go test

Please send any patches to the mailing list:

git send-email --to="~otl/public-inbox@lists.sr.ht" HEAD^

For those unfamiliar with this workflow, see git-send-email.io.

Tests

Some tests use a fake, in-process Icinga server. Not all features of the API are implemented, but on any unsupported request it should report an error. The fake server uses an in-memory map to store Icinga2 objects, which maps object's path in the API request (e.g. "objects/hosts/text.example.com") to the object's attributes (e.g. check_command and display_name).

Some tests dial an instance of Icinga2 running on the loopback address and the standard Icinga2 port 5665 (::1:5665). If this fails, those tests are skipped. To run these tests, create the following API user:

object ApiUser "icinga" {
	password = name
	permissions = [ "*" ]
}

Getting data from the loopback interface to an Icinga server is left as an exercise to the reader!

Personally, I run an Alpine Linux virtual machine using qemu. You could also use the official Icinga2 container image.

Code generation

Source code for the basic lookup, create and delete operations of some Icinga2 object types, such as Host and Service, are generated automatically.

To generate the code, ensure the following tools are available:

  • POSIX shell (/bin/sh)
  • awk
  • gofmt

The shell script crud.sh writes Go source code by reading a template file and doing some text substitution. It loops through object types, piping the template file crud.skel into the awk script crud.awk for each.

crud.sh writes code to the standard output by default:

./crud.sh

If the flag -o is set, code will be written to the file specified instead of to standard output:

./crud.sh -o crud.go

Code generation is used because the functions are trivial and call the exact same underlying methods on Client anyway. The only thing that differs is the type. Perhaps when Go gets type parameters then this will go away?

Why Another Package?

The icinga2 terraform provider uses the package github.com/lrsmith/go-icinga2-api/iapi. As I read the source code I felt I wasn't reading idiomatic Go as detailed in documents like Effective Go. Other properties of iapi felt unusual to me:

  • The client to the API has the confusing name server.
  • Every HTTP request creates a new http.Client.
  • Types have superfluous names like HostStruct instead of just Host.
  • Every response body from the API is decoded from JSON into one data strucutre, marshalled into JSON again, then unmarshalled back into another.
  • Every error returned from a function has a new name, rather than reusing the idiomatic name err.

If I was being paid, I'd create a fork and contribute patches upstream to carefully avoid breaking functionality of existing users of iapi.

But I'm not being paid ;)

Documentation

Overview

package icinga provides a client to the Icinga2 HTTP API.

A Client manages interaction with an Icinga2 server. It is created using Dial:

client, err := icinga.Dial("icinga.example.com:5665", "icinga", "secret", http.DefaultClient)
if err != nil {
	// handle error
}

Icinga2 servers in the wild often serve self-signed certificates which fail verification by Go's tls client. To ignore the errors, Dial the server with a modified http.Client:

t := http.DefaultTransport.(*http.Transport)
t.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
c := http.DefaultClient
c.Transport = t
client, err := icinga.Dial(addr, user, pass, c)
if err != nil {
	// handle error
}

Methods on Client provide API actions like looking up users and creating hosts:

user, err := client.LookupUser("oliver")
if err != nil {
	// handle error
}
host := Host{
	Name: "myserver.example.com",
	CheckCommand: "hostalive"
	Address: "192.0.2.1"
	Address6: "2001:db8::1"
}
if err := client.CreateHost(host); err != nil {
	// handle error
}

Since Client wraps http.Client, exported methods of http.Client such as Get and PostForm can be used to implement any extra functionality not provided by this package. For example:

resp, err := client.PostForm("https://icinga.example.com:5665", data)
if err != nil {
	// handle error
}

Index

Constants

This section is empty.

Variables

View Source
var ErrExist = errors.New("object already exists")
View Source
var ErrNoMatch = errors.New("no object matches filter")
View Source
var ErrNotExist = errors.New("object does not exist")

Functions

func NewRequest

func NewRequest(method, url, username, password string, body io.Reader) (*http.Request, error)

NewRequest returns an authenticated HTTP request with appropriate header for sending to an Icinga2 server.

func Permissions

func Permissions(c *Client) ([]string, error)

Permissions returns the permissions granted to the Client.

Types

type CheckResult

type CheckResult struct {
	CheckSource string `json:"check_source"`
	Command     interface{}
	Output      string
}

func (CheckResult) RawCommand

func (cr CheckResult) RawCommand() string

type Client

type Client struct {
	*http.Client
	// contains filtered or unexported fields
}

A Client represents a client connection to the Icinga2 HTTP API. It should be created using Dial. Since Client wraps http.Client, exported methods such as Get and PostForm can be used to implement any functionality not provided by methods of Client.

func Dial

func Dial(addr, username, password string, client *http.Client) (*Client, error)

Dial returns a new Client connected to the Icinga2 server at addr. The recommended value for client is http.DefaultClient. But it may also be a modified client which, for example, skips TLS certificate verification.

func (*Client) CheckHosts

func (c *Client) CheckHosts(filter string) error

CheckHosts schedules checks for all hosts matching the filter expression filter. If no hosts match the filter, error wraps ErrNoMatch.

func (*Client) CheckServices

func (c *Client) CheckServices(filter string) error

CheckHosts schedules checks for all services matching the filter expression filter. If no services match the filter, error wraps ErrNoMatch.

func (*Client) CreateHost

func (c *Client) CreateHost(host Host) error

CreateHost creates host. Some fields of host must be set for successful creation; see the type definition of Host for details.

func (*Client) CreateHostGroup

func (c *Client) CreateHostGroup(hostgroup HostGroup) error

CreateHostGroup creates hostgroup. Some fields of hostgroup must be set for successful creation; see the type definition of HostGroup for details.

func (*Client) CreateService

func (c *Client) CreateService(service Service) error

CreateService creates service. Some fields of service must be set for successful creation; see the type definition of Service for details.

func (*Client) CreateUser

func (c *Client) CreateUser(user User) error

CreateUser creates user. Some fields of user must be set for successful creation; see the type definition of User for details.

func (*Client) DeleteHost

func (c *Client) DeleteHost(name string, cascade bool) error

DeleteHost deletes the Host identified by name. If cascade is true, objects depending on the Host are also deleted. If no Host is found, error wraps ErrNotExist.

func (*Client) DeleteHostGroup

func (c *Client) DeleteHostGroup(name string, cascade bool) error

DeleteHostGroup deletes the HostGroup identified by name. If cascade is true, objects depending on the HostGroup are also deleted. If no HostGroup is found, error wraps ErrNotExist.

func (*Client) DeleteService

func (c *Client) DeleteService(name string, cascade bool) error

DeleteService deletes the Service identified by name. If cascade is true, objects depending on the Service are also deleted. If no Service is found, error wraps ErrNotExist.

func (*Client) DeleteUser

func (c *Client) DeleteUser(name string, cascade bool) error

DeleteUser deletes the User identified by name. If cascade is true, objects depending on the User are also deleted. If no User is found, error wraps ErrNotExist.

func (*Client) HostGroups

func (c *Client) HostGroups(filter string) ([]HostGroup, error)

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 (*Client) Hosts

func (c *Client) Hosts(filter string) ([]Host, error)

Hosts returns a slice of Host matching the filter expression filter. If no hosts match, error wraps ErrNoMatch. To fetch all host, set filter to the empty string ("").

func (*Client) LookupHost

func (c *Client) LookupHost(name string) (Host, error)

LookupHost returns the Host identified by name. If no Host is found, error wraps ErrNotExist.

func (*Client) LookupHostGroup

func (c *Client) LookupHostGroup(name string) (HostGroup, error)

LookupHostGroup returns the HostGroup identified by name. If no HostGroup is found, error wraps ErrNotExist.

func (*Client) LookupService

func (c *Client) LookupService(name string) (Service, error)

LookupService returns the Service identified by name. If no Service is found, error wraps ErrNotExist.

func (*Client) LookupUser

func (c *Client) LookupUser(name string) (User, error)

LookupUser returns the User identified by name. If no User is found, error wraps ErrNotExist.

func (*Client) Services

func (c *Client) Services(filter string) ([]Service, error)

Services returns a slice of Service matching the filter expression filter. If no services match, error wraps ErrNoMatch. To fetch all service, set filter to the empty string ("").

func (*Client) Subscribe

func (c *Client) Subscribe(typ, queue, filter string) (<-chan Event, error)

Subscribe returns a channel through which events from the corresponding Icinga Event Stream named in typ are sent. Queue is a unique identifier Icinga uses to manage stream clients. Filter is a filter expression which modifies which events will be received; the empty string means all events are sent.

Any errors on initialising the connection are returned immediately as a value. Subsequent errors reading the stream are set in the Error field of sent Events. Callers should handle both cases and resubscribe as required.

func (*Client) Users

func (c *Client) Users(filter string) ([]User, error)

Users returns a slice of User matching the filter expression filter. If no users match, error wraps ErrNoMatch. To fetch all user, set filter to the empty string ("").

type Event

type Event struct {
	// Type indicates the type of the stream, such as CheckResult.
	Type string `json:"type"`
	// Host is the name of an Icinga Host object which this event relates to.
	Host string `json:"host"`
	// Service is the name of an Icinga Service object which this event relates to.
	// It is empty when a CheckResult event of a Host object is received.
	Service         string       `json:"service"`
	Acknowledgement bool         `json:"acknowledgement"`
	CheckResult     *CheckResult `json:"check_result"`
	Error           error
}

An Event represents an event from the Icinga Event Stream.

type Host

type Host struct {
	Name            string      `json:"-"`
	Address         string      `json:"address"`
	Address6        string      `json:"address6"`
	Groups          []string    `json:"groups,omitempty"`
	State           HostState   `json:"state,omitempty"`
	StateType       StateType   `json:"state_type,omitempty"`
	CheckCommand    string      `json:"check_command"`
	DisplayName     string      `json:"display_name,omitempty"`
	LastCheck       time.Time   `json:",omitempty"`
	LastCheckResult CheckResult `json:"last_check_result,omitempty"`
	Acknowledgement bool        `json:",omitempty"`
	Notes           string      `json:"notes,omitempty"`
	NotesURL        string      `json:"notes_url,omitempty"`
}

Host represents a Host object. To create a Host, the Name and CheckCommand fields must be set.

func (Host) Check

func (h Host) Check(c *Client) error

Check reschedules the check for h via the provided Client.

func (*Host) UnmarshalJSON

func (h *Host) UnmarshalJSON(data []byte) error

UnmarhsalJSON unmarshals host attributes into more meaningful Host field types.

type HostGroup

type HostGroup struct {
	Name        string `json:"-"`
	DisplayName string `json:"display_name"`
}

func (HostGroup) Check

func (hg HostGroup) Check(c *Client) error

Check reschedules the checks for all hosts in the HostGroup hg via the provided Client.

type HostState

type HostState int
const (
	HostUp HostState = 0 + iota
	HostDown
	HostUnreachable
)

func (HostState) String

func (state HostState) String() string

type Service

type Service struct {
	Name            string       `json:"-"`
	Groups          []string     `json:"groups,omitempty"`
	State           ServiceState `json:"state,omitempty"`
	StateType       StateType    `json:"state_type,omitempty"`
	CheckCommand    string       `json:"check_command"`
	DisplayName     string       `json:"display_name,omitempty"`
	LastCheck       time.Time    `json:",omitempty"`
	LastCheckResult CheckResult  `json:"last_check_result,omitempty"`
	Acknowledgement bool         `json:",omitempty"`
	Notes           string       `json:"notes,omitempty"`
	NotesURL        string       `json:"notes_url,omitempty"`
}

Service represents a Service object.

func (Service) Check

func (s Service) Check(c *Client) error

Check reschedules the check for s via the provided Client.

func (Service) Host

func (s Service) Host() string

func (*Service) UnmarshalJSON

func (s *Service) UnmarshalJSON(data []byte) error

UnmarshalJSON unmarshals service attributes into more meaningful Service field types.

type ServiceState

type ServiceState int
const (
	ServiceOK ServiceState = 0 + iota
	ServiceWarning
	ServiceCritical
	ServiceUnknown
)

func (ServiceState) String

func (state ServiceState) String() string

type StateType

type StateType int
const (
	StateSoft StateType = 0 + iota
	StateHard
)

func (StateType) String

func (st StateType) String() string

type User

type User struct {
	Name   string   `json:"-"`
	Email  string   `json:"email,omitempty"`
	Groups []string `json:"groups,omitempty"`
}

User represents a User object. Note that this is different from an ApiUser.

Directories

Path Synopsis
cmd
checkweb
Command checkweb is a web application for...
Command checkweb is a web application for...

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL