tyrantmanager 1.3.2 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.rdoc +5 -0
- data/lib/tyrant_manager/cli.rb +29 -0
- data/lib/tyrant_manager/command.rb +1 -0
- data/lib/tyrant_manager/commands/archive_ulogs.rb +156 -0
- data/lib/tyrant_manager/commands/list.rb +9 -12
- data/lib/tyrant_manager/commands/replication_status.rb +10 -19
- data/lib/tyrant_manager/commands/start.rb +12 -15
- data/lib/tyrant_manager/commands/stats.rb +8 -10
- data/lib/tyrant_manager/commands/status.rb +5 -8
- data/lib/tyrant_manager/commands/stop.rb +6 -9
- data/lib/tyrant_manager/tyrant_instance.rb +38 -2
- data/lib/tyrant_manager/util.rb +9 -0
- data/lib/tyrant_manager/version.rb +2 -2
- data/lib/tyrant_manager.rb +14 -2
- data/spec/tyrant_instance_spec.rb +96 -29
- data/spec/tyrant_manager_spec.rb +18 -1
- metadata +6 -2
data/HISTORY.rdoc
CHANGED
data/lib/tyrant_manager/cli.rb
CHANGED
@@ -109,6 +109,35 @@ class TyrantManager
|
|
109
109
|
run { ::TyrantManager::Cli.run_command_with_params( 'list', params ) }
|
110
110
|
}
|
111
111
|
|
112
|
+
mode( 'archive-ulogs' ) {
|
113
|
+
description "Archive the ulog files that are no longer necessary for replication"
|
114
|
+
mixin :option_home
|
115
|
+
mixin :option_log_level
|
116
|
+
mixin :argument_instances
|
117
|
+
|
118
|
+
option( 'archive-method' ) {
|
119
|
+
description "The method of archiving, compress, or delete. Choosing 'delete' will also delete previously 'compressed' ulog files."
|
120
|
+
argument :required
|
121
|
+
validate { |m| %w[ compress delete ].include?( m.downcase ) }
|
122
|
+
default "compress"
|
123
|
+
}
|
124
|
+
|
125
|
+
option( 'dry-run' ) {
|
126
|
+
description "Do not archive, just show the commands"
|
127
|
+
default false
|
128
|
+
}
|
129
|
+
|
130
|
+
option( 'slaves' ) {
|
131
|
+
description "Comma separated list of slave instances connection strings host:port,host:port,..."
|
132
|
+
argument :required
|
133
|
+
cast :list_of_string
|
134
|
+
}
|
135
|
+
|
136
|
+
run { ::TyrantManager::Cli.run_command_with_params( 'archive-ulogs', params ) }
|
137
|
+
|
138
|
+
}
|
139
|
+
|
140
|
+
|
112
141
|
#--- Mixins ---
|
113
142
|
mixin :option_home do
|
114
143
|
option( :home ) do
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'tyrant_manager/command'
|
2
|
+
require 'socket'
|
3
|
+
|
4
|
+
class TyrantManager
|
5
|
+
module Commands
|
6
|
+
#
|
7
|
+
# Archive ulog files that are no longer used for replication.
|
8
|
+
#
|
9
|
+
# You must give the list of slave connection strings on the commandline, or
|
10
|
+
# if the server is in a single master-master relationship, then you can
|
11
|
+
# allow tyrantmanager to figure that out and do the right thing.
|
12
|
+
#
|
13
|
+
# Give the slaves of a particular master
|
14
|
+
#
|
15
|
+
# tyrantmanager archive-ulogs master1 --slaves slave1:11011,slave2:11012,slave3:11013
|
16
|
+
#
|
17
|
+
# Or if there is a master-master relationship tyrant manager can figure it
|
18
|
+
# out.
|
19
|
+
#
|
20
|
+
# tyrantmanager archive-ulogs master1
|
21
|
+
#
|
22
|
+
#
|
23
|
+
class ArchiveUlogs < Command
|
24
|
+
def self.command_name
|
25
|
+
'archive-ulogs'
|
26
|
+
end
|
27
|
+
|
28
|
+
def run
|
29
|
+
instance_slaves = determine_master_slave_mappings( options['slaves'] )
|
30
|
+
|
31
|
+
manager.each_instance( options['instances'] ) do |instance|
|
32
|
+
if instance.is_master_master? then
|
33
|
+
manager.logger.debug "#{instance.name} is master_master"
|
34
|
+
instance_slaves[instance.connection_string] << instance.master_connection
|
35
|
+
end
|
36
|
+
slave_connections = instance_slaves[instance.connection_string]
|
37
|
+
|
38
|
+
potential_removals = potential_ulog_archive_files( instance )
|
39
|
+
manager.logger.info "Checking #{slave_connections.size} slaves of #{instance.name}"
|
40
|
+
|
41
|
+
slave_connections.each do |conn|
|
42
|
+
potential_removals = trim_potential_removals( instance, potential_removals, conn )
|
43
|
+
end
|
44
|
+
|
45
|
+
archive_files_with_method( potential_removals.keys.sort, options['archive-method'] )
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Archive each of the files in the list with the given method
|
52
|
+
#
|
53
|
+
def archive_files_with_method( list, method )
|
54
|
+
list.each do |fname|
|
55
|
+
leader = (options['dry-run']) ? "(dry-run)" : ""
|
56
|
+
if "delete" == method then
|
57
|
+
File.unlink( fname ) unless options['dry-run']
|
58
|
+
manager.logger.info "deleted #{leader} #{fname}"
|
59
|
+
else
|
60
|
+
if File.extname( fname ) == ".ulog" then
|
61
|
+
%x[ gzip #{fname} ] unless options['dry-run']
|
62
|
+
manager.logger.info "#{leader} compressed #{fname}"
|
63
|
+
else
|
64
|
+
manager.logger.info "#{leader} already compressed #{fname}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# Remove all items from the potential removals list that have a timestamp
|
72
|
+
# that is newer than the last replication timestamp of the tyrant
|
73
|
+
# connection
|
74
|
+
#
|
75
|
+
def trim_potential_removals( master_instance, potential, slave_conn )
|
76
|
+
slave_stat = slave_conn.stat
|
77
|
+
milliseconds = Float( slave_stat['rts'] )
|
78
|
+
last_replication_at = Time.at( milliseconds / 1_000_000 )
|
79
|
+
|
80
|
+
manager.logger.debug "Slave #{slave_conn.host}:#{slave_conn.port} last replicated at #{last_replication_at.strftime("%Y-%m-%d %H:%M:%S")} from #{master_instance.connection_string}"
|
81
|
+
|
82
|
+
if milliseconds.to_i == 0 then
|
83
|
+
manager.logger.warn "It appears that the slave at #{slave_conn.host}:#{slave_conn.port} has never replicated"
|
84
|
+
manager.logger.warn "This means that no ulogs on the master will be removed, since there is no evidence of replication."
|
85
|
+
manager.logger.warn "It may be necessary to force a replication by inserting a record into the master:"
|
86
|
+
manager.logger.warn ""
|
87
|
+
manager.logger.warn " tcrmgr put -port #{master_instance.configuration.port} #{master_instance.configuration.host} __tyrant_manager.force_replication_at #{Time.now.utc.to_i}"
|
88
|
+
manager.logger.warn ""
|
89
|
+
manager.logger.warn "And then removing that record if you so choose:"
|
90
|
+
manager.logger.warn ""
|
91
|
+
manager.logger.warn " tcrmgr out -port #{master_instance.configuration.port} #{master_instance.configuration.host} __tyrant_manager.force_replication_at"
|
92
|
+
manager.logger.warn ""
|
93
|
+
end
|
94
|
+
|
95
|
+
manager.logger.debug "Trimming ulog files that are newer than #{last_replication_at.strftime("%Y-%m-%d %H:%M:%S")}"
|
96
|
+
|
97
|
+
trimmed_potential = remove_newer_than( potential, last_replication_at )
|
98
|
+
end
|
99
|
+
|
100
|
+
#
|
101
|
+
# Filter all the ulogs from the list whose value is greater than the input
|
102
|
+
# time.
|
103
|
+
#
|
104
|
+
def remove_newer_than( potential, whence )
|
105
|
+
potential.keys.sort.each do |fname|
|
106
|
+
if potential[fname] > whence then
|
107
|
+
potential.delete( fname )
|
108
|
+
end
|
109
|
+
end
|
110
|
+
return potential
|
111
|
+
end
|
112
|
+
|
113
|
+
#
|
114
|
+
# The list of potential files to remove from the ulog directory. This is
|
115
|
+
# all the files in the ulog directory, minus the last one lexically.
|
116
|
+
#
|
117
|
+
# A hash of filename => File.mtime values is returned
|
118
|
+
#
|
119
|
+
def potential_ulog_archive_files( instance )
|
120
|
+
names = instance.ulog_files[0..-2]
|
121
|
+
names += Dir.glob( "#{instance.ulog_dir}/*.ulog.gz" )
|
122
|
+
potential = {}
|
123
|
+
names.each do |name|
|
124
|
+
potential[name] = File.mtime( name )
|
125
|
+
end
|
126
|
+
return potential
|
127
|
+
end
|
128
|
+
|
129
|
+
# Given a list of slaves, create a hash that has as the key, the instance
|
130
|
+
# connection string of a master, as as the value, an array of
|
131
|
+
# Rufus::Tokyo::Tyrant connections.
|
132
|
+
#
|
133
|
+
def determine_master_slave_mappings( list_of_slaves )
|
134
|
+
master_to_slaves = Hash.new{ |h,k| h[k] = [] }
|
135
|
+
|
136
|
+
list_of_slaves ||= []
|
137
|
+
list_of_slaves.each do |connection_string|
|
138
|
+
host, port = connection_string.split(":")
|
139
|
+
conn = Rufus::Tokyo::Tyrant.new( host, port.to_i )
|
140
|
+
stat = conn.stat
|
141
|
+
master_host = stat['mhost']
|
142
|
+
master_port = stat['mport']
|
143
|
+
if master_host and master_port then
|
144
|
+
master_to_slaves["#{master_host}:#{master_port}"] << conn
|
145
|
+
else
|
146
|
+
manager.logger.warn "Slave #{connection_string} does not have a master server configured, skipping using it as a slave"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
return master_to_slaves
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
|
@@ -7,20 +7,17 @@ class TyrantManager
|
|
7
7
|
#
|
8
8
|
class List < Command
|
9
9
|
def run
|
10
|
-
manager.each_instance do |instance|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
parts << "port #{instance.configuration.port}"
|
16
|
-
parts << instance.home_dir
|
10
|
+
manager.each_instance( options['instances'] ) do |instance|
|
11
|
+
parts = []
|
12
|
+
parts << ("%20s" % instance.name)
|
13
|
+
parts << "port #{instance.configuration.port}"
|
14
|
+
parts << instance.home_dir
|
17
15
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
22
|
-
puts parts.join(" : ")
|
16
|
+
if instance.configuration.master_server then
|
17
|
+
parts << "server id #{"%2d" % instance.configuration.server_id}"
|
18
|
+
parts << "replicating from #{instance.configuration.master_server}:#{instance.configuration.master_port}"
|
23
19
|
end
|
20
|
+
puts parts.join(" : ")
|
24
21
|
end
|
25
22
|
end
|
26
23
|
end
|
@@ -12,12 +12,10 @@ class TyrantManager
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def run
|
15
|
-
manager.each_instance do |instance|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
s_stat = instance.stat
|
20
|
-
logger.info "#{instance.name} is replicating from #{s_stat['mhost']}:#{s_stat['mport']}"
|
15
|
+
manager.each_instance( options['instances'] ) do |instance|
|
16
|
+
if instance.running? and instance.is_slave? then
|
17
|
+
s_stat = instance.stat
|
18
|
+
logger.info "#{instance.name} is replicating from #{s_stat['mhost']}:#{s_stat['mport']}"
|
21
19
|
if m_conn = validate_master_connection( instance ) then
|
22
20
|
if validate_master_master( instance.connection, m_conn ) then
|
23
21
|
m_stat = m_conn.stat
|
@@ -30,10 +28,10 @@ class TyrantManager
|
|
30
28
|
end
|
31
29
|
|
32
30
|
p_stat = primary.stat
|
33
|
-
p_name = "#{ip_of( primary.host )}:#{primary.port}"
|
31
|
+
p_name = "#{manager.ip_of( primary.host )}:#{primary.port}"
|
34
32
|
|
35
33
|
f_stat = failover.stat
|
36
|
-
f_name = "#{ip_of( failover.host )}:#{failover.port}"
|
34
|
+
f_name = "#{manager.ip_of( failover.host )}:#{failover.port}"
|
37
35
|
|
38
36
|
n_width = [ p_name.length, f_name.length ].max
|
39
37
|
|
@@ -41,8 +39,7 @@ class TyrantManager
|
|
41
39
|
logger.info " Failover master : #{f_name} -> #{f_stat['rnum']} records, last replicated #{failover.stat['delay']} seconds ago"
|
42
40
|
end
|
43
41
|
end
|
44
|
-
|
45
|
-
end
|
42
|
+
logger.info ""
|
46
43
|
end
|
47
44
|
end
|
48
45
|
end
|
@@ -55,26 +52,20 @@ class TyrantManager
|
|
55
52
|
|
56
53
|
if ( m_stat['mhost'] and m_stat['mport'] ) then
|
57
54
|
logger.info " #{s_stat['mhost']}:#{s_stat['mport']} is replicating from #{m_stat['mhost']}:#{m_stat['mport']}"
|
58
|
-
mm_ip = ip_of( m_stat['mhost'] )
|
59
|
-
s_ip = ip_of( slave.host )
|
55
|
+
mm_ip = manager.ip_of( m_stat['mhost'] )
|
56
|
+
s_ip = manager.ip_of( slave.host )
|
60
57
|
if ( s_ip == mm_ip ) and ( slave.port == m_stat['mport'].to_i ) then
|
61
58
|
#logger.info " - this is a good master-master relationship"
|
62
59
|
return true
|
63
60
|
else
|
64
61
|
logger.error " Unsupported replication configuration!!!"
|
65
62
|
logger.error " (original hostnames) #{slave.host}:#{slave.port} -> #{(master.host)}:#{master.port} -> #{m_stat['mhost']}:#{m_stat['mport']}"
|
66
|
-
logger.error " (hostnames resolved) #{s_ip}:#{slave.port} -> #{ip_of(master.host)}:#{master.port} -> #{ip_of(m_stat['mhost'])}:#{m_stat['mport']}"
|
63
|
+
logger.error " (hostnames resolved) #{s_ip}:#{slave.port} -> #{manager.ip_of(master.host)}:#{master.port} -> #{manager.ip_of(m_stat['mhost'])}:#{m_stat['mport']}"
|
67
64
|
return false
|
68
65
|
end
|
69
66
|
end
|
70
67
|
end
|
71
68
|
|
72
|
-
def ip_of( hostname )
|
73
|
-
hostname = Socket.gethostname if %w[ localhost 0.0.0.0 ].include?( hostname )
|
74
|
-
addr_info = Socket.getaddrinfo( hostname, 1978, "AF_INET" )
|
75
|
-
return addr_info.first[3]
|
76
|
-
end
|
77
|
-
|
78
69
|
def validate_master_connection( slave )
|
79
70
|
begin
|
80
71
|
m_conn = slave.master_connection
|
@@ -6,24 +6,21 @@ class TyrantManager
|
|
6
6
|
#
|
7
7
|
class Start < Command
|
8
8
|
def run
|
9
|
-
manager.each_instance do |instance|
|
10
|
-
|
11
|
-
|
12
|
-
parts = [ "Starting #{instance.name}" ]
|
13
|
-
parts << instance.start_command
|
9
|
+
manager.each_instance( options['instances'] ) do |instance|
|
10
|
+
parts = [ "Starting #{instance.name}" ]
|
11
|
+
parts << instance.start_command
|
14
12
|
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
if options['dry-run'] then
|
14
|
+
parts << "(dry-run)"
|
15
|
+
logger.info parts.join(" : ")
|
18
16
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
end
|
24
|
-
else
|
25
|
-
logger.info "Instance #{instance.name} already running"
|
17
|
+
elsif not instance.running? then
|
18
|
+
logger.info parts.join(" : ")
|
19
|
+
Dir.chdir( instance.home_dir ) do
|
20
|
+
instance.start
|
26
21
|
end
|
22
|
+
else
|
23
|
+
logger.info "Instance #{instance.name} already running"
|
27
24
|
end
|
28
25
|
end
|
29
26
|
end
|
@@ -6,17 +6,15 @@ class TyrantManager
|
|
6
6
|
#
|
7
7
|
class Stats < Command
|
8
8
|
def run
|
9
|
-
manager.each_instance do |instance|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
puts " #{lhs} #{stats[k]}"
|
17
|
-
end
|
18
|
-
puts
|
9
|
+
manager.each_instance( options['instances'] ) do |instance|
|
10
|
+
puts "Instance #{instance.name} at #{instance.home_dir}"
|
11
|
+
stats = instance.stat
|
12
|
+
max_width = stats.keys.collect { |k| k.length }.sort.last + 2
|
13
|
+
stats.keys.sort.each do |k|
|
14
|
+
lhs = k.ljust(max_width, ".")
|
15
|
+
puts " #{lhs} #{stats[k]}"
|
19
16
|
end
|
17
|
+
puts
|
20
18
|
end
|
21
19
|
end
|
22
20
|
end
|
@@ -10,14 +10,11 @@ class TyrantManager
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def run
|
13
|
-
manager.each_instance do |instance|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
else
|
19
|
-
logger.info "#{instance.name} is not running, or its pid file is gone"
|
20
|
-
end
|
13
|
+
manager.each_instance( options['instances'] ) do |instance|
|
14
|
+
if instance.running? then
|
15
|
+
logger.info "#{instance.name} is running as pid #{instance.pid}"
|
16
|
+
else
|
17
|
+
logger.info "#{instance.name} is not running, or its pid file is gone"
|
21
18
|
end
|
22
19
|
end
|
23
20
|
end
|
@@ -6,15 +6,12 @@ class TyrantManager
|
|
6
6
|
#
|
7
7
|
class Stop < Command
|
8
8
|
def run
|
9
|
-
manager.each_instance do |instance|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
else
|
16
|
-
logger.info "Stopping #{instance.name} : no pid file, nothing to do"
|
17
|
-
end
|
9
|
+
manager.each_instance( options['instances'] ) do |instance|
|
10
|
+
if File.exist?( instance.pid_file ) then
|
11
|
+
logger.info "Stopping #{instance.name} : pid #{instance.pid}"
|
12
|
+
instance.stop
|
13
|
+
else
|
14
|
+
logger.info "Stopping #{instance.name} : no pid file, nothing to do"
|
18
15
|
end
|
19
16
|
end
|
20
17
|
end
|
@@ -152,6 +152,13 @@ class TyrantManager
|
|
152
152
|
@ulog_dir ||= append_to_home_if_not_absolute( configuration.ulog_dir )
|
153
153
|
end
|
154
154
|
|
155
|
+
#
|
156
|
+
# The list of .ulog files that are in the ulog/ directory
|
157
|
+
#
|
158
|
+
def ulog_files
|
159
|
+
Dir.glob( "#{ulog_dir}/*.ulog" ).sort
|
160
|
+
end
|
161
|
+
|
155
162
|
#
|
156
163
|
# The lua extension file
|
157
164
|
#
|
@@ -369,13 +376,21 @@ class TyrantManager
|
|
369
376
|
tclass.new( configuration.host, configuration.port.to_i )
|
370
377
|
end
|
371
378
|
|
379
|
+
#
|
380
|
+
# Return the host:port connection string of the instance
|
381
|
+
#
|
382
|
+
def connection_string
|
383
|
+
"#{configuration.host}:#{configuration.port}"
|
384
|
+
end
|
385
|
+
|
372
386
|
#
|
373
387
|
# Is this instance a slave of another server? This means it could be in a
|
374
|
-
# master-slave or master-master relationship
|
388
|
+
# master-slave or master-master relationship. returns true or false
|
389
|
+
# explicitly
|
375
390
|
#
|
376
391
|
def is_slave?
|
377
392
|
s = connection.stat
|
378
|
-
return (s['mhost'] and s['mport'])
|
393
|
+
return ((s['mhost'] and s['mport']) ? true : false )
|
379
394
|
end
|
380
395
|
|
381
396
|
#
|
@@ -389,6 +404,27 @@ class TyrantManager
|
|
389
404
|
return nil
|
390
405
|
end
|
391
406
|
|
407
|
+
#
|
408
|
+
# Is this instance in a master-master relationship with another server.
|
409
|
+
# This means that it is a slave, and its master server is also a slave of
|
410
|
+
# this server
|
411
|
+
#
|
412
|
+
def is_master_master?
|
413
|
+
if mc = self.master_connection then
|
414
|
+
mstat = mc.stat
|
415
|
+
mslave_host = manager.ip_of(mstat['mhost'])
|
416
|
+
mslave_port = mstat['mport']
|
417
|
+
|
418
|
+
mslave_conn_string = "#{mslave_host}:#{mslave_port}"
|
419
|
+
|
420
|
+
my_host = manager.ip_of( configuration.host )
|
421
|
+
my_conn_string = "#{my_host}:#{configuration.port}"
|
422
|
+
logger.debug "#is_master_master? -> my_conn_string = #{my_conn_string} mslave_conn_string = #{mslave_conn_string}"
|
423
|
+
|
424
|
+
return (my_conn_string == mslave_conn_string)
|
425
|
+
end
|
426
|
+
return false
|
427
|
+
end
|
392
428
|
|
393
429
|
private
|
394
430
|
|
data/lib/tyrant_manager.rb
CHANGED
@@ -7,10 +7,12 @@ require 'rubygems'
|
|
7
7
|
require 'loquacious'
|
8
8
|
require 'tyrant_manager/version'
|
9
9
|
require 'tyrant_manager/paths'
|
10
|
+
require 'tyrant_manager/util'
|
10
11
|
require 'tyrant_manager/log'
|
11
12
|
|
12
13
|
class TyrantManager
|
13
14
|
include TyrantManager::Paths
|
15
|
+
include TyrantManager::Util
|
14
16
|
|
15
17
|
class Error < StandardError; end
|
16
18
|
|
@@ -135,6 +137,8 @@ class TyrantManager
|
|
135
137
|
end
|
136
138
|
return TyrantManager.new( dir )
|
137
139
|
end
|
140
|
+
|
141
|
+
|
138
142
|
end
|
139
143
|
|
140
144
|
#
|
@@ -211,9 +215,17 @@ class TyrantManager
|
|
211
215
|
return @instances
|
212
216
|
end
|
213
217
|
|
214
|
-
|
218
|
+
# Yield each instance that exists in the limit list, if the limit exists.
|
219
|
+
# If the limit does not exist then yield each instance.
|
220
|
+
#
|
221
|
+
def each_instance( limit = %w[ all ])
|
222
|
+
limit = [ limit ].flatten
|
223
|
+
every = (limit.first == "all")
|
224
|
+
|
215
225
|
instances.keys.sort.each do |name|
|
216
|
-
|
226
|
+
if every or limit.include?( name ) then
|
227
|
+
yield instances[name]
|
228
|
+
end
|
217
229
|
end
|
218
230
|
end
|
219
231
|
|
@@ -5,17 +5,44 @@ require 'tyrant_manager/tyrant_instance'
|
|
5
5
|
|
6
6
|
describe TyrantManager::TyrantInstance do
|
7
7
|
before( :each ) do
|
8
|
-
@
|
8
|
+
@tyrant_manager_dir = File.join( temp_dir, 'tyrant' )
|
9
|
+
|
10
|
+
@instances = {
|
11
|
+
'standalone' => nil,
|
12
|
+
'slave_1' => nil,
|
13
|
+
'master_master_1' => nil,
|
14
|
+
'master_master_2' => nil
|
15
|
+
}
|
16
|
+
|
9
17
|
TyrantManager::Log.silent {
|
10
|
-
|
11
|
-
@
|
12
|
-
|
13
|
-
@
|
18
|
+
|
19
|
+
@mgr = TyrantManager.setup( @tyrant_manager_dir)
|
20
|
+
|
21
|
+
@instances.keys.each_with_index do |name, idx|
|
22
|
+
idir = @mgr.instances_path( name )
|
23
|
+
tyrant = TyrantManager::TyrantInstance.setup( idir )
|
24
|
+
tyrant.manager = @mgr
|
25
|
+
tyrant.configuration.port += idx
|
26
|
+
tyrant.configuration.server_id = tyrant.configuration.port
|
27
|
+
@instances[name] = tyrant
|
28
|
+
end
|
14
29
|
}
|
30
|
+
|
31
|
+
# set the slave_1 to be a slave of the standalone
|
32
|
+
@instances['slave_1'].configuration.master_server = "localhost"
|
33
|
+
@instances['slave_1'].configuration.master_port = @instances['standalone'].configuration.port
|
34
|
+
|
35
|
+
# set the master_master pairs into a master_master relationship
|
36
|
+
@instances['master_master_1'].configuration.master_server = "localhost"
|
37
|
+
@instances['master_master_1'].configuration.master_port = @instances['master_master_2'].configuration.port
|
38
|
+
|
39
|
+
@instances['master_master_2'].configuration.master_server = "localhost"
|
40
|
+
@instances['master_master_2'].configuration.master_port = @instances['master_master_1'].configuration.port
|
41
|
+
|
15
42
|
end
|
16
43
|
|
17
44
|
after( :each ) do
|
18
|
-
FileUtils.rm_rf @
|
45
|
+
FileUtils.rm_rf @tyrant_manager_dir
|
19
46
|
end
|
20
47
|
|
21
48
|
it "raises an exception if given an invalid directory on initialization" do
|
@@ -23,55 +50,95 @@ describe TyrantManager::TyrantInstance do
|
|
23
50
|
end
|
24
51
|
|
25
52
|
it "#config_file" do
|
26
|
-
@
|
27
|
-
File.exist?( @
|
53
|
+
@instances['standalone'].config_file.should == File.join( @tyrant_manager_dir, "instances", "standalone", "config.rb" )
|
54
|
+
File.exist?( @instances['standalone'].config_file ).should == true
|
28
55
|
end
|
29
56
|
|
30
57
|
it "#configuration" do
|
31
|
-
@
|
58
|
+
@instances['standalone'].configuration.should_not == nil
|
32
59
|
end
|
33
60
|
|
34
61
|
it "#pid_file" do
|
35
|
-
@
|
62
|
+
@instances['standalone'].pid_file.should == File.join( @tyrant_manager_dir, "instances", "standalone", "standalone.pid" )
|
36
63
|
end
|
37
64
|
|
38
65
|
it "#log_file" do
|
39
|
-
@
|
66
|
+
@instances['standalone'].log_file.should == File.join( @tyrant_manager_dir, "instances", "standalone", "log", "standalone.log" )
|
40
67
|
end
|
41
68
|
|
42
69
|
it "#replication_timestamp_file" do
|
43
|
-
@
|
70
|
+
@instances['standalone'].replication_timestamp_file.should == File.join( @tyrant_manager_dir, "instances", "standalone", "standalone.rts" )
|
44
71
|
end
|
45
72
|
|
46
73
|
it "#lua_extension_file" do
|
47
|
-
@
|
74
|
+
@instances['standalone'].lua_extension_file.should == File.join( @tyrant_manager_dir, "instances", "standalone", "lua", "standalone.lua" )
|
48
75
|
end
|
49
76
|
|
50
77
|
it "#data_dir" do
|
51
|
-
@
|
78
|
+
@instances['standalone'].data_dir.should == File.join( @tyrant_manager_dir, "instances", "standalone", "data" )
|
52
79
|
end
|
53
80
|
|
54
81
|
describe "against running instances" do
|
55
82
|
before( :each ) do
|
56
|
-
@
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
83
|
+
@instances.each_pair do |name, instance|
|
84
|
+
instance.start
|
85
|
+
start = Time.now
|
86
|
+
#print "#{name} : starting ->"
|
87
|
+
loop do
|
88
|
+
break if instance.running?
|
89
|
+
#print "+"
|
90
|
+
$stdout.flush
|
91
|
+
sleep 0.1
|
92
|
+
break if (Time.now - start) > 3
|
93
|
+
end
|
94
|
+
#puts
|
62
95
|
end
|
63
96
|
end
|
64
97
|
|
65
98
|
after( :each ) do
|
66
|
-
@
|
99
|
+
@instances.each_pair do |name, instance|
|
100
|
+
instance.stop
|
101
|
+
start = Time.now
|
102
|
+
#print "#{name} : stopping ->"
|
103
|
+
loop do
|
104
|
+
break unless instance.running?
|
105
|
+
#print "-"
|
106
|
+
$stdout.flush
|
107
|
+
sleep 0.1
|
108
|
+
break if (Time.now - start) > 3
|
109
|
+
end
|
110
|
+
#puts
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
it "#is_running?" do
|
115
|
+
@instances.each_pair do |name, instance|
|
116
|
+
[ name, instance.running? ].should == [ name, true ]
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
it "#is_slave? when it is NOT a slave" do
|
121
|
+
@instances['standalone'].running?.should == true
|
122
|
+
@instances['standalone'].is_slave?.should == false
|
123
|
+
end
|
124
|
+
|
125
|
+
it "#is_slave? when it IS a slave" do
|
126
|
+
@instances['slave_1'].running?.should == true
|
127
|
+
@instances['slave_1'].is_slave?.should == true
|
67
128
|
end
|
68
129
|
|
69
|
-
it "#
|
70
|
-
@
|
71
|
-
@
|
72
|
-
@tyrant.stop
|
130
|
+
it "#is_master_master? when it is NOT in a master_master relationship" do
|
131
|
+
@instances['slave_1'].running?.should == true
|
132
|
+
@instances['slave_1'].is_master_master?.should == false
|
73
133
|
end
|
74
134
|
|
135
|
+
it "#is_master_master? when it IS in a master_master relationship" do
|
136
|
+
@instances['master_master_1'].running?.should == true
|
137
|
+
@instances['master_master_1'].is_master_master?.should == true
|
138
|
+
|
139
|
+
@instances['master_master_2'].running?.should == true
|
140
|
+
@instances['master_master_2'].is_master_master?.should == true
|
141
|
+
end
|
75
142
|
end
|
76
143
|
|
77
144
|
|
@@ -84,23 +151,23 @@ describe TyrantManager::TyrantInstance do
|
|
84
151
|
'table' => "tct"
|
85
152
|
}.each_pair do |db_type, db_ext|
|
86
153
|
it "db_type of #{db_type} is db file with ext #{db_ext}" do
|
87
|
-
f = @
|
154
|
+
f = @instances['standalone'].db_file( db_type )
|
88
155
|
if f.size == 1 then
|
89
156
|
f.should == db_ext
|
90
157
|
else
|
91
|
-
f.should == File.join( @
|
158
|
+
f.should == File.join( @tyrant_manager_dir, "instances", "standalone", "data", "standalone.#{db_ext}" )
|
92
159
|
end
|
93
160
|
end
|
94
161
|
end
|
95
162
|
end
|
96
163
|
|
97
164
|
it "#ulog_dir" do
|
98
|
-
@
|
165
|
+
@instances['standalone'].ulog_dir.should == File.join( @tyrant_manager_dir, "instances", "standalone", "ulog" )
|
99
166
|
end
|
100
167
|
|
101
168
|
|
102
169
|
it "#start_command" do
|
103
|
-
@
|
170
|
+
@instances['standalone'].start_command.should =~ /^ttserver/
|
104
171
|
end
|
105
172
|
|
106
173
|
end
|
data/spec/tyrant_manager_spec.rb
CHANGED
@@ -51,7 +51,7 @@ describe TyrantManager do
|
|
51
51
|
@mgr.configuration.ttserver.should == "ttserver"
|
52
52
|
end
|
53
53
|
|
54
|
-
it "
|
54
|
+
it "iterates over all its instances" do
|
55
55
|
3.times do |x|
|
56
56
|
idir = @mgr.instances_path( "test#{x}" )
|
57
57
|
TyrantManager::TyrantInstance.setup( idir )
|
@@ -66,4 +66,21 @@ describe TyrantManager do
|
|
66
66
|
|
67
67
|
names.sort.should == %w[ test0 test1 test2 ]
|
68
68
|
end
|
69
|
+
|
70
|
+
it "iterates over a subset of instances" do
|
71
|
+
3.times do |x|
|
72
|
+
idir = @mgr.instances_path( "test#{x}" )
|
73
|
+
TyrantManager::TyrantInstance.setup( idir )
|
74
|
+
end
|
75
|
+
|
76
|
+
@mgr.instances.size.should == 3
|
77
|
+
names = []
|
78
|
+
@mgr.each_instance( %w[ test0 test2] ) do |i|
|
79
|
+
i.name.should =~ /test\d/
|
80
|
+
names << i.name
|
81
|
+
end
|
82
|
+
|
83
|
+
names.sort.should == %w[ test0 test2 ]
|
84
|
+
end
|
85
|
+
|
69
86
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tyrantmanager
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Hinegardner
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-21 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -88,6 +88,7 @@ extra_rdoc_files:
|
|
88
88
|
- LICENSE
|
89
89
|
- lib/tyrant_manager/cli.rb
|
90
90
|
- lib/tyrant_manager/command.rb
|
91
|
+
- lib/tyrant_manager/commands/archive_ulogs.rb
|
91
92
|
- lib/tyrant_manager/commands/create_instance.rb
|
92
93
|
- lib/tyrant_manager/commands/list.rb
|
93
94
|
- lib/tyrant_manager/commands/replication_status.rb
|
@@ -99,6 +100,7 @@ extra_rdoc_files:
|
|
99
100
|
- lib/tyrant_manager/paths.rb
|
100
101
|
- lib/tyrant_manager/runner.rb
|
101
102
|
- lib/tyrant_manager/tyrant_instance.rb
|
103
|
+
- lib/tyrant_manager/util.rb
|
102
104
|
- lib/tyrant_manager/version.rb
|
103
105
|
- lib/tyrant_manager.rb
|
104
106
|
- lib/tyrantmanager.rb
|
@@ -106,6 +108,7 @@ files:
|
|
106
108
|
- bin/tyrantmanager
|
107
109
|
- lib/tyrant_manager/cli.rb
|
108
110
|
- lib/tyrant_manager/command.rb
|
111
|
+
- lib/tyrant_manager/commands/archive_ulogs.rb
|
109
112
|
- lib/tyrant_manager/commands/create_instance.rb
|
110
113
|
- lib/tyrant_manager/commands/list.rb
|
111
114
|
- lib/tyrant_manager/commands/replication_status.rb
|
@@ -117,6 +120,7 @@ files:
|
|
117
120
|
- lib/tyrant_manager/paths.rb
|
118
121
|
- lib/tyrant_manager/runner.rb
|
119
122
|
- lib/tyrant_manager/tyrant_instance.rb
|
123
|
+
- lib/tyrant_manager/util.rb
|
120
124
|
- lib/tyrant_manager/version.rb
|
121
125
|
- lib/tyrant_manager.rb
|
122
126
|
- lib/tyrantmanager.rb
|