flapjack 1.0.0rc1 → 1.0.0rc2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +8 -0
- data/CHANGELOG.md +15 -0
- data/README.md +4 -0
- data/bin/flapjack +15 -2
- data/build.sh +22 -0
- data/dist/etc/init.d/flapjack +1 -1
- data/dist/etc/init.d/flapjack-nagios-receiver +3 -3
- data/dist/etc/init.d/flapper +3 -3
- data/etc/flapjack_config.yaml.example +35 -17
- data/lib/flapjack/cli/receiver.rb +25 -1
- data/lib/flapjack/cli/simulate.rb +16 -9
- data/lib/flapjack/data/entity.rb +17 -21
- data/lib/flapjack/data/entity_check.rb +10 -0
- data/lib/flapjack/gateways/jabber.rb +36 -12
- data/lib/flapjack/gateways/jsonapi/check_methods.rb +32 -0
- data/lib/flapjack/gateways/jsonapi/report_methods.rb +1 -5
- data/lib/flapjack/gateways/web/views/check.html.erb +1 -1
- data/lib/flapjack/gateways/web/views/checks.html.erb +2 -2
- data/lib/flapjack/gateways/web/views/contact.html.erb +2 -2
- data/lib/flapjack/gateways/web/views/entity.html.erb +1 -1
- data/lib/flapjack/patches.rb +70 -0
- data/lib/flapjack/version.rb +1 -1
- data/libexec/httpbroker.go +161 -0
- data/libexec/oneoff.go +75 -0
- data/spec/lib/flapjack/data/entity_spec.rb +1 -1
- data/spec/lib/flapjack/gateways/jabber_spec.rb +15 -17
- data/spec/lib/flapjack/gateways/jsonapi/check_methods_spec.rb +57 -0
- data/src/flapjack/event.go +25 -0
- data/src/flapjack/event_test.go +26 -0
- data/src/flapjack/transport.go +49 -0
- data/src/flapjack/transport_test.go +15 -0
- metadata +9 -2
data/libexec/oneoff.go
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
package main
|
2
|
+
|
3
|
+
import (
|
4
|
+
"os"
|
5
|
+
"fmt"
|
6
|
+
"time"
|
7
|
+
"strings"
|
8
|
+
"flapjack"
|
9
|
+
"gopkg.in/alecthomas/kingpin.v1"
|
10
|
+
"encoding/json"
|
11
|
+
)
|
12
|
+
|
13
|
+
var (
|
14
|
+
entity = kingpin.Arg("entity", "Entity name").Required().String()
|
15
|
+
check = kingpin.Arg("check", "Check name").Required().String()
|
16
|
+
state = kingpin.Arg("state", "Current state").Required().String()
|
17
|
+
summary = kingpin.Arg("summary", "Summary of event").Required().String()
|
18
|
+
debug = kingpin.Flag("debug", "Enable verbose output (default false)").Bool()
|
19
|
+
server = kingpin.Flag("server", "Redis server to connect to (default localhost:6380)").Default("localhost:6380").String()
|
20
|
+
database = kingpin.Flag("database", "Redis database to connect to (default 0)").Int()
|
21
|
+
)
|
22
|
+
|
23
|
+
func main() {
|
24
|
+
kingpin.Version("0.0.1")
|
25
|
+
kingpin.Parse()
|
26
|
+
|
27
|
+
if *debug {
|
28
|
+
fmt.Println("Entity:", *entity)
|
29
|
+
fmt.Println("Check:", *check)
|
30
|
+
fmt.Println("State:", *state)
|
31
|
+
fmt.Println("Summary:", *summary)
|
32
|
+
fmt.Println("Debug:", *debug)
|
33
|
+
fmt.Println("Server:", *server)
|
34
|
+
fmt.Println("Database:", *database)
|
35
|
+
}
|
36
|
+
|
37
|
+
addr := strings.Split(*server, ":")
|
38
|
+
if len(addr) != 2 {
|
39
|
+
fmt.Println("Error: invalid address specified:", *server)
|
40
|
+
fmt.Println("Should be in format `addr:port` (e.g. 127.0.0.1:6380)")
|
41
|
+
os.Exit(1)
|
42
|
+
}
|
43
|
+
|
44
|
+
event := flapjack.Event{
|
45
|
+
Entity: *entity,
|
46
|
+
Check: *check,
|
47
|
+
Type: "service",
|
48
|
+
State: *state,
|
49
|
+
Summary: *summary,
|
50
|
+
Time: time.Now().Unix(),
|
51
|
+
}
|
52
|
+
|
53
|
+
if *debug {
|
54
|
+
data, _ := json.Marshal(event)
|
55
|
+
fmt.Printf("Event data: %s\n", data)
|
56
|
+
}
|
57
|
+
|
58
|
+
transport, err := flapjack.Dial(*server, *database)
|
59
|
+
if *debug {
|
60
|
+
fmt.Printf("Transport: %+v\n", transport)
|
61
|
+
}
|
62
|
+
if err != nil {
|
63
|
+
fmt.Println("Error: couldn't connect to Redis:", err)
|
64
|
+
os.Exit(1)
|
65
|
+
}
|
66
|
+
|
67
|
+
reply, err := transport.Send(event)
|
68
|
+
if *debug {
|
69
|
+
fmt.Println("Reply from Redis:", reply)
|
70
|
+
}
|
71
|
+
if err != nil {
|
72
|
+
fmt.Println("Error: couldn't send event:", err)
|
73
|
+
os.Exit(1)
|
74
|
+
}
|
75
|
+
}
|
@@ -11,7 +11,7 @@ describe Flapjack::Data::Entity, :redis => true do
|
|
11
11
|
|
12
12
|
expect(entity).not_to be_nil
|
13
13
|
expect(entity.name).to eq(name)
|
14
|
-
expect(@redis.get("entity_id:#{name}")).to
|
14
|
+
expect(@redis.get("entity_id:#{name}")).to match(/^\S+$/)
|
15
15
|
end
|
16
16
|
|
17
17
|
it "adds a registered contact with an entity" do
|
@@ -3,13 +3,14 @@ require 'flapjack/gateways/jabber'
|
|
3
3
|
|
4
4
|
describe Flapjack::Gateways::Jabber, :logger => true do
|
5
5
|
|
6
|
-
let(:config) { {'queue'
|
7
|
-
'server'
|
8
|
-
'port'
|
9
|
-
'jabberid'
|
10
|
-
'password'
|
11
|
-
'alias'
|
12
|
-
'
|
6
|
+
let(:config) { {'queue' => 'jabber_notifications',
|
7
|
+
'server' => 'example.com',
|
8
|
+
'port' => '5222',
|
9
|
+
'jabberid' => 'flapjack@example.com',
|
10
|
+
'password' => 'password',
|
11
|
+
'alias' => 'flapjack',
|
12
|
+
'identifiers' => ['@flapjack'],
|
13
|
+
'rooms' => ['flapjacktest@conference.example.com']
|
13
14
|
}
|
14
15
|
}
|
15
16
|
|
@@ -26,10 +27,11 @@ describe Flapjack::Gateways::Jabber, :logger => true do
|
|
26
27
|
expect(fj).to receive(:register_handler).with(:ready).and_yield(stanza)
|
27
28
|
expect(fj).to receive(:on_ready).with(stanza)
|
28
29
|
|
29
|
-
|
30
|
+
body_matchers = [{:body => /^@flapjack[:\s]/}, {:body => /^flapjack[:\s]/}]
|
31
|
+
expect(fj).to receive(:register_handler).with(:message, :groupchat?, body_matchers).and_yield(stanza)
|
30
32
|
expect(fj).to receive(:on_groupchat).with(stanza)
|
31
33
|
|
32
|
-
expect(fj).to receive(:register_handler).with(:message, :chat
|
34
|
+
expect(fj).to receive(:register_handler).with(:message, :chat?, :body).and_yield(stanza)
|
33
35
|
expect(fj).to receive(:on_chat).with(stanza)
|
34
36
|
|
35
37
|
expect(fj).to receive(:register_handler).with(:disconnected).and_yield(stanza)
|
@@ -52,9 +54,8 @@ describe Flapjack::Gateways::Jabber, :logger => true do
|
|
52
54
|
end
|
53
55
|
|
54
56
|
it "receives an acknowledgement message" do
|
55
|
-
expect(stanza).to receive(:body).and_return('flapjack: ACKID 1f8ac10f fixing now duration: 90m')
|
57
|
+
expect(stanza).to receive(:body).twice.and_return('flapjack: ACKID 1f8ac10f fixing now duration: 90m')
|
56
58
|
from = double('from')
|
57
|
-
expect(from).to receive(:resource).and_return('sender')
|
58
59
|
expect(from).to receive(:stripped).and_return('sender')
|
59
60
|
expect(stanza).to receive(:from).and_return(from)
|
60
61
|
|
@@ -85,12 +86,11 @@ describe Flapjack::Gateways::Jabber, :logger => true do
|
|
85
86
|
end
|
86
87
|
|
87
88
|
it "strips XML tags from the received message" do
|
88
|
-
expect(stanza).to receive(:body).
|
89
|
+
expect(stanza).to receive(:body).twice.
|
89
90
|
and_return('flapjack: tell me about <span style="text-decoration: underline;">' +
|
90
91
|
'<a href="http://example.org/">example.org</a></span>')
|
91
92
|
|
92
93
|
from = double('from')
|
93
|
-
expect(from).to receive(:resource).and_return('sender')
|
94
94
|
expect(from).to receive(:stripped).and_return('sender')
|
95
95
|
expect(stanza).to receive(:from).and_return(from)
|
96
96
|
|
@@ -119,11 +119,10 @@ describe Flapjack::Gateways::Jabber, :logger => true do
|
|
119
119
|
end
|
120
120
|
|
121
121
|
it "handles a message with a newline in it" do
|
122
|
-
expect(stanza).to receive(:body).
|
122
|
+
expect(stanza).to receive(:body).twice.
|
123
123
|
and_return("flapjack: tell me about \nexample.com")
|
124
124
|
|
125
125
|
from = double('from')
|
126
|
-
expect(from).to receive(:resource).and_return('sender')
|
127
126
|
expect(from).to receive(:stripped).and_return('sender')
|
128
127
|
expect(stanza).to receive(:from).and_return(from)
|
129
128
|
|
@@ -152,9 +151,8 @@ describe Flapjack::Gateways::Jabber, :logger => true do
|
|
152
151
|
end
|
153
152
|
|
154
153
|
it "receives a message it doesn't understand" do
|
155
|
-
expect(stanza).to receive(:body).
|
154
|
+
expect(stanza).to receive(:body).twice.and_return('flapjack: hello!')
|
156
155
|
from = double('from')
|
157
|
-
expect(from).to receive(:resource).and_return('sender')
|
158
156
|
expect(from).to receive(:stripped).and_return('sender')
|
159
157
|
expect(stanza).to receive(:from).and_return(from)
|
160
158
|
|
@@ -14,6 +14,63 @@ describe 'Flapjack::Gateways::JSONAPI::CheckMethods', :sinatra => true, :logger
|
|
14
14
|
|
15
15
|
let(:check_presenter) { double(Flapjack::Gateways::JSONAPI::CheckPresenter) }
|
16
16
|
|
17
|
+
let(:check_data) { {'entity_name' => 'www.example.com', 'name' => 'PING' } }
|
18
|
+
|
19
|
+
it "retrieves all checks" do
|
20
|
+
expect(entity).to receive(:id).and_return('23')
|
21
|
+
|
22
|
+
expect(entity_check).to receive(:entity).and_return(entity)
|
23
|
+
expect(entity_check).to receive(:key).twice.and_return('PING')
|
24
|
+
expect(entity_check).to receive(:to_jsonapi).and_return(check_data.to_json)
|
25
|
+
expect(Flapjack::Data::EntityCheck).to receive(:find_all).with(:redis => redis).
|
26
|
+
and_return([entity_check])
|
27
|
+
|
28
|
+
aget '/checks'
|
29
|
+
expect(last_response).to be_ok
|
30
|
+
expect(last_response.body).to eq({:checks => [check_data]}.to_json)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "retrieves one check" do
|
34
|
+
expect(entity).to receive(:id).and_return('23')
|
35
|
+
|
36
|
+
expect(entity_check).to receive(:entity).and_return(entity)
|
37
|
+
expect(entity_check).to receive(:key).twice.and_return('PING')
|
38
|
+
expect(entity_check).to receive(:to_jsonapi).and_return(check_data.to_json)
|
39
|
+
expect(Flapjack::Data::EntityCheck).to receive(:for_event_id).
|
40
|
+
with('www.example.com:PING', :logger => @logger, :redis => redis).
|
41
|
+
and_return(entity_check)
|
42
|
+
|
43
|
+
aget '/checks/www.example.com:PING'
|
44
|
+
expect(last_response).to be_ok
|
45
|
+
expect(last_response.body).to eq({:checks => [check_data]}.to_json)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "retrieves several entities" do
|
49
|
+
entity_check_2 = double(Flapjack::Data::EntityCheck)
|
50
|
+
check_data_2 = {'name' => 'SSH',
|
51
|
+
'entity_name' => 'www.example.com'}
|
52
|
+
|
53
|
+
expect(entity).to receive(:id).twice.and_return('23')
|
54
|
+
|
55
|
+
expect(entity_check).to receive(:entity).and_return(entity)
|
56
|
+
expect(entity_check).to receive(:key).twice.and_return('PING')
|
57
|
+
expect(entity_check).to receive(:to_jsonapi).and_return(check_data.to_json)
|
58
|
+
expect(Flapjack::Data::EntityCheck).to receive(:for_event_id).
|
59
|
+
with('www.example.com:PING', :logger => @logger, :redis => redis).
|
60
|
+
and_return(entity_check)
|
61
|
+
|
62
|
+
expect(entity_check_2).to receive(:entity).and_return(entity)
|
63
|
+
expect(entity_check_2).to receive(:key).twice.and_return('SSH')
|
64
|
+
expect(entity_check_2).to receive(:to_jsonapi).and_return(check_data_2.to_json)
|
65
|
+
expect(Flapjack::Data::EntityCheck).to receive(:for_event_id).
|
66
|
+
with('www.example.com:SSH', :logger => @logger, :redis => redis).
|
67
|
+
and_return(entity_check_2)
|
68
|
+
|
69
|
+
aget '/checks/www.example.com:PING,www.example.com:SSH'
|
70
|
+
expect(last_response).to be_ok
|
71
|
+
expect(last_response.body).to eq({:checks => [check_data, check_data_2]}.to_json)
|
72
|
+
end
|
73
|
+
|
17
74
|
it 'disables a check' do
|
18
75
|
expect(Flapjack::Data::Entity).to receive(:find_by_name).
|
19
76
|
with(entity_name, :redis => redis).and_return(entity)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
package flapjack
|
2
|
+
|
3
|
+
import "errors"
|
4
|
+
|
5
|
+
// Event is a basic representation of a Flapjack event.
|
6
|
+
// Find more at https://github.com/flapjack/flapjack/wiki/DATA_STRUCTURES
|
7
|
+
type Event struct {
|
8
|
+
Entity string `json:"entity"`
|
9
|
+
Check string `json:"check"`
|
10
|
+
Type string `json:"type"`
|
11
|
+
State string `json:"state"`
|
12
|
+
Summary string `json:"summary"`
|
13
|
+
Time int64 `json:"time"`
|
14
|
+
}
|
15
|
+
|
16
|
+
// IsValid performs basic validations on the event data.
|
17
|
+
func (e Event) IsValid() (error) {
|
18
|
+
// FIXME(auxesis): provide validation errors for each failure
|
19
|
+
if len(e.Entity) == 0 { return errors.New("no entity") }
|
20
|
+
if len(e.Check) == 0 { return errors.New("no check") }
|
21
|
+
if len(e.State) == 0 { return errors.New("no state") }
|
22
|
+
if len(e.Summary) == 0 { return errors.New("no summary") }
|
23
|
+
return nil
|
24
|
+
}
|
25
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
package flapjack
|
2
|
+
|
3
|
+
import "testing"
|
4
|
+
|
5
|
+
func TestValidationFails(t *testing.T) {
|
6
|
+
event := Event{}
|
7
|
+
err := event.IsValid()
|
8
|
+
|
9
|
+
if err == nil {
|
10
|
+
t.Error("Expected validation to fail.")
|
11
|
+
}
|
12
|
+
}
|
13
|
+
|
14
|
+
func TestValidationPasses(t *testing.T) {
|
15
|
+
event := Event{
|
16
|
+
Entity: "hello",
|
17
|
+
Check: "world",
|
18
|
+
State: "ok",
|
19
|
+
Summary: "hello world",
|
20
|
+
}
|
21
|
+
err := event.IsValid()
|
22
|
+
|
23
|
+
if err != nil {
|
24
|
+
t.Error("Expected validation to pass, got:", err)
|
25
|
+
}
|
26
|
+
}
|
@@ -0,0 +1,49 @@
|
|
1
|
+
package flapjack
|
2
|
+
|
3
|
+
import (
|
4
|
+
"encoding/json"
|
5
|
+
"github.com/garyburd/redigo/redis"
|
6
|
+
)
|
7
|
+
|
8
|
+
// Transport is a representation of a Redis connection.
|
9
|
+
type Transport struct {
|
10
|
+
Address string
|
11
|
+
Database int
|
12
|
+
Connection redis.Conn
|
13
|
+
}
|
14
|
+
|
15
|
+
// Dial establishes a connection to Redis, wrapped in a Transport.
|
16
|
+
func Dial(address string, database int) (Transport,error) {
|
17
|
+
// Connect to Redis
|
18
|
+
conn, err := redis.Dial("tcp", address)
|
19
|
+
if err != nil {
|
20
|
+
return Transport{}, err
|
21
|
+
}
|
22
|
+
|
23
|
+
// Switch database
|
24
|
+
conn.Do("SELECT", database)
|
25
|
+
|
26
|
+
transport := Transport{
|
27
|
+
Address: address,
|
28
|
+
Database: database,
|
29
|
+
Connection: conn,
|
30
|
+
}
|
31
|
+
return transport, nil
|
32
|
+
}
|
33
|
+
|
34
|
+
// Send takes an event and sends it over a transport.
|
35
|
+
func (t Transport) Send(event Event) (interface{}, error) {
|
36
|
+
err := event.IsValid()
|
37
|
+
if err == nil {
|
38
|
+
data, _ := json.Marshal(event)
|
39
|
+
reply, err := t.Connection.Do("LPUSH", "events", data)
|
40
|
+
if err != nil {
|
41
|
+
return nil, err
|
42
|
+
}
|
43
|
+
|
44
|
+
return reply, nil
|
45
|
+
} else {
|
46
|
+
return nil, err
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
package flapjack
|
2
|
+
|
3
|
+
import "testing"
|
4
|
+
|
5
|
+
func TestDialFails(t *testing.T) {
|
6
|
+
address := "localhost:55555" // non-existent Redis server
|
7
|
+
database := 0
|
8
|
+
_, err := Dial(address, database)
|
9
|
+
|
10
|
+
if err == nil {
|
11
|
+
t.Error("Dial should fail")
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
// TODO(auxesis): add test for sending and receiving Events
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flapjack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.0rc2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lindsay Holmwood
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2014-
|
13
|
+
date: 2014-07-17 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: dante
|
@@ -356,6 +356,7 @@ files:
|
|
356
356
|
- README.md
|
357
357
|
- Rakefile
|
358
358
|
- bin/flapjack
|
359
|
+
- build.sh
|
359
360
|
- dist/etc/init.d/flapjack
|
360
361
|
- dist/etc/init.d/flapjack-nagios-receiver
|
361
362
|
- dist/etc/init.d/flapper
|
@@ -501,6 +502,8 @@ files:
|
|
501
502
|
- lib/flapjack/redis_pool.rb
|
502
503
|
- lib/flapjack/utility.rb
|
503
504
|
- lib/flapjack/version.rb
|
505
|
+
- libexec/httpbroker.go
|
506
|
+
- libexec/oneoff.go
|
504
507
|
- log/.gitkeep
|
505
508
|
- spec/lib/flapjack/coordinator_spec.rb
|
506
509
|
- spec/lib/flapjack/data/contact_spec.rb
|
@@ -546,6 +549,10 @@ files:
|
|
546
549
|
- spec/support/jsonapi_helper.rb
|
547
550
|
- spec/support/profile_all_formatter.rb
|
548
551
|
- spec/support/uncolored_doc_formatter.rb
|
552
|
+
- src/flapjack/event.go
|
553
|
+
- src/flapjack/event_test.go
|
554
|
+
- src/flapjack/transport.go
|
555
|
+
- src/flapjack/transport_test.go
|
549
556
|
- tasks/benchmarks.rake
|
550
557
|
- tasks/events.rake
|
551
558
|
- tasks/profile.rake
|