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.
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