flapjack 1.0.0rc1 → 1.0.0rc2

Sign up to get free protection for your applications and to get access to all the features.
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 eq('')
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' => 'jabber_notifications',
7
- 'server' => 'example.com',
8
- 'port' => '5222',
9
- 'jabberid' => 'flapjack@example.com',
10
- 'password' => 'password',
11
- 'alias' => 'flapjack',
12
- 'rooms' => ['flapjacktest@conference.example.com']
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
- expect(fj).to receive(:register_handler).with(:message, :groupchat?, :body => /^flapjack:\s+/).and_yield(stanza)
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?).and_yield(stanza)
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).once.and_return('flapjack: hello!')
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.0rc1
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-06-25 00:00:00.000000000 Z
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