jetpants 0.7.10 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +7 -3
- data/bin/jetpants +67 -33
- data/doc/commands.rdoc +2 -0
- data/doc/configuration.rdoc +3 -2
- data/doc/jetpants_collins.rdoc +1 -1
- data/doc/plugins.rdoc +4 -0
- data/doc/requirements.rdoc +1 -1
- data/lib/jetpants.rb +21 -4
- data/lib/jetpants/db.rb +4 -0
- data/lib/jetpants/db/client.rb +10 -4
- data/lib/jetpants/db/import_export.rb +28 -11
- data/lib/jetpants/db/privileges.rb +59 -10
- data/lib/jetpants/db/replication.rb +69 -20
- data/lib/jetpants/db/server.rb +41 -19
- data/lib/jetpants/db/state.rb +99 -8
- data/lib/jetpants/host.rb +33 -35
- data/lib/jetpants/monkeypatch.rb +9 -0
- data/lib/jetpants/pool.rb +14 -7
- data/lib/jetpants/shard.rb +10 -12
- data/lib/jetpants/table.rb +4 -0
- data/lib/jetpants/topology.rb +28 -9
- data/plugins/jetpants_collins/db.rb +12 -0
- data/plugins/jetpants_collins/jetpants_collins.rb +34 -7
- data/plugins/jetpants_collins/pool.rb +6 -2
- data/plugins/jetpants_collins/topology.rb +44 -6
- data/plugins/simple_tracker/topology.rb +1 -0
- metadata +33 -29
data/lib/jetpants/host.rb
CHANGED
@@ -38,7 +38,8 @@ module Jetpants
|
|
38
38
|
end
|
39
39
|
|
40
40
|
# Returns a Host object for the machine Jetpants is running on.
|
41
|
-
def self.local(interface=
|
41
|
+
def self.local(interface=false)
|
42
|
+
interface ||= Jetpants.private_interface
|
42
43
|
# This technique is adapted from Sergio Rubio Gracia's, described at
|
43
44
|
# http://blog.frameos.org/2006/12/09/getting-network-interface-addresses-using-ioctl-pure-ruby-2/
|
44
45
|
sock = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM,0)
|
@@ -156,38 +157,6 @@ module Jetpants
|
|
156
157
|
@available
|
157
158
|
end
|
158
159
|
|
159
|
-
###### ini file manipulation ###############################################
|
160
|
-
|
161
|
-
# Comments-out lines of an ini file beginning with any of the supplied prefixes
|
162
|
-
def comment_out_ini(file, *prefixes)
|
163
|
-
toggle_ini(file, prefixes, false)
|
164
|
-
end
|
165
|
-
|
166
|
-
# Un-comments-out lines of an ini file beginning with any of the supplied prefixes
|
167
|
-
# The prefixes should NOT include the # comment-out character -- ie, pass them
|
168
|
-
# the same as you would to DB#comment_out_ini
|
169
|
-
def uncomment_out_ini(file, *prefixes)
|
170
|
-
toggle_ini(file, prefixes, true)
|
171
|
-
end
|
172
|
-
|
173
|
-
# Comments-out (if enable is true) or un-comments-out (if enable is false) lines of an ini file.
|
174
|
-
def toggle_ini(file, prefixes, enable)
|
175
|
-
prefixes.flatten!
|
176
|
-
commands = []
|
177
|
-
prefixes.each do |setting|
|
178
|
-
if enable
|
179
|
-
search = '^#(\s*%s\s*(?:=.*)?)$' % setting
|
180
|
-
replace = '\1'
|
181
|
-
else
|
182
|
-
search = '^(\s*%s\s*(?:=.*)?)$' % setting
|
183
|
-
replace = '#\1'
|
184
|
-
end
|
185
|
-
commands << "ruby -i -pe 'sub(%r[#{search}], %q[#{replace}])' #{file}"
|
186
|
-
end
|
187
|
-
cmd_line = commands.join '; '
|
188
|
-
ssh_cmd cmd_line
|
189
|
-
end
|
190
|
-
|
191
160
|
|
192
161
|
###### Directory Copying / Listing / Comparison methods ####################
|
193
162
|
|
@@ -346,6 +315,22 @@ module Jetpants
|
|
346
315
|
end
|
347
316
|
total_size
|
348
317
|
end
|
318
|
+
|
319
|
+
def mount_stats(mount)
|
320
|
+
mount_stats = {}
|
321
|
+
|
322
|
+
output = ssh_cmd "df -k " + mount + "|tail -1| awk '{print $2\",\"$3\",\"$4}'"
|
323
|
+
if output
|
324
|
+
output = output.split(',').map{|s| s.to_i}
|
325
|
+
|
326
|
+
mount_stats['total'] = output[0] * 1024
|
327
|
+
mount_stats['used'] = output[1] * 1024
|
328
|
+
mount_stats['available'] = output[2] * 1024
|
329
|
+
return mount_stats
|
330
|
+
else
|
331
|
+
false
|
332
|
+
end
|
333
|
+
end
|
349
334
|
|
350
335
|
|
351
336
|
###### Misc methods ########################################################
|
@@ -358,8 +343,8 @@ module Jetpants
|
|
358
343
|
# methods that call Host#service with :status operation (such as
|
359
344
|
# DB#probe_running) in a custom plugin, to parse the output properly on
|
360
345
|
# your chosen Linux distro.
|
361
|
-
def service(operation, name)
|
362
|
-
ssh_cmd "service #{name} #{operation.to_s}"
|
346
|
+
def service(operation, name, options='')
|
347
|
+
ssh_cmd "service #{name} #{operation.to_s} #{options}".rstrip
|
363
348
|
end
|
364
349
|
|
365
350
|
# Changes the I/O scheduler to name (such as 'deadline', 'noop', 'cfq')
|
@@ -376,6 +361,19 @@ module Jetpants
|
|
376
361
|
true
|
377
362
|
end
|
378
363
|
|
364
|
+
# Checks if there's a process with the given process ID running on this host.
|
365
|
+
# Optionally also checks if matching_string is contained in the process name.
|
366
|
+
# Returns true if so, false if not.
|
367
|
+
# Warning: this implementation assumes Linux-style "ps" command; will not work
|
368
|
+
# on BSD hosts.
|
369
|
+
def pid_running?(pid, matching_string=false)
|
370
|
+
if matching_string
|
371
|
+
ssh_cmd("ps --no-headers -o command #{pid} | grep '#{matching_string}' | wc -l").chomp.to_i > 0
|
372
|
+
else
|
373
|
+
ssh_cmd("ps --no-headers #{pid} | wc -l").chomp.to_i > 0
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
379
377
|
# Returns number of cores on machine. (reflects virtual cores if hyperthreading
|
380
378
|
# enabled, so might be 2x real value in that case.)
|
381
379
|
# Not currently used by anything in Jetpants base, but might be useful for plugins
|
data/lib/jetpants/monkeypatch.rb
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# This file contains any methods we're adding to core Ruby modules
|
2
2
|
|
3
|
+
# Add a deep_merge method to Hash in order to more effectively join configs
|
4
|
+
class Hash
|
5
|
+
def deep_merge!(other_hash)
|
6
|
+
merge!(other_hash) do |key, oldval, newval|
|
7
|
+
(oldval.class == self.class && newval.class == oldval.class) ? oldval.deep_merge!(newval) : newval
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
3
12
|
# Reopen Enumerable to add some concurrent iterators
|
4
13
|
module Enumerable
|
5
14
|
# Works like each but runs the block in a separate thread per item.
|
data/lib/jetpants/pool.rb
CHANGED
@@ -125,16 +125,21 @@ module Jetpants
|
|
125
125
|
|
126
126
|
# Remove a slave from a pool entirely. This is destructive, ie, it does a
|
127
127
|
# RESET SLAVE on the db.
|
128
|
+
#
|
128
129
|
# Note that a plugin may want to override this (or implement after_remove_slave!)
|
129
130
|
# to actually sync the change to an asset tracker, depending on how the plugin
|
130
131
|
# implements Pool#sync_configuration. (If the implementation makes sync_configuration
|
131
132
|
# work by iterating over the pool's current slaves to update their status/role/pool, it
|
132
133
|
# won't see any slaves that have been removed, and therefore won't update them.)
|
134
|
+
#
|
135
|
+
# This method has no effect on slaves that are unavailable via SSH or have MySQL
|
136
|
+
# stopped, because these are only considered to be in the pool if your asset tracker
|
137
|
+
# plugin intentionally adds them. Such plugins could also handle this in the
|
138
|
+
# after_remove_slave! callback.
|
133
139
|
def remove_slave!(slave_db)
|
134
140
|
raise "Slave is not in this pool" unless slave_db.pool == self
|
141
|
+
return false unless (slave_db.running? && slave_db.available?)
|
135
142
|
slave_db.disable_monitoring
|
136
|
-
slave_db.stop_replication
|
137
|
-
slave_db.repl_binlog_coordinates # displays how far we replicated, in case you need to roll back this change manually
|
138
143
|
slave_db.disable_replication!
|
139
144
|
sync_configuration # may or may not be sufficient -- see note above.
|
140
145
|
end
|
@@ -177,21 +182,23 @@ module Jetpants
|
|
177
182
|
end
|
178
183
|
|
179
184
|
binlog_pos = extended_info ? details[@master][:coordinates].join(':') : ''
|
180
|
-
print "\tmaster = %-15s %-
|
185
|
+
print "\tmaster = %-15s %-32s %s\n" % [@master.ip, @master.hostname, binlog_pos]
|
181
186
|
|
182
187
|
[:active, :standby, :backup].each do |type|
|
183
188
|
slave_list = slaves(type)
|
184
189
|
slave_list.sort.each_with_index do |s, i|
|
185
190
|
binlog_pos = extended_info ? details[s][:coordinates].join(':') : ''
|
186
191
|
slave_lag = extended_info ? "lag=#{details[s][:lag]}" : ''
|
187
|
-
print "\t%-7s slave #{i + 1} = %-15s %-
|
192
|
+
print "\t%-7s slave #{i + 1} = %-15s %-32s %-26s %s\n" % [type, s.ip, s.hostname, binlog_pos, slave_lag]
|
188
193
|
end
|
189
194
|
end
|
190
195
|
true
|
191
196
|
end
|
192
197
|
|
193
198
|
# Demotes the pool's existing master, promoting a slave in its place.
|
194
|
-
|
199
|
+
# The old master will become a slave of the new master if enslave_old_master is true,
|
200
|
+
# unless the old master is unavailable/crashed.
|
201
|
+
def master_promotion!(promoted, enslave_old_master=true)
|
195
202
|
demoted = @master
|
196
203
|
raise "Demoted node is already the master of this pool!" if demoted == promoted
|
197
204
|
raise "Promoted host is not in the right pool!" unless demoted.slaves.include?(promoted)
|
@@ -201,7 +208,7 @@ module Jetpants
|
|
201
208
|
# If demoted machine is available, confirm it is read-only and binlog isn't moving,
|
202
209
|
# and then wait for slaves to catch up to this position
|
203
210
|
if demoted.running?
|
204
|
-
demoted.enable_read_only!
|
211
|
+
demoted.enable_read_only!
|
205
212
|
raise "Unable to enable global read-only mode on demoted machine" unless demoted.read_only?
|
206
213
|
coordinates = demoted.binlog_coordinates
|
207
214
|
raise "Demoted machine still taking writes (from superuser or replication?) despite being read-only" unless coordinates == demoted.binlog_coordinates
|
@@ -241,7 +248,7 @@ module Jetpants
|
|
241
248
|
|
242
249
|
# gather our new replicas
|
243
250
|
replicas.delete promoted
|
244
|
-
replicas << demoted if demoted.running?
|
251
|
+
replicas << demoted if demoted.running? && enslave_old_master
|
245
252
|
|
246
253
|
# perform promotion
|
247
254
|
replicas.each do |r|
|
data/lib/jetpants/shard.rb
CHANGED
@@ -34,8 +34,8 @@ module Jetpants
|
|
34
34
|
# :replicating -- Child shard that is being cloned to new replicas. Shard not in production yet.
|
35
35
|
# :child -- Child shard that is in production for reads, but still slaving from its parent for writes.
|
36
36
|
# :needs_cleanup -- Child shard that is fully in production, but parent replication not torn down yet, and redundant data (from wrong range) not removed yet
|
37
|
-
# :deprecated -- Parent shard that has been split but children are still in :child or :needs_cleanup state. Shard may still be in production for writes.
|
38
|
-
# :recycle -- Parent shard that has been split and children are now in the :ready state. Shard no longer in production.
|
37
|
+
# :deprecated -- Parent shard that has been split but children are still in :child or :needs_cleanup state. Shard may still be in production for writes / replication not torn down yet.
|
38
|
+
# :recycle -- Parent shard that has been split and children are now in the :ready state. Shard no longer in production, replication to children has been torn down.
|
39
39
|
attr_accessor :state
|
40
40
|
|
41
41
|
# Constructor for Shard --
|
@@ -126,9 +126,9 @@ module Jetpants
|
|
126
126
|
# If you omit id_ranges, the parent's ID range will be divided evenly amongst the
|
127
127
|
# children automatically.
|
128
128
|
def init_children(count, id_ranges=false)
|
129
|
-
# Make sure we have enough machines in spare pool
|
130
|
-
raise "Not enough master role machines in spare pool!" if count > Jetpants.topology.count_spares(role:
|
131
|
-
raise "Not enough standby_slave role machines in spare pool!" if count * Jetpants.standby_slaves_per_pool > Jetpants.topology.count_spares(role:
|
129
|
+
# Make sure we have enough machines (of correct hardware spec and role) in spare pool
|
130
|
+
raise "Not enough master role machines in spare pool!" if count > Jetpants.topology.count_spares(role: :master, like: master)
|
131
|
+
raise "Not enough standby_slave role machines in spare pool!" if count * Jetpants.standby_slaves_per_pool > Jetpants.topology.count_spares(role: :standby_slave, like: slaves.first)
|
132
132
|
|
133
133
|
# Make sure enough slaves of shard being split
|
134
134
|
raise "Must have at least #{Jetpants.standby_slaves_per_pool} slaves of shard being split" if master.slaves.count < Jetpants.standby_slaves_per_pool
|
@@ -149,7 +149,7 @@ module Jetpants
|
|
149
149
|
end
|
150
150
|
|
151
151
|
count.times do |i|
|
152
|
-
spare = Jetpants.topology.claim_spare(role:
|
152
|
+
spare = Jetpants.topology.claim_spare(role: :master, like: master)
|
153
153
|
spare.disable_read_only! if (spare.running? && spare.read_only?)
|
154
154
|
spare.output "Using ID range of #{id_ranges[i][0]} to #{id_ranges[i][1]} (inclusive)"
|
155
155
|
s = Shard.new(id_ranges[i][0], id_ranges[i][1], spare, :initializing)
|
@@ -170,7 +170,6 @@ module Jetpants
|
|
170
170
|
|
171
171
|
init_children(pieces) unless @children.count > 0
|
172
172
|
|
173
|
-
@children.concurrent_each {|c| c.disable_binary_logging}
|
174
173
|
clone_to_children!
|
175
174
|
@children.concurrent_each {|c| c.rebuild!}
|
176
175
|
@children.each {|c| c.sync_configuration}
|
@@ -208,7 +207,6 @@ module Jetpants
|
|
208
207
|
raise "Child shard master #{child_shard.master} is already a slave of another pool"
|
209
208
|
elsif child_shard.master.is_slave?
|
210
209
|
child_shard.output "Already slaving from parent shard master"
|
211
|
-
child_shard.restart_mysql # to make previous disable of binary logging take effect
|
212
210
|
else
|
213
211
|
targets << child_shard.master
|
214
212
|
end
|
@@ -233,12 +231,12 @@ module Jetpants
|
|
233
231
|
raise "Cannot rebuild a shard that isn't still slaving from another shard" unless @master.is_slave?
|
234
232
|
raise "Cannot rebuild an active shard" if in_config?
|
235
233
|
|
236
|
-
stop_query_killer
|
237
234
|
tables = Table.from_config 'sharded_tables'
|
238
235
|
|
239
236
|
if [:initializing, :exporting].include? @state
|
240
237
|
@state = :exporting
|
241
238
|
sync_configuration
|
239
|
+
stop_query_killer
|
242
240
|
export_schemata tables
|
243
241
|
export_data tables, @min_id, @max_id
|
244
242
|
end
|
@@ -248,17 +246,17 @@ module Jetpants
|
|
248
246
|
sync_configuration
|
249
247
|
import_schemata!
|
250
248
|
alter_schemata if respond_to? :alter_schemata
|
249
|
+
restart_mysql '--skip-log-bin', '--skip-log-slave-updates', '--innodb-autoinc-lock-mode=2', '--skip-slave-start'
|
251
250
|
import_data tables, @min_id, @max_id
|
251
|
+
restart_mysql # to clear out previous options '--skip-log-bin', '--skip-log-slave-updates', '--innodb-autoinc-lock-mode=2'
|
252
252
|
start_query_killer
|
253
253
|
end
|
254
254
|
|
255
255
|
if [:importing, :replicating].include? @state
|
256
|
-
enable_binary_logging
|
257
|
-
restart_mysql
|
258
256
|
@state = :replicating
|
259
257
|
sync_configuration
|
260
258
|
if Jetpants.standby_slaves_per_pool > 0
|
261
|
-
my_slaves = Jetpants.topology.claim_spares(Jetpants.standby_slaves_per_pool, role:
|
259
|
+
my_slaves = Jetpants.topology.claim_spares(Jetpants.standby_slaves_per_pool, role: :standby_slave, like: parent.slaves.first)
|
262
260
|
enslave!(my_slaves)
|
263
261
|
my_slaves.each {|slv| slv.resume_replication}
|
264
262
|
[self, my_slaves].flatten.each {|db| db.catch_up_to_master}
|
data/lib/jetpants/table.rb
CHANGED
@@ -47,6 +47,10 @@ module Jetpants
|
|
47
47
|
# 'sharding_key' (or equivalently 'primary_key'), 'chunks', and 'order_by'.
|
48
48
|
def initialize(name, params={})
|
49
49
|
@name = name
|
50
|
+
parse_params(params)
|
51
|
+
end
|
52
|
+
|
53
|
+
def parse_params(params = {})
|
50
54
|
params['sharding_key'] ||= params['primary_keys'] || params['primary_key'] || 'user_id'
|
51
55
|
@sharding_keys = (params['sharding_key'].is_a?(Array) ? params['sharding_key'] : [params['sharding_key']])
|
52
56
|
@chunks = params['chunks'] || 1
|
data/lib/jetpants/topology.rb
CHANGED
@@ -71,18 +71,23 @@ module Jetpants
|
|
71
71
|
synchronized
|
72
72
|
# Plugin should override so that this returns an array of [count] Jetpants::DB
|
73
73
|
# objects, or throws an exception if not enough left.
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
74
|
+
#
|
75
|
+
# Options hash is plugin-specific. Jetpants core will provide these two options,
|
76
|
+
# but it's up to a plugin to handle (or ignore) them:
|
77
|
+
#
|
78
|
+
# :role => :master or :standby_slave, indicating what purpose the new node(s)
|
79
|
+
# will be used for. Useful if your hardware spec varies by node role
|
80
|
+
# (not recommended!) or if you vet your master candidates more carefully.
|
81
|
+
# :like => a Jetpants::DB object, indicating that the spare node hardware spec
|
82
|
+
# should be like the specified DB's spec.
|
79
83
|
def claim_spares(count, options={})
|
80
84
|
raise "Plugin must override Topology#claim_spares"
|
81
85
|
end
|
82
86
|
|
83
87
|
synchronized
|
84
88
|
# Plugin should override so that this returns a count of spare machines
|
85
|
-
# matching the selected options.
|
89
|
+
# matching the selected options. options hash follows same format as for
|
90
|
+
# Topology#claim_spares.
|
86
91
|
def count_spares(options={})
|
87
92
|
raise "Plugin must override Topology#count_spares"
|
88
93
|
end
|
@@ -109,12 +114,13 @@ module Jetpants
|
|
109
114
|
@pools.reject {|p| p.is_a? Shard}
|
110
115
|
end
|
111
116
|
|
112
|
-
# Finds and returns a single Jetpants::Pool. Target may be a name (string
|
117
|
+
# Finds and returns a single Jetpants::Pool. Target may be a name (string, case insensitive)
|
118
|
+
# or master (DB object).
|
113
119
|
def pool(target)
|
114
120
|
if target.is_a?(DB)
|
115
121
|
@pools.select {|p| p.master == target}.first
|
116
122
|
else
|
117
|
-
@pools.select {|p| p.name == target}.first
|
123
|
+
@pools.select {|p| p.name.downcase == target.downcase}.first
|
118
124
|
end
|
119
125
|
end
|
120
126
|
|
@@ -137,8 +143,21 @@ module Jetpants
|
|
137
143
|
end
|
138
144
|
|
139
145
|
# Returns the Jetpants::Shard that handles the given ID.
|
146
|
+
# During a shard split, if the child isn't "in production" yet (ie, it's
|
147
|
+
# still being built), this will always return the parent shard. Once the
|
148
|
+
# child is fully built / in production, this method will always return
|
149
|
+
# the child shard. However, Shard#db(:write) will correctly delegate writes
|
150
|
+
# to the parent shard when appropriate in this case. (see also: Topology#shard_db_for_id)
|
140
151
|
def shard_for_id(id)
|
141
|
-
|
152
|
+
choices = shards.select {|s| s.min_id <= id && (s.max_id == 'INFINITY' || s.max_id >= id)}
|
153
|
+
choices.reject! {|s| s.parent && ! s.in_config?} # filter out child shards that are still being built
|
154
|
+
|
155
|
+
# Preferentially return child shards at this point
|
156
|
+
if choices.any? {|s| s.parent}
|
157
|
+
choices.select {|s| s.parent}.first
|
158
|
+
else
|
159
|
+
choices.first
|
160
|
+
end
|
142
161
|
end
|
143
162
|
|
144
163
|
# Returns the Jetpants::DB that handles the given ID with the specified
|
@@ -69,9 +69,21 @@ module Jetpants
|
|
69
69
|
|
70
70
|
##### NEW METHODS ##########################################################
|
71
71
|
|
72
|
+
# Returns true if this database is located in the same datacenter as jetpants_collins
|
73
|
+
# has been figured for, false otherwise.
|
72
74
|
def in_remote_datacenter?
|
73
75
|
@host.collins_location != Plugin::JetCollins.datacenter
|
74
76
|
end
|
75
77
|
|
78
|
+
# Returns true if this database is a spare node and looks ready for use, false otherwise.
|
79
|
+
# The default implementation just ensures a collins status of Provisioned.
|
80
|
+
# Downstream plugins may override this to do additional checks to ensure the node is
|
81
|
+
# in a sane state. (The caller of this method already checks that the node is SSHable,
|
82
|
+
# and that MySQL is running, and the node isn't already in a pool -- so no need to
|
83
|
+
# check any of those here.)
|
84
|
+
def usable_spare?
|
85
|
+
collins_status.downcase == 'provisioned'
|
86
|
+
end
|
87
|
+
|
76
88
|
end
|
77
89
|
end
|
@@ -62,7 +62,7 @@ module Jetpants
|
|
62
62
|
end
|
63
63
|
|
64
64
|
# We make these 4 accessors available to ANY class including this mixin
|
65
|
-
collins_attr_accessor :primary_role, :secondary_role, :pool, :status
|
65
|
+
collins_attr_accessor :primary_role, :secondary_role, :pool, :status, :state
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
@@ -137,12 +137,18 @@ module Jetpants
|
|
137
137
|
asset = collins_asset
|
138
138
|
if field_names.count > 1 || field_names[0].is_a?(Array)
|
139
139
|
field_names.flatten!
|
140
|
+
want_state = !! field_names.delete(:state)
|
140
141
|
results = Hash[field_names.map {|field| [field, (asset ? asset.send(field) : '')]}]
|
142
|
+
results[:state] = asset.state.name if want_state
|
141
143
|
results[:asset] = asset
|
142
144
|
results
|
143
145
|
elsif field_names.count == 1
|
144
146
|
return '' unless asset
|
145
|
-
|
147
|
+
if field_names[0] == :state
|
148
|
+
asset.state.name
|
149
|
+
else
|
150
|
+
asset.send field_names[0]
|
151
|
+
end
|
146
152
|
else
|
147
153
|
nil
|
148
154
|
end
|
@@ -174,11 +180,32 @@ module Jetpants
|
|
174
180
|
output "WARNING: unable to set Collins status to #{val}"
|
175
181
|
next
|
176
182
|
end
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
183
|
+
if attrs[:state]
|
184
|
+
previous_state = asset.state.name
|
185
|
+
previous_status = asset.status
|
186
|
+
if previous_state != attrs[:state].to_s || previous_status != attrs[:status].to_s
|
187
|
+
success = Jetpants::Plugin::JetCollins.set_status!(asset, attrs[:status], 'changed through jetpants', attrs[:state])
|
188
|
+
unless success
|
189
|
+
Jetpants::Plugin::JetCollins.state_create!(attrs[:state], attrs[:state], attrs[:state], attrs[:status])
|
190
|
+
success = Jetpants::Plugin::JetCollins.set_status!(asset, attrs[:status], 'changed through jetpants', attrs[:state])
|
191
|
+
end
|
192
|
+
raise "#{self}: Unable to set Collins state to #{attrs[:state]} and Unable to set Collins status to #{attrs[:status]}" unless success
|
193
|
+
output "Collins state changed from #{previous_state} to #{attrs[:state]}"
|
194
|
+
output "Collins status changed from #{previous_status} to #{attrs[:status]}"
|
195
|
+
end
|
196
|
+
else
|
197
|
+
previous_value = asset.status
|
198
|
+
if previous_value != val.to_s
|
199
|
+
success = Jetpants::Plugin::JetCollins.set_status!(asset, val)
|
200
|
+
raise "#{self}: Unable to set Collins status to #{val}" unless success
|
201
|
+
output "Collins status changed from #{previous_value} to #{val}"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
when :state
|
205
|
+
unless asset && asset.status && attrs[:status]
|
206
|
+
raise "#{self}: Unable to set state without settings a status" unless attrs[:status]
|
207
|
+
output "WARNING: unable to set Collins state to #{val}"
|
208
|
+
next
|
182
209
|
end
|
183
210
|
else
|
184
211
|
unless asset
|
@@ -111,7 +111,7 @@ module Jetpants
|
|
111
111
|
|
112
112
|
# If the demoted master was offline, record some info in Collins, otherwise
|
113
113
|
# there will be 2 masters listed
|
114
|
-
def after_master_promotion!(promoted)
|
114
|
+
def after_master_promotion!(promoted, enslave_old_master=true)
|
115
115
|
Jetpants.topology.clear_asset_cache
|
116
116
|
|
117
117
|
# Find the master asset(s) for this pool, filtering down to only current datacenter
|
@@ -119,9 +119,13 @@ module Jetpants
|
|
119
119
|
assets.reject! {|a| a.location && a.location.upcase != Plugin::JetCollins.datacenter}
|
120
120
|
assets.map(&:to_db).each do |db|
|
121
121
|
if db != @master || !db.running?
|
122
|
-
db.collins_status = 'Maintenance'
|
123
122
|
db.collins_pool = ''
|
124
123
|
db.collins_secondary_role = ''
|
124
|
+
if enslave_old_master
|
125
|
+
db.output 'REMINDER: you must manually put this host into Maintenance status in Collins' unless db.collins_status.downcase == 'maintenance'
|
126
|
+
else
|
127
|
+
db.collins_status = 'Unallocated'
|
128
|
+
end
|
125
129
|
end
|
126
130
|
end
|
127
131
|
end
|