Christopher Ramey
4 years ago
3 changed files with 250 additions and 76 deletions
-
233config.go
-
83main.go
-
10small.config
@ -0,0 +1,233 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"bufio" |
|||
"fmt" |
|||
"os" |
|||
"strings" |
|||
) |
|||
|
|||
type AlrmConfig struct { |
|||
Groups []*AlrmGroup |
|||
} |
|||
|
|||
func (ac *AlrmConfig) NewGroup() *AlrmGroup { |
|||
group := &AlrmGroup{} |
|||
ac.Groups = append(ac.Groups, group) |
|||
return group |
|||
} |
|||
|
|||
func (ac *AlrmConfig) LastGroup() *AlrmGroup { |
|||
return ac.Groups[len(ac.Groups)-1] |
|||
} |
|||
|
|||
type AlrmGroup struct { |
|||
Name string |
|||
Hosts []*AlrmHost |
|||
} |
|||
|
|||
func (ag *AlrmGroup) NewHost() *AlrmHost { |
|||
host := &AlrmHost{} |
|||
ag.Hosts = append(ag.Hosts, host) |
|||
return host |
|||
} |
|||
|
|||
func (ag *AlrmGroup) LastHost() *AlrmHost { |
|||
return ag.Hosts[len(ag.Hosts)-1] |
|||
} |
|||
|
|||
type AlrmHost struct { |
|||
Name string |
|||
Address string |
|||
} |
|||
|
|||
const ( |
|||
TK_NONE = iota |
|||
TK_MONITOR |
|||
TK_GROUP |
|||
TK_PLAIN_HOST |
|||
TK_GROUP_HOST |
|||
) |
|||
|
|||
func stateName(s int) string { |
|||
switch s { |
|||
case TK_NONE: |
|||
return "TK_NONE" |
|||
case TK_MONITOR: |
|||
return "TK_MONTIOR" |
|||
case TK_GROUP: |
|||
return "TK_GROUP" |
|||
case TK_PLAIN_HOST: |
|||
return "TK_PLAIN_HOST" |
|||
case TK_GROUP_HOST: |
|||
return "TK_GROUP_HOST" |
|||
default: |
|||
return "UNKNOWN" |
|||
} |
|||
} |
|||
|
|||
func ReadConfig(fn string) (*AlrmConfig, error) { |
|||
file, err := os.Open(fn) |
|||
if err != nil { |
|||
return nil, fmt.Errorf("cannot open config \"%s\": %s", fn, err.Error()) |
|||
} |
|||
defer file.Close() |
|||
|
|||
config := &AlrmConfig{} |
|||
parser := &Parser{} |
|||
|
|||
scan := bufio.NewScanner(file) |
|||
scan.Split(parser.Split) |
|||
for scan.Scan() { |
|||
tk := scan.Text() |
|||
|
|||
stateswitch: |
|||
switch parser.State { |
|||
case TK_NONE: |
|||
switch strings.ToLower(tk) { |
|||
case "monitor": |
|||
parser.SetState(TK_MONITOR) |
|||
default: |
|||
return nil, fmt.Errorf("Invalid token in %s, line %d: \"%s\"", |
|||
fn, parser.Line, tk) |
|||
} |
|||
|
|||
case TK_MONITOR: |
|||
switch strings.ToLower(tk) { |
|||
case "host": |
|||
config.NewGroup().NewHost() |
|||
parser.SetState(TK_PLAIN_HOST) |
|||
|
|||
case "group": |
|||
config.NewGroup() |
|||
parser.SetState(TK_GROUP) |
|||
|
|||
default: |
|||
parser.SetState(TK_NONE) |
|||
goto stateswitch |
|||
} |
|||
|
|||
case TK_GROUP: |
|||
group := config.LastGroup() |
|||
|
|||
switch strings.ToLower(tk) { |
|||
case "host": |
|||
group.NewHost() |
|||
parser.SetState(TK_GROUP_HOST) |
|||
continue |
|||
|
|||
default: |
|||
if group.Name == "" { |
|||
group.Name = tk |
|||
continue |
|||
} |
|||
|
|||
parser.SetState(TK_MONITOR) |
|||
goto stateswitch |
|||
} |
|||
|
|||
case TK_PLAIN_HOST: |
|||
fallthrough |
|||
case TK_GROUP_HOST: |
|||
host := config.LastGroup().LastHost() |
|||
if host.Name == "" { |
|||
host.Name = tk |
|||
continue |
|||
} |
|||
|
|||
switch strings.ToLower(tk) { |
|||
case "address": |
|||
if scan.Scan() { |
|||
host.Address = scan.Text() |
|||
} |
|||
continue |
|||
|
|||
default: |
|||
if parser.State == TK_GROUP_HOST { |
|||
parser.SetState(TK_GROUP) |
|||
} else if parser.State == TK_PLAIN_HOST { |
|||
parser.SetState(TK_MONITOR) |
|||
} |
|||
|
|||
goto stateswitch |
|||
} |
|||
|
|||
default: |
|||
return nil, fmt.Errorf("Unknown parser state: %d", parser.State) |
|||
} |
|||
} |
|||
if err := scan.Err(); err != nil { |
|||
return nil, err |
|||
} |
|||
return config, nil |
|||
} |
|||
|
|||
type Parser struct { |
|||
Line int |
|||
State int |
|||
} |
|||
|
|||
func (pr *Parser) SetState(state int) { |
|||
//fmt.Printf("%s -> %s\n", stateName(pr.State), stateName(state))
|
|||
pr.State = state |
|||
} |
|||
|
|||
func (pr *Parser) Split(data []byte, atEOF bool) (int, []byte, error) { |
|||
if atEOF && len(data) == 0 { |
|||
return 0, nil, nil |
|||
} |
|||
|
|||
var ignoreline bool |
|||
var started bool |
|||
var startidx int |
|||
var quote byte |
|||
|
|||
for i := 0; i < len(data); i++ { |
|||
c := data[i] |
|||
switch c { |
|||
case '\f', '\n', '\r': |
|||
pr.Line++ |
|||
if ignoreline { |
|||
ignoreline = false |
|||
continue |
|||
} |
|||
fallthrough |
|||
|
|||
case ' ', '\t', '\v': |
|||
if started && quote == 0 { |
|||
return i + 1, data[startidx:i], nil |
|||
} |
|||
|
|||
case '\'', '"', '`': |
|||
if started && quote == c { |
|||
return i + 1, data[startidx:i], nil |
|||
} |
|||
|
|||
if quote == 0 { |
|||
quote = c |
|||
} |
|||
|
|||
case '#': |
|||
if !started { |
|||
ignoreline = true |
|||
} |
|||
|
|||
default: |
|||
if !ignoreline && !started { |
|||
started = true |
|||
startidx = i |
|||
} |
|||
} |
|||
} |
|||
|
|||
if atEOF { |
|||
if ignoreline { |
|||
return len(data), nil, nil |
|||
} |
|||
if started { |
|||
return len(data), data[startidx:], nil |
|||
} |
|||
} |
|||
|
|||
return 0, nil, nil |
|||
} |
@ -1,2 +1,10 @@ |
|||
# Address is optional, derived from host |
|||
# Address is optional, derived from host |
|||
monitor host monkey.com |
|||
|
|||
monitor host stupid.com |
|||
|
|||
monitor group webservers |
|||
# Monitor host one |
|||
host one.com address 10.12.121.1 |
|||
# Monitor host two |
|||
host two.com address |
Write
Preview
Loading…
Cancel
Save
Reference in new issue