Class: BigBrother::Cluster

Inherits:
Object
  • Object
show all
Defined in:
lib/big_brother/cluster.rb

Direct Known Subclasses

ActiveActiveCluster, ActivePassiveCluster

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, attributes = {}) ⇒ Cluster



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# File 'lib/big_brother/cluster.rb', line 5

def initialize(name, attributes = {})
  @name = name
  @fwmark = attributes[:fwmark]
  @scheduler = attributes[:scheduler]
  @check_interval = attributes.fetch(:check_interval, 1)
  @monitored = false
  @nodes = attributes.fetch(:nodes, []).map { |node_config| _coerce_node(node_config) }
  @last_check = Time.new(0)
  @up_file = BigBrother::StatusFile.new('up', @name)
  @down_file = BigBrother::StatusFile.new('down', @name)
  @ramp_up_time = attributes.fetch(:ramp_up_time, 60)
  @has_downpage = attributes[:has_downpage]
  @nagios = attributes[:nagios]
  @backend_mode = attributes[:backend_mode]
end

Instance Attribute Details

#backend_modeObject (readonly)

Returns the value of attribute backend_mode.



3
4
5
# File 'lib/big_brother/cluster.rb', line 3

def backend_mode
  @backend_mode
end

#check_intervalObject (readonly)

Returns the value of attribute check_interval.



3
4
5
# File 'lib/big_brother/cluster.rb', line 3

def check_interval
  @check_interval
end

#fwmarkObject (readonly)

Returns the value of attribute fwmark.



3
4
5
# File 'lib/big_brother/cluster.rb', line 3

def fwmark
  @fwmark
end

#nagiosObject (readonly)

Returns the value of attribute nagios.



3
4
5
# File 'lib/big_brother/cluster.rb', line 3

def nagios
  @nagios
end

#nameObject (readonly)

Returns the value of attribute name.



3
4
5
# File 'lib/big_brother/cluster.rb', line 3

def name
  @name
end

#nodesObject (readonly)

Returns the value of attribute nodes.



3
4
5
# File 'lib/big_brother/cluster.rb', line 3

def nodes
  @nodes
end

#ramp_up_timeObject (readonly)

Returns the value of attribute ramp_up_time.



3
4
5
# File 'lib/big_brother/cluster.rb', line 3

def ramp_up_time
  @ramp_up_time
end

#schedulerObject (readonly)

Returns the value of attribute scheduler.



3
4
5
# File 'lib/big_brother/cluster.rb', line 3

def scheduler
  @scheduler
end

Instance Method Details

#==(other) ⇒ Object



107
108
109
# File 'lib/big_brother/cluster.rb', line 107

def ==(other)
  fwmark == other.fwmark
end

#_add_maintenance_nodeObject



134
135
136
137
# File 'lib/big_brother/cluster.rb', line 134

def _add_maintenance_node
  BigBrother.logger.info "Adding downpage to cluster #{self}"
  BigBrother.ipvs.start_node(fwmark, '169.254.254.254', 1)
end

#_add_nodes(addresses) ⇒ Object



127
128
129
130
131
132
# File 'lib/big_brother/cluster.rb', line 127

def _add_nodes(addresses)
  addresses.each do |address|
    BigBrother.logger.info "Adding #{address} to cluster #{self}"
    BigBrother.ipvs.start_node(fwmark, address, 0)
  end
end

#_check_downpageObject



139
140
141
142
143
144
145
146
147
148
# File 'lib/big_brother/cluster.rb', line 139

def _check_downpage
  total_health = @nodes.collect{ |n| n.weight || 0 }.reduce(:+)
  if total_health <= 0
    _add_maintenance_node unless downpage_enabled?
    @downpage_enabled = true
  else
    _remove_maintenance_node if downpage_enabled?
    @downpage_enabled = false
  end
end

#_coerce_node(node_config) ⇒ Object



21
22
23
# File 'lib/big_brother/cluster.rb', line 21

def _coerce_node(node_config)
  node_config.is_a?(Node) ? node_config : Node.new(node_config)
end

#_notify_nagiosObject



150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/big_brother/cluster.rb', line 150

def _notify_nagios
  nodes_down = @nodes.count{|n| n.weight == 0}
  return if @last_node_count == nodes_down
  if ((nodes_down / @nodes.count.to_f) >= 0.5)
    BigBrother.nagios.send_critical(nagios[:host], nagios[:check], "50% of nodes are down", nagios[:server])
  elsif nodes_down > 0
    BigBrother.nagios.send_warning(nagios[:host], nagios[:check], "a node is down", nagios[:server])
  else
    BigBrother.nagios.send_ok(nagios[:host], nagios[:check], "all nodes up", nagios[:server])
  end
  @last_node_count = nodes_down
end

#_remove_maintenance_nodeObject



163
164
165
# File 'lib/big_brother/cluster.rb', line 163

def _remove_maintenance_node
  BigBrother.ipvs.stop_node(fwmark, '127.0.0.1')
end

#_remove_nodes(addresses) ⇒ Object



167
168
169
170
171
172
# File 'lib/big_brother/cluster.rb', line 167

def _remove_nodes(addresses)
  addresses.each do |address|
    BigBrother.logger.info "Removing #{address} to cluster #{self}"
    BigBrother.ipvs.stop_node(fwmark, address)
  end
end

#_update_node(node, new_weight) ⇒ Object



174
175
176
# File 'lib/big_brother/cluster.rb', line 174

def _update_node(node, new_weight)
  BigBrother.ipvs.edit_node(fwmark, node.address, new_weight)
end

#cluster_nodesObject



79
80
81
# File 'lib/big_brother/cluster.rb', line 79

def cluster_nodes
  nodes.map(&:address)
end

#combined_weightObject



25
26
27
# File 'lib/big_brother/cluster.rb', line 25

def combined_weight
  nodes.inject(0) { |sum, node| sum + node.weight.to_i }
end

#down_file_exists?Boolean



115
116
117
# File 'lib/big_brother/cluster.rb', line 115

def down_file_exists?
  @down_file.exists?
end

#downpage_enabled?Boolean



29
30
31
# File 'lib/big_brother/cluster.rb', line 29

def downpage_enabled?
  @downpage_enabled
end

#find_node(address, port) ⇒ Object



33
34
35
# File 'lib/big_brother/cluster.rb', line 33

def find_node(address, port)
  nodes.find{|node| node.address == address && node.port == port}
end

#has_downpage?Boolean



37
38
39
# File 'lib/big_brother/cluster.rb', line 37

def has_downpage?
  @has_downpage
end

#incorporate_state(another_cluster) ⇒ Object



119
120
121
122
123
124
125
# File 'lib/big_brother/cluster.rb', line 119

def incorporate_state(another_cluster)
  nodes.each do |node|
    node.incorporate_state(another_cluster.find_node(node.address, node.port))
  end

  self
end

#monitor_nodesObject



88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/big_brother/cluster.rb', line 88

def monitor_nodes
  @last_check = Time.now
  return unless monitored?
  @nodes.each do |node|
    new_weight = node.monitor(self)
    if new_weight != node.weight
      _update_node(node, new_weight)
      node.weight = new_weight
    end
  end

  _check_downpage if has_downpage?
  _notify_nagios if nagios
end

#monitored?Boolean



41
42
43
# File 'lib/big_brother/cluster.rb', line 41

def monitored?
  @monitored
end

#needs_check?Boolean



83
84
85
86
# File 'lib/big_brother/cluster.rb', line 83

def needs_check?
  return false unless monitored?
  @last_check + @check_interval < Time.now
end

#resume_monitoring!Object



63
64
65
66
# File 'lib/big_brother/cluster.rb', line 63

def resume_monitoring!
  BigBrother.logger.info "Resuming monitoring on cluster #{to_s}"
  @monitored = true
end

#start_monitoring!Object



45
46
47
48
49
50
51
52
53
# File 'lib/big_brother/cluster.rb', line 45

def start_monitoring!
  BigBrother.logger.info "Starting monitoring on cluster #{to_s}"
  BigBrother.ipvs.start_cluster(@fwmark, @scheduler)
  @nodes.each do |node|
    BigBrother.ipvs.start_node(@fwmark, node.address, BigBrother::Node::INITIAL_WEIGHT)
  end

  @monitored = true
end

#stop_monitoring!Object



55
56
57
58
59
60
61
# File 'lib/big_brother/cluster.rb', line 55

def stop_monitoring!
  BigBrother.logger.info "Stopping monitoring on cluster #{to_s}"
  BigBrother.ipvs.stop_cluster(@fwmark)

  @monitored = false
  @nodes.each(&:invalidate_weight!)
end

#synchronize!Object



68
69
70
71
72
73
74
75
76
77
# File 'lib/big_brother/cluster.rb', line 68

def synchronize!
  ipvs_state = BigBrother.ipvs.running_configuration
  if ipvs_state.has_key?(fwmark.to_s)
    resume_monitoring!

    running_nodes = ipvs_state[fwmark.to_s]
    _remove_nodes(running_nodes - cluster_nodes)
    _add_nodes(cluster_nodes - running_nodes)
  end
end

#to_sObject



103
104
105
# File 'lib/big_brother/cluster.rb', line 103

def to_s
  "#{@name} (#{@fwmark})"
end

#up_file_exists?Boolean



111
112
113
# File 'lib/big_brother/cluster.rb', line 111

def up_file_exists?
  @up_file.exists?
end