Ejemplo n.º 1
0
// NewPoller returns a new poller instance
func NewPoller(c Config) *Poller {
	p := &Poller{
		config:  c,
		Workers: make([]*Worker, 0),
		wg:      &sync.WaitGroup{},
	}

	logger.Info("poller", "starting poller workers")

	names := set.New(set.ThreadSafe)

	for _, n := range c.Nodes {
		if n.Name == "" {
			logger.Error("poller", "missing mandatory `name' node parameter")
			continue
		} else if n.Address == "" {
			logger.Error("poller", "missing mandatory `remote_addr' node parameter")
			continue
		} else if names.Has(n.Name) {
			logger.Error("poller", "duplicate name `%s' found in node definition", n.Name)
			continue
		}

		w := NewWorker(n, p.wg)

		p.Workers = append(p.Workers, w)
		p.wg.Add(1)

		go w.Start()
		w.Refresh()

		names.Add(n.Name)
	}

	return p
}
Ejemplo n.º 2
0
func getComments(r livestatus.Record) ([]Comment, error) {
	data, err := r.GetSlice("comments_with_extra_info")
	if err != nil {
		return []Comment{}, err
	}

	result := []Comment{}
	for _, entry := range data {
		slice, ok := entry.([]interface{})
		if !ok || len(slice) != 5 {
			logger.Error("poller", "skipping comment entry %v", entry)
			continue
		}

		ct, ok := slice[3].(float64)
		if !ok {
			logger.Error("poller", "unable to parse comment type: skipping entry %v", entry)
			continue
		}

		cd, ok := slice[4].(float64)
		if !ok {
			logger.Error("poller", "unable to parse comment date: skipping entry %v", entry)
			continue
		}

		result = append(result, Comment{
			Author:  fmt.Sprintf("%v", slice[1]),
			Content: fmt.Sprintf("%v", slice[2]),
			Type:    int64(ct),
			Date:    time.Unix(int64(cd), 0),
		})
	}

	return result, nil
}
Ejemplo n.º 3
0
// Run starts the server processing
func (s *Server) Run() error {
	var err error

	logger.Info("server", "service started")

	// Initialize poller
	s.poller = poller.NewPoller(s.config.Poller)

	// Initialize HTTP router
	gin.SetMode(gin.ReleaseMode)

	s.router = gin.New()
	s.router.RedirectTrailingSlash = true

	// Set static files handlers
	s.router.Any("/", s.handleStatic)
	s.router.Any("/static/*path", s.handleStatic)

	// Set API handlers
	s.router.Any("/api/hosts/:name", s.handleAPIHost)
	s.router.Any("/api/hosts/", s.handleAPIHosts)
	s.router.Any("/api/groups/", s.handleAPIGroups)
	s.router.Any("/api/nodes/", s.handleAPINodes)
	s.router.Any("/api/search/", s.handleAPISearch)

	// Start HTTP router
	logger.Info("server", "listening on %q", s.config.BindAddr)

	err = s.router.Run(s.config.BindAddr)
	if err != nil {
		logger.Error("server", "failed to initialize router: %s", err)
		return err
	}

	return nil
}
Ejemplo n.º 4
0
func (w *Worker) poll() {
	var (
		l        *livestatus.Livestatus
		q        *livestatus.Query
		resp     *livestatus.Response
		services map[string][]livestatus.Record
		err      error
	)

	// Skip refresh if already in refreshing state
	if w.refreshing {
		logger.Warning("poller", "worker is already refreshing data from %q node", w.Config.Name)
		return
	}

	w.refreshing = true

	logger.Debug("poller", "refreshing data from %q node", w.Config.Name)

	c := NewCatalog(w)

	// Create new LiveStatus instance
	args := strings.SplitN(w.Config.Address, ":", 2)
	if len(args) != 2 {
		logger.Error("poller", "invalid node address %q", w.Config.Address)
		goto end
	}

	l = livestatus.NewLivestatus(args[0], args[1])

	// Query services data
	q = l.Query("services")
	q.Columns(
		"host_name",
		"description",
		"state",
		"last_state_change",
		"comments_with_extra_info",
		"plugin_output",
		"groups",
	)
	q.Filter("state_type > 0")

	resp, err = q.Exec()
	if err != nil {
		logger.Error("poller", "unable to retrieve services from %q node: %s", w.Config.Name, err)
		goto end
	}

	services = make(map[string][]livestatus.Record)
	for _, r := range resp.Records {
		name, err := r.GetString("host_name")
		if err != nil {
			logger.Error("poller", "unable to retrieve \"host_name\" from %q node: %s",
				w.Config.Name, err)
			goto end
		}

		if _, ok := services[name]; !ok {
			services[name] = make([]livestatus.Record, 0)
		}

		services[name] = append(services[name], r)
	}

	// Query hosts data
	q = l.Query("hosts")
	q.Columns(
		"host_name",
		"state",
		"last_state_change",
		"comments_with_extra_info",
		"groups",
	)

	resp, err = q.Exec()
	if err != nil {
		logger.Error("poller", "unable to retrieve hosts from %q node: %s", w.Config.Name, err)
		goto end
	}

	// Fill catalog with retrieved data
	for _, r := range resp.Records {
		h := &Host{
			Catalog: c,
		}

		h.Name, _ = r.GetString("host_name")
		h.State, _ = r.GetInt("state")
		h.StateChanged, _ = r.GetTime("last_state_change")
		h.Comments, _ = getComments(r)
		h.Links, _ = getLinks(h.Name, "", w.Config.Links)
		h.Groups, _ = getStringSlice(r, "groups")
		h.Services = make([]*Service, 0)

		if _, ok := services[h.Name]; ok {
			for _, sr := range services[h.Name] {
				s := &Service{Host: h}

				s.Name, _ = sr.GetString("description")
				s.State, _ = sr.GetInt("state")
				s.StateChanged, _ = sr.GetTime("last_state_change")
				s.Comments, _ = getComments(sr)
				s.Links, _ = getLinks(h.Name, s.Name, w.Config.Links)
				s.Output, _ = sr.GetString("plugin_output")
				s.Groups, _ = getStringSlice(sr, "groups")

				h.Services = append(h.Services, s)
			}
		}

		c.Hosts = append(c.Hosts, h)
	}

	// Replace catalog
	w.Catalog = c

end:
	// Reset refreshing state
	w.refreshing = false
}