jetpants 0.7.10 → 0.8.0
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/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
|