ey_stonith 0.3.6 → 0.4.1.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/.gitignore +10 -0
  2. data/Gemfile +3 -0
  3. data/Rakefile +26 -0
  4. data/ey_stonith.gemspec +36 -0
  5. data/features/check.feature +57 -0
  6. data/features/cron.feature +67 -0
  7. data/features/fixtures/dead.ru +6 -0
  8. data/features/fixtures/healthy.ru +1 -0
  9. data/features/help.feature +7 -0
  10. data/features/not_found.feature +24 -0
  11. data/features/notify.feature +35 -0
  12. data/features/resume.feature +49 -0
  13. data/features/steps/stonith_steps.rb +40 -0
  14. data/features/stop.feature +48 -0
  15. data/features/support/env.rb +77 -0
  16. data/lib/ey_stonith/awsm_notifier.rb +13 -8
  17. data/lib/ey_stonith/commands/abstract.rb +0 -4
  18. data/lib/ey_stonith/commands/check.rb +13 -36
  19. data/lib/ey_stonith/commands/claim.rb +5 -96
  20. data/lib/ey_stonith/commands/cron.rb +3 -5
  21. data/lib/ey_stonith/commands/info.rb +1 -4
  22. data/lib/ey_stonith/commands/not_found.rb +1 -0
  23. data/lib/ey_stonith/commands/notify.rb +16 -55
  24. data/lib/ey_stonith/commands/reset.rb +0 -1
  25. data/lib/ey_stonith/commands/stop.rb +0 -1
  26. data/lib/ey_stonith/commands/takeover.rb +5 -90
  27. data/lib/ey_stonith/commands.rb +1 -1
  28. data/lib/ey_stonith/config.rb +17 -66
  29. data/lib/ey_stonith/rackapp.rb +26 -2
  30. data/lib/ey_stonith.rb +8 -15
  31. data/spec/config_spec.rb +53 -0
  32. data/spec/fixtures/config.yml +11 -0
  33. data/spec/fixtures/empty.yml +1 -0
  34. data/spec/helpers.rb +15 -0
  35. data/spec/history_spec.rb +58 -0
  36. data/spec/rackapp_spec.rb +100 -0
  37. data/spec/spec_helper.rb +24 -0
  38. metadata +240 -60
  39. data/lib/ey_stonith/address_stealer.rb +0 -40
  40. data/lib/ey_stonith/check_recorder.rb +0 -55
  41. data/lib/ey_stonith/data.rb +0 -11
  42. data/lib/ey_stonith/database.rb +0 -78
@@ -2,110 +2,19 @@ module EY
2
2
  module Stonith
3
3
  module Commands
4
4
  class Claim < Abstract
5
-
6
5
  def self.command
7
6
  'claim'
8
7
  end
9
8
 
10
9
  def self.banner
11
- 'Claim the master record in the database'
12
- end
13
-
14
- def claim_path
15
- @claim_path ||= config.claim_path
10
+ "Legacy command. No longer used."
16
11
  end
17
12
 
18
13
  def invoke
19
- claim_path.exist?? invoke_with_claim_file : invoke_without_claim_file
20
- end
21
-
22
- def invoke_with_claim_file
23
- abort_on_existing_data
24
-
25
- attempts = (claim_path.read || 0).to_i.succ
26
-
27
- if @force || attempts >= 6
28
- reclaim!
29
- else
30
- persist_reclaim_attempt(attempts)
31
- end
32
- end
33
-
34
- def abort_on_existing_data
35
- return unless master_hostname
36
-
37
- if config.meta_data_hostname == master_hostname
38
- abort "Already claimed, not claiming."
39
- else
40
- claim_path.delete
41
- abort "#{master_hostname} is master, not claiming.\nRemoving stale claim file."
42
- end
43
- end
44
-
45
- def reclaim!
46
- Stonith.logger.info @force ? "Reclaim forced." : "Reclaim after 6 consecutive checks."
47
- claim_path.delete
48
- invoke_without_claim_file
49
- end
50
-
51
- def persist_reclaim_attempt(attempts)
52
- claim_path.open("w") { |f| f << attempts }
53
-
54
- abort <<-ERROR
55
- Master unknown and claim file exists, not claiming.
56
- Reclaim at 6th attempt or use --force
57
-
58
- Failed attempts: #{attempts}
59
- ERROR
60
- end
61
-
62
- def invoke_without_claim_file
63
- @force ? database.reset : confirm_master!
64
-
65
- data = Data.new(config.meta_data_hostname, config.meta_data_id, config.meta_data_ip)
66
- database.set data
67
- claim_path.open('w') {}
68
-
69
- Stonith.logger.info "Claimed with data: #{data}"
70
- history << :claim
71
- end
72
-
73
- def confirm_master!
74
- # TODO: Only claim if the master has an IP?
75
- # if fog.servers.get(config.meta_data_id).addresses.empty?
76
- # abort "No IP, not claiming." + (@force ? "\nIgnoring --force" : "")
77
- # end
78
-
79
- confirm_master_with_database
80
- confirm_master_with_config
81
- end
82
-
83
- def confirm_master_with_database
84
- return unless master_hostname
85
-
86
- if config.meta_data_hostname == master_hostname
87
- claim_path.open('w') {}
88
- abort "Already claimed, not claiming. Touching claim file."
89
- else
90
- abort "#{master_hostname} is master, not claiming."
91
- end
92
- end
93
-
94
- def confirm_master_with_config
95
- if config.meta_data_hostname != config.monitor_host
96
- abort "#{config.monitor_host} is master, not claiming."
97
- end
98
- end
99
-
100
- def master_hostname
101
- @master_hostname ||= database.with_data { |data| data.hostname }
102
- end
103
-
104
- def parser
105
- super.on('-f', '--force', "Force the command (only applicable to claim currently)") do |f|
106
- @force = f
107
- end
108
- super
14
+ puts <<-HELP
15
+ Yo Dawg, I heard you like Claim, but we removed it because we don't do that anymore, so stop using it.
16
+ There is no replacement command needed. Just update instances to update the master.
17
+ HELP
109
18
  end
110
19
  end
111
20
  end
@@ -13,7 +13,7 @@ module EY
13
13
  def invoke
14
14
  Stonith.logger.info "Stonith started"
15
15
  heartbeat_loop do |beat|
16
- unless_stopped { run_commands if beat.zero? }
16
+ unless_stopped { run_command if beat.zero? }
17
17
  sleep 1
18
18
  end
19
19
  end
@@ -30,10 +30,8 @@ module EY
30
30
  end
31
31
  end
32
32
 
33
- def run_commands
34
- %w[claim notify check].each do |cmd|
35
- system("#{script} #{cmd}#{command_options}")
36
- end
33
+ def run_command
34
+ system("#{script} check#{command_options}")
37
35
  end
38
36
  end
39
37
  end
@@ -7,14 +7,11 @@ module EY
7
7
  end
8
8
 
9
9
  def self.banner
10
- "Print the full config file and database contents"
10
+ "Print the full config file"
11
11
  end
12
12
 
13
13
  def invoke
14
14
  puts config
15
- puts "Database:"
16
- data = database.with_data { |data| data }
17
- puts " #{data}"
18
15
  end
19
16
  end
20
17
  end
@@ -3,6 +3,7 @@ module EY
3
3
  module Commands
4
4
  class NotFound < Abstract
5
5
  def invoke
6
+ Stonith.logger.error "Command not found: #{@argv.inspect}"
6
7
  abort "Command not found #{@argv.first.inspect}.\n#{parser}"
7
8
  end
8
9
  end
@@ -7,7 +7,7 @@ module EY
7
7
  end
8
8
 
9
9
  def self.banner
10
- 'Notify the provisioning server about a takeover'
10
+ 'Notify the provisioning server that master is down.'
11
11
  end
12
12
 
13
13
  def notify_path
@@ -15,70 +15,31 @@ module EY
15
15
  end
16
16
 
17
17
  def invoke
18
- abort_if_unintentional
19
-
20
- notify_path.delete if notify_path.exist?
21
-
22
- database.with_data do |data|
23
- abort_if_master data.hostname
24
- notify!
25
- end
26
-
27
- abort_no_data
28
- end
29
-
30
- def abort_if_unintentional
31
- return if @force || notify_path.exist?
32
-
33
- abort <<-ERROR
34
- Cannot notify, #{notify_path} does not exist.
35
- If you want to (destructively) notify AWSM that this instance is master, call with --force.
36
- ERROR
37
- end
38
-
39
- def abort_if_master(hostname)
40
- if config.meta_data_hostname != hostname
41
- Stonith.logger.error "Cannot notify, I am not master. Master is #{hostname}. Cancelling notify."
42
- abort "Cannot notify, I am not master."
43
- end
44
- end
45
-
46
- def abort_no_data
47
- msg = "Cannot notify, there is no master in the database. Giving up."
48
- Stonith.logger.error msg
49
- abort msg
18
+ Stonith.logger.warn "Notifying provisioning server that master is down."
19
+ history << :notify
20
+ notify!
21
+ exit
50
22
  end
51
23
 
52
24
  def notify!
53
- notifier = AwsmNotifier.new config.meta_data_id, config.takeover_uri, config.endpoint_token
54
- notifier.notify method(:success), method(:unreachable), method(:refused)
25
+ notifier = AwsmNotifier.new(config.notify_uri, config.endpoint_id, config.endpoint_token, {
26
+ 'monitor_host' => config.monitor_host
27
+ })
28
+
29
+ notifier.notify method(:success), method(:unreachable)
55
30
  end
56
31
 
57
- def success
58
- Stonith.logger.info "AWSM notified!"
32
+ def success(data)
59
33
  history << :notified
60
- exit
34
+ count = data['notification_count'] || 'N/A'
35
+ takeover = data['takeover'].inspect
36
+ Stonith.logger.info "Provisioning server notified: (notification_count: #{count}, takeover: #{takeover})"
61
37
  end
62
38
 
63
39
  def unreachable
64
- notify_path.open('w') {}
65
- msg = "Unable to reach AWSM for promotion to master."
40
+ msg = "Unable to notify provisioning server that master is down."
66
41
  Stonith.logger.warn msg
67
- abort "#{msg}\nIf you're running this from the command line, you should run ey-monitor-notify again."
68
- end
69
-
70
- def refused(response_body)
71
- msg = "Notify refused by endpoint. Giving up.\nResponse: #{response_body}"
72
- Stonith.logger.error msg
73
- history << :refused
74
- abort msg
75
- end
76
-
77
- def parser
78
- super.on '-f', '--force', "Force the command (only applicable to claim currently)" do |f|
79
- @force = f
80
- end
81
- super
42
+ abort "#{msg}\nIf you're running this from the command line, you should run `stonith notify` again."
82
43
  end
83
44
  end
84
45
  end
@@ -11,7 +11,6 @@ module EY
11
11
  end
12
12
 
13
13
  def invoke
14
- database.reset
15
14
  config.state_path.rmtree
16
15
  Stonith.logger.info "All state and database reset!"
17
16
  end
@@ -15,7 +15,6 @@ module EY
15
15
  sleep(0.5) until history.last == "stop"
16
16
 
17
17
  Stonith.logger.info "Stonith stopped"
18
- puts "takeover" if history.include?(:takeover)
19
18
  end
20
19
  end
21
20
  end
@@ -1,5 +1,3 @@
1
- require 'pathname'
2
-
3
1
  module EY
4
2
  module Stonith
5
3
  module Commands
@@ -9,97 +7,14 @@ module EY
9
7
  end
10
8
 
11
9
  def self.banner
12
- 'Cause a takeover of the specified master'
10
+ "Legacy command. No longer used. Run this command for more info."
13
11
  end
14
12
 
15
13
  def invoke
16
- abort_if_no_instance_id
17
- abort_if_self
18
-
19
- abort_if_takeover_lock
20
- set_takeover_lock
21
-
22
- database.with_locked_data do |data|
23
- restore_data_on_fail(data)
24
-
25
- if instance_id == data.instance_id
26
- locked!(data.instance_id, data.ip)
27
- else
28
- relent!
29
- end
30
- end
31
- end
32
-
33
- def abort_if_no_instance_id
34
- if !instance_id || instance_id == ""
35
- abort "Please call with the instance_id of the master to takeover.\n\n#{parser}"
36
- end
37
- end
38
-
39
- def abort_if_self
40
- if instance_id == config.meta_data_id
41
- abort "Cannot takeover self!"
42
- end
43
- end
44
-
45
- def abort_if_takeover_lock
46
- if config.takeover_path.exist?
47
- abort "Already attempting takeover!\n#{config.takeover_path.read}"
48
- end
49
- end
50
-
51
- def takeover_path
52
- @takeover_path ||= config.takeover_path
53
- end
54
-
55
- def set_takeover_lock
56
- at_exit { takeover_path.delete if takeover_path.exist? }
57
- takeover_path.open('w') { |f| f << "Takeover started at #{Time.now}" }
58
- end
59
-
60
- def restore_data_on_fail(data)
61
- at_exit do
62
- if database.set(data) # always replace the data if it wasn't set
63
- Stonith.logger.error("Emergency replacement of redis data #{data.inspect} occurred.")
64
- end
65
- end
66
- end
67
-
68
- def locked!(instance_id, master_ip)
69
- Stonith.logger.info "Locked! Taking over #{instance_id}."
70
- history << :takeover
71
-
72
- ip = steal_address(instance_id, master_ip)
73
- data = Data.new(config.meta_data_hostname, config.meta_data_id, ip)
74
- database.set data
75
-
76
- takeover_path.delete
77
- execute :notify, "--force"
78
- end
79
-
80
- def relent!
81
- history << :relent
82
- msg = "Failed to grab lock, relenting."
83
- Stonith.logger.info msg
84
- abort msg
85
- end
86
-
87
- def steal_address(instance_id, ip)
88
- Stonith.logger.info "Stealing IP #{ip} from #{instance_id}."
89
- address = AddressStealer.new(instance_id, ip, config.fog_credentials)
90
- address.associate(config.meta_data_id)
91
- address.ip
92
- end
93
-
94
- def instance_id
95
- @instance_id
96
- end
97
-
98
- def parser
99
- super.on('-i', '--instance INSTANCE_ID', "Amazon Instance ID of the failing master") do |instance|
100
- @instance_id = instance
101
- end
102
- super
14
+ puts <<-HELP
15
+ Takeovers are no longer performed from the instance side directly.
16
+ You can cause a takeover by running `stonith notify` 6 times quickly if you really need to.
17
+ HELP
103
18
  end
104
19
  end
105
20
  end
@@ -14,8 +14,8 @@ module EY
14
14
  'help' => :Help,
15
15
  'info' => :Info,
16
16
  'notify' => :Notify,
17
- 'reset' => :Reset,
18
17
  'resume' => :Resume,
18
+ 'reset' => :Reset,
19
19
  'status' => :Status,
20
20
  'stop' => :Stop,
21
21
  'takeover' => :Takeover,
@@ -1,6 +1,5 @@
1
1
  require 'yaml'
2
2
  require 'json'
3
- require 'open-uri'
4
3
 
5
4
  module EY
6
5
  module Stonith
@@ -24,24 +23,15 @@ module EY
24
23
  end
25
24
 
26
25
  DEFAULT = {
27
- 'log' => '/var/log/stonith.log',
28
- 'state_dir' => '/var/run/stonith',
29
- 'heartbeat' => 10,
30
- 'endpoint_uri' => nil,
31
- 'endpoint_token' => nil,
32
-
33
- 'monitor_host' => nil,
34
- 'monitor_path' => '/haproxy/monitor',
26
+ 'log' => '/var/log/stonith.log',
27
+ 'state_dir' => '/var/run/stonith',
28
+ 'heartbeat' => 10,
29
+ 'endpoint_uri' => nil,
30
+ 'endpoint_token' => nil,
31
+ 'endpoint_id' => nil,
32
+ 'monitor_host' => nil,
33
+ 'monitor_path' => '/haproxy/monitor',
35
34
  'monitor_timeout' => 5,
36
-
37
- 'redis_host' => nil,
38
- 'redis_port' => 6379,
39
- 'redis_key' => 'stonith',
40
- 'redis_db' => 14,
41
- 'redis_timeout' => 60 * 5,
42
-
43
- 'aws_secret_id' => nil,
44
- 'aws_secret_key' => nil,
45
35
  }
46
36
 
47
37
  def initialize(config_path)
@@ -65,71 +55,36 @@ Config:
65
55
 
66
56
  state_path: #{state_path}
67
57
  stop_path: #{stop_path}
68
- claim_path: #{claim_path}
69
- checks_path: #{checks_path}
70
- notify_path: #{notify_path}
71
58
  history_path: #{history_path}
72
- takeover_path: #{takeover_path}
59
+ success_path: #{success_path}
73
60
 
74
- endpoint_uri: #{endpoint_uri}
61
+ endpoint_uri: #{endpoint_uri}
75
62
  endpoint_token: #{endpoint_token}
76
- takeover_uri: #{takeover_uri}
77
- fog_credentials: #{fog_credentials.inspect}
78
- awsm_credentials: #{awsm_credentials.inspect}
79
-
80
- meta_data_hostname: #{meta_data_hostname}
81
- meta_data_id: #{meta_data_id}
82
- meta_data_ip: #{meta_data_ip}
63
+ endpoint_id: #{endpoint_id}
64
+ notify_uri: #{notify_uri}
83
65
 
84
- monitor_host: #{monitor_host}
85
- monitor_path: #{monitor_path}
66
+ monitor_host: #{monitor_host}
67
+ monitor_path: #{monitor_path}
86
68
  monitor_timeout: #{monitor_timeout}
87
-
88
- redis_host: #{redis_host}
89
- redis_port: #{redis_port}
90
- redis_key: #{redis_key}
91
- redis_db: #{redis_db}
92
- redis_timeout: #{redis_timeout}
93
69
  STRING
94
70
  end
95
71
 
96
72
  def log_path() pathname(log) end
97
73
  def state_path() ensure_exists(pathname(state_dir)) end
98
74
  def stop_path() state_path + 'stop' end
99
- def claim_path() state_path + 'claim' end
100
- def checks_path() state_path + 'checks' end
101
- def notify_path() state_path + 'notify' end
102
75
  def history_path() state_path + 'history' end
103
- def takeover_path() state_path + 'takeover' end
76
+ def success_path() state_path + 'success' end
104
77
  def endpoint_uri() URI.parse(method_missing('endpoint_uri')) end
105
- def takeover_uri
78
+ def notify_uri
106
79
  result = endpoint_uri
107
- result.path << TAKEOVER_PATH
80
+ result.path << NOTIFY_PATH
108
81
  result
109
82
  end
110
83
 
111
- def meta_data_hostname() @data['meta_data_hostname'] ||= meta_data('local-hostname') end
112
- def meta_data_id() @data['meta_data_id'] ||= meta_data('instance-id') end
113
- def meta_data_ip() @data['meta_data_ip'] || meta_data('public-ipv4') end # don't cache
114
-
115
84
  def respond_to?(meth)
116
85
  @data.key?(meth) || super
117
86
  end
118
87
 
119
- def awsm_credentials
120
- {
121
- 'aws_secret_id' => aws_secret_id,
122
- 'aws_secret_key' => aws_secret_key,
123
- }
124
- end
125
-
126
- def fog_credentials
127
- {
128
- :aws_access_key_id => aws_secret_id,
129
- :aws_secret_access_key => aws_secret_key,
130
- }
131
- end
132
-
133
88
  private
134
89
 
135
90
  def self.secret_hack
@@ -139,10 +94,6 @@ Config:
139
94
  def self.pwned?
140
95
  @secret_hack
141
96
  end
142
-
143
- def meta_data(key)
144
- open("http://169.254.169.254/latest/meta-data/#{key}").read
145
- end
146
97
 
147
98
  def pathname(path) path && Pathname.new(path) end
148
99
 
@@ -4,8 +4,12 @@ require 'json'
4
4
  module EY
5
5
  module Stonith
6
6
  class Rackapp < Sinatra::Base
7
+ enable :raise_errors
8
+ disable :dump_errors
9
+ disable :show_exceptions
10
+
7
11
  before { content_type :json }
8
- get('/') { {}.to_json }
12
+ get('/') { '' }
9
13
 
10
14
  get HEALTH_PATH do
11
15
  unless EY::Stonith.healthy?
@@ -15,14 +19,34 @@ module EY
15
19
  end
16
20
 
17
21
  post TAKEOVER_PATH do
18
- unless EY::Stonith.takeover(label, token)
22
+ if valid?
23
+ unless EY::Stonith.takeover(label)
24
+ status 410
25
+ end
26
+ else
19
27
  status 410
20
28
  end
21
29
  {}.to_json
22
30
  end
23
31
 
32
+ post NOTIFY_PATH do
33
+ if valid?
34
+ EY::Stonith.notify(label, params[:monitor_host])
35
+ {
36
+ 'notification_count' => '1',
37
+ 'takeover' => false
38
+ }.to_json
39
+ else
40
+ status 403
41
+ end
42
+ end
43
+
24
44
  private
25
45
 
46
+ def valid?
47
+ EY::Stonith.valid?(label, token)
48
+ end
49
+
26
50
  def label() params['label'] end
27
51
  def token() params['token'] end
28
52
  end
data/lib/ey_stonith.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'logger'
2
+ require 'open-uri'
2
3
 
3
4
  $LOAD_PATH.unshift(File.expand_path('..', __FILE__))
4
5
 
@@ -6,25 +7,15 @@ module EY
6
7
  module Stonith
7
8
  class Error < StandardError; end
8
9
 
9
- autoload :AbstractMaster, 'ey_stonith/abstract_master'
10
10
  autoload :AwsmNotifier, 'ey_stonith/awsm_notifier'
11
- autoload :AddressStealer, 'ey_stonith/address_stealer'
12
- autoload :Box, 'ey_stonith/box'
13
- autoload :CheckRecorder, 'ey_stonith/check_recorder'
14
11
  autoload :Commands, 'ey_stonith/commands'
15
- autoload :CLI, 'ey_stonith/cli'
16
12
  autoload :Config, 'ey_stonith/config'
17
- autoload :Data, 'ey_stonith/data'
18
- autoload :Database, 'ey_stonith/database'
19
13
  autoload :History, 'ey_stonith/history'
20
- autoload :LocalMaster, 'ey_stonith/local_master'
21
- autoload :Master, 'ey_stonith/master'
22
- autoload :MetaData, 'ey_stonith/meta_data'
23
14
  autoload :Rackapp, 'ey_stonith/rackapp'
24
- autoload :Slave, 'ey_stonith/slave'
25
15
 
26
16
  HEALTH_PATH = '/health' unless defined? HEALTH_PATH
27
17
  TAKEOVER_PATH = '/takeover' unless defined? TAKEOVER_PATH
18
+ NOTIFY_PATH = '/notify' unless defined? NOTIFY_PATH
28
19
 
29
20
  def self.log_to(io)
30
21
  @@logger = Logger.new io
@@ -38,10 +29,12 @@ module EY
38
29
 
39
30
  def self.healthy?() callback_module.healthy? end
40
31
 
41
- def self.takeover(label, token)
42
- if valid? label, token
43
- callback_module.takeover label
44
- end
32
+ def self.takeover(label)
33
+ callback_module.takeover label
34
+ end
35
+
36
+ def self.notify(label, monitor_host)
37
+ callback_module.notify label, monitor_host
45
38
  end
46
39
 
47
40
  def self.valid?(label, token)
@@ -0,0 +1,53 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+ require 'pathname'
3
+
4
+ describe EY::Stonith::Config do
5
+ before { described_class.send(:secret_hack) }
6
+ def fixture_path(file)
7
+ Pathname.new(File.expand_path(File.join('../fixtures', file), __FILE__))
8
+ end
9
+
10
+ describe "default" do
11
+ subject { described_class.new(fixture_path('empty.yml')) }
12
+
13
+ def self.it_requires(key)
14
+ it(key) { lambda { subject.send(key) }.should raise_error(EY::Stonith::Config::RequiredSetting) }
15
+ end
16
+
17
+ its(:path) { should == fixture_path('empty.yml') }
18
+ its(:log_path) { should == Pathname.new('/var/log/stonith.log') }
19
+ its(:state_path) { should == Pathname.new('/var/run/stonith') }
20
+ its(:stop_path) { should == Pathname.new('/var/run/stonith/stop') }
21
+ its(:history_path) { should == Pathname.new('/var/run/stonith/history') }
22
+ its(:success_path) { should == Pathname.new('/var/run/stonith/success') }
23
+ its(:heartbeat) { should == 10 }
24
+
25
+ it_requires(:monitor_host)
26
+ its(:monitor_path) { should == '/haproxy/monitor' }
27
+ its(:monitor_timeout) { should == 5 }
28
+
29
+ it_requires(:endpoint_uri)
30
+ it_requires(:endpoint_token)
31
+ it_requires(:endpoint_id)
32
+ end
33
+
34
+ describe "overridden" do
35
+ subject { described_class.new(fixture_path('config.yml')) }
36
+
37
+ its(:path) { should == fixture_path('config.yml') }
38
+ its(:log_path) { should == Pathname.new('var/log/stonith.log') }
39
+ its(:state_path) { should == Pathname.new('var/run/stonith') }
40
+ its(:stop_path) { should == Pathname.new('var/run/stonith/stop') }
41
+ its(:history_path) { should == Pathname.new('var/run/stonith/history') }
42
+ its(:success_path) { should == Pathname.new('var/run/stonith/success') }
43
+ its(:heartbeat) { should == 1 }
44
+
45
+ its(:monitor_host) { should == 'localhost' }
46
+ its(:monitor_path) { should == '/chickity/check' }
47
+ its(:monitor_timeout) { should == 10 }
48
+
49
+ its(:endpoint_uri) { should == URI.parse('http://example.com/stonith') }
50
+ its(:endpoint_token) { should == 'i-87654321' }
51
+ its(:endpoint_id) { should == "i-87654321" }
52
+ end
53
+ end