Browse Source

Added framework for alarms, code cleanup

master
Christopher Ramey 3 years ago
parent
commit
2d99960f06
  1. 19
      alarm/alarm.go
  2. 66
      alarm/alarm_email.go
  3. 10
      alrmrc
  4. 4
      check/check.go
  5. 46
      config/config.go
  6. 12
      config/group.go
  7. 8
      config/host.go
  8. 76
      config/parser.go

19
alarm/alarm.go

@ -0,0 +1,19 @@
package alarm
import (
"fmt"
)
type Alarm interface {
Parse(string) (bool, error)
Alarm() error
}
func NewAlarm(name string, typename string) (Alarm, error) {
switch typename {
case "email":
return NewAlarmEmail(name), nil
default:
return nil, fmt.Errorf("unknown alarm name \"%s\"", name)
}
}

66
alarm/alarm_email.go

@ -0,0 +1,66 @@
package alarm
import (
"fmt"
"strings"
)
const (
TK_NONE = iota
TK_TO
TK_SMTP
TK_FROM
)
type AlarmEmail struct {
Type string
Name string
From string
SMTP string
To []string
state int
}
func NewAlarmEmail(name string) *AlarmEmail {
return &AlarmEmail{
Type: "email", Name: name,
}
}
func (a *AlarmEmail) Alarm() error {
fmt.Printf("email alarm")
return nil
}
func (a *AlarmEmail) Parse(tk string) (bool, error) {
switch a.state {
case TK_NONE:
switch strings.ToLower(tk){
case "to":
a.state = TK_TO
case "from":
a.state = TK_FROM
case "smtp":
a.state = TK_SMTP
default:
return false, nil
}
case TK_FROM:
a.From = tk
a.state = TK_NONE
case TK_SMTP:
a.SMTP = tk
a.state = TK_NONE
case TK_TO:
a.To = append(a.To, tk)
a.state = TK_NONE
default:
return false, fmt.Errorf("invalid state in alarm_email")
}
return true, nil
}

10
alrmrc

@ -1,10 +1,10 @@
set interval 30s
#alarm people email
# to test1@localhost
# to test2@localhost
# smtp localhost
# from alrm@localhost
alarm people email
to test1@localhost
to test2@localhost
smtp localhost
from alrm@localhost
monitor group webservers
host www1.example.com address 10.11.135.101

4
check/check.go

@ -4,12 +4,12 @@ import (
"fmt"
)
type AlrmCheck interface {
type Check interface {
Parse(string) (bool, error)
Check(int) error
}
func NewCheck(name string, addr string) (AlrmCheck, error) {
func NewCheck(name string, addr string) (Check, error) {
switch name {
case "ping":
return NewCheckPing(addr), nil

46
config/config.go

@ -3,45 +3,65 @@ package config
import (
"fmt"
"time"
"alrm/alarm"
)
type AlrmConfig struct {
Groups map[string]*AlrmGroup
type Config struct {
Groups map[string]*Group
Alarms map[string]alarm.Alarm
Interval time.Duration
}
func NewConfig() *AlrmConfig {
return &AlrmConfig{
func NewConfig() *Config {
return &Config{
// Default check interval, 30 seconds
Interval: time.Second * 30,
}
}
func (ac *AlrmConfig) NewGroup(name string) (*AlrmGroup, error) {
if ac.Groups == nil {
ac.Groups = make(map[string]*AlrmGroup)
func (c *Config) NewAlarm(name string, typename string) (alarm.Alarm, error) {
if c.Alarms == nil {
c.Alarms = make(map[string]alarm.Alarm)
}
if _, exists := ac.Groups[name]; exists {
if _, exists := c.Alarms[name]; exists {
return nil, fmt.Errorf("alarm %s already exists", name)
}
a, err := alarm.NewAlarm(name, typename)
if err != nil {
return nil, err
}
c.Alarms[name] = a
return a, nil
}
func (c *Config) NewGroup(name string) (*Group, error) {
if c.Groups == nil {
c.Groups = make(map[string]*Group)
}
if _, exists := c.Groups[name]; exists {
return nil, fmt.Errorf("group %s already exists", name)
}
group := &AlrmGroup{Name: name}
ac.Groups[name] = group
group := &Group{Name: name}
c.Groups[name] = group
return group, nil
}
func (ac *AlrmConfig) SetInterval(val string) error {
func (c *Config) SetInterval(val string) error {
interval, err := time.ParseDuration(val)
if err != nil {
return err
}
ac.Interval = interval
c.Interval = interval
return nil
}
func ReadConfig(fn string, debuglvl int) (*AlrmConfig, error) {
func ReadConfig(fn string, debuglvl int) (*Config, error) {
parser := &Parser{DebugLevel: debuglvl}
config, err := parser.Parse(fn)
if err != nil {

12
config/group.go

@ -4,26 +4,26 @@ import (
"fmt"
)
type AlrmGroup struct {
type Group struct {
Name string
Hosts map[string]*AlrmHost
Hosts map[string]*Host
}
func (ag *AlrmGroup) NewHost(name string) (*AlrmHost, error) {
func (ag *Group) NewHost(name string) (*Host, error) {
if ag.Hosts == nil {
ag.Hosts = make(map[string]*AlrmHost)
ag.Hosts = make(map[string]*Host)
}
if _, exists := ag.Hosts[name]; exists {
return nil, fmt.Errorf("host %s already exists", name)
}
host := &AlrmHost{Name: name}
host := &Host{Name: name}
ag.Hosts[name] = host
return host, nil
}
func (ag *AlrmGroup) Check(debuglvl int) error {
func (ag *Group) Check(debuglvl int) error {
for _, host := range ag.Hosts {
for _, chk := range host.Checks {
err := chk.Check(debuglvl)

8
config/host.go

@ -4,20 +4,20 @@ import (
"alrm/check"
)
type AlrmHost struct {
type Host struct {
Name string
Address string
Checks []check.AlrmCheck
Checks []check.Check
}
func (ah *AlrmHost) GetAddress() string {
func (ah *Host) GetAddress() string {
if ah.Address != "" {
return ah.Address
}
return ah.Name
}
func (ah *AlrmHost) NewCheck(name string) (check.AlrmCheck, error) {
func (ah *Host) NewCheck(name string) (check.Check, error) {
chk, err := check.NewCheck(name, ah.GetAddress())
if err != nil {
return nil, err

76
config/parser.go

@ -1,6 +1,7 @@
package config
import (
"alrm/alarm"
"alrm/check"
"bufio"
"fmt"
@ -15,18 +16,21 @@ const (
TK_GROUP
TK_HOST
TK_CHECK
TK_ALARM
)
type Parser struct {
DebugLevel int
Line int
states []int
lasthost *AlrmHost
lastgroup *AlrmGroup
lastcheck check.AlrmCheck
DebugLevel int
Line int
states []int
lastHost *Host
lastGroup *Group
lastCheck check.Check
lastAlarm alarm.Alarm
lastAlarmName string
}
func (p *Parser) Parse(fn string) (*AlrmConfig, error) {
func (p *Parser) Parse(fn string) (*Config, error) {
file, err := os.Open(fn)
if err != nil {
return nil, fmt.Errorf("cannot open config \"%s\": %s", fn, err.Error())
@ -47,6 +51,8 @@ func (p *Parser) Parse(fn string) (*AlrmConfig, error) {
p.setState(TK_MONITOR)
case "set":
p.setState(TK_SET)
case "alarm":
p.setState(TK_ALARM)
default:
return nil, fmt.Errorf("invalid token in %s, line %d: \"%s\"",
fn, p.Line, tk)
@ -90,8 +96,8 @@ func (p *Parser) Parse(fn string) (*AlrmConfig, error) {
}
case TK_GROUP:
if p.lastgroup == nil {
p.lastgroup, err = config.NewGroup(tk)
if p.lastGroup == nil {
p.lastGroup, err = config.NewGroup(tk)
if err != nil {
return nil, fmt.Errorf("%s in %s, line %d",
err.Error(), fn, p.Line,
@ -111,8 +117,8 @@ func (p *Parser) Parse(fn string) (*AlrmConfig, error) {
case TK_HOST:
// If a host has no group, inherit the host name
if p.lastgroup == nil {
p.lastgroup, err = config.NewGroup(tk)
if p.lastGroup == nil {
p.lastGroup, err = config.NewGroup(tk)
if err != nil {
return nil, fmt.Errorf("%s in %s, line %d",
err.Error(), fn, p.Line,
@ -120,8 +126,8 @@ func (p *Parser) Parse(fn string) (*AlrmConfig, error) {
}
}
if p.lasthost == nil {
p.lasthost, err = p.lastgroup.NewHost(tk)
if p.lastHost == nil {
p.lastHost, err = p.lastGroup.NewHost(tk)
if err != nil {
return nil, fmt.Errorf("%s in %s, line %d",
err.Error(), fn, p.Line,
@ -136,7 +142,7 @@ func (p *Parser) Parse(fn string) (*AlrmConfig, error) {
return nil, fmt.Errorf("empty address for host in %s, line %d",
fn, p.Line)
}
p.lasthost.Address = scan.Text()
p.lastHost.Address = scan.Text()
case "check":
p.setState(TK_CHECK)
@ -147,21 +153,47 @@ func (p *Parser) Parse(fn string) (*AlrmConfig, error) {
}
case TK_CHECK:
if p.lastcheck == nil {
p.lastcheck, err = p.lasthost.NewCheck(tk)
if p.lastCheck == nil {
p.lastCheck, err = p.lastHost.NewCheck(tk)
if err != nil {
return nil, fmt.Errorf("%s in %s, line %d",
err.Error(), fn, p.Line)
}
continue
}
cont, err := p.lastcheck.Parse(tk)
cont, err := p.lastCheck.Parse(tk)
if err != nil {
return nil, fmt.Errorf("%s in %s, line %d",
err.Error(), fn, p.Line)
}
if !cont {
p.lastcheck = nil
p.lastCheck = nil
p.prevState()
goto stateswitch
}
case TK_ALARM:
if p.lastAlarm == nil {
if p.lastAlarmName == "" {
p.lastAlarmName = tk
continue
}
p.lastAlarm, err = config.NewAlarm(p.lastAlarmName, tk)
if err != nil {
return nil, fmt.Errorf("%s in %s, line %d",
err.Error(), fn, p.Line)
}
p.lastAlarmName = ""
continue
}
cont, err := p.lastAlarm.Parse(tk)
if err != nil {
return nil, fmt.Errorf("%s in %s, line %d",
err.Error(), fn, p.Line)
}
if !cont {
p.lastAlarm = nil
p.prevState()
goto stateswitch
}
@ -188,11 +220,11 @@ func (p *Parser) setState(state int) {
case TK_SET, TK_MONITOR:
fallthrough
case TK_GROUP:
p.lastgroup = nil
p.lastGroup = nil
fallthrough
case TK_HOST:
p.lasthost = nil
p.lastcheck = nil
p.lastHost = nil
p.lastCheck = nil
}
if p.DebugLevel > 1 {
@ -225,6 +257,8 @@ func (p *Parser) stateName() string {
return "TK_HOST"
case TK_CHECK:
return "TK_CHECK"
case TK_ALARM:
return "TK_ALARM"
default:
return "UNKNOWN"
}

Loading…
Cancel
Save